てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] 複数の assert を一通り実施したあとで全結果を再 assert する

はじめに

Ansible には、値が期待したした条件を満たすかどうかをチェック assert モジュールがあります(標準モジュール)。

基本的には、assert 結果が fail だとその時点で Playbook の処理が中止されます。

一方で、1つ fail しただけで止めるのではなく、いくつかの assert を一通り実行しそれらの結果がすべて success なら success としたい場合もあるのではないでしょうか。

ignore_errors を併用すると実現できます。 この記事では簡単なサンプルでご紹介します。

(もっといい方法があるかも知れません)

  • 動作確認環境
    • ansible-base 2.10.1

サンプル Playbook

2つの 個別の assert があります。fail しても中止しないように、ignore_errors: true を指定します。(タスクごとに指定するのが面倒の場合は block で囲って指定) また、あとで、assert 結果を参照できるように、個別の assert には register で結果を受け取るようにします。

ここでは 1つめの assert が fail するようにしています。

---
- hosts: all
  gather_facts: false

  tasks:
    - name: assert 1   # 個別 assert
      assert:
        that: 1 == 0     # fail する
      ignore_errors: true
      register: res_assert1

    - name: assert 2  # 個別 assert
      assert:
        that: 2 == 2
      ignore_errors: true
      register: res_assert2

    - name: all assert
      assert:
        that:   # 複数指定で and 条件
          - not res_assert1.failed  # fail
          - not res_assert2.failed  # success

    - name: Finished
      debug:
        msg: Finished!


実行1(failパターン)

まずは、1つめの assert が fail するパターンです。

実行

$ ansible-playbook -i localhost, assert.yml

PLAY [all] **********************************************************************************************************

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

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

TASK [all assert] ***************************************************************************************************
fatal: [localhost]: FAILED! => {
    "assertion": "not res_assert1.failed",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}

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

中断せずに 2つめに assert しているのが分かります。また、2つの結果をまとめて assert するタスク「all assert」では fail していることが分かります。


実行2 (successパターン)

1つめの assert の条件を以下のようにして、success になるようにして再実行します。

   - name: assert 1   # 個別 assert
      assert:
        that: 1 == 1     # ★修正
      ignore_errors: true
      register: res_assert1

実行

$ ansible-playbook -i localhost, assert.yml

PLAY [all] **********************************************************************************************************

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

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

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

TASK [Finished] *****************************************************************************************************
ok: [localhost] => {
    "msg": "Finished!"
}

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

個別の assert もまとめの assert も success となり、最後の debug タスクも実行されました。


応用

再 assert ではなく、結果を一覧で 表示する場合は、タスク all assert の代わりに以下のようにします。

    - name: assert results
      debug:
        msg:
          - "{{ res_assert1 }}"
          - "{{ res_assert2 }}"

実行結果(抜粋)

TASK [assert results] ***************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "assertion": "1 == 0",
            "changed": false,
            "evaluated_to": false,
            "failed": true,
            "msg": "Assertion failed"
        },
        {
            "changed": false,
            "failed": false,
            "msg": "All assertions passed"
        }
    ]
}


別解(loop の活用)

今回のように、比較する値が予めすべて取り揃っている状態から assert する場合は、loop で回すという方法もあります。 loop で assert すると、一通り assert しつつも、1つでも fail になるとそのタスクが fail となります。

---
- hosts: all
  gather_facts: false

  tasks:
    - name: assert
      assert:
        that: "{{ item }}" 
      loop:
        - 1 == 0    # fail
        - 2 == 2    # success

    - name: Finished
      debug:
        msg: Finished!

実行

$ ansible-playbook -i localhost, assert_loop.yml

PLAY [all] **********************************************************************************************************

TASK [assert] *******************************************************************************************************
failed: [localhost] (item=1 == 0) => {
    "ansible_loop_var": "item",
    "assertion": "1 == 0",
    "changed": false,
    "evaluated_to": false,
    "item": "1 == 0",
    "msg": "Assertion failed"
}
ok: [localhost] => (item=2 == 2) => {
    "ansible_loop_var": "item",
    "changed": false,
    "item": "2 == 2",
    "msg": "All assertions passed"
}

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