Ansible 根据设备名称合并两个列表

问题描述 投票:0回答:2

我有这两个列表:

"list": [
            {
                "DEVICE_NAME": "uscx001.net",
                "IMPLEMENTATION": "system\nInterface range Gi1/10/0/42 to Gi1/10/0/45 Gi2/10/0/32 to Gi2/10/0/34\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force",
                "POST_CHECK": "dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]",
                "PRE_CHECK": "dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]",
                "NO": "1"
            },
            {
                "DEVICE_NAME": "uscx002.net",
                "IMPLEMENTATION": "system\nInterface range Gi1/9/0/9 to Gi1/9/0/12 Gi2/9/0/9 to Gi2/9/0/11\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force",
                "POST_CHECK": "dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]",
                "PRE_CHECK": "dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]",
                "NO": "2"
            }
        ]

  "json": {
    "offset": 0,
    "limit": 1000,
    "search": {},
    "filter_op": "and",
    "total": 701,
    "fields": [
      "ID",
      "Name",
      "PluginKey"
    ],
    "data": [
      {
        "ID": 54,
        "Name": "inet-fw.lab.net",
        "PluginKey": "checkpoint_gaia"
      },
      {
        "ID": 2558,
        "Name": "uscx001.net",
        "PluginKey": "hp_aseries_alt_2"
      },
      {
        "ID": 2559,
        "Name": "uscx002.net",
        "PluginKey": "hp_aseries_alt_2"
      },
      {
        "ID": 2560,
        "Name": "test1.net",
        "PluginKey": "hp_aseries_alt_2"
      }
    ]
  }

目的是创建一个新列表,其中将包含第一个列表以及第二个列表中找到的设备的附加信息 ID 和 PluginKey,因此它将如下所示:

"list2": [
            {
                "DEVICE_NAME": "uscx001.net",
                "IMPLEMENTATION": "system\nInterface range Gi1/10/0/42 to Gi1/10/0/45 Gi2/10/0/32 to Gi2/10/0/34\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force",
                "POST_CHECK": "dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]",
                "PRE_CHECK": "dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]",
                "NO": "1",
                "ID": 2558,
                "PluginKey": "hp_aseries_alt_2"
            },
            {
                "DEVICE_NAME": "uscx002.net",
                "IMPLEMENTATION": "system\nInterface range Gi1/9/0/9 to Gi1/9/0/12 Gi2/9/0/9 to Gi2/9/0/11\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force",
                "POST_CHECK": "dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]",
                "PRE_CHECK": "dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]",
                "NO": "2",
                "ID": 2559,
                "PluginKey": "hp_aseries_alt_2"
            }
        ]

我一直在玩联合收割机、拉链、地图,但它总是只给我一个项目,而不是完整的项目列表。

有人可以帮我完成这项任务吗?

理想情况下,如果我们可以使用过滤器而不是循环,那将是完美的,因为我期望一个包含数千项的非常大的列表 - 这个示例只是非常小的数据提取。

谢谢!!

真诚的,

托马斯

list filter ansible ansible-awx
2个回答
1
投票

这能给你你想要的吗?

    - name: create new list
      set_fact:
        list2: "{{ list2 | default([]) + [item | combine({'ID': device.ID, 'PluginKey': device.PluginKey})] }}"
      loop: "{{ list1 }}"
      vars:
        device: "{{ json2.data | selectattr('Name', 'equalto', item.DEVICE_NAME) | list | first }}"

    - name: debug it
      debug:
        msg: "{{ list2 }}"

0
投票

以下内容自愿详细且不言自明。一旦有了想法就可以随意重构。请注意,此解决方案使用过滤器(尽管它也使用一些模板)并满足您不使用不必要的任务的要求。

此解决方案使用

community.general.lists_mergeby
过滤器。该集合包含在 ansible 社区 pip 包中,但如果您仅安装了 ansible-core,则可能需要安装它:

