La promesse, et ce qui la casse
Un playbook idempotent peut être rejoué autant de fois qu'on veut : la première exécution change ce qui doit l'être, les suivantes ne changent rien.
C'est ce qui rend Ansible utilisable en production. Sans cette propriété, on hésite à relancer, on découpe, on exécute à la main : autrement dit, on perd tout le bénéfice de l'outil.
Les modules d'Ansible sont idempotents par conception. Ce qui casse la promesse, ce sont presque toujours les mêmes trois choses.
Les trois briseurs d'idempotence
Les commandes brutes. command et shell exécutent, sans savoir si le travail est déjà fait. Ansible les déclare donc modifiées à chaque passage.
Deux réponses, dans cet ordre : chercher d'abord s'il existe un module dédié, ce qui est vrai neuf fois sur dix, et sinon encadrer la commande.
- name: Initialiser la base applicative
ansible.builtin.command: /opt/app/init-db.sh
args:
creates: /var/lib/app/.db-initialisee
creates indique à Ansible de ne rien faire si le fichier existe. removes fait l'inverse. changed_when permet de décider soi-même ce qui compte comme un changement.
Les modèles qui changent tout seuls. Un fichier de configuration qui embarque une date ou un identifiant aléatoire est réécrit à chaque exécution, et redémarre le service par la même occasion. Sortez le contenu variable du modèle.
Les tâches d'ajout aveugle. Ajouter une ligne à un fichier sans condition produit une accumulation. lineinfile avec une expression régulière, ou un modèle complet, évite le problème.
Le mode simulation, et sa limite
ansible-playbook site.yml --check --diff
--check annonce ce qui changerait sans rien modifier, --diff montre le contenu ligne à ligne. C'est le filet de sécurité avant une exécution en production.
Sa limite doit être connue : une tâche conditionnée par le résultat d'une commande précédente ne peut pas être évaluée correctement, puisque la commande n'a pas été exécutée. Le mode simulation est un bon indicateur, pas une preuve.
--diff sur un fichier contenant des secrets les affiche : ajoutez no_log: true sur ces tâches.
Vérifier qu'un playbook est idempotent
Le test tient en une ligne, et il devrait être systématique : exécutez-le deux fois de suite. Le second passage doit afficher zéro modification.
Ce test est si simple qu'il s'automatise en intégration continue, et il attrape la quasi-totalité des régressions d'idempotence.
Ce que l'idempotence n'apporte pas
Elle ne garantit pas que le résultat est correct, seulement qu'il est stable. Un playbook qui installe une mauvaise configuration l'installe de façon parfaitement idempotente.
Elle ne protège pas non plus d'une dérive manuelle : si quelqu'un modifie le serveur à la main, Ansible le corrigera au prochain passage, ce qui est souhaitable, mais peut surprendre.
À retenir
Modules plutôt que commandes brutes ; sinon creates, removes ou changed_when. Sortez le contenu variable des modèles. Testez en jouant deux fois : zéro changement au second passage. Et --check indique, il ne prouve pas.