Genie Operational Recipes

Note

This section assumes pyATS and Genie are installed and ready to be used.

Note

It also assumes you have a testbed file ready to be used with a device.

1. Summary

Note

This section gives a summary of what is an Ops object. Dig into the documentation for more information.

Genie Ops learns everything that can be learn about a feature operational state, and pack it into 1 structured object. This structure is common for all OS.

Here are some use cases where these objects are useful:

  1. Learn all interfaces on a device and their operation state

  2. Learn any protocol state - Bgp, Ospf, Acl, Dot1x, lldp, …

  3. Device state - Platforms, linecards, …

The technology has also been used for a non-networking purpose such as:

  1. Learn website information to work with Selenium

All supported feature can be seen on our models page. Each object follows a structure which can also be seen on the same page. Take a look at the model page for the ops structure.

Here are some use cases where these objects can be used:

  1. Learn a feature and retrieve some values out of the structure.
    1. Learn Interface object and check if a particular interface is up

    2. Learn Bgp object and check if the bgp has some peer policies

  2. Learn a feature and use the Find object to navigate it
    1. Learn Ospf object and check which instances have nsr activated

    2. Learn Ospf object and check which instances have nsr activated and is connected with a particular interface.

  3. Take a snapshot of the object and compare it at a later time
    1. Take a snapshot of the Interface object. Do some modifications to some interface. Retake a snapshot and compare that the changes are as expected.

    2. Same idea as above, but make sure nothing has been modified.

  4. Take a snapshot and save it to a file. On another day, take the same snapshot and compare with the previous day snapshot. This provides assurance that your network has not changed over time.

2. Retrieve a snapshot of the Operation state of your device

Learning a device feature is now easier than ever. Ops object learns everything to know about the operation state of a device feature such as ospf, interface, etc.

This sends multiple commands on the device and creates a structure for all the information.

# The OS choices are - nxos; iosxr; iosxe - For this example, we will be
# using nxos
from genie import testbed
from genie.libs.ops.interface.nxos.interface import Interface

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)

# Find the uut device. Either the alias or the hostname of the device can
# be provided
uut = testbed.devices['uut']
uut.connect()

# Instantiate the OPS object
interface = Interface(device=uut)

# This will send many show command to learn the operational state
# of interfaces for this device
interface.learn()

import pprint
pprint.pprint(interface.info)

# The object is too big to print, here a snippet
# {'Ethernet2/1': {'auto_negotiate': False,
#                  'bandwidth': 1000000,
#                  'counters': {'in_broadcast_pkts': 0,
#                               'in_crc_errors': 0,
#                               'in_errors': 0,
#                               'in_mac_pause_frames': 0,
#                               'in_multicast_pkts': 0,
#                               'in_octets': 0,
#                               'in_pkts': 0,
#                               'in_unicast_pkts': 0,
#                               'in_unknown_protos': 0,
#                               'last_clear': 'never',
#                               'out_broadcast_pkts': 0,
#                               'out_discard': 0,
#                               'out_errors': 0,
#                               'out_mac_pause_frames': 0,
#                               'out_multicast_pkts': 0,
#                               'out_octets': 0,
#                               'out_pkts': 0,
#                               'out_unicast_pkts': 0,
#                               'rate': {'in_rate': 0,
#                                        'in_rate_pkts': 0,
#                                        'load_interval': 0,
#                                        'out_rate': 0,
#                                        'out_rate_pkts': 0}},
#                  'delay': 10,
#                  'duplex_mode': 'full',
#                  'enabled': True,
#                  'encapsulation': {'encapsulation': 'arpa'},
#                  'flow_control': {'receive': False, 'send': False},
#                  'ipv4': {'10.0.1.2/24': {'ip': '10.0.1.2',
#                                           'prefix_length': '24'}},
#                  'mac_address': '0000.0000.002f',
#                  'medium': 'broadcast',
#                  'mtu': 1500,
#                  'oper_status': 'up',
#                  'phys_address': 'fa16.3eb3.07f1',
#                  'port_channel': {'port_channel_member': False},
#                  'port_speed': '1000',
#                  'type': 'Ethernet',
#                 'vrf': 'default'},
# ...

All supported feature can be seen on our models page.

Note

More information can be found on the Ops page.

Tip

use device.learn('all') to learn all the supported features on the device, and the result will be returned in a dictionary format like: {'interface' : <Interface object at 0x7fcec85d8160>}. If an exception occurred while learning a particular feature, then featureObject will become the exception object.

3. Get partial state of a feature - command based

The above recipe learns everything about this feature by sending many commands the device. To reduce execution time, we can dictate to only learn from specific commands.

# The OS choices are - nxos; iosxr; iosxe - For this example we will be
# using nxos
from genie import testbed
from genie.libs.ops.interface.nxos.interface import Interface
from genie.libs.parser.nxos.show_interface import ShowVrfAllInterface

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']
uut.connect()

