rescue / always - block 内のエラー処理

2019/05/26

Ansible

 Ansible Documentation

Blocks error handling

 通常のタスクの動作

 block 内のタスクが失敗した場合、その対象ホストの play の実行はその時点で終了します。動作確認用の play です。block内の 2 つ目のタスクで shell モジュールを使用して diff コマンドを実行します。ファイルの内容は対象ホスト node-c0706 は異なり、node-u1804 は同じです。
---
- hosts: all
  gather_facts: no

  tasks:
    - name: block 内でエラーが発生する例
      block:
      - name: 1 つ目のタスク
        debug:
          msg: "1 つ目"
      - name: 2 つ目のタスク
        shell: diff ~/file-a ~/file-b
      - name: 3 つ目のタスク
        debug:
          msg: "3 つ目"

    - name: block の外のタスク
      debug:
        msg: "block の外"
ファイルの内容が異なる node-c0706 は 2 つ目のタスクでしてエラーが発生し、それ以降のタスクは実行されません。ファイルの内容が同じ node-u1804 はエラーが発生せず、すべてのタスクが実行されました。
ansibleman@ubuntu-pc:~/ansible/block$ ansible-playbook -i hosts.yml site.yml

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

TASK [1 つ目のタスク] ****************************************************************************************************
ok: [node-c0706] => {
    "msg": "1 つ目"
}
ok: [node-u1804] => {
    "msg": "1 つ目"
}

TASK [2 つ目のタスク] ****************************************************************************************************
changed: [node-u1804]
fatal: [node-c0706]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "diff ~/file-a ~/file-b", "delta": "0:00:00.008303", "end": "2019-05-26 19:45:33.416847", "msg": "non-zero return code", "rc": 1, "start": "2019-05-26 19:45:33.408544", "stderr": "", "stderr_lines": [], "stdout": "1c1\n< abc\n---\n> xyz", "stdout_lines": ["1c1", "< abc", "---", "> xyz"]}

TASK [3 つ目のタスク] ****************************************************************************************************
ok: [node-u1804] => {
    "msg": "3 つ目"
}

TASK [block の外のタスク] ************************************************************************************************
ok: [node-u1804] => {
    "msg": "block の外"
}

PLAY RECAP *********************************************************************************************************
node-c0706                 : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
node-u1804                 : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansibleman@ubuntu-pc:~/ansible/block$

 rescue

 rescue を使用して block 内のタスクでエラーが発生した場合に実行するタスクを定義します。rescue 内のタスクが実行されるのは、block 内のすべてのタスクの実行が終了した後になります。
---
- hosts: all
  gather_facts: no

  tasks:
    - name: block 内でエラーが発生する例
      block:
      - name: 1 つ目のタスク
        debug:
          msg: "1 つ目"
      - name: 2 つ目のタスク
        shell: diff ~/file-a ~/file-b
      - name: 3 つ目のタスク
        debug:
          msg: "3 つ目"

      rescue:
      - name: block 内でエラーが発生したときの処理
        debug:
          msg: "ファイルの内容が異なります"

    - name: block の外のタスク
      debug:
        msg: "block の外"
 node-u1804 はエラーが発生していないので rescue で定義したタスク以外はすべて実行されました。node-c0706 は block 内の 2 つ目のタスクでエラーが発生したので block 内のタスクの実行を中断し rescue 内で定義したタスクを実行しました。rescue 内のタスクを実行した後はエラーがなかったように block の外のタスクを実行しています。RECAP でも failed はカウントされず、rescued がカウントされました。
ansibleman@ubuntu-pc:~/ansible/block$ ansible-playbook -i hosts.yml site.yml

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

TASK [1 つ目のタスク] ****************************************************************************************************
ok: [node-c0706] => {
    "msg": "1 つ目"
}
ok: [node-u1804] => {
    "msg": "1 つ目"
}

TASK [2 つ目のタスク] ****************************************************************************************************
fatal: [node-c0706]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "diff ~/file-a ~/file-b", "delta": "0:00:00.006554", "end": "2019-05-26 19:58:34.499283", "msg": "non-zero return code", "rc": 1, "start": "2019-05-26 19:58:34.492729", "stderr": "", "stderr_lines": [], "stdout": "1c1\n< abc\n---\n> xyz", "stdout_lines": ["1c1", "< abc", "---", "> xyz"]}
changed: [node-u1804]

