{"id":32570901,"url":"https://github.com/netascode/go-netconf","last_synced_at":"2025-10-29T08:21:21.512Z","repository":{"id":319527336,"uuid":"1078900882","full_name":"netascode/go-netconf","owner":"netascode","description":"A simple, fluent Go client library for interacting with network devices using the NETCONF protocol (RFC 6241).","archived":false,"fork":false,"pushed_at":"2025-10-18T18:49:24.000Z","size":124,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-19T11:05:27.146Z","etag":null,"topics":["golang","netconf"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/netascode.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-18T17:00:44.000Z","updated_at":"2025-10-18T18:49:28.000Z","dependencies_parsed_at":"2025-10-19T11:05:34.988Z","dependency_job_id":"ebc8213d-6c93-45bc-ac7a-2c34c946e721","html_url":"https://github.com/netascode/go-netconf","commit_stats":null,"previous_names":["netascode/go-netconf"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/netascode/go-netconf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fgo-netconf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fgo-netconf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fgo-netconf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fgo-netconf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/netascode","download_url":"https://codeload.github.com/netascode/go-netconf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netascode%2Fgo-netconf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281585773,"owners_count":26526364,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-29T02:00:06.901Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","netconf"],"created_at":"2025-10-29T08:19:36.252Z","updated_at":"2025-10-29T08:21:21.499Z","avatar_url":"https://github.com/netascode.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003ego-netconf\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://godoc.org/github.com/netascode/go-netconf\"\u003e\u003cimg src=\"https://img.shields.io/badge/api-reference-blue.svg?style=flat-square\" alt=\"GoDoc\"\u003e\u003c/a\u003e\n\u003ca href=\"https://goreportcard.com/report/github.com/netascode/go-netconf\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/netascode/go-netconf?style=flat-square\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/netascode/go-netconf/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/netascode/go-netconf/ci.yml?branch=main\u0026style=flat-square\u0026label=build\" alt=\"CI\"\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/gh/netascode/go-netconf\"\u003e\u003cimg src=\"https://codecov.io/gh/netascode/go-netconf/branch/main/graph/badge.svg?style=flat-square\" alt=\"codecov\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/netascode/go-netconf/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MPL--2.0-blue.svg?style=flat-square\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003eA simple, fluent Go client library for interacting with network devices using the NETCONF protocol (RFC 6241).\u003c/h3\u003e\n\n## Features\n\n- **Simple API**: Fluent, chainable API design\n- **XML Manipulation**: Path-based XML operations using [xmldot](https://github.com/netascode/xmldot) (like gjson/sjson for JSON)\n- **Complete NETCONF Support**: All standard operations (Get, GetConfig, EditConfig, Lock, Commit, etc.)\n- **Robust Transport**: Built on [scrapligo](https://github.com/scrapli/scrapligo) for reliable SSH connectivity and NETCONF protocol handling\n- **Automatic Retry**: Built-in retry logic with exponential backoff for transient errors\n- **Thread-Safe**: Concurrent read operations with synchronized write operations\n- **Capability Discovery**: Automatic capability negotiation and checking\n- **Transaction Support**: Full candidate datastore workflow support\n- **Structured Logging**: Configurable logging with automatic sensitive data redaction\n\n## Installation\n\n```bash\ngo get github.com/netascode/go-netconf\n```\n\n## Requirements\n\n- Go 1.24 or later\n- Network device with NETCONF support\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n\n    \"github.com/netascode/go-netconf\"\n)\n\nfunc main() {\n    // Create client\n    client, err := netconf.NewClient(\n        \"192.168.1.1\",\n        netconf.Username(\"admin\"),\n        netconf.Password(\"secret\"),\n        netconf.Port(830),\n    )\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer client.Close()\n\n    // Get configuration with filter\n    ctx := context.Background()\n    filter := netconf.SubtreeFilter(\"\u003cinterfaces/\u003e\")\n    res, err := client.GetConfig(ctx, \"running\", filter)\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Parse response using xmldot\n    ifName := res.Res.Get(\"data.interfaces.interface.name\").String()\n    fmt.Println(\"Interface:\", ifName)\n}\n```\n\n## Usage\n\n### Client Creation\n\n```go\nclient, err := netconf.NewClient(\n    \"192.168.1.1\",\n    netconf.Username(\"admin\"),\n    netconf.Password(\"secret\"),\n    netconf.Port(830),\n    netconf.MaxRetries(5),\n    netconf.OperationTimeout(120*time.Second),\n)\n```\n\n### Get Configuration\n\n```go\nctx := context.Background()\n\n// Get with filter\nfilter := netconf.SubtreeFilter(\"\u003cinterfaces/\u003e\")\nres, err := client.GetConfig(ctx, \"running\", filter)\n\n// Get with XPath filter\nfilter := netconf.XPathFilter(\"/interfaces/interface[name='GigabitEthernet1']\")\nres, err := client.Get(ctx, filter)\n\n// Get without filter (all data)\nres, err := client.GetConfig(ctx, \"running\", netconf.NoFilter())\n```\n\n### Edit Configuration\n\n```go\nctx := context.Background()\n\n// Build configuration using Body builder\nconfig := netconf.Body{}.\n    Set(\"interfaces.interface.name\", \"GigabitEthernet1\").\n    Set(\"interfaces.interface.description\", \"WAN Interface\").\n    Set(\"interfaces.interface.enabled\", true).String()\n\n// Apply configuration\nres, err := client.EditConfig(ctx, \"candidate\", config,\n    netconf.DefaultOperation(\"merge\"),\n    netconf.TestOption(\"test-then-set\"),\n)\n```\n\n### Transaction Workflow\n\n```go\nctx := context.Background()\n\n// Lock candidate datastore\nif _, err := client.Lock(ctx, \"candidate\"); err != nil {\n    log.Fatal(err)\n}\ndefer client.Unlock(ctx, \"candidate\")\n\n// Edit configuration\nconfig := netconf.Body{}.\n    Set(\"system.hostname\", \"router1\").String()\n_, err = client.EditConfig(ctx, \"candidate\", config)\nif err != nil {\n    client.Discard(ctx)\n    log.Fatal(err)\n}\n\n// Commit changes\nif _, err := client.Commit(ctx); err != nil {\n    log.Fatal(err)\n}\n```\n\n### Error Handling\n\nThe library automatically retries transient errors (lock conflicts, resource exhaustion, transport failures) with exponential backoff:\n\n```go\nclient, err := netconf.NewClient(\n    \"192.168.1.1\",\n    netconf.Username(\"admin\"),\n    netconf.Password(\"secret\"),\n    netconf.MaxRetries(10),                      // Maximum retry attempts\n    netconf.BackoffMinDelay(1*time.Second),      // Minimum 1 second delay\n    netconf.BackoffMaxDelay(60*time.Second),     // Maximum 60 second delay\n    netconf.BackoffDelayFactor(1.2),             // Exponential factor\n)\n```\n\n### Capability Checking\n\n```go\n// Check if server supports candidate datastore\nif client.ServerHasCapability(\"urn:ietf:params:netconf:capability:candidate:1.0\") {\n    ctx := context.Background()\n    // Use candidate datastore\n    client.Lock(ctx, \"candidate\")\n    // ...\n}\n\n// Get all server capabilities\ncaps := client.ServerCapabilities()\nfor _, cap := range caps {\n    fmt.Println(cap)\n}\n```\n\n### Custom RPC Operations\n\n```go\nctx := context.Background()\nrpc := `\n\u003cget-system-info xmlns=\"http://example.com/system\"\u003e\n    \u003cdetail\u003efull\u003c/detail\u003e\n\u003c/get-system-info\u003e\n`\nres, err := client.RPC(ctx, rpc)\n```\n\n## Supported Operations\n\n| Operation | Description |\n|-----------|-------------|\n| Get | Retrieve configuration and state data |\n| GetConfig | Retrieve configuration from datastore |\n| EditConfig | Modify configuration |\n| CopyConfig | Copy configuration between datastores |\n| DeleteConfig | Delete configuration datastore |\n| Lock | Lock datastore |\n| Unlock | Unlock datastore |\n| Commit | Commit candidate to running |\n| Discard | Discard candidate changes |\n| Validate | Validate configuration (requires `:validate` capability) |\n| RPC | Send custom RPC operations |\n\n## Documentation\n\n- [GoDoc](https://pkg.go.dev/github.com/netascode/go-netconf)\n- [RFC 6241 - NETCONF Protocol](https://tools.ietf.org/html/rfc6241)\n- [RFC 6242 - NETCONF over SSH](https://tools.ietf.org/html/rfc6242)\n\n## Examples\n\nSee the [examples](examples/) directory for library usage examples:\n\n- **basic** - Client creation, GetConfig, EditConfig, response parsing\n- **candidate** - Lock/Unlock, Validate, Commit/Discard workflows\n- **concurrent** - Thread-safe concurrent operations\n- **custom-rpc** - Custom RPC operations with RPC() method\n- **filters** - SubtreeFilter, XPathFilter, NoFilter APIs\n- **logging** - Logger configuration and log levels\n\n## Testing\n\n```bash\n# Run tests\nmake test\n\n# Run tests with coverage\nmake coverage\n\n# Run linters\nmake lint\n\n# Run all checks\nmake verify\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues or pull requests.\n\n## Acknowledgments\n\nThis library is built on top of [scrapligo](https://github.com/scrapli/scrapligo) for the NETCONF transport layer. Scrapligo provides robust SSH connectivity and NETCONF protocol handling, allowing go-netconf to focus on providing a simple, idiomatic Go API.\n\n## License\n\nMozilla Public License Version 2.0 - see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetascode%2Fgo-netconf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetascode%2Fgo-netconf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetascode%2Fgo-netconf/lists"}