75

I am learning Ansible. I have a playbook to clean up resources, and I want the playbook to ignore every error and keep going on till the end , and then fail at the end if there were errors.

I can ignore errors with

  ignore_errors: yes

If it was one task, I could do something like ( from ansible error catching)

- name: this command prints FAILED when it fails
  command: /usr/bin/example-command -x -y -z
  register: command_result
  ignore_errors: True

- name: fail the play if the previous command did not succeed
  fail: msg="the command failed"
  when: "'FAILED' in command_result.stderr"

How do I fail at the end ? I have several tasks, what would my "When" condition be?

Illusionist
  • 5,204
  • 11
  • 46
  • 76
  • XY problem I think. ansible default behavior is to tell you which hosts failed at the end. If you use ignore_errors, ansible will continue attempting to run tasks against that host. The default workflow is to fail, then ignore that host for the rest of the playbook. Then at the end, admin researches why the hosts failed, fixes them, then reruns the playbook against the ones that failed. The .retry file option helps with this. I thin the idea is you still have to touch the failed systems again, so stop executing to prevent strange results. – Jeter-work Jun 08 '22 at 16:06

7 Answers7

51

Use Fail module.

  1. Use ignore_errors with every task that you need to ignore in case of errors.
  2. Set a flag (say, result = false) whenever there is a failure in any task execution
  3. At the end of the playbook, check if flag is set, and depending on that, fail the execution
- fail: msg="The execution has failed because of errors."
  when: flag == "failed"

Update:

Use register to store the result of a task like you have shown in your example. Then, use a task like this:

- name: Set flag
  set_fact: flag = failed
  when: "'FAILED' in command_result.stderr"
Shashimee
  • 256
  • 3
  • 20
clever_bassi
  • 2,392
  • 2
  • 24
  • 43
  • 1
    Thanks ! How do i set a flag only on errors in ansible ? – Illusionist Aug 10 '16 at 18:50
  • see update. Basically, you are setting this flag after each task execution. If at the end of this playbook, the flag is set to failed, your playbook is failed. It will only set to fail if any of your task fails. Else it will not be set to failed and playbook execution will be successful. – clever_bassi Aug 11 '16 at 14:49
  • 2
    You might want to look at `failed_when` and `command_result is failed` instead of the string processing (it'll give you something that'll work for more generically for other commands as well). – DylanYoung Nov 22 '18 at 21:45
  • Do we have any way to mark as fail instead of ignore and continue execution. – Jeenit khatri Feb 04 '21 at 11:42
  • This is fine for one command. If two commands exist, the first fails and the second one succeeds, command_result will be for the later task, not the earlier one that failed. – Jeter-work Jun 08 '22 at 16:09
38

You can wrap all tasks which can fail in block, and use ignore_errors: yes with that block.

tasks:
  - name: ls
    command: ls -la
  - name: pwd
    command: pwd

  - block:
    - name: ls non-existing txt file
      command: ls -la no_file.txt
    - name: ls non-existing pic
      command: ls -la no_pic.jpg
    ignore_errors: yes 

Read more about error handling in blocks here.

Damian T.
  • 321
  • 1
  • 10
Olga
  • 982
  • 1
  • 11
  • 17
3

Fail module works great! Thanks.

I had to define my fact before checking it, otherwise I'd get an undefined variable error.

And I had issues when doing setting the fact with quotes and without spaces.

This worked:

set_fact: flag="failed"

This threw errors:

set_fact: flag = failed 
dank
  • 579
  • 3
  • 11
3

try failed_when

- name: Fail task when the command error output prints FAILED
  ansible.builtin.command: /usr/bin/example-command -x -y -z
  register: command_result
  failed_when: "'FAILED' in command_result.stderr"
sudhir tataraju
  • 1,159
  • 1
  • 14
  • 30
1

I found this to be helpful:

https://medium.com/opsops/anternative-way-to-handle-errors-in-ansible-245a066c340

In your task you want to register the task.

register: some_name

Then add ignore_errors: yes

Then use set_fact to get each register attribute:

- set_fact:
    success: '{{ not([e1, e2]|map(attribute="failed")|max) }}'

Then place this at the end of your block:

- name: Fail server build
  command: >
    bash scripts/test_file.sh
  when: success == false
  ignore_errors: yes

The block above would only be executed when success is false. The key is using ignore_errors and making a register. From the link I posted and from my testing the task attribute is registered if it fails or not.

Example output:

PLAY [localhost] ***********************************************************************************************

TASK [Gathering Facts] *****************************************************************************************
ok: [localhost]

TASK [Task 1 test] *********************************************************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["bash", "scripts/unknown_file.sh"], "delta": "0:00:00.004343", "end": "2021-10-20 14:20:59.320389", "msg": "non-zero return code", "rc": 127, "start": "2021-10-20 14:20:59.316046", "stderr": "bash: scripts/unknown_file.sh: No such file or directory", "stderr_lines": ["bash: scripts/unknown_file.sh: No such file or directory"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Task 2 test] *********************************************************************************************
changed: [localhost]

TASK [set_fact] ************************************************************************************************
ok: [localhost]

TASK [Fail server build] ***************************************************************************************
changed: [localhost]

TASK [debug] ***************************************************************************************************
ok: [localhost] => {
    "success": false
}

PLAY RECAP *****************************************************************************************************
localhost                  : ok=6    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1
dirdi
  • 267
  • 1
  • 14
Robert Saylor
  • 1,279
  • 9
  • 11
0

In my case, command_result.stderr: "". I kept looking and the 'FAILED' output was at command_result.stdout. So i changed the last "when" to it:

when: "'FAILED' in command_result.stdout"

Hope i can help someone. I am a begginer too.

Matias
  • 1
0

I would recommend using the "block", "rescue" and "always" functions. It´s like a try/catch/finally handling from other programming languages. https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_blocks.html

Example:

    - name: Do complex stuff
      block:
         - name: Task 1
           ansible.builtin.debug:
             msg: 'execute task 1'

         - name: Task 2
           ansible.builtin.debug:
             msg: 'execute task 2'

      rescue:
         - name: Complex stuf block failed
           ansible.builtin.debug:
             msg: 'handle failure'
      always:
         - name: Clean up task
           ansible.builtin.debug:
             msg: "run always"  
Paul Franke
  • 579
  • 3
  • 11