# Learn interface based only on 1 command
interface = Interface(device=uut, commands=[ShowVrfAllInterface])

interface.learn()

import pprint
pprint.pprint(interface.info)

# {'Ethernet2/1': {'vrf': 'default'},
# ...

To know which command is used for this Ops object, the code is needed to be checked. All code is hosted in git in directories pkgs/ops-pkg/src/genie/libs/ops.

4. Get partial state of a feature - Attribute based

Another way to save execution time is by providing the variables that you care about. Only the commands related to these keys will be sent and learnt.

In this recipe, we only care about the variable duplex_mode.

# The OS choices are - nxos; iosxr; iosxe - For this example, we will be
# using nxos
from genie import testbed
from genie.libs.ops.interface.nxos.interface import Interface

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']
uut.connect()

# Learn all interface which has duplex mode as a key
interface = Interface(device=uut, attributes=['info[(.*)][duplex_mode]'])

interface.learn()

import pprint
pprint.pprint(interface.info)

# {'Ethernet2/1': {'duplex_mode': 'full'},
# 'Ethernet2/2': {'duplex_mode': 'full'},
#  'mgmt0': {'duplex_mode': 'full'}}

In this case, only 2 commands out of 7 were sent to the device. This can be massive time saver.

All supported feature and their variable structure can be seen on our models page. All of them are to be used in the same way.

Note

More information can be found on the Ops page - Extra features.

5. Use Ops object to verify state is as expected.

A great feature of Ops is the built-in verify mode. Learn a feature and verify if it’s as expected. If it is not then sleep for sometime and try again. This is very useful after doing some actions on the device and expecting the device to take some time to stabilize.

# The OS choices are - nxos; iosxr; iosxe - For this example, we will be
# using nxos
from genie import testbed
from genie.libs.ops.interface.nxos.interface import Interface

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']
uut.connect()

def verify_interface_status(obj):
    # Interface object that was learnt
    # Let's verify that at least one interface is up
    for intf in obj.info:
        if obj.info[intf].get('oper_status', None) and\
           obj.info[intf]['oper_status'] == 'up':
            return
    # If no interface was found to have an up oper_status, then
    # raise an exception
    raise Exception("Could not find any up interface")

# Learn all interface which has duplex mode as a key
interface = Interface(device=uut)

# Try to verify up to 6 times that at least one interface is up
# with sleep of 5 seconds between each attempt
interface.learn_poll(verify=verify_interface_status, sleep=5, attempt=6)

Note

More information can be found on the Ops page - Polling.

6. Compare two feature snapshots - Diff two ops object.

Want to know if the state of your network has changed over time? Take snapshots at a different time, and compare them!

# The OS choices are - nxos; iosxr; iosxe - For this example, we will be
# using nxos
from genie import testbed
from genie.libs.ops.interface.nxos.interface import Interface

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']
uut.connect()

# Learn all interface
interface = Interface(device=uut)

interface.learn()

# Let's modify one of the interface, so we can demonstrate the comparison
# Find an up interface
for intf in interface.info:
    if interface.info[intf].get('oper_status', None) and\
       interface.info[intf]['oper_status'] == 'up':
       up_interface = intf
       break
else:
    # No up interface
    raise Exception("Could not find any up interface")

uut.configure('''\\\
interface {intf}
 shut'''.format(intf=up_interface))

# let's take a new snapshot now and compare
interface_after = Interface(device=uut)

interface_after.learn()

import pprint
pprint.pprint(interface.info)
diff = interface_after.diff(interface)
print(diff)

# info:
#  loopback1:
# +  enabled: False
# -  enabled: True
# +  oper_status: down
# -  oper_status: up

uut.configure('''\\\
interface {intf}
 no shut'''.format(intf=up_interface))

This opens up the possibility of Testing and Assurance to the next level! This allows the script to check at any point if any part of the operational state has changed.

Note

More information can be found on the Ops page - Diff.

7. Save snapshot to file, and re-use them at a later time

The previous recipe is perfect for within script comparison. This recipe allows to save the object as a file, and compare it at a later date. Perfect for a weekly check of the operation state of your devices,

# The OS choices are - nxos; iosxr; iosxe - For this example, we will be
# using nxos
from genie import testbed
from genie.libs.ops.interface.nxos.interface import Interface

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']
uut.connect()

# Learn all interface
interface = Interface(device=uut)

interface.learn()
with open(file, 'wb') as f:
    f.write(interface.pickle(interface))

Then at a later time, you can do

from genie.ops.base import Base

with open(file, 'rb') as f:
    interface = Base.unpickle(f.read())

Then once you get the object, you can do a normal comparison.

Note

More information can be found on the official python documentation.

Note

More information can be found on the Ops page - Diff.

8. Connection pool with Ops - Learn Faster!