TASK [3 つ目のタスク] ****************************************************************************************************
ok: [node-u1804] => {
    "msg": "3 つ目"
}

TASK [block 内でエラーが発生したときの処理] ***************************************************************************************
ok: [node-c0706] => {
    "msg": "ファイルの内容が異なります"
}

TASK [block の外のタスク] ************************************************************************************************
ok: [node-c0706] => {
    "msg": "block の外"
}
ok: [node-u1804] => {
    "msg": "block の外"
}

PLAY RECAP *********************************************************************************************************
node-c0706                 : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0   
node-u1804                 : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansibleman@ubuntu-pc:~/ansible/block$

 rescue 内で次の 2 つの変数を使用して、rescue が呼ばれた原因を確認できます。
  • ansible_failed_task
    • rescue を呼び出すトリガーになったタスクの情報
  • ansible_failed_result
    • rescue を呼び出すトリガーになったタスクの実行結果(register 変数で取得できる内容と同じ)
実際に確認します。
---
- hosts: all
  gather_facts: no

  tasks:
    - name: block 内でエラーが発生する例
      block:
      - name: 1 つ目のタスク
        debug:
          msg: "1 つ目"
      - name: 2 つ目のタスク
        shell: diff ~/file-a ~/file-b
      - name: 3 つ目のタスク
        debug:
          msg: "3 つ目"

      rescue:
      - name: block 内でエラーが発生したときの処理
        debug:
          msg: "ファイルの内容が異なります"
      - name: ansible_failed_task の値
        debug:
          var: ansible_failed_task
      - name: ansible_failed_result の値
        debug:
          var: ansible_failed_result

    - name: block の外のタスク
      debug:
        msg: "block の外"
実行結果です。rescue を呼び出すトリガーになったタスクは ansible_failed_task.name で確認できます。
ansibleman@ubuntu-pc:~/ansible/block$ ansible-playbook -i hosts.yml site.yml

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

TASK [1 つ目のタスク] ****************************************************************************************************
ok: [node-c0706] => {
    "msg": "1 つ目"
}
ok: [node-u1804] => {
    "msg": "1 つ目"
}

TASK [2 つ目のタスク] ****************************************************************************************************
fatal: [node-c0706]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "diff ~/file-a ~/file-b", "delta": "0:00:00.006094", "end": "2019-05-26 20:17:47.858342", "msg": "non-zero return code", "rc": 1, "start": "2019-05-26 20:17:47.852248", "stderr": "", "stderr_lines": [], "stdout": "1c1\n< abc\n---\n> xyz", "stdout_lines": ["1c1", "< abc", "---", "> xyz"]}
changed: [node-u1804]

TASK [3 つ目のタスク] ****************************************************************************************************
ok: [node-u1804] => {
    "msg": "3 つ目"
}

TASK [block 内でエラーが発生したときの処理] ***************************************************************************************
ok: [node-c0706] => {
    "msg": "ファイルの内容が異なります"
}

TASK [ansible_failed_task の値] **************************************************************************************
ok: [node-c0706] => {
    "ansible_failed_task": {
        "action": "command",
        "any_errors_fatal": false,
        "args": {
            "_raw_params": "diff ~/file-a ~/file-b",
            "_uses_shell": true,
            "warn": true
        },
        "async": 0,
        "async_val": 0,
        "become": false,
        "become_flags": null,
        "become_method": "sudo",
        "become_user": null,
        "changed_when": [],
        "check_mode": false,
        "collections": null,
        "connection": "smart",
        "debugger": null,
        "delay": 5,
        "delegate_facts": null,
        "delegate_to": null,
        "diff": false,
        "environment": [
            {}
        ],
        "failed_when": [],
        "finalized": false,
        "ignore_errors": null,
        "ignore_unreachable": null,
        "loop": null,
        "loop_control": null,
        "loop_with": null,
        "module_defaults": [],
        "name": "2 つ目のタスク",
        "no_log": null,
        "notify": null,
        "parent": {
            "any_errors_fatal": false,
            "become": false,
            "become_flags": null,
            "become_method": "sudo",
            "become_user": null,
            "check_mode": false,
            "collections": null,
            "connection": "smart",
            "debugger": null,
            "delegate_facts": null,
            "delegate_to": null,
            "dep_chain": null,
            "diff": false,
            "environment": null,
            "eor": false,
            "ignore_errors": null,
            "ignore_unreachable": null,
            "module_defaults": null,
            "name": "block 内でエラーが発生する例",
            "no_log": null,
            "port": null,
            "remote_user": null,
            "run_once": null,
            "tags": [],
            "vars": {},
            "when": []
        },
        "parent_type": "Block",
        "poll": 10,
        "port": null,
        "register": null,
        "remote_user": null,
        "retries": 3,
        "run_once": null,
        "squashed": false,
        "tags": [],
        "until": [],
        "uuid": "0050562c-70da-6765-eb0d-00000000000a",
        "vars": {},
        "when": []
    }
}

