Print(“A Python Post”)

Standard

Python keeps coming up again and again in various networking discussions since people are always debating exactly how much automation stuff you should learn as you get more senior.Python keeps coming up again and again in various networking discussions since people are always debating exactly how much automation stuff you should learn as you get more senior.

Let’s kick the tires with python a bit to see what all the fuss is about. We won’t go very deep into explaining things so this will be more of a show and tell type deal.

Python is baked into most Linux and Mac OSs by default, typically you will find 2.7 in the wild since python 3 makes some changes that people are reluctant to adopt  so you will find many 2 vs 3 debates about the subject. Windows doesn't have python baked in so you will need to install it online if you want to use that to follow along. I personally like anaconda's package.

Python also has a package manager call `pip` that can be used to install various addons. I'll install pip and also ipython which is a awesome python sense I love.

root@Home01:~# apt-get install python-pip ipython -y    Reading package lists... Done    Building dependency tree    Reading state information... Done

Once pip is installed we can add more functionality into python by installing modules, I’ll install the netaddr module which lets us do some IP operations.

[root@Fedora-S01 ~]# pip install netaddr
Collecting netaddr
Downloading netaddr-0.7.19-py2.py3-none-any.whl (1.6MB)        100% |████████████████████████████████| 1.6MB 885kB/s
Installing collected packages: netaddr</
Successfully installed netaddr-0.7.19

Python can be run in two modes, an interactive mode where we pop into a python shell and can type commands line by line as needed or a non-interactive mode where we will write up the full script to be run. Typically we will just use the interactive mode for testing things out and will mostly run script files.

For now we will open up ipython and play around a bit, I like ipython more than the traditional shell because it adds features like tab completion for commands and some other neat things. It is supported on all platforms.

 [root@Fedora-S01 ~]# ipython    Python 2.7.13 (default, May 10 2017, 20:04:28)     Type "copyright", "credits" or "license" for more information.        IPython 5.3.0 -- An enhanced Interactive Python.    ?         -> Introduction and overview of IPython's features.    %quickref -> Quick reference.    help      -> Python's own help system.    object?   -> Details about 'object', use 'object??' for extra details.        In [1]:

It is a bit of tradition in the programming world to have your first script be “hello world”, lets try this out in the shell.

In [1]: print "Hello World"    Hello World

To write a script file, we make a file called helloworld.py and then we can call it with the python command and pointing to the file.

[root@Fedora-S01 ~]# cat helloworld.py print "Hello World"[root@Fedora-S01 ~]#

python helloworld.py Hello World

If you don’t want to have to use the python command to run scripts then you need to make sure your script starts with #!/bin/env python so the script can find the python interpreter.

[root@Fedora-S01 ~]# cat helloworld.py     
#!/bin/env python    
print "Hello World"

 

In linux we need to set the file to be a executable and we can run it.

[root@Fedora-S01 ~]# chmod u+x helloworld.py            

[root@Fedora-S01 ~]# ./helloworld.py             

Hello World

To play with our netaddr module we first need to import it into python. When we use this method we need to prepend all the functions with netaddr to test this out we will make a variable called IP and use the netaddr.IPAddress function to examine an IP address.

[root@Fedora-S01 ~]# ipython                      

In [1]: import netaddr        

In [2]: ip = netaddr.IPAddress('192.168.77.100')        

In [3]: ip.version    

Out[3]: 4        

In [4]: ip.bin    

Out[4]: '0b11000000101010000100110101100100'

We can also change the name of the module we need to call by using the as keyword, then we can call the functions by using CAT instead. This time we will use the IPNetwork function to figure out the subnet mask.

In [12]: import netaddr as CAT        

In [13]: net = CAT.IPNetwork('192.168.77.0/23')        

In [14]: net.netmask    

Out[14]: IPAddress('255.255.254.0')

Lastly if you don’t want to call the module every time we can directly import the commands so we can directly call the functions.

In [15]: from netaddr import *        

In [16]: newnet = IPNetwork('192.168.88.0/12')        

In [17]: newnet.netmask    

Out[17]: IPAddress('255.240.0.0')

If you need to brush up on what a module can do you can use the help command to pull up the module’s help file.

In [15]: help(net)

Help on IPNetwork in module netaddr.ip object:

In [15]: help(net)