# Check if collection is installed (example output on my current environment)
$ ansible-galaxy collection list | grep community.general
community.general             8.1.0 

# Install collection if needed
$ ansible-galaxy collection install community.general

以下剧本应该非常清晰易懂:

- hosts: localhost
  gather_facts: false

  vars:
    # Your original `list` renamed to `device_list`
    # on a single json line for legibility
    # Note: `list` is definitely not a good variable name
    # as it may conflict with python builtin class name
    device_list: [{"DEVICE_NAME":"uscx001.net","IMPLEMENTATION":"system\nInterface range Gi1/10/0/42 to Gi1/10/0/45 Gi2/10/0/32 to Gi2/10/0/34\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force","POST_CHECK":"dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]","PRE_CHECK":"dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]","NO":"1"},{"DEVICE_NAME":"uscx002.net","IMPLEMENTATION":"system\nInterface range Gi1/9/0/9 to Gi1/9/0/12 Gi2/9/0/9 to Gi2/9/0/11\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force","POST_CHECK":"dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]","PRE_CHECK":"dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]","NO":"2"}]

    # Your original json on a single line for legibility,
    # encapsulated in a higher level var (as I guess you get
    # that result from a REST call to an API)
    some_uri_response: {"json":{"offset":0,"limit":1000,"search":{},"filter_op":"and","total":701,"fields":["ID","Name","PluginKey"],"data":[{"ID":54,"Name":"inet-fw.lab.net","PluginKey":"checkpoint_gaia"},{"ID":2558,"Name":"uscx001.net","PluginKey":"hp_aseries_alt_2"},{"ID":2559,"Name":"uscx002.net","PluginKey":"hp_aseries_alt_2"},{"ID":2560,"Name":"test1.net","PluginKey":"hp_aseries_alt_2"}]}}

    # Transform the list in json to duplicate key `Name`
    # to `DEVICE_NAME`. The goal is to get a common attribute
    # between the two lists. There are other options here
    # but doing it through templating is quite adapted
    # in that case.
    transformed_json_list: |-
      {% filter from_yaml %}
      {% set transformed_result = [] %}
      {% for entry in some_uri_response.json.data %}
      {% set new_entry = entry | combine({'DEVICE_NAME': entry.Name}) %}
      {{ transformed_result.append(new_entry) }}
      {% endfor %}
      {{ transformed_result }}
      {% endfilter %}

    # Merge the two lists on their common attribute.
    # Elements which are not common will remain in the result
    raw_merged_list: "{{ device_list | community.general.lists_mergeby(transformed_json_list, 'DEVICE_NAME') }}"

    # Filter out elements from json list wich were
    # not present in the list of devices. Here are
    # inferred that devices always have the `IMPLEMENTATION`
    # attribute set. Adapt if you need to be more specific.
    merged_list: "{{ raw_merged_list | selectattr('IMPLEMENTATION', 'defined') }}"

  tasks:
    - name: Show original device list (run with -v to display)
      ansible.builtin.debug:
        var: device_list
        verbosity: 1

    - name: Show original json result (run with -v to display)
      ansible.builtin.debug:
        var: some_uri_response
        verbosity: 1

    - name: Show json list transformed with `DEVICE_NAME` added
      ansible.builtin.debug:
        var: transformed_list

    - name: Show merged list before cleaning out unwanted elements
      ansible.builtin.debug:
        var: raw_merged_list

    - name: Final expected list cleaned out
      ansible.builtin.debug:
        var: merged_list

