Введение
В этом лабораторном занятии (lab) вы познакомитесь с Jinja2, мощным шаблонизатором, используемым в Ansible. Jinja2 позволяет создавать динамическое содержимое, делая ваши Ansible-плейбуки более гибкими и адаптивными. К концу этого лабораторного занятия вы научитесь использовать синтаксис Jinja2 в Ansible, включая переменные, фильтры, условные операторы и циклы. Эти знания позволят вам создавать более динамичные и эффективные Ansible-плейбуки и роли.
Понимание основ Jinja2
Jinja2 — это современный и удобный для дизайнеров шаблонизатор для Python, вдохновлённый шаблонами Django. В Ansible Jinja2 используется для создания шаблонов файлов, динамических структур плейбуков и многое другое.
Начнём с создания простого шаблона Jinja2. Сначала перейдите в каталог проекта:
cd ~/project
Теперь создадим каталог для наших шаблонов:
mkdir templates
cd templates
Создайте новый файл с именем hello.j2:
nano hello.j2
Добавьте следующее содержимое:
Hello, {{ name }}!
Today is {{ ansible_date_time.date }}.
Your home directory is {{ ansible_env.HOME }}.
Сохраните изменения и выйдите из редактора nano (Ctrl+X, затем Y, затем Enter).
В этом шаблоне:
{{ name }}— это переменная, которая будет заменена на фактическое значение при рендеринге шаблона.{{ ansible_date_time.date }}и{{ ansible_env.HOME }}— это факты Ansible, которые будут автоматически заполнены.
Теперь создадим плейбук для использования этого шаблона. Вернитесь в корень проекта и создайте новый файл с именем use_template.yml:
cd ~/project
nano use_template.yml
Добавьте следующее содержимое:
---
- name: Use Jinja2 template
hosts: localhost
vars:
name: "Ansible Learner"
tasks:
- name: Create file from template
template:
src: templates/hello.j2
dest: /tmp/hello.txt
Этот плейбук использует модуль template для рендеринга нашего шаблона Jinja2 и создания файла по пути /tmp/hello.txt.
Запустите плейбук:
ansible-playbook use_template.yml
После запуска плейбука проверьте содержимое созданного файла:
cat /tmp/hello.txt
Вы должны увидеть отрендеренный шаблон с заменёнными переменными и фактами на фактические значения.
Использование фильтров Jinja2
Фильтры Jinja2 — это функции, которые можно применять к переменным. Они отделяются от переменной вертикальной чертой (|). Ansible включает в себя множество встроенных фильтров, а вы также можете создавать свои собственные.
Создадим новый шаблон, который демонстрирует некоторые распространенные фильтры. Создайте новый файл с именем filters.j2:
cd ~/project/templates
nano filters.j2
Добавьте следующее содержимое:
1. Uppercase filter: {{ name | upper }}
2. Length filter: {{ name | length }}
3. Default filter: {{ optional_var | default('No value provided') }}
4. Join filter: {{ fruits | join(', ') }}
5. Random item: {{ fruits | random }}
6. First item: {{ fruits | first }}
7. JSON encode: {{ complex_data | to_json }}
Теперь создадим плейбук для использования этого шаблона. Вернитесь в корень проекта и создайте новый файл с именем use_filters.yml:
cd ~/project
nano use_filters.yml
Добавьте следующее содержимое:
---
- name: Use Jinja2 filters
hosts: localhost
vars:
name: "ansible learner"
fruits:
- apple
- banana
- cherry
complex_data:
key1: value1
key2:
- item1
- item2
tasks:
- name: Create file from template
template:
src: templates/filters.j2
dest: /tmp/filters.txt
- name: Display file contents
command: cat /tmp/filters.txt
register: file_contents
- name: Show file contents
debug:
var: file_contents.stdout_lines
Этот плейбук применяет различные фильтры Jinja2 к нашим переменным и отображает результаты.
Запустите плейбук:
ansible-playbook use_filters.yml
Вывод показывает, как каждый фильтр изменяет входные данные. Это демонстрирует, как фильтры можно использовать для манипуляции данными в шаблонах.
Условные операторы Jinja2
Jinja2 позволяет использовать условные операторы в своих шаблонах. Это особенно полезно, когда необходимо включать или исключать контент в зависимости от определенных условий.
Создайте новый файл шаблона с именем conditionals.j2:
cd ~/project/templates
nano conditionals.j2
Добавьте следующее содержимое:
{% if user_type == 'admin' %}
Welcome, Administrator!
You have full access to the system.
{% elif user_type == 'user' %}
Welcome, User!
You have limited access to the system.
{% else %}
Welcome, Guest!
You have read-only access to the system.
{% endif %}
{% if fruits %}
Available fruits:
{% for fruit in fruits %}
- {{ fruit }}
{% endfor %}
{% else %}
No fruits available.
{% endif %}
Теперь создадим плейбук для использования этого шаблона. Вернитесь в корень проекта и создайте новый файл с именем use_conditionals.yml:
cd ~/project
nano use_conditionals.yml
Добавьте следующее содержимое:
---
- name: Use Jinja2 conditionals
hosts: localhost
vars:
user_type: "admin"
fruits:
- apple
- banana
- cherry
tasks:
- name: Create file from template (admin)
template:
src: templates/conditionals.j2
dest: /tmp/conditionals_admin.txt
- name: Create file from template (user)
template:
src: templates/conditionals.j2
dest: /tmp/conditionals_user.txt
vars:
user_type: "user"
- name: Create file from template (guest)
template:
src: templates/conditionals.j2
dest: /tmp/conditionals_guest.txt
vars:
user_type: "guest"
fruits: []
- name: Display file contents
command: "cat {{ item }}"
loop:
- /tmp/conditionals_admin.txt
- /tmp/conditionals_user.txt
- /tmp/conditionals_guest.txt
register: file_contents
- name: Show file contents
debug:
var: file_contents.results[item].stdout_lines
loop: [0, 1, 2]
Этот плейбук создает три разных файла, используя один и тот же шаблон, но с разными значениями переменных, демонстрируя, как работают условные операторы в шаблоне.
Запустите плейбук:
ansible-playbook use_conditionals.yml
Вывод показывает, как содержимое шаблона меняется в зависимости от разных условий.
Циклы в Jinja2
Jinja2 предоставляет конструкции для циклов, которые позволяют перебирать списки и словари. Это особенно полезно, когда вам нужно генерировать повторяющийся контент на основе переменных данных.
Создайте новый файл шаблона с именем loops.j2:
cd ~/project/templates
nano loops.j2
Добавьте следующее содержимое:
1. Simple loop:
{% for item in simple_list %}
- {{ item }}
{% endfor %}
2. Loop with index:
{% for item in simple_list %}
{{ loop.index }}. {{ item }}
{% endfor %}
3. Loop over a dictionary:
{% for key, value in simple_dict.items() %}
{{ key }}: {{ value }}
{% endfor %}
4. Nested loop:
{% for category, items in nested_dict.items() %}
{{ category }}:
{% for item in items %}
- {{ item }}
{% endfor %}
{% endfor %}
5. Conditional in loop:
{% for item in simple_list %}
{% if loop.first %}First item: {% endif %}
{% if loop.last %}Last item: {% endif %}
{{ item }}
{% endfor %}
Теперь создадим плейбук для использования этого шаблона. Вернитесь в корень проекта и создайте новый файл с именем use_loops.yml:
cd ~/project
nano use_loops.yml
Добавьте следующее содержимое:
---
- name: Use Jinja2 loops
hosts: localhost
vars:
simple_list:
- apple
- banana
- cherry
simple_dict:
name: John Doe
age: 30
city: New York
nested_dict:
fruits:
- apple
- banana
vegetables:
- carrot
- potato
tasks:
- name: Create file from template
template:
src: templates/loops.j2
dest: /tmp/loops.txt
- name: Display file contents
command: cat /tmp/loops.txt
register: file_contents
- name: Show file contents
debug:
var: file_contents.stdout_lines
Этот плейбук демонстрирует различные способы использования циклов в шаблонах Jinja2.
Запустите плейбук:
ansible-playbook use_loops.yml
Вывод показывает, как различные конструкции циклов в шаблоне генерируют контент на основе предоставленных переменных.
Продвинутые техники Jinja2
В этом последнем шаге мы рассмотрим некоторые продвинутые техники Jinja2, включая макросы и фильтры. Макросы — это повторно используемые фрагменты шаблонов, аналогичные функциям в языках программирования.
Создайте новый файл шаблона с именем advanced.j2:
cd ~/project/templates
nano advanced.j2
Добавьте следующее содержимое:
{% macro render_list(title, items) %}
{{ title }}:
{% for item in items %}
- {{ item }}
{% endfor %}
{% endmacro %}
1. Using a macro:
{{ render_list("Fruits", fruits) }}
{{ render_list("Vegetables", vegetables) }}
2. Using set:
{% set greeting = "Hello, " + name + "!" %}
{{ greeting }}
3. Custom filter (defined in playbook):
{{ complex_data | to_nice_json }}
4. Whitespace control:
{% for item in fruits -%}
{{ item }}
{%- if not loop.last %}, {% endif %}
{%- endfor %}
5. Raw block (no processing):
{% raw %}
This {{ will_not_be_processed }}
{% endraw %}
6. Include another template:
{% include 'simple_include.j2' %}
Теперь создадим простой включаемый файл. Создайте новый файл с именем simple_include.j2:
nano simple_include.j2
Добавьте следующее содержимое:
This is content from an included template.
Current user: {{ ansible_user_id }}
Теперь создадим плейбук для использования этого продвинутого шаблона. Вернитесь в корень проекта и создайте новый файл с именем use_advanced.yml:
cd ~/project
nano use_advanced.yml
Добавьте следующее содержимое:
---
- name: Use advanced Jinja2 techniques
hosts: localhost
vars:
name: "Ansible Expert"
fruits:
- apple
- banana
- cherry
vegetables:
- carrot
- potato
- broccoli
complex_data:
key1: value1
key2:
- item1
- item2
custom_filters:
to_nice_json: "{{ '(' ~ ((complex_data | to_json) | replace('\"', '\\\"')) ~ ')' | from_json | to_nice_json }}"
tasks:
- name: Create file from template
template:
src: templates/advanced.j2
dest: /tmp/advanced.txt
- name: Display file contents
command: cat /tmp/advanced.txt
register: file_contents
- name: Show file contents
debug:
var: file_contents.stdout_lines
Этот плейбук демонстрирует продвинутые техники Jinja2, включая макросы, пользовательские фильтры, управление пробелами и включение других шаблонов.
Запустите плейбук:
ansible-playbook use_advanced.yml
Вывод показывает, как эти продвинутые техники Jinja2 работают на практике.
Резюме
В этом практическом занятии вы изучили использование шаблонов Jinja2 в Ansible, рассмотрев широкий спектр возможностей и техник. Вот основные выводы:
- Базовый синтаксис Jinja2: Вы узнали, как использовать переменные и факты Ansible в шаблонах.
- Фильтры Jinja2: Вы исследовали различные встроенные фильтры для манипуляции данными в шаблонах.
- Условные операторы: Вы использовали конструкции if-elif-else для создания динамического контента в зависимости от условий.
- Циклы: Вы научились перебирать списки и словари, включая вложенные циклы и управление циклами.
- Продвинутые техники: Вы изучили макросы, пользовательские фильтры, управление пробелами, блоки raw и включение других шаблонов.
Эти возможности Jinja2 позволяют создавать высоко динамические и гибкие шаблоны в Ansible. Они дают возможность генерировать конфигурационные файлы, скрипты и другой контент, который может адаптироваться к различным сценариям и входным данным.
По мере продолжения работы с Ansible вы заметите, что овладение шаблонированием Jinja2 является важным условием для создания эффективных и адаптивных плейбуков и ролей. Это позволяет писать более компактный и поддерживаемый код, уменьшая дублирование и делая ваши проекты на Ansible более масштабируемыми.
Не забывайте, что хотя Jinja2 является мощным инструментом, важно найти баланс между гибкостью и читаемостью. Слишком сложные шаблоны могут быть трудными для поддержки, поэтому всегда стремитесь к ясности в дизайне своих шаблонов.
Практикуйте использование этих возможностей Jinja2 в своих проектах на Ansible, и вы сможете легко справляться с все более сложными задачами автоматизации.


