
Le module ansible.builtin.template est l’outil principal pour générer un fichier de configuration depuis un template Jinja2. Il prend un fichier .j2 côté control node, l’évalue avec les variables Ansible, et copie le résultat sur le managed node — avec les options classiques (mode, owner, group) plus des options spécifiques précieuses : validate: (rejette une config invalide avant écriture), backup: (préserve l’ancien fichier), lstrip_blocks: + trim_blocks: (whitespace control).
C’est l’alternative idiomatique à lineinfile: quand vous gérez plus de 2-3 lignes de config (voir lineinfile vs template).
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Les paramètres essentiels :
src,dest,mode,owner,group validate:— rejeter un fichier généré invalide avant écriturebackup: true— conserver l’ancienne versionlstrip_blocks:+trim_blocks:— whitespace control automatiqueforce: false— ne pas écraser un fichier existant- Comment notifier un handler quand le template change
Prérequis
Section intitulée « Prérequis »- Avoir lu Jinja2 — syntaxe de base ;
- Connaître le pattern handlers (cf. Handlers).
Syntaxe minimale
Section intitulée « Syntaxe minimale »- name: Poser un fichier de config depuis un template ansible.builtin.template: src: templates/nginx.conf.j2 dest: /etc/nginx/nginx.conf mode: "0644" owner: root group: rootsrc: est cherché dans cet ordre (depuis le playbook ou le rôle) :
templates/nginx.conf.j2(relatif au playbook ou au rôle)nginx.conf.j2(relatif au playbook)
Le module évalue le template côté control node, puis copie le résultat. Idempotent : si le contenu généré est identique au fichier distant existant, changed=false.
validate: — refuser une config cassée
Section intitulée « validate: — refuser une config cassée »- name: Mettre à jour sshd_config (avec validation) ansible.builtin.template: src: sshd_config.j2 dest: /etc/ssh/sshd_config owner: root group: root mode: "0600" validate: '/usr/sbin/sshd -t -f %s' notify: Restart sshdvalidate: '<commande> %s' lance la commande sur le fichier temporaire généré (%s est remplacé par le path temporaire). Si la commande échoue (exit ≠ 0), Ansible n’écrit pas le fichier final → vous ne vous bloquez pas hors du serveur si la config sshd est cassée.
Quelques validateurs utiles :
| Service | Validate |
|---|---|
| sshd | /usr/sbin/sshd -t -f %s |
| nginx | /usr/sbin/nginx -t -c %s |
| Apache | /usr/sbin/httpd -t -f %s |
| Sudo | /usr/sbin/visudo -cf %s |
| named (BIND) | /usr/sbin/named-checkconf %s |
Toujours poser un validate: sur les services critiques (sshd, nginx, sudoers) — c’est le filet de sécurité qui empêche le verrou complet.
backup: true — préserver l’ancienne version
Section intitulée « backup: true — préserver l’ancienne version »- name: Update httpd.conf ansible.builtin.template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf backup: trueSi le fichier existe et change, Ansible crée d’abord /etc/httpd/conf/httpd.conf.<timestamp>~ avant d’écrire le nouveau contenu. Permet de revenir à l’ancienne version en cas de problème.
Le chemin du backup est retourné dans result.backup_file (avec register:) :
- name: Update et capturer le backup ansible.builtin.template: src: httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf backup: true register: tpl_result
- name: Afficher le backup créé ansible.builtin.debug: msg: "Backup : {{ tpl_result.backup_file | default('aucun changement') }}"lstrip_blocks + trim_blocks — whitespace propre
Section intitulée « lstrip_blocks + trim_blocks — whitespace propre »- name: Template avec whitespace control auto ansible.builtin.template: src: motd.j2 dest: /etc/motd lstrip_blocks: true # supprime les espaces avant les {% %} trim_blocks: true # supprime le \n après les {% %}Avec ces deux options activées, vous écrivez votre .j2 sans {%- / -%} partout — Jinja2 nettoie automatiquement les sauts de ligne. C’est la combinaison recommandée pour tout nouveau template.
Cf. Jinja2 — syntaxe de base pour le détail.
force: false — ne pas écraser
Section intitulée « force: false — ne pas écraser »- name: Poser le fichier seulement si absent ansible.builtin.template: src: motd.j2 dest: /etc/motd force: falseAvec force: false, le fichier n’est posé qu’une seule fois — au premier run. Les exécutions suivantes ne touchent pas au fichier, même s’il a été modifié à la main. Cas typique : laisser l’admin local faire des modifications post-déploiement.
Notifier un handler quand le template change
Section intitulée « Notifier un handler quand le template change »Pattern restart-on-config-change (cf. Handlers) :
tasks: - name: Update nginx.conf ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf validate: '/usr/sbin/nginx -t -c %s' backup: true notify: Reload nginx
handlers: - name: Reload nginx ansible.builtin.systemd: name: nginx state: reloadedLe notify: ne déclenche le handler que si le template a changé (idempotence du module). Au second run, changed=false → handler non déclenché.
Cas pratique — banner avec validate (lab ecrire-code/module-template)
Section intitulée « Cas pratique — banner avec validate (lab ecrire-code/module-template) »Voici l’exemple validé sur le lab 29-ecrire-code-module-template :
- name: Challenge module template hosts: db1.lab become: true vars: motd_text: "Bienvenue !" metadata: generated: "2026-04-25" owner: "ops-team" tasks: - name: Poser le banner via template ansible.builtin.template: src: templates/banner.txt.j2 dest: /etc/banner.txt owner: root group: root mode: "0644" backup: true lstrip_blocks: true trim_blocks: trueAvec templates/banner.txt.j2 :
===================={{ motd_text }}===================={% for k, v in metadata.items() %}{{ k | capitalize }}: {{ v }}{% endfor %}Sortie sur db1.lab dans /etc/banner.txt :
====================Bienvenue !====================Generated: 2026-04-25Owner: ops-teamLe lstrip_blocks: true + trim_blocks: true produit un fichier propre sans lignes vides indésirables.
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
Could not find or access 'templates/foo.j2' | Mauvais chemin de src: | Vérifier la convention : templates/ à côté du playbook ou dans le rôle |
validate: plante alors que la config semble bonne | La commande de validation a besoin de paths relatifs | Tester la commande à la main avec un fichier temporaire |
backup: true ne crée pas de backup | Le fichier n’a pas changé (idempotence) | Comportement attendu : pas de backup si pas de changement |
Whitespace pollué malgré lstrip_blocks: true | Manque trim_blocks: true | Toujours activer les deux ensemble |
| Permissions du fichier reset à chaque run | Faux : si mode: est posé et conforme, changed=false | Vérifier le mode: dans le module |
À retenir
Section intitulée « À retenir »ansible.builtin.template=src(.j2côté control) +dest(managed node) + options.validate:est le filet de sécurité — toujours l’utiliser sur sshd, nginx, sudoers.backup: truepréserve l’ancien fichier en<dest>.<timestamp>~.lstrip_blocks: true+trim_blocks: true= whitespace control auto (combinaison recommandée).notify:déclenche un handler uniquement si le template a changé — pattern restart-on-config-change.force: falsepose le fichier une seule fois (laisse les modifications locales intactes).
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/ecrire-code/module-template/ dans
stephrobert/ansible-training. Le challenge
fait poser un /etc/banner.txt généré depuis un template Jinja2 avec backup: true,
lstrip_blocks: true, trim_blocks: true.
cd ~/Projets/ansible-training/labs/ecrire-code/module-template/cat README.mdpytest -v challenge/tests/