failedになっても最後まで実行し、最後にassertで判定する

はじめに

Ansibleはfail-fastな設計のため、Taskが失敗した時点でPlaybookは異常終了します。 しかし、assertモジュールによるバリデーション等は、エラーがあっても ある程度まとめて実行したいケースがあります。

そこで、下記の条件を満たすPlaybookを簡単に書いてみました。

条件

  • Assert 1、Assert 2、Assert 3という3つのタスクがある
  • 3つすべてがokの場合、後続を実行する
  • 1つでもfailedの場合、後続は実行しない
  • 3つのタスクは、評価結果の真偽に関わらず、すべて実行する

3つすべてokの場合

Playbook

---
- hosts: localhost
  gather_facts: false
  connection: local
  tasks:
    - name: Assertions
      ignore_errors: true
      ##########################################################################
      # block start
      block:
        - name: Assert 1
          assert:
            that: true
          register: res_assert1

        - name: Assert 2
          assert:
            that: true
          register: res_assert2

        - name: Assert 3
          assert:
            that: true
          register: res_assert3
      # block end
      ##########################################################################

    - name: Assert all
      assert:
        that: item.failed == false
      loop:
        - "{{ res_assert1 }}"
        - "{{ res_assert2 }}"
        - "{{ res_assert3 }}"

    - name: Next task
      debug:
        msg: Next task

実行結果

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

TASK [Assert 1] *******************************************************************************************************************************************************************************
ok: [localhost] => {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [Assert 2] *******************************************************************************************************************************************************************************
ok: [localhost] => {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [Assert 3] *******************************************************************************************************************************************************************************
ok: [localhost] => {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [Assert all] *****************************************************************************************************************************************************************************
ok: [localhost] => (item={'changed': False, 'msg': 'All assertions passed', 'failed': False}) => {
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "changed": false,
        "failed": false,
        "msg": "All assertions passed"
    },
    "msg": "All assertions passed"
}
ok: [localhost] => (item={'changed': False, 'msg': 'All assertions passed', 'failed': False}) => {
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "changed": false,
        "failed": false,
        "msg": "All assertions passed"
    },
    "msg": "All assertions passed"
}
ok: [localhost] => (item={'changed': False, 'msg': 'All assertions passed', 'failed': False}) => {
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "changed": false,
        "failed": false,
        "msg": "All assertions passed"
    },
    "msg": "All assertions passed"
}

TASK [Next task] ******************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "Next task"
}

PLAY RECAP ************************************************************************************************************************************************************************************
localhost                  : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Assert 2のみエラーの場合

Playbook

---
- hosts: localhost
  gather_facts: false
  connection: local
  tasks:
    - name: Assertions
      ignore_errors: true
      ##########################################################################
      # block start
      block:
        - name: Assert 1
          assert:
            that: true
          register: res_assert1

        - name: Assert 2
          assert:
            that: false
          register: res_assert2

        - name: Assert 3
          assert:
            that: true
          register: res_assert3
      # block end
      ##########################################################################

    - name: Assert all
      assert:
        that: item.failed == false
      loop:
        - "{{ res_assert1 }}"
        - "{{ res_assert2 }}"
        - "{{ res_assert3 }}"

    - name: Next task
      debug:
        msg: Next task

実行結果

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

TASK [Assert 1] *******************************************************************************************************************************************************************************
ok: [localhost] => {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [Assert 2] *******************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {
    "assertion": false,
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}
...ignoring

TASK [Assert 3] *******************************************************************************************************************************************************************************
ok: [localhost] => {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [Assert all] *****************************************************************************************************************************************************************************
ok: [localhost] => (item={'changed': False, 'msg': 'All assertions passed', 'failed': False}) => {
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "changed": false,
        "failed": false,
        "msg": "All assertions passed"
    },
    "msg": "All assertions passed"
}
failed: [localhost] (item={'failed': True, 'evaluated_to': False, 'assertion': False, 'msg': 'Assertion failed', 'changed': False}) => {
    "ansible_loop_var": "item",
    "assertion": "item.failed == false",
    "changed": false,
    "evaluated_to": false,
    "item": {
        "assertion": false,
        "changed": false,
        "evaluated_to": false,
        "failed": true,
        "msg": "Assertion failed"
    },
    "msg": "Assertion failed"
}
ok: [localhost] => (item={'changed': False, 'msg': 'All assertions passed', 'failed': False}) => {
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "changed": false,
        "failed": false,
        "msg": "All assertions passed"
    },
    "msg": "All assertions passed"
}

PLAY RECAP ************************************************************************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=1