
Au début de chaque play, Ansible peut collecter automatiquement des centaines de variables sur chaque managed node : distribution, version, IP, mémoire, CPU, montages, packages, services, utilisateurs. Ce sont les facts, exposés sous la racine ansible_facts.* (et historiquement aussi en ansible_* directement). Cette page explique comment les utiliser, comment limiter leur collecte pour gagner en performance (gather_subset:), et comment lire les magic vars d'Ansible : inventory_hostname, groups, hostvars, ansible_play_hosts.
Maîtriser cette couche, c'est passer du playbook qui cible 1 hôte au playbook qui s'adapte automatiquement à la distribution, à la mémoire disponible, à la composition du groupe, sans aucune config manuelle.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Activer / désactiver
gather_facts:au niveau du play - Limiter la collecte avec
gather_subset:pour gagner du temps sur grandes fleets - Lire les facts les plus utiles :
ansible_distribution,ansible_default_ipv4,ansible_memtotal_mb,ansible_memory_mb - Utiliser les magic vars :
inventory_hostname,groups,hostvars,ansible_play_hosts,ansible_play_batch - Accéder aux facts d'un autre hôte via
hostvars['<host>'].ansible_*
Prérequis
Section intitulée « Prérequis »- Avoir lu Variables, déclaration et Types collections ;
- Avoir un lab opérationnel (
ansible all -m pingrépondpong).
La phase gather_facts
Section intitulée « La phase gather_facts »Au démarrage de chaque play (par défaut), Ansible exécute le module setup sur chaque hôte cible. Ce module remonte des centaines de variables :
ansible web1.lab -m setup | head -40Sortie (extrait) :
web1.lab | SUCCESS => { "ansible_facts": { "ansible_distribution": "AlmaLinux", "ansible_distribution_version": "10.1", "ansible_distribution_major_version": "10", "ansible_default_ipv4": { "address": "10.10.20.21", "interface": "eth0", "netmask": "255.255.255.0" }, "ansible_memtotal_mb": 1740, "ansible_processor_cores": 1, ... }}Ces facts sont disponibles dans toutes les tâches qui suivent, directement par leur nom ({{ ansible_distribution }}) ou via ansible_facts.*.
Les facts les plus utiles
Section intitulée « Les facts les plus utiles »Le module setup remonte plusieurs centaines de clés ; celles du tableau
couvrent la quasi-totalité des besoins d'un playbook courant. Regardez la
colonne Type avant d'écrire une condition : ansible_distribution_version
vaut "10.1", une chaîne, donc ansible_distribution_version > 9 échoue.
Pour comparer des numéros de version, utilisez le filtre
is version('10', '>=') ou la clé ansible_distribution_major_version. Même
piège inverse sur ansible_memtotal_mb, qui est un entier et se calcule
directement. Notez enfin la différence entre ansible_hostname (nom court, tel
que la machine se connaît) et inventory_hostname (nom tel que l'inventaire le
désigne) : ils divergent souvent, et c'est presque toujours le second qu'il faut
pour identifier un hôte.
| Fact | Type | Exemple |
|---|---|---|
ansible_distribution | string | AlmaLinux, Ubuntu, Debian |
ansible_distribution_version | string | 10.1 |
ansible_distribution_major_version | string | 10 |
ansible_os_family | string | RedHat, Debian |
ansible_default_ipv4.address | string | 10.10.20.21 |
ansible_all_ipv4_addresses | list | ["10.10.20.21"] |
ansible_memtotal_mb | int | 1740 |
ansible_processor_cores | int | 1 |
ansible_processor_count | int | 1 |
ansible_kernel | string | 5.14.0-...el10.x86_64 |
ansible_hostname | string | web1 (court) |
ansible_fqdn | string | web1.lab (FQDN) |
ansible_python_version | string | 3.12.x |
ansible_pkg_mgr | string | dnf, apt |
Désactiver les facts pour la performance
Section intitulée « Désactiver les facts pour la performance »La phase gather_facts: true prend 2-5 secondes par hôte. Sur 100 hôtes, c'est 5 minutes perdues si vous n'utilisez aucun fact :
- name: Tâche simple sans facts hosts: webservers gather_facts: false # désactive la collecte tasks: - name: Install nginx ansible.builtin.dnf: name: nginx state: presentbecome_method: sudo et les modules courants (dnf, systemd) n'ont pas besoin des facts. Les variables comme ansible_distribution ne sont en revanche plus disponibles.
Limiter la collecte avec gather_subset:
Section intitulée « Limiter la collecte avec gather_subset: »Plutôt que tout collecter ou rien, filtrez :
- name: Collecter uniquement les facts réseau hosts: webservers gather_facts: true gather_subset: - "!all" # ne pas tout collecter - "!min" # même pas le minimum - network # mais inclure le réseauSubsets disponibles :
| Subset | Contient |
|---|---|
all | Tout (par défaut) |
min | Sous-ensemble minimal (distribution, kernel, hostname) |
network | Interfaces, IPs, MAC |
hardware | CPU, mémoire, disques |
virtual | Virtualisation détectée |
facter, ohai | External fact gatherers |
Préfixer avec ! = exclure, et l'ordre compte : la liste se lit de
gauche à droite, chaque entrée retire ou rajoute par-dessus la précédente.
C'est pourquoi on écrit !all puis !min puis le sous-ensemble voulu, et
jamais l'inverse. Combinaisons typiques :
['!all', '!min', 'network']: seulement le réseau['!all', 'min']: juste le minimum vital
Le gain se mesure facilement en comptant les clés remontées, sans avoir besoin d'un chronomètre :
for s in all min '!all,!min,network' '!all,!min'; do printf '%-20s ' "$s" ansible localhost -m setup -a "gather_subset=$s" \ | sed '1s/^[^{]*//' \ | python3 -c 'import sys,json; print(len(json.load(sys.stdin)["ansible_facts"]))'doneSur un poste de développement, ce comptage donne environ 198 clés pour
all, 55 pour min et 2 pour !all,!min (seulement les métadonnées de
la collecte elle-même). Les sous-ensembles network et hardware sont les plus
lourds, parce qu'ils énumèrent respectivement toutes les interfaces et tous les
points de montage : une machine chargée en interfaces virtuelles, typiquement un
hôte Docker, voit son temps de collecte réseau exploser. Mesurez sur vos
machines avant de choisir, les écarts dépendent entièrement du parc.
Les magic vars
Section intitulée « Les magic vars »Les magic vars sont injectées par Ansible lui-même à partir de l'inventaire
et de l'état du play : elles n'ont rien à voir avec le module setup et restent
disponibles même avec gather_facts: false. Elles répondent à des questions que
la machine cible ne peut pas se poser toute seule : « comment est-ce que
l'inventaire m'appelle », « qui d'autre est dans mon groupe », « quelle est
l'adresse du serveur voisin ». Vous ne pouvez pas les redéfinir : Ansible les
réserve et écrase toute variable du même nom.
inventory_hostname
Section intitulée « inventory_hostname »Le nom de l'hôte courant tel que défini dans l'inventaire (web1.lab, pas web1).
- name: Saluer ansible.builtin.debug: msg: "Bonjour depuis {{ inventory_hostname }}"Dict des groupes de l'inventaire. groups['webservers'] retourne la liste des hôtes du groupe :
- name: Lister les webservers ansible.builtin.debug: msg: "{{ groups['webservers'] }}"# → ['web1.lab', 'web2.lab']
- name: Compter les webservers ansible.builtin.debug: msg: "{{ groups['webservers'] | length }} webservers"# → "2 webservers"hostvars
Section intitulée « hostvars »Dict indexé par hostname qui contient toutes les variables et facts de chaque hôte. Pour lire un fact d'un autre hôte :
- name: Afficher l'IP de web2 depuis web1 ansible.builtin.debug: msg: "{{ hostvars['web2.lab'].ansible_default_ipv4.address }}"ansible_play_hosts et ansible_play_batch
Section intitulée « ansible_play_hosts et ansible_play_batch »Trois variables décrivent « les hôtes du play » et elles ne renvoient pas la
même chose dès que vous utilisez serial:. La distinction compte quand vous
construisez une configuration de cluster : générer une liste de pairs à partir
du batch courant produirait un fichier différent à chaque vague de déploiement.
ansible_play_hosts_all: tous les hôtes que le motif du play a sélectionnés, y compris ceux qui ont échoué depuis.ansible_play_hosts: les hôtes encore actifs du play, sans filtrage parserial:. C'est celle qu'il faut pour écrire une liste de membres.ansible_play_batch: uniquement les hôtes de la vague courante quandserial: Nest actif. Sansserial:, elle vaut la même chose queansible_play_hosts.
- name: Liste du batch courant ansible.builtin.debug: msg: "Batch : {{ ansible_play_batch }} / play : {{ ansible_play_hosts }}"Sur un play serial: 2 ciblant trois hôtes, la première vague affiche :
"msg": "Batch : ['h1', 'h2'] / play : ['h1', 'h2', 'h3']"Cas pratique, synthèse cross-host
Section intitulée « Cas pratique, synthèse cross-host »Voici l'exemple validé sur le lab ecrire-code-facts-magic-vars :
---- name: Pre-gather facts sur web1 (rend hostvars web1 disponibles) hosts: web1.lab gather_facts: true tasks: []
- name: Synthese facts sur db1 hosts: db1.lab become: true gather_facts: true tasks: - name: Poser le fichier de synthese ansible.builtin.copy: dest: /tmp/facts-summary.txt content: | db1_hostname={{ inventory_hostname }} db1_os={{ ansible_distribution }} db1_memory={{ ansible_memtotal_mb }} webservers_count={{ groups['webservers'] | length }} web1_ip={{ hostvars['web1.lab'].ansible_default_ipv4.address }} mode: "0644"Contenu du fichier sur db1.lab :
db1_hostname=db1.labdb1_os=AlmaLinuxdb1_memory=1740webservers_count=2web1_ip=10.10.20.21Le pre-gather sur web1.lab est nécessaire pour que hostvars['web1.lab'] soit peuplé au moment du second play.
Quand utiliser quoi
Section intitulée « Quand utiliser quoi »Ce tableau se lit par la gauche : partez du besoin, pas du mécanisme. La ligne
de démarcation à retenir est celle entre les facts (ce que la machine dit
d'elle-même, disponibles uniquement après un gather) et les magic vars (ce
que l'inventaire et le play savent, disponibles même avec
gather_facts: false). Les trois premières lignes dépendent d'une collecte
réussie, les trois dernières fonctionnent sans.
| Situation | Mécanisme |
|---|---|
| Adapter une commande à la distribution | when: ansible_distribution == 'AlmaLinux' |
| Calculer une mémoire dépendante de la machine | nginx_workers: "{{ ansible_processor_cores * 2 }}" |
| Connaître l'IP d'un hôte voisin | hostvars['<host>'].ansible_default_ipv4.address |
| Itérer sur tous les membres d'un groupe | loop: "{{ groups['webservers'] }}" |
| Identifier l'hôte courant dans un template | {{ inventory_hostname }} |
| Connaître quels hôtes sont dans le batch courant | {{ ansible_play_batch }} |
Pièges fréquents
Section intitulée « Pièges fréquents »Quatre de ces cinq erreurs se produisent à l'exécution du template, pas au
parsing du playbook : ansible-playbook --syntax-check les laisse toutes
passer. Le seul contrôle qui les attrape avant la production est un
--check sur un hôte réel, ou l'inspection de l'inventaire avec
ansible-inventory --graph. La dernière ligne est différente : elle ne
provoque pas d'erreur aujourd'hui, elle annonce une rupture à venir, et c'est
la raison d'écrire ansible_facts.distribution dès maintenant.
| Symptôme | Cause | Fix |
|---|---|---|
'NoneType' object has no attribute 'ansible_default_ipv4' | hostvars de l'hôte n'a pas été gather | Ajouter un pre-gather play sur le groupe |
gather_facts: false mais le playbook utilise ansible_distribution | Désactivation accidentelle | Réactiver gather_facts: true ou utiliser le module setup ad-hoc |
groups vide ou incorrect | Mauvais nom de groupe ou inventaire pas chargé | Vérifier avec ansible-inventory --graph |
gather_subset ignore mes choix | Mauvaise syntaxe de l'expression | Vérifier l'ordre ['!all', 'network'] (l'ordre compte) |
ansible_* direct (sans ansible_facts.) | INJECT_FACTS_AS_VARS désactivé (futur Ansible) | Toujours préférer ansible_facts.distribution à ansible_distribution |
À retenir
Section intitulée « À retenir »gather_facts: true(défaut) collecte les facts via le modulesetupau début de chaque play.gather_subset:filtre la collecte, passer deallàminpeut diviser par 2 le temps de gather.- Les magic vars essentielles :
inventory_hostname,groups,hostvars,ansible_play_hosts,ansible_play_batch.play_hostsest dépréciée (alias deansible_play_batch, retrait annoncé en 2.23). hostvars['<host>'].ansible_*lit les facts d'un autre hôte, nécessite que cet hôte ait été gather au préalable.- À l'avenir,
ansible_facts.distributionsera la forme canonique,ansible_distributiondeprecated.
Mettre en pratique
Section intitulée « Mettre en pratique »Lire les facts d'un autre hôte suppose que cet hôte ait déjà été collecté, ce qu'un exemple statique ne montre jamais. Le lab vous fait exploiter inventory_hostname, groups et hostvars pour produire une synthèse croisée entre plusieurs machines, puis réduire le coût de la collecte avec gather_subset. Le fichier de synthèse sert de preuve : s'il manque une adresse IP, c'est que le pre-gather n'a pas eu lieu.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Précédence des variables : situer les facts parmi les 22 niveaux évite les surprises quand une variable les écrase.
- register et set_fact :
set_factaveccacheable: trueajoute vos propres valeurs au cache de facts. - Conditions avec when : les facts servent surtout à brancher une tâche selon la distribution ou la mémoire disponible.