In May I will be teaching an Interop workshop on Python Basics for Networking Professionals. In that course, you will (hopefully) gain an understanding of Python fundamentals that you can build upon to automate tasks in your environment.
While an understanding of programming fundamentals is ultimately essential for automation, it is also helpful to see practical automation examples. In that vein, this article will show you how to use Python to configure BGP on three network devices.
In order to make the example more interesting, this demonstration will use three different platforms -- Arista EOS, Cisco IOS-XR, and Cisco IOS.
Additionally, the program will perform both ‘show’ and ‘config’ operations. In other words, the program will use a combination of operational state information and configuration changes (as well as interactions between the two).
With all that covered...let’s get started.
My lab environment contains these three network devices:
- an Arista vEOS switch running EOS 4.15.4F on KVM,
- a Cisco IOS-XRv router running IOS-XR version 5.3.1 on KVM,
- and a Cisco IOS router running IOS version 15.4(2)T1.
The three devices all share a common LAN subnet (10.220.88.0/24).
In addition to the network devices, I also have an AWS EC2 Linux server running Python 2.7.10. This server has SSH access into the three network devices.

Learn more about Python and how to apply it to network automation in Kirk Byers' half-day workshop, Python Basics for Networking Pros, on May 3 at Interop. Register now for Interop, May 2-6 in Las Vegas. Don’t miss out!
Create the Python environment
The first thing I need to do is set up my Python environment; basically, I want a clean Python environment. In order to accomplish this, I use Python’s virtualenv to create a new sandbox with a minimal set of libraries pre-installed.
The AWS instance that I am using contains multiple versions of Python; consequently, I explicitly specify the Python that I want to use when creating the virtual environment.
$ virtualenv -p /usr/bin/python2.7 bgp_test
Running virtualenv with interpreter /usr/bin/python2.7
New python executable in bgp_test/bin/python2.7
Also creating executable in bgp_test/bin/python
Installing setuptools, pip, wheel...done.
Now that the virtual environment has been created, I next need to ‘activate’ it. This will cause my Python context to switch to the new virtual environment.
$ source ~/VENV/bgp_test/bin/activate
At this point, I am ready to install any libraries that I require.
For this demonstration, I am going to use Netmiko. Netmiko is an open-source Python library based on Paramiko SSH that I have been working on since late 2014. It provides a fairly uniform programming interface across a broad set of network devices. It also handles many of the low-level SSH details that can be time consuming and problematic.
Since Netmiko is based on SSH, it is still a legacy screen-scraping interface. In other words, Netmiko uses an interface primarily intended for humans (SSH) and returns text strings that have to be processed (as contrasted to using an API that returns structured data).
Because I want to use Netmiko version 0.4.2 for this demonstration, I am going to clone the ‘master’ branch from GitHub and then install it.
$ cd ~
$ git clone https://github.com/ktbyers/netmiko
Cloning into 'netmiko'...
remote: Counting objects: 3173, done.
remote: Compressing objects: 100% (118/118), done.
remote: Total 3173 (delta 46), reused 0 (delta 0), pack-reused 3055
Receiving objects: 100% (3173/3173), 600.13 KiB | 619.00 KiB/s, done.
Resolving deltas: 100% (2037/2037), done.
Checking connectivity... done.
$ cd netmiko
$ python setup.py install
Note, you could also just execute ‘pip install netmiko’ but this will get you a slightly older version of Netmiko (Netmiko 0.3.4).
Now I can verify that Netmiko is properly installed:
Note, you could also just execute ‘pip install netmiko’ but this will get you a slightly older version of Netmiko (Netmiko 0.3.4).
Now I can verify that Netmiko is properly installed:
$ python
Python 2.7.10 (default, Dec 8 2015, 18:25:05)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import netmiko
>>> netmiko.__version__
'0.4.2'
The programming environment is now set up correctly. Consequently, I can start working on the basics of the program.
Build the program
The first thing I need to do is establish an SSH connection to each of the three devices. I also need to verify that this connection is working properly.
In order to establish an SSH connection, I need certain information (for example, IP address, SSH port, username, and password). Since I am going to be reusing this information and since some of the information is confidential, I am going to specify this information in a separate Python file named my_devices.py.
This file currently looks as follows:
cisco_ios = {
'device_type': 'cisco_ios_ssh',
'ip': '10.10.10.27',
'username': 'admin',
'password': 'passwd',
'port': 22,
}
cisco_xr = {
'device_type': 'cisco_xr_ssh',
'ip': '10.10.10.27',
'username': 'admin',
'password': 'passwd',
'port': 9722,
}
arista_veos = {
'device_type': 'arista_eos_ssh',
'ip': '10.10.10.27',
'username': 'admin',
'password': 'passwd',
'secret': '',
'port': 8622,
}
The above file contains three Python dictionaries with each dictionary corresponding to one of the network devices.
The mechanics of Python dictionaries are not too important here, but the above definitions provide Netmiko with everything it needs to create the SSH connection. (Note, I have made some minor modifications to the above data to keep my usernames, passwords, and IP addresses private.)
Now that we have defined all of the devices, how do we create a Python script that establishes the SSH connections? What follows is an initial version of the program (this script is also posted online here).
I am going to skip over some of the mechanics of how Python would process this file, but the main program execution starts by calling the main() function. The main function is the line specified by ‘def main():’.
Inside this function, a timestamp is created to indicate the start of the program (it is not quite the start of the program, but it is close enough for our purposes). This will let us keep track of how long the program takes to execute.
The program then enters a small for-loop. This for-loop will take each of the three network devices (defined in the my_devices.py file) and connect to them one after the other.
for a_device in device_list:
net_connect = ConnectHandler(**a_device)
ConnectHandler is a Netmiko function that picks the correct class to use based on the device type (basically one set of code will be executed if the device is ‘Cisco IOS,’ a different set of code will be executed for ‘Cisco IOS XR’, etc.). This ConnectHandler call will cause the SSH connection to be created including logging into the device.
After the connection is completed, I execute a print statement that prints out the type of device and the current router prompt.
Here is what I see when I execute the program:
$ ./load_bgp_config_part1.py
cisco_ios_ssh: pynet-rtr1#
cisco_xr_ssh: RP/0/0/CPU0:pynet-xrv#
arista_eos_ssh: arista-sw5>
Time elapsed: 0:00:06.272486