[Ansible] コマンドの実行結果に応じて別のコマンドを実行するかしないかを制御する

## 2015-08-30追記

この記事のストック数が100になって、さらに読まれそうなので補足です。

すみません、この記事の例はちょっとよくなかったです。yumのレポジトリのキーをインストールするにはAnsibleの [rpm_key](http://docs.ansible.com/ansible/rpm_key_module.html)モジュールが用意されているので、これを使うほうが楽です。

以下の記事は、モジュールが用意されていなくて、状態をチェックするコマンドと変更するコマンドの2つで実現するときの話だと思って読んでください。

## 今ではfailed_whenでスッキリ書けます (2013-10-08追記)

[Add failed_when module variable. by hnakamur · Pull Request #4073 · ansible/ansible](https://github.com/ansible/ansible/pull/4073)によりfailed_whenが追加されました。failed_whenについては[Controlling What Defines Failure](http://docs.ansible.com/playbooks_error_handling.html#controlling-what-defines-failure)を参照してください。

サンプルは
https://github.com/ansible/ansible/blob/devel/test/playbook-failed_when.yml
にあります。

```yaml
  - action: shell exit 1
    register: exit
    failed_when: exit.rc not in [0, 1]
```

このページの元の例は以下のように書けます。

```yaml:
- name: check nginx repo key is imported
  shell: |
    rpm -qi gpg-pubkey-* | grep -q '^Summary     : gpg(nginx signing key <signing-key@nginx.com>)$'
  register: result
  failed_when: result.rc not in [0, 1]
- name: import nginx repo key
  command: rpm --import http://nginx.org/keys/nginx_signing.key
  when: result.rc == 1
```

## 以下元のドキュメントです

詳細は[Conditionals — Ansible Documentation](http://docs.ansible.com/playbooks_conditionals.html)を参照してください。

nginx.orgのgpg keyがインストール済みかをチェックして、インストールされていない場合にのみインストールする例です。

```yaml:
- name: check nginx repo key is imported
  shell: |
    rpm -qi gpg-pubkey-* | grep -q '^Summary     : gpg(nginx signing key <signing-key@nginx.com>)$'
  register: result
  ignore_errors: True
- name: import nginx repo key
  command: rpm --import http://nginx.org/keys/nginx_signing.key
  when: result|failed
```

register: resultの指定により、チェック用のコマンドの終了ステータスをresultという変数に保持しておきます。また、コマンドの終了ステータスが異常(0以外)でも処理を継続するためにignore_errors: Trueの指定が必要です。

gpg keyをインストールするコマンドのほうにはwhen: result|failedという条件を指定して、まだインストールされていない場合にのみ実行するようにしています。

インストールされていなかった場合の実行結果は以下のようになります。

```
TASK: [check nginx repo key is imported] ************************************** 
failed: [cent6.4] => {"changed": true, "cmd": "rpm -qi gpg-pubkey-* | grep -q '^Summary     : gpg(nginx signing key <signing-key@nginx.com>)$'\n ", "delta": "0:00:00.014660", "end": "2013-08-09 10:21:00.501157", "item": "", "rc": 1, "start": "2013-08-09 10:21:00.486497"}
...ignoring

TASK: [import nginx repo key] ************************************************* 
changed: [cent6.4]
```

インストール済みの場合の実行結果は以下のようになります。

```
TASK: [check nginx repo key is imported] ************************************** 
changed: [cent6.4]

TASK: [import nginx repo key] ************************************************* 
skipping: [cent6.4]
```

なお、rpmのkeyのインストールには[rpm_key](http://docs.ansible.com/rpm_key_module.html)というモジュールがあるらしいのですが、Ansibleのバージョン1.3以降が必要とのことです。現時点でepelからインストールすると1.2.2なので上記のように自前でrpmコマンドで対応しています。

## (別解1) echo $?で終了コードを出力して条件分岐する方法

上の方法だと終了ステータスがエラー(0以外の場合)はfailedの後に...ignoringと出て、failedのログは赤字で表示されるので実行失敗かと一瞬焦ってしまいます。

[Register Variables](http://docs.ansible.com/playbooks_conditionals.html#register-variables)を見ると、シェルの実行ステータスだけではなく標準出力に出力した内容も取得できることがわかりました。

そこで、shellのコマンドに; echo $?をつけておいて、whenのほうはresult.stdout != '0'のように条件式を書くことでコマンドの結果に応じて分岐出来ました。

```yaml
- name: check nginx repo key is imported
  shell: | 
    rpm -qi gpg-pubkey-* | grep -q '^Summary     : gpg(nginx signing key <signing-key@nginx.com>)$'; echo $?
  register: result
- name: import nginx repo key
  command: rpm --import http://nginx.org/keys/nginx_signing.key
  when: result.stdout != '0'
```

ログは以下のようになり、安心して見られるようになりました。

実際にインポートした場合のログ。

```
TASK: [check nginx repo key is imported] ************************************** 
changed: [cent64]

TASK: [import nginx repo key] ************************************************* 
changed: [cent64]
```

インポート済みだったので何もしなかった場合のログ。

```
TASK: [check nginx repo key is imported] ************************************** 
changed: [cent64]

TASK: [import nginx repo key] ************************************************* 
skipping: [cent64]
```

## (別解2) Ansibleのconditional executionの仕組みを使わずにシェルスクリプトで条件分岐する方法

以下のようにシェルスクリプトで条件分岐しても同じ事は実現できます。

```yaml:
- name: check nginx repo key is imported
  shell: |
    if ! rpm -qi gpg-pubkey-* | grep -q '^Summary     : gpg(nginx signing key <signing-key@nginx.com>)$'; then
      rpm --import http://nginx.org/keys/nginx_signing.key
    fi
```

ただ、この方法だと実行結果を見ても、今回インストールしたかどうかはわからないです。