pyATS Genie parsers are a set of pre-built data parsers designed to transform raw CLI command outputs into structured Python dictionaries. These parsers eliminate the need for complex manual text parsing with regular expressions, allowing for easier data access and processing in automation workflows.

pyATS Genie Parsers Fndamental

"pyATS Learn" vs. "pyATS Parse"

The first question is: What is the difference between the „pyats learn“ and „pyats parse“ commands?

The “pyats learn” command is used to collect structured data about various device features, such as BGP. When you use “pyats learn bgp”, it runs multiple predefined BGP-related commands and aggregates their outputs into a structured format. This is commonly used to take snapshots of a device’s state, which can later be compared with other snapshots for troubleshooting and change tracking.

On the other hand, the “pyats parse” (or “genie parse”) command is used to convert the output of a single CLI command into a structured Python dictionary. Instead of manually parsing text using regular expressions, you can access command output components in an automation-friendly format.

For example, if you run pyats parse “show version”, Instead of receiving raw CLI output, you get structured data that can be easily processed by automation scripts.

Aspect pyats learn pyats parse
What it does Collects data from many commands Structures one command’s output
Example pyats learn bgp pyats parse "show version"
Output Structured data (feature-level) Structured data (single command)
Best for Snapshots, troubleshooting Automation, scripting
...
    },
    "os": "IOS-XE",
    "platform": "Virtual XE",
    "processor_type": "VXE",
    "returned_to_rom_by": "reload",
    "rom": "IOS-XE ROMMON",
    "rtr_type": "CSR1000V",
    "system_image": "bootflash:packages.conf",
    "uptime": "16 weeks, 4 days, 23 hours, 16 minutes",
    "uptime_this_cp": "16 weeks, 4 days, 23 hours, 18 minutes",
    "version": "17.1.1",
    "version_short": "17.1",
    "xe_version": "17.01.01"
  }
...

Supported Parsers in Cisco pyATS Genie framework

This is a list of parsers supported by the Genie framework in pyATS, covering approximately 20 different vendors and operating systems. These include IOS, IOSXE, IOSXR, NXOS, and ASA from Cisco devices, JUNOS from Juniper devices, as well as BIG-IP and Linux, among others.

If you review the commands supported by each of these operating systems, you’ll find that the most important ones are covered. This means that Cisco has already provided structured versions of the outputs for all these commands.

pyats parse examples using cli

The pyats parse command can be executed using either the CLI or an automation script.

Ensure that the testbed is properly prepared before executing these commands. Here is my testbed file.

(majid) root@majid-ubuntu:/home/majid/devnet/pyats# cat testbed.yaml
---
devices:
  R1:
    connections:
      cli:
        ip: 192.168.2.91
        protocol: ssh
    credentials:
      default:
        password: rayka-co.com
        username: rayka
    os: iosxe
    type: iosxe
  R2:
    connections:
      cli:
        ip: 192.168.2.92
        protocol: ssh
    credentials:
      default:
        password: rayka-co.com
        username: rayka
    os: iosxe
    type: iosxe

Let’s first explore some pyats
parse
examples using the CLI and review their structured outputs.

# Parse "show version" command output using pyATS with a testbed file
pyats parse "show version" --testbed-file testbed.yaml
# Parse "show version" command output using Genie (pyATS) with a testbed file
genie parse "show version" --testbed-file testbed.yaml
# Parse "show interfaces" output for device R1 and save the result to a specified output directory
pyats parse "show interfaces" --testbed-file testbed.yaml --devices R1 --output show_interfaces/
# Parse "show version" output for device R1 and save the result to a specified output directory
pyats parse "show version" --testbed-file testbed.yaml --devices R1 --output show_version/

And finally, this is the last CLI-based example, which parses the output of the “show ip interface brief” command along with its corresponding structured output.

# Parse "show ip interface brief" output for device R1 and save the result to a specified output directory
pyats parse "show ip interface brief" --testbed-file testbed.yaml --devices R1 --output show_ip_interface_brief/
(majid) root@majid-ubuntu:/home/majid/devnet/pyats# pyats parse "show ip interface brief" --testbed-file testbed.yaml --devices R1 --output show_ip_interface_brief/
  from pyats.cli.__main__ import main
