Passer au contenu principal

Organisation (Ansible)

Templates Jinja2

Jinja2 est le moteur de templating utilisé dans Ansible, aussi bien dans les fichiers .j2 que dans les valeurs de variables directement dans les playbooks. Maîtriser Jinja2 permet de générer des fichiers de configuration dynamiques, d'écrire des conditions expressives, et d'éviter la duplication de playbooks pour des environnements légèrement différents.

Module template

Le module template traite un fichier source Jinja2 et dépose le résultat rendu sur la cible :

- ansible.builtin.template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: "0644"
    validate: nginx -t -c %s   # validation avant déploiement

Par convention, les templates sont placés dans templates/ avec l'extension .j2. Le chemin src est relatif au répertoire du playbook ou du rôle.

Syntaxe Jinja2

# Substitution de variable
server_name {{ app_domain }};

# Condition
{% if ssl_enabled %}
listen 443 ssl;
ssl_certificate /etc/ssl/certs/{{ app_domain }}.pem;
{% else %}
listen 80;
{% endif %}

# Boucle
upstream backend {
{% for host in groups['app'] %}
    server {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port }};
{% endfor %}
}

Filtres essentiels

Les filtres transforment une valeur. Syntaxe : {{ valeur | filtre }}.

# Valeur par défaut si variable non définie ou vide
{{ app_timeout | default(30) }}
{{ app_name | default('myapp') | upper }}

# Manipulation de chaînes
{{ app_name | upper }}          # MYAPP
{{ app_name | lower }}          # myapp
{{ app_name | replace('-', '_') }}
{{ app_domain | regex_replace('\.', '_') }}

# Listes
{{ mylist | join(', ') }}
{{ mylist | length }}
{{ mylist | sort }}
{{ mylist | unique }}
{{ mylist | select('match', '^web') | list }}

# Dictionnaires
{{ mydict | dict2items }}       # convertit en liste de {key, value}
{{ items_list | items2dict }}   # inverse

# Nombres
{{ memory_mb | int * 1024 * 1024 }}
{{ value | round(2) }}

# Réseau
{{ '192.168.1.0/24' | ansible.utils.ipaddr('network') }}

# JSON
{{ myvar | to_json }}
{{ myvar | to_nice_json }}

Tests Jinja2

Les tests retournent un booléen, utilisables dans when ou {% if %} :

{% if app_port is defined %}
listen {{ app_port }};
{% endif %}

{% if myvar is none %}
# variable non définie ou nulle
{% endif %}

{% if myvar is string %}
# c'est une chaîne
{% endif %}

{% if myvar is iterable %}
# c'est une liste ou un dict
{% endif %}

Exemple concret : configuration nginx

# templates/nginx.conf.j2
worker_processes {{ nginx_worker_processes | default(ansible_processor_vcpus) }};

events {
    worker_connections {{ nginx_worker_connections | default(1024) }};
}

http {
    upstream {{ app_name }}_backend {
{% for host in groups[app_group | default('app')] %}
        server {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port }};
{% endfor %}
    }

    server {
        listen 80;
        server_name {{ app_domain }};

{% if redirect_to_https | default(false) %}
        return 301 https://$host$request_uri;
{% else %}
        location / {
            proxy_pass http://{{ app_name }}_backend;
        }
{% endif %}
    }
}

Le filtre default : éviter les erreurs

Sans default(), une variable non définie lève une erreur. Avec default(), on définit un comportement de repli :

# Valeur de secours fixe
{{ timeout | default(30) }}

# Valeur de secours dynamique
{{ workers | default(ansible_processor_vcpus * 2) }}

# Comportement si false ou vide (deuxième argument à true)
{{ myvar | default('fallback', true) }}