Illusionist
Illusionist

Reputation: 5489

Ansible Ignore errors in tasks and fail at end of the playbook if any tasks had errors

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?

Upvotes: 83

Views: 288509

Answers (7)

Paul Franke
Paul Franke

Reputation: 649

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"  

Upvotes: 0

clever_bassi
clever_bassi

Reputation: 2480

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"

Upvotes: 57

Matias
Matias

Reputation: 11

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.

Upvotes: 0

Robert Saylor
Robert Saylor

Reputation: 1369

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

Upvotes: 2

sudhir tataraju
sudhir tataraju

Reputation: 1379

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"

Upvotes: 4

Olga
Olga

Reputation: 1022

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.

Upvotes: 40

dank
dank

Reputation: 589

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 

Upvotes: 3

Related Questions