
Au-delà des filtres essentiels (default, combine, selectattr, dict2items...) déjà couverts dans la sous-section Variables et facts, Ansible expose des filtres avancés pour les cas plus pointus. Cette page liste les filtres avancés que vous rencontrerez dans les templates de production : extraction par regex (regex_search, regex_findall), aplatissement de listes nested (flatten), encodages (b64encode, b64decode), hash de mot de passe (password_hash), parsing/sérialisation de YAML (from_yaml, to_nice_yaml), empreintes (hash).
C'est une page de référence : on revient ici quand on cherche un filtre précis pour un besoin spécifique.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »regex_searchetregex_findallpour extraire par regexflattenpour aplatir une liste de listesb64encodeetb64decodepour Base64password_hash('sha512')pour générer un hash compatible/etc/shadowfrom_yaml,to_nice_yamlpour parser/sérialiserhash('sha256')pour calculer une empreinte hex
Prérequis
Section intitulée « Prérequis »- Avoir lu Filtres Jinja2 essentiels ;
- Connaître la syntaxe Jinja2 (cf. Jinja2, syntaxe de base).
regex_search et regex_findall
Section intitulée « regex_search et regex_findall »regex_search('pattern') retourne la première occurrence (ou None) :
{{ 'web1.lab.example.com' | regex_search('^([a-z]+)') }} ← 'web'{{ 'IP : 10.10.20.21' | regex_search('\\d+\\.\\d+\\.\\d+\\.\\d+') }} ← '10.10.20.21'{{ 'rien à matcher' | regex_search('xyz') }} ← '' (chaîne vide)regex_findall('pattern') retourne toutes les occurrences sous forme de liste :
{{ 'a-1, b-2, c-3' | regex_findall('([a-z])-(\\d)') }}← [['a', '1'], ['b', '2'], ['c', '3']]Pour ne capturer qu'un seul groupe :
{{ 'a-1 b-2 c-3' | regex_findall('([a-z])-\\d') }} ← ['a', 'b', 'c']Cas pratique : extraire toutes les IPs d'un fichier de config :
{% set ips = config_text | regex_findall('\\d+\\.\\d+\\.\\d+\\.\\d+') %}Adresses détectées : {{ ips | join(', ') }}flatten, aplatir une liste de listes
Section intitulée « flatten, aplatir une liste de listes »{{ [[1, 2], [3, [4, 5]]] | flatten }} ← [1, 2, 3, 4, 5]{{ [[1, 2], [3, [4, 5]]] | flatten(levels=1) }} ← [1, 2, 3, [4, 5]]Sans levels, récursif (aplatit tous les niveaux). Avec levels=1, un seul niveau.
Cas pratique : agréger les services de plusieurs groupes :
vars: webservers_services: [nginx, php-fpm] dbservers_services: [postgresql, redis] caches_services: [memcached]
template_var: "{{ [webservers_services, dbservers_services, caches_services] | flatten | unique }}"b64encode et b64decode
Section intitulée « b64encode et b64decode »{{ 'admin:secret' | b64encode }} ← 'YWRtaW46c2VjcmV0'{{ 'YWRtaW46c2VjcmV0' | b64decode }} ← 'admin:secret'Cas pratique : générer un header Authorization: Basic ... :
- name: Appel API avec auth basic ansible.builtin.uri: url: https://api.example.com/data headers: Authorization: "Basic {{ (api_user + ':' + api_password) | b64encode }}"password_hash, hash compatible /etc/shadow
Section intitulée « password_hash, hash compatible /etc/shadow »{{ 'mySecretPass' | password_hash('sha512') }}← '$6$xxx$xxxxxxxxxxx...' (hash crypt SHA-512)Avec un salt explicite (idempotent) :
{{ 'mySecretPass' | password_hash('sha512', 'mysalt2024') }}Sans salt explicite, Ansible génère un salt aléatoire à chaque appel, vous obtenez un nouveau hash à chaque run, ce qui casse l'idempotence du module user. Toujours poser un salt fixe en production :
- name: Définir le mot de passe d'un user ansible.builtin.user: name: alice password: "{{ 'mySecretPass' | password_hash('sha512', 'salt-alice-2024') }}"from_yaml et to_nice_yaml
Section intitulée « from_yaml et to_nice_yaml »from_yaml parse une string YAML en objet Python :
{% set parsed = "key: value\nlist:\n - a\n - b" | from_yaml %}{{ parsed.key }} ← 'value'{{ parsed.list | length }} ← 2to_nice_yaml(indent=2) sérialise un dict/liste en YAML lisible :
{{ my_dict | to_nice_yaml(indent=2) }}Cas pratique : poser un fichier YAML à partir d'un dict Ansible :
- name: Poser un manifest Kubernetes ansible.builtin.copy: dest: /etc/k8s/deployment.yml content: "{{ k8s_deployment | to_nice_yaml(indent=2) }}" mode: "0644"hash('sha256'), empreinte hex
Section intitulée « hash('sha256'), empreinte hex »{{ 'foobar' | hash('sha256') }}← 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'Algos supportés : md5, sha1, sha256, sha512. Cas pratique : générer un identifiant déterministe à partir d'une string :
- name: Générer un cache key ansible.builtin.set_fact: cache_key: "{{ (env + '-' + version) | hash('sha256') | truncate(16, true, '') }}"Cas pratique, combinaison de 4 filtres avancés
Section intitulée « Cas pratique, combinaison de 4 filtres avancés »Voici l'exemple validé sur le lab ecrire-code-filtres-jinja-avances :
vars: fqdn: "web1.lab.example.com" secret: "admin:secret" nested: [[1, 2], [3, [4, 5]]] to_hash: "foobar"
tasks: - name: Poser le fichier de résultats ansible.builtin.copy: dest: /tmp/filtres-avances.txt content: | prefix={{ fqdn | regex_search('^([a-z]+)') }} b64={{ secret | b64encode }} flat={{ nested | flatten }} sha256={{ to_hash | hash('sha256') }}Sortie :
prefix=webb64=YWRtaW46c2VjcmV0flat=[1, 2, 3, 4, 5]sha256=c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2Filtres bonus
Section intitulée « Filtres bonus »| Filtre | Usage |
|---|---|
urlsplit('host') | Décompose une URL (https://api.com/foo → 'api.com') |
dict2items / items2dict | Conversion dict ↔ liste de paires |
groupby('attr') | Groupe une liste de dicts par valeur d'une clé |
subelements('key') | Itère sur des sous-éléments d'une liste de dicts |
community.general.json_query('expr') | JMESPath sur des structures complexes |
ipaddr / ipv4 / ipv6 | Manipulations IP ('10.0.0.0/8' | ipaddr('host')) |
random / shuffle | Aléatoire |
truncate(N, end='...') | Tronquer une string |
wordcount / wordwrap(width) | Compter / wrapper des mots |
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
regex_search retourne vide | Regex Python (re module), pas POSIX | Vérifier la syntaxe regex Python |
password_hash change à chaque run | Pas de salt explicite | Ajouter un salt fixe : password_hash('sha512', 'mon_salt') |
flatten retourne des éléments imbriqués | Sans levels, c'est récursif, vérifier que c'est OK | flatten(levels=1) pour 1 seul niveau |
b64encode plante sur des bytes | Le filtre attend une string | Caster d'abord en string |
hash('md5') rejeté en mode FIPS | MD5 désactivé en FIPS | Passer à sha256 ou sha512 |
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »regex_search= première occurrence ;regex_findall= toutes les occurrences.flattenaplatit récursivement par défaut, ou un seul niveau aveclevels=1.b64encode/b64decodepour Base64 (auth headers, transport binaire).password_hash('sha512', 'salt'): toujours un salt explicite pour l'idempotence.from_yamlparse une string YAML,to_nice_yamlsérialise, utile pour les manifests Kubernetes.hash('sha256')= empreinte déterministe de string (cache keys, identifiants).
Mettre en pratique
Section intitulée « Mettre en pratique »Les filtres avancés se valident sur leur sortie exacte, à un caractère près. Le lab vous fait extraire une valeur avec regex_search, encoder en b64encode, hacher un mot de passe en password_hash('sha512') avec un salt fixe, interroger une structure JSON avec json_query et manipuler des CIDR. Le fichier marqueur produit est comparé au résultat attendu, donc un salt oublié se voit immédiatement.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Module template : l'endroit où ces filtres servent vraiment, au moment de générer le fichier sur la cible.
- lineinfile vs template : le critère de choix entre générer un fichier entier et n'en modifier que deux lignes.
- Quiz Écrire du code : trente questions pour vérifier que filtres, précédence et handlers sont réellement acquis.