Ansibleで実行結果の値を使って処理を変えたい〜registerの使い方〜

## はじめに
今の仕事では、サーバの状態によってAnsibleの実行処理を変えることがよくあります。
その時にお世話になったregisterの使い方について書いていきます。


## registerとは
Ansibleのモジュールの一つで、実行タスクの`様々な結果`を格納するモジュールです。
私は主に実行結果をregisterで変数に詰めて、その変数の内容から処理を変えたりエラーメッセージを出したりしています。

### 使い方

結果を取得したいモジュールの箇所にregisterを入れるだけです。値は自由。
今回は中に何が入ってるか見る為にdebugモジュールとmsgパラメータを使います。

```yaml

- hosts: vagrants
  tasks:
    - name: yumモジュールチェック
      shell: rpm -qa | grep yum | wc -l
      register: yum_check

    - name: 実行結果
      debug:
        msg: "{{ yum_check }}"
```

```yaml
[実行結果]

TASK [yumモジュールチェック] ***************************************************************************************************************************************************************************************
[WARNING]: Consider using the yum, dnf or zypper module rather than running 'rpm'.  If you need to use command because yum, dnf or zypper is insufficient you can add 'warn: false' to this command task
or set 'command_warnings=False' in ansible.cfg to get rid of this message.

changed: [192.168.11.10]

TASK [実行結果] ************************************************************************************************************************************************************************************************
ok: [192.168.11.10] => {
    "msg": {
        "changed": true,
        "cmd": "rpm -qa | grep yum | wc -l",
        "delta": "0:00:01.016315",
        "end": "2019-12-07 05:11:40.782799",
        "failed": false,
        "rc": 0,
        "start": "2019-12-07 05:11:39.766484",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "3",
        "stdout_lines": [
            "3"
        ],
        "warnings": [
            "Consider using the yum, dnf or zypper module rather than running 'rpm'.  If you need to use command because yum, dnf or zypper is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message."
        ]
    }
}
```

`TASK [yumモジュールチェック] `のwarningは今回は気にしないでください。
ちなみに`ansibleにyumモジュールがあるからそれを使えよ!`というメッセージです。でもyumモジュールを使うとリポジトリ情報も一緒に取ってくるから整形が面倒だしコマンドラインを組み合わせるのがよくわからないし。。。。。（ぐちぐち）

msgの中に入っているのがregisterで取得した情報です。
自分がよく使ってる、わかってるものだけ簡単に説明します。


| パラメータ | 意味 |
| --- | --- |
| changed | 変更処理の値についてです。コマンド自体は問題なく実行出来たので今回はtrueが入っています。
| cmd | 実行したコマンドが入っています。 |
| rc | linuxで言う所の「echo $?」です。実行結果の数値が入っています。0は成功です。 |
| stdout | コマンド実行結果の値が格納されています。今回の実行結果ではyumとつくモジュール数の`3`が格納されています。 |


私が条件で使用するのは`rc`と`stdout`です。


#### rcを使った条件文。〜処理が正常に完了したら。しなかったら。

実際にregisterを使って、rcの値によって処理を変えてみます。


```yaml
[正常系]
- hosts: vagrants
  tasks:
    - name: yumモジュールチェック
      shell: rpm -qa | grep yum | wc -l
      args:
        warn: false
      register: yum_check


    - name: コマンド実行結果チェック
      assert:
        that: "{{ yum_check.rc == 0 }}"
        msg: "コマンド実行でエラーが発生しました。"

[実行結果]
TASK [yumモジュールチェック] ***************************************************************************************************************************************************************************************
changed: [192.168.11.10]

TASK [コマンド実行結果チェック] *************************************************************************************************************************************************************************************
ok: [192.168.11.10] => {
    "changed": false,
    "msg": "All assertions passed"
}
```

shellモジュールの実行結果がエラーだった場合にメッセージを出力するというプレイブックです。
`assert`モジュールのthatパラメータの条件に該当しなければmsgパラメータで指定したメッセージが出力されます。今回だと`rpm -qa | grep yum | wc -lコマンドが失敗したら「コマンド実行でエラーが発生しました。」`が出力されるようになっています。

