The Nornir framework
Nornir (https://nornir.readthedocs.io/en/latest/) is a pure Python automation framework intended to be used directly from Python. We will start with installing nornir
in our environment:
(venv)$ pip install nornir nornir_utils nornir_netmiko
Nornir expects us to define an inventory file, hosts.yaml
, consisting of the device information in a YAML format. The information specified in this file is no different than what we have previously defined using the Python dictionary in the Netmiko example:
---
lax-edg-r1:
hostname: '192.168.2.51'
port: 22
username: 'cisco'
password: 'cisco'
platform: 'cisco_ios'
lax-edg-r2:
hostname: '192.168.2.52'
port: 22
username: 'cisco'
password: 'cisco'
platform: 'cisco_ios'
We can use the netmiko
plugin from the nornir
library to interact with our device, as illustrated in the chapter2_5.py
file:
#!/usr/bin/env python
from nornir import InitNornir
from nornir_utils.plugins.functions import print_result
from nornir_netmiko import netmiko_send_command
nr = InitNornir()
result = nr.run(
task=netmiko_send_command,
command_string="show arp"
)
print_result(result)
The execution output is shown as follows:
(venv) $ python chapter2_5.py
netmiko_send_command************************************************************
* lax-edg-r1 ** changed : False ************************************************
vvvv netmiko_send_command ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
Protocol Address Age (min) Hardware Addr Type Interface
Internet 10.0.0.1 - 5254.001e.e911 ARPA GigabitEthernet0/1
Internet 10.0.0.2 17 fa16.3e00.0001 ARPA GigabitEthernet0/1
^^^^ END netmiko_send_command ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* lax-edg-r2 ** changed : False ************************************************
vvvv netmiko_send_command ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
Protocol Address Age (min) Hardware Addr Type Interface
Internet 10.0.128.1 17 fa16.3e00.0002 ARPA GigabitEthernet0/1
Internet 10.0.128.2 - 5254.0014.e052 ARPA GigabitEthernet0/1
^^^^ END netmiko_send_command ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are other plugins in Nornir besides Netmiko, such as the popular NAPALM library (https://github.com/napalm-automation/napalm). Please feel free to check out Nornir’s project page for the latest plugins: https://nornir.readthedocs.io/en/latest/plugins/index.html.
We have taken a pretty huge leap forward in this chapter in automating our network using Python. However, some of the methods we have used feel like workarounds for automation. We attempted to trick the remote devices into thinking they were interacting with a human on the other end. Even if we use libraries such as Netmiko or the Nornir framework, the underlying approach remains the same. Just because somebody else has done the work to help abstract the grunt work of the low-level interaction, we are still susceptible to the downsides of dealing with CLI-only devices.
Looking ahead, let us discuss some of the downsides of Pexpect and Paramiko compared to other tools in preparation for our discussion on API-driven methods in the next chapters.
Downsides of Pexpect and Paramiko compared to other tools
The biggest downside of our current method for automating CLI-only devices is that the remote devices do not return structured data. They return data that is ideal for fitting on a terminal to be interpreted by a human, not by a computer program. The human eye can easily interpret a space, while a computer only sees a return character.
We will take a look at a better way in the upcoming chapter. As a prelude to Chapter 3, APIs and Intent-Driven Networking, let’s discuss the idea of idempotency.
Idempotent network device interaction
The term idempotency has different meanings, depending on its context. But in this book’s context, the term means that when a client makes the same call to a remote device, the result should always be the same. I believe we can all agree that this is necessary. Imagine a scenario where each time you execute the same script, you get a different result back. I find that scenario very scary. How can you trust your script if that is the case? It would render our automation effort useless because we need to be prepared to handle different returns.
Since Pexpect and Paramiko are blasting out a series of commands interactively, the chance of having a non-idempotent interaction is higher. Going back to the fact that the return results needed to be screen scraped for useful elements, the risk of difference is much higher. Something on the remote end might have changed between the time we wrote the script and the time when the script is executed for the 100th time. For example, if the vendor makes a screen output change between releases without us updating the script, the script might break our network.
If we need to rely on the script for production, we need the script to be idempotent as much as possible.
Bad automation speeds up bad things
Bad automation allows you to poke yourself in the eye a lot faster, it is as simple as that. Computers are much faster at executing tasks than human engineers. If we had the same set of operating procedures executed by a human versus a script, the script would finish faster than humans, sometimes without the benefit of having a solid feedback loop between steps. The internet is full of horror stories of when someone pressed the Enter key and immediately regretted it.
We need to minimize the chances of bad automation scripts screwing things up. We all make mistakes; carefully testing your script before any production work and having a small blast radius are two keys to making sure you can catch your mistake before it comes back and bites you. No tool or human can eliminate mistakes completely, but we can strive to minimize the mistakes. As we have seen, as great as some of the libraries we have used in this chapter are, the underlying CLI-based method is inherently faulty and error-prone. We will introduce the API-driven method in the next chapter, which addresses some of the CLI-driven management deficiencies.