如何基于字典变量在Ansible的Jinja2模板中包含对应文件?
问题
我正在尝试使用Ansible和Jinja2生成模板化配置文件,现有如下配置:
变量定义
internal_sites: - {name: "site1" ,url: "site1.example.com" } - {name: "site2" ,url: "site2.example.com" } - {name: "site3" ,url: "site3.example.com" } - {name: "site4" ,url: "site4.example.com" }
模板目录结构
├── templates │ ├── base.cfg.j2 │ └── services │ ├── internal │ │ ├── site1.txt │ │ ├── site2.txt │ │ ├── site3.txt │ │ ├── site4.txt
需求是在base.cfg.j2中遍历internal_sites的每个条目,生成配置的同时引入对应名称的文本文件内容。尝试了两种写法均报错:
第一种写法
{% for site in internal_sites %} acl {{ site.name }} hdr(host) -i {{ site.url }} use_backend {{ site.name }} if {{ site.name }} backend {{ site.name}} {% include "templates/services/internal/"{{lookup('vars', site.name)}} %} {% endfor %}
报错信息:
FAILED! => {"changed": false, "msg": "AnsibleError: template error while templating string: expected token 'end of statement block', got '{'. String: {% for site in internal_sites %} acl {{ site.name }} hdr(host) -i {{ site.url }} use_backend {{ site.name }} if {{ site.name }} backend {{ site.name}} {% include \"templates/services/internal/\"{{lookup('vars', site.name)}} %} {% endfor %} "}
第二种写法
{% for site in internal_sites %} {% set fileloc = 'templates/services/internal/' + site.name %} acl {{ site.name }} hdr(host) -i {{ site.url }} use_backend {{ site.name }} if {{ site.name }} backend {{ site.name}} {% include {{fileloc}} %} {% endfor %}
预期输出示例:
acl site1 hdr(host) -i site1.example.com use_backend site1 if site1 backend site1 contents of site1.txt are included here
正确实现方式
错误原因分析
- Jinja2的
{% include %}语句中,路径参数不需要用{{}}包裹,嵌套{{}}会触发语法解析错误。 - Ansible模板路径默认相对于
templates目录,无需在路径中添加templates前缀。 - 目标文件是带
.txt后缀的文件,之前的写法遗漏了后缀,会导致文件查找失败。
修正后的模板代码
{% for site in internal_sites %} acl {{ site.name }} hdr(host) -i {{ site.url }} use_backend {{ site.name }} if {{ site.name }} backend {{ site.name }} {% include "services/internal/" ~ site.name ~ ".txt" %} {% endfor %}
关键说明
- 使用Jinja2字符串拼接符
~组合路径:"services/internal/" ~ site.name ~ ".txt",可正确生成每个站点对应的文件路径。 include语句直接使用拼接后的路径字符串,符合Jinja2语法规范。- 路径从
templates目录开始,因此直接写services/internal/...即可,Ansible会自动在templates目录下定位文件。
运行上述模板后,即可生成符合预期的配置文件,自动引入对应站点的txt文件内容。
内容的提问来源于stack exchange,提问作者CosmicLentil
相关产品推荐
相关产品推荐

