Handlers in Ansible are special tasks triggered by the notify directive within a playbook. These tasks are executed only when the associated task makes a change on the target system. Unlike regular tasks, handlers help optimize resource usage by ensuring idempotency in configuration management.
Ansible Handlers allow you to trigger specific actions based on the results of a task. They are commonly used for tasks such as restarting services, reloading configurations, or notifying dependent systems when a task has been executed successfully.
In this article, we’ll dive deep into what handlers are, their syntax, usage, and how to leverage them in real-world examples.
Table of Contents
Basic Syntax of Handlers
Handlers are declared under the handlers section in a playbook. Below is a basic syntax:
- name: Demonstrate Basic Syntax of Handlers
hosts: web
tasks:
- name: Update web server configuration
template:
src: /path/to/template.j2
dest: /etc/nginx/nginx.conf
notify: Restart NGINX
handlers:
- name: Restart NGINX
service:
name: nginx
state: restarted
In this example:
- A template task updates the nginx.conf file.
- The notify directive calls the Restart NGINX handler, which restarts the NGINX service.
Using Handlers in Ansible Playbooks
Here’s a step-by-step guide to using handlers effectively:
Step 1: Create a Playbook
Start with defining your tasks and specifying the notify keyword for any task that requires triggering a handler.
Step 2: Define the Handlers
Handlers should be placed in the handlers section of the playbook, ensuring they match the names used in notify.
In this Example Playbook, the copy module copies the nginx.conf configuration file to the remote host and restart the Nginx service.
---
- name: Manage web server
hosts: web
tasks:
- name: Copy NGINX configuration
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: Restart NGINX
- name: Install NGINX
apt:
name: nginx
state: present
handlers:
- name: Restart NGINX
service:
name: nginx
state: restarted
Step 3: Run the Playbook
Execute the playbook using:
# ansible-playbook playbook.yml
If the copy task modifies the NGINX configuration file, the handler will restart the service. Otherwise, the handler won’t run.
Using Multiple Handlers for Different Notifications
Multiple handlers are defined in the handlers section of your playbook. Each handler must have a unique name and can be notified by one or more tasks.
Here is an example:
- name: Use Multiple Handlers for Different Notifications
hosts: web
tasks:
- name: Update NGINX configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Restart NGINX
- Reload Firewall
- name: Update firewall rules
copy:
src: firewall.rules
dest: /etc/firewall.rules
notify: Reload Firewall
handlers:
- name: Restart NGINX
service:
name: nginx
state: restarted
- name: Reload Firewall
command: firewall-cmd --reload
This playbook updates the NGINX configuration using a template file and notifies handlers to restart NGINX and reload the firewall.
Handling Task Errors
It’s essential to ensure that errors in the notified tasks are handled gracefully to avoid service disruption or inconsistent states. Below are some strategies to manage task errors effectively in Ansible playbooks:
1. Use ignore_errors
The ignore_errors directive can be applied to a task to allow the playbook to continue execution even if the task fails.
- name: Handle Task Errors with ignore_errors
hosts: web
tasks:
- name: Copy configuration file
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: Restart NGINX
ignore_errors: yes
handlers:
- name: Restart NGINX
service:
name: nginx
state: restarted
This playbook will continue to run even if the copy task fails. However, be cautious when using this directive, as it may hide critical issues.
2. Use failed_when to Define Failure Conditions
By default, Ansible determines task success or failure based on the return code. However, you can customize these conditions using failed_when.
Here is an example playbook:
- name: Handle Task Errors with failed_when
hosts: web
tasks:
- name: Validate configuration file syntax
command: nginx -t
notify: Restart NGINX
failed_when: "'syntax is ok' not in stdout"
handlers:
- name: Restart NGINX
service:
name: nginx
state: restarted
In this example:
The task fails only if the string ‘syntax is ok’ is missing from the command output, ensuring the handler is triggered only for valid configurations.
3. Use rescue and always Blocks
Ansible provides error handling blocks (rescue and always) to handle failures more granularly.
Here is an example:
- name: Handle Task Errors with rescue and always blocks
hosts: web
tasks:
- name: Copy configuration file with error handling
block:
- name: Copy configuration file
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: Restart NGINX
rescue:
- name: Handle copy task failure
debug:
msg: "Failed to copy configuration file. Skipping handler."
always:
- name: Log completion message
debug:
msg: "Task completed, regardless of the outcome."
handlers:
- name: Restart NGINX
service:
name: nginx
state: restarted
Explanation:
- block: Contains tasks that might fail.
- rescue: Executes if a task in the block fails, preventing the handler from being triggered unnecessarily.
- always: Runs regardless of task success or failure, ensuring cleanup or logging.
4. Log Task and Handler Errors
Logging errors can help identify issues quickly. Use the debug module with when conditionals to log outputs or error messages.
Here is the example playbook:
- name: Log Task Errors for Debugging
hosts: web
tasks:
- name: Copy configuration file
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: Restart NGINX
- name: Log error message
debug:
msg: "Task failed to copy configuration file!"
when: copy_task_failed is defined and copy_task_failed
handlers:
- name: Restart NGINX
service:
name: nginx
state: restarted
Conclusion
Handlers in Ansible are powerful features that enable you to manage system state changes efficiently. They are very useful for automating actions like restarting services or reloading configurations. They only run when tasks notify them, making your playbooks efficient.
FAQs
1. Can a handler be notified multiple times?
Yes, but it will execute only once per playbook run, regardless of the number of notifications.
2. What happens if no task notifies a handler?
The handler will not run if it is not notified by any task.
3. Can multiple tasks notify the same handler?
Yes, multiple tasks can notify a single handler, which ensures efficient execution.