Modèles Jinja2 pour Ansible

AnsibleBeginner
Pratiquer maintenant

Introduction

Dans ce laboratoire (lab), vous allez explorer Jinja2, le puissant moteur de modèles (templating engine) utilisé par Ansible. Jinja2 vous permet de créer du contenu dynamique, rendant vos playbooks Ansible plus flexibles et adaptables. À la fin de ce laboratoire, vous comprendrez comment utiliser la syntaxe Jinja2 dans Ansible, y compris les variables, les filtres, les conditions et les boucles. Cette connaissance vous permettra de créer des playbooks et des rôles Ansible plus dynamiques et efficaces.

Comprendre les bases de Jinja2

Jinja2 est un langage de modèles (templating language) moderne et convivial pour les concepteurs, conçu pour Python et inspiré des modèles de Django. Dans Ansible, Jinja2 est utilisé pour créer des modèles de fichiers, des structures de play dynamiques, etc.

Commençons par créer un simple modèle Jinja2. Tout d'abord, accédez au répertoire de votre projet :

cd ~/project

Maintenant, créons un répertoire pour nos modèles :

mkdir templates
cd templates

Créez un nouveau fichier nommé hello.j2 :

nano hello.j2

Ajoutez le contenu suivant :

Hello, {{ name }}!

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

Enregistrez et quittez l'éditeur nano (Ctrl+X, puis Y, puis Entrée).

Dans ce modèle :

  • {{ name }} est une variable qui sera remplacée par une valeur réelle lorsque le modèle sera rendu.
  • {{ ansible_date_time.date }} et {{ ansible_env.HOME }} sont des faits Ansible qui seront automatiquement renseignés.

Maintenant, créons un playbook pour utiliser ce modèle. Revenez à la racine du projet et créez un nouveau fichier nommé use_template.yml :

cd ~/project
nano use_template.yml

Ajoutez le contenu suivant :

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

Ce playbook utilise le module template pour rendre notre modèle Jinja2 et créer un fichier à l'emplacement /tmp/hello.txt.

Exécutez le playbook :

ansible-playbook use_template.yml

Après avoir exécuté le playbook, vérifiez le contenu du fichier créé :

cat /tmp/hello.txt

Vous devriez voir le modèle rendu avec la variable et les faits remplacés par des valeurs réelles.

Utilisation des filtres Jinja2

Les filtres Jinja2 sont des fonctions qui peuvent être appliquées aux variables. Ils sont séparés de la variable par un symbole pipe (|). Ansible inclut de nombreux filtres intégrés, et vous pouvez également en créer de personnalisés.

Créons un nouveau modèle qui démontre quelques filtres courants. Créez un nouveau fichier nommé filters.j2 :

cd ~/project/templates
nano filters.j2

Ajoutez le contenu suivant :

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

Maintenant, créons un playbook pour utiliser ce modèle. Revenez à la racine du projet et créez un nouveau fichier nommé use_filters.yml :

cd ~/project
nano use_filters.yml

Ajoutez le contenu suivant :

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

Ce playbook applique divers filtres Jinja2 à nos variables et affiche les résultats.

Exécutez le playbook :

ansible-playbook use_filters.yml

La sortie vous montrera comment chaque filtre modifie les données d'entrée. Cela démontre comment les filtres peuvent être utilisés pour manipuler les données dans vos modèles.

Instructions conditionnelles Jinja2

Jinja2 vous permet d'utiliser des instructions conditionnelles dans vos modèles. Cela est particulièrement utile lorsque vous devez inclure ou exclure du contenu en fonction de certaines conditions.

Créez un nouveau fichier de modèle nommé conditionals.j2 :

cd ~/project/templates
nano conditionals.j2

Ajoutez le contenu suivant :

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

Maintenant, créons un playbook pour utiliser ce modèle. Revenez à la racine du projet et créez un nouveau fichier nommé use_conditionals.yml :

cd ~/project
nano use_conditionals.yml

Ajoutez le contenu suivant :

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

Ce playbook crée trois fichiers différents en utilisant le même modèle mais avec des valeurs de variables différentes, démontrant ainsi le fonctionnement des instructions conditionnelles dans le modèle.

