Execute task (or handler) if any task failed

I wrote up a full example on how to use Block/Rescue and the Slack module (not callback plugin) that provides meaningful error output with formatting:

The first answer here got me part of the way, but just for anyone else that comes this way struggling with the same thing!

A simple playbook example looks as follows:

playbooks/playbook.yml

- hosts: "{{ target_host | default('127.0.0.1') }}"
  gather_facts: true

  tasks:
  - block:
    - include_role:
        name: install_app
    - name: Greet the world
      shell: echo "hello world!"
    - fail:
       msg: "I've gone and failed the play!"
    rescue:
      - include_role:
          name: slack_handler
          tasks_from: failure

And in my slack_handler role (for reusability):

roles/slack_handler/tasks/failure.yml

- name: Notify Slack of Playbook Failure
  slack:
    username: 'Ansible'
    color: danger
    token: "{{ slack_webhook.split('https://hooks.slack.com/services/')[1] }}"
    channel: "#deployment-alerts"
    msg: "Ansible failed on *{{ ansible_hostname }} ({{ inventory_hostname }})* \n
    *Task*: {{ ansible_failed_task.name }} \n
    *Action*: {{ ansible_failed_task.action }} \n
    *Error Message*: \n ```{{ ansible_failed_result | to_nice_json }}``` "
  delegate_to: localhost

Ref: http://www.petewilcock.com/ansible-slack-failure-handler/


I don't think a handler is a solution, because a handler will only be notified if the task reports a changed state. On a failed state the handler will not be notified.

Also, handlers by default will not be fired if the playbook failed. But that can be changed. For that you will need to set this in your ansible.cfg:

force_handlers = True

But yes, there are better options available.

If you use Ansible 2 you can use the new blocks feature. Blocks group tasks together and have a rescue section which will be only triggered if any of the tasks have failed.

tasks:
  - block:
      - here
      - go
      - all
      - your
      - tasks
    rescue:
      - name: notify slack of deploy failure
        local_action:
          module: slack
          token: "{{slack_token}}"
          msg: "Deploy failed on {{inventory_hostname}}"

Another option and especially interesting if you're using Ansible 1.x might be callback plugins. As the name suggests with these kind of plugins you can write callbacks which can be fired on various events.

Again, if you're using Ansible 2 you're lucky, because there already is a slack callback plugin available: https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/callback/slack.py

To use this plugin you need to enable it in your ansible.cfg:

callback_whitelist = slack

And define some environment variables on your system for configuration:

 This plugin makes use of the following environment variables:
    SLACK_WEBHOOK_URL (required): Slack Webhook URL
    SLACK_CHANNEL     (optional): Slack room to post in. Default: #ansible
    SLACK_USERNAME    (optional): Username to post as. Default: ansible
    SLACK_INVOCATION  (optional): Show command line invocation
                                  details. Default: False

That plugin might need some modifications to fit your needs. If that's the case copy the source and store it relative to your playbook as callback_plugins/custom_slack.py and then enable it in your ansible.cfg:

callback_whitelist = custom_slack

If you use Ansible 1.x you'll have to see how you can convert it. The API is different, examples for the old API can be found here: https://github.com/ansible/ansible/tree/v1.9.4-1/plugins/callbacks

Tags:

Ansible