如何借助ansible_play_hosts为各主机生成匹配与非匹配项列表?
Ansible 跨主机生成匹配/非匹配项列表解决方案
场景说明
各主机的found_items列表如下:
- host-1:
- /tmp/a - /tmp/b - /tmp/c - /tmp/d - /tmp/e
- host-2:
- /tmp/b - /tmp/c
- host-3:
- /tmp/c - /tmp/d
技术需求
必须使用魔术变量ansible_play_hosts,为play中的每个主机动态生成两个列表:
- 匹配项列表:当前主机
found_items中,在至少一个其他主机的found_items里存在的项(例如host-1的匹配项为/tmp/b、/tmp/c、/tmp/d) - 非匹配项列表:当前主机
found_items中,仅在自身存在的项(例如host-1的非匹配项为/tmp/a、/tmp/e)
已尝试代码
- name: set fact for shared files set_fact: shared_files: "{{ hostvars[item].found_items }}" loop: "{{ ansible_play_hosts }}" when: - hostvars[item.ansible_host].found_items is defined - hostvars[item.ansible_host].found_items == found_items
注:变量found_items存储各主机对应的列表。
问题分析
原有代码存在两个核心问题:
- 条件判断逻辑错误:
hostvars[item.ansible_host].found_items == found_items是在寻找和当前主机found_items完全一致的主机,不符合“项在其他主机存在”的需求; - 主机变量访问错误:
item是ansible_play_hosts返回的主机名,直接用hostvars[item]访问即可,无需item.ansible_host。
解决方案
以下代码通过ansible_play_hosts实现需求:
- name: 收集所有主机的found_items列表 set_fact: all_hosts_found: "{{ ansible_play_hosts | map('extract', hostvars, 'found_items') | list }}" run_once: true - name: 生成匹配项与非匹配项列表 set_fact: # 匹配项:当前主机项在其他主机中出现过 matched_items: >- {{ found_items | select('in', all_hosts_found | flatten | difference(found_items)) | list }} # 非匹配项:当前主机项仅在自身存在 unmatched_items: >- {{ found_items | reject('in', all_hosts_found | flatten | difference(found_items)) | list }}
逻辑说明
all_hosts_found:通过ansible_play_hosts遍历所有主机,提取每个主机的found_items,组成包含所有主机列表的二维数组;all_hosts_found | flatten | difference(found_items):将二维数组转为一维,再剔除当前主机的所有项,得到其他所有主机的所有项的合集;matched_items:筛选当前主机found_items中存在于上述合集的项,即跨主机存在的匹配项;unmatched_items:筛选当前主机found_items中不存在于上述合集的项,即仅自身存在的非匹配项。
内容的提问来源于stack exchange,提问作者Kevin C
相关产品推荐
相关产品推荐

