NETCONF combined with YANG data models gives engineers a structured, programmatic alternative to screen-scraping CLI output.This article walks through using Python’s ncclient library to connect to Cisco IOS-XE and Juniper Junos devices, retrieve operational state, and push configuration changes using proper YANG-modeled payloads.
Table of Contents
What You Need Before Starting
This guide assumes you have:
- Python 3.8+
ncclientinstalled (pip install ncclient)- An IOS-XE device (physical or CSR1000v/Catalyst 8000v) with NETCONF enabled
- A Junos device (physical or vMX) with NETCONF over SSH configured
- SSH access and credentials for both
Install dependencies:
pip install ncclient lxml
lxml is needed for parsing and building XML payloads, which is what NETCONF speaks underneath.
Enabling NETCONF on Devices
Cisco IOS-XE
configure terminal
netconf-yang
netconf-yang feature candidate-datastore
end
Verify it’s listening on TCP 830:
ssh -p 830 admin@192.168.1.1 -s netconf
You should receive a <hello> capabilities exchange. If you don’t, check that ip ssh version 2 is configured and the management VRF is correct.
Juniper Junos
set system services netconf ssh port 830
commit
Junos enables NETCONF over SSH by default on port 830 once this is set. No additional daemon configuration is required.
Connecting with ncclient
ncclient abstracts the NETCONF session negotiation, capability exchange, and RPC framing. Connection parameters differ slightly per vendor.
IOS-XE Connection
from ncclient import manager
ios_xe = manager.connect(
host="192.168.1.1",
port=830,
username="admin",
password="C1sc0!",
hostkey_verify=False,
device_params={"name": "iosxe"}
)
device_params={"name": "iosxe"} tells ncclient which manager handler to load. This adjusts behavior around candidate datastores and commit operations specific to IOS-XE.
Junos Connection
junos = manager.connect(
host="192.168.1.2",
port=830,
username="netconf_user",
password="Junip3r!",
hostkey_verify=False,
device_params={"name": "junos"}
)
Retrieving Configuration with get-config
NETCONF’s <get-config> RPC pulls configuration from a specified datastore (running, candidate, or startup).
Get Interface Config from IOS-XE
The filter below uses a subtree filter scoped to the ietf-interfaces YANG model:
interface_filter = """
<filter xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>GigabitEthernet1</name>
</interface>
</interfaces>
</filter>
"""
response = ios_xe.get_config(source="running", filter=interface_filter)
print(response.xml)
The XML response will include the full subtree for GigabitEthernet1 — IP address, description, admin state, and MTU — all structured according to the YANG schema.
Get Interface Config from Junos
Junos uses its own native YANG models in addition to OpenConfig:
junos_filter = """
<filter type="subtree">
<configuration>
<interfaces>
<interface>
<name>ge-0/0/0</name>
</interface>
</interfaces>
</configuration>
</filter>
"""
response = junos.get_config(source="running", filter=junos_filter)
print(response.xml)
Retrieving Operational State with get
<get> retrieves live operational data, not just configuration. This is equivalent to show commands, but structured.
oper_filter = """
<filter xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>GigabitEthernet1</name>
<statistics/>
</interface>
</interfaces-state>
</filter>
"""
oper_data = ios_xe.get(filter=oper_filter)
print(oper_data.xml)
Parse specific values using lxml:
from lxml import etree
root = etree.fromstring(oper_data.xml.encode())
ns = {
"nc": "urn:ietf:params:xml:ns:netconf:base:1.0",
"if": "urn:ietf:params:xml:ns:yang:ietf-interfaces"
}
in_octets = root.find(".//if:in-octets", ns)
if in_octets is not None:
print(f"Inbound octets: {in_octets.text}")
Pushing Configuration Changes with edit-config
This is where NETCONF becomes operationally useful. You’re sending a structured XML payload that maps directly to a YANG model — no regex, no CLI parsing.
Add a Loopback on IOS-XE
loopback_config = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>Loopback100</name>
<type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
ianaift:softwareLoopback
</type>
<enabled>true</enabled>
<ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
<address>
<ip>10.100.0.1</ip>
<prefix-length>32</prefix-length>
</address>
</ipv4>
</interface>
</interfaces>
</config>
"""
response = ios_xe.edit_config(target="running", config=loopback_config)
print(response.xml)
A successful operation returns <ok/> inside an <rpc-reply>. If the payload is malformed or violates the YANG schema, you’ll receive an <rpc-error> with the error message and path.
Modify an Interface Description on Junos (with Commit)
Junos uses a candidate datastore by default. You must explicitly commit after editing:
junos_edit = """
<config>
<configuration>
<interfaces>
<interface>
<name>ge-0/0/0</name>
<description>Uplink to Core</description>
</interface>
</interfaces>
</configuration>
</config>
"""
junos.edit_config(target="candidate", config=junos_edit)
junos.commit()
To validate the candidate before committing:
junos.validate(source="candidate")
junos.commit()
For IOS-XE with candidate datastore enabled, the same pattern applies:
ios_xe.edit_config(target="candidate", config=loopback_config)
ios_xe.validate(source="candidate")
ios_xe.commit()
Deleting Configuration
Use the operation="delete" attribute inside the XML payload to remove config elements:
delete_loopback = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface operation="delete">
<name>Loopback100</name>
</interface>
</interfaces>
</config>
"""
ios_xe.edit_config(target="running", config=delete_loopback)
Discovering Supported YANG Models
Before you write payloads, confirm which YANG modules the device advertises. These are exchanged in the initial <hello> message.
for capability in ios_xe.server_capabilities:
if "yang" in capability.lower():
print(capability)
For IOS-XE, you’ll see entries like:
urn:ietf:params:xml:ns:yang:ietf-interfaces?module=ietf-interfaces&revision=2018-02-20
http://cisco.com/ns/yang/Cisco-IOS-XE-native?module=Cisco-IOS-XE-native&revision=2023-03-01
The revision date matters — YANG models evolve, and a payload built against an older revision may fail against a newer one. Use pyang or Cisco’s YANG Suite to explore model structure offline.
A Note on RESTCONF vs NETCONF
RESTCONF (RFC 8040) exposes the same YANG data models over HTTP/HTTPS using JSON or XML. If your environment already has REST tooling in place, RESTCONF with Python’s requests library can be simpler for read operations:
import requests
url = "https://192.168.1.1/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet1"
headers = {"Accept": "application/yang-data+json"}
response = requests.get(url, auth=("admin", "C1sc0!"), headers=headers, verify=False)
print(response.json())
However, NETCONF remains the better choice for transactional config changes — particularly where candidate datastores, rollback-on-error, and confirmed-commit semantics matter. RESTCONF Python integration works well for read-heavy workflows; ncclient Python NETCONF is the stronger option for full config lifecycle management.
Conclusion
NETCONF YANG network automation removes the ambiguity of CLI scraping and replaces it with schema-validated, transactional configuration management. The patterns shown here — get-config, edit-config, validate, and commit — cover the majority of day-to-day automation tasks on IOS-XE and Junos. The biggest operational hurdle is understanding which YANG models a given platform version supports and at what revision; invest time in pyang and vendor YANG repositories before writing production payloads. Once your model-to-payload mapping is solid, these same Python patterns scale cleanly across dozens or hundreds of devices with minimal modification.
- NETCONF & YANG: Automate Network Configs via Python - April 2, 2026
- Palo Alto – How to Configure Your Next-Generation Firewall - April 2, 2026
- Fortinet– How to configure NTP on FortiGate - January 13, 2026
Want to become a networking expert ?
Here is our hand-picked selection of the best courses you can find online:
Cisco CCNA Certification Gold Bootcamp
Complete Cyber Security Course – Network Security
Internet Security Deep Dive course
Python Pro Bootcamp
and our recommended certification practice exams:
Delta Practice Tests