Using Ansible to PUSH Cisco IOS Configurations

There are a lot of very good articles on the Internet about how Network Engineers can use Ansible to create standardized network device configurations or use Ansible with existing network vendor API’s to make changes to network devices. Some of my favorites can be found on the Python for Network Engineers and Jason Edelman’s sites.

However, what if you have [older, legacy] network devices or are running on software revisions that don’t support the newer vendor API’s? What if you need to push a common configuration among a multi-vendor or multi-platform of devices quickly? Pushing configurations quickly is easy with my PyMultiChange tool, but one of its biggest limitations is a multi-[vendor, platform] support – where common configurations may have differing syntax, by [vendor, platform] to accomplish the same task. I have yet to find any blogs on Google that share ideas of this category.

For a while, this led me to believe that it it just wasn’t possible, unless you invested the time in developing the appropriate Ansible modules.  However, I had an idea the other day, which proved that it is possible to push configurations to this category of network devices.

Here is my example playbook:

In this playbook, you can see that I call a group of devices call ‘netdevices’. The first play is to generate the configuration. In this case, I am modifying the snmp-server contact information. It calls a source template called snmp-contact.j2. Here is what the template looks like:

The template calls the ‘contact_name’ variable and destination of the template is in the input directory and named using the ‘hostname’ variable.

The hostname variable is called from host_vars. Here is the host_var for a test device, called core1a:

The contact_name variable is called from group_vars/all. Here is what my group_var/all looks like:

The result is a file in the input directory called core1a.conf, with the following configuration:

Once the configuration file has been created, the next play is called. This play is responsible for pushing the configuration to each device. It runs a local script called netsible.py. The script takes two arguments. The first is the hostname of the device to access. The second is the location of the configuration file that was created.

In the background, the script connects to the network device, via SSH, accesses enable mode, reads the configuration file, then executes each command on the router. The script utilizes my netlib library, to make this process simple. Here is the code for the netsible.py script:

If your device is running on a version of code that doesn’t support ssh, it would be easy, with the netlib library, to utilize telnet. All you would have to do is import the Telnet library via:

Then replace the ssh variable with the Telnet Library.

In the playbook, the ‘delegate_to’ call tells Ansible to run the command locally on the Ansible master, rather than Ansible connecting to the remote devices directly.

Here is what it looks like when I run the playbook:

This obviously works, but it does have a couple limitations, currently the playbook is not multi-[vendor, platform] ready. To do this, I would need to specify host_vars that define each device by vendor or platoform.

For example, I could define a variable called ‘network_platform’ in the host_vars and define each host by platform. I could use the values of IOS, NX-OS, IOS-XR, EOS, or JUN-OS defined as the ‘network_platform’ in the host_vars. Then when I called my playbooks, it could look like:

The other limitation that is that the script writes the configuration to the network devices every time that the playbook is ran, regardless of whether it’s needed or not. For creating an snmp contact, this isn’t a huge deal, with the exception of taking extra CPU cycles. However, what if you ran a playbook that was entirely roll based, and it called a role to define BGP route reflectors. Obviously, this would bounce BGP neighbors every time that you ran the playbook. Basically, it boils down to needing a method of checking whether the configuration is actually needed before the script applies it. This is something that I hope to be able to work on. In the mean time, I hope that you’ve enjoyed this. If you have any ideas, please feel free to share them with me!

I have a generic Github repository that I’ve been using to play with Ansible Network Engineering functionality. Feel free to play with it and contribute to it! Note that ‘netlib‘ is called as a submodule. :) Enjoy!

Share on FacebookTweet about this on TwitterShare on LinkedInShare on RedditEmail this to someone

August 29, 2015

Posted In: Ansible, Cisco Administration Python Scripting, DevOps, IOS, IOS-XE, IOS-XR, Network DevOps, Network Programmability, Python Tips

pyMultiChange rewrite and Netlib

I re-wrote ‘pyMultiChange‘ around my new library for connecting and managing devices. Before I was using ‘pyRouterLib’, but now I’ve deprecated that library with the creation of my new library ‘netlib‘.

Netlib is super easy to use and is more complete than pyRouterLib was. Utilizing Netlib, allowed me to cut the code in pyMultiChange by almost half and netlib is more flexible and user friendly.

To use netlib, first clone the git repo and install the necessary python libraries:

After that, you’re ready to go. Accessing network devices via telnet and ssh are currently supported. Both have a very similar API syntax, that is layed out in the README on github.

Here is an example of how to use the ssh module:

How easy is that? I’m stoked about netlib. It should make rapidly creating code for interact with network devices pretty trivial. I’m experimenting with SNMP functionality, though it’s not ready for prime time.

I also have a method for storing and reading user credentials, so that they don’t have to be stored in the script, called every time a script is run, or entered manually for every device that is accessed.

Let me know what you think, add feature requests, or do a pull request. :)

Share on FacebookTweet about this on TwitterShare on LinkedInShare on RedditEmail this to someone

August 26, 2015

Posted In: Cisco Administration Python Scripting, Python Tips