In this post, we are going to cover the very basics of Netmiko. This is a beginner-level introduction on how to automate networking devices using python netmiko in which we will talk about how to install and set up SSH to network devices using python. Also how to write a basic script for interacting with devices programmatically.
Installation
pip install netmiko / pip3 install netmiko
Depending upon if you are using pip or pip3
Interact (SSH / Telnet ) with a network device using Netmiko
Create a dictionary of all devices that we want to interact with. For this post, we will create the dictionary statically but we can also generate the dictionary dynamically from any network inventory source as well like excel sheets.
csr1000v1 = {
'device_type': 'cisco_xe',
'host': 'sandbox-iosxe-latest-1.cisco.com',
'username': 'developer',
'password': 'C1sco12345',
'port' : 22, # optional, defaults to 22
'secret': 'C1sco12345', # optional, defaults to ''
}
csr1000v2 = {
'device_type': 'cisco_xe',
'host': 'sandbox-iosxe-recomm-1.cisco.com',
'username': 'developer',
'password': 'C1sco12345',
'port' : 22,
'secret': 'C1sco12345',
}
iosxrv9000 = {
'device_type': 'cisco_xr',
'host': 'sandbox-iosxr-1.cisco.com',
'username': 'admin',
'password': 'C1sco12345',
'port' : 22,
'secret': 'C1sco12345',
}
nxosv9000 = {
'device_type': 'cisco_nxos',
'host': 'sandbox-nxos-1.cisco.com',
'username': 'admin',
'password': 'Admin_1234!',
'port' : 22,
'secret': 'Admin_1234!',
}
Let’s connect to csr1000v1 device and extract the output of show ip int br from that device using python
from netmiko import ConnectHandler
net_connect = ConnectHandler(**csr1000v1)
output = net_connect.send_command('show ip int brief')
print(output)
╰─ python3 script.py ─╯
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES NVRAM up up
GigabitEthernet2 unassigned YES NVRAM administratively down down
GigabitEthernet3 unassigned YES NVRAM administratively down down
Loopback100 111.111.111.111 YES manual up up
Explanation:-
- Import ConnectHandler from netmiko module. ConnectHandler is responsible for establishing the SSH read write connection with the device in the background.
- net_connect = ConnectHandler(**csr1000v1)
- Pass the dictionary of device details that we want to connect to and assign that connection to a variable called net_connect. You could call it anything you want to.
- To see available methods for net_connect, type print(dir(net_connect)) and this will show you all the methods that you can call against that connection. You can read more about all these methods in the github API documentation of Netmiko. The intention here is to cover the absolute basics to get the ball rolling.
- output = net_connect.send_command(‘show ip int brief’)
- Call send_command method on net_connect connection handler and pass in the command you want to execute on the device. The result of the command execution will be saved to a variable called output.
If we want to extract outputs from all devices, we can put all the dictionary of devices into a list like below
For each device in the all_devices list
all_devices = [csr1000v1, csr1000v2, iosxrv9000, nxosv9000]
for device in all_devices:
net_connect = ConnectHandler(**device)
output = net_connect.send_command('show ip int brief | ex unass')
print(device['host'])
print("=" * len(device['host']))
print(output)
╰─ python3 script.py ─╯
sandbox-iosxe-latest-1.cisco.com
================================
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES NVRAM up up
GigabitEthernet2 10.255.255.2 YES other up up
Loopback100 111.111.111.111 YES manual up up
sandbox-iosxe-recomm-1.cisco.com
================================
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES NVRAM up up
GigabitEthernet3 172.31.1.1 YES manual down down
Loopback2 2.2.2.2 YES manual up up
Loopback10 10.111.10.1 YES manual up up
Loopback100 10.3.3.3 YES other up up
VirtualPortGroup0 192.168.0.254 YES manual up up
sandbox-iosxr-1.cisco.com
=========================
Fri Jul 30 14:21:41.134 UTC
Interface IP-Address Status Protocol Vrf-Name
Loopback100 1.1.1.100 Up Up default
Loopback200 1.1.1.200 Up Up default
MgmtEth0/RP0/CPU0/0 10.10.20.175 Up Up default
sandbox-nxos-1.cisco.com
========================
IP Interface Status for VRF "default"(1)
Interface IP Address Interface Status
Vlan3 33.33.33.33 protocol-down/link-down/admin-up
Vlan100 172.16.100.1 protocol-up/link-up/admin-up
Vlan101 172.16.101.1 protocol-down/link-down/admin-down
Vlan102 172.16.102.1 protocol-down/link-down/admin-down
Vlan103 172.16.103.1 protocol-down/link-down/admin-down
Vlan104 172.16.104.1 protocol-down/link-down/admin-down
Vlan105 172.16.105.1 protocol-down/link-down/admin-down
Lo1 172.16.0.1 protocol-up/link-up/admin-up
Lo21 3.3.3.3 protocol-up/link-up/admin-up
Lo23 27.27.27.27 protocol-up/link-up/admin-up
Lo25 8.8.8.8 protocol-up/link-up/admin-up
Lo31 2.2.2.2 protocol-up/link-up/admin-up
Lo101 192.168.232.0 protocol-up/link-up/admin-up
Lo102 192.168.2.1 protocol-up/link-up/admin-up
Lo127 192.168.127.1 protocol-up/link-up/admin-up
Lo128 192.168.128.1 protocol-up/link-up/admin-up
Lo200 5.5.5.5 protocol-up/link-up/admin-up
Lo201 201.201.201.201 protocol-up/link-up/admin-up
Lo500 9.9.9.9 protocol-up/link-up/admin-up
Lo998 7.7.7.7 protocol-up/link-up/admin-up
Lo999 4.4.4.4 protocol-up/link-up/admin-up
Eth1/5 172.16.1.1 protocol-up/link-up/admin-up
If we want to extract multiple commands and multiple devices, we can modify the script a little bit to do so.
For each device in the all_devices list, we will execute each command in the commands list. We are using nested for loops here to achieve the task.
all_devices = [csr1000v1, csr1000v2, iosxrv9000, nxosv9000]
commands = ['show version', 'show ip int br | ex unass', 'show cdp nei']
for device in all_devices:
net_connect = ConnectHandler(**device)
print(device['host'])
print("=" * len(device['host']))
for command in commands:
output = net_connect.send_command(command)
print(output)
send_command as the name suggests sends the command to the device and outputs the response to a variable. send_command method is looking for the device prompt, it keeps on reading the output until the device prompt is found again which is usually when the command execution is completed. Instead of using send_command, there may be scenarios where you need to execute
- send_command_timing
- You can control the delay in this command in scenarios where you want to copy paste files to and from bootflash and the default wait interval of netmiko is too less specially when you want to work over WAN. So instead of stopping the execution after finding the device prompt, the script works on predefined delay intervals.
- send_command_expect
- Interactive CLI commands where you need to hit return / enter. So instead of stopping the command execution after default device prompt is seen or a specific time. The command execution is controlled by the pattern you specify and expect to see the entire order of operations.
# cisco1#delete flash:/testb.txt # Delete filename [testb.txt]? # Delete flash:/testb.txt? [confirm]y # Use 'send_command' and the 'expect_string' argument (note, expect_string uses RegEx patterns). # Netmiko will move-on to the next command when the 'expect_string' is detected.Here is a showcase of all arguments that you can pass to the netmiko send_command( ) method
def send_command( self, command_string: str, expect_string: Optional[str] = None, delay_factor: float = 1.0, max_loops: int = 500, auto_find_prompt: bool = True, strip_prompt: bool = True, strip_command: bool = True, normalize: bool = True, use_textfsm: bool = False, textfsm_template: Optional[str] = None, use_ttp: bool = False, ttp_template: Optional[str] = None, use_genie: bool = False, cmd_verify: bool = True, ) -> str: """Execute command_string on the SSH channel using a pattern-based mechanism. Generally used for show commands. By default this method will keep waiting to receive data until the network device prompt is detected. The current network device prompt will be determined automatically. :param command_string: The command to be executed on the remote device. :type command_string: str :param expect_string: Regular expression pattern to use for determining end of output. If left blank will default to being based on router prompt. :type expect_string: str :param delay_factor: Multiplying factor used to adjust delays (default: 1). :type delay_factor: int :param max_loops: Controls wait time in conjunction with delay_factor. Will default to be based upon self.timeout. :type max_loops: int :param strip_prompt: Remove the trailing router prompt from the output (default: True). :type strip_prompt: bool :param strip_command: Remove the echo of the command from the output (default: True). :type strip_command: bool :param normalize: Ensure the proper enter is sent at end of command (default: True). :type normalize: bool :param use_textfsm: Process command output through TextFSM template (default: False). :type normalize: bool :param textfsm_template: Name of template to parse output with; can be fully qualified path, relative path, or name of file in current directory. (default: None). :param use_ttp: Process command output through TTP template (default: False). :type use_ttp: bool :param ttp_template: Name of template to parse output with; can be fully qualified path, relative path, or name of file in current directory. (default: None). :type ttp_template: str :param use_genie: Process command output through PyATS/Genie parser (default: False). :type normalize: bool :param cmd_verify: Verify command echo before proceeding (default: True). :type cmd_verify: bool """
In the next post on how to automate networking devices using python netmiko series, we see how to enter into enable mode and configure mode to push configuration changes to devices.
3 thoughts on “How to Automate Network Devices using Python Netmiko Part I”