Get the array variable name if the array element matches with a value in Ansible

Viewed 267

I would like to to get the array name (like DNS_One, NTP, etc.), if a particular key value (here cidr) from an input file matches.
I have tried with the below playbook, but that is causing errors.

Input.yaml:

[
    {
        "id": "111177789966",
        "cidr": "10.10.10.10/24"
    },
   
    {
        "id": "13215464897",
        "cidr": "10.100.100.0/24" 
    }
]

Input_var.yaml:

---
Stores:
    -   name: "Test1"
        DNS_One:
             - "10.10.10.10/24"
             - "192.168.1.1/24"
        DNS_One-HO: 
             - "10.20.25.100"
             - "10.100.100.0/24"
    -   name: "Test2"
        DNS_One:
             - "10.20.10.10/24"
             

Expected output:

[
    {
        "id": "111177789966",
        "cidr": "10.10.10.10/24",
        "net_name": "DNS_One"
    },
   
    {
        "id": "13215464897",
        "cidr": "10.100.100.0/24",
        "net_name": "DNS_One-HO"
    }
]

Playbook:

- name: Search
  vars:
        test-merge: >-
            {{ 
                input_var
                | selectattr('name', 'eq', Test1 | string )
                | map(attribute= item)
                | first
                | default([])
            }}
      set_fact:
        po_g: >-
         {{
            po_g | default([]) + 
            [{  
                'id': item.id,
                'cidr': item.cidr,
                'subnetname': test-merge
                 }] 
         }} 
      loop: "{{ input }}"
1 Answers

You will have to use dict2items on the elements of your input_var.Stores list, in order to make it more queryable. You can apply this filter on all the items of the list, with the help of map.

Then you fall back to what you where trying to do, a selectattr to fetch the element that correspond to the CIDR of the input item your are currently looping on. On a list, this can be achieved with the help of the contains test that Ansible provides on top on Jinja builtin tests.

Which ends up in this set_fact:

- set_fact:
    output: >-
      {{
        output | default([])
        + [item | combine({'net_name': DNS.key})]
      }}
  vars: 
    DNS: >-
      {{ 
        input_var.Stores 
        | map('dict2items') 
        | flatten 
        | selectattr('value', 'contains', item.cidr)
        | first
      }}
  loop: "{{ input }}"
  loop_control:
    label: "{{ item.id }}"

Given the playbook:

- hosts: localhost
  gather_facts: no
  vars:
    input:
      - id: "111177789966"
        cidr: 10.10.10.10/24
      - id: "13215464897"
        cidr: 10.100.100.0/24
    input_var:
      Stores:
        - name: Test1
          DNS_One:
            - 10.10.10.10/24
            - 192.168.1.1/24
          DNS_One-HO: 
            - 10.20.25.100
            - 10.100.100.0/24
        - name: Test2
          DNS_One:
            - 10.20.10.10/24

  tasks:
    - set_fact:
        output: >-
          {{
            output | default([])
            + [item | combine({'net_name': DNS.key})]
          }}
      vars: 
        DNS: >-
          {{ 
            input_var.Stores 
            | map('dict2items') 
            | flatten 
            | selectattr('value', 'contains', item.cidr)
            | first
          }}
      loop: "{{ input }}"
      loop_control:
        label: "{{ item.id }}"

    - debug:
        var: output

This yields:

TASK [set_fact] ***************************************************************
ok: [localhost] => (item=111177789966)
ok: [localhost] => (item=13215464897)

TASK [debug] ******************************************************************
ok: [localhost] => 
  output:
  - cidr: 10.10.10.10/24
    id: '111177789966'
    net_name: DNS_One
  - cidr: 10.100.100.0/24
    id: '13215464897'
    net_name: DNS_One-HO
Related