ansibleでの実行結果のsuccess/failedとignore_errors/failed_whenがよくわからなかったので調べてみた

  • 43
    Like
  • 0
    Comment
More than 1 year has passed since last update.

知りたいこと

  • ansibleでのsuccessとfailedの判定
  • それをハンドリングするための ignore_errors と failed_when の使い方

事前実験

存在しないコマンドを実行してみる

ansibleでの接続先(リモートサーバー。CentOS6)で `sakaimo --version' コマンドしてみる。ちなみに現時点のsakaimoのversionは39.7くらいのはず。

# sakaimo --version
-bash: sakaimo: command not found

CentOSさんにはこんなコマンドは存在しないのでnot foundになります。

ansibleでやってみる

playbook

- shell: sakaimo --version

- debug: msg="debug"

実行結果

PLAY [app] ********************************************************************

TASK: [sakaimo| shell sakaimo --version] *************************************
failed: [qa-lecture01] => {"changed": true, "cmd": "sakaimo --version", "delta": "0:00:00.146319", "end": "2015-05-12 10:52:53.548610", "rc": 127, "start": "2015-05-12 10:52:53.402291", "warnings": []}
stderr: /bin/sh: sakaimo: command not found

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
           to retry, use: --limit @/root/qa-lecture-playbook.retry

qa-lecture01               : ok=0    changed=0    unreachable=0    failed=1

一つ目でエラーが出た場合に- debug: msg="debug"は実行されていないことがわかります。しれっと「エラーが出た場合」と言っていますが、何がansibleで「エラー」と判定されるのかどうかを知りたくて調べてるんですけどねw

ignore_errors

ignore_errorsを付けてみる。

playbook

- shell: sakaimo --version
  ignore_errors: True #←ここ

- debug: msg="debug"

出力結果

PLAY [app] ********************************************************************

TASK: [sakaimo | shell sakaimo --version] *************************************
failed: [qa-lecture01] => {"changed": true, "cmd": "sakaimo --version", "delta": "0:00:00.143888", "end": "2015-05-12 10:53:30.886426", "rc": 127, "start": "2015-05-12 10:53:30.742538", "warnings": []}
stderr: /bin/sh: sakaimo: command not found
...ignoring

TASK: [sakaimo | debug msg="debug"] ****************************************
ok: [qa-lecture01] => {
    "msg": "debug"
}

PLAY RECAP ********************************************************************
qa-lecture01               : ok=2    changed=1    unreachable=0    failed=0

ignore_errors: Trueでは文字通りエラーがあっても無視して先にすすんでくれるようです。(debugが出力されているから) つまりcommand not foundはエラーとして認識されるみたいね。

実行結果によって分岐させてみる

when: result|failedを付けてみた。

playbook

- shell: sakaimo --version
  register: result
  ignore_errors: True

- debug: msg="debug"
  when: result|failed #←ここ

実行結果

PLAY [app] ********************************************************************

TASK: [sakaimo | shell sakaimo --version] *************************************
failed: [qa-lecture01] => {"changed": true, "cmd": "sakaimo --version", "delta": "0:00:00.142611", "end": "2015-05-12 11:00:33.019179", "rc": 127, "start": "2015-05-12 11:00:32.876568", "warnings": []}
stderr: /bin/sh: sakaimo: command not found
...ignoring

TASK: [sakaimo | debug msg="debug"] ****************************************
ok: [qa-lecture01] => {
    "msg": "debug"
}

PLAY RECAP ********************************************************************
qa-lecture01               : ok=2    changed=1    unreachable=0    failed=0

failedをsuccessにしてみたplaybook

- shell: sakaimo --version
  register: result
  ignore_errors: True

- debug: msg="debug"
  when: result|success #←ここ

実行結果

PLAY [app] ********************************************************************

TASK: [sakaimo | shell sakaimo --version] *************************************
failed: [qa-lecture01] => {"changed": true, "cmd": "sakaimo --version", "delta": "0:00:00.144219", "end": "2015-05-12 11:01:29.798585", "rc": 127, "start": "2015-05-12 11:01:29.654366", "warnings": []}
stderr: /bin/sh: sakaimo: command not found
...ignoring

TASK: [sakaimo | debug msg="debug"] ****************************************
skipping: [qa-lecture01]

PLAY RECAP ********************************************************************
qa-lecture01               : ok=1    changed=1    unreachable=0    failed=0

resultがfailedなので、debugがskipされています。ということはcommand not foundは'failed'と判定されるということね。

TASK: [sakaimo | debug msg="debug"] ****************************************
skipping: [qa-lecture01]

では成功するコマンドだったらどうなるのか。unameコマンドで実験。

リモートサーバーでの実行結果は

# uname
Linux

になってます。

playbook

- shell: uname
  register: result
  ignore_errors: True

- debug: msg="debug"
  when: result|success

実行結果

PLAY [app] ********************************************************************

TASK: [sakaimo | shell uname] *************************************************
changed: [qa-lecture01]

TASK: [sakaimo | debug msg="debug"] *******************************************
ok: [qa-lecture01] => {
    "msg": "debug"
}

PLAY RECAP ********************************************************************
qa-lecture01               : ok=2    changed=1    unreachable=0    failed=0

successをfailedにしてみる

playbook

- shell: uname
  register: result
  ignore_errors: True

- debug: msg="debug"
  when: result|failed #←ここ

実行結果

PLAY [app] ********************************************************************

TASK: [sakaimo | shell uname] *************************************************
changed: [qa-lecture01]

TASK: [sakaimo | debug msg="debug"] *******************************************
skipping: [qa-lecture01]

PLAY RECAP ********************************************************************
qa-lecture01               : ok=1    changed=1    unreachable=0    failed=0

これにより、unameでLinuxって返ってきてることはsuccessと判断されているってことね。

failed_when

どうやらfailed_whenは「こういう時はfailedにしてね」って感じのコマンドのようです。
ansible公式サイトより

例としてこんなんが載ってるので、

- name: this command prints FAILED when it fails
  command: /usr/bin/example-command -x -y -z
  register: command_result
  failed_when: "'FAILED' in command_result.stderr"

私の例で言うと

- shell: sakaimo --version
  register: result
  failed_when: "'command not found' in result.stderr"

- debug: msg="debug"

標準エラー(stderr)に「command not found」っていう文字列が含まれていたらfailedとして判定してね、って指定しました。

実行結果

PLAY [app] ********************************************************************

TASK: [sakaimo | shell sakaimo --version] *************************************
failed: [qa-lecture01] => {"changed": true, "cmd": "sakaimo --version", "delta": "0:00:00.139589", "end": "2015-05-12 12:07:03.049756", "failed": true, "failed_when_result": true, "rc": 127, "start": "2015-05-12 12:07:02.910167", "stdout_lines": [], "warnings": []}
stderr: /bin/sh: sakaimo : command not found

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
           to retry, use: --limit @/root/qa-lecture-playbook.retry

qa-lecture01               : ok=0    changed=0    unreachable=0    failed=1

うん、想定通りエラーになりました。そしてエラーになって処理が止まっているので、debugは出力されていません。

では今度は実行結果にerrorrrrrっていう文字列があったらfailedにするようにしてみます。

- shell: sakaimo --version
  register: result
  failed_when: "'errorrrrr'in result.stderr"

- debug: msg="debug"

にした場合、

PLAY [app] ********************************************************************

TASK: [sakaimo | shell sakaimo --version] *************************************
changed: [qa-lecture01]

TASK: [sakaimo | debug msg="debug"] *******************************************
ok: [qa-lecture01] => {
    "msg": "debug"
}

PLAY RECAP ********************************************************************
qa-lecture01               : ok=2    changed=1    unreachable=0    failed=0

となりました。errorrrrrは(リモートサーバーから)出力されていないので  successとみなされ failedではないとみなされ、次の処理に進んでdebugも表示されています。

ではwhen: result|successを追加したらどうでしょうか。

- shell: sakaimo --version
  register: result
  failed_when: "'errorrrrr'in result.stderr"

- debug: msg="debug"
  when: result|success #←ここ
PLAY [app] ********************************************************************

TASK: [sakaimo | shell sakaimo --version] *************************************
changed: [qa-lecture01]

TASK: [sakaimo | debug msg="debug"] *******************************************
skipping: [qa-lecture01]

PLAY RECAP ********************************************************************
qa-lecture01               : ok=1    changed=1    unreachable=0    failed=0

debugがskipされています。つまりresultfailedだったってことですね。

ということは、failed_whenを使って「こういう時はfailedにしてね」という指定はできるけれども、これは「それ以外のときはsuccsessだよ」という指定ではないってことですよねあたりまえかw

ためしに

- shell: sakaimo --version
  register: result
  failed_when: "'errorrrrr'in result.stderr"

- debug: msg="debug"
  when: result|failed #←ここを変えた

にして実行したら

PLAY [app] ********************************************************************

TASK: [sakaimo | shell sakaimo --version] *************************************
changed: [qa-lecture01]

TASK: [sakaimo | debug msg="debug"] *******************************************
ok: [qa-lecture01] => {
    "msg": "debug"
}

PLAY RECAP ********************************************************************
qa-lecture01               : ok=2    changed=1    unreachable=0    failed=0

になりました。

ということは

- shell: sakaimo --version
  register: result
  failed_when: "'errorrrrr'in result.stderr"

- debug: msg="debug"
  when: result|failed #←ここを変えた

において、

  • sakaimo --versionのリモートサーバーでの実行結果は-bash: sakaimo: command not found
  • だからresultにはfailedが入る (when: result|failed がtrue判定されてdebugが出力されているから)
  • なんだけどfailed_when: "'errorrrrr'in result.stderr"でfailedの条件を指定してしまっている
  • だからこの3行全体での処理結果としては「failedじゃない」(successとはいえない)けど、resultfailedなのでdebugは実行される

...あれ、頭がこんがらがってきた。