Ansible Tips: shellモジュール失敗時の実行ログを見やすく表示させる例


# 追記 2021/07

以下の対応の方が容易かつ読みやすいと思えます。

https://qiita.com/hiroyuki_onodera/items/d5bcbf57dcd8189b0345





# 問題: shellモジュールで失敗した場合のログは読みにくい

## サンプルplaybook

```yaml:pb1.yml

- hosts: all
  gather_subset: [ '!all' ]
  tasks:
  - shell: |-
      set -ex                          # set -xにて実行されたコマンドをstderrに出力。set -eにてコマンド失敗時にそこでスクリプトを終了させる。
      exec 2>&1                        # stderrをstdoutにマージ
      :
      echo abc
      ls /abc                          # このコマンドでエラー
      echo def                         # set -eの為、実行されない
    register: r

  - debug: { var: r.stdout_lines }     # shellモジュールの実行ログ(stdout)出力用だが、そもそもここまで辿り着けない。
```

## サンプルplaybookの実行結果
ファイル/abcが無い状態でサンプルplaybookを実行する。


```
$ ansible-playbook -i localhost, -c local pb1.yml 

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

TASK [Gathering Facts] *********************************************************************************************************
ok: [localhost]

TASK [shell] *******************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "set -ex\nexec 2>&1\n:\necho abc\nls /abc\necho def", "delta": "0:00:00.026305", "end": "2021-02-10 15:31:53.545597", "msg": "non-zero return code", "rc": 1, "start": "2021-02-10 15:31:53.519292", "stderr": "+ exec", "stderr_lines": ["+ exec"], "stdout": "+ :\n+ echo abc\nabc\n+ ls /abc\nls: /abc: No such file or directory", "stdout_lines": ["+ :", "+ echo abc", "abc", "+ ls /abc", "ls: /abc: No such file or directory"]}

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

shellモジュールの実行結果に、"ls: /abc: No such file or directory"というエラーの内容が含まれてはいるが、改行されていない為、そのままでは人間にとってとても読みにくい。

# ソリューション: ignore_errors: trueにて一旦処理を進め、shellモジュールの実行ログ出力後にassertモジュールにて停止させる

# サンプルplaybook2

```yaml:pb2.yml
- hosts: all
  gather_subset: [ '!all' ]
  tasks:

  - shell: |-
      set -ex                          # set -xにて実行されたコマンドをstderrに出力。set -eにてコマンド失敗時にそこでスクリプトを終了させる。
      exec 2>&1                        # stderrをstdoutにマージ
      :   
      echo abc
      ls /abc                          # このコマンドでエラー
      echo def                         # set -eの為、実行されない
    register: r
    ignore_errors: true                # shellモジュールがエラーで終わってもplaybookを進める
  
  - debug: { var: r.stdout_lines }     # shellモジュールの実行ログ(stdout)を出力
  
  - assert: { that: r is succeeded, quiet: true }   # shellモジュールが失敗していた場合、playbookの実行を失敗させる
```

assertは、指定された条件が __false__ の場合にplaybookの実行を失敗させる

## サンプルplaybook2の実行結果
ファイル/abcが無い状態で、サンプルplaybook2を実行する。

```
$ ansible-playbook -i localhost, -c local pb2.yml 

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

TASK [Gathering Facts] *********************************************************************************************************
ok: [localhost]

TASK [shell] *******************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "set -ex\nexec 2>&1\n:\necho abc\nls /abc\necho def\n", "delta": "0:00:00.022862", "end": "2021-02-10 15:41:59.516200", "msg": "non-zero return code", "rc": 1, "start": "2021-02-10 15:41:59.493338", "stderr": "+ exec", "stderr_lines": ["+ exec"], "stdout": "+ :\n+ echo abc\nabc\n+ ls /abc\nls: /abc: No such file or directory", "stdout_lines": ["+ :", "+ echo abc", "abc", "+ ls /abc", "ls: /abc: No such file or directory"]}
...ignoring

TASK [debug] *******************************************************************************************************************
ok: [localhost] => {
    "r.stdout_lines": [
        "+ :",
        "+ echo abc",
        "abc",
        "+ ls /abc",
        "ls: /abc: No such file or directory"
    ]
}

TASK [assert] ******************************************************************************************************************
fatal: [localhost]: FAILED! => {"assertion": "r is succeeded", "changed": false, "evaluated_to": false, "msg": "Assertion failed"}
```