Run handler on failed task

Hi,

So what I want to do, and have not yet found a way todo yet, is to run a handler if a taks fails rather then if it succeeds.
For example I want to do a yum install mysql on a server, but this server does not have python-simplejson and/or other packages that is neccesary for Ansible.
How do I then trigger a “fix” and then preferably rerun the failed task. Is this possible?

Something similar to:

  • hosts: mysql
    user: admin
    vars:
    passwd: VeryHardPasswd
    user: analytics
    tasks:
  • name: create user Analytics
    mysql_user: name={{ user }}
    password={{ passwd }}
    priv=.:SELECT,‘SHOW DATABASES’
    state=present
    login_user=ROOT
    login_password=PASSWORD
    register: mysql_result
    ignore_errors: True
    notify_on_fail: install mysqldb-python
    handlers:
  • name: Install mysqldb-python
    raw: sudo yum install -y MySQL-python

In this specific case you'd just assert the python-simplejson package
exists right?
If it's already installed then nothing happens, and you'll be able to
skip on to the
other tasks.

If of course you're in a catch-22 situation (can't run ansible to set
up ansible pre-requisites),
then you'll need to seed your base image with what's required.

For example, my kickstarts bring up a machine with

* SSHd enabled and tcp/22 inbound permitted on the local firewall
* an 'ansible' account with a pre-defined list of SSH keys in its
authorised_keys file
* passwordless sudo configured for that account

Everything else is managed by Ansible.

This general approach also applies to CM with puppet, chef, etc.
(which typically
have much more requirements).

To be honest, I would also be interested in a solution to this.

Of course all the machines, that I install myself (preseed, kickstart, ...) meet the requirements for ansible.

For already existing machines which should be managed by us, the requirements are somewhere in the middle of met or unmet.

To my knowledge python-simplejson (required on Python 2.4 boxes) can only be installed using the raw module and not with the apt or yum module.
Therefore this is a task which I'd not like to be executed on every run.

Maybe the first task in the list could be an ansible ping and if it fails do some brute-force raw commands.
....
And as writing this I answered my question :slight_smile:

My prototype looks like this:

- hosts: all
   user: root
   tasks:
   - name: ping
     ping:
     register: result
   - name: conditional task
     raw: here_your_command
     when: result|failed

Cheers
Christian

Hmm -
I have fixed it with a when statement and then notify a handler that in turns install and notifies yet another handler.
Thou this solution does not look nice and I would really like to not relay on any other managementsystem other then Ansible.

My sollution to problem looks like this atm:

  • name: something

    register: something
    ignore_errors: True

  • name: simplejson
    raw: “yum -y install python-simplejson”
    when: something|failed
    notify:

  • somethingAgain

handlers:

  • name: somethingAgain

The above one works kinda but is not the best looking.

Preffered would be similar to:

  • name: something

    register: something
    notify_when: something|failed
  • simplejson

handlers:

  • name: simplejson
    raw: “yum -y install python-simplejson”

Does anyone know if something like this might be implemented in the near future or if anyone can point me to where I can suggest a “patch” :slight_smile:

You are definitely overcomplicating it.

There’s no reason to need the register really.

  • shell: yum -y install python-simplejson

Yum naturally is smart enough to not do anything if the package is already installed, so it takes care of the “idempotence” (I kinda still hate the over-complexity of that word, but it’s a word) for you.

As we have to manage a mixed environment, we do have different packagemanagers.
So I often use when clauses like this
when: ansible_pkg_mgr == "apt"
I really like facts to be available in my playbooks.

So my goal is/was to avoid running raw yum commands against a debian or apt against Red Hat in our global site playbook.

A other thing I want to avoid is having a complicated documentation about which playbook to run against a server.
I am dreaming of a one-size-fits-all playbook :slight_smile:

Will the shell module work if the install of python-simplejson is required?
At least for the install of python (Minimal debian does not have it) I need to go for raw.

- shell: yum install python-simplejson
  ignore_errors: true
  changed_when: False

ugly but should work

This is also a bit weird looking, but you could abuse the "removes"
parameter to the shell command, which does not run a command when a binary
does not exist.

The downside is this makes your playbook look weirder.

- shell: yum install python-simplejson removes=/usr/bin/yum

referenced here: http://docs.ansible.com/shell_module.html

Generally this is done to prevent running installers a second time, and
will not remove the indicated file.

Another solution is usually to have the kickstart or base image slightly
prepped in the case of those older OSes, but we definitely don't require it.