Automated network tests face challenges in achieving futureproofing due to the dynamic nature of networks and their evolving requirements. The pyATS library (Genie) provides the Genie Harness to execute network tests with dynamic and robust capabilities. The Genie Harness is part of the pyATS library (Genie), which is built on the foundation of pyATS. It introduces the ability for engineers to create dynamic, event-driven tests with the use of processors, triggers, and verifications. In this chapter, the following topics are going to be covered:
Genie objects
Genie Harness
Triggers
Verifications
The Genie Harness can be daunting for new users of the pyATS library (Genie), as there are many configuration options and parameters. The focus of this chapter will be to provide an overview of Genie Harness and its features and wrap up with a focus on triggers and verifications. By the end of the chapter, you’ll understand the powerful capabilities of Genie Harness and how to write and execute triggers and verifications.
Genie Objects
One of the hardest parts of network automation is figuring out how to normalize and structure the data returned from multiple network device types. For example, running commands to gather operational data (CPU, memory, interface statistics, routing state, and so on) from a Cisco IOS XE switch, IOS XR router, and an ASA firewall may have different, but similar, output. How do we account for the miniscule differences across the different outputs? The pyATS library (Genie) abstracts the details of the parsed data returned from devices by creating network OS-agnostic data models. Two types of Genie objects represent these models: Ops and Conf. In the following sections, you’ll dive into the details of each object.
Genie Ops
As you may be able to guess from the name, the Genie Ops object learns everything about the operational state of a device. The operational state data is represented as a structured data model, or feature. A feature is a network OS-agnostic data model that is created when pyATS “learns” about a device. Multiple commands are executed on a device and the output is parsed and normalized to create the structure of the feature. You can access the learned feature data by accessing <feature>.info. To learn more information about the available models, check out the Genie models documentation (https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/models). Example 9-1 shows how to instantiate an Ops object for BGP and learn the BGP feature on a Cat8000v device. Figure 9-1 shows the associated output.
Example 9-1 Genie Ops Object
from genie import testbed from genie.libs.ops.bgp.iosxe.bgp import Bgp import pprint # Load Genie testbed testbed = testbed.load(testbed="testbed.yaml") # Find the device using hostname or alias uut = testbed.devices["cat8k-rt2"] uut.connect() # Instantiate the Ops object bgp_obj = Bgp(device=uut) # This will send many show commands to learn the operational state # of BGP on this device bgp_obj.learn() pprint.pprint(bgp_obj.info)
Figure 9.1 Genie Ops Object Output
Genie Conf
The Genie Conf object allows you to take advantage of Python’s object-oriented programming (OOP) approach by building logical representations of devices and generating configurations based on the logical device and its attributes. Just like Genie Ops, the structure of Genie Conf objects is based on the feature models. The best way to describe the Conf object is by example. Example 9-2 shows how to build a simple network interface object for an IOS XE device. You’ll notice that the code is very comprehensive, specifically for a network engineer, and will even generate the configuration!
Example 9-2 Genie Conf Object
from genie import testbed from genie.libs.conf.interface.iosxe.interface import Interface import pprint # Load Genie testbed testbed = testbed.load(testbed="testbed.yaml") # Find the device using hostname or alias uut = testbed.devices["cat8k-rt2"] # Instantiate the Conf object interface_obj = Interface(device=uut, name="Loopback100") # Add attributes to the Interface object interface_obj.description = "Managed by pyATS" interface_obj.ipv4 = "1.1.1.1" interface_obj.ipv4.netmask = "255.255.255.255" interface_obj.shutdown = False # Build the configuration for the interface print(interface_obj.build_config(apply=False)) ! Code Execution Output interface Loopback100 description Managed by pyATS ip address 1.1.1.1 255.255.255.255 no shutdown exit
You may notice the last line of code actually builds the necessary configuration for you! To go one step further, you can add the interface object to a testbed device and push the configuration to a device. The Conf object allows you to drive the configuration of network devices with Python, which takes you one step further into the world of automation.