You can find the library at https://github.com/ktbyers/netmiko and the latest released version of the software can be
downloaded here.
The purposes of the library are the following:
- Successfully establish an SSH connection to the device
- Simplify the execution of show commands and the retrieval of output data
- Simplify execution of configuration commands including possibly commit actions
- Do the above across a broad set of networking vendors and platforms
Netmiko has support for the following platforms:
- Cisco IOS
- Cisco IOS-XE
- Cisco ASA
- Cisco NX-OS
- Cisco IOS-XR
- Cisco WLC (limited testing)
- Arista EOS
- HP ProCurve
- HP Comware (limited testing)
- Juniper Junos
- Brocade VDX (limited testing)
- F5 LTM (experimental)
- Huawei (limited testing)
As with anything involving programming, test extensively in your own
environment and for your own specific use cases. It is your
responsibility to know what you are doing and to have good testing
processes in place.
Example 1, a simple SSH session to a Cisco router that executes the 'show ip int brief' command.
First, I must import the ConnectHandler factory function from Netmiko.
This factory function selects the correct Netmiko class based upon the
device_type. I then define a network device dictionary consisting of a
device_type, ip, username, and password.
>>> from netmiko import ConnectHandler >>> cisco_881 = { ... 'device_type': 'cisco_ios', ... 'ip': '10.10.10.227', ... 'username': 'pyclass', ... 'password': 'password', ... }
At this point, I should be able to connect to the device.
Notice above that I have specified the device_type as 'cisco_ios'. The
supported device_type's are cisco_ios, cisco_xe, cisco_asa, cisco_nxos,
cisco_xr, cisco_wlc_ssh, arista_eos, hp_procurve, hp_comware, huawei,
f5_ltm, juniper, and brocade_vdx.
Now in order to connect all I need to do is call the ConnectHandler
factory function and pass in my earlier defined device dictionary:
>>> net_connect = ConnectHandler(**cisco_881) SSH connection established to 10.10.10.227:22 Interactive SSH session established
Alternatively, I could just call the ConnectHandler function directly and not use a dictionary (as follows):
>>> net_connect = ConnectHandler(device_type='cisco_ios', ip='10.10.10.227', username='pyclass', password='password')
Now at this point we have an SSH connection.
I can verify this by executing the .find_prompt() method
>>> net_connect.find_prompt() u'pynet-rtr1#'
I can also send commands down the SSH channel and receive the output
back.
Here, I use the .send_command() method to send the 'show ip int
brief' command:
>>> output = net_connect.send_command("show ip int brief") >>> print output Interface IP-Address OK? Method Status Protocol FastEthernet0 unassigned YES unset down down FastEthernet1 unassigned YES unset down down FastEthernet2 unassigned YES unset down down FastEthernet3 unassigned YES unset down down FastEthernet4 10.220.88.20 YES NVRAM up up Vlan1 unassigned YES unset down down
Let's also try to make a configuration change to this router. First, let's look at the current logging configuration:
>>> output = net_connect.send_command("show run | inc logging") >>> print output logging buffered 8880 no logging console
Now in order to make configuration changes, I create a list of
configuration commands that I want to execute. This could be a single
command or multiple commands.
>>> config_commands = ['logging buffered 19999']
I then execute the send_config_set() method. This method will enter
configuration mode, execute the commands, and then exit configuration
mode (note, there will be some exceptions to this behavior depending on
the platform--for example, IOS-XR will not exit configuration mode due
to pending changes).
>>> output = net_connect.send_config_set(config_commands) >>> print output config term Enter configuration commands, one per line. End with CNTL/Z. pynet-rtr1(config)#logging buffered 19999 pynet-rtr1(config)#end pynet-rtr1#
I can then verify my change:
>>> output = net_connect.send_command("show run | inc logging") >>> print output logging buffered 19999 no logging console
Example 2, executing 'show arp' on a set of networking devices consisting of different vendors and platforms.
First, I need to define the networking devices (real IP addresses and passwords have been hidden):
>>> from netmiko import ConnectHandler >>> from datetime import datetime >>> cisco_881 = { ... 'device_type': 'cisco_ios', ... 'ip': '10.10.10.227', ... 'username': 'pyclass', ... 'password': 'password', ... 'verbose': False, ... } >>> >>> cisco_asa = { ... 'device_type': 'cisco_asa', ... 'ip': '10.10.10.10', ... 'username': 'admin', ... 'password': 'password', ... 'secret': 'secret', ... 'verbose': False, ... } >>> >>> cisco_xrv = { ... 'device_type': 'cisco_xr', ... 'ip': '10.10.10.227', ... 'username': 'admin1', ... 'password': 'password', ... 'port': 9722, # there is a firewall performing NAT in front of this device ... 'verbose': False, ... } >>> >>> arista_veos_sw = { ... 'device_type': 'arista_eos', ... 'ip': '10.10.10.227', ... 'username': 'admin1', ... 'password': 'password', ... 'port': 8522, # there is a firewall performing NAT in front of this device ... 'verbose': False, ... } >>> >>> hp_procurve = { ... 'device_type': 'hp_procurve', ... 'ip': '10.10.10.227', ... 'username': 'admin', ... 'password': 'password', ... 'port': 9922, # there is a firewall performing NAT in front of this device ... 'verbose': False, ... } >>> >>> juniper_srx = { ... 'device_type': 'juniper', ... 'ip': '10.10.10.227', ... 'username': 'pyclass', ... 'password': 'password', ... 'port': 9822, # there is a firewall performing NAT in front of this device ... 'verbose': False, ... }
Next, I need to create a Python list that includes all of these devices:
>>> all_devices = [cisco_881, cisco_asa, cisco_xrv, arista_veos_sw, hp_procurve, juniper_srx]
Now, I will create a for loop that iterates over all of these devices.
Each time through the loop: the code will connect to the device, execute
the 'show arp' command, and then display the output. I will also keep
track of the time that it takes for the code execute.
Note, I have removed a
couple of public IP addresses from the arp output. Additionally, I have
changed the output slightly (so that you can more clearly see what I
pasted in versus the output back from the devices).
>>> >>> start_time = datetime.now() >>> for a_device in all_devices: ... net_connect = ConnectHandler(**a_device) ... output = net_connect.send_command("show arp") ... print "\n\n>>>>>>>>> Device {0} <<<<<<<<<".format(a_device['device_type']) ... print output ... print ">>>>>>>>> End <<<<<<<<<" ... >>> end_time = datetime.now() >>> >>> total_time = end_time - start_time
Here is the output from the for loop (i.e. all of the "show arp" output):
>>>>>>>>> Device cisco_ios <<<<<<<<< Protocol Address Age (min) Hardware Addr Type Interface Internet 10.220.88.1 4 001f.9e92.16fb ARPA FastEthernet4 Internet 10.220.88.20 - c89c.1dea.0eb6 ARPA FastEthernet4 Internet 10.220.88.100 10 f0ad.4e01.d933 ARPA FastEthernet4 >>>>>>>>> End <<<<<<<<< >>>>>>>>> Device cisco_asa <<<<<<<<< inside 10.220.88.100 f0ad.4e01.d933 251 inside 10.220.88.31 5254.0001.3737 311 inside 10.220.88.39 6464.9be8.08c8 361 inside 10.220.88.30 5254.0092.13bb 1451 inside 10.220.88.10 0018.fe1e.b020 1700 inside 10.220.88.29 5254.0098.69b6 3071 inside 10.220.88.21 1c6a.7aaf.576c 3431 inside 10.220.88.28 5254.00ee.446c 5111 inside 10.220.88.38 0001.00ff.0001 8231 inside 10.220.88.20 c89c.1dea.0eb6 11081 inside 10.220.88.40 001c.c4bf.826a 12671 >>>>>>>>> End <<<<<<<<< >>>>>>>>> Device cisco_xr <<<<<<<<< Wed Dec 30 00:04:47.641 UTC ------------------------------------------------------------------------------- 0/0/CPU0 ------------------------------------------------------------------------------- Address Age Hardware Addr State Type Interface 10.220.88.1 00:04:19 001f.9e92.16fb Dynamic ARPA GigabitEthernet0/0/0/0 10.220.88.10 00:28:28 0018.fe1e.b020 Dynamic ARPA GigabitEthernet0/0/0/0 10.220.88.28 02:54:39 5254.00ee.446c Dynamic ARPA GigabitEthernet0/0/0/0 10.220.88.29 01:37:22 5254.0098.69b6 Dynamic ARPA GigabitEthernet0/0/0/0 10.220.88.30 00:38:28 5254.0092.13bb Dynamic ARPA GigabitEthernet0/0/0/0 10.220.88.31 02:19:09 5254.0001.3737 Dynamic ARPA GigabitEthernet0/0/0/0 10.220.88.38 - 0001.00ff.0001 Interface ARPA GigabitEthernet0/0/0/0 10.220.88.39 00:06:08 6464.9be8.08c8 Dynamic ARPA GigabitEthernet0/0/0/0 >>>>>>>>> End <<<<<<<<< >>>>>>>>> Device arista_eos <<<<<<<<< Address Age (min) Hardware Addr Interface 10.220.88.1 0 001f.9e92.16fb Vlan1, Ethernet1 10.220.88.21 0 1c6a.7aaf.576c Vlan1, not learned 10.220.88.28 0 5254.00ee.446c Vlan1, not learned 10.220.88.29 0 5254.0098.69b6 Vlan1, not learned 10.220.88.30 0 5254.0092.13bb Vlan1, not learned 10.220.88.38 0 0001.00ff.0001 Vlan1, not learned >>>>>>>>> End <<<<<<<<< >>>>>>>>> Device hp_procurve <<<<<<<<< IP ARP table IP Address MAC Address Type Port --------------- ----------------- ------- ---- 10.220.88.1 001f9e-9216fb dynamic 19 >>>>>>>>> End <<<<<<<<< >>>>>>>>> Device juniper <<<<<<<<< MAC Address Address Name Interface Flags 00:1f:9e:92:16:fb 10.220.88.1 10.220.88.1 vlan.0 none 00:19:e8:45:ce:80 10.220.88.22 10.220.88.22 vlan.0 none f0:ad:4e:01:d9:33 10.220.88.100 10.220.88.100 vlan.0 none Total entries: 3 >>>>>>>>> End <<<<<<<<< >>> print total_time 0:00:44.791650 >>>
As you can see it took almost 45 seconds for the above for-loop to
execute. This could be significantly improved by executing the SSH
sessions in parallel, for an example of this see the code here
Some Netmiko methods that are generally available to you:
- net_connect.config_mode() -- Enter into config mode
- net_connect.check_config_mode() -- Check if you are in config mode, return a boolean
- net_connect.exit_config_mode() -- Exit config mode
- net_connect.clear_buffer() -- Clear the output buffer on the remote device
- net_connect.enable() -- Enter enable mode
- net_connect.exit_enable_mode() -- Exit enable mode
- net_connect.find_prompt() -- Return the current router prompt
- net_connect.commit(arguments) -- Execute a commit action on Juniper and IOS-XR
- net_connect.disconnect() -- Close the SSH connection
- net_connect.send_command(arguments) -- Send command down the SSH channel, return output back
- net_connect.send_config_set(arguments) -- Send a set of configuration commands to remote device
- net_connect.send_config_from_file(arguments) -- Send a set of configuration commands loaded from a file
Note:
I specified 'arguments' in the above methods if arguments are
required or reasonably common. Some of the other methods also support
arguments, but you typically wouldn't need them.
No comments:
Post a Comment
Thank you for your comment. Will try to react as soon as possible.
Regards,
Networ King