Help on IPNetwork in module netaddr.ip object:
 
 class IPNetwork(BaseIP, IPListMixin)
 | An IPv4 or IPv6 network or subnet.
 | 
 | A combination of an IP address and a network mask.
 | 
 | Accepts CIDR and several related variants :
 | 
 | a) Standard CIDR::
 | 
 | x.x.x.x/y -> 192.0.2.0/24
 | x::/y -> fe80::/10
 | 
 | b) Hybrid CIDR format (netmask address instead of prefix), where 'y' address represent a valid netmask::
 | 
 | x.x.x.x/y.y.y.y -> 192.0.2.0/255.255.255.0
 | x::/y:: -> fe80::/ffc0::
 | 
 | c) ACL hybrid CIDR format (hostmask address instead of prefix like Cisco's ACL bitmasks), where 'y' address represent a valid netmask::
 | 
 | x.x.x.x/y.y.y.y -> 192.0.2.0/0.0.0.255
 | x::/y:: -> fe80::/3f:ffff:ffff:ffff:ffff:ffff:ffff:ffff
 | 
 | d) Abbreviated CIDR format (as of netaddr 0.7.x this requires the optional constructor argument ``implicit_prefix=True``)::
 | 
 | x -> 192
 | x/y -> 10/8
 | x.x/y -> 192.168/16
 | x.x.x/y -> 192.168.0/24
 | 
 | which are equivalent to::
 | 
 | x.0.0.0/y -> 192.0.0.0/24
 | x.0.0.0/y -> 10.0.0.0/8
 | x.x.0.0/y -> 192.168.0.0/16
 | x.x.x.0/y -> 192.168.0.0/24

Another highly useful thing is using loops to run through a bunch of data, lets use netaddr to return all the IPs in a /28 subnet.

 In [27]: for ip in IPNetwork('172.10.9.230/28'):
 ...: print ip
 ...: 
 ...: 
 172.10.9.224
 172.10.9.225
 172.10.9.226
 172.10.9.227
 172.10.9.228
 172.10.9.229
 172.10.9.230
 172.10.9.231
 172.10.9.232
 172.10.9.233
 172.10.9.234
 172.10.9.235
 172.10.9.236
 172.10.9.237
 172.10.9.238
 172.10.9.239

Get on with the Cisco!Get on with the Cisco!

Let’s close out this intro to python by showing off a simple python script that will collect show ip interface brief from a few routers.
First we will import netmiko which is a good Cisco friendly ssh module for python

  #!/bin/env python
 
 from netmiko import ConnectHandler

Next we will tell netmiko how to connect to each router, there are quite a few different ways we can do it but I’ll make a dictionary that contains the various connection parameters for each device. BTW you can use # to make comments to explain what you are doing in your code, it is a good idea to make notes as you go so you understand your code later or so other people can follow your logic.

  #Add Device Info
 
 R01 = {
 'device_type': 'cisco_ios',
 'ip': '10.10.21.101',
 'username': 'admin',
 'password': 'meowcat',
 'secret': 'meowcat',
 'verbose': False,
 }
 
 R02 = {
 'device_type': 'cisco_ios',
 'ip': '10.10.21.102',
 'username': 'admin',
 'password': 'meowcat',
 'secret': 'meowcat',
 'verbose': False,
 }
 
 R03 = {
 'device_type': 'cisco_ios',
 'ip': '10.10.21.103',
 'username': 'admin',
 'password': 'meowcat',
 'secret': 'meowcat',
 'verbose': False,
 }

Once they are all made I will group them all in to a variable we can call.

 #Make Varible for routers
 all_routers = [R01,R02,R03]

Then we simply make a loop that connects to each device and runs the show ip int brief command  then displays the output in a pretty way.

#Loop to collect "show ip int brief" and display it        
for router in all_routers:
    net_connect = ConnectHandler(**router)
    output = net_connect.send_command("show ip interface brief")
    print "\n **************** {0} ************".format(router['ip'])
    print output    print "**************** END ****************\n"

Output

Here is what things look like when we are done. Something like this could be useful if you need to collect info across several different devices.

 python "C:\Users\the-packet-thrower\cisco.py"
 **************** 10.10.21.101 ************
 
 Interface IP-Address OK? Method Status Protocol
 
 GigabitEthernet1 10.10.21.101 YES DHCP up up 
 
 GigabitEthernet2 unassigned YES NVRAM up up 
 
 GigabitEthernet2.12 10.1.2.1 YES manual up up 
 
 GigabitEthernet3 unassigned YES NVRAM administratively down down 
 
 Loopback0 192.168.254.1 YES manual up up 
 
 **************** END ****************
 
 **************** 10.10.21.102 ************
 
 Interface IP-Address OK? Method Status Protocol
 
 GigabitEthernet1 10.10.21.102 YES DHCP up up 
 
 GigabitEthernet2 unassigned YES unset up up 
 
 GigabitEthernet2.12 10.1.2.2 YES manual up up 
 
 GigabitEthernet2.23 10.2.3.2 YES manual up up 
 
 Loopback0 192.168.254.2 YES manual up up 
 
 **************** END ****************
 
 **************** 10.10.21.103 ************
 
 Interface IP-Address OK? Method Status Protocol
 
 GigabitEthernet1 10.10.21.103 YES DHCP up up 
 
 GigabitEthernet2 unassigned YES unset up up 
 
 GigabitEthernet2.23 10.2.3.3 YES manual up up 
 
 GigabitEthernet2.34 10.3.4.3 YES manual up up 
 
 Loopback0 192.168.254.3 YES manual up up 
 
 **************** END ****************

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.