LoginSignup
1
0

More than 5 years have passed since last update.

Chefで、Ruby実行時とリソース実行時の変数の値の差を抑えるには、イテレータで変数として渡された値を使うと容易

Last updated at Posted at 2018-06-11

fileリソースでのcontentに対するlazy指定

個人的には、その前のリソースで既に編集されている可能性があるファイルを編集する際には、fileリソースでcontent lazy { } をよく使う。
(lazy指定が無いと、編集対象が、他リソース未適用のファイル内容となってしまう。)

recipes/default.rb


file '/tmp/test.txt' do
  content lazy {

    # 何らかの文字列を返す処理
    `cat #{path} | sed -e 's/^AAA=.*$/AAA=true/'`

  }
end

この例では、ファイルの内容に対して、sedにて編集を行なっている

Ruby実行時とリソース実行時のズレによる問題の例

ここで、このcontent lazy { } の中に値を渡す時には、Ruby実行時とリソース実行時のズレを考慮しないと問題となりうる。

recipes/default.rb

val = 'true'

file '/tmp/test.txt' do
  content lazy {

    # 何らかの文字列を返す処理
    `cat #{path} | sed -e 's/^AAA=.*$/AAA=#{val}/'`  # この#{val}の値は?

  }
end

...

val = 'false' # 別の処理でvalに'false'を設定して使用

...

適用時には、どの様にリソースを実行するのかを決める為にまずRubyのプログラムとして実行され、その後、その結果に基づいてリソースの反映が行われる。
しかし、lazy指定箇所はリソース反映時に処理される。その為、この例の場合、#{val}にはRuby実行終了時点で設定されている値、つまり'false'が使用されてしまう。

簡単な対応方法

イテレータでブロックに渡される変数を使う

recipes/default.rb

node.default['file_edit']['AAA'] = 'true'

node['file_edit'].each do |key, val|
  file '/tmp/test.txt' do
    content lazy {

      # 何らかの文字列を返す処理
      `cat #{path} | sed -e 's/^#{key}=.*$/#{key}=#{val}/'`

    }
  end
end

...

val = 'false' # 別の処理でvalに'false'を設定して使用

...


これなら、最初のvalは.eachのブロック内でのみ有効なので、#{val}には'true'が設定される。
(ついでにkey部分も汎用化)

蛇足 : 汎用的な対応???

イテレーターへの値渡し以外では、


# NG
begin

  ...

end


# NG
1.times {

  ...

}


# OK イテレータへの値渡しそのもの
[val].each do |val|

  ...

end


# OK やりすぎ感
def file_tmp_test_txt(val)

  ...

end

file_tmp_test_txt(val)


予想外にも、あまり綺麗な方法は見つかっていない。

1
0
0

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
1
0