TASK [ansible_failed_result の値] ************************************************************************************
ok: [node-c0706] => {
    "ansible_failed_result": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        },
        "changed": true,
        "cmd": "diff ~/file-a ~/file-b",
        "delta": "0:00:00.006094",
        "end": "2019-05-26 20:17:47.858342",
        "failed": true,
        "invocation": {
            "module_args": {
                "_raw_params": "diff ~/file-a ~/file-b",
                "_uses_shell": true,
                "argv": null,
                "chdir": null,
                "creates": null,
                "executable": null,
                "removes": null,
                "stdin": null,
                "stdin_add_newline": true,
                "strip_empty_ends": true,
                "warn": true
            }
        },
        "msg": "non-zero return code",
        "rc": 1,
        "start": "2019-05-26 20:17:47.852248",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "1c1\n< abc\n---\n> xyz",
        "stdout_lines": [
            "1c1",
            "< abc",
            "---",
            "> xyz"
        ]
    }
}

TASK [block の外のタスク] ************************************************************************************************
ok: [node-c0706] => {
    "msg": "block の外"
}
ok: [node-u1804] => {
    "msg": "block の外"
}

PLAY RECAP *********************************************************************************************************
node-c0706                 : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0   
node-u1804                 : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansibleman@ubuntu-pc:~/ansible/block$

参考までに node-c0706 および node-u1804 で、file-a と file-b を同じ内容にした例です。
---
- hosts: all
  gather_facts: no

  tasks:
    - name: block 内でエラーが発生する例
      block:
      - name: 1 つ目のタスク
        debug:
          msg: "1 つ目"
      - name: 2 つ目のタスク
        shell: diff ~/file-a ~/file-b
      - name: 3 つ目のタスク
        debug:
          msg: "3 つ目"

      rescue:
      - name: block 内でエラーが発生したときの処理
        debug:
          msg: "ファイルの内容が異なります"

    - name: block の外のタスク
      debug:
        msg: "block の外"
 block 内でエラーが発生していないので rescue で定義したタスクは実行されません。
ansibleman@ubuntu-pc:~/ansible/block$ ansible-playbook -i hosts.yml site.yml

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

TASK [1 つ目のタスク] ****************************************************************************************************
ok: [node-c0706] => {
    "msg": "1 つ目"
}
ok: [node-u1804] => {
    "msg": "1 つ目"
}

TASK [2 つ目のタスク] ****************************************************************************************************
changed: [node-c0706]
changed: [node-u1804]

TASK [3 つ目のタスク] ****************************************************************************************************
ok: [node-c0706] => {
    "msg": "3 つ目"
}
ok: [node-u1804] => {
    "msg": "3 つ目"
}

TASK [block の外のタスク] ************************************************************************************************
ok: [node-c0706] => {
    "msg": "block の外"
}
ok: [node-u1804] => {
    "msg": "block の外"
}

PLAY RECAP *********************************************************************************************************
node-c0706                 : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
node-u1804                 : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansibleman@ubuntu-pc:~/ansible/block$

 always

 always を使用して block 内のタスクの状況(成功 / 失敗)に関わらず実行するタスクを定義します。always 内のタスクが実行されるのは、block 内のすべてのタスクの実行が終了した後になります。
---
- hosts: all
  gather_facts: no

  tasks:
    - name: block 内でエラーが発生する例
      block:
      - name: 1 つ目のタスク
        debug:
          msg: "1 つ目"
      - name: 2 つ目のタスク
        shell: diff ~/file-a ~/file-b
      - name: 3 つ目のタスク
        debug:
          msg: "3 つ目"

      always:
      - name: block 内の状況に関係なく実行するタスク
        debug:
          msg: "必ず実行されるタスク"

    - name: block の外のタスク
      debug:
        msg: "block の外"
 node-u1804 は block 内でエラーが発生していないので、block内 / always 内 / blockの外のすべてのタスクを実行しています。node-c0706 は block 内の 2 つ目のタスクの実行でエラーが発生したため、always 内のタスクを実行した後に終了しています。
