
Jinja2 est le moteur de templating utilisé par Ansible pour générer des fichiers de configuration dynamiques. Au-delà de la simple interpolation {{ var }} que vous avez vue partout, Jinja2 supporte des boucles ({% for %}), des conditions ({% if %}), des commentaires ({# #}), et un contrôle fin du whitespace ({%- ... -%}). Cette page synthétise la syntaxe que vous taperez dans tout fichier .j2 ou dans une string Ansible avec interpolation Jinja.
L'enjeu : générer un fichier de config (motd, nginx.conf, sshd_config) à partir d'un template + variables, sans avoir à scripter ligne par ligne avec lineinfile:.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »{{ var }}pour interpoler une variable ou une expression{% for %}+{% if %}pour la logique{# commentaire #}pour commenter (ne sera pas dans la sortie)- Le whitespace control :
{%- ... -%}et l'optiontrim_blocks: true - Différence entre un fichier
.j2(template) et une string Ansible avec Jinja inline
Prérequis
Section intitulée « Prérequis »- Avoir lu Filtres Jinja2 essentiels ;
- Connaître les variables Ansible (cf. Variables, déclaration).
Les 3 marqueurs Jinja2
Section intitulée « Les 3 marqueurs Jinja2 »{# Ceci est un commentaire (n'apparaît PAS dans la sortie générée) #}
Hello {{ name | upper }} ← interpolation : remplace par la valeur
{% if user_count > 0 %} ← logique : pas affiché tel quelVous avez {{ user_count }} utilisateurs.{% endif %}
{% for u in users %} ← boucle- {{ u.name }} ({{ u.email }}){% endfor %}| Marqueur | Rôle | Apparaît dans la sortie ? |
|---|---|---|
{{ ... }} | Interpolation d'une variable / expression | Oui (la valeur) |
{% ... %} | Logique (if, for, set, include) | Non (mais le résultat est dans la sortie) |
{# ... #} | Commentaire | Non |
Interpolation {{ var }}
Section intitulée « Interpolation {{ var }} »{{ ansible_distribution }} {{ ansible_distribution_version }}{{ user.name | default('inconnu') }}{{ ports | join(', ') }}{{ 2 + 3 }} ← expression Python (5)L'interpolation accepte toute expression Python valide (limitée par sandbox) + les filtres Jinja (| upper, | default, | join).
Conditions {% if %}
Section intitulée « Conditions {% if %} »{% if env == 'prod' %}debug = false{% elif env == 'staging' %}debug = truelog_level = info{% else %}debug = truelog_level = debug{% endif %}Les opérateurs disponibles : ==, !=, >, <, >=, <=, and, or, not, in. Les tests (vu page suivante) : is defined, is none, is mapping.
Boucles {% for %}
Section intitulée « Boucles {% for %} »{% for user in users %}- {{ user.name }} ({{ user.email }}){% endfor %}Variables magiques loop.* disponibles dans la boucle :
| Variable | Valeur |
|---|---|
loop.index | Index 1-based (1, 2, 3...) |
loop.index0 | Index 0-based (0, 1, 2...) |
loop.first | true si première itération |
loop.last | true si dernière itération |
loop.length | Nombre total d'éléments |
{% for u in users -%}{{ loop.index }}. {{ u.name }}{% if not loop.last %},{% endif %}{% endfor %}Boucle imbriquée :
{% for env, hosts in environments.items() %}[{{ env }}]{% for h in hosts %}{{ h }}{% endfor %}{% endfor %}Commentaires {# #}
Section intitulée « Commentaires {# #} »{# Cette ligne est invisible dans le fichier généré #}{# Utile pour expliquer la logique du template aux mainteneurs #}{# Ne pas confondre avec les commentaires shell # qui SONT dans la sortie #}Les {# #} ne sont jamais dans la sortie, différents des # bash comments qui apparaissent dans le fichier généré (parce qu'ils sont du texte normal pour Jinja).
Whitespace control, le piège n°1
Section intitulée « Whitespace control, le piège n°1 »Sans contrôle, ce template :
Services :{% for s in services %} - {{ s }}{% endfor %}Produit (avec des lignes vides indésirables) :
Services :
- sshd
- chronyd
- firewalldLe \n après chaque {% ... %} est conservé. Solution : {%- ... -%} strip le whitespace avant/après le tag :
Services :{% for s in services -%} - {{ s }}{% endfor %}Sortie propre :
Services : - sshd - chronyd - firewalldConvention :
{%-: strip whitespace avant le tag-%}: strip whitespace après le tag{{- ... -}}: idem pour les expressions
Options globales : trim_blocks + lstrip_blocks
Section intitulée « Options globales : trim_blocks + lstrip_blocks »Plutôt que poser {%- / -%} partout, vous pouvez activer ces deux options au niveau du module template :
- name: Template avec whitespace control automatique ansible.builtin.template: src: motd.j2 dest: /etc/motd trim_blocks: true # supprime le \n après chaque {% %} lstrip_blocks: true # supprime les espaces de début de ligne devant {% %} mode: "0644"Avec trim_blocks: true + lstrip_blocks: true, le template précédent sans {%- produit le bon résultat. C'est la combinaison recommandée, vous l'activez par défaut.
Cas pratique, MOTD avec if + for
Section intitulée « Cas pratique, MOTD avec if + for »Voici le template validé sur le lab ecrire-code-jinja2-base :
========================================== Bienvenue sur {{ inventory_hostname }}=========================================={% if host_role == "DB" %}Profil : DB{% endif %}Services :{% for s in services -%} - {{ s }}{% endfor %}Le playbook qui consomme ce template :
- name: Challenge jinja2 base hosts: db1.lab become: true vars: host_role: DB services: - postgresql - chronyd - firewalld tasks: - name: Poser /etc/motd-challenge via template ansible.builtin.template: src: templates/motd.j2 dest: /etc/motd-challenge mode: "0644"Contenu posé sur db1.lab :
========================================== Bienvenue sur db1.lab==========================================
Profil : DB
Services : - postgresql - chronyd - firewalldLes if et for sont rendus, le whitespace control sur le for évite les lignes vides entre services.
Différence : fichier .j2 vs Jinja inline
Section intitulée « Différence : fichier .j2 vs Jinja inline »Il y a deux contextes où vous écrivez du Jinja en Ansible :
1. Fichier .j2 consommé par template:
Section intitulée « 1. Fichier .j2 consommé par template: »- name: Générer nginx.conf ansible.builtin.template: src: templates/nginx.conf.j2 dest: /etc/nginx/nginx.conf mode: "0644"Le fichier complet est traité comme template Jinja2. Tous les marqueurs {{ }}, {% %}, {# #} sont actifs.
2. Jinja inline dans une string Ansible
Section intitulée « 2. Jinja inline dans une string Ansible »- name: Déposer foo ansible.builtin.copy: dest: /tmp/foo content: "Bienvenue sur {{ inventory_hostname }}\n" mode: "0644"Seules les expressions {{ }} sont évaluées. Pas de boucles ou conditions inline.
Pour les logiques complexes, basculez sur un vrai fichier .j2 + le module template:.
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
Lignes vides indésirables après {% for %} | Whitespace par défaut conservé | {%- ... -%} ou trim_blocks: true + lstrip_blocks: true |
{# commentaire #} apparaît dans la sortie | Mauvais marqueur (probablement { # ... # } avec espaces) | Pas d'espaces : {# comment #} |
Boucle qui plante avec 'NoneType' has no attribute | Variable absente dans certains items | Préfixer par is defined ou default() |
Variables Ansible non interpolées dans .j2 | Variables non passées au play | Vérifier vars: du play ou host_vars/ |
{{ var }} non interpolé dans un YAML inline | Manque les quotes | Toujours quoter : content: "{{ var }}\n" |
À retenir
Section intitulée « À retenir »- 3 marqueurs Jinja2 :
{{ }}interpolation,{% %}logique,{# #}commentaire. - Whitespace control essentiel :
{%- ... -%}outrim_blocks: true+lstrip_blocks: true(recommandé). loop.*exposeindex,first,last,lengthdans une bouclefor.- Différence fichier
.j2(Jinja complet) vs Jinja inline (interpolation seule). - Le module
template:transforme le.j2côté control node, copie le résultat vers le managed node.
Mettre en pratique
Section intitulée « Mettre en pratique »Le whitespace d'un template ne se corrige qu'en regardant le fichier rendu. Le lab vous fait interpoler des variables, conditionner un bloc avec {% if %}, itérer avec {% for %}, puis supprimer les lignes vides parasites par le whitespace control. Le fichier généré est comparé au résultat attendu, ce qui rend chaque saut de ligne en trop détectable.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Module template : le module qui consomme ce
.j2, avectrim_blocks,backupet surtoutvalidate. - Tests Jinja2 : les prédicats
is definedetis mappingqui sécurisent les blocs{% if %}de vos gabarits. - lineinfile vs template : savoir reconnaître les cas où deux lignes suffisent et où un gabarit complet est disproportionné.