
Pendant l’exécution d’un playbook, vous avez souvent besoin de capturer une sortie de module et de la réutiliser plus loin. C’est le rôle de register: (capture la sortie d’une tâche) et set_fact: (crée une variable au runtime). Cette page explique la différence, les champs disponibles dans un register: (stdout, rc, delta…), la durée de vie des variables, et l’option cacheable: true qui rend un fact persistant entre runs via le fact caching.
C’est l’outil de prédilection pour chaîner des tâches : récupérer un version, calculer un identifiant, conditionner une suite d’actions sur le résultat d’une commande.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »register: varcapture la sortie complète d’un module (rc, stdout, stderr, delta…)- Accéder aux champs :
var.stdout,var.rc,var.changed,var.failed set_fact:crée une variable de runtime, scope du play entiercacheable: truerend le fact persistant via fact_caching (jsonfile/redis/memcached)- La différence entre
register(lié à la tâche),set_fact(manuel) et les facts (gather)
Prérequis
Section intitulée « Prérequis »- Avoir lu les pages précédentes de la sous-section Variables et facts.
register: — capturer la sortie d’un module
Section intitulée « register: — capturer la sortie d’un module »- name: Récupérer le hostname ansible.builtin.command: hostname -s register: hostname_result changed_when: false
- name: Afficher ansible.builtin.debug: msg: "stdout={{ hostname_result.stdout }} rc={{ hostname_result.rc }}"hostname_result contient tout ce que le module a retourné. Pour le module command :
| Champ | Contenu |
|---|---|
stdout | Sortie standard (string) |
stdout_lines | Sortie standard (liste de lignes) |
stderr | Sortie d’erreur |
stderr_lines | Idem en liste |
rc | Exit code (0 = succès) |
cmd | La commande exécutée |
start, end, delta | Timestamps |
changed, failed, skipped | Status booléens |
Pour les autres modules, les champs varient. Exemple avec uri :
- name: Appeler une API ansible.builtin.uri: url: http://localhost return_content: true register: api_responseapi_response contient :
status: code HTTP retournécontent: corps de la réponsejson: si la réponse est JSON, parsée automatiquementcookies: cookies reçuselapsed: temps écoulé
Toujours regarder la doc du module (ansible-doc <fqcn>) pour connaître les champs exposés.
set_fact: — créer une variable au runtime
Section intitulée « set_fact: — créer une variable au runtime »- name: Calculer un identifiant à partir de plusieurs sources ansible.builtin.set_fact: server_id: "{{ inventory_hostname | upper }}-{{ ansible_default_ipv4.address | replace('.', '-') }}"
- name: Utiliser server_id ansible.builtin.debug: msg: "Server ID = {{ server_id }}"set_fact: crée une variable de play disponible dans toutes les tâches suivantes. Elle est précédence niveau 19 — gagne sur le vars: du play (12) mais pas sur --extra-vars (22).
Plusieurs faits dans un même set_fact: :
- name: Plusieurs facts ansible.builtin.set_fact: server_id: "{{ inventory_hostname | upper }}" deploy_date: "{{ ansible_date_time.iso8601 }}" deploy_user: "{{ ansible_user_id }}"La portée d’un set_fact:
Section intitulée « La portée d’un set_fact: »Par défaut, un set_fact: est éphémère : disponible dans le play courant, perdu au prochain run. Avec cacheable: true, il est stocké dans le fact_caching :
- name: Set_fact persistant ansible.builtin.set_fact: last_deploy_date: "{{ ansible_date_time.iso8601 }}" cacheable: trueAu prochain run sur le même hôte, last_deploy_date est automatiquement chargé depuis le cache avant la phase gather_facts. Vous pouvez l’utiliser pour comparer des dates.
Configuration du fact_caching dans ansible.cfg :
[defaults]fact_caching = jsonfilefact_caching_connection = ./.ansible_factsfact_caching_timeout = 7200 # 2hBackends supportés : jsonfile (fichiers locaux), redis (recommandé production), memcached.
Cas pratique — chaîner register puis set_fact
Section intitulée « Cas pratique — chaîner register puis set_fact »Voici l’exemple validé sur le lab 16-ecrire-code-register-set-fact :
---- name: Challenge register set_fact hosts: db1.lab become: true
tasks: - name: Hostname ansible.builtin.command: hostname -s register: hostname_result changed_when: false
- name: Kernel ansible.builtin.command: uname -r register: kernel_result changed_when: false
- name: Construire system_id ansible.builtin.set_fact: system_id: "{{ hostname_result.stdout }}:{{ kernel_result.stdout }}"
- name: Poser le fichier ansible.builtin.copy: dest: /tmp/system-id.txt content: "system_id={{ system_id }}\n" mode: "0644"Contenu de /tmp/system-id.txt sur db1.lab :
system_id=db1:5.14.0-628.el10.x86_64Pattern : deux command registered, un set_fact qui combine, une tâche qui consomme la variable créée.
changed_when: false sur les commandes de lecture
Section intitulée « changed_when: false sur les commandes de lecture »Une commande comme hostname -s ne modifie pas l’état du système — pourtant le module command la marque par défaut comme changed=true, ce qui pollue le PLAY RECAP et peut déclencher des handlers à tort.
Toujours poser changed_when: false sur une commande de lecture :
- name: Lire le hostname (lecture pure, pas de modif) ansible.builtin.command: hostname -s register: hostname_result changed_when: false # ← ne marque pas comme changed check_mode: false # ← exécute même en --check (pour avoir la vraie valeur)Combiné à check_mode: false, vous obtenez la valeur réelle même quand le playbook tourne en --check.
until: pour attendre une condition
Section intitulée « until: pour attendre une condition »Couplé avec register:, until: répète une tâche jusqu’à ce qu’une condition soit vraie :
- name: Attendre que le service réponde ansible.builtin.uri: url: http://localhost/health status_code: 200 register: health_check until: health_check.status == 200 retries: 30 delay: 2 # 30 retries × 2s = 60s d'attente maxTrès utile après un démarrage de service ou un déploiement — la tâche échoue après le timeout total si la condition n’est jamais vraie.
failed_when: et changed_when:
Section intitulée « failed_when: et changed_when: »Avec register:, vous pouvez redéfinir quand une tâche est considérée failed ou changed :
- name: Lancer un script qui retourne 0 ou 1 selon l'état ansible.builtin.command: /usr/local/bin/check-state.sh register: state_result failed_when: state_result.rc not in [0, 1] # rc=2 = vraiment failed changed_when: state_result.rc == 1 # rc=1 = changement détectéPermet d’utiliser command: ou shell: de façon idempotente en mappant les codes retour sur la sémantique Ansible.
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
'dict object' has no attribute 'stdout' | La tâche a échoué avant — register n’a pas le champ attendu | when: not result.failed ou failed_when: adapté |
set_fact perdu entre 2 plays | Sans cacheable: true, le fact est limité au play courant | Ajouter cacheable: true (avec attention à la persistence) |
changed=true à chaque run sur un command de lecture | Pas de changed_when: posé | Ajouter changed_when: false |
register: ne capture rien quand la tâche est en --check | command est skippé en check mode | Ajouter check_mode: false sur la tâche |
| Fact persistant qui contient une valeur obsolète | cacheable: true sans expiration | Ajuster fact_caching_timeout ou nettoyer le cache (rm -rf .ansible_facts/) |
À retenir
Section intitulée « À retenir »register: varcapture la sortie d’un module ; champs courants :stdout,rc,changed,failed,delta.set_fact:crée une variable de play au runtime ; précédence niveau 19.cacheable: truesur set_fact = fact persistant via fact_caching (jsonfile/redis/memcached).- Sur les commandes de lecture pure : toujours
changed_when: false+check_mode: false. until + retries + delaytransforme une tâche en boucle d’attente conditionnelle.failed_when:etchanged_when:redéfinissent la sémantique Ansible d’un module non-idempotent.
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/ecrire-code/register-set-fact/ dans
stephrobert/ansible-training. Il contient
un README.md guidé, un Makefile (make verify lance les tests), et un
challenge final auto-évalué : chaîner register: (hostname, kernel) puis set_fact: pour construire un system_id.
Une fois le lab provisionné :
cd ~/Projets/ansible-training/labs/ecrire-code/register-set-fact/
cat README.md # tuto pas à pascat challenge/README.md # consigne du challenge finalpytest -v challenge/tests/ # lancer les tests testinfraSi les tests passent, vous maîtrisez les concepts couverts dans ce guide. En
cas de blocage, docs/troubleshooting.md
à la racine du repo couvre les pièges fréquents (rate-limit SSH, clé absente,
collection manquante).