Handlers#
Observation#
Parmi les exemples de code que vous trouverez immanquablement sur la toile, le déclenchement de tasks en fonction du résultat d’une autre task revient souvent sous ces formes :
#
# Ne pas reproduire chez vous
#
- name: Templating de conf
template:
src: ...
dest ...
register: _templating
- name: Restart de service si la conf change
service:
state: restarted
when: _templating is changed
Cette approche complexifie inutilement le code de vos rôles/playbooks en réimplémentant la mécanique interne à Ansible qu’est le handler. Un des arguments est que les handlers se déclenchent en fin d’exécution de playbook et donc diffèrent parfois trop le lancement de ces comportements conditionnels.
Proposition#
En couplant la définition classique de handler avec l’usage du module meta, moins connu, on obtient l’effet désiré. Si on prend l’exemple d’un micro-playbook pour illustrer, cela donne :
---
- hosts: localhost
become: yes
tasks:
- name: Templating de conf
template:
src: ...
dest: ...
notify: Restart service
- name: Application de tous les handlers notifiés jusqu'ici
meta: flush_handlers
- debug:
msg: "Si la config a été modifiée, à ce stade, le service est déjà redémarré."
handlers:
- name: Restart service
service:
name: ...
state: restarted
Pour compléter le pattern, ajoutez systématiquement un appel au meta: flush_handlers
en fin de rôle :
#
# un_role/tasks/main.yml
#
[...]
- name: Toujours flush les handlers en dernière task de rôle
meta: flush_handlers
#
# End-Of-File
#
Si on oublie ce flush de fin de rôle, il est possible qu’un autre rôle plante et le re-jeu de notre rôle ne détectera
pas de modifications sur son périmètre, donc ne lancera pas de notify
et ne déclenchera pas les handlers.
En appliquant cette technique on s’assure que chaque rôle ne déborde pas de son périmètre et a bien fini ses actions avant de passer la main à un autre rôle.
Intégration#
Cette approche est aussi bien applicable dans un contexte de playbooks comme vu au-dessus, que dans un contexte de rôle. Dans un rôle
vous rangerez vos handlers dans le fichier handlers/main.yml
et vous utiliserez la combo attribut notify
+ module meta: flush_handlers
là où cela sera utile.