Search code examples
listdictionaryansiblejson-query

Match a key to value from a dict and replace a value matching another dictionary using ansible


I've a dictionary containing the below items.

PID:
  Cisco:
    - A9K-MOD80-TR
    - A9K-RSP440-TR
    - ASR9001-LC
    - SFP-10G-SR

The above dictionary I want to match with the list below with the following logic, if "SFP-10G-SR" (or any of the other values exist) exist in any of the part_id below, then replace 'Manufacturer' with Cisco (Cisco in this case is the key in the dict PID).

ok: [localhost] => (item={'hostname': '-', 'device_id': 287, 'serial': '-', 'Name': '-', 'Manufacturer': '', 'part_id': 'ASR9001-LC'})
ok: [localhost] => (item={'hostname': '-', 'device_id': 287, 'serial': '-', 'Name': '-', 'Manufacturer': '', 'part_id': 'SFP-10G-SR'})

I've somehow managed to get it to work but it's ugly and it's in a weird format with the below code.

  - name: test
    set_fact:
      new_merged_list: "{{new_merged_list}} {{ item|combine({'Manufacturer': PID|dict2items|json_query(query)}) }}"
    loop: "{{ merged_list | flatten(levels=1) }}"
    vars:
      query: "[?contains(value, '{{item.part_id }}')].key"

  - debug:
      msg: "{{ new_merged_list }}"

It gives me the below output

{
    "msg": " 
    {'hostname': '-', 'device_id': 287, 'serial': '-', 'Name': '-', 'Manufacturer': ['Cisco'], 'part_id': 'ASR9001-LC'} 
    {'hostname': '-', 'device_id': 287, 'serial': '-', 'Name': '-', 'Manufacturer': ['Cisco'], 'part_id': 'SFP-10G-SR'} 
}

If I run a debug on the "new_merged_list" I'm getting the below message

"msg": "AnsibleUnsafeText"

What I want is to keep the above as a dictionary, could anyone assist with a better solution or maybe assist in converting this back to a dictionary? In it's current state I'm having issues working with the "new_merged_list".


Solution

  • Your approach is correct despite the fact that it might seem ugly and weird. Let's simplify the data, e.g.

        PID:
          Cisco: [A, B]
          HP: [C, D]
        merged_list:
            - {Manufacturer: '', part_id: A}
            - {Manufacturer: '', part_id: D}
    

    Your code with only a few modifications

        - set_fact:
            new_merged_list: "{{ new_merged_list|default([]) +
                                 [item|combine({'Manufacturer': manufacturer})] }}"
          loop: "{{ merged_list }}"
          vars:
            _dict: "{{ PID|dict2items }}"
            query: "[?contains(value, '{{ item.part_id }}')].key"
            manufacturer: "{{ _dict|json_query(query)|first }}"
    

    gives the new list

      new_merged_list:
      - Manufacturer: Cisco
        part_id: A
      - Manufacturer: HP
        part_id: D