Utilizing NSO with pyATS Parsers to Test Operational State



This weblog is authored by Rodolphe Trujillo,
Cisco Buyer Supply Engineering Technical Chief

One of many difficult matters of community automation is to check the routers to see if their present operational state match the anticipated operational state. Or, within the case you might be altering configuration, evaluate pre-operational states with post-operational states.

The normal manner for community engineers to do that is to make use of the CLI. We discover the info returned on the display screen… retrieve the related states, counters… and put them in an Excel doc. As there are lots of of these states and counters, verifications change into tough if the operation has plenty of checks. Furthermore when you have all these checks multiplied by numerous gadgets, it’s unattainable to cowl with out automation.

You may have a number of methods to automate checks in your community. You should use customized scripts, open supply options like Netmiko or Ansible. Alternatively, you should utilize pyATS, which is an excellent testing framework from Cisco.

The goal of this put up is to indicate a solution to automate checks with NSO and create an Excel doc for audit.
This isn’t THE solution to do it, simply A manner, however I’ve utilized it on hundreds of gadgets and run hundreds of thousands of checks with an analogous technique because the one introduced right here.

Together with NSO I may also use the pyATS parser. Traditionally, I used to be utilizing TextFSM home made templates for doing the parsing a part of my workflow. Nevertheless, I are likely to progressively migrate to the very wealthy parsers record of pyATS.

Be aware: The code supplied solely works with CLI NEDs and Cisco gadgets.

On the Python set up operating alongside your NSO let’s set up some libraries I’ve ready for this demonstration :

pip set up pyats-parser

This library, as described within the documentation, carry the ability of the large PyATS parsers assortment to each piece of python you may write, the draw back is, due to dependencies, you’ll have to set up all of the PyATS libraries and never solely the parsing half.

pip set up nso-live-status

In reality, you may immediately set up this library as a result of it will depend on pyats-parser to run. So, pyats-parser shall be put in routinely. NSO-live-status is a wrapper to the dwell standing of NSO, and I wished to have a handy operate:

run_live_status(root_nso_object, machine, str_cli_command)

Not solely will this operate execute the dwell standing, but when the command is acknowledged by pyATS it is going to be parsed and the thing returned will include a structured output.

pip set up nso-restconf

This shall be helpful for manipulating NSO by means of the Restconf API. Lastly, the favored openpyxl for producing excel paperwork:

pip set up openpyxl

For this instance we are going to merely verify the model of IOS-XR to see if it match a goal model.

I’ve ready a NSO Package deal which can be utilized as a “checks beginning pack” at: https://github.com/rtrjl/check_device, so all you need to do is:

git clone [email protected]:rtrjl/check_device.git

in your NSO packages listing, and

cd check_device
cd src
make clear

within the NSO CLI session:

# packages reload

As soon as the package deal reload is completed, we are able to strive the motion within the NSO CLI session:

# check_device check_version machine Paris-75 target_version 7.5.1
check_status NOK
check_message [check_version] Present model 7.3.2 would not match the 
goal model 7.5.1 on the machine Paris-75

You now have an motion to verify the model and you may name it with the CLI which is good, however NSO carry a really highly effective built-in function with an auto-generated RESTConf API on prime of all of your actions and providers.
Utilizing this RESTConf API we are able to launch the checks on a set of gadgets:

import json
from nso_restconf.restconf import RestConf

from concurrent.futures import ThreadPoolExecutor, as_completed

nso_api = RestConf(tackle="", port=8080,
                   username="admin", password="admin")
# for the instance credentials are within the code :-)
devices_list = ["Kiev-47",
#the numbers haven't any significations they're simply the final bytes of the IP of the routers on the lab I take advantage of.

def nso_check_version(machine, target_version):
    information = json.dumps({'enter': {'machine': f"{machine}", "target_version": f"{target_version}"}})
    outcome = nso_api.motion(information, "check_device/check_version")
    return outcome.json()

The script ought to print one thing like this:

{'check_device:output': {'machine': 'Kiev-47', 'current_version': '7.3.2', 'operating_system': 'IOSXR', 'check_status': 'NOK', 'check_message': "[check_version] Present model 7.3.2 would not match the goal model 7.5.1 on the machine Kiev-47"}}
{'check_device:output': {'machine': 'Madrid-40', 'current_version': '7.3.2', 'operating_system': 'IOSXR', 'check_status': 'NOK', 'check_message': "[check_version] Present model 7.3.2 would not match the goal model 7.5.1 on the machine Madrid-40"}}
{'check_device:output': {'machine': 'Napoli-50', 'current_version': '7.3.2', 'operating_system': 'IOSXR', 'check_status': 'NOK', 'check_message': "[check_version] Present model 7.3.2 would not match the goal model 7.5.1 on the machine Napoli-50"}}
{'check_device:output': {'machine': 'Paris-66', 'current_version': '7.3.2', 'operating_system': 'IOSXR', 'check_status': 'NOK', 'check_message': "[check_version] Present model 7.3.2 would not match the goal model 7.5.1 on the machine Paris-66"}}
{'check_device:output': {'machine': 'Riga-46', 'current_version': '7.3.2', 'operating_system': 'IOSXR', 'check_status': 'NOK', 'check_message': "[check_version] Present model 7.3.2 would not match the goal model 7.5.1 on the machine Riga-46"}}
{'check_device:output': {'machine': 'Stuttgard-64', 'current_version': '7.3.2', 'operating_system': 'IOSXR', 'check_status': 'NOK', 'check_message': "[check_version] Present model 7.3.2 would not match the goal model 7.5.1 on the machine Stuttgard-64"}}

The script is operating effectively. Nevertheless, with this strategy it may take a whole lot of time as a result of it can connect with gadgets one after the opposite. It is going to be nice on a small community however on an even bigger one…?

Let’s use threads to speed up the method:

from concurrent.futures import ThreadPoolExecutor, as_completed

processes = []
with ThreadPoolExecutor(max_workers=10) as executor:
    for machine in devices_list:
    processes.append(executor.submit(nso_check_version, machine, "7.5.1"))

for activity in as_completed(processes):

The identical output because the sequential one shall be printed however on this model we leverage one other attention-grabbing function of NSO:
gadgets might be reached in parallel to run present instructions, with limits , it can rely on the quantity of RAM on the server on which NSO is put in, however we are able to run 10 staff with out issues.

Now we now have retrieved the checks we are able to put the ends in a great outdated excel doc:

checks_list = []
for activity in as_completed(processes):
    outcome = activity.outcome()["check_device:output"]
    checks_list.append([result["device"], outcome["operating_system"], outcome["current_version"], outcome["check_status"], outcome["check_message"]])

from openpyxl import Workbook

wb = Workbook()
ws = wb.lively
headers = ["Device", "OS", "OS version", "Check status", "Check message"]
for information in checks_list:

Actions pyATS

On this demo we now have checked out completely different matters similar to:

  • utilizing pyATS parsers with NSO
  • doing NSO dwell standing (present instructions) in parallel leveraging the auto-generated RESTCONF API
  • writing a verify utilizing actions in NSO

Discover the pyATS parsers web page and picture all of the checks you are able to do. 🙂