运行 playbook 会给出(如果您想显示原始变量,请添加

-v

PLAY [localhost] *************************************************************************************************************************************************************************************************************

TASK [Show original device list (run with -v to display)] ********************************************************************************************************************************************************************
skipping: [localhost]

TASK [Show original json result (run with -v to display)] ********************************************************************************************************************************************************************
skipping: [localhost]

TASK [Show json list transformed with `DEVICE_NAME` added] *******************************************************************************************************************************************************************
ok: [localhost] => {
    "transformed_json_list": [
        {
            "DEVICE_NAME": "inet-fw.lab.net",
            "ID": 54,
            "Name": "inet-fw.lab.net",
            "PluginKey": "checkpoint_gaia"
        },
        {
            "DEVICE_NAME": "uscx001.net",
            "ID": 2558,
            "Name": "uscx001.net",
            "PluginKey": "hp_aseries_alt_2"
        },
        {
            "DEVICE_NAME": "uscx002.net",
            "ID": 2559,
            "Name": "uscx002.net",
            "PluginKey": "hp_aseries_alt_2"
        },
        {
            "DEVICE_NAME": "test1.net",
            "ID": 2560,
            "Name": "test1.net",
            "PluginKey": "hp_aseries_alt_2"
        }
    ]
}

TASK [Show merged list before cleaning out unwanted elements] ****************************************************************************************************************************************************************
ok: [localhost] => {
    "raw_merged_list": [
        {
            "DEVICE_NAME": "inet-fw.lab.net",
            "ID": 54,
            "Name": "inet-fw.lab.net",
            "PluginKey": "checkpoint_gaia"
        },
        {
            "DEVICE_NAME": "test1.net",
            "ID": 2560,
            "Name": "test1.net",
            "PluginKey": "hp_aseries_alt_2"
        },
        {
            "DEVICE_NAME": "uscx001.net",
            "ID": 2558,
            "IMPLEMENTATION": "system\nInterface range Gi1/10/0/42 to Gi1/10/0/45 Gi2/10/0/32 to Gi2/10/0/34\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force",
            "NO": "1",
            "Name": "uscx001.net",
            "POST_CHECK": "dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]",
            "PRE_CHECK": "dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]",
            "PluginKey": "hp_aseries_alt_2"
        },
        {
            "DEVICE_NAME": "uscx002.net",
            "ID": 2559,
            "IMPLEMENTATION": "system\nInterface range Gi1/9/0/9 to Gi1/9/0/12 Gi2/9/0/9 to Gi2/9/0/11\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force",
            "NO": "2",
            "Name": "uscx002.net",
            "POST_CHECK": "dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]",
            "PRE_CHECK": "dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]",
            "PluginKey": "hp_aseries_alt_2"
        }
    ]
}

TASK [Final expected list cleaned out] ***************************************************************************************************************************************************************************************
ok: [localhost] => {
    "merged_list": [
        {
            "DEVICE_NAME": "uscx001.net",
            "ID": 2558,
            "IMPLEMENTATION": "system\nInterface range Gi1/10/0/42 to Gi1/10/0/45 Gi2/10/0/32 to Gi2/10/0/34\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force",
            "NO": "1",
            "Name": "uscx001.net",
            "POST_CHECK": "dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]",
            "PRE_CHECK": "dis inter brief | inc 1/10/0/4[2345]|2/10/0/3[234]",
            "PluginKey": "hp_aseries_alt_2"
        },
        {
            "DEVICE_NAME": "uscx002.net",
            "ID": 2559,
            "IMPLEMENTATION": "system\nInterface range Gi1/9/0/9 to Gi1/9/0/12 Gi2/9/0/9 to Gi2/9/0/11\ndefault\nport link-mode bridge\ndescription *::HP-HSP::Available::::\nport access vlan 999\nshutdown\nreturn\nsave force",
            "NO": "2",
            "Name": "uscx002.net",
            "POST_CHECK": "dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]",
            "PRE_CHECK": "dis inter brief | inc 1/9/0/9|1/9/0/1[012]|2/9/0/9|2/9/0/1[01]",
            "PluginKey": "hp_aseries_alt_2"
        }
    ]
}

PLAY RECAP *******************************************************************************************************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0   
© www.soinside.com 2019 - 2024. All rights reserved.