
Les handlers sont des actions réactives déclenchées uniquement quand une tâche du rôle a fait changed=true et notify: un handler. C’est le pattern standard pour redémarrer un service après modification de sa config sans le redémarrer inutilement à chaque run idempotent.
Cette page démontre 3 handlers dans le rôle webserver (Restart, Reload, Notify deployment), explique la temporalité d’exécution, et enrichit le meta/main.yml pour publication Galaxy.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Écrire des handlers dans
handlers/main.yml. - Connecter les handlers via
notify:dans les tâches. - Comprendre quand les handlers s’exécutent (à la fin du play, sauf
flush_handlers). - Distinguer
RestartvsReload(différent niveau de perturbation). - Enrichir
meta/main.ymlavec galaxy_info, platforms, dependencies, allow_duplicates.
Prérequis
Section intitulée « Prérequis »- Avoir suivi Variables defaults vs vars.
- Comprendre le concept de handlers Ansible.
Le cycle handler — temporalité
Section intitulée « Le cycle handler — temporalité »1. Une tâche fait changed=true2. notify: lui associe un handler3. Ansible enregistre le handler dans une queue4. À la FIN de la section (tasks → post_tasks → roles), tous les handlers notifiés s'exécutent dans l'ordre où ils ont été DÉFINIS (pas notifiés)5. Si plusieurs notifs sur le même handler → exécuté UNE FOISConséquence : modifier 5 fichiers nginx déclenche Reload nginx une seule fois, pas 5. C’est exactement le comportement attendu.
Étape 1 — Définir les handlers
Section intitulée « Étape 1 — Définir les handlers »# handlers/main.yml — 3 handlers du rôle webserver---- name: Restart nginx ansible.builtin.systemd_service: name: "{{ webserver_package }}" state: restarted
- name: Reload nginx ansible.builtin.systemd_service: name: "{{ webserver_package }}" state: reloaded
- name: Notify deployment ansible.builtin.copy: dest: /var/log/deploy-notification.log content: | Deployment completed: {{ ansible_date_time.iso8601 }} Host: {{ inventory_hostname }} Webserver port: {{ webserver_listen_port }} mode: "0644"3 handlers nommés explicitement (verbe d’action). Le nom est l’identifiant utilisé par notify:.
Étape 2 — Restart vs Reload — le bon choix
Section intitulée « Étape 2 — Restart vs Reload — le bon choix »| Action | Quand l’utiliser |
|---|---|
state: restarted | Modification du binaire (upgrade nginx) ou modules natifs. Downtime court mais réel. |
state: reloaded | Modification de la config uniquement (nginx.conf, fichiers conf.d/). Pas de downtime — SIGHUP au processus. |
Règle pratique : config change → reloaded. Binaire change → restarted.
Étape 3 — Brancher notify: dans les tâches
Section intitulée « Étape 3 — Brancher notify: dans les tâches »# tasks/main.yml — démontre l'usage de notify---- name: Supprimer la conf par défaut conflictuelle ansible.builtin.file: path: /etc/nginx/conf.d/default.conf state: absent notify: Restart nginx # ← changement structurel → restart
- name: Déployer nginx.conf depuis le template ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: Reload nginx # ← changement de config → reload
- name: Déployer la page d'accueil ansible.builtin.copy: dest: "{{ __webserver_html_dir }}/index.html" content: "{{ webserver_index_content }}\n" # PAS de notify — un changement de page HTML ne nécessite pas de reload nginx
- name: Tracer le déploiement ansible.builtin.copy: dest: /var/log/webserver-deploy.log content: "Deployed at {{ ansible_date_time.iso8601 }}\n" notify: Notify deployment # ← handler custom de notificationNotez : la tâche « Déployer la page d’accueil » n’a pas de notify:. Modifier une page HTML statique ne nécessite aucun redémarrage nginx — éviter les notifs inutiles.
Étape 4 — meta/main.yml enrichi
Section intitulée « Étape 4 — meta/main.yml enrichi »# meta/main.yml — carte d'identité Galaxy enrichie---galaxy_info: author: Stéphane Robert namespace: stephrobert role_name: webserver description: | Installer et configurer nginx avec configuration paramétrable. Supporte le déploiement sur RHEL 9/10 et AlmaLinux 9/10. company: stephane-robert.info license: MIT min_ansible_version: "2.16" issue_tracker_url: https://github.com/stephrobert/ansible-training/issues
platforms: - name: EL versions: - "9" - "10" - name: AlmaLinux versions: - "9" - "10"
galaxy_tags: - nginx - webserver - http - rhce
dependencies: []
allow_duplicates: falseChamps essentiels :
role_name+namespace: identifiant Galaxy (stephrobert.webserver).min_ansible_version: version mini requise par votre code (vérifiable paransible --version).platforms: OS + versions supportés. Galaxy filtre les recherches selon ces tags.galaxy_tags: mots-clés pour la recherche utilisateur.issue_tracker_url: où signaler les bugs.allow_duplicates: false: empêche d’inclure 2 fois le rôle dans le même play (warning sinon).
dependencies: — chaîner les rôles
Section intitulée « dependencies: — chaîner les rôles »dependencies: - role: stephrobert.firewalld version: ">=1.0.0" vars: firewalld_zones: - publicAvant que tasks/main.yml du rôle s’exécute, les dépendances sont jouées. Pratique pour : firewall avant service web, selinux avant httpd. Couvert en détail au lab roles/dependencies.
meta: flush_handlers — forcer l’exécution immédiate
Section intitulée « meta: flush_handlers — forcer l’exécution immédiate »Si vous ne pouvez pas attendre la fin du play pour qu’un handler tourne (ex : tester nginx après reload, dans le même play) :
- name: Modifier la conf ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: Reload nginx
- name: Forcer le reload IMMÉDIATEMENT ansible.builtin.meta: flush_handlers
- name: Tester que la nouvelle conf répond ansible.builtin.uri: url: http://localhost status_code: 200Sans flush_handlers, le test tournerait avant le reload — donc sur l’ancienne config.
Pratiquer dans le lab
Section intitulée « Pratiquer dans le lab »Cette page a un lab d’accompagnement : labs/roles/handlers-meta/ dans
stephrobert/ansible-training.
Le lab étend le rôle webserver du lab roles/variables-defaults-vars avec 3 handlers + meta/main.yml enrichi. Le challenge déploie sur db1 avec port 8080 et valide les handlers déclenchés via les fichiers de log qu’ils créent (6 tests testinfra).
cd ~/Projets/ansible-training/labs/roles/handlers-meta/
ansible-playbook playbook.ymlcat /var/log/deploy-notification.log # créé par le handlerpytest -v challenge/tests/Pièges courants
Section intitulée « Pièges courants »| Symptôme | Cause | Fix |
|---|---|---|
| Handler ne se déclenche pas | Tâche en ok (pas changed) | Normal — un handler ne tourne que sur changed |
| Handler tourne 5× | Pas possible — Ansible déduplique automatiquement | Vérifier que les 5 tâches notifient le même nom de handler |
notify: ignoré silencieusement | Faute de frappe sur le nom | Restart nginx ≠ Restart Nginx (case-sensitive) |
| Service redémarre à chaque run | state: restarted au lieu de reloaded | Préférer reloaded pour changements de config |
| Test post-reload échoue | Reload pas encore fait | Ajouter meta: flush_handlers avant le test |
À retenir
Section intitulée « À retenir »- Handlers = actions réactives, déclenchées uniquement par
notify:+changed=true. RestartvsReload: restart = downtime, reload = pas de downtime (SIGHUP).- Handlers s’exécutent à la fin de leur section (tasks/post_tasks/etc.).
- Déduplication automatique : 5× notify → 1× exécution.
meta: flush_handlersforce l’exécution immédiate dans la même section.meta/main.yml= carte d’identité Galaxy : platforms, tags, dependencies, allow_duplicates.