Posted on September 2, 2017
Since version Ansible 2.2, so quite a while, there is another way to notify a handler or a couple of handlers or no handlers. No handlers? Right, this sound a bit funny, doesn’t it? Well, it is a bit comparable with talking to kids, if no one is listen, no one will react :).
Before 2.2, there was only one way to notify a handler, by notifying the name of the handler:
1... 2tasks: 3 - copy: 4 src: main.conf 5 dest: /etc/postfix/main.cnf 6 notify: restart postfix 7 8handlers: 9 - name: restart postfix 10 service: name=postfix state=restarted
This is simple and works great, especially if your handler is logically related to the task, like in a playbook or within a role. Because with using the name, the handler and the task are are directly coupled.
When you run a playbook, Ansible make all handlers available to the play (or tasks stage). So we are not limited in notifying only the handlers within the same role. If we are aware of the handlers name of other roles, we can also notify those as well.
There is nothing against this practice in general, except, the two roles are now coupled and not generic anymore.
Subscribe to Changes
We extend our example and assume we want to get notified for a particular change of the postfix config. The usual way to handle this would to add another handler name to the notify clause of the task:
1... 2tasks: 3- name: configure postfix 4 template: 5 src: main.conf.j2 6 dest: /etc/postfix/main.cnf 7 notify: 8 - restart postfix 9 - post on slack 10 11handlers: 12 - name: restart postfix 13 service: 14 name: postfix 15 state: restarted 16 17 - name: post on slack 18 slack: 19 token: ... 20 msg: ... 21 delegate_to: localhost
Our postfix playbook has all we want and we think about to turn it into a generic postfix role and sharing it on galaxy.
The slack handler is nothing we want to put in a generic postfix role, right. Further having a notify for a handler located outside a role is not practical. Let’s remove the slack notification from role change the playbook to use the postfix role.
1# file: role/postfix/tasks/main.yml 2- name: configure postfix 3 template: 4 src: main.conf.j2 5 dest: /etc/postfix/main.cnf 6 notify: 7 - restart postfix
1# file: role/postfix/handlers/main.yml 2- name: restart postfix 3 service: 4 name: postfix 5 state: restarted
We remove the postfix task in our playbook and use the new created postfix role:
1... 2roles: 3 - role: postfix 4 5handlers: 6 - name: post on slack 7 slack: 8 token: ... 9 msg: ... 10 delegate_to: localhost
We are back to the problem that the slack handler won’t get notified anymore. How we can solve that? How can we subscribe to a change of a task? Handler listen!
We change the handler to listen on a key word or call it event, a handlers name. No modifications in the role is required, we can keep it generic. The only thing to do is to add
listen: <handler name> to the slack task.
1... 2roles: 3 - role: postfix 4 5handlers: 6 - name: post on slack 7 slack: 8 token: ... 9 msg: ... 10 delegate_to: localhost 11 listen: restart postfix
The configure task in the postfix role is not coupled to the handler’s name anymore. The role has no relation to the slack handler. Handler listen allows us to even add more handlers listen to the event without touching the task clause.
1... 2roles: 3 - role: postfix 4 5handlers: 6 - name: post on slack 7 slack: 8 token: ... 9 msg: ... 10 delegate_to: localhost 11 listen: restart postfix 12 13 - name: reaction on postfix config change 14 command: ... 15 listen: restart postfix
This decoupling is especially helpful in roles, make your roles to notify an event if you think this might be helpful to trigger tasks outside the role. But note, make sure to have a least one handler to listen to it or to have the identical name or Ansible will complain about notifying a inexistent handler.
Hint. It can be a handler with a debug task.