Home > Net >  Ansible; how to add list of dicts into nested dict?
Ansible; how to add list of dicts into nested dict?

Time:12-19

i have empty dict 'ixes' which should be filled with data from external source collected to 'peeringdb_response_net'.

vars:
  ixes:
    ix_id_001:
      ix_short_name: 'ix1'
      ixlan_id: '331'
      ix_neighbors:
    ix_id_002:
      ix_short_name: 'ix2'
      ixlan_id: '222'
      ix_neighbors:


{
    "peeringdb_response_net": {
        "data": [
            {
                "aka": "BIX.BG",
                "netixlan_set": [
                    {
                        "asn": 15669,
                        "ipaddr4": "193.169.199.10",
                        "ipaddr6": "2001:7f8:58::3d35:0:2",
                        "ixlan_id": 331,
                        "operational": true,
                        "status": "ok",
                    },
                    {
                        "asn": 15669,
                        "ipaddr4": "193.169.198.10",
                        "ipaddr6": "2001:7f8:58::3d35:0:1",
                        "ixlan_id": 331,
                        "operational": true,
                        "status": "ok",
                    }
                ],
            }
        ],
    }
}

please help me find the way to get the following result. the neighbors entries should be filled only if "status": "ok", "operational": true and "ixlan_id" equals. 'ix_neighbor_short_name' should be indexed.

vars:
  ixes:
    ix_id_001:
      ix_short_name: 'ix1'
      ixlan_id: '331'
      ix_neighbors:
        - { ix_neighbor_ipv4_addr: '193.169.199.10', ix_neighbor_short_name: 'rs1' }
        - { ix_neighbor_ipv4_addr: '193.169.198.10', ix_neighbor_short_name: 'rs2' }
    ix_id_002:
      ix_short_name: 'ix2'
      ixlan_id: '222'
      ix_neighbors:

no idea how to code it

CodePudding user response:

Given the data

  peeringdb_response_net:
    data:
      - aka: BIX.BG
        netixlan_set:
        - asn: 15669
          ipaddr4: 193.169.199.10
          ipaddr6: 2001:7f8:58::3d35:0:2
          ixlan_id: 331
          operational: true
          status: ok
        - asn: 15669
          ipaddr4: 193.169.198.10
          ipaddr6: 2001:7f8:58::3d35:0:1
          ixlan_id: 331
          operational: true
          status: ok

Select the sets

  sets: "{{ peeringdb_response_net.data|
            map(attribute='netixlan_set')|
            map('groupby', 'ixlan_id')|
            list }}"

gives

  sets:
  - - - 331
      - - asn: 15669
          ipaddr4: 193.169.199.10
          ipaddr6: 2001:7f8:58::3d35:0:2
          ixlan_id: 331
          operational: true
          status: ok
        - asn: 15669
          ipaddr4: 193.169.198.10
          ipaddr6: 2001:7f8:58::3d35:0:1
          ixlan_id: 331
          operational: true
          status: ok

Use Jinja to create the structure and convert it from YAML

  ixes_str: |
    {% for set in sets %}
    ix_id_{{ "d"|format(loop.index) }}:
      ix_short_name: 'ix{{ loop.index }}'
      ixlan_id: '{{ set.0.0 }}'
      ix_neighbors: [
    {% for neighbor in set.0.1 %}
    {% if neighbor.status == 'ok' and neighbor.operational %}
      {ix_neighbor_ipv4_addr: '{{ neighbor.ipaddr4 }}',
       ix_neighbor_short_name: 'rs{{ loop.index }}'},
    {% endif %}
    {% endfor %}
      ]
    {% endfor %}
  ixes: "{{ ixes_str|from_yaml }}"

gives

  ixes:
    ix_id_001:
      ix_neighbors:
      - ix_neighbor_ipv4_addr: 193.169.199.10
        ix_neighbor_short_name: rs1
      - ix_neighbor_ipv4_addr: 193.169.198.10
        ix_neighbor_short_name: rs2
      ix_short_name: ix1
      ixlan_id: '331'

You can take the default dictionary

  ixes_default:
    ix_id_001:
      ix_short_name: 'ix1'
      ixlan_id: '331'
      ix_neighbors:
    ix_id_002:
      ix_short_name: 'ix2'
      ixlan_id: '222'
      ix_neighbors:

and combine the dictionaries

  ixes: "{{ ixes_default|combine(ixes_str|from_yaml) }}"

gives

  ixes:
    ix_id_001:
      ix_neighbors:
      - ix_neighbor_ipv4_addr: 193.169.199.10
        ix_neighbor_short_name: rs1
      - ix_neighbor_ipv4_addr: 193.169.198.10
        ix_neighbor_short_name: rs2
      ix_short_name: ix1
      ixlan_id: '331'
    ix_id_002:
      ix_neighbors: null
      ix_short_name: ix2
      ixlan_id: '222'

Example of a complete playbook for testing

- hosts: localhost

  vars:

    peeringdb_response_net:
      data:
      - aka: BIX.BG
        netixlan_set:
        - asn: 15669
          ipaddr4: 193.169.199.10
          ipaddr6: 2001:7f8:58::3d35:0:2
          ixlan_id: 331
          operational: true
          status: ok
        - asn: 15669
          ipaddr4: 193.169.198.10
          ipaddr6: 2001:7f8:58::3d35:0:1
          ixlan_id: 331
          operational: true
          status: ok

    sets: "{{ peeringdb_response_net.data|
              map(attribute='netixlan_set')|
              map('groupby', 'ixlan_id')|
              list }}"
    ixes_str: |
      {% for set in sets %}
      ix_id_{{ "d"|format(loop.index) }}:
        ix_short_name: 'ix{{ loop.index }}'
        ixlan_id: '{{ set.0.0 }}'
        ix_neighbors: [
      {% for neighbor in set.0.1 %}
      {% if neighbor.status == 'ok' and neighbor.operational %}
        {ix_neighbor_ipv4_addr: '{{ neighbor.ipaddr4 }}',
         ix_neighbor_short_name: 'rs{{ loop.index }}'},
      {% endif %}
      {% endfor %}
        ]
      {% endfor %}
    ixes1: "{{ ixes_str|from_yaml }}"
    ixes2: "{{ ixes_default|combine(ixes_str|from_yaml) }}"

    ixes_default:
      ix_id_001:
        ix_short_name: 'ix1'
        ixlan_id: '331'
        ix_neighbors:
      ix_id_002:
        ix_short_name: 'ix2'
        ixlan_id: '222'
        ix_neighbors:

  tasks:

    - debug:
        var: peeringdb_response_net
    - debug:
        var: sets
    - debug:
        var: ixes_str
    - debug:
        var: ixes1
    - debug:
        var: ixes2
  • Related