【问题标题】:Include files in Jinja, applying template then filtering在 Jinja 中包含文件,应用模板然后过滤
【发布时间】:2020-06-12 02:11:30
【问题描述】:

总结

我有一个使用 Ansible 运行的 Jinja2 模板。

我希望我的模板加载另一个文件作为模板(即评估{{ var }}),然后我将对其进行过滤,然后然后将结果粘贴到顶级模板中。

我想我快到了,我只需要找到一个 Jinja2 过滤器,它接收一个字符串并将其解析为模板。

MWE

在此示例中,假设我要应用的过滤器只是将文件设为大写。 (显然这个案例非常简单,我可以在一个模板文件中完成。但我的实际用例更复杂。)

顶级模板main.yaml.j2:

---
something:
   blah:
      x: {{ y }}
      {%- set names = [ 'John', 'Amy' ] %}
      z: >
        {{ lookup('file', './other-file.j2') | upper | indent(4*2) }}

other-file.j2:

{%- for name in names %}
Hello {{ name }}
{%- endfor %}

使用这个 Ansible playbook 运行它:

---
- hosts: localhost
  connection: local
  tasks:
  - name: generate template
    template:
      src: "main.yaml.j2"
      dest: "output.yaml.j2"
      trim_blocks: False
    register: templating
    vars:
      y: 5

期望的输出

---
something:
   blah:
      x: 5
      z: >
        HELLO JOHN
        HELLO AMY

实际输出

---
something:
   blah:
      x: 5
      z: >
        {%- FOR NAME IN NAMES %}
        HELLO {{ NAME }}
        {%- ENDFOR %}

最佳猜测

我想我快到了。 我只需要一个将 Jinja2 模板应用于文本的过滤器。

即类似:

{{ lookup('file', './other-file.j2') | template | upper | indent(4*2) }}

(但template 不是真正的过滤器。也许还有另一个名字?)

我还尝试了什么

{{ include './other-file.j2' | upper | indent(4*2) }}

没用。

致命:[127.0.0.1]:失败! => {"changed": false, "msg": "AnsibleError: 模板化字符串时出现模板错误:预期令牌'打印语句结束',得到'字符串'。字符串:---\nsomething:\n blah:\n x: {{ y }}\n {%- set names = [ 'John', 'Amy' ] %}\n z: >\n {{ include './other-file.j2' | upper | indent(4*2) }}"}

{% include './other-file.j2' | upper | indent(4*2) %}

“未找到模板:./OTHER-FILE.J2”

没用。

用例

对于上下文,我的用例是我有一个 Jinja2 模板生成 AWS CloudFormation 模板。 我试图在 YAML 中完成这一切,而不是 JSON。 (因为 YAML 可以有 cmets,而且你不必担心列表中的最后一项是否有尾随逗号,并且通常更容易读写和调试。) 一些 CloudFormation 资源需要将文字 JSON 粘贴到 YAML 文件中。 (例如CloudWatch Dashboard bodies)。 所以我想在 YAML 中有另一个文件,Jinja2 将其转换为 json,然后粘贴到我的整个 YAML 模板中。 我希望使用 for 循环生成此仪表板,并传入变量。 我想要一个单独的

【问题讨论】:

    标签: templates ansible jinja2


    【解决方案1】:

    代替file插件

    lookup('file', './other-file.j2')
    

    使用 template plugin

    lookup('template', './other-file.j2')
    

    注意变量{% set names = ['John', 'Amy'] %}的作用域是模板main.yaml.j2。如果在模板other-file.j2 中使用此变量,命令lookup('template', './other-file.j2') 将崩溃并出现错误:

    "AnsibleUndefinedVariable: 'names' 未定义"

    解决方案

    在剧本范围内声明变量。例如

      - template:
          src: "main.j2"
          dest: "output.txt"
        vars:
          names: ['John', 'Amy']
    

    main.j2

    {{ lookup('template', './other-file.j2') }}
    

    其他文件.j2

    {% for name in names %}
    Hello {{ name }}
    {% endfor %}
    

    shell> cat output.txt 
    Hello John
    Hello Amy
    

    【讨论】:

    • 哇,回想起来很明显,哈。
    • 此解决方案不起作用。当我使用lookup('template', './other-file.j2') 时,变量不会传播到other-file.j2。错误“AnsibleUndefinedVariable:'names' 未定义”。执行lookup('template', './other-file.j2', names=names) 会出现同样的错误。
    • 啊,好像顶级 Jinja 文件中定义的变量没有通过,但 Ansible 中定义的变量可以。有没有办法解决这个问题? (在我的实际用例中,我想在 Jinja for 循环中执行此操作 lookup。)
    猜你喜欢
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 2021-09-22
    • 2015-05-22
    • 2020-07-29
    相关资源
    最近更新 更多