如何从Ansible组中所有主机提取多个hostvars变量?
问题描述
需从主机中提取INSTANCE_CLASS变量,主机变量以无扩展名文件存储在hostvars目录中,文件名对应主机名,例如host12的变量内容如下:
--- ansible_host: 10.11.12.15 INSTANCE_CLASS: vm_host ...
此前已实现多主机提取hostvar的方法,但现在需要生成字典列表而非字符串列表,两次尝试均未达到预期:
尝试1:循环赋值导致变量覆盖
使用循环逐个生成字典,但每次set_fact都会覆盖ne_hosts,最终仅保留最后一个元素:
- hosts: general gather_facts: false vars: ip_list: "{{ ansible_play_hosts_all | map('extract', hostvars, 'ansible_hostname') }}" tasks: - name: Get all IPs set_fact: ne_hosts: - ip: "{{ hostvars[item]['ansible_host'] }}" instance_class: "{{ hostvars[item]['INSTANCE_CLASS'] }}" loop: "{{ ip_list }}" delegate_to: localhost delegate_facts: true run_once: true - hosts: localhost gather_facts: false tasks: - name: Display gathered IPs debug: var: ne_hosts
执行结果:
TASK [Display gathered IPs] *************************************************************************************************************************************** ok: [localhost] => { "ne_hosts": [ { "instance_class": "mdd_controller", "ip": "10.11.12.19" } ] }
尝试2:IP列表完整但INSTANCE_CLASS仅取最后一个
直接赋值列表和单个变量,导致INSTANCE_CLASS只拿到当前主机的最后一个值:
- hosts: general gather_facts: false vars: ip_list: "{{ ansible_play_hosts_all | map('extract', hostvars, 'ansible_host') }}" tasks: - name: Get all IPs set_fact: ne_hosts: "ip: {{ ip_list }}, instance_class: {{ INSTANCE_CLASS }}" delegate_to: localhost delegate_facts: true run_once: true - hosts: localhost gather_facts: false tasks: - name: Display gathered IPs debug: var: ne_hosts
执行结果:
TASK [Display gathered IPs] *************************************************************************************************************************************** ok: [localhost] => { "ne_hosts": "ip: ['10.11.12.15', '10.11.12.19'], instance_class: mdd_controller" }
预期结果
期望生成包含每个主机对应IP和INSTANCE_CLASS的字典列表:
"ne_hosts": [ {ip: '10.11.12.15', instance_class: vm_host}, {ip: '10.11.12.19', instance_class: mdd_controller} ]
解决方案
可以利用Ansible过滤器直接生成目标列表,无需循环赋值,提供两种简洁实现方式:
方式1:使用map+zip+dict过滤器
- hosts: general gather_facts: false tasks: - name: Generate hosts dictionary list set_fact: ne_hosts: "{{ ansible_play_hosts_all | map('extract', hostvars, ['ansible_host', 'INSTANCE_CLASS']) | map('zip', ['ip', 'instance_class']) | map('dict') | list }}" delegate_to: localhost delegate_facts: true run_once: true - hosts: localhost gather_facts: false tasks: - name: Display result debug: var: ne_hosts
方式2:使用json_query(语法更直观)
- hosts: general gather_facts: false tasks: - name: Generate hosts dictionary list with json_query set_fact: ne_hosts: "{{ ansible_play_hosts_all | map('extract', hostvars) | json_query('[].{ip: ansible_host, instance_class: INSTANCE_CLASS}') }}" delegate_to: localhost delegate_facts: true run_once: true - hosts: localhost gather_facts: false tasks: - name: Display result debug: var: ne_hosts
方案说明
- 方式1逻辑:先从每个主机hostvars中提取指定变量得到元组列表,再将元组与目标键名配对,最后转换为字典并组成列表。
- 方式2利用JMESPath表达式,直接通过
json_query筛选并构造所需的字典结构,可读性更强。
内容的提问来源于Stack Exchange,提问作者AbreQueVoy
相关产品推荐
相关产品推荐

