Posted on 2017-09-02
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.
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
Done!
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.