まずは結論から、例えば以下のようなタスクの場合、
- uname -a コマンドの結果を /tmp/hoge に出力する
- /tmp/hoge が既にあるなら実行しない
- コメントの通りファイルの存在確認なら stat モジュールで十分なのですが、より多くのケース(なにかしらのコマンドの結果を元に実行の有無を制御)を想定してあえて shell モジュールを使います
次のようにします。
- hosts: localhost
tasks:
- shell: test -e /tmp/hoge
register: res
always_run: yes
failed_when: no
changed_when: res.rc != 0
- shell: uname -a > /tmp/hoge
when: res|changed
これだけなら shell モジュールの creates を使うだけでいいんじゃない?
と思わなくもないですが、良いサンプルが思いつかなかったのでその辺は無視してください。
その1
単に uname -a の結果を /tmp/hoge に書くだけなら、何回実行しても結果は変わらないので次のようにしても大丈夫です。
- hosts: localhost
tasks:
- shell: uname -a > /tmp/hoge
その2
がしかし、これだと何回実行しても changed と表示されます。
せっかく Ansible を使うならその辺の表示もそれなりにしたいところです。
そこで、タスクを実行する必要があるかどうかを先行するタスクで確認する方法が考えられます。
- hosts: localhost
tasks:
- shell: test -e /tmp/hoge
register: res
failed_when: no
- shell: uname -a > /tmp/hoge
when: res.rc != 0
最初の test のタスクで /tmp/hoge が存在するかどうか確認し、その結果から次のタスクを実行するかどうかを when で分岐します。
その3
がしかし、これだと test の方のタスクが常に changed になってしまいます。
test のタスクはファイルの存在をチェックしているだけで実際にはなにもしないので、次のように changed_when
を追加して changed にならないようにします。
- hosts: localhost
tasks:
- shell: test -e /tmp/hoge
register: res
failed_when: no
changed_when: no
- shell: uname -a > /tmp/hoge
when: res.rc != 0
これで test のタスクは常に ok となります。
その4
がしかし、このプレイブックをチェックモード (--check|-C
) で実行すると失敗します。
チェックモードでは shell はスキップされるため、2番目のタスクの when で参照している res 変数が未定義になるためです。
そこで、次のように test のタスクに always_run
を追加してチェックモードでも実行されるようにします。
- hosts: localhost
tasks:
- shell: test -e /tmp/hoge
register: res
always_run: yes
failed_when: no
changed_when: no
- shell: uname -a > /tmp/hoge
when: res.rc != 0
これで test のタスクはチェックモードでも実行されるので、2番目のタスクで res 変数が未定義になることはありません。
その5
がしかし、このプレイブックを、/tmp/hoge が存在しない、かつ、チェックモード、で実行すると、changed が 0 件になります。2番目のタスクが when の条件に依らずチェックモードだとスキップされるためです。
プレイブックを実行する前に、なにかしらの変化があるかどうかを予め確認するためにチェックモードで実行することはあると思います。が、これではあたかもプレイブックを実行する必要が無いように感じてしまいます(実際には /tmp/hoge が作成されていないにも関わらず)。
そこで、2番目のタスクを実行する必要があるときには、1番目のタスクが changed になるようにします。
- hosts: localhost
tasks:
- shell: test -e /tmp/hoge
register: res
always_run: yes
failed_when: no
changed_when: res.rc != 0
- shell: uname -a > /tmp/hoge
when: res|changed
というわけで、最初に示した形になりました。
まとめ
整理すると・・・
- 実行の要否を判断するタスク
- test コマンドなどの実際にはなにも変化をもたらさないことだけやる
- チェックモードでも実行されるように
always_run
を指定する - 実行結果を
register
で変数に登録する - 終了コードが非ゼロでも失敗にならないように
failed_when
を指定する- 実行するコマンドによっては必要ない
- 例えば実行の要否を標準出力で判断する場合など
- 実行の要否を
changed_when
で指定する- 実行が必要な場合に changed にする
- 実際に処理するタスク
- 先行するタスクが changed のときだけ実行する
となります。