Aller au contenu
Infrastructure as Code medium

Modules assert et fail Ansible : validation défensive

65 min de lecture

Logo Ansible

Deux modules complémentaires pour la programmation défensive en Ansible :

  • ansible.builtin.assert: valide une condition ; si elle est fausse, le play échoue avec un message clair. Pattern de précondition en début de play.
  • ansible.builtin.fail: échoue explicitement avec un message custom. Pattern de branche d'erreur dans une logique conditionnelle.

Différence sémantique : assert: exprime "ça doit être vrai" ; fail: exprime "j'arrête maintenant parce que telle condition est rencontrée".

  • Valider des prérequis en début de play avec assert:.
  • Personnaliser les messages avec fail_msg: / success_msg:.
  • Échouer explicitement avec fail: + when: (branche d'erreur).
  • Combiner assert: avec tests Jinja2 (is defined, is integer).
  • Choisir entre assert:, fail:, et failed_when: selon le contexte.
  • Connaître les tests Jinja2 (cf. Lab 28).
- name: Valider que app_port est dans la plage non-privilegiee
ansible.builtin.assert:
that:
- app_port is defined
- app_port is integer
- app_port > 1024
- app_port < 65535
fail_msg: "app_port doit etre un entier entre 1024 et 65535 (recu : {{ app_port | default('absent') }})"
success_msg: "Validation OK : app_port = {{ app_port }}"

Comportement :

  • Si toutes les conditions sont vraies → success_msg affiché, play continue.
  • Si une condition échouefail_msg affiché, play failed.

that: accepte une liste de conditions = AND implicite.

- name: Detecter un environnement non supporte
ansible.builtin.fail:
msg: |
Environnement non supporte :
- OS : {{ ansible_distribution }}
- Version : {{ ansible_distribution_version }}
Ce playbook necessite RHEL/AlmaLinux 9+.
when: ansible_distribution not in ['AlmaLinux', 'RedHat', 'Rocky']
or ansible_distribution_major_version | int < 9

fail: est une tâche qui échoue toujours quand elle s'exécute. when: la conditionne.

# Equivalent fonctionnel
- name: Vérifier les prérequis
ansible.builtin.assert:
that: ansible_distribution_major_version | int >= 9
fail_msg: "RHEL 9+ requis"
- name: Interrompre avec un message explicite
ansible.builtin.fail:
msg: "RHEL 9+ requis"
when: ansible_distribution_major_version | int < 9

Préférer assert: quand la condition est positive ("ça doit être vrai"). Préférer fail: quand la logique est branche d'erreur explicite ("si l'OS est X, on ne supporte pas").

- name: Deploy myapp
hosts: webservers
become: true
pre_tasks:
- name: Pre-requis - OS
ansible.builtin.assert:
that:
- ansible_distribution in ['AlmaLinux', 'RedHat', 'Rocky']
- ansible_distribution_major_version | int >= 9
fail_msg: "OS non supporte"
- name: Collecter la liste des paquets installes
ansible.builtin.package_facts:
- name: Pre-requis - paquets installes
ansible.builtin.assert:
that:
- "'chrony' in ansible_facts.packages"
- "'firewalld' in ansible_facts.packages"
fail_msg: "chrony et firewalld doivent etre installes"
- name: Pre-requis - port libre
ansible.builtin.wait_for:
port: 8080
state: stopped
timeout: 5
tasks:
# ... vraies taches de deploy

pre_tasks: est la section dédiée aux préconditions. Si une assert: failed dedans, les tasks: ne tournent pas. Pattern fail-fast propre.

- name: Valider la structure d une variable complexe
vars:
db_config:
host: db1.lab
port: 5432
pool_size: 10
ansible.builtin.assert:
that:
- db_config is defined
- db_config is mapping # est un dict
- db_config.host is defined
- db_config.host is string
- db_config.port is defined
- db_config.port is integer
- db_config.port > 0
- db_config.port < 65536
- db_config.pool_size is integer
- db_config.pool_size > 0
fail_msg: "Structure de db_config invalide"

Pattern schema validation à la main. Pour des cas complexes, on combine plusieurs tests (is defined, is mapping, is integer).

- name: Capturer le rc de openssl
ansible.builtin.command: openssl version
register: openssl_check
changed_when: false
failed_when: false # Capturer meme en cas d echec
- name: Valider que la version est >= 3
ansible.builtin.assert:
that:
- openssl_check.rc == 0
- openssl_check.stdout is search('OpenSSL 3\\.')
fail_msg: "OpenSSL 3+ requis (vu : {{ openssl_check.stdout | default('non installe') }})"

Pattern très courant pour valider une version de binaire avant utilisation. Le failed_when: false sur le command: permet à assert: de générer le message d'erreur clair au lieu de l'erreur brute du module.

Sur des dizaines d'assertions, le bruit dans la sortie est gênant. quiet: true affiche uniquement les fail_msg: (pas les success).

- name: 50 validations silencieuses
ansible.builtin.assert:
that:
- ansible_memtotal_mb >= 1024
fail_msg: "Memoire insuffisante"
quiet: true

Sortie console plus lisible sur les playbooks de conformité (CIS Benchmark, audit RGS).

SymptômeCauseFix
Message d'erreur cryptiquePas de fail_msg: personnaliséToujours fournir un fail_msg: clair
Play s'arrête sur la première erreurComportement par défautSi désiré, ajouter ignore_errors: true ou block/rescue
fail: toujours déclenchéOubli du when:fail: sans when: = toujours échoue
Pollution des logs sur 50+ assertsPas de quiet: trueActiver quiet: true
  • assert: that: = liste de conditions, AND implicite.
  • fail_msg: / success_msg: pour personnaliser les messages.
  • fail: = échec explicite, à combiner avec when:.
  • pre_tasks: est la section idiomatique pour les assert: de validation.
  • Préférer assert: pour les préconditions, fail: pour les branches d'erreur.
  • quiet: true pour éviter la pollution sur les playbooks d'audit.

Une validation défensive ne se juge qu'à l'échec qu'elle sait produire. Le lab vous fait poser sur db1.lab un fail: qui écarte tout hôte inattendu, puis une batterie d'assert: sur la distribution, sa version majeure et la mémoire disponible, chacun avec un fail_msg: lisible. Les tests inspectent le fichier témoin écrit une fois les contrôles passés, ce qui prouve que les préconditions ont été franchies dans l'ordre plutôt que contournées.

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