Ansible 搜索列表,如果找到匹配项,则将值作为新值附加到字典

Ansible search a list and if a match is found append value as a new value to the dict

我通过 API 收集了一本字典,如下所示,

ok: [localhost] => {
    "filtered_inventory": [
        {
            "Manufacturer": "",
            "Name": "daughtercard 0/0/CPU0",
            "Serial_number": "serial",
            "device_id": 287,
            "part_id": "ASR9001-LC"
        },
        {
            "Manufacturer": "",
            "Name": "module mau 0/0/2/3",
            "Serial_number": "serial",
            "device_id": 287,
            "part_id": "SFP-10G-SR"
        },

我还使用以下 API 来获取以下值,但它存储为列表

ok: [localhost] => {
"devices": [
    {
        "device_id": 287,
        "hostname": "example.test.com"
    },
    {
        "device_id": 350,
        "hostname": "example.test.se"
    },

我想要实现的是,如果 device_id 在列表和字典中相同,则将主机名附加到字典中。我已经用下面的代码解决了这个问题,但是因为我正在使用一个大字典,所以它非常低效,运行 下面的循环需要大约 1 小时并占用大量内存。

  - name: Merge hostname with inventory
    #no_log: True
    set_fact:
      merged_list: "{{ merged_list|default([]) +
        [{'hostname': item[0].hostname|upper,
        'device_id': item[0].device_id,
        'serial': item[1].Serial_number,
        'Name': item[1].Name,
        'Manufacturer': item[1].Manufacturer,
        'part_id': item[1].part_id}] }}"
    when: "item[0].device_id == item[1].device_id"
    loop: "{{ query('nested', devices, filtered_inventory) }}"

到目前为止,我一直在想这可能可以通过循环遍历字典然后将其与列表匹配来解决,但还没有想出如何做到这一点,有什么想法吗?

我认为下面的代码可能是一个开始,但我尝试了几种不同的方法但未能让它发挥作用。

  - name: Merge hostname with inventory
    #no_log: True
    set_fact:
      merged_list: "{{ merged_list|default([]) + [item|combine
        ({'device_id': item.device_id,
        'serial': item.Serial_number,
        'Name': item.Name,
        'Manufacturer': item.Manufacturer,
        'part_id': item.part_id,
        'hostname': '' })] }}"
    loop: "{{ filtered_inventory }}"
    when:
      - "item.device_id is in devices|json_query(query)"
    vars:
      query: "'[*].device_id'"

创建主机名字典,例如

    - set_fact:
        devices_dict: "{{ devices|items2dict(key_name='device_id', value_name='hostname') }}"

给予

  devices_dict:
    287: example.test.com
    350: example.test.se

然后,使用这个字典来组合修改列表的项目,例如

    - set_fact:
        fi2: "{{ fi2|default([]) +
                 [item|combine({'hostname': devices_dict[item.device_id]})] }}"
      loop: "{{ filtered_inventory }}"

给予

  fi2:
  - Manufacturer: ''
    Name: daughtercard 0/0/CPU0
    Serial_number: serial
    device_id: 287
    hostname: example.test.com
    part_id: ASR9001-LC
  - Manufacturer: ''
    Name: module mau 0/0/2/3
    Serial_number: serial
    device_id: 287
    hostname: example.test.com
    part_id: SFP-10G-SR

问:"大约需要 6 分钟才能 运行 ..."

A:这太过分了。试试下面的过滤器

shell> cat filter_plugins/combine_attr.py
def combine_attr(l, d, k, v):
    x = []
    for i in l:
        i[k] = d[i[v]]
        x.append(i)
    return x

class FilterModule(object):
    ''' Ansible filter. Add an attribute to the dictionaries in the list.'''

    def filters(self):
        return {
            'combine_attr': combine_attr,
            }

例如

    - set_fact:
        fi2: "{{ filtered_inventory|
                 combine_attr(devices_dict, 'hostname', 'device_id') }}"