Ansible如何按device属性合并两个列表?求正确实现方式
如何用Jinja2过滤器按device属性合并两个列表?
我有两个通过API调用获取的列表,需要按device属性进行合并。以下是两个列表的打印输出:
List1
TASK [Print List1] ************************************************************************************************************************************************************************************** ok: [localhost] => { "msg": [ [ { "device": "LTM1_Device", "link": "LTM1_Link", "ltm_pool": "LTM1_Pool" }, { "device": "LTM2_Device", "link": "LTM2_Link", "ltm_pool": "LTM2_Pool" }, { "device": "LTM3_Device", "link": "LTM3_Link", "ltm_pool": "LTM3_Pool" } ] ] }
List2
TASK [Print List2] **************************************************************************************************************************************************************************************************** ok: [localhost] => { "msg": [ [ { "device": "LTM1_Device", "host": "/Common/LTM1_Host1", "ip": "0.0.0.1", "port": "5555" }, { "device": "LTM1_Device", "host": "/Common/LTM1_Host2", "ip": "0.0.0.2", "port": "5555" }, { "device": "LTM2_Device", "host": "/Common/LTM2_Host1", "ip": "0.0.0.3", "port": "5555" }, { "device": "LTM2_Device", "host": "/Common/LTM2_Host2", "ip": "0.0.0.4", "port": "5555" }, { "device": "LTM3_Device", "host": "/Common/LTM3_Host1", "ip": "0.0.0.5", "port": "5555" }, { "device": "LTM3_Device", "host": "/Common/LTM3_Host2", "ip": "0.0.0.6", "port": "5555" } ] ] }
尝试过的调试代码
我用了以下两条debug语句,结果都不符合预期:
- name: Debug debug: msg: - "{{ (list2 + list1) | groupby('device') | map('last') | map('combine') | list }}" - "{{ (list2 + list1) | groupby('device') | map('last') | list }}"
当前输出结果
TASK [Debug] **************************************************************************************************************************************************************************************************** ok: [localhost] => { "msg": [ [ { "device": "LTM1_Device", "host": "/Common/LTM1_Host2", "ip": "0.0.0.1", "link": "LTM1_Link", "ltm_pool": "LTM1_Pool", "port": "5555" }, { "device": "LTM2_Device", "host": "/Common/LTM2_Host2", "ip": "0.0.0.3", "link": "LTM2_Link", "ltm_pool": "LTM2_Pool", "port": "5555" }, { "device": "LTM3_Device", "host": "/Common/LTM2_Host2", "ip": "0.0.0.5", "link": "LTM3_Link", "ltm_pool": "LTM3_Pool", "port": "5555" } ], [ [ { "device": "LTM1_Device", "host": "/Common/LTM1_Host1", "ip": "0.0.0.1", "port": "5555" }, { "device": "LTM1_Device", "host": "/Common/LTM1_Host2", "ip": "0.0.0.2", "port": "5555" }, { "device": "LTM1_Device", "link": "LTM1_Link", "ltm_pool": "LTM1_Pool" } ], [ { "device": "LTM2_Device", "host": "/Common/LTM2_Host1", "ip": "0.0.0.3", "port": "5555" }, { "device": "LTM2_Device", "host": "/Common/LTM2_Host2", "ip": "0.0.0.4", "port": "5555" }, { "device": "LTM2_Device", "link": "LTM2_Link", "ltm_pool": "LTM2_Pool" } ], [ { "device": "LTM3_Device", "host": "/Common/LTM3_Host1", "ip": "0.0.0.5", "port": "5555" }, { "device": "LTM3_Device", "host": "/Common/LTM3_Host2", "ip": "0.0.0.6", "port": "5555" }, { "device": "LTM3_Device", "link": "LTM3_Link", "ltm_pool": "LTM3_Pool" } ] ] ] }
第一条语句会丢失List2中每个device对应的第一个host元素,第二条则将元素以嵌套列表形式分开。
期望的合并效果
我希望实现如下合并结果(不介意嵌套列表,后续可自行扁平化):
[ [ { "device": "LTM1_Device", "host": "/Common/LTM1_Host1", "ip": "0.0.0.1", "link": "LTM1_Link", "ltm_pool": "LTM1_Pool", "port": "5555" }, { "device": "LTM1_Device", "host": "/Common/LTM1_Host2", "ip": "0.0.0.2", "link": "LTM1_Link", "ltm_pool": "LTM1_Pool", "port": "5555" } ], [ { "device": "LTM2_Device", "host": "/Common/LTM2_Host1", "ip": "0.0.0.3", "link": "LTM2_Link", "ltm_pool": "LTM2_Pool", "port": "5555" }, { "device": "LTM2_Device", "host": "/Common/LTM2_Host2", "ip": "0.0.0.4", "link": "LTM2_Link", "ltm_pool": "LTM2_Pool", "port": "5555" } ], [ { "device": "LTM3_Device", "host": "/Common/LTM3_Host1", "ip": "0.0.0.5", "link": "LTM3_Link", "ltm_pool": "LTM3_Pool", "port": "5555" }, { "device": "LTM3_Device", "host": "/Common/LTM3_Host2", "ip": "0.0.0.6", "link": "LTM3_Link", "ltm_pool": "LTM3_Pool", "port": "5555" } ] ]
解决方案
可以通过以下步骤实现需求:
- 先将List1转换为以
device为键的字典,方便快速匹配对应属性:
- set_fact: list1_device_map: "{{ list1 | items2dict(key_name='device') }}"
- 对List2按
device分组,然后将每组内的每个元素与字典中对应device的属性合并:
- name: 合并并分组列表 debug: msg: >- {{ list2 | groupby('device') | map('last') | map('map', 'combine', list1_device_map) | list }}
解释
list1 | items2dict(key_name='device'):把List1的元素转成字典,key是device的值,value是对应的整个字典对象。list2 | groupby('device') | map('last'):对List2按device分组,提取每组的元素列表。map('map', 'combine', list1_device_map):对每个分组里的元素,调用combine过滤器,把元素和list1_device_map中对应device的字典合并。
这样就能得到你期望的嵌套列表结构,每个device下的所有host元素都带上了List1中的link和ltm_pool属性。
内容的提问来源于stack exchange,提问作者cilles
相关产品推荐
相关产品推荐

