Bootstrap FreeKB - Ansible - Run tasks at end of pre_tasks, tasks, post_tasks using handlers and notify
Ansible - Run tasks at end of pre_tasks, tasks, post_tasks using handlers and notify

Updated:   |  Ansible articles

handlers are used to do something at the end of a playbook, after all prior tasks have been run. Often, handlers are used to perform cleanup tasks at the very end of a playbook.

As an example, let's say a cleanup script must always be run as the last task in the playbook. Here is how you could run cleanup.sh as the last task in the playbook.

---
- hosts: all
  tasks:
  - name: first shell command
    shell: <some command>
    notify: cleanup <- must be an exact match of the handler name

  - name: second shell command
    shell: <some command>
    notify: cleanup <- must be an exact match of the handler name

  handlers:
  - name: cleanup
    script: cleanup.sh
...

 

Something like this should be returned which shows that the cleanup handler was run as the last task in the playbook.

TASK [first shell command] 
changed: [server1.example.com]

TASK [second shell command] 
changed: [server1.example.com]

RUNNING HANDLER [cleanup] 
changed: [server1.example.com]

 

However, consider the scenario where the first shell command returns fatal. In this scenario, the handler would NOT be run.

TASK [first shell command] 
fatal: [server1.example.com]: FAILED! => {"changed": true, "cmd": "ls /tmp/files", "delta": "0:00:00.006940", "end": "2023-02-28 03:07:55.479674", "msg": "non-zero return code", "rc": 2, "start": "2023-02-28 03:07:55.472734", "stderr": "ls: cannot access /tmp/files: No such file or directory", "stderr_lines": ["ls: cannot access /tmp/files: No such file or directory"], "stdout": "", "stdout_lines": []}

server1.example.com    : ok=0   changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

 

I think the most stable solution here is to use block and rescue to ensure that the cleanup tasks are run even when something fatal occurs. You may not even want or need to use handlers and notify in a scenario like this.

---
- hosts: all
  - block:
    - shell: ls /bogus
    rescue:
    - script: cleanup.sh
...

 

Handlers are often created in a role.

roles/foo/handlers/main.yml

 

In this scenario, you could include the handler in the role like this. You may want to also include changed_when: true and failed_when: false to ensure the handler is run, even when one or more task return fatal.

  • Using the --force-handlers command line option
  • Using force_handlers: true in ansible.cfg or in your playbook
---
- hosts: all
  tasks:
  - name: first shell command
    shell: <some command>
    changed_when: true <- include this if the handler must always be run
    failed_when: false <- include this if the handler must always be run
    notify: cleanup <- must be an exact match of the handler name

  - name: second shell command
    shell: <some command>
    changed_when: true <- include this if the handler must always be run
    failed_when: false <- include this if the handler must always be run
    notify: cleanup <- must be an exact match of the handler name

  handlers:
  - include: roles/foo/handlers/main.yml
...

 

Tasks are performed in this order.

  1. pre_tasks
    • If there are pre_tasks that are using notify, the notify handlers will be run as the very last pre_tasks
  2. tasks
    • If there are tasks that are using notify, the notify handlers will be run as the very last tasks
  3. post_tasks
    • If there are post_tasks that are using notify, the notify handlers will be run as the very last post_tasks

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 56467c in the box below so that we can be sure you are a human.