
Les filtres Jinja2 transforment une valeur via la syntaxe {{ valeur | filtre }} — c’est le levier principal pour générer un fichier de config, fusionner deux sources, filtrer une liste ou nettoyer une string. Ansible expose les filtres standard Jinja2 + ses propres filtres custom (combine, selectattr étendu, dict2items…). Cette page liste les 10 filtres essentiels de la RHCE EX294 avec un exemple concret pour chacun.
C’est une page de référence : on revient la consulter quand on a besoin de transformer une variable et qu’on cherche le filtre adapté.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Le filtre
defaultpour les variables optionnelles regex_replacepour transformer une string par regexto_json,to_yaml,to_nice_yamlpour la sérialisationdict2itemsetitems2dictpour boucler sur des dictscombinepour fusionner deux dictionnairesselectattr+map(attribute='name')pour filtrer une liste de dictsunique,union,difference,intersectpour les opérations d’ensemblelength,min,max,sumpour les agrégatsupper,lower,title,trimpour les transformations de strings
Prérequis
Section intitulée « Prérequis »- Avoir lu les pages précédentes de la sous-section Variables et facts ;
- Connaître la syntaxe Jinja2 de base (
{{ }},{% %}).
Le top 10 RHCE
Section intitulée « Le top 10 RHCE »1. default — valeur de fallback
Section intitulée « 1. default — valeur de fallback »{{ undefined_var | default('fallback') }}Si la variable est absente ou None, retourne 'fallback'. Plusieurs variantes :
{{ var | default('fallback', true) }} ← fallback aussi si var est falsy ('', 0, [], {}){{ var | default(omit) }} ← omet le paramètre si var absente (Ansible spécifique)omit est ultra-utile pour conditionner un argument de module :
- name: Créer un user (sans password si var absente) ansible.builtin.user: name: "{{ user_name }}" password: "{{ user_password | default(omit) }}"2. regex_replace — transformation par regex
Section intitulée « 2. regex_replace — transformation par regex »{{ 'foo-bar-baz' | regex_replace('-', '_') }}Sortie : foo_bar_baz. Avec groupes de capture :
{{ 'web1.lab' | regex_replace('^(\w+)(\d+)\.(\w+)$', '\\1_\\2_\\3') }}Sortie : web_1_lab (les \1, \2, \3 sont les groupes capturés).
3. to_json / to_yaml / to_nice_yaml
Section intitulée « 3. to_json / to_yaml / to_nice_yaml »Sérialisation d’une variable structurée :
{{ my_dict | to_json }} ← JSON compact{{ my_dict | to_nice_json(indent=2) }} ← JSON indenté{{ my_dict | to_yaml }} ← YAML{{ my_dict | to_nice_yaml(indent=2) }} ← YAML indentéCas pratique : poser un fichier JSON à partir d’un dict Ansible :
- name: Poser un config JSON ansible.builtin.copy: dest: /etc/app/config.json content: "{{ app_config | to_nice_json(indent=2) }}"4. dict2items / items2dict
Section intitulée « 4. dict2items / items2dict »dict2items convertit un dict en liste de {key, value} (utile pour boucler) :
vars: ports: nginx: 80 redis: 6379
tasks: - name: Itérer sur le dict ansible.builtin.debug: msg: "{{ item.key }} : {{ item.value }}" loop: "{{ ports | dict2items }}"items2dict fait l’inverse — utile quand vous avez une liste de paires que vous voulez transformer en dict :
{{ [{key: 'a', value: 1}, {key: 'b', value: 2}] | items2dict }}Sortie : {'a': 1, 'b': 2}.
5. combine — fusion de dicts
Section intitulée « 5. combine — fusion de dicts »{{ {a: 1, b: 2} | combine({b: 99, c: 3}) }}Sortie : {'a': 1, 'b': 99, 'c': 3}. Le second dict gagne sur le premier en cas de conflit.
Pour une fusion récursive (nested) :
{{ defaults | combine(overrides, recursive=true) }}Pattern classique : merger des defaults avec un overrides de l’environnement.
6. selectattr — filtrer une liste de dicts
Section intitulée « 6. selectattr — filtrer une liste de dicts »{{ services | selectattr('env', 'equalto', 'prod') | list }}Garde uniquement les éléments dont la clé env vaut 'prod'. Tests disponibles : equalto, defined, undefined, match (regex), search (regex), in, gt, lt.
{{ users | selectattr('age', 'gt', 18) | list }} ← users majeurs{{ services | rejectattr('disabled') | list }} ← services non disabled7. map(attribute='name') — extraire un champ
Section intitulée « 7. map(attribute='name') — extraire un champ »{{ services | map(attribute='name') | list }}Sortie : liste des noms des services. Combiné avec selectattr :
{{ services | selectattr('env', 'equalto', 'prod') | map(attribute='name') | list }}Liste des noms des services prod.
8. unique, union, difference, intersect
Section intitulée « 8. unique, union, difference, intersect »Opérations d’ensemble :
{{ ['a', 'b', 'a', 'c'] | unique }} ← ['a', 'b', 'c']{{ ['a', 'b'] | union(['b', 'c']) }} ← ['a', 'b', 'c']{{ ['a', 'b', 'c'] | difference(['b']) }} ← ['a', 'c']{{ ['a', 'b'] | intersect(['b', 'c']) }} ← ['b']Ne fonctionnent que sur des listes. Pour un dict, passez par keys() ou values().
9. length, min, max, sum
Section intitulée « 9. length, min, max, sum »Agrégats :
{{ groups['webservers'] | length }} ← nombre de webservers{{ [10, 20, 5] | min }} ← 5{{ [10, 20, 5] | max }} ← 20{{ [10, 20, 5] | sum }} ← 3510. upper, lower, title, trim, replace
Section intitulée « 10. upper, lower, title, trim, replace »Transformations de strings :
{{ 'hello' | upper }} ← HELLO{{ 'HELLO' | lower }} ← hello{{ 'hello world' | title }} ← Hello World{{ ' hello ' | trim }} ← 'hello'{{ 'foo-bar' | replace('-', '_') }} ← foo_barCas pratique — combinaison de 6 filtres (lab ecrire-code/filtres-jinja-essentiels)
Section intitulée « Cas pratique — combinaison de 6 filtres (lab ecrire-code/filtres-jinja-essentiels) »Voici l’exemple validé sur le lab 18-ecrire-code-filtres-jinja-essentiels :
vars: raw_input: " HELLO World " pkgs_a: ["nginx", "redis", "postgres"] pkgs_b: ["redis", "memcached"] services: - { name: api, port: 8080, env: prod } - { name: web, port: 80, env: staging } - { name: cache, port: 6379, env: prod } base_config: { app: api, port: 80 } tls_overrides: { port: 443, tls: true }
tasks: - name: Poser un fichier qui combine 6 filtres ansible.builtin.copy: dest: /tmp/filtres-result.txt content: | trimmed={{ raw_input | trim | lower }} union={{ (pkgs_a + pkgs_b) | unique | sort | join(',') }} prod_services={{ services | selectattr('env', 'equalto', 'prod') | map(attribute='name') | sort | join(',') }} merged={{ (base_config | combine(tls_overrides)).items() | map('join', '=') | sort | join(' ') }} default_value={{ undefined_var | default('fallback-OK') }} yaml_safe={{ {'hello': 'world'} | to_yaml | trim }} mode: "0644"Contenu posé sur db1.lab :
trimmed=hello worldunion=memcached,nginx,postgres,redisprod_services=api,cachemerged=app=api port=443 tls=Truedefault_value=fallback-OKyaml_safe="hello: world"6 filtres en action : trim | lower, unique | sort | join, selectattr | map | sort | join, combine + items + map | sort | join, default, to_yaml | trim.
Filtres souvent utilisés mais avancés
Section intitulée « Filtres souvent utilisés mais avancés »| Filtre | Usage |
|---|---|
flatten(levels=N) | Aplatit une liste de listes |
random | Élément aléatoire d’une liste |
shuffle | Mélange une liste |
dict_diff(other) | Différence entre deux dicts |
bool | Convertit en booléen ('yes' | bool → true) |
int, float, string | Conversions de type |
b64encode / b64decode | Base64 |
hash('sha256') | Hashage |
password_hash('sha512') | Hash compatible /etc/shadow |
regex_findall(pattern) | Toutes les occurrences regex |
community.general.json_query(...) | JMESPath sur des structures complexes |
Pièges fréquents
Section intitulée « Pièges fréquents »| Symptôme | Cause | Fix |
|---|---|---|
'list' object is not callable | Oubli des parenthèses sur length | var | length (pas var | length()) |
default retourne quand même la variable | La var existe mais est vide ('') | Ajouter le true : var | default('x', true) |
combine ne fusionne pas en profondeur | Mode non récursif par défaut | Ajouter recursive=true |
selectattr retourne tout | Mauvais test : utiliser 'equalto', pas '==' | selectattr('env', 'equalto', 'prod') |
to_yaml produit du !!set ou des balises bizarres | Variable contient des objets non standards | Préférer to_nice_yaml ou caster en dict standard |
À retenir
Section intitulée « À retenir »default('x')= fallback ;default('x', true)= aussi pour valeur vide ;default(omit)= omet le paramètre.regex_replace('pattern', '\\1')= transformation regex avec groupes de capture.combine(dict, recursive=true)= fusion de dicts (récursive si demandé).selectattr('attr', 'equalto', 'value')+map(attribute='name')= pattern central pour filtrer/extraire.dict2items= transforme dict en liste de{key, value}pour boucler.unique | sort | join(',')= chaîne classique pour produire une string déterministe.
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/ecrire-code/filtres-jinja-essentiels/ dans
stephrobert/ansible-training. Il contient
un README.md guidé, un Makefile (make verify lance les tests), et un
challenge final auto-évalué : appliquer 6 filtres dans un fichier marqueur : trim/lower, unique, selectattr, combine, default.
Une fois le lab provisionné :
cd ~/Projets/ansible-training/labs/ecrire-code/filtres-jinja-essentiels/
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).