
Les facts standards (ansible_distribution, ansible_default_ipv4, ansible_memtotal_mb, etc.) sont collectés par le module setup au début de chaque play. Les custom facts étendent ce mécanisme : on dépose un script (Bash, Python ou JSON/INI statique) dans /etc/ansible/facts.d/<nom>.fact sur la cible, et Ansible le lit à chaque gather_facts: true puis expose le résultat sous ansible_local.<nom>.
À la fin de cette page, vous saurez créer deux types de custom facts (statique INI + dynamique script Bash → JSON), les lire dans un playbook, et choisir entre custom facts, set_fact et host_vars selon le cas d’usage.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Déposer un custom fact statique au format INI dans
/etc/ansible/facts.d/. - Déposer un custom fact dynamique (script Bash exécutable retournant du JSON).
- Lire un custom fact via
ansible_local.<nom>dans un playbook. - Filtrer la sortie de
setuppour ne garder que lesansible_local. - Choisir entre custom facts,
set_fact,host_vars, inventaire dynamique.
Prérequis
Section intitulée « Prérequis »- Avoir lu Facts et magic vars.
- Connaître
ansible.builtin.copyetansible.builtin.file.
Pourquoi des custom facts
Section intitulée « Pourquoi des custom facts »Trois cas d’usage récurrents :
- Tagger un hôte avec son rôle métier (
web,db,cache,monitoring) sans toucher à l’inventaire centralisé. - Exposer des données spécifiques à une application : version déployée, hash du dernier commit, statut d’une migration de base.
- Centraliser des informations propriétaires : numéro de série hardware, contrat de support, compartiment cloud.
L’avantage : la vérité vit côté cible (la machine sait elle-même son rôle). Le control node n’a rien à savoir — il lit au lieu de déclarer.
Format des custom facts
Section intitulée « Format des custom facts »Ansible accepte deux formats dans /etc/ansible/facts.d/<nom>.fact :
| Format | Détection | Cas d’usage |
|---|---|---|
| Statique (INI, YAML, JSON) | Fichier non exécutable (mode 0644) | Données figées au déploiement |
| Dynamique (script) | Fichier exécutable (mode 0755) | Données qui changent (uptime, load, statut service) |
🔍 Observation cruciale : le bit exécutable (+x) est ce qui distingue les deux. Avec 0755, Ansible exécute le script et parse la sortie. Avec 0644, Ansible lit le fichier comme statique.
Custom fact INI statique
Section intitulée « Custom fact INI statique »; /etc/ansible/facts.d/server.fact (mode 0644)[meta]role = databaseenvironment = productionmanaged_by = ansible
[deployment]version = 1.4.2deployed_on = 2026-04-27Via Ansible, depuis le control node :
- hosts: db1.lab become: true tasks: - name: Créer /etc/ansible/facts.d/ ansible.builtin.file: path: /etc/ansible/facts.d state: directory mode: "0755"
- name: Déposer le custom fact statique ansible.builtin.copy: dest: /etc/ansible/facts.d/server.fact mode: "0644" content: | [meta] role = database environment = production [deployment] version = 1.4.2Lire le custom fact
Section intitulée « Lire le custom fact »ansible db1.lab -m ansible.builtin.setup -a "filter=ansible_local"Sortie :
ansible_local: server: deployment: version: "1.4.2" meta: environment: production role: database🔍 Observation : la structure est ansible_local.<nom_fichier_sans_.fact>.<section>.<clé>. Le fichier server.fact produit la racine ansible_local.server, les sections INI deviennent des sous-clés. Filter ansible_local isole les custom facts du reste.
Utiliser le custom fact dans un playbook
Section intitulée « Utiliser le custom fact dans un playbook »- hosts: db1.lab gather_facts: true # ← obligatoire pour collecter ansible_local tasks: - ansible.builtin.copy: dest: /tmp/config.txt content: | Hostname: {{ inventory_hostname }} Role: {{ ansible_local.server.meta.role }} Env: {{ ansible_local.server.meta.environment }} Version: {{ ansible_local.server.deployment.version }} mode: "0644"Custom fact dynamique (script Bash → JSON)
Section intitulée « Custom fact dynamique (script Bash → JSON) »#!/bin/bash# /etc/ansible/facts.d/uptime.fact (mode 0755 EXÉCUTABLE)cat <<EOF{ "uptime_seconds": $(awk '{print int($1)}' /proc/uptime), "load_1min": "$(awk '{print $1}' /proc/loadavg)", "kernel": "$(uname -r)"}EOFVia Ansible :
- name: Déposer le fact dynamique ansible.builtin.copy: dest: /etc/ansible/facts.d/uptime.fact mode: "0755" # ← BIT EXÉCUTABLE OBLIGATOIRE content: | #!/bin/bash cat <<EOF { "uptime_seconds": $(awk '{print int($1)}' /proc/uptime), "kernel": "$(uname -r)" } EOFLecture (après setup avec filter=ansible_local) :
ansible_local: uptime: kernel: "5.14.0-..." uptime_seconds: 3242🔍 Observation : Ansible détecte automatiquement le bit +x. Si oui, exécute le script et parse la sortie comme JSON. Format alternatif accepté : YAML, INI. Le script peut être en Python, Perl, ou n’importe quel langage exécutable.
Custom facts vs alternatives
Section intitulée « Custom facts vs alternatives »| Mécanisme | Stockage | Persistance | Cas d’usage |
|---|---|---|---|
Custom fact (facts.d/*.fact) | Sur la cible | Persistant entre runs | Tag métier, rôle, version déployée |
set_fact | En mémoire pendant le play | Détruit en fin de play | Calcul intermédiaire dans un playbook |
host_vars/<host>.yml | Sur le control node (Git) | Versionné dans le repo | Config statique connue à l’avance |
| Inventaire dynamique | Source externe (Cloud, DB) | Re-collecté à chaque run | Cloud, K8s, NetBox, infra dynamique |
Décision pratique : custom facts = vérité côté cible. host_vars = vérité côté gestion. Les deux peuvent coexister. Custom facts brillent pour le bootstrap (la machine s’auto-déclare son rôle dès le cloud-init).
Lab pratique
Section intitulée « Lab pratique »Le lab ecrire-code/custom-facts (labs/ecrire-code/custom-facts/) couvre les deux formats (INI statique + script Bash dynamique) avec 8 tests pytest qui valident le mode 0644 vs 0755, la structure ansible_local, et la combinaison des deux dans un playbook.
Pièges classiques
Section intitulée « Pièges classiques »- Bit exécutable oublié :
0644sur un script → Ansible le lit comme statique → parsing échoue (le shebang#!/bin/bashn’est pas du JSON). gather_facts: false:ansible_localreste vide. Soit activergather_facts: true, soit appelersetup:explicitement après dépôt.- Nom de fichier avec
-:lab14a-uptime.fact→ accessible viaansible_local['lab14a-uptime'](notation crochets, pas point). - Permissions de
/etc/ansible/facts.d/: doit être0755accessible en lecture par tout user qui lance Ansible (ou root sibecome: true).
À retenir
Section intitulée « À retenir »/etc/ansible/facts.d/<nom>.fact= chemin par défaut.- Format : INI/YAML/JSON statique OU script exécutable retournant du JSON.
- Lecture :
ansible_local.<nom>.<section>.<clé>aprèsgather_facts: true. - Bit exécutable (
mode: 0755) → script. Sinon (0644) → statique. ansible -m setup -a "filter=ansible_local"isole les custom facts.- Pas testé directement à l’EX294 mais utile en prod (tagging d’inventaire).