1

I have this JSON in a variable :

{
"device_vlans": {
    "1": {
        "name": "default",
        "interfaces": [
            "GigabitEthernet1/1",
            "GigabitEthernet1/2",
            "GigabitEthernet1/3"
        ]
    },
    "20": {
        "name": "VLAN20",
        "interfaces": [
            "GigabitEthernet1/2"
        ]
    },
    "30": {
        "name": "VLAN30",
        "interfaces": [
            "GigabitEthernet1/3"
        ]
    }
}

But I need it to look more like this :

{
"device_vlans": {
    "GigabitEthernet1/1": {
        "vlans": [
            "1"
        ]
    },
    "GigabitEthernet1/2": {
        "vlans": [
            "1",
            "20"
        ]
    },
    "GigabitEthernet1/3": {
        "vlans": [
            "1",
            "30"
        ]
    }
}

Currently I'm looping over all interfaces of the device and inside that loop I'm looping over all items in the device_vlans variable with a when: item == interface. It's really slow and causing me problems..

Is there any better way of doing that with ansible ?

I thought of a custom filter would that be the solution ?

raw
  • 91
  • 2
  • 7

1 Answers1

2

Create a list of devices and interfaces

    - set_fact:
        dev_ifc: "{{ dev_ifc|d([]) + [{'dev': item.1, 'ifc': item.0.key}] }}"
      with_subelements:
        - "{{ device_vlans|dict2items }}"
        - value.interfaces

gives

  dev_ifc:
    - {dev: GigabitEthernet1/1, ifc: '1'}
    - {dev: GigabitEthernet1/2, ifc: '1'}
    - {dev: GigabitEthernet1/3, ifc: '1'}
    - {dev: GigabitEthernet1/2, ifc: '20'}
    - {dev: GigabitEthernet1/3, ifc: '30'}

Then, group the list by the devices and create the dictionary

    - set_fact:
        device_vlans: "{{ dict(key|zip(val)) }}"
      vars:
        arr: "{{ dev_ifc|groupby('dev') }}"
        key: "{{ arr|map('first')|list }}"
        val: "{{ arr|map('last')|
                     map('json_query', '[].ifc')|
                     map('community.general.dict_kv', 'interfaces')|
                     list }}"

gives

  device_vlans:
    GigabitEthernet1/1:
      interfaces: ['1']
    GigabitEthernet1/2:
      interfaces: ['1', '20']
    GigabitEthernet1/3:
      interfaces: ['1', '30']

It's possible to avoid iteration in a task. Instead, put the iteration into Jinja2. For example, put the declarations below as appropriate

    dev_ifc_str: |-
      {% for ifc in device_vlans.keys() %}
      {% for dev in device_vlans[ifc]['interfaces'] %}
      - {dev: {{ dev }}, ifc: {{ ifc }}}
      {% endfor %}
      {% endfor %}
    dev_ifc: "{{ dev_ifc_str|from_yaml }}"
    device_vlans2: "{{ dict(_key|zip(_val)) }}"
    _arr: "{{ dev_ifc|groupby('dev') }}"
    _key: "{{ _arr|map('first')|list }}"
    _val: "{{ _arr|map('last')|
                   map('json_query', '[].ifc')|
                   map('community.general.dict_kv', 'interfaces')|
                   list }}"
Vladimir Botka
  • 5,138
  • 8
  • 20