Netmiko's Real-World Use Cases - Network Automation

Netmiko is arguably one of the great tools for Network Automation. I've been using it for a couple of years now and have been using it for a wide variety of tasks. Let's go through some of the use cases in this blog post. If you are unfamiliar with Netmiko, I highly recommend checking out my previous posts below.

Part 1 - https://www.packetswitch.co.uk/netmiko-intro/

Part 2 - https://www.packetswitch.co.uk/netmiko-par2/

Part 3 - https://www.packetswitch.co.uk/netmiko-and-textfsm-example/

1. Run show commands and save the output

Frequently I end up in scenarios where I have to run some show commands on one or multiple devices and save the output to a file. Of course, you can log in to the CLI, run the commands and manually save the output to a file but what's the fun in it? If you were to do the same task again the next day, you will have to start all over again.

For example, if you are doing a migration, you might want to copy the output of show ip route, show ip arp, show ip ospf neighbor and then compare it after the migration to ensure everything is working as expected. Netmiko can be very handy in those situations. You can use the following script to save the output of multiple show commands to a file.

from netmiko import ConnectHandler
from datetime import datetime
import getpass

now = datetime.now()
dt_string = now.strftime("%d_%m_%Y")
passwd = getpass.getpass('Please enter the password: ')
switch_list = ['192.168.12.15', '192.168.12.16']
device_list = []

for ip in switch_list:
    device = {
        "device_type": "cisco_xe",
        "host": ip,
        "username": "admin",
        "password": passwd,
        "secret": passwd # Enable password
    }
    device_list.append(device)

commands = ['show ip route', 'show ip arp', 'show ip ospf neighbor']
for device in device_list:
    host_ip = device['host']
    connection = ConnectHandler(**device)
    
    for command in commands:
        output = connection.send_command(command)
        with open(f"{dt_string}_{host_ip}_output.txt", 'a') as f:
            f.write(output)
            f.write('\n')
            f.write('\n')

    print('Closing Connection')
    connection.disconnect()

Once you run the script, you will have a separate file for each device that contains the output from the show commands.

├── 16_01_2023_192.168.12.15_output.txt
├── 16_01_2023_192.168.12.16_output.txt
├── ios_raw_commands.py

2. Backup the device configurations

Similar to the previous example, I have a habit of backing up the devices' configurations to my local computer before starting any major work. Most enterprises use NCM to back up the configs automatically but in case if you don't have such luxury, you may find yourself backing up the configs manually on multiple devices. It can be time-consuming to log into each device and save the output. Just like the previous example, you can use a simple Netmiko script to back up the configurations manually and save it to a file.

from netmiko import ConnectHandler
from datetime import datetime
import getpass

now = datetime.now()
dt_string = now.strftime("%d_%m_%Y")
passwd = getpass.getpass('Please enter the password: ')
switch_list = ['192.168.12.15', '192.168.12.16']
device_list = []

for ip in switch_list:
    device = {
        "device_type": "cisco_xe",
        "host": ip,
        "username": "admin",
        "password": passwd,
        "secret": passwd # Enable password
    }
    device_list.append(device)

for device in device_list:
    host_ip = device['host']
    connection = ConnectHandler(**device)
    
    output = connection.send_command('show run')
    with open(f"{dt_string}_{host_ip}_config.txt", 'a') as f:
        f.write(output)

    print('Closing Connection')
    connection.disconnect()

3. Configure a subset of Interfaces

I often find myself configuring a subset of interfaces based on the VLAN ID, interface status, access/trunk ports, etc. My typical workflow would be to SSH to the device, find the appropriate interfaces, put together required configurations and then finally configure them.

Let's say we want to find all the interfaces that have the status notconnect and change the description on them. Without any automation, you would typically SSH to the device, run show interface status | incl notconnect, find the interfaces and then configure them one by one. You can achieve the same results with just a few lines of a Python script and the use of TextFSM templates. If you want learn more about TextFSM, please check out my other blog post here

from netmiko import ConnectHandler
import json

sw_01 = {
    "device_type": "cisco_ios",
    "host": "10.10.20.12",
    "username": "cisco",
    "password": "Cisco123",
    "secret": 'Cisco123'
}

connection = ConnectHandler(**sw_01)
output = connection.send_command('show interfaces status', use_textfsm=True)

not_connect_interfaces = [item['port'] for item in output if item['status'] == 'notconnect' ]

connection.enable() # Enable method
connection.config_mode() # Global config mode

for interface in not_connect_interfaces:
    commands = [f"interface {interface}", 'description NOT-CONNECTED']
    config_output = connection.send_config_set(commands)
    print(config_output)

connection.disconnect()

As you can see below, there are three interfaces that have the status notconnect. Let's run the script and see what happens.

sureshv@mac:~/Documents/netmiko-textfsm|⇒  python netmiko-ios.py

Port      Name               Status       Vlan       Duplex  Speed Type 
Gi0/0                        connected    10         a-full   auto RJ45
Gi0/1                        connected    1          a-full   auto RJ45
Gi0/2                        notconnect   1          a-full   auto RJ45
Gi0/3                        connected    1          a-full   auto RJ45
Gi1/0                        notconnect   1          a-full   auto RJ45
Gi1/1                        notconnect   1          a-full   auto RJ45
Gi1/2                        connected    1          a-full   auto RJ45
Gi1/3                        connected    1          a-full   auto RJ45
sureshv@mac:~/Documents/netmiko-textfsm|⇒  python netmiko-ios.py
interface Gi0/2
sw-01(config-if)#description NOT-CONNECTED
sw-01(config-if)#end
sw-01#
configure terminal
Enter configuration commands, one per line.  End with CNTL/Z.
sw-01(config)#interface Gi1/0
sw-01(config-if)#description NOT-CONNECTED
sw-01(config-if)#end
sw-01#
configure terminal
Enter configuration commands, one per line.  End with CNTL/Z.
sw-01(config)#interface Gi1/1
sw-01(config-if)#description NOT-CONNECTED
sw-01(config-if)#end
sw-01#
sw-01#show interfaces description 
Interface                      Status         Protocol Description
Gi0/0                          up             up       
Gi0/1                          up             up       
Gi0/2                          down           down     NOT-CONNECTED
Gi0/3                          up             up       
Gi1/0                          down           down     NOT-CONNECTED
Gi1/1                          down           down     NOT-CONNECTED
Gi1/2                          up             up       
Gi1/3                          up             up       
Vl10                           up             up      

As you can see above, the three interfaces are correctly configured with a description.

Closing up

You can think of Netmiko as a tool that can SSH to any network kit and execute any commands that we want. Because Netmiko is written in Python, you have access to all the Python ecosystems and modules to manipulate the output. The examples in the post are just the tip of the iceberg.