Plantillas Jinja2 de Ansible

AnsibleAnsibleBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, explorarás Jinja2, el potente motor de plantillas utilizado por Ansible. Jinja2 te permite crear contenido dinámico, lo que hace que tus playbooks de Ansible sean más flexibles y adaptables. Al final de este laboratorio, entenderás cómo utilizar la sintaxis de Jinja2 en Ansible, incluyendo variables, filtros, condicionales y bucles. Este conocimiento te permitirá crear playbooks y roles de Ansible más dinámicos y eficientes.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL ansible(("Ansible")) -.-> ansible/ModuleOperationsGroup(["Module Operations"]) ansible(("Ansible")) -.-> ansible/PlaybookEssentialsGroup(["Playbook Essentials"]) ansible/ModuleOperationsGroup -.-> ansible/template("Generate Files from Templates") ansible/PlaybookEssentialsGroup -.-> ansible/loop("Iteration") ansible/PlaybookEssentialsGroup -.-> ansible/playbook("Execute Playbook") subgraph Lab Skills ansible/template -.-> lab-390470{{"Plantillas Jinja2 de Ansible"}} ansible/loop -.-> lab-390470{{"Plantillas Jinja2 de Ansible"}} ansible/playbook -.-> lab-390470{{"Plantillas Jinja2 de Ansible"}} end

Comprendiendo los conceptos básicos de Jinja2

Jinja2 es un lenguaje de plantillas moderno y amigable con el diseñador para Python, inspirado en las plantillas de Django. En Ansible, Jinja2 se utiliza para crear plantillas de archivos, estructuras de play dinámicas y más.

Comencemos creando una plantilla Jinja2 simple. Primero, navega hasta el directorio de tu proyecto:

cd ~/project

Ahora, creemos un directorio para nuestras plantillas:

mkdir templates
cd templates

Crea un nuevo archivo llamado hello.j2:

nano hello.j2

Agrega el siguiente contenido:

Hello, {{ name }}!

Today is {{ ansible_date_time.date }}.
Your home directory is {{ ansible_env.HOME }}.

Guarda y sale del editor nano (Ctrl+X, luego Y, luego Enter).

En esta plantilla:

  • {{ name }} es una variable que se reemplazará con un valor real cuando se renderice la plantilla.
  • {{ ansible_date_time.date }} y {{ ansible_env.HOME }} son hechos (facts) de Ansible que se llenarán automáticamente.

Ahora, creemos un playbook para usar esta plantilla. Regresa a la raíz del proyecto y crea un nuevo archivo llamado use_template.yml:

cd ~/project
nano use_template.yml

Agrega el siguiente contenido:

---
- 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

Este playbook utiliza el módulo template para renderizar nuestra plantilla Jinja2 y crear un archivo en /tmp/hello.txt.

Ejecuta el playbook:

ansible-playbook use_template.yml

Después de ejecutar el playbook, verifica el contenido del archivo creado:

cat /tmp/hello.txt

Deberías ver la plantilla renderizada con la variable y los hechos reemplazados por valores reales.

Usando filtros de Jinja2

Los filtros de Jinja2 son funciones que se pueden aplicar a variables. Se separan de la variable por un símbolo de tubería (|). Ansible incluye muchos filtros integrados, y también puedes crear tus propios filtros personalizados.

Creemos una nueva plantilla que demuestre algunos filtros comunes. Crea un nuevo archivo llamado filters.j2:

cd ~/project/templates
nano filters.j2

Agrega el siguiente contenido:

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 }}

Ahora, creemos un playbook para usar esta plantilla. Regresa a la raíz del proyecto y crea un nuevo archivo llamado use_filters.yml:

cd ~/project
nano use_filters.yml

Agrega el siguiente contenido:

---
- 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

Este playbook aplica varios filtros de Jinja2 a nuestras variables y muestra los resultados.

Ejecuta el playbook:

ansible-playbook use_filters.yml

La salida te mostrará cómo cada filtro modifica los datos de entrada. Esto demuestra cómo se pueden usar los filtros para manipular datos dentro de tus plantillas.

Condicionales en Jinja2

Jinja2 te permite utilizar declaraciones condicionales en tus plantillas. Esto es especialmente útil cuando necesitas incluir o excluir contenido basado en ciertas condiciones.

Crea un nuevo archivo de plantilla llamado conditionals.j2:

cd ~/project/templates
nano conditionals.j2

Agrega el siguiente contenido:

