pyATS series - Parsing like a pro

9 minutes read

pyats_hello2.jpg

Introduction

Ever dreamed of a test framework that could be used across multiple platforms, OS and vendors, which could do regression, sanity and feature testing; already used by thousands of engineers and developers worldwide? Guess what, it exists, it’s free, and you can start using it right now!

pyATS (Python Automated Test Systems, to be pronounced “py A. T. S.”) was first created as an internal project, to ease the validation of two OS versions. It has been made public in 2017 through Cisco Devnet.

This blog post will be the second one of a series on pyATS. Today, we will explore pyATS libraries (also known as Genie), and we will collect our first parsed output. More use cases are going to be covered in the next posts.

Other pyATS episodes

You’ve missed the first episode? You would like to read more? Below the list of published episodes:

EpisodeURLWhat’s covered
1 - Install and use pyATSLinkWhat’s pyATS, Install pyATS, Collect a raw CLI output
2 - Parsing like a proLinkExplore pyATS libraries, Collect and parse a CLI output
3 - Be a modelLinkWhat a pyATS model and when to use it

pyATS librairies overview

pyATS building blocks

pyATS is made of three main building blocks:

  • pyATS, the core block of this ecosystem. It’s a Python framework which leverages multiple Python libraries such as Unicon, providing a simplified connection experience to network devices. It supports CLI, NETCONF, RESTCONF and gRPC. It enables network engineers and developers to start with small and simple test cases.
  • pyATS libraries (also known as Genie) which provides everything you need for network testing such as parsers, triggers and APIs.
  • XPRESSO, the pyATS Web UI Dashboard.

You can read more about pyATS ecosystem in the official documentation.

pyATS libraries are the pyATS SDK (Software Development Kit, a big toolbox) which contains all the tools that you need for Network Test Automation. It has been used internally at Cisco since 2010 for our automated testing. Yes! You can use the same tools that we use to automate the validation of your network.

You can read more about pyATS librairies in the official documentation.

pyATS libraries in a nutshell

  • 2800+ parsers accross 11 OS (as of April 2021),
  • 32 supported models (more to come about them in a coming episode),
  • Multiple tools for Test Harness such as triggers or traffic,
  • Ansible and Robot libraries for easy integration with other tools.

You can find supported parsers and models in the official documentation.

Getting your hands dirty

Enough talking, let’s code!

keyboard cat_small2.png

pyATS installation has been covered in the First episode. Check it out to learn how to install pyATS.

Parsing a CLI output from a device

In the first use case, we saw how we can get a simple CLI output (show ip interface brief) from an IOS XR device.

In this second use case, we are going to see how we can collect and parse a CLI output (show ip interface brief).

In order for everyone to be able to run the code, we will use the IOS XR always-on sandbox on Cisco Devnet. Feel free to adapt the code to use your own device(s). Below the sandbox information.

KeyValue
IOS XRv 9000 hostsbx-iosxr-mgmt.cisco.com
SSH Port8181
Usernameadmin
PasswordC1sco12345

Building a testbed

The simplest way to connect to a device is through a pyATS testbed file, written in YAML. This information will be used by Unicon to connect to the device and send the requested commands.

You can find the complete documentation on how to build a testbed here.

testbed.yaml

# Step 0: list of devices
devices:
  iosxr1:
    # Step 1: OS and Type
    type: iosxr-devnet
    os: iosxr
    # Step 2: credentials
    credentials:
      default:
        username: admin
        password: C1sco12345
    # Step 3: connection parameters
    connections:
      vty:
        protocol: ssh
        ip: sbx-iosxr-mgmt.cisco.com
        port: 8181

The testbed.yaml file is available here.

The testbed construction has been covered in the First episode. Have a look to understand how to build a testbed from scratch

Raw output vs Parsed output

Now, you know how to get a CLI output using pyATS. Getting a specific information in this big text output is easy for a human; but what about a computer? You got it, that’s the power of the pyATS libraries: converting this raw output (string) into a parsed output (dictionary) where you can easily get a value by accessing a specific key.

raw_parsed_output_small.png

Let’s take an example. Below the CLI output you would get by typing show ip interface brief.

Raw CLI output


Interface                      IP-Address      Status          Protocol Vrf-Name
Loopback100                    1.1.1.100       Up              Up       default 
Loopback200                    1.1.1.200       Down            Down     Red 

And now, the same output, of the same CLI command show ip interface brief, parsed with pyATS libraries. Note that you can see the exact same information compared to the raw output above. Nothing more, nothing less.

Parsed CLI output


