Using Ansible to update your Home Dynamic DNS via Rackspace Cloud DNS

Like most home Internet users, my home Internet has a dynamic IP Address. For many years, I used DynDNS to keep a hostname associated to my home Internet, so that I could access my home resources remotely. After DynDNS started charging for the service, I just created a sub-domain off one of the domains that I own. The problem has always been that I would only find out about my IP Address changing after a failed login attempt. Since then, I have created a couple scripts. However, as I go down the Ansible journey, I try to apply the same problems to Ansible to see how it can solve problems. So, I decided to write a playbook to have Ansible automatically update my DNS record as needed.

Here is the playbook:

As you can see it’s pretty straight forward. I define several facts up front, mostly dealing with the Rackspace Cloud DNS Authentication, domain, and hostname settings. Then I run plays to determine what my current IP Address is, what the DNS A record is, comparing the two, then updating the DNS as needed.

It should be simple enough to run the playbook as a cron-job. So far, it works great!

The playbook is available via my github.

January 29, 2016

Posted In: Ansible, DevOps

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 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 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!

August 29, 2015

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