Parse complex data in ansible

I have fetched data from remote firewall device using ssh in ansible .
I got the context data in stdout_lines in below format.I wanted to form a dict mapped with first and 3rd item in string.How to achieve so?Please help

  • my code!
Example
Output of show context in ansible from remote cisco asa fw device
stdout_lines: [
                       [ 
                             "Context Name           Class                      Interfaces        Mode.                        URL"
                             "  TD-BW-SNSL-Workplace   default       Port-channel1.2345, "   Routed       disk0:/
                             "                                                                        Port-channel10.2298-"
                             "                                                                       2299, Port-,"
                             "                                                                     channel20.2229 "                   
]
]

How can I get the context name and interface from this data in ansible?

The data youve provided is invalid yaml/json, and seems to be irregular as a table (theres no clear correlation between columns in each row). Can you try to provide a better example? As youve posted it, I dont think you can parse it really.

If we clean it up a bit:

# vars.yml
stdout_lines:
  [
    [
      "Context Name           Class                      Interfaces        Mode.                        URL",
      "TD-BW-SNSL-Workplace   default       Port-channel1.2345,    Routed       disk0:/",
      "c2                     default       Port-channel10.2298  Routed  disk0:/",
    ],
  ]

Then this playbook parses it:

- hosts: localhost
  gather_facts: false
  vars_files:
    - vars.yml
  tasks:
    - set_fact:
        s: "{{ (stdout_lines)[0] }}"
    - set_fact:
        contexts: >-
          {{ (contexts | default([])) + [
            item.split()[0] | trim | trim(',')
          ] }}
        interfaces: >-
          {{ (interfaces | default([])) + [
            item.split()[2] | trim | trim(',')
          ] }}
      loop: "{{ s }}"
      when: not item.startswith('Context Name')

    - debug:
        var: contexts
    - debug:
        var: interfaces
    - debug:
        var: contexts | zip(interfaces) | community.general.dict

Heres the (partial) output

TASK [debug] ***********************************************************************************************************************************************************************************************************************************************
ok: [mikemorency] => {
    "contexts": [
        "TD-BW-SNSL-Workplace",
        "c2"
    ]
}

TASK [debug] ***********************************************************************************************************************************************************************************************************************************************
ok: [mikemorency] => {
    "interfaces": [
        "Port-channel1.2345",
        "Port-channel10.2298"
    ]
}

TASK [debug] ***********************************************************************************************************************************************************************************************************************************************
ok: [mikemorency] => {
    "contexts | zip(interfaces) | community.general.dict": {
        "TD-BW-SNSL-Workplace": "Port-channel1.2345",
        "c2": "Port-channel10.2298"
    }
}
1 Like

Thanks for the help.
Below is the format of data coming in from remote device…Is there a way I can parse below data and include the remaining port channel from separate string to first row.

[
                "Context Name      Class                Interfaces           Mode         URL",
                " TD-BW-SNSL-Workplace default              Port-channel1.2345,  Routed       disk0:/TD-BW-SNSL-Workplace.cfg",
                "                                       Port-channel10.2298-",
                "                                       2299,Port-          ",
                "                                       channel20.2229"
            ]

Im not sure I understand, is this the value you want?

[
  "Port-channel1.2345",
  "Port-channel10.2298-2299",
  "Port-channel20.2229"
]

Data is

[
                "Context Name      Class                Interfaces           Mode         URL",
                " TD-BW-SNSL-Workplace default              Port-channel1.2345,  Routed       disk0:/TD-BW-SNSL-Workplace.cfg",
                "                                       Port-channel10.2298-",
                "                                       2299,Port-          ",
                "                                       channel20.2229"
            ]

