私が歌川です

@utgwkk が書いている

Ansibleでitamaeのexecuteやnot_ifのようなことをする

さまざまな事情があって、Ansibleでシェルスクリプトを1つのtaskとして実行したくなったり、コマンドのreturn codeに応じて処理を分岐したりしたくなると思います。 itamaeなら executenot_if で実現できるのですが、同じことをAnsibleでやろうとして手間がかかったので記録しておきます。

シェルスクリプトを実行する

shell リソースでコマンドを実行することができます。 さらに、YAMLでは複数行の文字列を書くことができるので、次のように書くことができます。

- shell:
    VAR=`command_expand`
    command1;
    command2;
    command3

注意点としては、複数行のコマンドを入力しても一度に実行されるので、シェルスクリプトと異なりコマンド区切りの ; が必要です。 あまり検証していませんが、POSIXに準拠しているシェルスクリプトなら対応しているのではないでしょうか。

コマンドのreturn codeを取得する

shell リソースでコマンドを実行することができるので、その結果を変数に格納すればreturn codeが取れそうだなということをすぐに思いつくと思います。 たとえば次のように書けそうです。

- shell: which hoge
  register: check_result

しかしこれだけでは、 which hoge のreturn codeが0でない場合にfailになります。 この場合ではfailになりうることは分かっていて、我々はreturn codeを使って分岐したいのです。

ここではfailを無視するために ignore_errors: yes を追加します。

- shell: which hoge
  register: check_result
  ignore_errors: yes

これでめでたく which hoge のreturn codeを check_result.rc で取得できるようになりました、といきたいところですが、まだあります。

このtaskは、check modeのときは実行されません。 したがって check_result という変数が定義されないので、これ以降のtaskで check_result を参照するとエラーで落ちます(!)。

check_mode: no を追加してやればcheck modeでも実行が強制されるので、 check_result を参照できるようになります。

- shell: which hoge
  register: check_result
  ignore_errors: yes
  check_mode: no

組み合わせる

- shell: which hoge
  register: check_result
  ignore_errors: yes

- shell:
    VAR=`command_expand`
    command1;
    command2;
    command3
  when: check_result.rc != 0

これで executenot_if のようなことができるようになりました。よかったですね。もうちょっと楽に書けないものか。

参考