Handlers in Ansible provide another type of conditional execution. They define a task or tasks whose execution is dependent upon the completion status of the play.
For instance, it is a good practice to define an idle timeout limit on ssh sessions. Configuring idle timeout for the ssh daemon requires setting a limit in seconds in its configuration file. Ansible’s lineinfile module is capable of making this change to the configuration file but the daemon still must be restarted before the setting will take effect. This provides an perfect use case for a handler.
The following playbook uses a handler to signal to Ansible engine that a task which restarts the ssh daemon should be executed after the daemon’s configuration file is altered.
--- - name: Set SSHD idle session timeout limit hosts: all tasks: - name: Set client alive interval to 10 minutes (600s) lineinfile: path: /etc/ssh/sshd_config state: present insertafter: '^#ClientAliveInterval' line: ClientAliveInterval 600 backup: True notify: restart_sshd handlers: - name: restart_sshd service: name: sshd state: restarted
Notice that the notify keyword is used at the task level to trigger tasks defined in the handlers section. Also note that the handler task name must exactly match the argument provided with the notify keyword.
An ansible play typically returns one of three completion statuses to the management node. These are ok, changed, and failed. As you might guess, a return value of changed indicates that a play ran and succeeded at making some changes to the target managed host, while failed indicates a change was attempted but unsuccessful. Because Ansible always attempts to maintain idempotency a third completion status is necessary. For this reason the ok status exists to indicate that a play ran but did not need to change anything. It is important to make this distinction here because handlers will not be triggered for plays returning ok or failed statuses. Handlers will only be triggered to run when the play returns a changed status.
When considering these three play completion statuses it is possible to imagine a case in which one of several tasks defined in a play encounters a failure condition. By default this would mean that the related handlers would not be triggered. When defining a play whose handlers are required to run even in the event of a task causing the play’s completion status to return failed it is possible to use the more general ignore_errors: true, and/or the more specific force_handlers: true construction to guarantee that handlers will be triggered upon the play’s completion.
--- - name: Demo force_handlers hosts: all force_handlers: True ignore_errors: True tasks: - name: Define a task which will fail copy: src: /tmp/nothing dest: /tmp/nowhere - name: Define a task which will succeed copy: content: "This task will succeed!" dest: /tmp/msg notify: print_completion_message handlers: - name: print_completion_message debug: msg: "Task complete! Running handler!"
Happy Independence Day, USA!