Getting Structured Data from Cisco IOS Devices using Ansible

  • April 29, 2016

This tutorial shows how to get structured data (JSON) from traditional SSH-enabled network devices that typically return raw text via the CLI. What we show in this tutorial eliminates the need to do manual and tedious parsing of large strings while also simplifying the use of regular expressions.

It's quite simple to do this because there is an Ansible module called ntc_show_command that is a wrapper for both Netmiko and Trigger (both are SSH libraries built for network devices) as well as TextFSM, which was "developed by Google to allow programmatic access to information returned from the command line interface (CLI) of networking devices," as described on their GitHub page.

Note: We don't cover TextFSM because our focus is on the Ansible user experience in this tutorial.

Setup Ansible Inventory

We are going to setup a basic inventory file that has two Cisco IOS routers in it in a single group.

[routers:vars]
username=ntc
password=ntc123

[routers]
176.126.89.81
176.126.91.177

This inventory is saved as the file called hosts.

Create Playbook

All we want to show is the usage of ntc_show_command, so all we really need is a single task in a playbook. We'll save the playbook as get-data.yml

---

- name: GET STRUCTURED DATA BACK FROM CLI DEVICES
  hosts: csr1
  connection: local
  gather_facts: False

  tasks:

    - name: GET SH IP INT BRIEF
      ntc_show_command:
        connection: ssh
        template_dir: /home/ntc/library/ntc-templates/templates/
        platform: cisco_ios
        command: 'show ip interface brief'
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"

The parameters used are as follows:

  • connection: this module supports 4 different connection types. ssh and netmiko_ssh are the same and they are the default. It simply means netmiko will be used as the SSH library under the covers. trigger_ssh is also an option. This is helpful for those who are already using trigger in their environment. Finally, offline is an option for testing.
  • template_dir: use this to specify where your TextFSM templates are located
  • platform: remember, this a multi-vendor module, so when netmiko is used, a platform must be specified. trigger takes care of this in their inventory, so it's technically not needed when using trigger.
  • command: this is the command that will run on the device.
  • The final three are the host/IP information and credentials of the device.
  • There are a few other parameters supported as well that are more advanced, so we'll save them for a future tutorial.

Run the Playbook

To run the playbook, we'll use the -i flag to specify the Ansible inventory.

$ ansible-playbook -i hosts get-data.yml

PLAY [GET STRUCTURED DATA BACK FROM CLI DEVICES] *******************************

TASK [GET SH IP INT BRIEF] *****************************************************
ok: [10.0.0.51]

PLAY RECAP *********************************************************************
10.0.0.51              : ok=1    changed=0    unreachable=0    failed=0   

The quickest way to view the data is to use verbose mode. Now re-run the playbook with the -v flag.

$ ansible-playbook -i hosts get-data.yml -v
Using /etc/ansible/ansible.cfg as config file

PLAY [GET STRUCTURED DATA BACK FROM CLI DEVICES] *******************************

TASK [GET SH IP INT BRIEF] *****************************************************
ok: [10.0.0.51] => {"changed": false, "response": [{"intf": "GigabitEthernet1", "ipaddr": "10.0.0.51", "proto": "up", "status": "up"}, {"intf": "GigabitEthernet2", "ipaddr": "unassigned", "proto": "up", "status": "up"}, {"intf": "GigabitEthernet3", "ipaddr": "unassigned", "proto": "up", "status": "up"}, {"intf": "GigabitEthernet4", "ipaddr": "10.1.12.1", "proto": "up", "status": "up"}], "response_list": []}

PLAY RECAP *********************************************************************
10.0.0.51              : ok=1    changed=0    unreachable=0    failed=0   

If you notice, we are getting structured JSON data back from an IOS device via SSH not using APIs!

The matching output from the CLI that matches is as follows:

csr1#show ip int brief
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       10.0.0.51       YES NVRAM  up                    up      
GigabitEthernet2       unassigned      YES NVRAM  up                    up      
GigabitEthernet3       unassigned      YES NVRAM  up                    up      
GigabitEthernet4       10.1.12.1       YES NVRAM  up                    up  

The key for making this work is ensuring there are TextFSM for the specific platform and command you need to run. You can verify all supported commands and platforms here: https://github.com/networktocode/ntc-templates/tree/master/templates. These are open source and contributions are welcome!

Let's look at one more. This time, we'll get the output from a show version, but rather than using the -v flag, we'll get a pretty output by using the debug module along with the register directive.

$ ansible-playbook -i hosts get-data.yml

PLAY [GET STRUCTURED DATA BACK FROM CLI DEVICES] *******************************

TASK [GET SH VER] **************************************************************
ok: [10.0.0.51]
ok: [10.0.0.52]

TASK [DUMP TO TERMINAL] ********************************************************
ok: [10.0.0.52] => {
    "output": {
        "changed": false, 
        "response": [
            {
                "config_register": "0x2102", 
                "hardware": "CSR1000V", 
                "hostname": "csr2", 
                "running_image": "packages.conf", 
                "serial": "", 
                "uptime": "47 minutes", 
                "version": "15.5(3)S2"
            }
        ], 
        "response_list": []
    }
}
ok: [10.0.0.51] => {
    "output": {
        "changed": false, 
        "response": [
            {
                "config_register": "0x2102", 
                "hardware": "CSR1000V", 
                "hostname": "csr1", 
                "running_image": "packages.conf", 
                "serial": "", 
                "uptime": "47 minutes", 
                "version": "15.5(3)S2"
            }
        ], 
        "response_list": []
    }
}

PLAY RECAP *********************************************************************
10.0.0.52              : ok=2    changed=0    unreachable=0    failed=0   
10.0.0.51             : ok=2    changed=0    unreachable=0    failed=0   

Since the return data from the network devices is now structured, we can use this data as inputs to other tasks in Ansible or in templates to create dynamic and real-time reports.

-Jason