よくよく考えてみると当たり前なのですが、案外ハマる可能性があるかと思ったので共有しておきます。
Chef では、execute
リソースや script
リソースなどで、どうしても独自でスクリプトを動かしたいときがあると思います。その場合、冪等性は保証されないので、自分でがんばる必要があります。
たとえば、/tmp/to_be_appended
を /etc/whatever.cfg
に追記するという処理をレシピに入れたいとします。実行するたびに追記されたら困るので、追記した内容のうち目印となる文字列を grep してなければ追加する、という条件をいれます。ここでは、追記するファイルに # ADDED
があるとします。そこで、最初、私はこういう書き方をしました。
execute "Add a content of /tmp/to_be_appended to /etc/whatever.cfg" do
command "cat /tmp/to_be_appended >> /etc/whatever.cfg"
not_if { "grep '# ADDED' /etc/whatever.cfg" }
end
これが動かなくてハマりました。先に答えを言いますと、
execute "Add a content of /tmp/to_be_appended to /etc/whatever.cfg" do
command "cat /tmp/to_be_appended >> /etc/whatever.cfg"
not_if "grep '# ADDED' /etc/whatever.cfg"
end
が正解となります。 大事なのはnot_if
の後ろの{``}
です。 only_if
と not_if
はブロックも文字列も引数としてとることができます。しかし当然のことながら動きが違うわけです。整理しますと、
- ブロックの場合は、中身を評価した結果
- 文字列の場合は、文字列をシェルで実行してその結果(
0
が成功、それ以外が失敗)
が渡されます。ですので、
only_if { File.exists?("/path/to/must_exist") }
や
only_if "grep httpd /etc/password"
のように使うのが正しい使い方です。
ですので、一番最初に書いたような
only_if { "grep something /path/to" }
としてしまうと、ブロック内は文字列であるため常に true
となってしまいます。これをやってしまうと、only_if
だと常に実行され、not_if
だと全く実行されません。気をつけましょう。
ああ恥ずかしい。