Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to require my library in chef ruby_block

I'm developing a cookbook to deploy a simple ROR application. I write an app_helper.rb and put it into the libraries directory of my cookbook, here is the content:

module AppHelper

    def self.find_gem
      if File.exists?("/usr/local/rvm/bin/rvm")
        return `/usr/local/rvm/bin/rvm default exec which gem`.chomp
      else
        return "/usr/bin/gem"
      end
    end
  end

In the recipes/default.rb, I mix in the above module into Chef::Recipe class

class Chef::Recipe
  include AppHelper
end

As you know, the find_gem function can be called from anywhere of the recipe.

when I'm trying to use the find_gem function in my ruby_block like this:

ruby_block "find gem" do
   block do
    gem_bin = Chef::Recipe::find_gem
    # or gem_bin = find_gem
  end
end

I got a NoMethodError: undefined method 'find_gem'.

Also try to mix in the module into Chef::Resource::RubyBlock, it doesn't work neither.

class Chef::Resource::RubyBlock
  include AppHelper
end

ruby_block "find gem" do
   block do
    gem_bin = Chef::Resource::RubyBlock::find_gem
    # or gem_bin = find_gem
  end
end

Is there any way to call the function in the module from the ruby_block? Or Is there an variable of chef to location the files in the libraries, so that I can be able to require the module in the ruby_block.

Thanks!

like image 770
Xiaoming Avatar asked Dec 30 '13 08:12

Xiaoming


1 Answers

Depending on load order, you might be including your module into an anonymous Ruby class instead of what you think.

If you want to use your method in a recipe, do this at the top of your recipe:

include AppHelper

You could alternatively use :send at the end of your library:

Chef::Recipe.send(:include, AppHelper)

This is different because it will raise an exception if Chef::Recipe is not defined (whereas you are creating a new class if it doesn't exist).

That's all you should need to do unless you want to use the helper in not_if and only_if guards. Then you need to include the helper in the resource:

Chef::Resource.send(:include, AppHelper)

Okay, now that I explained all of that, it won't actually help you. The Ruby Block provider simply calls the block - it doesn't instance eval it. So including the helper in the resource doesn't do anything.

So, you'll need to use a singleton object in this instance (it's the only solution I can reliably think of). The way you've defined your method, you can call it directly from the global namespace:

AppHelper.find_gem('...')

So:

ruby_block "find gem" do
  block do
    gem_bin = AppHelper.find_gem('...')
  end
end
like image 129
sethvargo Avatar answered Nov 11 '22 15:11

sethvargo