Aller au contenu
Infrastructure as Code medium

Conditions Ansible (when) : opérateurs, multi-conditions, tests Jinja

60 min de lecture

Logo Ansible

when: est la directive Ansible qui conditionne l'exécution d'une tâche, d'un block ou d'un rôle sur une expression Jinja2. Si l'expression est vraie, la tâche s'exécute ; sinon elle est marquée skipped dans le PLAY RECAP. Cette page couvre la syntaxe correcte (sans {{ }} ni quotes), les opérateurs de comparaison, les multi-conditions via liste (and implicite), les tests Jinja (is defined, is none, is mapping), et les pièges classiques.

C'est la directive la plus utilisée pour adapter un playbook à différentes distributions, environnements ou variables optionnelles.

  • La syntaxe de when:, pas de {{ }}, pas de quotes
  • Les opérateurs de comparaison : ==, !=, >, <, >=, <=, in, not in
  • Multi-conditions via liste (and implicite) ou expression (and, or, not)
  • Les tests Jinja : is defined, is undefined, is none, is mapping, is sequence
  • when: sur un block : applique la condition à toutes les tâches du block
- name: Installer nginx uniquement sur RedHat
ansible.builtin.dnf:
name: nginx
when: ansible_os_family == "RedHat"

3 règles importantes sur when: :

  1. Pas de {{ }} : when: accepte directement une expression Jinja, pas une interpolation.

    when: ansible_os_family == "RedHat" # ✅
    when: "{{ ansible_os_family == 'RedHat' }}" # ❌ erreur, double évaluation
  2. Pas de quotes externes sauf si l'expression contient des caractères ambigus :

    when: var == 1 # ✅
    when: "var == 1" # ✅ aussi OK
    when: var: var == 1 # ❌ deux-points cassent le YAML
  3. Une string non vide est truthy : when: my_var est vrai si my_var est défini ET non vide/zéro/false.

when: ansible_distribution == "AlmaLinux"
when: ansible_distribution != "Ubuntu"
when: ansible_distribution_major_version | int >= 10
when: ansible_memtotal_mb < 2048
when: "'docker' in ansible_facts.packages"
when: env not in ["dev", "staging"]

Le filtre | int ou | float est nécessaire quand le fact est une string (la plupart des ansible_*_version sont des strings).

Quand vous avez plusieurs conditions à combiner avec and (cas le plus fréquent), passez une liste :

when:
- ansible_distribution == "AlmaLinux"
- ansible_distribution_major_version | int >= 10
- ansible_memtotal_mb >= 1024

Toutes les conditions doivent être vraies pour que la tâche s'exécute. C'est plus lisible qu'une longue expression and.

Pour or ou des combinaisons mixtes, écrivez l'expression complète sur une ligne :

when: ansible_distribution == "AlmaLinux" or ansible_distribution == "RHEL"
when: (env == "prod" and not maintenance_mode) or force_run | default(false)

Les tests Jinja sont écrits avec is :

TestVrai si...
var is definedLa variable existe
var is undefinedElle n'existe pas
var is noneElle est None/null
var is mappingC'est un dict
var is sequenceC'est une liste
var is iterableItérable (liste, dict, string)
var is stringC'est une string
var is numberC'est un nombre
var is regexC'est un objet regex

Cas typique, variable optionnelle :

- name: Activer une feature optionnelle
ansible.builtin.copy:
dest: /tmp/feature.txt
content: "feature ON\n"
mode: "0644"
when:
- enable_feature is defined
- enable_feature | bool

enable_feature is defined évite l'erreur "undefined variable" ; | bool convertit 'true'/'1'/'yes' en vrai booléen.

- name: Installer et démarrer le service sur les distributions RedHat
when: ansible_os_family == "RedHat"
block:
- name: Tâche A (RedHat only)
ansible.builtin.dnf:
name: foo
- name: Tâche B (RedHat only)
ansible.builtin.systemd:
name: foo
state: started

Le when: sur le block est propagé à toutes les tâches du block. Plus DRY que de répéter le when: sur chacune.

Voici l'exemple validé sur le lab ecrire-code-conditions-when :

---
- name: Challenge conditions when
hosts: db1.lab
become: true
gather_facts: true
tasks:
- name: cond-redhat
ansible.builtin.copy:
dest: /tmp/cond-redhat.txt
content: "famille=redhat\n"
mode: "0644"
when: ansible_os_family == "RedHat"
- name: cond-alma10
ansible.builtin.copy:
dest: /tmp/cond-alma10.txt
content: "os=AlmaLinux10\n"
mode: "0644"
when:
- ansible_distribution == "AlmaLinux"
- ansible_distribution_major_version | int >= 10
- name: cond-feature
ansible.builtin.copy:
dest: /tmp/cond-feature.txt
content: "feature=enabled\n"
mode: "0644"
when:
- enable_feature is defined
- enable_feature | bool
- name: cond-debian (NE doit PAS s'exécuter sur AlmaLinux)
ansible.builtin.copy:
dest: /tmp/cond-debian.txt
content: "famille=debian\n"
mode: "0644"
when: ansible_os_family == "Debian"

Lancement avec --extra-vars "enable_feature=true" :

PLAY RECAP
db1.lab : ok=4 changed=3 skipped=1 failed=0

3 fichiers posés (redhat, alma10, feature), 1 task skipped (debian).

when: est évalué à chaque itération de la boucle :

- name: Installer uniquement les paquets activés
ansible.builtin.dnf:
name: "{{ item.name }}"
state: present
loop:
- { name: nginx, enabled: true }
- { name: redis, enabled: false }
- { name: postgresql, enabled: true }
when: item.enabled

redis est skippé pour cette itération uniquement ; les deux autres sont installés.

SymptômeCauseFix
when: "&#123;&#123; var == 'x' &#125;&#125;" ne fonctionne pasDouble évaluation JinjaRetirer &#123;&#123; &#125;&#125; : when: var == 'x'
Expression compare une string et un int incorrectlyType mismatchFiltre | int ou | string selon besoin
when: sur une variable absente planteVariable undefinedPréfixer par var is defined and ...
when: var est faux alors que var: "yes"'yes' est une string non vide donc truthy, mais YAML 1.2 ne convertit pasUtiliser | bool : when: var | bool
not item.enabled fait planter quand enabled est absentAccès à clé inexistanteUtiliser not item.enabled | default(false)
  • when: prend une expression Jinja sans {{ }} ni quotes externes.
  • Multi-conditions and : passer une liste, plus lisible qu'une expression longue.
  • is defined + | bool sont les deux outils pour gérer les variables optionnelles proprement.
  • when: sur un block propage la condition à toutes les tâches enfants.
  • Combiné avec loop:, when: est évalué à chaque itération.

Une condition fausse ne se voit pas dans le code, elle se voit dans le PLAY RECAP. Le lab vous fait conditionner des tâches sur un fact collecté, combiner plusieurs critères dans une liste, tester la présence d'une variable optionnelle avec is defined, et diagnostiquer un when: qui matche à tort. La validation porte sur les tâches réellement passées en skipped, pas sur l'expression écrite.

  • Block / rescue / always : une condition posée sur un block s'applique à toutes ses tâches, c'est la façon la plus économique de conditionner un groupe.
  • failed_when et changed_when : la même syntaxe d'expression sert à redéfinir le succès et le changement d'une tâche.
  • Tests Jinja2 : le catalogue complet des tests is defined, is none ou is mapping qui alimentent vos conditions.

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