
Un lookup Ansible récupère une donnée depuis une source externe au moment de l’évaluation Jinja2. Lire le contenu d’un fichier local, une variable d’environnement, le résultat d’une commande, un secret HashiCorp Vault, une ligne d’un CSV — tout passe par les plugins lookup. Cette page couvre les lookups built-in essentiels : file, env, pipe, password, vars, csvfile, ini, dig. Et la nuance importante : un lookup s’exécute côté control node, pas côté managed node.
C’est l’outil de prédilection pour injecter des secrets depuis un coffre local, paramétrer un playbook depuis un fichier de config, ou parser un CSV de hôtes.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- La syntaxe
lookup('plugin', args)et la différence avecquery; - Les lookups built-in essentiels :
file,env,pipe,password,vars; - Que les lookups s’exécutent côté control node (pas managed node) ;
- Combiner plusieurs lookups dans un même template ;
- Cas pratiques : injection de secret, paramétrage CI/CD, génération de mot de passe.
Prérequis
Section intitulée « Prérequis »- Avoir lu Variables — déclaration ;
- Avoir manipulé des templates Jinja2 (
{{ var }}dans uncopy: content:).
La syntaxe lookup
Section intitulée « La syntaxe lookup »{{ lookup('plugin_name', 'arg1', 'arg2', option=value) }}Le plugin_name identifie le lookup, suivi des arguments propres au plugin. Quelques plugins essentiels :
| Plugin | Rôle | Exemple |
|---|---|---|
file | Lit le contenu d’un fichier local | lookup('file', 'files/secret.txt') |
env | Variable d’environnement du shell qui a lancé Ansible | lookup('env', 'USER') |
pipe | Exécute une commande locale et retourne stdout | lookup('pipe', 'date +%Y-%m-%d') |
password | Génère et stocke un mot de passe | lookup('password', '/tmp/.pass length=20') |
vars | Lit une variable Ansible existante (utile en boucle) | lookup('vars', 'app_' + env) |
csvfile | Cherche une ligne dans un CSV | lookup('csvfile', 'web1 file=hosts.csv col=2') |
ini | Lit une clé d’un fichier INI | lookup('ini', 'name section=Owner file=app.ini') |
dig | Résolution DNS | lookup('dig', 'web1.lab') |
hashi_vault | HashiCorp Vault | lookup('community.hashi_vault.vault_kv2_get', 'secret/data/api') |
L’exécution côté control node
Section intitulée « L’exécution côté control node »Point crucial : un lookup s’exécute côté control node (votre poste), pas côté managed node. Conséquences :
lookup('file', 'foo.txt')litfoo.txtsur votre poste ;lookup('env', 'USER')lit$USERdu shell qui a lancéansible-playbook;lookup('pipe', 'hostname -s')retourne le hostname du control node, pas du managed node.
C’est par dessein : un lookup sert souvent à injecter une donnée du dépôt ou de l’environnement de CI/CD dans le playbook.
Cas pratique — combinaison de 3 lookups (lab ecrire-code/lookups)
Section intitulée « Cas pratique — combinaison de 3 lookups (lab ecrire-code/lookups) »Voici l’exemple validé sur le lab 17-ecrire-code-lookups :
---- name: Challenge lookups hosts: db1.lab become: true
tasks: - name: Poser un fichier qui combine 3 lookups ansible.builtin.copy: dest: /tmp/lookups-challenge.txt content: | token={{ lookup('file', 'files/api-token.txt') }} home={{ lookup('env', 'HOME') }} host_local={{ lookup('pipe', 'hostname -s') }} mode: "0644"Avec files/api-token.txt côté control node contenant MAGIC-TOKEN-RHCE-2026 :
Contenu de /tmp/lookups-challenge.txt sur db1.lab :
token=MAGIC-TOKEN-RHCE-2026home=/home/bobhost_local=master1Tous les lookups ont été résolus côté control node (votre poste), puis le copy: a transféré le contenu vers db1.
lookup vs query
Section intitulée « lookup vs query »query est strictement équivalent à lookup mais retourne toujours une liste :
{{ lookup('file', 'a.txt') }} ← retourne le contenu (string ou liste selon plugin){{ query('file', 'a.txt') }} ← retourne TOUJOURS une listeUtile dans une boucle :
- name: Itérer sur les fichiers ansible.builtin.debug: msg: "{{ item }}" loop: "{{ query('fileglob', 'files/*.txt') }}"fileglob ne renvoie pas une seule entrée mais une liste de fichiers matchant le glob — query ou lookup retournent tous deux ici une liste.
Règle pratique : query quand vous itérez (loop:), lookup quand vous interpolez une seule valeur.
Lookups essentiels en détail
Section intitulée « Lookups essentiels en détail »file — contenu d’un fichier local
Section intitulée « file — contenu d’un fichier local »- name: Distribuer un certificat depuis le control node ansible.builtin.copy: dest: /etc/ssl/cert.pem content: "{{ lookup('file', 'files/ca-bundle.pem') }}" mode: "0644"Le fichier files/ca-bundle.pem est lu localement ; son contenu est posé côté managed node.
env — variable d’environnement
Section intitulée « env — variable d’environnement »- name: Tag de release fourni par CI ansible.builtin.debug: msg: "Tag : {{ lookup('env', 'CI_COMMIT_TAG') }}"Lit $CI_COMMIT_TAG du shell. Très utilisé en CI/CD.
pipe — sortie de commande locale
Section intitulée « pipe — sortie de commande locale »- name: Récupérer la version Git du repo ansible.builtin.set_fact: git_version: "{{ lookup('pipe', 'git -C ' + playbook_dir + ' rev-parse HEAD') }}"Exécute git rev-parse HEAD côté control node et capture la sortie.
password — générer + stocker un mot de passe
Section intitulée « password — générer + stocker un mot de passe »- name: Mot de passe d'un user PostgreSQL ansible.builtin.user: name: appuser password: "{{ lookup('password', '/srv/secrets/appuser.pwd length=24 chars=ascii_letters,digits') }}"Le lookup génère un mot de passe aléatoire la première fois, le stocke dans /srv/secrets/appuser.pwd côté control node, et le retourne à chaque appel suivant. Idempotent — tant que le fichier existe, le mot de passe ne change pas.
Caractères supportés : ascii_letters, digits, punctuation, ou un set custom.
vars — variable Ansible existante
Section intitulée « vars — variable Ansible existante »Utile pour construire dynamiquement le nom d’une variable :
vars: app_dev: { port: 8000 } app_prod: { port: 80 }
tasks: - name: Récupérer la conf dynamiquement ansible.builtin.debug: msg: "{{ lookup('vars', 'app_' + env).port }}"Avec env=prod, vous lisez app_prod.port.
hashi_vault — secrets HashiCorp Vault
Section intitulée « hashi_vault — secrets HashiCorp Vault »- name: Lire un secret depuis Vault ansible.builtin.set_fact: api_key: "{{ lookup('community.hashi_vault.vault_kv2_get', 'secret/data/api', url='https://vault.example.com').data.data.api_key }}"Demande la collection community.hashi_vault (ansible-galaxy collection install community.hashi_vault).
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
lookup('file', ...) retourne FileNotFoundError | Fichier introuvable depuis le cwd du playbook | Utiliser un path absolu ou playbook_dir + '/files/...' |
lookup('env', 'X') retourne '' | Variable non posée dans le shell qui a lancé ansible-playbook | Ajouter default('') : `lookup(‘env’, ‘X’) |
lookup('pipe', '...') plante | La commande ne s’exécute pas (erreur shell, binaire absent) | Tester la commande à la main d’abord ; ajouter 2>/dev/null |
| Lookup re-exécuté à chaque task | C’est le comportement par défaut | Capturer dans set_fact une fois, réutiliser |
| Performance : 1000 lookups dans un loop | Exécutés à chaque itération côté control | Pré-charger via set_fact ou vars_files |
À retenir
Section intitulée « À retenir »lookup('plugin', args)= récupération depuis une source externe, exécutée côté control node.- Plugins essentiels :
file,env,pipe,password,vars,csvfile,hashi_vault. queryretourne toujours une liste — préférer pour les boucles.- Un lookup ne sait rien des managed nodes — pour lire un fichier distant, utiliser
slurpoucommand: cat. lookup('password', ...)est idempotent : il génère puis réutilise le mot de passe stocké.
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/ecrire-code/lookups/ dans
stephrobert/ansible-training. Il contient
un README.md guidé, un Makefile (make verify lance les tests), et un
challenge final auto-évalué : combiner 3 lookups (file, env, pipe) pour générer un fichier marqueur côté managed node.
Une fois le lab provisionné :
cd ~/Projets/ansible-training/labs/ecrire-code/lookups/
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).