Skip to main content
  1. Posts/

Ansible: Parse Cisco commando ouputs with TEXTFSM

·390 words·2 mins·
netdevops blog cisco textfsm ansible
Maximilian Thoma
Author
Maximilian Thoma
network engineer
Table of Contents

To parse outputs of commands in Ansible you can use TEXTFSM. You need to install textfsm with pip.

TEXTFSM is a template based parser for commandline outputs.

Install of the required packages
#
python -m virtualenv venv
source venv/bin/activate
pip install ansible ansible-pylibssh textfsm
Example: TEXTFSM parser file inventory_cisco_ios.textfsm
#

There are already ready-made templates for many network manufacturers such as Cisco, I have the example here from networktocode/ntc-templates (Github), as a fork directly from me lanbugs/ntc-templates: TextFSM templates for parsing show commands of network devices (github .com) on Github.

Value NAME (.*)
Value DESCR (.*)
Value PID (([\S+]+|.*))
Value VID (.*)
Value SN ([\w+\d+]+)

Start
  ^NAME:\s+"${NAME}",\s+DESCR:\s+"${DESCR}"
  ^PID:\s+${PID}.*,.*VID:\s+${VID},.*SN:\s+${SN} -> Record
  ^PID:\s+,.*VID:\s+${VID},.*SN: -> Record
  ^PID:\s+${PID}.*,.*VID:\s+${VID},.*SN: -> Record
  ^PID:\s+,.*VID:\s+${VID},.*SN:\s+${SN} -> Record
  ^PID:\s+${PID}.*,.*VID:\s+${VID}.*
  ^PID:\s+,.*VID:\s+${VID}.*
  ^.*SN:\s+${SN} -> Record
  ^.*SN: -> Record
  # Capture time-stamp if vty line has command time-stamping turned on
  ^Load\s+for\s+
  ^Time\s+source\s+is
Example: Ansible playbook collect_inventory.yml
#

The module ansible.utils.cli_parse is used and as a parser ansible.utils.textfsm. The textfsm file that can parse the output is specified as template_path.

---
- name: Collect invenory of device
  hosts: testswitch
  gather_facts: False

  vars:
    ansible_connection: network_cli
    ansible_network_os: ios

  connection: network_cli
  
  tasks:
    - name: Collect inventory
      ansible.utils.cli_parse:
        command: show inventory
        parser:
          name: ansible.utils.textfsm
          template_path: inventory_cisco_ios.textfsm
      register: inv

    - name: Debug
      debug:
        msg: "{{ inv }}"
```

##### Example: inventory.ini
```ìni
[devices]
testswitch ansible_host=10.1.1.1 ansible_user=cisco ansible_ssh_pass=cisco
```
##### Output
```
(venv) lab@labhost:~$ ansible-playbook -i inventory.ini collect_inventory.yml                                                 

PLAY [Collect invenory of device] ********************************************************************************************************************************************

TASK [Gather invenory] ***************************************************************************************************************************************************
ok: [testswitch]

TASK [Debug] *************************************************************************************************************************************************************
ok: [testswitch] => {
    "msg": {
        "changed": false,
        "failed": false,
        "parsed": [
            {
                "DESCR": "WS-C3560CG-8PC-S",
                "NAME": "1",
                "PID": "WS-C3560CG-8PC-S",
                "SN": "FOC1234A0ZZ",
                "VID": "V03  "
            }
        ],
        "stdout": "NAME: \"1\", DESCR: \"WS-C3560CG-8PC-S\"\nPID: WS-C3560CG-8PC-S  , VID: V03  , SN: FOC1234A0ZZ",
        "stdout_lines": [
            "NAME: \"1\", DESCR: \"WS-C3560CG-8PC-S\"",
            "PID: WS-C3560CG-8PC-S  , VID: V03  , SN: FOC1234A0ZZ"
        ]
    }
}

PLAY RECAP ***************************************************************************************************************************************************************
testswitch             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
```

In inv.parsed is now a list of dictionaries with the parsed data. In inv.stdout_lines are the originals of the return.

Now you could e.g. write that in a CSV file, here is an addition for the playbook:

```bash
    - name: Add to report
      lineinfile:
        insertafter: EOF
        dest: inv_report.txt
        line: "'{{ inventory_hostname }}','{{ item.NAME|default('no name') }}','{{ item.DESCR|default('no descr') }}','{{ item.PID|default('no pid') }}','{{ item.SN|default('no sn') }}','{{ item.VID|default('no vid') }}'"
      with_list: "{{ inv.parsed }}"
      when: inv.failed is false
      delegate_to: localhost
```

Related

Reboot Accesspoints with Ansible
·160 words·1 min
netdevops blog ansible cisco
Sometimes it is necessary to reboot the accesspoints and if you don`t want to do it by hand let Ansible work for you :-)
dnsq - Tool to check DNS zones syncronity
·302 words·2 mins
netdevops blog dns go
This is my first GO project to learn the programming language :-)
High load on ASA-5500-X Series with Anyconnect DTLS
·604 words·3 mins
troubleshooting blog cisco asa anyconnect vpn
I identified 3 problems at a ASA setup which is used as VPN concentrator for Anyconnect DTLS VPN clients.