Edited at

chef の ruby_block 内でリソースを実行する

More than 1 year has passed since last update.

ruby コードを Compile フェーズではなく、Convergence フェーズで実行したい場合は、ruby_block リソースを利用することができる。cf. Chefのレシピは上から下に実行されるという誤解

さて、ruby_block リソース中で ruby の実行結果を元に他のリソースを実行したい場合にどのように書けば良いか。


やり方

以下のように書けばできる。


recipes/default.rb

recipe = self

ruby_block "foo" do
block do
contents = File.read("/tmp/foo")
recipe.log "foo" do
message contents
end
end
end


block ブロックの中では、log などのリソースメソッドが生えていない(スコープが違う)ので、リソースメソッドを持っているレシピオブジェクトを ローカル変数(ここでは recipe)に格納しておいて呼び出している。


何に使うか

例えば、


  1. remote_directory で指定ディレクトリ以下のサブディレクトリを全て転送

  2. remote_directory で転送したサブディレクトリ全てに対して(この情報の取得が Compile フェーズではできない)、/service 以下にシンボリックリンクを貼る

みたいな daemontools でサービス管理している場合にうれしそうな処理ができる。こんな感じ。


recipes/default.rb

recipe = self

remote_directory "/home/sonots/service" do
source "service"
mode "0755"
end

ruby_block "link for daemontools" do
block do
dirs = Dir::glob("/home/sonots/service/*")
dirs.each do |dir|
recipe.link "/service/#{File.basename(dir)}" do
to dir
end
end
end
end



他のやり方

今回のサンプルコードの要件であれば、逆に remote_directory リソースを Compile フェーズで実行させて満たすこともできる。run_action を使えば Compile フェーズで実行させることができるので、次のように書くこともできそう。でも、自分はやはり Convergence フェーズで実行させたいなぁ。


recipes/default.rb

remote_directory "/home/sonots/service" do

source "service"
mode "0755"
end.run_action(:create)

dirs = Dir::glob("/home/sonots/service/*")
dirs.each do |dir|
link "/service/#{File.basename(dir)}" do
to dir
end
end



おわりに

読みにくくなるので良い子は真似しない方がよいと思う。