command
やshell
モジュール使用時の冪等性の処理に「事前チェックtaskを実行、結果をregister
で保持、その内容を使ってwhen
でガード」ってよくするけど、ファイルの有無程度であれば標準機能でカバーできる。
(command
の結果ファイルを生成するような処理の場合、そのファイルが作成済みであればスルーする、など)
以下すべてcommand
の例だけど、shell
も同じ動作。
確認した環境は以下の通り。
[zaki@cloud-dev ansible-work]$ cat /etc/redhat-release CentOS Linux release 7.8.2003 (Core) [zaki@cloud-dev ansible-work]$ ansible-playbook --version ansible-playbook 2.9.10 config file = None configured module search path = ['/home/zaki/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /home/zaki/.local/lib/python3.6/site-packages/ansible executable location = /usr/local/bin/ansible-playbook python version = 3.6.8 (default, Apr 2 2020, 13:34:55) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
書式
command:
の行に実行するコマンドを書かずに、cmd:
をパラメタとして渡すように書く。そこにcreates
やremoves
も追加する。
- name: mv file command: cmd: mv /tmp/zzz-src /tmp/zzz-dest removes: /tmp/zzz-src
以下のように書くとエラーになる。
- name: mv file command: mv /tmp/zzz-src /tmp/zzz-dest removes: /tmp/zzz-src
というかそもそもこれはYAML的に書式がおかしい。
command
というキーにmv ~~~
という値をセットいている以上、そのサブキー(なんて言うのが正しい?)は書けない。
あとドキュメントにも書かれている通り、以下のようにワイルドカードも使用可能。
shellの方には書かれてないけど、shell
でもワイルドカードは使えた。
- name: mv file shell: cmd: mv /tmp/zzz-src /tmp/zzz-dest removes: /tmp/zzz-sr*
A filename or (since 2.0) glob pattern
creates
- name: mv file command: cmd: mv /tmp/zzz-src /tmp/zzz-dest creates: /tmp/zzz-dest
これは、/tmp/zzz-dest
が作成済みであれば実行されない(ok
になる)
ok: [localhost] => changed=false cmd: - mv - /tmp/zzz-src - /tmp/zzz-dest rc: 0 stdout: skipped, since /tmp/zzz-dest exists stdout_lines: <omitted>
removes
- name: mv file command: cmd: mv /tmp/zzz-src /tmp/zzz-dest removes: /tmp/zzz-src
removesを使うと逆で、/tmp/zzz-src
が無い場合は実行されない
ok: [localhost] => changed=false cmd: - mv - /tmp/zzz-src - /tmp/zzz-dest rc: 0 stdout: skipped, since /tmp/zzz-src does not exist stdout_lines: <omitted>
同時指定
両方していするとどうなるか。
- name: mv file command: cmd: mv /tmp/zzz-src /tmp/zzz-dest creates: /tmp/zzz-dest removes: /tmp/zzz-src
# | src | dest | 動作 |
---|---|---|---|
1 | ない | ない | removes: /tmp/zzz-src の条件によりskip (1) |
2 | ある | ない | creates/removesの条件を満たさず、task動作 |
3 | ない | ある | creates: /tmp/zzz-dest の条件によりskip (2) |
4 | ある | ある | creates: /tmp/zzz-dest の条件によりskip (2) |
stdout: skipped, since /tmp/zzz-src does not exist
stdout: skipped, since /tmp/zzz-dest exists
#4
の動作を見る限り、内部処理でcreates
→removes
に評価していると思われる。
というかソース見るとそうなってる。
Ansible的には「どちらかでも条件を満たせばskip (評価順はcreates
->removes
)」となる。(ANDではなくOR)
例: 「ファイルを移動する」をこれ使って簡易的にやりたいとき
srcファイルが無い場合
通常は「エラー」じゃなくて「何もしない」を期待すると思うので、基本的に removes: /tmp/zzz-src
は大前提と考える。
これは #3
の場合でcreates
未指定であっても、removes: /tmp/zzz-src
を満たすので、「何もしない」動作になる。
destファイルが既にある場合
上記の表の#3
/#4
だが、#4
の「srcファイルが存在する場合」の実行は要件によって以下の2パターンが考えられる。
- destがあるなら無視
- srcがあるならdestを上書き
srcがあっても無視
これは上記表の#4
の動作の通り。
よって、creates
/removes
両方を指定する。
cmd: mv /tmp/zzz-src /tmp/zzz-dest removes: /tmp/zzz-src creates: /tmp/zzz-dest
srcがあるならdestを上書き
上記表#4
の条件時に、skipでなく実行させたいというパターン。
これはcreates
の定義を外せば要件を満たす。
creates
を条件に使用している#3
については、前述のsrcファイルが無い場合の通り、removes
の条件で同じ要件を満たすので問題ない。
よって、removes
のみ指定する。
cmd: mv /tmp/zzz-src /tmp/zzz-dest removes: /tmp/zzz-src
この場合の動作は
# | src | dest | 動作 |
---|---|---|---|
1 | ない | ない | removes: /tmp/zzz-src の条件によりskip |
2 | ある | ない | removesの条件を満たさず、task実行 |
3 | ない | ある | removes: /tmp/zzz-src の条件によりskip |
4 | ある | ある | removesの条件を満たさず、task実行 |
(余談)srcとdestに差異がある場合は上書き
cmd: mv
とcreates
/removes
の組み合わせじゃ無理なのでcopy
モジュールとか使うしかないかな?
この場合、「コピー」になるのでdestを上書きしてもsrcは残ったままなので消したい場合は工夫(changed
の場合のみ消すとか)が必要だけど。
もし「creates
とremoves
どっちがどの条件のときに動くのか動かないのかどっち?」と思った人は、Ansibleらしく「creates
/reomoves
の状態にする(その状態になってたら何もしない)」と覚えればOK