Skip to content

Idempotence

Objectif

Comprendre et appliquer le concept d'idempotence : une opération ansible exécutée plusieurs fois produit toujours le même résultat, sans effets de bord indésirables.

Durée

~30 minutes

Course

Course Link

Commandes utilisées pour la mise en oeuvre/compréhension.

cd $HOME/git/gh/formation-ansible/atelier-07
vagrant up
vagrant ssh ansible

# inside the vm
cd ansible/projets/ema/
ansible rocky -m user -a "name=greg shell=/bin/bash"

Le statut de création d'un nouvel utilisateur passe en CHANGED la première fois.

Création de l'utilisateur greg - statut CHANGED

Si nous relançons le même playbook, avec les mêmes arguments sur le même Target Host : la tâche passe en statut SUCCESS car aucune action n'est à effectuer sur l'hôte (comparé au statut CHANGED qui les a appliquées) et qu'il a constaté que la configuration souhaitée était bien instruite - conformément à ce qui lui est demandé.

Relance de la même commande - statut SUCCESS (rien à changer)

À vous de jouer !

Link

Le groupe d'hôtes testing existe dans l'atelier, je vais l'utiliser pour les commandes ad-hoc.

cat inventory

Contenu du fichier d'inventaire avec le groupe testing

Ajouter des paquets

Je vais utiliser le module package sur le groupe testing pour installer les paquets demandés.

Pas besoin de modifier le parallélisme car fork de 5 par défaut.

Ici on a de la chance que le user vagrant peut lancer des commandes avec sudo sans mot de passe, sinon il aurait fallut ajouter l'option -b pour become.

ansible testing -m package -b -a "name=tree,git,nmap state=present"
J'ai exécuté la commande deux fois pour montrer le statut SUCCESS

Installation de tree, git, nmap - CHANGED puis SUCCESS à la 2e exécution

Retirer des paquets

Pour supprimer les paquets, remplacer state=present par state=absent

ansible testing -m package -b -a "name=tree,git,nmap state=absent"

Suppression des paquets avec state=absent

Copier un fichier du Control vers les Target Hosts

Utilisation du module copy comme vu dans sa documentation...

Ca effacera le fichier /etc/fstab existant des Target Hosts, donc je rajoute backup=true.

ansible testing -m copy -a "src=/etc/fstab dest=/tmp/test3.txt backup=true"
Exécuté deux fois Copie de fichier avec le module copy et backup=true

Supprimer un fichier

Utilisation du module file

ansible testing -m file -a "dest=/tmp/test3.txt state=absent"

Suppression d'un fichier avec le module file et state=absent

Lancer une commande

Je vais lancer la commande du -sh / sur les Target Hosts avec les options que j'utilise d'habitude.

Commande du -sh sur les Target Hosts

ansible testing -m shell -a "df -h / --output=source,size,used,pcent,target"

Résultat de df -h sur les trois distributions

Je remarque que Debian est la distribution la plus légère et que l'emplacement de son filestystem est particulier.

Sinon la manière ansible d'avoir ces infos seraient pas les facts pour moi... avec ansible_mounts dans ce cas. Par défault il affiche tous les points de montage.

ansible testing -m setup -a "filter=ansible_mounts"

ansible facts ansible_mounts sur les Target Hosts

Je retiens

  • CHANGED = l'état du système a été modifié. SUCCESS / ok = l'état souhaité est déjà en place.
  • Un playbook idempotent peut être relancé autant de fois que nécessaire sans risque.
  • Les modules ansible (package, copy, file, user...) sont idempotents par conception.
  • Le module setup avec filter=ansible_mounts donne les infos de montage de manière structurée (alternative à df).

Cheatsheet

Symptôme Cause probable Correction
Un module command / shell renvoie systématiquement CHANGED Ces modules sont non-idempotents par nature : ansible ne sait pas inspecter leur effet Ajouter changed_when: false pour une lecture seule, ou définir changed_when: "<condition>" selon le retour
ansible testing -m package -a "name=foo state=present"sudo: a password is required Pas de -b (become) ou pas de NOPASSWD pour l'utilisateur cible Ajouter -b ou configurer become dans l'inventaire ; utiliser --ask-become-pass en dépannage
ansible testing -m copy -a "src=/etc/fstab dest=/tmp/test3.txt" écrase un fichier existant sans prévenir backup non demandé → pas de filet de sécurité Ajouter backup=true pour obtenir une copie .<timestamp>.bak avant écrasement
2ᵉ exécution renvoie encore CHANGED alors que rien ne devrait changer Un champ volatile est comparé (timestamp, contenu généré) ; le module file sans state convergent Vérifier les modes / owners demandés vs réels ; utiliser --check --diff pour identifier ce qui bouge
ansible testing -m setup -a "filter=ansible_mounts"filter ignoré Mauvaise orthographe du filtre (fnmatch), le filtre par défaut est [] donc rien ne sort Utiliser un glob valide : filter=ansible_mounts ou filter=ansible_distribution*

Sources (principales)


Précédent : Ad-hoc Commands Suite : 1st Playbook