如何用Ansible按module字段拆分字典列表生成对应目标文件?
问题描述
现有字典列表变量sites:
sites: - { site: "https://site1.com", project: "own", module: "2xx" } - { site: "https://site2.com", project: "external", module: "2xx" } - { site: "https://site3.net", project: "own", module: "ssl" } - { site: "https://site4.org", project: "external", module: "ssl2" } - { site: "https://site5.co", project: "external", module: "2xx"}
使用模板文件test.yml.j2:
{% for dict_item in sites %} - targets: - {{ dict_item.site }} labels: instance: {{ dict_item.site }} job: "blackbox_exporter | sites_check" project: {{ dict_item.project }} module: {{ dict_item.module }} {% endfor %}
以及Ansible任务:
- name: "Test multi" template: src: "test.yml.j2" dest: "/opt/test/{{ item.module }}.yml" with_items: "{{ sites }}"
当前问题:每个生成的{{ module }}.yml文件都包含所有目标的完整列表,内容完全相同。期望每个文件仅包含对应module字段的目标项(比如2xx.yml只保留module为2xx的条目),且不想为每个模块单独写任务,遵循DRY原则。
解决方案
1. 按module分组站点列表
先添加一个set_fact任务,把sites按module字段分组,生成一个键为模块名、值为对应站点列表的字典:
- name: 按module字段分组站点 set_fact: sites_by_module: "{{ sites | groupby('module') | items2dict(key_name='0', value_name='1') }}"
这里用到的Ansible过滤器说明:
groupby('module'):将sites列表按module字段分组,输出格式为[('模块名', [对应站点列表]), ...]items2dict:将分组后的列表转换为字典,指定第0位为键、第1位为值。
2. 修改模板与任务
调整模板文件test.yml.j2
将循环对象改为传入的当前模块专属站点列表,不再遍历整个sites:
{% for dict_item in module_sites %} - targets: - {{ dict_item.site }} labels: instance: {{ dict_item.site }} job: "blackbox_exporter | sites_check" project: {{ dict_item.project }} module: {{ dict_item.module }} {% endfor %}
更新Ansible任务
遍历分组后的字典,为每个模块生成对应配置文件,同时传递该模块的站点列表给模板:
- name: 生成各模块的配置文件 template: src: "test.yml.j2" dest: "/opt/test/{{ item.key }}.yml" vars: module_sites: "{{ item.value }}" loop: "{{ sites_by_module | dict2items }}"
这样每个模块的配置文件只会包含对应module的目标项,且无需为每个模块单独编写任务,符合DRY原则。
内容的提问来源于stack exchange,提问作者Nikolai
相关产品推荐
相关产品推荐

