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.