Read a particular status keyword from Cisco output in Ansible

112 Views Asked by At

I am trying to run a show command on a cisco router to find out the down interfaces.

I would like to print only the Ethernet Interface name(for eg:Eth1/3) for those are having the Status as down in the command output in a JSON fromat.

Cisco output(input.json)

[
    [
        [
            "--------------------------------------------------------------------------------",
            "Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port",
            "Interface                                                                    Ch #",
            "--------------------------------------------------------------------------------",
            "Eth1/20         --      eth  routed down    XCVR not inserted        auto(D) --"
        ]
    ],
    [
        [
            "--------------------------------------------------------------------------------",
            "Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port",
            "Interface                                                                    Ch #",
            "--------------------------------------------------------------------------------",
            "Eth1/21         --      eth  routed down    XCVR not inserted        auto(D) --"
        ]
    ],
    [
        [
            "--------------------------------------------------------------------------------",
            "Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port",
            "Interface                                                                    Ch #",
            "--------------------------------------------------------------------------------",
            "Eth1/22         --      eth  routed down    XCVR not inserted        auto(D) --"
        ]
    ],
    [
        [
            "--------------------------------------------------------------------------------",
            "Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port",
            "Interface                                                                    Ch #",
            "--------------------------------------------------------------------------------",
            "Eth1/23         --      eth  routed down    XCVR not inserted        auto(D) --"
        ]
    ]
]

Playbook

    - name: Set global device name
      set_fact:
        global_device_name: "{{ device_name }}"
  

    - name: Execute command on interfaces
      cisco.ios.ios_command:
        commands:
          -  "show interface {{ item }} brief"
      loop: "{{ hostvars[global_device_name]['ports'] }}"
      delegate_to: "{{ global_device_name }}"
      register: command_output
      changed_when: false
    
    - name: Create a list of interface details
      set_fact:
        interface_list: "{{ interface_list|default([]) + [item.stdout_lines] }}"
      loop: "{{ command_output.results }}"
      loop_control:
        label: "{{ item.item }}"
      
    - name: Save output to JSON file
      copy:
        content: "{{ interface_list  | to_nice_json}}"
        dest: output.json
    
    - name: Firewall Rule Create/Update variable
      set_fact: 
        command_output: "{{ lookup('file', 'output.json') }}"  
    
    - name: Firewall Rule Create/Update variable
      set_fact:   
        interface_details: "{{ command_output|map('flatten')}}"
    
    - name: Format output
      debug:
        msg: "{{ interface_details  }}"

Here the interface_details is the Cisco output

With the above playbook i am getting an empty array.

1

There are 1 best solutions below

4
Vladimir Botka On

Given the file command_output.yml for testing

shell> cat command_output.yml
[
  [
    [
      "--------------------------------------------------------------------------------",
      "Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port",
      "Interface                                                                    Ch #",
      "--------------------------------------------------------------------------------",
      "Eth1/1          1       eth  trunk  down    XCVR not inserted        auto(D) --"
    ]
  ],
  [
    [
      "--------------------------------------------------------------------------------",
      "Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port",
      "Interface                                                                    Ch #",
      "--------------------------------------------------------------------------------",
      "Eth1/2          1       eth  trunk  down    XCVR not inserted        auto(D) --"
    ]
  ],
  [
    [
       "--------------------------------------------------------------------------------",
      "Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port",
      "Interface                                                                    Ch #",
      "--------------------------------------------------------------------------------",
      "Eth1/3          1       eth  trunk  down    XCVR not inserted        auto(D) --"
    ]
  ]
]

Read the file and flatten the lists

  command_output: "{{ lookup('file', 'command_output.yml') }}"
  interface_details: "{{ command_output|map('flatten') }}"

gives

  interface_details:
  - - '--------------------------------------------------------------------------------'
    - Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port
    - 'Interface                                                                    Ch #'
    - '--------------------------------------------------------------------------------'
    - Eth1/1          1       eth  trunk  down    XCVR not inserted        auto(D) --
  - - '--------------------------------------------------------------------------------'
    - Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port
    - 'Interface                                                                    Ch #'
    - '--------------------------------------------------------------------------------'
    - Eth1/2          1       eth  trunk  down    XCVR not inserted        auto(D) --
  - - '--------------------------------------------------------------------------------'
    - Ethernet        VLAN    Type Mode   Status  Reason                 Speed     Port
    - 'Interface                                                                    Ch #'
    - '--------------------------------------------------------------------------------'
    - Eth1/3          1       eth  trunk  down    XCVR not inserted        auto(D) --

Get the dictionary interface_status

  interface_status: |
    {% filter from_yaml %}
    {% for i in interface_details %}
    {% set val=i.4|split() %}
    {{ val.0 }}: {{ val.4 }}
    {% endfor %}
    {% endfilter %}

gives

  interface_status:
    Eth1/1: down
    Eth1/2: down
    Eth1/3: down

Optionally, the declarations below give the same result

  interface_values: "{{ interface_details|
                        map(attribute='4')|
                        map('split') }}"
  interface_status: "{{ dict(interface_values|map(attribute='0')|
                             zip(interface_values|map(attribute='4'))) }}"

and select(filter) the the interfaces

  interface_filtered: "{{ interface_status|dict2items|
                          selectattr('value', 'eq','down')|
                          map(attribute='key') }}"

gives

  interface_filtered:
  - Eth1/1
  - Eth1/2
  - Eth1/3

Example of a complete playbook for testing

- hosts: localhost

  vars:

    command_output: "{{ lookup('file', 'command_output.yml') }}"
    interface_details: "{{ command_output|map('flatten') }}"

    interface_status: |
      {% filter from_yaml %}
      {% for i in interface_details %}
      {% set val=i.4|split() %}
      {{ val.0 }}: {{ val.4 }}
      {% endfor %}
      {% endfilter %}
    interface_values: "{{ interface_details|
                          map(attribute='4')|
                          map('split') }}"
    interface_statu2: "{{ dict(interface_values|map(attribute='0')|
                               zip(interface_values|map(attribute='4'))) }}"
    interface_filtered: "{{ interface_status|dict2items|
                            selectattr('value', 'eq','down')|
                            map(attribute='key') }}"

  tasks:

    - debug:
        var: interface_details
    - debug:
        var: interface_status
    - debug:
        var: interface_statu2
    - debug:
        var: interface_filtered