You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用动态Ansible Playbook时,如何在主机间共享facts并对比变量?

问题

需要对比两台动态添加主机(无主机文件,无法通过主机名引用,只能用ansible_play_hosts)上的变量,但共享主机间变量时遇到问题。简化后的Playbook代码如下:

- set_fact:
    samplevar0: var_from_first_server_in_play
  when: inventory_hostname == ansible_play_hosts[0]
  
- set_fact:
    samplevar1: var_from_second_server_in_play
  when: inventory_hostname == ansible_play_hosts[1]
  
- ansible.builtin.debug: msg="echoing vars from both servers in play  {{ hostvars.ansible_play_hosts[0].samplevar0 }} {{ hostvars.ansible_play_hosts[1].samplevar1 }}"

- ansible.builtin.debug: msg="vars 0 and 1 are equal. "
  when: "{{ hostvars.ansible_play_hosts[0].samplevar0 }} == {{ hostvars.ansible_play_hosts[1].samplevar1 }}"

执行后报错,输出如下:

TASK [fact_check_role: set_fact] *************************************
ok: [host2255]

TASK [fact_check_role: set_fact] *************************************
ok: [host2892]

TASK [fact_check_role : ansible.builtin.debug] ************************
fatal: [llrp107d]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: "hostvars['ansible_play_hosts']" is undefined. "hostvars['ansible_play_hosts']" is undefined

The error appears to be in '/runner/project/roles/fact_check_role/tasks/preflight_host1.yml': line 195, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

  • ansible.builtin.debug: msg="echoing vars from both servers in play {{ hostvars.ansible_play_hosts[0].samplevar0 }} {{ hostvars.ansible_play_hosts[1].samplevar1 }}"
    ^ here
    We could be wrong, but this one looks like it might be an issue with
    missing quotes. Always quote template expression brackets when they
    start a value. For instance:

    with_items:
    - {{ foo }}

Should be written as:

with_items:
  - "{{ foo }}"

"}

疑问:是否是嵌套变量的Jinja格式使用错误导致的问题?

原因与解决方法

确实是Jinja2嵌套变量的语法错误导致的问题,核心问题有两个:

  1. hostvars访问方式错误:hostvars是字典类型,当使用动态变量(比如ansible_play_hosts[0]这种运行时确定的主机名)作为键时,不能用点号.访问,必须用方括号[]形式。否则Ansible会把ansible_play_hosts当成主机名去hostvars里查找,而非解析这个变量的实际值。

  2. when条件语法错误:Ansible的when参数本身处于Jinja2上下文,无需再用{{}}包裹表达式,直接写条件逻辑即可。

修正后的Playbook代码如下:

- set_fact:
    samplevar0: var_from_first_server_in_play
  when: inventory_hostname == ansible_play_hosts[0]
  
- set_fact:
    samplevar1: var_from_second_server_in_play
  when: inventory_hostname == ansible_play_hosts[1]
  
- ansible.builtin.debug: 
    msg: "echoing vars from both servers in play  {{ hostvars[ansible_play_hosts[0]].samplevar0 }} {{ hostvars[ansible_play_hosts[1]].samplevar1 }}"

- ansible.builtin.debug: 
    msg: "vars 0 and 1 are equal. "
  when: hostvars[ansible_play_hosts[0]].samplevar0 == hostvars[ansible_play_hosts[1]].samplevar1

关键修改点说明:

  • 将hostvars.ansible_play_hosts[0]改为hostvars[ansible_play_hosts[0]]:先解析ansible_play_hosts[0]得到第一个主机名,再用该主机名作为键去hostvars字典中获取对应主机的变量。
  • 移除when条件中的{{}}:直接编写变量对比逻辑,Ansible会自动在Jinja2上下文中解析。

内容的提问来源于stack exchange,提问作者CaptainSkyfish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 18:56:19