ansibleman@ubuntu-pc:~/ansible/block$ ansible-playbook -i hosts.yml site.yml

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

TASK [1 つ目のタスク] ****************************************************************************************************
ok: [node-c0706] => {
    "msg": "1 つ目"
}
ok: [node-u1804] => {
    "msg": "1 つ目"
}

TASK [2 つ目のタスク] ****************************************************************************************************
fatal: [node-c0706]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "diff ~/file-a ~/file-b", "delta": "0:00:00.006702", "end": "2019-05-26 21:06:40.921524", "msg": "non-zero return code", "rc": 1, "start": "2019-05-26 21:06:40.914822", "stderr": "", "stderr_lines": [], "stdout": "1c1\n< abc\n---\n> xyz", "stdout_lines": ["1c1", "< abc", "---", "> xyz"]}
changed: [node-u1804]

TASK [3 つ目のタスク] ****************************************************************************************************
ok: [node-u1804] => {
    "msg": "3 つ目"
}

TASK [block 内の状況に関係なく実行するタスク] **************************************************************************************
ok: [node-c0706] => {
    "msg": "必ず実行されるタスク"
}
ok: [node-u1804] => {
    "msg": "必ず実行されるタスク"
}

TASK [block の外のタスク] ************************************************************************************************
ok: [node-u1804] => {
    "msg": "block の外"
}

PLAY RECAP *********************************************************************************************************
node-c0706                 : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
node-u1804                 : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansibleman@ubuntu-pc:~/ansible/block$ 

 rescue と always

 rescue と always は併用できます。
---
- hosts: all
  gather_facts: no

  tasks:
    - name: block 内でエラーが発生する例
      block:
      - name: 1 つ目のタスク
        debug:
          msg: "1 つ目"
      - name: 2 つ目のタスク
        shell: diff ~/file-a ~/file-b
      - name: 3 つ目のタスク
        debug:
          msg: "3 つ目"

      always:
      - name: block 内の状況に関係なく実行するタスク
        debug:
          msg: "必ず実行されるタスク"

      rescue:
      - name: block 内でエラーが発生したときの処理
        debug:
          msg: "ファイルの内容が異なります"

    - name: block の外のタスク
      debug:
        msg: "block の外"
実行結果です。block 内のタスク → rescue 内のタスク → always 内のタスク の順に実行されています。
ansibleman@ubuntu-pc:~/ansible/block$ ansible-playbook -i hosts.yml site.yml

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

TASK [1 つ目のタスク] ****************************************************************************************************
ok: [node-c0706] => {
    "msg": "1 つ目"
}
ok: [node-u1804] => {
    "msg": "1 つ目"
}

TASK [2 つ目のタスク] ****************************************************************************************************
fatal: [node-c0706]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "diff ~/file-a ~/file-b", "delta": "0:00:00.006588", "end": "2019-05-26 21:22:59.901297", "msg": "non-zero return code", "rc": 1, "start": "2019-05-26 21:22:59.894709", "stderr": "", "stderr_lines": [], "stdout": "1c1\n< abc\n---\n> xyz", "stdout_lines": ["1c1", "< abc", "---", "> xyz"]}
changed: [node-u1804]

TASK [3 つ目のタスク] ****************************************************************************************************
ok: [node-u1804] => {
    "msg": "3 つ目"
}

TASK [block 内でエラーが発生したときの処理] ***************************************************************************************
ok: [node-c0706] => {
    "msg": "ファイルの内容が異なります"
}

TASK [block 内の状況に関係なく実行するタスク] **************************************************************************************
ok: [node-c0706] => {
    "msg": "必ず実行されるタスク"
}
ok: [node-u1804] => {
    "msg": "必ず実行されるタスク"
}

TASK [block の外のタスク] ************************************************************************************************
ok: [node-c0706] => {
    "msg": "block の外"
}
ok: [node-u1804] => {
    "msg": "block の外"
}

PLAY RECAP *********************************************************************************************************
node-c0706                 : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0   
node-u1804                 : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

ansibleman@ubuntu-pc:~/ansible/block$ 

カテゴリー

目次

QooQ