It's an important concept as we learn more about Ansible playbooks and march towards Ansible roles. Ansible handlers are very useful in the scenarios where we need to run some task when a change takes place on the remote node.
For example we want to restart or reload a service immediately after a change has been made to its configuration file.
Handlers must have a unique name globally. The tasks which requires to run handler contains notify
directive. If nothing notifies a handler, it will not run.
Regardless of how many tasks notifies a handler, it will only run once, after all of the tasks complete in a particular play.
Handlers are mostly used when we need to restart services or trigger reboots.
Implementing Handlers in a Playbook
Here is my playbook. This will go to our worker nodes install epel repository on them and then install the nginx web server.
Once the nginx package is installed it will notify
the handler task and handler task (restarting nginx service) will then start execution.
---
- name: Handlers implementation example-1
hosts: workers
tasks:
- name: Enable EPEL Repository on CentOS 7
yum:
name: https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ ansible_distribution_major_version }}.noarch.rpm
state: present
become: True
- name: Import EPEL GPG key.
rpm_key:
key: /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-{{ ansible_distribution_major_version }}
state: present
become: True
- name: Install nginx latest version
yum:
name: nginx
state: present
become: true
notify: restart_nginx
handlers:
- name: restart_nginx
become: true
service:
name: nginx
state: restarted
Let's execute our playbook.
handler_tags $ ansible-playbook handler-1.yml -i myinventory -kK
SSH password:
BECOME password[defaults to SSH password]:
PLAY [Handlers implementation example-1] ***********************************************************************
TASK [Gathering Facts] *****************************************************************************************
ok: [worker1]
ok: [worker2]
TASK [Enable EPEL Repository on CentOS 7] **********************************************************************
changed: [worker1]
changed: [worker2]
TASK [Import EPEL GPG key.] ************************************************************************************
changed: [worker1]
changed: [worker2]
TASK [Install nginx latest version] ****************************************************************************
changed: [worker1]
changed: [worker2]
RUNNING HANDLER [restart_nginx] ********************************************************************************
changed: [worker1]
changed: [worker2]
PLAY RECAP *****************************************************************************************************
worker1 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker2 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
By looking at the above output you can clearly see that once package installation was completed successfully Ansible triggered the handler task to run.
handlers
keyword in the playbook should be at the same level as "tasks".
Here you have learned "How to enable EPEL repository on RHEL/CentOS through Ansible" as well.
Grouping of multiple handlers
Multiple handlers can be grouped as well. Handlers “listen” to generic topics, and tasks can notify those topics.
For example:
---
- name: Handlers grouping example
hosts: workers
tasks:
- name: restart everything
command: echo "this task will restart web and ftp services"
notify: "restart web and ftp services"
become: true
handlers:
- name: restart vsftpd
service: name=vsftpd state=restarted
listen: "restart web and ftp services"
become: true
- name: restart nginx
service: name=nginx state=restarted
listen: "restart web and ftp services"
become: true
listen
directive makes it easier for us to trigger multiple handlers. It also decouples handlers from their names, making it easier to share handlers among playbooks and roles.
Controlling handler run
As designed all the handlers run once and after all the tasks in a particular play have been completed regardless of how many tasks notify it.
By using meta
module the handlers can be run before the end of the play.
If you want to force the handler to run in between the two tasks instead of at the end of the play, you need to put this between the two tasks
Here is example playbook:
- name: Flush handlers
meta: flush_handlers
The meta: flush_handlers task triggers any handlers that have been notified at that point in the play.
Using variables with handlers
Using variables within handlers is also possible and important when we have different OS distributions and different service names, and you want your output to show the exact name of the restarted service for each target machine. We should avoid placing variables in the name of the handler.
handlers:
# This handler name may cause your play to fail!
- name: Restart "{{ web_service_name }}"
If the variable used in the handler name is not available, the entire play fails.
We should instead place variables in the task parameters of your handler.
---
- name: Handlers grouping example
hosts: workers
vars:
ftp_service_name: vsftpd
web_service_name: nginx
tasks:
- name: restart everything
command: echo "this task will restart web and ftp services"
notify: "restart web and ftp services"
become: true
handlers:
- name: restart vsftpd
service: name="{{ ftp_service_name | default('vsftpd')}}" state=restarted
listen: "restart web and ftp services"
become: true
- name: restart nginx
service: name="{{ web_service_name | default('httpd')}}" state=restarted
listen: "restart web and ftp services"
become: true
In the above playbook we are using variables as part of handler task which can be either declared in a separate file or within the playbook itself.
You can provide default values for variables directly in your templates using the Jinja2 ‘default’ filter. This is often a better approach than failing if a variable is not defined.
That's all for this article. I am sure you will have a very good idea now about Ansible handlers and their use cases.
Hope you like the article. Stay Tuned for more.
Thank you. Happy learning!