如何在Ansible中合并同键字典生成全局服务器列表
如何在Ansible中将多台服务器的独立字典合并为全局字典?
问题背景
我正在用Ansible完成一项任务,已经通过以下playbook为每台服务器生成了包含Servername、IP-Adresse、OS、Plattform字段的server_list字典:
- name: Create and Add items to server_list set_fact: server_list: "{{ server_list | default({}) | combine ({ item.key : item.value }) }}" with_items: - { 'key': 'Servername' , 'value': "{{ ansible_hostname }}"} - { 'key': 'IP-Adresse' , 'value': "{{ ansible_default_ipv4.address }}"} - { 'key': 'OS' , 'value': "{{ ansible_os_family }} {{ ansible_distribution_major_version }}"} - { 'key': 'Plattform' , 'value': "{{ ansible_system }}"} - name: DEBUG server_list debug: var=server_list
当前每台服务器会输出独立的server_list字典,示例如下:
ok: [XXX] => { "server_list": { "IP-Adresse": "x.x.x.x", "OS": "Debian 11", "Plattform": "Linux", "Servername": "XXX" } } ok: [YYY] => { "server_list": { "IP-Adresse": "x.x.x.y", "OS": "Debian 11", "Plattform": "Linux", "Servername": "YYY" } }
我需要将这些字典合并为一个全局的server_list_dict,格式示例如下:
{ "server_list_dict": { "0": { "Servername": "XXX", "IP-Adresse": "x.x.x.x", "OS": "Debian 11", "Plattform": "Linux" }, "1": { "Servername": "YYY", "IP-Adresse": "x.x.x.y", "OS": "Debian 11", "Plattform": "Linux" } } }
后续计划用这个全局字典通过以下模板生成服务器信息HTML表格:
<table style="width:100%"> <!-- table header --> {% if server_list_dict %} <tr> {% for key in server_list_dict[0] %} <th> {{ key }} </th> {% endfor %} </tr> {% endif %} <!-- table rows --> {% for dict_item in server_list_dict %} <tr> {% for value in dict_item.values() %} <td> {{ value }} </td> {% endfor %} </tr> {% endfor %} </table>
解决方案
核心思路是收集所有主机上的server_list变量,在控制节点组装成全局字典,以下是两种可行实现方式:
方法1:一步生成带数字索引的全局字典
在原playbook末尾添加以下任务,通过delegate_to: localhost指定任务在控制节点执行,避免远程服务器重复操作:
- name: 收集所有主机信息并生成全局字典 delegate_to: localhost set_fact: server_list_dict: "{{ dict( range(0, groups['all'] | length ) | map('string'), groups['all'] | map('extract', hostvars, 'server_list') ) }}" run_once: true
代码说明:
groups['all']:获取所有目标主机的列表map('extract', hostvars, 'server_list'):从每台主机的hostvars中提取server_list字典,生成包含所有服务器信息的列表range(0, groups['all'] | length ) | map('string'):生成从0开始的字符串类型索引(如"0"、"1")dict(...):将索引列表与服务器信息列表配对,生成符合要求的全局字典
方法2:分步实现(逻辑更直观)
如果觉得一步写法过于紧凑,可以拆分为两步:
# 第一步:收集所有主机的server_list为列表 - name: 收集所有主机信息到临时列表 delegate_to: localhost set_fact: server_list_temp: "{{ groups['all'] | map('extract', hostvars, 'server_list') | list }}" run_once: true # 第二步:将列表转换为带数字键的全局字典 - name: 将列表转换为全局字典 delegate_to: localhost set_fact: server_list_dict: "{{ dict( server_list_temp | indices | map('string'), server_list_temp ) }}" run_once: true
代码说明:
server_list_temp:先将所有服务器的server_list收集为普通列表,格式为[ {服务器1信息}, {服务器2信息}, ... ]server_list_temp | indices:获取列表的索引(0、1、2...),转换为字符串后与列表元素配对生成字典
验证结果
添加以下debug任务可查看最终生成的全局字典:
- name: 验证全局server_list_dict delegate_to: localhost debug: var: server_list_dict run_once: true
执行后即可得到符合要求的全局字典,之后可直接在模板中使用server_list_dict变量生成HTML表格。
内容的提问来源于stack exchange,提问作者marcb4
相关产品推荐
相关产品推荐

