Cette page condense en une seule lecture tout ce qu’il faut avoir en tête le jour de l’EX294. Commandes ansible-*, modules essentiels par catégorie, ansible.cfg minimal, syntaxes Vault , FQCN, pièges YAML qui font perdre des points. À lire la veille de l’examen et à garder ouverte pendant les mocks (lab rhce/mock-ex294 ).
L’EX294 est performance-based : aucun QCM, vous écrivez des playbooks sur un environnement RHEL/AlmaLinux live. Le score se calcule sur des objectifs vérifiés automatiquement . Un playbook qui ne passe pas l’objectif = 0 sur cet objectif. Pas de point partiel.
Besoin Commande Tester la connexion Ansible ansible all -m ansible.builtin.pingLister inventaire ansible-inventory --graphVoir variables d’un host ansible-inventory --host db1.labDoc d’un module ansible-doc ansible.builtin.copyLister tous les modules d’une collection ansible-doc -l community.generalLancer un playbook ansible-playbook -i inventory.yml site.ymlMode dry-run ansible-playbook --check --diff site.ymlLimiter à un host ansible-playbook --limit web1.lab site.ymlFiltrer par tags ansible-playbook --tags config site.ymlVault encrypt fichier ansible-vault encrypt secret.ymlVault encrypt variable inline ansible-vault encrypt_string 'value' --name 'key'Vault edit ansible-vault edit secret.ymlVault rekey ansible-vault rekey secret.ymlLancer playbook avec vault ansible-playbook --vault-password-file=.vault_pass site.ymlInspecter config active ansible-config dump --only-changedLister tâches sans exécuter ansible-playbook --list-tasks site.ymlLister hosts ciblés ansible-playbook --list-hosts site.ymlLint qualité production ansible-lint --profile production site.ymlInstaller collection ansible-galaxy collection install -r requirements.ymlInstaller rôle Galaxy ansible-galaxy role install geerlingguy.docker
inventory = inventory/hosts.yml
host_key_checking = False
collections_path = ./collections
deprecation_warnings = False
À placer dans le répertoire de travail au début de l’examen — précédence locale > home > /etc.
Module Usage type ansible.builtin.copyDéposer un fichier (avec content: ou src:) ansible.builtin.templateDéposer fichier paramétré Jinja2 (src: file.j2) ansible.builtin.fileÉtat d’un fichier/dossier (state: directory|absent|touch) ansible.builtin.lineinfileUne seule ligne dans un fichier (regexp: obligatoire) ansible.builtin.blockinfileBloc de lignes (marker: configurable) ansible.builtin.fetchRécupérer un fichier de la cible vers le control node community.general.archive / ansible.builtin.unarchivetar .gz, zip
Module Usage ansible.builtin.dnfRHEL/AlmaLinux paquets (name:, state: present|latest|absent) ansible.builtin.systemd_serviceActiver + démarrer (state: started, enabled: true) ansible.builtin.cronTâche planifiée
Module Usage ansible.builtin.userCréer user (name:, uid:, group:, shell:, password:) ansible.builtin.groupCréer group (name:, gid:) ansible.posix.authorized_keyDéposer clé SSH (user:, key:) community.general.sudoersRègle sudo dédiée
Module Usage ansible.posix.firewalldpermanent: true, immediate: trueansible.posix.sebooleanActiver un booléen SELinux (state: true, persistent: true) ansible.builtin.sefcontext (community.general)Contexte SELinux community.general.lvolCréer un LV community.general.filesystemFormater (xfs, ext4) ansible.posix.mountMonter + fstab
Module Usage ansible.builtin.command / shellCommandes (changed_when: false pour lecture) ansible.builtin.assertVérification d’une condition ansible.builtin.failÉchec explicite ansible.builtin.debugAffichage de variables (var: ou msg:) ansible.builtin.uriHTTP request ansible.builtin.wait_forAttendre un port / état
mode : " 0644 " # ← TOUJOURS quoté (sinon octal interprété en décimal → 420)
become : true # ← niveau play : toutes les tâches en sudo
become_user : appuser # ← override niveau task
- ansible.builtin.command : curl --version
changed_when : false # ← lecture seule, pas idempotent
- { name : alice , uid : 2001 }
- { name : bob , uid : 2002 }
label : " {{ item.name }} " # ← masque le contenu détaillé en sortie
- ansible_facts.os_family == "RedHat"
- ansible_facts.distribution_major_version | int >= 9
- inventory_hostname in groups['webservers']
ansible-vault encrypt_string ' SuperSecret ' --name ' admin_password '
$ANSIBLE_VAULT;1.1;AES256
39373335366336323033666336323535...
ansible-playbook --vault-id dev@.vault_pass_dev --vault-id prod@.vault_pass_prod site.yml
--extra-vars (CLI) — prioritaire absolue
Block vars
Task vars
include_vars
set_fact / registered vars
Play vars (vars:)
vars/main.yml d’un rôle
Host facts
host_vars/
group_vars/ (du plus spécifique au plus général)
defaults/main.yml d’un rôle — prioritaire la plus basse
Command line role default
🔍 Mémoire pratique : --extra-vars écrase tout le reste. defaults/main.yml se fait écraser par tout le reste.
├── defaults/main.yml # variables par défaut (faible précédence)
├── vars/main.yml # variables internes (haute précédence)
├── tasks/main.yml # tâches principales
├── handlers/main.yml # handlers (notifiés par notify:)
├── files/ # fichiers à copy:
├── meta/main.yml # dependencies, supported_platforms
└── meta/argument_specs.yml # validation des inputs (Ansible 2.11+)
Erreur Conséquence mode: 0644 (non quoté)YAML lit octal → décimal 420 → mode 0644 peut devenir 0644 dans certains parseurs ; toujours mode: "0644" name: Migration with_* vers loop: (terminé par :)YAML 1.2 lit comme mapping. Quoter : name: "..." dnf: state=present name=httpd (vieux style)Toujours YAML structuré : dnf: { state: present, name: httpd } ou multi-ligne Oublier permanent: true sur firewalld Règle non persistante après reboot — permanent: true, immediate: true systématique Oublier python3-libselinux côté cible template:/copy: plantent si SELinux=enforcingname: Démarrer httpd: finit par :YAML mapping — quoter Confondre import_* (static) et include_* (dynamic) Tags/conditions ne se propagent pas pareillement — voir Import vs Include
Étape Temps Action Lecture des consignes 5-10 min Lire les 12-15 tâches en entier avant d’écrire une ligneSetup ansible.cfg + inventaire 5-10 min Poser le ansible.cfg minimal + tester ansible all -m ping Tâches faciles 1h Faire les 8-9 tâches simples d’abord (validation rapide) Tâches complexes 1h30 Rôles, Vault, SELinux, LVM/XFS — les plus longues Vérification 30 min Re-lancer chaque playbook, vérifier l’idempotence (changed=0 au 2e run)Buffer 30 min Marge pour les pièges de dernière minute
🔍 Règle d’or : vérifier au fur et à mesure . Ne pas attendre la fin pour relancer tous les playbooks — un bug détecté à la 4e heure coûte 30 min de panique.
ansible-playbook playbook.yml # 1er run
ansible-playbook playbook.yml | grep -E ' changed=[1-9] ' # 2e run : doit être vide
# Vérifier qu'un service est bien actif après reboot
ansible <host> -m ansible.builtin.systemd_service -a ' name=httpd ' -b
# → "ActiveState": "active"
# → "UnitFileState": "enabled"
# Vérifier un fichier déposé
ansible <host> -m ansible.builtin.stat -a ' path=/tmp/file.txt ' -b
ansible <host> -m ansible.builtin.command -a ' id appuser ' -b
ansible-doc <module> — la doc complète est embarquée dans l’EE de l’examen.
ansible-doc -l | grep <mot> — retrouver le FQCN d’un module par mot-clé.
man ansible-playbook — options CLI rapides.
/usr/share/doc/ansible*/ — docs locales sur RHEL.
L’examen vous autorise la documentation locale (ansible-doc, man). Aucun accès internet .
Performance-based : on écrit des playbooks. Pas de QCM.
ansible.cfg projet en premier — précédence locale > home > /etc.
FQCN systématique : ansible.builtin.copy, jamais copy.
mode: toujours quoté ("0644").
changed_when: false sur toute commande de lecture.
firewalld : permanent: true, immediate: true.
python3-libselinux côté cible si SELinux enforcing.
Vérifier l’idempotence : 2e run doit avoir changed=0.
ansible-doc est votre meilleur ami pendant l’examen.