Pages

Thursday, 22 April 2021

EX294 Configure Ansible error handling

1. Errors vs failures

Personally, I would like to differentiate between "errors" and "failures".  Wrong playbook syntax, network connection issues are "ERRORS", which the playbook itself can do nothing about it.

On the other side, a task may fail to execute due to any reasons. I call such a failed task "FAILURE".

2. What will happen by default when a task failure occurs

By default, for any managed node, Ansible stops running remaining tasks when a task failed.
In the below example, task3 will not run.

[smstong@mk8 ansible]$ cat testbook.yml
- name: test play
  hosts: localhost
  tasks:
    - name: task1
      debug:
        msg: task1 done

    - name: task2
      debug:
        msg: task2 done
      failed_when: True

    # task3 will never be executed
    - name: task3
      debug:
        msg: task3 done

3. Ignore failures

Sometimes, we want to run the remaining tasks even if a task fails. Ansible allows that by setting "ignore_errors".

[smstong@mk8 ansible]$ cat testbook.yml
- name: test play
  hosts: localhost
  tasks:
    - name: task1
      debug:
        msg: task1 done

    - name: task2
      debug:
        msg: task2 done
      failed_when: True
      ignore_errors: True

    # tasl3 will execute even if task2 failed.
    - name: task3
      debug:
        msg: task3 done

4. Action based on task failure status

"ignore_errors" works fine, but we may still need to know if a task failed or not, and run some tasks based on it. 

Every task returns a result that contains a boolean typed property named "failed". If the task failed, this property was set to "True" by Ansible.

[smstong@mk8 ansible]$ cat testbook.yml
- name: test play
  hosts: localhost
  tasks:
    - name: task1
      debug:
        msg: task1 done

    - name: task2
      debug:
        msg: task2 done
      failed_when: True
      ignore_errors: True
      register: task2_result

    # task3 will run only if task2 failed
    - name: task3
      debug:
        msg: task3 done
      when: task2_result.failed

    # task4 will run only if task2 didn't fail
    - name: task4
      debug:
          msg: task4 done
      when: not task2_result.failed

5. Overwrite the task status

Every module has its own logic to define if the task fails or not. For example, the "command" module fails based on the exit code of the command to run.

However, Ansible tasks allow you to overwrite the status of the module by setting "failed_when".

[smstong@mk8 ansible]$ cat testbook.yml
- name: test play
  hosts: localhost
  tasks:

    # never fail
    - name: task1
      command: /bin/false
      failed_when: false


    # failed if user1 is not found
    - name: task2
      shell: cat /etc/passwd
      register: r
      failed_when: "'user1' not in r.stdout"

6. block failure handling

Checking every task is kind of tedious. Just like most programming languages' exception handling, Ansible support block/rescue/always.

[smstong@mk8 ansible]$ cat testbook.yml
- name: test play
  hosts: localhost
  tasks:
      - name: block 1
        block:
            - name: task1
              command: /bin/false

            - name: task2
              debug:
                  msg: task 2 will never run
        rescue:
             - name: task3
               debug:
                   msg: task3 only run when task1 or task2 failed
        always:
             - name: task4
               debug:
                   msg: task4 will always run


No comments:

Post a Comment