TAGS: | |

Reimagining ‘Show IP Interface Brief’

John Capobianco

Welcome back! In my first post here on Packet Pushers (Applying A Software Design Pattern To Network Automation – Packet Pushers) we explored the Model View Controller (MVC) software design pattern and how it can be applied to network automation.

This post will go a little deeper into how this is achieved and the mix of Python tools I’ve used to develop this solution. To help you connect the theory and concepts from the initial post, I’ll take an everyday, popular CLI command – show ip interface brief – and “modernize it” using the MVC approach and the Django framework.

For reference; ”the old way”

Planning

I always like to write a high-level outline of the approach, sort of light pseudo-code, that I will then translate into Python.

  • Secure, agentless, connectivity to our device(s).
  • Capture the show ip interface brief command output.
  • Transform the output from unstructured, standard CLI output, to structured JavaScript Object Notation.
  • Populate the database with the network state.
  • Present the network state to the stakeholders in business-ready documents.

The Tools

Here are the various frameworks and libraries in the toolkit:

  • VS Code (IDE) + Extensions (PostgreSQL browser; Django; Python)
  • Django (MVC framework)
  • Django REST Framework (REST API)
  • PostgreSQL (database)
  • pyATS Framework (connectivity and test harness)
  • pyATS Libraries (parsing)
  • Celery / Beat / Redis (scheduling)
  • Data tables (datatables.net)
  • Bootstrap (spinners)
  • Some web tools like basic HTML, JavaScript (JS), Cascading Style Sheets (CSS), and AJAX

Network Connectivity And Traditional pyATS

Traditionally, pyATS tests (jobs) are performed against a “testbed”; that is, a YAML file that contains a representation of the network topology. For example, the Cisco DevNet Nexus 9000 Sandbox’s testbed.yaml file would look like this:

The dreaded YAML file format

With this simple testbed file, we can use the pyATS command-line interface (yes there is a CLI available) against the topology.

Which provides us with the CLI output parsed into JavaScript Object Notation (JSON):

The soothing JSON format

As a side note, I would argue that the modern network engineer is much better suited keeping a testbed.yaml file instead of a bunch of saved Putty sessions in this day and age. Most of the common CLI commands have parsers and you need not SSH directly to the device any longer.

YAML-Free With PostgreSQL

In the first article you saw the devices model and how we migrated the model into a PostgreSQL table using Django. In order to go YAML-free, we can manually, on-demand, build a dynamic testbed. This gets a little more advanced, but if you look up pyATS manual topology in their documentation (Creating Topology — pyATS Documentation (devnetcloud.com)) you’ll find this:

Remember, we have allowed our users to populate a database table with all the necessary information to build, dynamically, and Pythonically, a testbed from this table. Inside our show_ip_interface_brief_job.py file – the pyATS job itself – we can query the database and pass along the dynamic testbed to the show_ip_interface_brief.py primary pyATS logic.

device_list now contains “all” devices

Testbed now contains all of the necessary keys, from the database, to run a pyATS job

Now, moving to the actual Python logic, we first have to connect to the devices using the AETest library.

Testbed.connect actually spawns SSH sessions against the devices in the dynamic testbed

Next, we want to set up our tests; in this case can we parse the CLI Command successfully, in a loop (every device in the testbed).

In a loop for each device in the database table – do something

Now that we are connected to the topology and inside our per-device loop we can actually perform the same parsing we did with the pyats parse CLI command but with Python! Because I do so much of the exact same parsing steps and tests, and this was actually a community contribution to my code, I use a repeatable object (a Class) so that I can re-use the same line of code and simply change the command I am parsing.

A function in my general_functionalities.py file

 

Passing the CLI command to be parsed into my function

Ready To Model And Ingest JSON

Now that we have established connectivity, at scale, and YAML-free, to our network topology and have parsed the CLI Command we will have the JSON inside the self.parsed_show_ip_brief variable. We want it inside our database as a table, which means we need a new model. The model comes from the JSON schema and you can either use the CLI JSON we captured at the beginning as your model (real data) or from the pyATS Library JSON Schema directly via index – Genie Docs – Document – Cisco DevNet (under Available Parsers).

Finding our parser schema by operating system and keyword

Mapping JSON Schema to a Django Database Model

 

Register the new model in the Django Batteries Included Admin Page (admin.py)

We first need to makemigrations and migrate this new model into the PostgreSQL database with a couple of easy administrative management steps (Django’s manage.py file). I’ve done this in a BASH shell script that is part of my Dockerfile.

startup.sh

Now we have somewhere to put the JSON! Let’s finish the show_ip_interface.py Controller code.

First, I like to confirm that even though the initial parser may have passed the pyATS test, there is still a chance that the variable is empty. If it’s not empty (there is JSON inside) proceed.

You can’t fill a database without JSON

We will need a For Loop to iterate over each of the interfaces inside the returned self.parsed_show_ip_brief[‘interface’] key to get the JSON from each interface.

There is a hidden gotcha waiting in the weeds here. If you look carefully at the JSON schema you will notice you could have VLAN interfaces and other-interfaces (physical, loopback, port-channel, etc) which changes the structure (schema) of the returned JSON. So, we will test if it’s a VLAN.

We have to handle the JSON differently if it’s a VLAN Interface based on the Schema

 

If it is a VLAN we have to go a step deeper into each VLAN

The next step is the magical moment where we set up a variable that maps our model to the JSON we’ve captured from the network. Notice how closely this controller Python code maps to the model and to the JSON schema directly.

This schema is slightly different if it is not a VLAN.

We are ready to write the record to the model. By importing our model, we can access various functions and methods such as .save! It’s really that simple!

Boom! Network CLI to JSON to PostgreSQL with pyATS and Django

Views

Now that we have all of this network state-as-SQL what can we do with it?

In my next, and final, post in this three-part series we will present the network state to our users in a variety of Views. Stay tuned!

About John Capobianco: My name is John Capobianco, a 20-year IT professional who has fallen in love with automation, including network automation. I like to help other IT professionals learn how to modernize their approach to problem-solving with an automated DevOps infrastructure as code approach.