Ansible跨hosts块复用set_fact变量时提示变量未定义
问题场景
你正在使用ansible-playbook管理两个VM主机池:vms1(仅含一台主机)和vms2。你希望在vms1的任务中动态获取该主机的hostname,然后在vms2的任务里复用这个变量,但执行时遇到了错误:
FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'myHostname' is undefined"}
你的Playbook大致如下:
- hosts: vms1 tasks: - name: Getting hostname shell: hostname register: shellOutput - set_fact: myHostname: "{{ shellOutput.stdout }}" - hosts: vms2 tasks: - name: Pinging shell: "ping {{ myHostname }} -n 2 >> /tmp/otherHosts.txt"
你也提到这个问题不同于常见的跨主机访问预定义YAML数据场景,而是执行过程中自行设置变量后想复用的情况。
问题原因
默认情况下,set_fact定义的变量是绑定在当前执行任务的主机实例上的。也就是说,你在vms1的主机上执行set_fact后,myHostname只属于那台vms1主机的本地facts集合,vms2的主机无法直接访问这个变量,所以会触发"变量未定义"的错误。
解决方案
因为你明确vms1只有一台主机,这里提供两种简单可靠的解决方法:
方法1:通过hostvars跨主机引用变量
既然myHostname存储在vms1的主机上,你可以在vms2的任务中通过hostvars对象结合主机组信息来引用它。利用groups['vms1'][0]可以直接取出vms1组里的唯一主机:
- hosts: vms1 tasks: - name: Getting hostname shell: hostname register: shellOutput - set_fact: myHostname: "{{ shellOutput.stdout }}" - hosts: vms2 tasks: - name: Pinging shell: "ping {{ hostvars[groups['vms1'][0]]['myHostname'] }} -n 2 >> /tmp/otherHosts.txt"
方法2:将变量存储到控制节点(localhost)
如果你希望变量脱离vms1主机的依赖,可以把变量直接存储在控制节点(localhost)上,这样所有后续主机组都能轻松引用。只需给set_fact添加delegate_to: localhost和run_once: yes参数(确保只执行一次):
- hosts: vms1 tasks: - name: Getting hostname shell: hostname register: shellOutput - set_fact: myHostname: "{{ shellOutput.stdout }}" delegate_to: localhost run_once: yes - hosts: vms2 tasks: - name: Pinging shell: "ping {{ hostvars['localhost']['myHostname'] }} -n 2 >> /tmp/otherHosts.txt"
额外提示
如果未来vms1主机池扩展为多台主机,记得调整逻辑:比如保留run_once: yes只取第一台主机的hostname,或者根据实际需求处理多台主机的hostname收集和使用场景。
内容的提问来源于stack exchange,提问作者Ashwin

