Ansible中hostvars['variable_holder']未定义及跨主机组传参问题咨询
TASK [microstrategy.mstrpax_configure : Get Project Names from Rest API] *** skipping: [] => changed=false false_condition: mstr_role in ("webserver") skip_reason: Conditional result was False TASK [microstrategy.mstrpax_configure : Configure Telemetry Logging] *** fatal: []: FAILED! => msg: '"hostvars[''variable_holder'']" is undefined. "hostvars[''variable_holder'']" is undefined'
Ansible跨主机组变量传递问题排查与解决
1. 为什么Ansible提示hostvars['variable_holder']未定义?
核心原因是创建variable_holder虚拟主机的任务从未执行:
- 你通过
when: mstr_role in ("webserver")限制了Get Project Names from Rest API任务仅在webserver角色的主机上运行; - 当执行iserver角色主机的
Configure Telemetry Logging任务时,前置的变量创建任务已被跳过(日志中的skip_reason也能验证这一点),导致variable_holder这个虚拟主机从未被add_host指令创建,自然在hostvars中找不到对应条目。
2. 该如何修复这个问题?
方案1:调整任务执行顺序,确保变量先被创建
把获取项目名并创建共享变量的逻辑放到独立的play中,指定在webserver组执行,之后再执行iserver组的任务。示例结构:
- name: 从webserver获取项目名并创建共享变量 hosts: webserver tasks: - name: 'Get Project Names from Rest API' ansible.builtin.include_tasks: mstrpax_projects_loaded.yml - name: 在iserver上配置遥测日志 hosts: iserver tasks: - name: 'Enable Telemetry Logging' block: - name: 'Configure Telemetry Logging' ansible.builtin.include_tasks: mstrpax_telemetry_logging.yml loop: "{{ hostvars['variable_holder']['mstr_api_projnames_output'].json | map(attribute='name') | list }}" loop_control: loop_var: mstr_projects
这种方式能确保variable_holder在iserver任务执行前就已被创建。
方案2:给变量访问加默认值,避免直接报错
如果无法调整play顺序,可以通过get方法给变量加默认值,同时跳过变量不存在时的任务:
- name: 'Enable Telemetry Logging' block: - name: 'Configure Telemetry Logging' ansible.builtin.include_tasks: mstrpax_telemetry_logging.yml loop: "{{ hostvars.get('variable_holder', {}).get('mstr_api_projnames_output', {}).json | default([]) | map(attribute='name') | list }}" loop_control: loop_var: mstr_projects when: - mstr_role in ("iserver") - hostvars.get('variable_holder', {}).get('mstr_api_projnames_output', {}).json is defined
注意:这种方式只是临时规避报错,核心还是要保证变量能被正确创建。
3. 如何将变量从webserver主机组传递到iserver主机组?
常用的几种实现方式:
- 使用
add_host创建虚拟主机(你当前的方案):在webserver组的play中执行add_host,把变量绑定到虚拟主机上,后续所有play都能通过hostvars['虚拟主机名']访问,前提是这个创建任务必须被执行。 - 使用
set_fact+cacheable共享变量:在webserver主机上获取变量后,用set_fact设置变量并开启缓存,让其他主机组能读取:
后续iserver主机可以直接使用- name: 保存项目名到全局可访问的fact ansible.builtin.set_fact: mstr_api_projnames_output: '{{ mstr_api_projnames_loaded }}' run_once: true delegate_to: "{{ groups['webserver'][0] }}" cacheable: true{{ mstr_api_projnames_output }}。 - 直接从webserver主机的hostvars读取:如果知道webserver组中某台主机的名字,直接从该主机的hostvars中获取变量:
注意要保证该webserver主机已经执行过获取变量的任务。loop: "{{ hostvars['webserver_hostname']['mstr_api_projnames_output'].json | map(attribute='name') | list }}"
内容的提问来源于stack exchange,提问作者wicemantel
相关产品推荐
相关产品推荐