※普通こんな確認は行いませんが、例ということで。。実用的な使いどころとしては、コマンドモジュールの一部をユーザーが定義する変数にしていて、おかしな値が入る可能性があるとかいう時に使えます。

あと今回の内容と関係ないですが、warningメッセージが出るのが鬱陶しいので、argsのwarnパラメータをfalseにしてwarningが出ないようにしています。

次に異常系を記載します。今の状態だと如何あっても成功するのでコマンドモジュールの一部をわざとおかしくします。
あと、普通におかしくしたままだとコマンド実行結果チェックの前に異常終了してしまうので、yumモジュールチェックのところでは`ignore_errors`を使ってエラーでも処理を続行するようにします。

```yaml
[異常系]
- hosts: vagrants
  tasks:
    - name: yumモジュールチェック
      shell: rpm -qa | grep yum | wac -l
      args:
        warn: false
      register: yum_check
      ignore_errors: true

    - name: コマンド実行結果チェック
      assert:
        that: "{{ yum_check.rc == 0 }}"
        msg: "コマンド実行でエラーが発生しました。"

[実行結果]
TASK [yumモジュールチェック] **************************************************************************************************************************************************************************************
fatal: [192.168.11.10]: FAILED! => {"changed": true, "cmd": "rpm -qa | grep yum | wac -l", "delta": "0:00:00.579428", "end": "2019-12-07 05:52:25.649060", "msg": "non-zero return code", "rc": 127, "start": "2019-12-07 05:52:25.069632", "stderr": "/bin/sh: wac: コマンドが見つかりません", "stderr_lines": ["/bin/sh: wac: コマンドが見つかりません"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [コマンド実行結果チェック] **************************************************************************************************************************************************************************************
fatal: [192.168.11.10]: FAILED! => {
    "assertion": false,
    "changed": false,
    "evaluated_to": false,
    "msg": "コマンド実行でエラーが発生しました。"
}
```

#### stdoutを使った条件文。

`yum_check.rc`の部分を`yum_check.stdout`にすれば実行結果の値（3）を使用出来ます。
折角なのでrcの時と条件を変えて、`yumモジュールの数が*だったら`で条件文を作ってみます

```yaml
- hosts: vagrants
  tasks:
    - name: yumモジュールチェック
      shell: rpm -qa | grep yum | wc -l
      args:
        warn: false
      register: yum_check
      ignore_errors: true

    - name: コマンド実行結果チェック1
      debug:
        msg: "yumモジュールが足りません。yumモジュールの数は{{ yum_check.stdout }}です。"
      when: yum_check.stdout == '1'

    - name: コマンド実行結果チェック3
      debug:
        msg: "OK。yumモジュールの数は{{ yum_check.stdout }}です"
      when: yum_check.stdout == '3'
```

whenモジュールを使ってyumモジュールの数が1か3かで出力されるメッセージを変えています。
whenの条件に合致しないタスクはスキップされます。

```yaml
[実行結果]
TASK [yumモジュールチェック] **************************************************************************************************************************************************************************************
changed: [192.168.11.10]

TASK [コマンド実行結果チェック1] *************************************************************************************************************************************************************************************
skipping: [192.168.11.10]

TASK [コマンド実行結果チェック3] *************************************************************************************************************************************************************************************
ok: [192.168.11.10] => {
    "msg": "OK。yumモジュールの数は3です"
}
```

こんな具合です。

正直、通常の自動化ではそう使うことは無いと思いますが、複数の環境に対応したプレイブックを作成したいとか、絶対に実行させたく無い環境で実行しようとした場合に止めたいとかって時に使えます。

その他、変数を使って上手くいかないときはこのregisterを途中で挟んで、意図したものが変数に入ってるかチェックするのにも使えます。

条件文で使うのは中級な感じですが、変数の確認は便利なので知っておいて損は無いかなーと思います。