Ansible の block でエラーハンドリング

Ansible で一連の処理を実行する際に、途中で失敗したらそれまでの変更も元に戻したいといったことがあるかもしれません。そんな場合に使えるのが Block 機能です。Ansible 2.3 (2017年4月)から使える結構古い機能です。

存在は知っていたけど使ったことなかったのでどんなものか試してみます。

block 内の task が失敗した場合に、block 内の以降の処理をスキップして rescue 内の task が実行されます。 rescue 内の task が失敗するとそこでそのホストへの処理は中断されます。

次のように書けば step 2 でコケて rescue の task が実行される

\- hosts: all
  gather\_facts: no
  tasks:
    - name: some procedure
      block:
        - name: step 1
          command: /bin/true
        - name: step 2 \# 失敗する
          command: /bin/false
        - name: step 3 \# 前の task が失敗しているため実行されない
          command: /bin/true
      rescue:
        \# block 内がすべて成功していれば rescue 内は実行されない
        - name: rescue 1
          command: /bin/false
          \# 失敗すると継続の処理が実行されないため false にする
          failed\_when: false
        - name: rescue 2
          debug:
            msg: "Rescue 2"
        - name: failed task
          debug:
            \# 失敗した task の情報が ansible\_failed\_task 変数に入っている
            var: ansible\_failed\_task.name
        - name: failed result
          debug:
            \# 失敗した task の結果が ansible\_failed\_result 変数入っている、register で登録されるのと同じ内容
            var: ansible\_failed\_result

上記の Playbook を site.yml として保存し、実際に実行してみると次のようになります。(環境変数 ANSIBLE_STDOUT_CALLBACKyaml にしているため出力が JSON ではなく YAML になっています)

$ ansible-playbook -i localhost, site.yml --connection=local

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

TASK \[step 1\] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
changed: \[localhost\]

TASK \[step 2\] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
fatal: \[localhost\]: FAILED! => changed=true
  cmd:
  - /bin/false
  delta: '0:00:00.007922'
  end: '2019-09-14 08:51:21.915700'
  msg: non-zero return code
  rc: 1
  start: '2019-09-14 08:51:21.907778'
  stderr: ''
  stderr\_lines: \[\]
  stdout: ''
  stdout\_lines: TASK \[rescue 1\] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
changed: \[localhost\]

TASK \[rescue 2\] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
ok: \[localhost\] =>
  msg: Rescue 2

TASK \[failed task\] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
ok: \[localhost\] =>
  ansible\_failed\_task.name: step 2

TASK \[failed result\] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
ok: \[localhost\] =>
  ansible\_failed\_result:
    changed: true
    cmd:
    - /bin/false
    delta: '0:00:00.007922'
    end: '2019-09-14 08:51:21.915700'
    failed: true
    invocation:
      module\_args:
        \_raw\_params: /bin/false
        \_uses\_shell: false
        argv: null
        chdir: null
        creates: null
        executable: null
        removes: null
        stdin: null
        warn: true
    msg: non-zero return code
    rc: 1
    start: '2019-09-14 08:51:21.907778'
    stderr: ''
    stderr\_lines: \[\]
    stdout: ''
    stdout\_lines: \[\]

PLAY RECAP \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
localhost                  : ok=5    changed=2    unreachable=0    failed=1 
Built with Hugo
テーマ StackJimmy によって設計されています。