I hacked together an Ansible module called
ansible-netmiko-stdlib. This post discusses how it can be used, what its
limitations are, and shows an example of the module in action. You can follow
along by grabbing the source for this post’s example
To set up to follow along, you should clone the above repository.
You should have two Cisco IOS devices that are connected to each other.
They can be connected via any type of interface–just make a note of it. You
should edit the ~/git/ios-deploy/hosts file with a name that will resolve to
an IP address for each of the two hosts. If you don’t have FQDNs fro them, you
can modify your /etc/hosts file and add two lines similar to below:
Next, edit the two files in ~/git/ios-deploy/host_vars/. You should only need
to change the interface that is used. Abbreviated interface names (such as
gi3) will work, but ensure that they are unique enough for IOS to decipher the
You should also configure your IOS devices with some basic configuration. At a
minimum, each device should have the following configured:
Interface: admin up and IP address
User: ansible/Ansible123, privilege 15
SSH: SSHv2 for the ansible user
Almost finished! You’ll need the actual Ansible module. Follow the
instructions for the module
Finally, run the playbook: ansible-playbook -i hosts deploy.yml. That command
needs to be run from the repository ios-deploy.
Module in Action
I wrote a role and playbook to show off the module. It’s not terribly complex,
but it does show off the features of the module fairly well. I have two IOS
devices connected to each other. Their interfaces are configured, and there
is a user called ansible that has been configured.
By “their interfaces are configured”, I mean that they have IP addresses and
they are administratively up.
Running the Playbook
Now, let’s see the playbook in action!
Understanding What’s Going On
Looks like a lot going on just to deploy OSPF, right?
Not really. A lot of it is housekeeping. Ensure build and config directories are
clean. Ensure all of the necessary directories exist. Get the current time.
Use Jinja2 to template the OSPF configuration (by way
of the Ansible template module).
Use the netmiko_install_config module to push the config, diff the configs, and
log all of the work.
Reviewing the Results
First, I can tell you that the deploy was successful by logging into the box.
Here’s the output of show ip ospf neighbor detail after I ran the playbook:
Although manually logging in and verifying the expected results is fine
(and a good idea!), it isn’t scalable. Look into automated testing of
your changes. I presented recently on this, and I’ve written a post
with more to follow about automated network testing and verification.
The module will also write logfiles if you pass it the log_file parameter.
Here’s the output of the logs for each router.
They aren’t extremely descriptive, and the logging will be improved over time, but
you can at least get a basic idea of where things might have gone wrong (if, for
example, the authentication failed).
This is a feature that’s particularly powerful: diffing the configs. This is
handled by the module automatically if you pass the diff_file parameter. Let’s
see what it looks like!
I’ve shown you everything except for the actual lines that were sent to the remote
IOS devices. The playbook also records that data. Note that it’s the playbook
that saves a copy of the final config, not the module, and the playbook will
clear out the config directory on its next run–so be sure to review before that
And now you know a lot about everything this playbook just did and can do! What’s
This module is multi-vendor, so if Netmiko
supports a vendor, then so does this module. There’s a caveat, however: the
diff_file parameter only supports devices for which the command to show the
current configuration is show running-config. This will change in future
versions, though, so keep an eye on the changelog!
Another issue that will change in future versions is that this module does not make
changes to the configuration permanent. In other words, it doesn’t run the
copy running-config startup-config or write memory commands.
The above issues will be addressed in the near future. If you want to contribute,
you can open pull requests and I will review and merge them when appropriate to
A very big thank you to Ed Henry who reviewed
this post prior to its publication.