Ansible跨主机用hostvars调用注册变量报错:HostVarsVars object has no element
问题描述
我有一个在两台主机上运行的Ansible Playbook,原本计划先在host1上执行任务并把结果注册到变量,之后在host2上通过hostvars调用该变量做loop循环,但执行失败,报错信息为ansible.vars.hostvars.HostVarsVars object has no element。
执行时通过参数-l "host1,host2"指定目标主机,用when条件控制任务在对应主机执行(可能有更优实现方式)。
host1上的任务代码
- command: /some/command when: "'host1' in inventory_hostname" register: results - debug: var=results.stdout_lines
host2上的任务代码
- command: /some/command loop: "{{ hostvars['host1.example.com'][registered_var][stdout_lines] }}" when: "'host2' in inventory_hostname" register: output - debug: var=output.results
报错信息
skipping: [host1.example.com]
fatal: [host2.example.com]: FAILED! => {}MSG:
ansible.vars.hostvars.HostVarsVars object has no element {'skip_reason': u'Conditional result was False', 'skipped': True, 'changed': False}
错误原因
- 变量引用语法错误:host2的loop表达式写法有误,正确的变量引用应该是
hostvars['host1.example.com'].results.stdout_lines(因为host1上注册的变量名是results,不是registered_var)。 - 任务执行顺序冲突:Ansible默认按主机批量执行任务——先在所有目标主机上跑完第一个任务,再执行第二个任务。这会导致host2执行loop任务时,host1的
results变量可能还没被注册。 - 跳过任务的变量无效:如果host1的任务因条件不满足被跳过,
results会变成一个标记为skipped的对象,此时直接访问stdout_lines就会触发报错。
解决方案
1. 修正变量引用语法
把host2任务里的loop表达式改成正确的格式:
loop: "{{ hostvars['host1.example.com'].results.stdout_lines }}"
2. 拆分Play确保执行顺序
最稳妥的方式是把host1和host2的任务拆成两个独立的Play,先执行host1的任务,再执行host2的任务,这样完全避免顺序问题:
# 第一个Play:仅在host1上执行任务 - name: Run tasks on host1 hosts: host1 tasks: - command: /some/command register: results - debug: var=results.stdout_lines # 第二个Play:在host2上调用host1的变量执行任务 - name: Run tasks on host2 with host1's data hosts: host2 tasks: - command: /some/command loop: "{{ hostvars['host1.example.com'].results.stdout_lines }}" register: output - debug: var=output.results
这种方式不需要when条件,直接通过hosts指定目标主机,执行逻辑清晰。
3. 增加变量有效性检查(单Play场景)
如果坚持用同一个Play,要在host2的任务里先检查变量是否有效:
- command: /some/command loop: "{{ hostvars['host1.example.com'].results.stdout_lines | default([]) }}" when: - "'host2' in inventory_hostname" - hostvars['host1.example.com'].results is defined - hostvars['host1.example.com'].results.skipped is not defined or not hostvars['host1.example.com'].results.skipped register: output
这样即使host1的任务被跳过,host2的任务也不会直接报错,要么用空列表循环,要么直接跳过执行。
内容的提问来源于stack exchange,提问作者blackcountrylad
相关产品推荐
相关产品推荐

