I tend to assess automation tools in four different contexts which is, in fact, a very general networking and automation workflow:
- How easy is it to find out about the network, document its configuration (the configuration of a device itself) and state (show commands "snapshotting" its state)?
- Configuration Creation
- How easy is it to generate configurations for a device, given a template?
- Configuration Application
- How easy is it to apply a set of configuration commands to one or more devices based on criteria?
- Verification & Testing
- How easy is it to audit and validate configurations and script results?
- Yes, unglamorous though this may be it is a vital function for any network engineer and I would say doubly so with automation.
We looked at Step 1, discovery, in the introduction to Nornir. This is step 2 in that workflow as I become more familiar with Nornir.
In my initial notes about Nornir I mentioned a few areas where Nornir really seemed to shine. Since then, I've had occasion to truly appreciate its native python roots. I recently worked with a Client where I was not able to install Ansible in their environment but they had no issues with Python. Nornir saves the day!
In keeping with my "assessment methodology" (trust me that sounds far more rigorous than it is) my first use of Nornir (then called Brigade) involved using Napalm get_facts against a couple of network devices and then decomposing the returned data (figuring out what it is and how to get to the data). In this way, I was easily able to discover key facts about all the network devices in my inventory and return them as structured data.
Why do we talk about "structured data" so often? Its our way of saying you don't have to parse the ever changing stream of data you get back from some network devices. Perhaps it is more accurate to say that someone has already parsed the data for us and is returning it in a nice data structure that we can easily manipulate (a list, a dictionary, or more commonly a combination of both). For todays task we are going to parse the unstructured data we get back from each device ourselves so we can truly appreciate all the heavy lifting tools like Napalm do for us.
It drove me crazy that the first thing everyone always taught in Ansible was how to generate configs because that is not what I found powerful about it. For quite a while all anyone (in the networking community at least) ever learned to do with Ansible was generate configs! So I was pleased that most of the early Nornir examples started with what I call "discovery". However, now it is time to look at configuration creation with Nornir.
Let's get started.
I have a simple task I want to accomplish. I need to evaluate all of my switches and remove any vlans that are not in use. I also want to make sure I have a set of standard vlans configured on each switch:
- 10 for Data
- 100 for Voice
- 300 for Digital Signage
- 666 for User Static IP Devices
We will take this one step at a time.
First we will query our devices for the data that we need to help us decide what vlans to keep and what vlans to remove.
We will then take that data and generate a customized configuration "snippet" or set of commands that we can later apply to each device to achieve our desired result.
Each switch will only have vlans that are in use and a standard set of vlans supporting voice, data, digital signage, and user devices with static IPs. As an added wrinkle, I have some devices that are only accessible via Telnet (you would be surprised at how often I find this to be the case.)
I'm not doing too much here with idempotency or "declarative" networking but I find that I understand things a bit better if I look at it from the current "classical" perspective and then look at how these tools can help leapfrog me into a much more efficient way of doing things.
This little automation exercise starts to bring in a variety of tools which will help us accomplish our task.
- Nornir, and python of course, provide our ready made inventory, connection, and task environment. With Nornir in place I can now perform tasks on any subset of my inventory. We won't cover filtering here but know it is an available feature.
- Napalm easily accessible to us via Nornir provides the connectivity method (napalm_cli) that allows us to query, real time, our devices and obtain the data we need to achieve our "vlan cleanup & standardization" task.
- TextFMS and NetworkToCode parsing templates allow us to extract our data as structured data so we can easily manipulate it and apply logic. We need this because napalm does not yet make available a "get vlans" getter and so we have to do this ourselves.
- Note that for some devices we might be able to use the interface getter for this data but I think there is great value in knowing how to do this ourselves should the need arise. We can't have Mr. Barroso and team do all of our work for us!
- Jinja2 also available to us via the Nornir framework will allow us to generate the customized configuration snippets.
Let see where they come into play in our task breakdown
Query devices for data
- Environment set up via Nornir
- Connectivity method used via a standard Nornir task using Napalm CLI
Analyze the data retrieved from each device and determine a vlan "disposition" (keeping or removing)
- Taking the data provided by the Napalm CLI (and the "show vlan" command we sent) we were able to quickly parse it via TextFSM and an existing TextFSM Template from the NetworkToCode TextFSM Template Repository
- With our data now in a python data structure we were able to apply our "business rules logic" to get an understanding of the changes required in each device.
== Parsing vlan output for device arctic-as01 using TextFSM and NetworkToCode template. ================================================================================ VLAN_ID NAME STATUS TOTAL_INT_IN_VLAN ACTION 1 default active 7 Keeping this vlan 10 Management_Vlan active 1 Keeping this vlan 20 Web_Tier active 0 This vlan will be removed! 30 App_Tier active 0 This vlan will be removed! 40 DB_Tier active 0 This vlan will be removed! ================================================================================
Generate a customized set of configuration commands to achieve our desired vlan state
- Using the built in Nornir task that allows us to generate configurations based on Jinja2, we used the logic above to generate specific configuration commands for each device that, when applied, will achieve our desired state.
Here is the resulting configuration snippet for this particular device.
! For device arctic-as01 ! no vlan 20 no vlan 30 no vlan 40 vlan 10 name Data_Vlan vlan 100 name Voice_Vlan vlan 300 name Digital_Signage vlan 666 name User_Static_IP_Devices
As you can see, Nornir is bringing together the tools and functions that we use for day to day network automation tasks under one native Python wrapper. Where we need some customization or a tool does not exist it is a simple matter of using Python to bridge that gap!
Lets add a little more functionality to our original repository and try to gain a better understanding of Nornir.
Please see my nornir-config GitHub repository for the details!
Cisco Blog - Developer Exploring Nornir, the Python Automation Framework
A quick example of using TextFSM to parse data from Cisco show commands
How Network Engineers Can Manage Credentials and Keys More Securely in Python