52
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Chef の only_if / not_if でハマった。

Last updated at Posted at 2014-06-14

よくよく考えてみると当たり前なのですが、案外ハマる可能性があるかと思ったので共有しておきます。

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_ifnot_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 だと全く実行されません。気をつけましょう。

ああ恥ずかしい。

52
40
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?