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 tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn