interesting new paramiko variant (SSH module for python)

Started by wintermute000, January 08, 2015, 03:54:43 AM

Previous topic - Next topic

wintermute000

I subscribe to this guy's mailing list for his free python for network engineers email course, and he's just released an interesting little module.
Hope other python users find it interesting and/or useful!

It basically makes it much easier to manipulate devices in SSH than manually using existing tools like paramiko or pexpect which you have to manually 'screen scrape' the syntax in telnet/ssh (e.g. confirmation prompts, formatting issues, enable mode, etc.)

Highly recommend signing up for his course BTW

Kirk Byers
Twitter: @kirkbyers
https://pynet.twb-tech.com

-----------------------------------------------------------------------

I have recently been working on an open-source Python library that simplifies SSH management to network devices. The library is based on the Paramiko SSH library.

The library is located here:
https://github.com/ktbyers/netmiko

and the latest release/download can be found at:
https://github.com/ktbyers/netmiko/releases




The purposes of the library are the following:
1. Successfully establish an SSH connection to a device
2. Make it easy to execute show commands and to retrieve the output data
3. Make it easy to execute configuration commands
4. Do the above across a broad set of networking vendors and platforms
I have observed across time that you can encounter quite a few problems in managing Python SSH sessions.  As an example, an HP ProCurve switch presents a "Press any key to continue" message after login.  The ProCurve also has ANSI escape codes in the output. Note, this is not to pick on HP, you will run into issues with other vendors as well.
These type of issues can easily add hours of development time to your script and what is worse we have no way of leveraging the learning from other people (i.e. each person goes and reinvents the wheel).
So netmiko intends to simplify this lower-level SSH management across a wide set of networking vendors and platforms.
As of January 2015, Netmiko has been tested on the following (see the Netmiko README.md for more details):
Cisco IOS
Cisco IOS XE
Cisco IOS XR
Cisco ASA
Cisco NX-OS
Arista vEOS
HP ProCurve
Juniper Junos

Let me show you a couple of examples.

Example 1, a simple SSH session to a Cisco router that executes the 'show ip int brief' command.
First, I import the netmiko library and then define the network device as a dictionary:
>>> import netmiko
>>> cisco_881 = {
...     'device_type': 'cisco_ios',
...     'ip':   '10.10.10.10',              # real IP address hidden as it was a public IP
...     'username': 'test1',         
...     'password': 'password',
...     'secret': 'secret',
...  }
I then call a dispatcher using the device_type.  The dispatcher just makes sure the right class is used.
>>> SSHClass = netmiko.ssh_dispatcher(cisco_881['device_type'])






I then connect to the device using the dictionary I created earlier:


>>> net_connect = SSHClass(**cisco_881)
SSH connection established to 10.10.10.10:22
Interactive SSH session established




At this point I have an SSH connection to the device and can execute commands on the channel.  I use the send_command() method for this.
>>> 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, I go into enable mode (which may or may not be necessary depending on your AAA setup):
>>> net_connect.enable()
>>> output = net_connect.send_command("show run | inc logging")
>>> print output
logging buffered 20010
no logging console

Now in order to make configuration changes, I specify a list of config 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 takes care of entering configuration mode, enters the command(s), and then exits configuration mode.


>>> output = net_connect.send_config_set(config_commands)
>>> print output


pynet-rtr1#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 define the networking devices:


>>> import netmiko
>>>
>>> cisco_881 = {
...     'device_type': 'cisco_ios',
...     'ip':   '10.10.10.10',
...     'username': 'admin',
...     'password': 'password',
...     'secret': 'secret',
... }
>>>
>>> cisco_asa = {
...     'device_type': 'cisco_asa',
...     'ip':   '10.10.10.11',
...     'username': 'admin',
...     'password': 'password',
...     'secret': 'secret',
... }
>>>
>>> arista_veos_sw = {
...     'device_type': 'arista_eos',
...     'ip':   '10.10.10.12',
...     'username': 'admin',
...     'password': 'password',
...     'port': 8522,                    # Firewall in front of this device, PAT from 8522 to 22
... }
>>>
>>> hp_procurve = {
...     'device_type': 'hp_procurve',
...     'ip':   '10.10.10.12',
...     'username': 'admin',
...     'password': 'password',
...     'port': 9922,                     # Firewall in front of this device, PAT from 9922 to 22
... }
>>>
>>> juniper_srx = {
...     'device_type': 'juniper',
...     'ip':   '10.10.10.12',
...     'username': 'root',
...     'password': 'password',
...     'port': 9822,                     # Firewall in front of this device, PAT from 9822 to 22
... }




Then create a list that includes all of these devices:


>>> all_devices = [cisco_881, cisco_asa, arista_veos_sw, hp_procurve, juniper_srx]




Finally, iterate over each of these devices and execute the 'show arp' command:


>>> for a_device in all_devices:
...   SSHClass = netmiko.ssh_dispatcher(a_device['device_type'])
...   net_connect = SSHClass(**a_device)
...   output = net_connect.send_command("show arp")
...   print "\n\n>>>>>>>>> Device {0} <<<<<<<<<".format(a_device['device_type'])
...   print output
...   print ">>>>>>>>> End <<<<<<<<<"
...




>>>>>>>>> Device cisco_ios <<<<<<<<<
Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  10.220.88.1            42   001f.9e92.16fb  ARPA   FastEthernet4
Internet  10.220.88.20            -   c89c.1dea.0eb6  ARPA   FastEthernet4
Internet  10.220.88.100         207   f0ad.4e01.d933  ARPA   FastEthernet4
>>>>>>>>> End <<<<<<<<<




>>>>>>>>> Device cisco_asa <<<<<<<<<
    inside 10.220.88.10 0018.fe1e.b020 179
    inside 10.220.88.39 6464.9be8.08c8 316
    inside 10.220.88.31 5254.0001.3737 1068
    inside 10.220.88.100 f0ad.4e01.d933 2568
    inside 10.220.88.30 5254.0092.13bb 4049
    inside 10.220.88.29 5254.0098.69b6 5408
    inside 10.220.88.21 1c6a.7aaf.576c 6318
    inside 10.220.88.28 5254.00ee.446c 6796
    inside 10.220.88.40 001c.c4bf.826a 8358
    inside 10.220.88.20 c89c.1dea.0eb6 11838
>>>>>>>>> End <<<<<<<<<




>>>>>>>>> Device arista_eos <<<<<<<<<
Address         Age (min)  Hardware Addr   Interface
10.220.88.1             0  001f.9e92.16fb  Vlan1, Ethernet1
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
>>>>>>>>> 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
f0:ad:4e:01:d9:33 10.220.88.100   10.220.88.100             vlan.0              none
Total entries: 2


>>>>>>>>> End <<<<<<<<<




Note, it took 51 seconds for the above for-loop code to execute.  This could be improved by executing the SSH sessions in parallel, for an example of this see:


https://github.com/ktbyers/netmiko/blob/master/examples/multiprocess_example.py




For a list of supported device_types see:


https://github.com/ktbyers/netmiko/blob/master/netmiko/ssh_dispatcher.py










If you have additional vendors or platforms that you want supported, email me (or even better send me a pull-request).  I would like to add additional vendor support, but in order to do this, I need a reasonable way to test the code against said vendor.


Special thanks to Pablo Lucena, Ron Nilekani, and Will Dennis for the assistance they have provided in writing and/or testing some of the code.


Kirk Byers
Twitter: @kirkbyers
https://pynet.twb-tech.com


AnthonyC

I think this type of modules had existed for years; I used something similar for Perl many years ago. 
"It can also be argued that DNA is nothing more than a program designed to preserve itself. Life has become more complex in the overwhelming sea of information. And life, when organized into species, relies upon genes to be its memory system."

vito_corleone

That's interesting. I've tried to avoid using modules like this recently. I had a few scripts that heavily relied on Exscript and they would always break when some lower-level module updated. It ended up being more work than just using Paramiko by itself.

jinxer

Been using perl for stuff like this but with the huge momentum python has going maybe its time to pick it up..


Sent from my iPhone using Tapatalk