Включите файлы в Jinja, применяя шаблон, затем фильтруя - PullRequest
1 голос
/ 28 февраля 2020

Сводка

У меня есть шаблон Jinja2, с которым я работаю Ansible.

Я бы хотел, чтобы мой шаблон загружал другой файл как шаблон (то есть оценивая {{ 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 %}

Best Guess

Я думаю, что я почти у цели. Мне просто нужен фильтр, который применяет шаблон Jinja2 к тексту.

то есть что-то вроде:

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

(Но template не является реальным фильтром. Может быть, есть другое имя?)

Что еще я пробовал

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

не работает.

смертельно: [127.0.0.1]: FAILED! => {"updated": 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) %}

"TemplateNotFound: ./OTHER-FILE.J2"

не работает.

Вариант использования

Для контекста, мое использование дело в том, что у меня есть шаблон Jinja2, генерирующий AWS шаблоны CloudFormation. Я пытаюсь сделать все это в YAML, а не JSON. (потому что YAML может иметь комментарии, и вам не нужно беспокоиться о том, последний Элемент в списке имеет запятую, и обычно его легче читать, писать и отлаживать.) Некоторые ресурсы CloudFormation должны вставляться в файл YAML буквально JSON (например, Тела CloudWatch Dashboard ). Поэтому я Я хочу иметь другой файл в YAML, который Jinja2 преобразует в json и вставляет в мой общий шаблон YAML. Я хочу, чтобы эта панель инструментов была сгенерирована с помощью для l oop и передавала переменные. Я хотел бы иметь отдельный

1 Ответ

1 голос
/ 28 февраля 2020

Вместо file плагин

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

используйте template плагин

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

Обратите внимание, что областью действия переменной {% set names = ['John', 'Amy'] %} является шаблон main.yaml.j2. Если эта переменная используется в шаблоне other-file.j2, команда lookup('template', './other-file.j2') выполнит sh с ошибкой:

"AnsibleUndefinedVariable: 'names' не определено"

Solution

Объявите переменную в области Playbook. Например,

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

main.j2

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

other-file.j2

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

предоставить

shell> cat output.txt 
Hello John
Hello Amy
...