100%|███████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  1.66it/s]
+==============================================================================+
| Genie Parse Summary for R1                                                   |
+==============================================================================+
|  Connected to R1                                                             |
|  -  Log: show_ip_interface_brief//connection_R1.txt                          |
|------------------------------------------------------------------------------|
|  Parsed command 'show ip interface brief'                                    |
|  -  Parsed structure: show_ip_interface_brief//R1_show-ip-interface-         |
| brief_parsed.txt                                                             |
|  -  Device Console:   show_ip_interface_brief//R1_show-ip-interface-         |
| brief_console.txt                                                            |
|------------------------------------------------------------------------------|
(majid) root@majid-ubuntu:/home/majid/devnet/pyats# cat show_ip_interface_brief/
connection_R1.txt                         R1_show-ip-interface-brief_exception.txt
R1_show-ip-interface-brief_console.txt
(majid) root@majid-ubuntu:/home/majid/devnet/pyats# cat show_ip_interface_brief/R1_show-ip-interface-brief_parsed.txt
{
  "_exclude": [
    "method",
    "(Tunnel.*)"
  ],
  "interface": {
    "GigabitEthernet1": {
      "interface_is_ok": "YES",
      "ip_address": "10.13.14.16",
      "method": "manual",
      "protocol": "up",
      "status": "up"
    },
...

pyats parse Example using Python Script

The primary use of Cisco pyATS Genie parsers is in network automation. Essentially, your script executes specific commands on network devices and then processes the structured output based on key-value pairs. This allows you to take automated actions in your script.

Parsing commands programmatically is crucial for automation. To demonstrate this, I have prepared a Python script that runs the show ip route command on testbed devices and retrieves the structured output.

import json
from genie.testbed import load

# Load the testbed file
testbed = load("testbed.yaml")

# Get all devices from the testbed
devices = testbed.devices

# Iterate over each device and parse any supported commands
for device_name, device in devices.items():
    print(f"Connecting to {device_name}...")
    # Connect to the device
    device.connect(log_stdout=False)

    # Parse any supported commands
    #parsed_output = device.parse("show ip interface brief")
    #parsed_output = device.parse("show version")
    parsed_output = device.parse("show ip route")
    #parsed_output = device.parse("show ip ospf neighbor")

    parsed_output_json = json.dumps(parsed_output,indent=2)

    # Print the parsed output
    print(f"Parsed output for {device_name}:")
    print(parsed_output_json)


    try:
        routes = parsed_output["vrf"]["default"]["address_family"]["ipv4"]["routes"]

        print(f"\nRoutes Lists for {device_name}:")
        for route, details in routes.items():
            print(f"- Route: {route}")
    except KeyError:
        print("Error: Some expected keys are missing in the parsed output.")


    print("\n")

    # Disconnect from the device
    device.disconnect()
Connecting to R1...
Parsed output for R1:
{
  "vrf": {
    "default": {
      "address_family": {
        "ipv4": {
          "routes": {
            "0.0.0.0/0": {
              "route": "0.0.0.0/0",
              "active": true,
              "metric": 0,
              "route_preference": 1,
              "source_protocol_codes": "S*",
              "source_protocol": "static",
              "next_hop": {
                "next_hop_list": {
                  "1": {
                    "index": 1,
                    "next_hop": "10.13.14.1"
                  }
                }
              }
            },
...
Connecting to R2...
Parsed output for R2:
{
  "vrf": {
    "default": {
      "address_family": {
        "ipv4": {
          "routes": {
            "0.0.0.0/0": {
              "route": "0.0.0.0/0",
              "active": true,
              "metric": 0,
              "route_preference": 1,
              "source_protocol_codes": "S*",
              "source_protocol": "static",
              "next_hop": {
                "next_hop_list": {
                  "1": {
                    "index": 1,
                    "next_hop": "10.13.14.1"
                  }
                }
              }
            },
...

To highlight the benefits of structured data, I further process the output to extract only the list of routes, making it easier to work with the data efficiently.

Routes Lists for R1:
- Route: 0.0.0.0/0
- Route: 1.1.1.1/32
- Route: 2.2.2.2/32
- Route: 10.10.10.10/32
- Route: 10.13.14.0/24
- Route: 10.13.14.16/32
- Route: 10.13.15.0/24
- Route: 10.13.15.16/32
- Route: 10.13.24.0/24
- Route: 10.13.24.110/32
- Route: 192.168.200.0/24
- Route: 192.168.200.200/32
Routes Lists for R2:
- Route: 0.0.0.0/0
- Route: 1.1.1.1/32
- Route: 2.2.2.2/32
- Route: 4.2.2.4/32
- Route: 8.8.8.8/32
- Route: 10.10.10.10/32
- Route: 10.13.14.0/24
- Route: 10.13.14.17/32
- Route: 10.13.15.0/24
- Route: 10.13.15.17/32
- Route: 10.13.24.0/24
- Route: 10.13.24.111/32
- Route: 192.168.200.0/24
Back to: Network Automation with pyATS & Genie (in Progress) > pyATS Introduction

Leave a Reply

Your email address will not be published. Required fields are marked *


Post comment