Simple Cisco Device Reports with Ansible

A great way to start using Ansible for network automation is for generating reports. This can help familiarize yourself with creating playbooks, their structure, and getting your network environment setup to begin automation. Reports are also good because you are just gathering information – there is no configuration changes so there is no worry about bringing the network down. In this post, I’ll share an HTML report I found and modified from a Red Hat Network Automation Git Hub page.

If you haven’t used Ansible with Cisco gear, you can refer to my last blog post to get an initial setup. I will use the same exact setup for this, but adding more devices into the inventory file and adding a Jinja template that will be used to create the HTML reports. I will be using two Cisco CSR 1000v routers and a 7200 router (all in GNS3) to show how this report can be used for both IOS and IOS-XE routers. Below is a layout of the files I used for this report:

  • inventory (inventory file)
  • group_vars/ios (variables file)
  • main.yml (playbook)
  • iosReport.j2 (jinja2 template)

The inventory file is simple and just contains the IP addresses of the hosts I will run the report on:

[ios]
192.168.122.2
10.1.1.2
10.1.2.2

Now we have the variables file. Because all of my devices are in the same [ios] group in my inventory, I can put all the common variables into the group_vars/ios file:

ansible_connection: network_cli
ansible_become: yes
ansible_become_method: enable
ansible_network_os: cisco.ios.ios
ansible_user: otaku

The difference between this group_vars file and the one in my last blog is that I moved the ansible_connection out of the playbook and into the variables file. This is a basic group_vars file and will serve as a solid one to use for many playbooks using Cisco IOS/IOS-XE devices. Make sure you have the user set to whatever username is configured on your devices. Moving all of these common variables into a group_vars file will tidy up your playbooks and let you focus on just the tasks you need to accomplish.

Next up we have the playbook, which is actually very simple:

---

- name: Generating an HTML report
  gather_facts: false 
  hosts: all
  tasks:

    - name: Gather the facts
      ios_facts:
      register: all_facts

    - name: Create HTML report
      template:
        src: iosReport.j2
        dest: inventory_report.html
      delegate_to: localhost
      run_once: true

We only have two simple tasks here: gather all the facts from the device and then generate an HTML file based on our jinja2 template. The key for the ios_facts task is that we register it. This will save each fact as a variable that we will then use to populate the template. For the template task, we have to supply it a source and destination. The source is our iosReport.j2 template, and you can name the destination whatever you would like. Giving it the .html file extension will make it easy to double click and have open in your default web browser.

If you read my jinja2 templates post from a while back, you will remember that we don’t have to connect to a device to create a file from the template. Because of that, we add the ‘delegate_to: localhost’ line to tell ansible that we generate that locally, not by connecting to the devices in our inventory. Additionally, because we are doing the template generation locally on the machine running ansible, we only need to run it once since ansible has already saved the facts from all three devices. We set ‘run_once’ to true to accomplish that.

The last file for our playbook is the jinja2 template. If you have had any experience in HTML, you will see this is just a simple web page with a table in it. You can add or delete rows as you wish, and you shouldn’t need much explanation on how to do that. Just add another <th>Heading</th> line for a new column header, and then add another <td> </td> line below. You will keep the hostvars[device] portion as this is the logic to run through the specific variables for each host, and you will just change the ‘ansible_net_FACT’ portion. You can look here for a list of all the available facts you could use.

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="css/main.css">
</head>
<body>
<table>
    <thead>
        <tr>
            <th>Hostname</th>
            <th>Model Type</th>
            <th>Serial Number</th>
	    <th>IOS/IOS-XE</th>
            <th>Code Version</th>
        </tr>
    </thead>
    <tbody>
{% for device in groups['ios'] %}
        <tr>
            <td>{{hostvars[device]['ansible_net_hostname']}}</td>
            <td>{{hostvars[device]['ansible_net_model']}}</td>
            <td>{{hostvars[device]['ansible_net_serialnum']}}</td>
	    <td>{{hostvars[device]['ansible_net_iostype']}}</td>
	    <td>{{hostvars[device]['ansible_net_version']}}</td>
	    <td>
        </tr>
{% endfor %}
    </tbody>
</table>

</body>
</html>

The report above will pull the hostname, model type, serial number, IOS type (IOS vs IOS-XE), and the specific code version running. There is a simple ‘for’ loop that will create a new row for each device and populate the variables. Here is a quick breakdown of the pieces of the ‘for’ loop if you aren’t familiar with one.

“for device in groups[‘ios’]” is basically saying that for each item within the group ‘ios’, do the things within this loop. I use the word ‘device’ here, but you can make it anything you want. This confused me at first when I learned about for loops, because I didn’t understand how you could make that word be anything you want. You can mess around with changing it to ‘router’, ‘switch’, or anything else, but you will have to also change the word ‘device’ in each line below.

So for each item that it finds in the group, first the template will generate a new row <tr>. Then, within each row you will create a data cell <td> and inside that data cell will be a variable. All jinja2 variables are contained with double curly brackets {{ }}. Each variable is pulled from the items in the loop (hostvars[device]) and the variable that was saved from gathering the facts ([‘ansible_net_FACT’]). This is where you can run into trouble if you changed ‘device’ in the beginning of the loop but didn’t change it within the variables for each cell.

Once you have all of this, you can simply run the playbook:

ansible-playbook -k -i inventory main.yml

Upon successful completion, there is now a inventory_report.html file in the same directory where I ran the playbook. If I open it up in a web browser, this is what I see:

Simple as that and you have a quick playbook to gather some basic information from all of your devices.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s