Output shoulld be
{
{TD-BW-SNSL-Workplace : Port-channel1.2345}, {TD-BW-SNSL-Workplace:Port-channel10.2298-2299}, {TD-BW-SNSL-Workplace: Port- channel20.2229"}
}

I see. This is a very challenging data format. It might be easier to look at ways to get better input data formats instead of parsing this.

Would you have a case where there are multiple contexts? Like

TD-BW-SNSL-Workplace
TD-BW-SNSL-Workplace1
TD-BW-SNSL-Workplace2

This data is generated automatically using ansible ssh to connect to remote cisco asa firewall device and ran the show context command using cisco.asa module of ansible

Can you check below formats if we can fetch data from any of the formats

Output is coming either as

{
    "ansible_facts": {
        "context_names": [
            " ST-BW-SNSL-OPG-COMMSEE default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-OPG-COMMSEE.cfg",
            "                                       Port-channel10.2006-",
            "                                       2007,Port-          ",
            "                                       channel20.2224      ",
            " ST-BW-SNSL-COMMSEC-NONPROD default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-COMMSEC-NONPROD.cfg",
            "                                       Port-channel10.2273-",
            "                                       2276,Port-          ",
            "                                       channel20.2223      ",
            " ST-BW-SNSL-CYBERARK default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-CYBERARK.cfg",
            "                                       Port-channel10.2272,",
            "                                       Port-channel20.2222 ",
            " ST-BW-SNSL-NON-STOP default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-NON-STOP.cfg",
            "                                       Port-channel10.2041-",
            "                                       2054,2108-2115,Port-",
            "                                       channel20.2227      ",
            " ST-BW-SNSL-ENTERPRISE-MF default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-ENTERPRISE-MF.cfg",
            "                                       Port-channel10.2283,",
            "                                       Port-channel20.2226 ",
            " ST-BW-SNSL-DOT   default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-DOT.cfg",
            "                                       Port-channel10.2279-",
            "                                       2282,2284-2287,Port-",
            "                                       channel20.2225      ",
            " ST-BW-SNSL-Internet-Browsing default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-Internet-Browsing.cfg",
            "                                       Port-channel10.1568,",
            "                                       1570,Port-          ",
            "                                       channel20.2228      ",
            " TD-BW-SNSL-Workplace default              Port-channel1.2345,  Routed       disk0:/TD-BW-SNSL-Workplace.cfg",
            "                                       Port-channel10.2298-",
            "                                       2299,Port-          ",
            "                                       channel20.2229      ",
            "",
            "Total active Security Contexts: 9"
        ]
    },
    "changed": false
}

or in format

"stdout": [
        "",
        "Context Name      Class                Interfaces           Mode         URL\n ST-BW-SNSL-OPG-COMMSEE default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-OPG-COMMSEE.cfg\n                                       Port-channel10.2006-\n                                       2007,Port-          \n                                       channel20.2224"
    ],

or the format I have shared earlier

OK, really messy but here it is:

# vars.yml
context_names:
  [
    " ST-BW-SNSL-OPG-COMMSEE default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-OPG-COMMSEE.cfg",
    "                                       Port-channel10.2006-",
    "                                       2007,Port-          ",
    "                                       channel20.2224      ",
    " ST-BW-SNSL-COMMSEC-NONPROD default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-COMMSEC-NONPROD.cfg",
    "                                       Port-channel10.2273-",
    "                                       2276,Port-          ",
    "                                       channel20.2223      ",
    " ST-BW-SNSL-CYBERARK default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-CYBERARK.cfg",
    "                                       Port-channel10.2272,",
    "                                       Port-channel20.2222 ",
    " ST-BW-SNSL-NON-STOP default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-NON-STOP.cfg",
    "                                       Port-channel10.2041-",
    "                                       2054,2108-2115,Port-",
    "                                       channel20.2227      ",
    " ST-BW-SNSL-ENTERPRISE-MF default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-ENTERPRISE-MF.cfg",
    "                                       Port-channel10.2283,",
    "                                       Port-channel20.2226 ",
    " ST-BW-SNSL-DOT   default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-DOT.cfg",
    "                                       Port-channel10.2279-",
    "                                       2282,2284-2287,Port-",
    "                                       channel20.2225      ",
    " ST-BW-SNSL-Internet-Browsing default              Port-channel1.2345,  Routed       disk0:/ST-BW-SNSL-Internet-Browsing.cfg",
    "                                       Port-channel10.1568,",
    "                                       1570,Port-          ",
    "                                       channel20.2228      ",
    " TD-BW-SNSL-Workplace default              Port-channel1.2345,  Routed       disk0:/TD-BW-SNSL-Workplace.cfg",
    "                                       Port-channel10.2298-",
    "                                       2299,Port-          ",
    "                                       channel20.2229      ",
    "",
    "Total active Security Contexts: 9",
  ]
# playbook.yml
- hosts: localhost
  gather_facts: false
  vars_files:
    - vars.yml
  tasks:
    - set_fact:
        context_indices: "{{ context_indices | default([]) + [idx] }}"
      when: item is search('^ \w') or not item
      loop: "{{ context_names }}"
      loop_control:
        index_var: idx

    - set_fact:
        context_groups: >-
          {{ context_groups | default([]) +
          [context_names[context_indices[idx]:context_indices[idx+1]]]
          }}
      when: context_indices[idx+1] is defined
      loop: "{{ context_indices }}"
      loop_control:
        index_var: idx

    - set_fact:
        contexts: "{{ contexts | default([]) + [(item | first | split())[0] | trim()] }}"
        port_channel_first: >-
          {{ port_channel_first | default([]) + [(item | first | split())[2] | trim()] }}
        port_channel_other: >-
          {{ port_channel_other | default([]) +
          [(item[1:] | map('trim') | join()) | default([])]
          }}
      loop: "{{ context_groups }}"

    - set_fact:
        port_channels: >-
          {{ port_channel_first | zip(port_channel_other) | map('join') | map('split', ',') }}

    - set_fact:
        context_port_channel_map: >-
          {{ contexts | zip(port_channels) | community.general.dict }}

    - debug:
        var: context_port_channel_map

Outputs:

TASK [debug] ***********************************************************************************************************************************************************************************************************************************************
ok: [mikemorency] => {
    "context_port_channel_map": {
        "ST-BW-SNSL-COMMSEC-NONPROD": [
            "Port-channel1.2345",
            "Port-channel10.2273-2276",
            "Port-channel20.2223"
        ],
        "ST-BW-SNSL-CYBERARK": [
            "Port-channel1.2345",
            "Port-channel10.2272",
            "Port-channel20.2222"
        ],
        "ST-BW-SNSL-DOT": [
            "Port-channel1.2345",
            "Port-channel10.2279-2282",
            "2284-2287",
            "Port-channel20.2225"
        ],
        "ST-BW-SNSL-ENTERPRISE-MF": [
            "Port-channel1.2345",
            "Port-channel10.2283",
            "Port-channel20.2226"
        ],
        "ST-BW-SNSL-Internet-Browsing": [
            "Port-channel1.2345",
            "Port-channel10.1568",
            "1570",
            "Port-channel20.2228"
        ],
        "ST-BW-SNSL-NON-STOP": [
            "Port-channel1.2345",
            "Port-channel10.2041-2054",
            "2108-2115",
            "Port-channel20.2227"
        ],
        "ST-BW-SNSL-OPG-COMMSEE": [
            "Port-channel1.2345",
            "Port-channel10.2006-2007",
            "Port-channel20.2224"
        ],
        "TD-BW-SNSL-Workplace": [
            "Port-channel1.2345",
            "Port-channel10.2298-2299",
            "Port-channel20.2229"
        ]
    }
}
1 Like

Thank you so much for the quick help,
I will implement the same and get back if encountered any issue

Also one quick query, do we have ansible netbox module which can create interface with virtual device context ? I know the ansible module which can create the interface but haven’t found any attribute using which i can create virtual device context for the interface.

You can search on Ansible galaxy, check here
https://docs.ansible.com/ansible/latest/collections/index.html
or check here
https://docs.ansible.com/ansible/latest/collections/community/general/index.html#plugins-in-community-general

I already checked but could not find any collection to assign virtual device context to interfaces

https://docs.ansible.com/ansible/latest/collections/netbox/netbox/netbox_device_interface_module.html#ansible-collections-netbox-netbox-netbox-device-interface-module

I did not find anything here also
https://docs.ansible.com/ansible/latest/collections/community/general/index.html#plugins-in-community-general