YANG Model Downloads with ncclient
Now that we have ydk-gen installed and ready to generate Python class bindings for interacting with devices via YANG models, we need to decide which models we create Python classes for. As part of this portion of the lab, we'd like to generate Python bindings based on models we download directly from the lab devices. This helps to demonstrate how the devices themselves authoritatively declare what YANG models they support, and moreover, can be used to craft the Python bindings based on their capability advertisements.
Script Name: ydk_models_get.py
For this exercise, create a new Python file in your /workspace directory called ydk_models_get.py
Imports Required
For this exercise we need re (Regular Expressions) and manager from ncclient.
import re
from ncclient import manager
We will use Python's re module for extracting model names from the capability list returned, and ncclient as the transport mechanism for mediating our YANG-based model queries to the device.
Create the ncclient manager
In order to determine what YANG models the device supports, we must first instantiate an ncclient manager instance. We will use this manager to request the capabilities listing from the devices. For this exercise we choose to use the IOS-XRv device (xr), however the same technique could be applied to any device with YANG get_schema() capabilities.
# Context manager keeping ncclient connection alive for the duration of
# the context.
with manager.connect(
host='10.2.100.12', # IP address of the XR device in your pod
port=830, # Port to connect to
username='admin', # SSH Username
password='cisco.123', # SSH Password
hostkey_verify=False # Allow unknown hostkeys not in local store
) as m: # Context manager reference, i.e. instance of connected manager
# The rest of your script code should go here.
pass
With the manager created, we will now proceed to discover YANG models that the device supports.
Collect Model Capabilities
We will now ask ncclient to poll the devices capabilities, storing these in a list for later use.
capabilities = []
# Write each capability to console
for capability in m.server_capabilities:
# Print the capability
print("Capability: %s" % capability)
# Store the capability list for later.
capabilities.append(capability)
# Sort the list alphabetically.
capabilities = sorted(capabilities)
Extract Supported Named YANG Models
Now that we have the capabilities list, we need to post-process them to extract the specific set of YANG model names that the device supports. Pay mind to the Python comment explaining the use of the regular expression.
# Sort the list alphabetically.
capabilities = sorted(capabilities)
# List of modules that we store for use later
modules = []
# Iterate server capabilities and extract supported modules.
for capability in capabilities:
# Scan the capabilities and extract modules via this regex.
# i.e., if this was the capability string:
# http://www.cisco.com/calvados/show_diag?module=show_diag&revision=2012-03-27
# then:
# show_diag
# .. would be the module printed.
# Scan capability string for module
supported_model = re.search('module=(.*)&', capability)
# If module found in string, store it.
if supported_model is not None:
# Module string was found, store it.
print("Supported Model: %s" % supported_model.group(1))
# Store the module for later use.
modules.append(supported_model.groups(0)[0])
Download the Models
For this module, we want to download the openconfig-interfaces native model schema files directly from the device. This is done as follows:
# List of models that we want to download.
# We will get the schema for each and write it to disk.
models_desired = ['openconfig-extensions', 'openconfig-interfaces']
# Iterate each desired model and write it to ./lab/models/
for model in models_desired:
# Get the model schema.
schema = m.get_schema(model)
# Open new file handle.
with open("./{}.yang".format(model), 'w') as f:
# Write schema
f.write(schema.data)
The Full Script
The full script should look as follows:
import re
from ncclient import manager
# Context manager keeping ncclient connection alive for the duration of
# the context.
with manager.connect(
host='10.2.100.12', # IP address of the XR device in your pod
port=830, # Port to connect to
username='admin', # SSH Username
password='cisco.123', # SSH Password
hostkey_verify=False # Allow unknown hostkeys not in local store
) as m: # Context manager reference, i.e. instance of connected manager
# The rest of your script code should go here.
capabilities = []
# Write each capability to console
for capability in m.server_capabilities:
# Print the capability
print("Capability: %s" % capability)
# Store the capability list for later.
capabilities.append(capability)
# Sort the list alphabetically.
capabilities = sorted(capabilities)
# List of modules that we store for use later
modules = []
# Iterate server capabilities and extract supported modules.
for capability in capabilities:
# Scan the capabilities and extract modules via this regex.
# i.e., if this was the capability string:
# http://www.cisco.com/calvados/show_diag?module=show_diag&revision=2012-03-27
# then:
# show_diag
# .. would be the module printed.
# Scan capability string for module
supported_model = re.search('module=(.*)&', capability)
# If module found in string, store it.
if supported_model is not None:
# Module string was found, store it.
print("Supported Model: %s" % supported_model.group(1))
# Store the module for later use.
modules.append(supported_model.groups(0)[0])
# List of models that we want to download.
# We will get the schema for each and write it to disk.
models_desired = ['openconfig-extensions', 'openconfig-interfaces']
# Iterate each desired model and write it to ./lab/models/
for model in models_desired:
# Get the model schema.
schema = m.get_schema(model)
# Open new file handle.
with open("./{}.yang".format(model), 'w') as f:
# Write schema
f.write(schema.data)
This full script will connect to the YANG-enabled IOS-XRv device, download it's NETCONF capability listing, extract a list of supported YANG modules using regular expressions, and then download from the device the openconfig-extensions and openconfig-interfaces .yang model definitions that we will use in a subsequent module to create Python classes via YDK.
Execute Python Script
cd /workspace
python3.6 ydk_models_get.py
After putting it all together and executing the script, you should have the openconfig-interfaces.yang and openconfig-extension.yang files in your container's workspace folder. Let's now explore one of the downloaded models.
Using the pyang Utility
The Python tool pyang is used to explore, validate, and translate yang models either user-created, cloned from public repositories, or downloaded from devices as we have done in this module.
Let us explore our downloaded openconfig-interfaces model a little with pyang. The syntax for viewing the YANG model tree using pyang is as follows:
[root@234c5dde8ad6 workspace]# pyang -f tree openconfig-interfaces.yang
So what does openconfig-interfaces actually contain?
[root@234c5dde8ad6 workspace]# pyang -f tree openconfig-interfaces.yang
module: openconfig-interfaces
+--rw interfaces
+--rw interface* [name]
+--rw name -> ../config/name
+--rw config
| +--rw type identityref
| +--rw mtu? uint16
| +--rw name? string
| +--rw description? string
| +--rw enabled? boolean
+--ro state
| +--ro type identityref
| +--ro mtu? uint16
| +--ro name? string
| +--ro description? string
| +--ro enabled? boolean
| +--ro ifindex? uint32
| +--ro admin-status enumeration
| +--ro oper-status enumeration
| +--ro last-change? yang:timeticks
| +--ro counters
| +--ro in-octets? yang:counter64
| +--ro in-unicast-pkts? yang:counter64
| +--ro in-broadcast-pkts? yang:counter64
| +--ro in-multicast-pkts? yang:counter64
| +--ro in-discards? yang:counter64
| +--ro in-errors? yang:counter64
| +--ro in-unknown-protos? yang:counter32
| +--ro out-octets? yang:counter64
| +--ro out-unicast-pkts? yang:counter64
| +--ro out-broadcast-pkts? yang:counter64
| +--ro out-multicast-pkts? yang:counter64
| +--ro out-discards? yang:counter64
| +--ro out-errors? yang:counter64
| +--ro last-clear? yang:date-and-time
+--rw hold-time
| +--rw config
| | +--rw up? uint32
| | +--rw down? uint32
| +--ro state
| +--ro up? uint32
| +--ro down? uint32
+--rw subinterfaces
+--rw subinterface* [index]
+--rw index -> ../config/index
+--rw config
| +--rw index? uint32
| +--rw name? string
| +--rw description? string
| +--rw enabled? boolean
+--ro state
+--ro index? uint32
+--ro name? string
+--ro description? string
+--ro enabled? boolean
+--ro ifindex? uint32
+--ro admin-status enumeration
+--ro oper-status enumeration
+--ro last-change? yang:timeticks
+--ro counters
+--ro in-octets? yang:counter64
+--ro in-unicast-pkts? yang:counter64
+--ro in-broadcast-pkts? yang:counter64
+--ro in-multicast-pkts? yang:counter64
+--ro in-discards? yang:counter64
+--ro in-errors? yang:counter64
+--ro in-unknown-protos? yang:counter32
+--ro out-octets? yang:counter64
+--ro out-unicast-pkts? yang:counter64
+--ro out-broadcast-pkts? yang:counter64
+--ro out-multicast-pkts? yang:counter64
+--ro out-discards? yang:counter64
+--ro out-errors? yang:counter64
+--ro last-clear? yang:date-and-time
[root@234c5dde8ad6 models]#
The pyang utility is incredibly powerful with its robust feature-set for exploring and manipulating with YANG models. We highly
encourage you to explore its documentation and capabilities here.
We will now use these downloaded schema files as the basis for the creation of the Python bindings using ydk-gen.