{% 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 %}

Ahora, creemos un playbook para usar esta plantilla. Regresa a la raíz del proyecto y crea un nuevo archivo llamado use_conditionals.yml:

cd ~/project
nano use_conditionals.yml

Agrega el siguiente contenido:

---
- 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]

Este playbook crea tres archivos diferentes utilizando la misma plantilla pero con diferentes valores de variables, demostrando cómo funcionan las declaraciones condicionales en la plantilla.

Ejecuta el playbook:

ansible-playbook use_conditionals.yml

La salida te mostrará cómo cambia el contenido de la plantilla en función de las diferentes condiciones.

Bucles en Jinja2

Jinja2 proporciona estructuras de bucle que te permiten iterar sobre listas y diccionarios. Esto es especialmente útil cuando necesitas generar contenido repetitivo basado en datos variables.

Crea un nuevo archivo de plantilla llamado loops.j2:

cd ~/project/templates
nano loops.j2

Agrega el siguiente contenido:

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 %}

Ahora, creemos un playbook para usar esta plantilla. Regresa a la raíz del proyecto y crea un nuevo archivo llamado use_loops.yml:

cd ~/project
nano use_loops.yml

Agrega el siguiente contenido:

---
- 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

Este playbook demuestra varias formas de usar bucles en plantillas Jinja2.

Ejecuta el playbook:

ansible-playbook use_loops.yml

La salida te mostrará cómo las diferentes estructuras de bucle en la plantilla generan contenido basado en las variables proporcionadas.

Técnicas avanzadas de Jinja2

En este último paso, exploraremos algunas técnicas avanzadas de Jinja2, incluyendo macros y filtros. Las macros son fragmentos de plantilla reutilizables, similares a las funciones en los lenguajes de programación.

Crea un nuevo archivo de plantilla llamado advanced.j2:

cd ~/project/templates
nano advanced.j2

Agrega el siguiente contenido:

{% 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' %}

Ahora, creemos el archivo de inclusión simple. Crea un nuevo archivo llamado simple_include.j2:

nano simple_include.j2

Agrega el siguiente contenido:

This is content from an included template.
Current user: {{ ansible_user_id }}

Ahora, creemos un playbook para usar esta plantilla avanzada. Regresa a la raíz del proyecto y crea un nuevo archivo llamado use_advanced.yml:

cd ~/project
nano use_advanced.yml

Agrega el siguiente contenido:

---
- 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

Este playbook demuestra técnicas avanzadas de Jinja2, incluyendo macros, filtros personalizados, control de espacios en blanco e inclusión de otras plantillas.

Ejecuta el playbook:

ansible-playbook use_advanced.yml

La salida te mostrará cómo funcionan estas técnicas avanzadas de Jinja2 en la práctica.

Resumen

En este laboratorio, has explorado las plantillas de Jinja2 en Ansible, cubriendo una amplia gama de características y técnicas. Estos son los puntos clave:

  1. Sintaxis básica de Jinja2: Aprendiste cómo usar variables y hechos (facts) de Ansible en plantillas.
  2. Filtros de Jinja2: Exploraste varios filtros integrados para manipular datos dentro de las plantillas.
  3. Condicionales: Usaste declaraciones if-elif-else para crear contenido dinámico basado en condiciones.
  4. Bucles: Aprendiste cómo iterar sobre listas y diccionarios, incluyendo bucles anidados y controles de bucle.
  5. Técnicas avanzadas: Exploraste macros, filtros personalizados, control de espacios en blanco, bloques raw e inclusión de plantillas.

Estas características de Jinja2 te permiten crear plantillas altamente dinámicas y flexibles en Ansible. Te permiten generar archivos de configuración, scripts y otro contenido que puede adaptarse a diferentes escenarios y entradas de datos.

A medida que sigas trabajando con Ansible, descubrirás que dominar las plantillas de Jinja2 es crucial para crear playbooks y roles eficientes y adaptables. Te permite escribir código más conciso y mantenible, reduciendo la repetición y haciendo que tus proyectos de Ansible sean más escalables.

Recuerda que aunque Jinja2 es poderoso, es importante equilibrar la flexibilidad con la legibilidad. Las plantillas demasiado complejas pueden ser difíciles de mantener, así que siempre busca la claridad en el diseño de tus plantillas.

Practica el uso de estas características de Jinja2 en tus proyectos de Ansible, y podrás manejar tareas de automatización cada vez más complejas con facilidad.