Exécutez le playbook :

ansible-playbook use_conditionals.yml

La sortie vous montrera comment le contenu du modèle change en fonction des différentes conditions.

Boucles Jinja2

Jinja2 propose des structures de boucles qui vous permettent d'itérer sur des listes et des dictionnaires. Cela est particulièrement utile lorsque vous devez générer du contenu répétitif en fonction de données variables.

Créez un nouveau fichier de modèle nommé loops.j2 :

cd ~/project/templates
nano loops.j2

Ajoutez le contenu suivant :

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

Maintenant, créons un playbook pour utiliser ce modèle. Revenez à la racine du projet et créez un nouveau fichier nommé use_loops.yml :

cd ~/project
nano use_loops.yml

Ajoutez le contenu suivant :

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

Ce playbook démontre diverses façons d'utiliser les boucles dans les modèles Jinja2.

Exécutez le playbook :

ansible-playbook use_loops.yml

La sortie vous montrera comment les différentes structures de boucles dans le modèle génèrent du contenu en fonction des variables fournies.

Techniques avancées de Jinja2

Dans cette étape finale, nous allons explorer quelques techniques avancées de Jinja2, notamment les macros et les filtres. Les macros sont des extraits de modèle réutilisables, similaires aux fonctions dans les langages de programmation.

Créez un nouveau fichier de modèle nommé advanced.j2 :

cd ~/project/templates
nano advanced.j2

Ajoutez le contenu suivant :

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

Maintenant, créons le fichier d'inclusion simple. Créez un nouveau fichier nommé simple_include.j2 :

nano simple_include.j2

Ajoutez le contenu suivant :

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

Maintenant, créons un playbook pour utiliser ce modèle avancé. Revenez à la racine du projet et créez un nouveau fichier nommé use_advanced.yml :

cd ~/project
nano use_advanced.yml

Ajoutez le contenu suivant :

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

Ce playbook démontre des techniques avancées de Jinja2, notamment les macros, les filtres personnalisés, le contrôle des espaces blancs et l'inclusion d'autres modèles.

Exécutez le playbook :

ansible-playbook use_advanced.yml

La sortie vous montrera comment ces techniques avancées de Jinja2 fonctionnent en pratique.

Résumé

Dans ce laboratoire, vous avez exploré le modèle (templating) Jinja2 dans Ansible, couvrant une large gamme de fonctionnalités et de techniques. Voici les points clés à retenir :

  1. Syntaxe de base de Jinja2 : Vous avez appris à utiliser les variables et les faits Ansible dans les modèles.
  2. Filtres Jinja2 : Vous avez exploré divers filtres intégrés pour manipuler les données dans les modèles.
  3. Instructions conditionnelles : Vous avez utilisé des instructions if-elif-else pour créer du contenu dynamique en fonction de conditions.
  4. Boucles : Vous avez appris à itérer sur des listes et des dictionnaires, y compris les boucles imbriquées et les contrôles de boucle.
  5. Techniques avancées : Vous avez exploré les macros, les filtres personnalisés, le contrôle des espaces blancs, les blocs bruts (raw blocks) et l'inclusion de modèles.

Ces fonctionnalités de Jinja2 vous permettent de créer des modèles hautement dynamiques et flexibles dans Ansible. Elles vous permettent de générer des fichiers de configuration, des scripts et d'autres contenus qui peuvent s'adapter à différents scénarios et entrées de données.

Au fur et à mesure que vous continuerez à travailler avec Ansible, vous constaterez que maîtriser le modèle Jinja2 est crucial pour créer des playbooks et des rôles efficaces et adaptables. Cela vous permet d'écrire un code plus concis et plus facilement maintenable, en réduisant la répétition et en rendant vos projets Ansible plus évolutifs.

N'oubliez pas que bien que Jinja2 soit puissant, il est important d'équilibrer la flexibilité et la lisibilité. Des modèles trop complexes peuvent être difficiles à maintenir, alors toujours cherchez à être clair dans la conception de vos modèles.

Pratiquez l'utilisation de ces fonctionnalités Jinja2 dans vos projets Ansible, et vous pourrez gérer facilement des tâches d'automatisation de plus en plus complexes.