Your time is valuable, hence Genie provides asynchronous execution methodology! With the new connection pool mechanism, learning a feature can be done much faster. Commands are sent in parallel to the device providing exceptional performance.

# The OS choices are - nxos; iosxr; iosxe - For this example, we will be
# using nxos
from genie import testbed
from genie.libs.ops.interface.nxos.interface import Interface

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']

# With connection pool, its important to provide an alias. More information
# on this in the note below.
uut.start_pool(alias='a', size = 1)

# Learn all interface
interface = Interface(device=uut)

interface.learn()

To fully utilize this functionality, a management port should be used which can accept multiple connections.

devices:
  nx-osv-1:
      alias: 'uut'
      type: 'Nexus'
      os: 'nxos'
      tacacs:
          login_prompt: "login:"
          password_prompt: "Password:"
          username: "admin"
      passwords:
          tacacs: Cisc0123
          enable: admin
          line: admin
      connections:
          defaults:
            class: 'unicon.Unicon'
          a:
              protocol: telnet
              ip: "172.25.192.90"
              port: 17052
          vty:
              protocol: telnet
              ip: "10.1.1.2"

The vty connection has been added to connect to the management port of the device.

# Same as earlier
# ...
uut.start_pool(alias='vty', size = 10)

# Learn all interface
interface = Interface(device=uut)

Connection pool increases the performance of Ops by using multiple connections to the device.

Note

More information can be found on the Connection pool documentation.

Note

More information can be found on the Ops page - Pool connection.

9. One script across all platform! - abstract package

In an earlier recipe, we’ve used this kind of import

from genie.libs.ops.interface.nxos.interface import Interface

Why not have one script which works across all devices? Not a dream anymore! With Genie.abstract and Genie.ops you write it once for all platforms.

from genie import testbed
# Import the main level of the library
from genie.libs import ops
# Import Abstract library
from genie.abstract import Lookup

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']
uut.start_pool(alias='vty', size = 10)

lookup = Lookup.from_device(uut)
Interface = lookup.ops.interface.interface.Interface
# Interface is now -> <class 'genie.libs.ops.interface.nxos.interface.Interface'>
# More information on this below

interface = Interface(uut)
interface.learn()

Abstract will look for the device os and find the corresponding library. As Ops structure are identical across all platforms, the same script can be used!

Amazed enough?! Here is even better news!

For ops we can use the newly implemented get_ops API which returns the abstracted ops class without even calling Lookup as above.

# import testbed and get_ops
from genie import testbed
from genie.ops.utils import get_ops

# Load Genie testbed
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']
uut.connect()

# Get the Ops objecet
Interface = get_ops('interface', uut)

# Learn all interfaces
interface.learn()

Note

More granular abstract can be provided if needed.

10. One script across all Interface management (Cli/Yang/Xml/…)

Following the same design as the previous recipe, the same concept is applied for different interface management.

from genie import testbed
# Import the main level of the library
from genie.libs import ops
# Import Abstract library
from genie.abstract import Lookup

# Load Genie testbed which contains a Xml connection
# With xml added in the abstraction section
testbed = testbed.load(testbed=<path of testbed file>)
uut = testbed.devices['uut']
# This is needed only when multiple interface management are used.
uut.mapping['cli'] = 'vty'
uut.mapping['xml'] = 'vty'
uut.start_pool(alias='vty', size = 10)

lookup = Lookup.from_device(uut)
bgp = lookup.ops.bgp.bgp.Bgp
# Bgp is now -> <class 'genie.libs.ops.bgp.nxos.xml.bgp.bgp'>

bgp = Bgp(uut)
Bgp.learn()

Example of Testbed file with Xml Support. Same idea for all the context interface management.

devices:
  nx-osv-1:
      alias: 'uut'
      type: 'Nexus'
      os: 'nxos'
      tacacs:
          login_prompt: "login:"
          password_prompt: "Password:"
          username: "admin"
      passwords:
          tacacs: Cisc0123
          enable: admin
          line: admin
      connections:
          defaults:
            class: 'unicon.Unicon'
          vty:
              protocol: telnet
              ip: "172.25.192.90"
      custom:
        abstraction:
          order: [os, context]
          context: 'xml'

This will send all the supported commands using XML, and the rest will be sent using Cli and merged together.

12. Where are the object models located?

All the objects models are displayed on our models page.

13. How to contribute

To contribute to the code of Genie, take a look at our commit guideline!

To contribute to the Ops object models, visit the opsOps contribution page.

14. Get exclude keys for an ops object

from genie.ops.utils import get_ops_exclude
get_ops_exclude('interface', dev)
['in_discards', 'in_octets', 'in_pkts', 'last_clear', 'out_octets', 'out_pkts', 'in_rate', 'out_rate', 'in_errors', 'in_crc_errors', 'in_rate_pkts', ...]