Ansible跨play引用storage_moved变量提示未定义问题求助
问题根本原因
Ansible 的变量存在严格的作用域规则:通过register注册的任务结果变量,是与执行该任务的目标主机一一绑定的,仅存储在对应主机的hostvars命名空间下,不会自动成为全局变量。
你第二个play的执行目标是storage组的存储服务器,storage_moved变量仅存在于各存储节点的hostvars中;而第三个play的执行目标是localhost,localhost 本身没有执行过注册storage_moved的任务,因此直接在第三个play的上下文中调用{{ storage_moved }}必然会触发未定义报错。你之前通过遍历storage组主机读取对应hostvars的写法完全符合Ansible的设计逻辑,是正确的实现。
优化方案
方案1:优化现有模板的可读性(最推荐,无需修改play结构)
你现有的循环写法已经是标准实现,只需补充判空逻辑和格式化输出,即可直接生成适合邮件阅读的内容,避免部分节点未执行任务时的报错:
{% for host in groups['storage'] %} {% if hostvars[host]['storage_moved'] is defined %} --- ### 存储节点:{{ host }} - 执行状态:{{ '成功' if not hostvars[host].storage_moved.failed else '失败' }} - 目录移动状态:{{ '已移动' if hostvars[host].storage_moved.changed else '无需移动(目录不存在)' }} - 执行命令:{{ hostvars[host].storage_moved.cmd | join(' ') }} - 执行耗时:{{ hostvars[host].storage_moved.delta }} {% endif %} {% endfor %}
方案2:提前聚合结果为全局变量(适合多场景复用结果)
如果需要在多个地方用到存储节点的执行结果,可以在第二个play末尾新增聚合任务,把所有结果提前合并为localhost的本地变量,后续调用无需再遍历hostvars:
- name: "Playbook: Terminate storage" hosts: storage gather_facts: False roles: - { role: storage_termination, tags: ['storage_termination', 'always'] } # 新增后置任务聚合结果 post_tasks: - name: 聚合存储节点操作结果 run_once: yes delegate_to: localhost set_fact: all_storage_exec_results: >- {{ all_storage_exec_results | default([]) + [ { 'host': item, 'result': hostvars[item].storage_moved } ] }} loop: "{{ groups['storage'] }}" when: hostvars[item].storage_moved is defined
后续第三个play的模板中直接遍历{{ all_storage_exec_results }}即可读取所有结果。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

