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
examples using the CLI and review their structured outputs.
parse
# 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