{
    "interface": {
        "Loopback100": {
            "ip_address": "1.1.1.100",
            "interface_status": "Up",
            "protocol_status": "Up",
            "vrf_name": "default",
        },
        "Loopback200": {
            "ip_address": "1.1.1.200",
            "interface_status": "Down",
            "protocol_status": "Down",
            "vrf_name": "Red",
        }
}

Collecting and parsing your first CLI output with pyATS libraries

Now that we understand the difference between a raw output (a string) and a parsed output (a dictionary), let’s look at the code. This script will collect a parsed output of the show ip interface brief command. It will extract the interface name and the interface ip address from the dictionary, then print each couple. The script will be further detailed and explained below.

1_parsed_output.py

# New module! Now using Genie!
from genie import testbed

# Step 0: load the testbed
testbed = testbed.load('./testbed.yaml')

# Step 1: testbed is a dictionary. Extract the device iosxr1
iosxr1 = testbed.devices["iosxr1"]

# Step 2: Connect to the device
iosxr1.connect(init_exec_commands=[], init_config_commands=[], log_stdout=False)

# Step 3: saving the `show ip interface brief` output in a variable
show_interface = iosxr1.parse('show ip interface brief')

# Step 4: iterating through the parsed output. Extracting interface name and IP
for interface in show_interface['interface']:
    print(f"{interface} -- {show_interface['interface'][interface]['ip_address']}")

# Step 5: disconnect from the device
iosxr1.disconnect()

The 1_parsed_output.py file is available here.

Executing the script

From your bash terminal


python 1_parsed_output.py

In this example, the testbed.yaml file need to be in the same folder as the 1_parsed_output.py file. Also, you need to execute the Python script in the folder where you have these two files.

Let’s now explain the building blocks of the Python script. The parts below will refer to each inline comment of the code block above.

Output example

Here is an output example of the above script. It might slightly vary according to the configuration of the device.

Python console


Loopback333 -- 3.3.3.3
Loopback99 -- 99.99.99.99
Loopback11 -- 1.2.3.1
GigabitEthernet2 -- Unassigned
GigabitEthernet1 -- 10.10.20.48
GigabitEthernet3 -- Unassigned

Step 0: load the testbed

From the genie module, we import the testbed.load() function. This function will be used to load the testbed file we have created.

We load the testbed information, stored in our testbed.yaml file. We assign it to an object: testbed.

Step 1: extract device information

testbed is a Python dictionary. We are extracting the device iosxr1 information. We assign it to an object: iosxr1.

You can name the object with the name you want. The object name does not need to match the hostname of you device.

Step 2: connect to the device

We use the connect() method on the iosxr1 object to connect to the device.

By default, pyATS will send exec and configuration commands to the device (such as terminal length 0 and show version). To avoid such behavior, we are passing arguments to the conect() method. We are also disabling the logging to standard output. More information in the [documentation].(https://pubhub.devnetcloud.com/media/unicon/docs/user_guide/connection.html)

Step 3: save the "show ip interface brief" output in a variable

This step is the most important step in our script. It will collect the show ip interface brief output and parse it. Each information of the CLI output will be mapped either as a dictionary key or a value. There should be no entropy loss between the raw CLI output and the parsed output.

To do so, we are using the parse() method on the device object. The parse method takes a string as parameter, which is the IOS XR command we would like to collect and parse. We are saving this parsed output in a variable show_interface.

You can find all available pyATS parsers in the [documentation].(More information in the documentation.

A parsed output example (i.e. the dictionary saved in the variable show_interface) can be seen in Step 4.

Step 4: Python logic to print interface name and IP

Below an example of parsed output for the show ip interface brief command. Most interfaces are missing, for conciseness.

Parsed CLI output


{
    "interface": {
        "Loopback100": {
            "ip_address": "1.1.1.100",
            "interface_status": "Up",
            "protocol_status": "Up",
            "vrf_name": "default",
        },
        "Loopback200": {
            "ip_address": "1.1.1.200",
            "interface_status": "Down",
            "protocol_status": "Down",
            "vrf_name": "Red",
        }
}

In the above output, we have a list of interfaces: Loopback100 and Loopback200. We are iterating through this list. For each interface, we are accessing the ip_address value. We’re then printting the interface name and IP.

It might not be useful in a real life use case. Goal here is to take a concise example, to show how easy it is to extract values of a CLI output when parsed with pyATS libraries.

Step 5: disconnect from the device

We use the disconnect() method to properly disconnect from the device.

It’s important to properly disconnect from the device, otherwise the vty connection will remain open on the device, until it times out.

Conclusion

In this second episode of the pyATS series, we learnt:

  • The difference between a raw and parsed output,
  • Why pyATS libraries are powerful,
  • How to collect and parse a CLI output from a device,
  • How to get a value from a parsed output.

In the next post, we will learn what’s a Model, why it’s powerful when parsing from multiple OS at once and how to use them.

The code used for each blog post can be found here. This link will include the code for all posts.

Resources

Below a few useful pyATS resources.

Leave a Comment