LoginSignup
14

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-01-24

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

おわりに

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

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
14