Capturing show output with Ansible!

In this article I’ll show you an Ansible Playbook that captures show output from multiple show commands on a Cisco router, and then stores the output in a text file that is the hostname of the device. Let’s do this!

But first, if you’re not yet familiar with Ansible I’d like to direct you to my “Starting your Automation Journey with Ansible” mini series.

The Setup

I have four routers in my lab and let’s say I want to capture show output from each. Even though there’s only four of them it’ll still take me so time to connect to each, run the show commands, capture the output, and so forth. Ansible is really great at automation and this includes capturing show output.

In my previous lab articles we did some baseline config and then configured some interfaces for simulated WAN and LAN connections, and we configured EIGRP on the WAN interfaces. Let’s run a playbook to capture the output of some show commands that will verify our previous playbooks deployed successfully.

So, what show commands do we need now? Let’s do a full show run to verify all the new configuration took, a show ip route to ensure that we’ve learned all the new routes we’d expect to, a show ip eigrp neighbors to ensure our adjacencies have formed, and lastly let’s do a show version so we can prepare for an upcoming IOS upgrade.

The Playbook

The Ansible Playbook for this one is going to be pretty simple, only 2 plays. The first play will run the show commands we want the output for, the second play pipes the output to texts files saved on the Ansible server.

---
  - name: capture show output
    hosts: routers
    gather_facts: no
    connection: network_cli

    tasks:
        - name: show run
        ios_command:
          commands:
          - show run
          - show ip route
          - show ip eigrp neighbors
          - show version
        register: config

      - name: save output to local directory
        copy:
          content: "{{ config.stdout | replace('\\n', '\n') }}"           dest: "show-output/{{ inventory_hostname }}.ios"
...

Notice in the beginning of the second play – “replace ‘\\n’, ‘\n'” \n is the ASCII symbol for new line. Ansible was catching the raw output the router was sending over the wire to the terminal emulator software, and for some reason it was getting “\\n” rather than “\n” A co-worker of mine came to me with this issue and we tried to solve it together, he found the fix before I did. The fix was, as you can see here. Without this fix the output was just one big blog of text that wasn’t very human readable.

You can also see the output is stored in a folder called show-output and the file name is the hostname of the device as it appears in the inventory file.

Running the playbook is as easy as running any other Ansible Playbook – ansible-playbook show-commands.yml.

The Result

First, a quick note on the .ios file extension. I use, and love, Visual Studio Code. There’s a handy Cisco IOS add-in for it that will colorize Cisco syntax, like VSC does for other programming languages. If you save files as .ios VSC will know it’s a “Cisco” file type and use the Cisco add-in to colorize the output. It makes it much easier to read and look for import pieces of config. Let’s open one of these files up! Here’s the output from R4:

From the output we can see that all of the interfaces have been configured per the playbook!

Then, here’s our routing table, EIGRP Neighbors, and we can see R4 here is running IOS 15.7(3)M7.

Want a copy?

If you want a copy of this playbook you can grab it from the code snippet earlier in this article, or you can head over to my Git Hub page and grab it from there! Enjoy, and as always you can hit me up on Twitter, the contact page on my blog, or just leave a comment here for any assistance or feedback!

5 thoughts

  1. Thank you! I found this really helpful.

    Regarding the formatting of the output: since stdout is a list, we can call each of the index items. Using another idea I saw online (https://www.reddit.com/r/ansible/comments/bqzyx2/comment/eo9iyrt/?utm_source=share&utm_medium=web2x&context=3), you can combine it so that it looks something like this:

    – name: save output to local directory
    lineinfile:
    line: “{{ config.stdout[item.index] }}\n”
    dest: “show-output/{{ inventory_hostname }}.ios”
    loop_control:
    label: “{{ item.name }}”
    loop:
    – name: show run
    index: 0
    – name: show ip route
    index: 1

    To use the lineinline, you must have created the file beforehand:

    – name: “create .ios file”
    file:
    path: “show-output/{{ inventory_hostname }}.ios”
    state: touch
    mode: 0755

    Like

  2. Thank you! I found this really helpful.

    Regarding the formatting of the output, since stdout is a list, we can call each output using an index. Combining it with a comment I saw on Reddit (https://www.reddit.com/r/ansible/comments/bqzyx2/comment/eo9iyrt/?utm_source=share&utm_medium=web2x&context=3), you can have something like:

    – name: save output to local directory
    lineinfile:
    line: “{{ config.stdout[item.index] }} \n”
    dest: “show-output/{{ inventory_hostname }}.ios”
    loop_control:
    label: “{{ item.name }}”
    loop:
    – name: show run
    index: 0
    – name: show ip route
    index: 1

    To use this method, you must have created the file beforehand:

    – name: “create {{ inventory_hostname }}.ios file”
    file:
    path: “show-output/{{ inventory_hostname }}.ios”
    state: touch
    mode: 0755

    Thanks again!

    Like

  3. Hi. Mine does not issue the second command. What am I missing? It’s only capturing the show version, not the show inventory.

    – name: Run command and save output to file
    hosts: nswbc
    gather_facts: no
    connection: network_cli

    tasks:
    – name: Run show command
    ios_command:
    commands:
    – show version
    – show inventory
    register: term_output

    – name: Save the terminal output to file
    copy:
    content: “{{ term_output.stdout[0] }}”
    dest: “{{ inventory_hostname }}.txt”

    Like

Leave a comment