ncclient
NETCONF client library to make NETCONF API requestsNETCONF is an XML RPC that communicates over SSH utilizing TCP port 830. It is often used to provide an API to network devices.
Some of the features of NETCONF are:
Model-driven API would not be possible without YANG data models provided by IETF, ITU, OpenConfig, etc., and also provided by networking vendors, like Cisco, for device-specific features and functionality.
These data models define the structure of the NETCONF RPC XML data. How the YANG models are defined and utilized by developers is a larger subject we will not be covering here. What we will cover is how to get data from a network device through some exploration, then parse it and display the results.
Layer | Example |
---|---|
Content | XML Documents (XSD, YANG, etc.) |
Operations | <get-config> , <get> , <copy-config> , <commit> , <validate> , <lock> , <unlock> , <edit-config> , <delete-config> |
Messages | <rpc> , <rpc-reply> |
Protocols | SSHv2, TLS |
This data encoding is used for NETCONF XML, and you can see the operations listed as they are represented in XML. The messages being passed between the client and the device (server) are encapsulated in <rpc> ...</rpc>
and <rpc-reply> ... </rpc-reply>
.
NETCONF has this concept of data stores. For Cisco IOS XE, you can see the <running>
and <startup>
, which should look familiar. Something to keep in mind is not all platforms and devices have the <candidate>
data store.
Some key features of the data stores are:
NETCONF is a client/server type of conversation where the client makes a connection, the server responses with supported capabilities, the client sends the capabilities it supports as well as a request, then the server performs the request and issues a response. The connection can be used for additional operations until it has been disconnected.
At this point, we are going to use your local Python 3.6+. If you have not installed Python 3.6+, please refer to the linked setup instructions in the Overview.
We will be discussing the Python script in sections. As each section is discussed, copy and paste each code block in order to your script, so when we get to the end, you will have a fully functioning script.
Time to construct our Python script to get the hostname and version of the network device.
First, we need to import
the needed Python libraries.
# Include python modules
from lxml import etree
from ncclient import manager
These are the libraries we will be using in this script.
The from lxml import etree
exposes the etree
method used to work with XML data.
The from ncclient import manager
exposes the manager
method from the nclient
library. This is the NETCONF client connection manager.
# Request information
username = "developer"
password = "C1sco12345"
hostname = "sandbox-iosxe-recomm-1.cisco.com"
port = "830"
Here, we are setting some NETCONF connection-related variables.
Note: For the purpose of this exercise, we are connecting the DevNet Always On CSR 1000V Sandbox for our NETCONF request. If you are having problems connecting, please make sure the Sandbox is available.
# Make NETCONF connection
device = manager.connect(host=hostname, port=port,
username=username, password=password,
hostkey_verify=False, device_params={},
allow_agent=False, look_for_keys=False)
Now we use the manager
we imported from the ncclient
library to make the NETCONF connection, using all the variables we have previously defined.
First, we need to define the xml_filter
to get the elements we are interested in retrieving.
# Define XML Filter Request
xml_filter = """
<native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
<version />
<hostname />
</native>
"""
Now we can make the request to the device.
# Request data from device with XML Filter
netconf_response = device.get(('subtree', xml_filter))
First, we are going to print the XML that the device returned but formatted for us noncomputer types to read. The last print
statement is where the “magic” is happening. The ncclient
library holds the response in memory, and we use the lxml
etree
method to format the XML.
# Print the XML Response
print('XML Response:')
print('-' * 80)
print(etree.tostring(netconf_response.data_ele, pretty_print=True).decode('utf-8'))
Because we are dealing with XML here, we have to “find” the “hostname” and “version” in the response. But to do that, we need to define the XML namespaces to search. Here, we define the namespaces for the IOS XE native YANG model.
# Define XML Namespace for Find
ns_find = {
None: "http://cisco.com/ns/yang/Cisco-IOS-XE-native",
}
Now we can use the response object, calling the find
method on the data
to find the “hostname” and “version”.
# Find the elements we want values
device_hostname = netconf_response.data.find(".//hostname", namespaces=ns_find).text
device_version = netconf_response.data.find(".//version", namespaces=ns_find).text
It is important to note that YANG data models do define this structure. Using tools like Cisco YANG Suite, you can load the YANG models to explore the structure of the API.
# Print the results
print('-' * 80)
print(f'Hostname: {device_hostname}')
print(f'Version: {device_version}')
print("\n")
Finally, we print the hostname and version of the network device using f-string templates.
workstation $ python3 get_iosxe_version.py
XML Response:
--------------------------------------------------------------------------------
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
<native xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-native">
<version>16.9</version>
<hostname>Router</hostname>
</native>
</data>
--------------------------------------------------------------------------------
Hostname: Router
Version: 16.9
Awesome—it worked!
The complete script used today in this exercise is available for download.
While this is a simple script utilizing NETCONF API on Cisco IOS XE to get
the hostname and version, it still shows the basics of how to use Python and
the ncclient
and lxml
libraries to utilize the NETCONF API. There are a few things that can be done to extend the Python script beyond the basic demonstration in this exercise to make it more functional, but that is for a later time.
I hope this exercise was helpful and inspires you to learn more!