Les handlers
Les handlers résolvent un problème classique : redémarrer un service uniquement si sa configuration a changé, et uniquement une fois même si plusieurs tâches ont déclenché la demande. Sans handlers, on se retrouve à relancer nginx trois fois au cours d'un play, ou à le redémarrer même quand rien n'a changé.
Principe de fonctionnement
Un handler est une tâche spéciale déclarée dans une section handlers. Il n'est exécuté que si :
- Au moins une tâche du play a émis un
notifyvers ce handler - La tâche qui a notifié a le statut
changed(pasokniskipped)
L'exécution se fait à la fin du play, une seule fois, quel que soit le nombre de tâches qui l'ont notifié.
Syntaxe de base
---
- name: Configurer nginx
hosts: web
become: true
tasks:
- name: Déployer la configuration nginx
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Recharger nginx
- name: Déployer le vhost
ansible.builtin.template:
src: vhost.conf.j2
dest: /etc/nginx/sites-available/myapp
notify: Recharger nginx # même handler, déclenché qu'une seule fois
handlers:
- name: Recharger nginx
ansible.builtin.service:
name: nginx
state: reloadedSi les deux tâches de configuration ont le statut changed, le handler "Recharger nginx" ne sera quand même exécuté qu'une seule fois, à la fin du play.
Notifier plusieurs handlers
- name: Mettre à jour la configuration SSL
ansible.builtin.copy:
src: cert.pem
dest: /etc/ssl/certs/myapp.pem
notify:
- Recharger nginx
- Mettre à jour le monitoringChaîner les handlers
Un handler peut lui-même notifier un autre handler :
handlers:
- name: Recompiler l'application
ansible.builtin.command:
cmd: make -C /srv/myapp
notify: Redémarrer l'application
- name: Redémarrer l'application
ansible.builtin.systemd:
name: myapp
state: restartedflush_handlers : forcer l'exécution immédiate
Parfois, on a besoin qu'un handler s'exécute en milieu de play, avant les tâches suivantes. Par exemple, redémarrer un service avant de tester qu'il répond correctement :
tasks:
- name: Déployer la configuration
ansible.builtin.template:
src: app.conf.j2
dest: /etc/myapp/app.conf
notify: Redémarrer myapp
- name: Forcer l'exécution des handlers en attente
ansible.builtin.meta: flush_handlers
- name: Vérifier que l'application répond
ansible.builtin.uri:
url: http://localhost:8080/health
status_code: 200Pièges classiques
Handler non déclenché si la tâche est skippée : si une tâche avec when: false est skippée, elle n'émet pas de notify même si le handler y est listé.
Handler avec statut ok : si une tâche n'a rien changé (statut ok), son notify n'est pas pris en compte. C'est le comportement voulu pour l'idempotence.
Handlers dans les rôles : les handlers définis dans un rôle ne sont visibles que depuis ce rôle. Pour notifier un handler d'un rôle depuis un autre rôle, passer par listen :
handlers:
- name: Recharger nginx
ansible.builtin.service:
name: nginx
state: reloaded
listen: "nginx config changed" # alias écoutable par n'importe quelle tâche