RousselTMLEARNING

Automatisation

Ansible : générer des fichiers dynamiques avec Jinja2 et les facts

Créer des fichiers de configuration dynamiques : templates Jinja2, variables, facts, filtres, boucles, conditions, lookups et vérification avec validate.

1. Le moteur de templates Jinja2 #

Variables, expressions, filtres.

Principe #

Ansible s'appuie sur Jinja2 : tout texte entre {{ ... }} est évalué comme une expression, tout bloc entre {% ... %} est une instruction (boucle, condition). Le module template rend un fichier .j2 sur le contrôleur, puis le copie sur l'hôte : chaque machine reçoit un fichier adapté à ses variables et à ses facts.

Génération d'un fichier à partir d'un template Jinja2
Le même template produit un fichier différent pour chaque hôte.

Les facts : informations sur la machine #

ansible web1.lab -m setup -a "filter=ansible_distribution*"
ansible web1.lab -m setup -a "filter=ansible_memtotal_mb"
ansible web1.lab -m setup -a "filter=ansible_default_ipv4"

# Dans un playbook
- ansible.builtin.debug:
    msg: "{{ ansible_hostname }} - {{ ansible_distribution }} {{ ansible_distribution_version }} - {{ ansible_memtotal_mb }} Mo" 

Les facts les plus utilisés : ansible_hostname, ansible_fqdn, ansible_default_ipv4.address, ansible_os_family, ansible_processor_vcpus, ansible_memtotal_mb, ansible_mounts.

Bonne Pratique : Désactivez la collecte (gather_facts: false) sur les plays qui n'en ont pas besoin ou limitez-la avec gather_subset: ['!all', 'network'] pour gagner plusieurs secondes par hôte.

2. Écrire un template utile #

Boucles, conditions et filtres.

Exemple : configuration d'un reverse proxy #

# templates/upstream.conf.j2
# {{ ansible_managed }}
upstream backend {
{% for host in groups['webservers'] %}
    server {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port | default(8080) }}{% if loop.first %} weight=2{% endif %};
{% endfor %}
}

server {
    listen {{ proxy_port | default(80) }};
{% if enable_tls | default(false) %}
    listen 443 ssl;
    ssl_certificate /etc/ssl/{{ inventory_hostname }}.crt;
{% endif %}
    server_name {{ ansible_fqdn }};
    location / {
        proxy_pass http://backend;
        proxy_set_header X-Env "{{ env | upper }}";
    }
}
- name: Configurer le reverse proxy
  ansible.builtin.template:
    src: upstream.conf.j2
    dest: /etc/nginx/conf.d/upstream.conf
    mode: "0644"
    validate: nginx -t -c %s     # %s = fichier temporaire à valider
  notify: Recharger nginx
À savoir : La variable magique ansible_managed insère un commentaire « fichier géré par Ansible » : utile pour éviter les modifications manuelles.

Les filtres les plus utiles #

FiltreExempleRésultat
default{{ port | default(80) }}Valeur de repli
upper / lower{{ env | upper }}PROD
join{{ ['a','b'] | join(',') }}a,b
to_json / to_nice_yaml{{ cfg | to_nice_yaml }}Sérialisation
regex_replace{{ ver | regex_replace('^v','') }}Nettoyage
ipaddr{{ ip | ansible.utils.ipaddr('network') }}Calcul réseau
b64encode / hash{{ pwd | password_hash('sha512') }}Encodage et hash
int / float / bool{{ '8' | int + 1 }}9

3. Boucles, conditions et lookups #

Rendre les playbooks dynamiques.

loop, when et register #

- name: Créer plusieurs utilisateurs
  ansible.builtin.user:
    name: "{{ item.name }}"
    groups: "{{ item.groups | default(omit) }}"
  loop:
    - { name: alice, groups: sudo }
    - { name: bob }
  when: ansible_os_family == "Debian"

- name: Lire la version installée
  ansible.builtin.command: nginx -v
  register: nginx_version
  changed_when: false
  failed_when: nginx_version.rc not in [0, 1]

- ansible.builtin.debug:
    msg: "{{ nginx_version.stderr }}" 

Les lookups : lire des données externes #

vars:
  db_password: "{{ lookup('env', 'DB_PASSWORD') }}"
  ssh_key:     "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
  today:       "{{ lookup('pipe', 'date +%F') }}"
  tokens:      "{{ query('community.general.random_string', length=24) }}"
  secret:      "{{ lookup('community.hashi_vault.hashi_vault', 'secret=kv/app:password') }}" 

Tester un template sans le déployer #

# Rendre un template localement pour vérifier le résultat
ansible web1.lab -m template -a "src=templates/upstream.conf.j2 dest=/tmp/upstream.conf" --check --diff
ansible localhost -m ansible.builtin.template -a "src=app.conf.j2 dest=/tmp/app.conf" -e @vars.yml
cat /tmp/app.conf
Erreur Courante : N'oubliez pas validate: sur les fichiers critiques (nginx, sshd, sudoers) : un template invalide déployé en production peut vous enfermer hors du serveur.

Articles liés

Ansible : l'inventaire (statique, dynamique, groupes et variables)

Comprendre et maîtriser l'inventaire Ansible : fichiers INI et YAML, groupes, variables d'hôte et de groupe, …

Ansible : les commandes Ad-Hoc

Exécuter des actions immédiates sur un parc de serveurs avec ansible : modules ping, command, shell, copy, ap…

Ansible : structurer son code avec les rôles

Créer, organiser et réutiliser des rôles Ansible : arborescence, defaults, tasks, handlers, templates, dépend…

Pour aller plus loin

Soutenir

♥ SOUTENIR

Soutenez RousselTM Learning

Les formations, articles, TP et attestations restent gratuits et sans publicité intrusive. Une contribution libre, du montant de votre choix, finance l’hébergement, les environnements de TP et l’écriture de nouveaux contenus.

Contribuer avec PayPal Montant libre · carte bancaire ou compte PayPalEn savoir plus
QR code PayPal
Ou scannez ce QR code avec votre téléphone

Merci, chaque contribution compte !