Aller au contenu
Infrastructure as Code medium

Facts et magic vars Ansible : ansible_facts, gather_subset, hostvars

12 min de lecture

Logo Ansible

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, 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.

  • 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, play_hosts, ansible_play_batch
  • Accéder aux facts d’un autre hôte via hostvars['<host>'].ansible_*

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 :

Fenêtre de terminal
ansible web1.lab -m setup | head -40

Sortie (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.*.

FactTypeExemple
ansible_distributionstringAlmaLinux, Ubuntu, Debian
ansible_distribution_versionstring10.1
ansible_distribution_major_versionstring10
ansible_os_familystringRedHat, Debian
ansible_default_ipv4.addressstring10.10.20.21
ansible_all_ipv4_addresseslist["10.10.20.21"]
ansible_memtotal_mbint1740
ansible_processor_coresint1
ansible_processor_countint1
ansible_kernelstring5.14.0-...el10.x86_64
ansible_hostnamestringweb1 (court)
ansible_fqdnstringweb1.lab (FQDN)
ansible_python_versionstring3.12.x
ansible_pkg_mgrstringdnf, apt

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: present

become_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.

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éseau

Subsets disponibles :

SubsetContient
allTout (par défaut)
minSous-ensemble minimal (distribution, kernel, hostname)
networkInterfaces, IPs, MAC
hardwareCPU, mémoire, disques
virtualVirtualisation détectée
facter, ohaiExternal fact gatherers

Préfixer avec ! = exclure. Combinaisons typiques :

  • ['!all', '!min', 'network'] : seulement le réseau (le plus rapide)
  • ['!all', 'min'] : juste le minimum vital

Sur 100 hôtes, passer de all à min peut réduire le temps de gather de 50 %.

Variables automatiquement injectées par Ansible, pas issues du gather :

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"

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 }}"
  • play_hosts : liste des hôtes ciblés par le play avant filtrage par serial:.
  • ansible_play_batch : liste des hôtes du batch courant (pertinent quand serial: N).
- name: Liste du batch courant
ansible.builtin.debug:
msg: "Batch : {{ ansible_play_batch }}"

Cas pratique — synthèse cross-host (lab ecrire-code/facts-magic-vars)

Section intitulée « Cas pratique — synthèse cross-host (lab ecrire-code/facts-magic-vars) »

Voici l’exemple validé sur le lab 14-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.lab
db1_os=AlmaLinux
db1_memory=1740
webservers_count=2
web1_ip=10.10.20.21

Le pre-gather sur web1.lab est nécessaire pour que hostvars['web1.lab'] soit peuplé au moment du second play.

SituationMécanisme
Adapter une commande à la distributionwhen: ansible_distribution == 'AlmaLinux'
Calculer une mémoire dépendante de la machinenginx_workers: "&#123;&#123; ansible_processor_cores * 2 &#125;&#125;"
Connaître l’IP d’un hôte voisinhostvars['<host>'].ansible_default_ipv4.address
Itérer sur tous les membres d’un groupeloop: "&#123;&#123; groups['webservers'] &#125;&#125;"
Identifier l’hôte courant dans un template&#123;&#123; inventory_hostname &#125;&#125;
Connaître quels hôtes sont dans le batch courant&#123;&#123; ansible_play_batch &#125;&#125;
SymptômeCauseFix
'NoneType' object has no attribute 'ansible_default_ipv4'hostvars de l’hôte n’a pas été gatherAjouter un pre-gather play sur le groupe
gather_facts: false mais le playbook utilise ansible_distributionDésactivation accidentelleRéactiver gather_facts: true ou utiliser le module setup ad-hoc
groups vide ou incorrectMauvais nom de groupe ou inventaire pas chargéVérifier avec ansible-inventory --graph
gather_subset ignore mes choixMauvaise syntaxe de l’expressionVé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
  • gather_facts: true (défaut) collecte les facts via le module setup au début de chaque play.
  • gather_subset: filtre la collecte — passer de all à min peut diviser par 2 le temps de gather.
  • Les magic vars essentielles : inventory_hostname, groups, hostvars, play_hosts, ansible_play_batch.
  • 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.distribution sera la forme canonique — ansible_distribution deprecated.

Cette page a un lab d’accompagnement : labs/ecrire-code/facts-magic-vars/ dans stephrobert/ansible-training. Il contient un README.md guidé, un Makefile (make verify lance les tests), et un challenge final auto-évalué : synthèse cross-host : facts db1 + IP web1 via hostvars (pre-gather sur web1).

Une fois le lab provisionné :

Fenêtre de terminal
cd ~/Projets/ansible-training/labs/ecrire-code/facts-magic-vars/
cat README.md # tuto pas à pas
cat challenge/README.md # consigne du challenge final
pytest -v challenge/tests/ # lancer les tests testinfra

Si 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).

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn