Ansible技术问题:如何从模板/YAML文件中使用set_fact?
解决Ansible中set_fact加载模板后变量未定义的问题
问题场景
使用Jinja2模板生成包含YAML块的文件,通过set_fact结合template lookup加载模板内容后,无法访问生成的my_list_from_template变量,提示该变量未定义。
模板文件tmp/test.yml内容:
my_list_from_template: {% filter from_yaml %} {% for my_os_stage in all_os_stage -%} - name: "Template for {{ my_os_stage }}" {% endfor %} {% endfilter %}
Playbook内容:
--- - name: "read tmp/test.yml" hosts: localhost connection: local remote_user: opsadm gather_facts: False become: yes vars: all_os_stage: - TST - DEV - INT - PRD tasks: - name: "read tmp/test.yml as template" ansible.builtin.set_fact: "{{ lookup('ansible.builtin.template', 'tmp/test.yml') }}" - debug: msg: "{{ my_list_from_template }}"
报错原因
从执行日志可见,set_fact将模板渲染后的完整字符串赋值给了_raw_params,并未解析YAML中的键值对结构。直接使用{{ lookup(...) }}作为set_fact的参数时,Ansible不会自动解析字符串内的YAML格式,导致my_list_from_template未被注册为有效事实变量。
解决方案
方案1:直接解析YAML并赋值给set_fact
修改set_fact任务,用from_yaml过滤器解析模板渲染后的字符串,将其作为字典传递给set_fact:
- name: 加载模板并解析为事实变量 ansible.builtin.set_fact: "{{ lookup('ansible.builtin.template', 'tmp/test.yml') | from_yaml }}"
同时简化模板文件(去掉冗余的from_yaml过滤器),tmp/test.yml改为:
my_list_from_template: {% for my_os_stage in all_os_stage -%} - name: "Template for {{ my_os_stage }}" {% endfor %}
方案2:先渲染模板到文件,再用include_vars加载
若偏好通过文件管理变量,可先将模板渲染为实际文件,再通过include_vars加载:
- name: 渲染模板到临时文件 ansible.builtin.template: src: tmp/test.yml dest: /tmp/rendered_vars.yml mode: '0644' - name: 加载渲染后的变量文件 ansible.builtin.include_vars: file: /tmp/rendered_vars.yml
验证结果
执行修改后的Playbook,debug任务将正常输出:
ok: [localhost] => { "msg": [ { "name": "Template for TST" }, { "name": "Template for DEV" }, { "name": "Template for INT" }, { "name": "Template for PRD" } ] }
内容的提问来源于stack exchange,提问作者Isabella
相关产品推荐
相关产品推荐

