A Python NETCONF client connects to network devices that expose the NETCONF protocol. NETCONF is commonly used for structured configuration, state retrieval, and automation on routers, switches, firewalls, and network controllers.
In Python, the common client library is ncclient. It provides a high-level API around NETCONF sessions, RPC calls, configuration retrieval, edits, locking, and commits. The ncclient documentation covers the full API, while the ncclient PyPI page lists current package releases.
Use NETCONF when the device supports model-driven configuration and you want repeatable changes instead of screen-scraping CLI output. For broader API automation concepts, see the Google API client Python guide.
The main advantage is structure. Instead of parsing command output meant for humans, a NETCONF client sends XML RPC requests and receives structured replies based on device models. That makes scripts easier to validate, test, and review before they change production equipment.
Still, NETCONF automation should be treated like any other infrastructure change. Use lab devices first, limit account permissions, keep logs, and make read-only checks work before writing configuration.
Install ncclient
Install ncclient into the same Python environment that runs your automation script. Calling pip through sys.executable helps avoid installing into the wrong interpreter.
After installing, run a small import test before connecting to a real device. This separates local setup problems from network or authentication problems. If an editor or notebook cannot import ncclient, check that it is using the same interpreter where you installed the package.
Open A NETCONF Session
The manager.connect() helper opens a NETCONF session. Use lab credentials and a test device while learning.
from ncclient import manager
with manager.connect(
host="device.example.com",
port=830,
username="netconf-user",
password="change-me",
hostkey_verify=False,
look_for_keys=False,
) as session:
print(session.connected)
print(session.session_id)
Port 830 is the standard NETCONF-over-SSH port, though some labs and vendors use a different port. In production, configure host-key verification instead of disabling it.
If the connection fails, separate transport issues from NETCONF issues. Confirm DNS or IP reachability, SSH access, the configured port, and whether NETCONF is enabled on the device. A successful SSH login does not always mean the NETCONF service is active.
Read Device Capabilities
Capabilities tell you which NETCONF versions, models, and optional features the device advertises.
from ncclient import manager
with manager.connect(
host="device.example.com",
port=830,
username="netconf-user",
password="change-me",
hostkey_verify=False,
) as session:
for capability in session.server_capabilities:
print(capability)
Review capabilities before sending model-specific RPC calls. If the device does not advertise the model you expect, the request may fail even though the connection works.
Capabilities are also useful when scripts need to support several vendors or operating system versions. Store the capability output from a lab session so you can compare it after upgrades.
Get Running Configuration
Use get_config() to read a datastore such as running. The response object contains XML returned by the device.
from ncclient import manager
with manager.connect(
host="device.example.com",
port=830,
username="netconf-user",
password="change-me",
hostkey_verify=False,
) as session:
reply = session.get_config(source="running")
print(reply.xml)
For large devices, avoid pulling everything when you only need one subtree. Use filters to limit the response and reduce processing time.
Read-only calls are the safest place to begin. They help you confirm authentication, namespaces, model support, and XML parsing before any script is allowed to edit configuration.
Use A Subtree Filter
A subtree filter asks the device for a specific section of state or configuration. The exact XML depends on the device model.
from ncclient import manager
interface_filter = """
<filter>
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"/>
</filter>
"""
with manager.connect(
host="device.example.com",
port=830,
username="netconf-user",
password="change-me",
hostkey_verify=False,
) as session:
reply = session.get(filter=interface_filter)
print(reply.xml)
Filters make scripts faster and safer to inspect because each request has a narrow purpose. Keep filters in named constants so reviews can see exactly what each RPC asks for.
Edit Configuration Carefully
Configuration changes should start in a lab or maintenance window. If the device supports a candidate datastore, edit candidate first and commit only after validation.
from ncclient import manager
config_xml = """
<config>
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>Loopback100</name>
<description>Managed by Python NETCONF</description>
</interface>
</interfaces>
</config>
"""
with manager.connect(
host="device.example.com",
port=830,
username="netconf-user",
password="change-me",
hostkey_verify=False,
) as session:
session.edit_config(target="candidate", config=config_xml)
session.commit()
Not every device supports the same datastore workflow. Some require edits to running, while others support candidate, locking, validation, confirmed commits, or rollback.
Handle RPC Errors
NETCONF errors are often returned as RPC errors. Catch them and log enough context to identify the device, operation, and datastore involved.
from ncclient import manager
from ncclient.operations import RPCError
try:
with manager.connect(
host="device.example.com",
port=830,
username="netconf-user",
password="change-me",
hostkey_verify=False,
) as session:
session.get_config(source="running")
except RPCError as error:
print("RPC error:", error.message)
except OSError as error:
print("Connection error:", error)
Separate RPC errors from connection errors. An RPC error means the session reached the device but the request failed. A connection error usually points to routing, firewall, SSH, credentials, or port configuration.
When logging failures, include the operation name and target datastore, but do not print secrets. Clear logs make it easier to decide whether the script should retry, stop, or require manual review.
Best Practices
Keep connection settings outside the code you commit, use a lab device first, and log every change before sending it. For production automation, enable host-key verification, use least-privilege accounts, and keep credentials in a secure secret store.
Build read-only scripts before write scripts. Reading capabilities, fetching state, and validating filters teach you how a device responds without risking configuration drift.
The reliable pattern is to open a clear session, read capabilities, request a narrow subtree, and only then apply controlled edits. That keeps Python NETCONF automation understandable, reviewable, and safer to operate.