Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

chef recipe - module methods not available within resources

Tags:

chef-infra

I extended the recipe class via a module to provide some properties which give me global access to my paths, which are dynamically constructed. Example:

module Variables
  def user
    "user_name"
  end
  def user_home
    "/home/#{node['user']}"
  end
end

class Chef::Recipe
  include Variables
end

The problem is, that within the resource blocks these methods are not available.

bash "do_something_with_property" do
  user user
  code "somecommand #{user_home}"
end

NoMethodError: undefined method `user_home' for Chef::Resource::Bash

The odd behavior is, that the user property works fine, but the a property used within the code block does not work.

After this I also included the module into all Resources by doing this:

class Chef::Resource
  include Variables
end

Now my user_home property behaves differently within resource blocks than when used "outside", meaning:

directory "#{user_home}/new_dir" do
  action :create
end

creates /home/user_name/new_dir

bash "create_dir" do
   code "mkdir #{user_home}/new_dir"
end

results in /home//new_dir

I have tested this with a little test-script and everything works fine.

module MyModule
def module_method
    puts "blablalba"
end
end

class A
def block_method (&block)
    block.call
end
end

class B
include MyModule

def doit
    a = A.new
    a.block_method { module_method }
end
end

B.new.doit

So to me it seems this must be a Chef-specific problem.

Can anyone explain me, why this is happening?

Is there a better solution for a global access to my paths and attributes which get build dynamically?

Thanks.

like image 782
DELUXEnized Avatar asked Nov 08 '12 13:11

DELUXEnized


1 Answers

I have had success injecting methods into the scope of a resource as follows:

libraries/helper.rb:

module MyCookbook
  module Helper
    def my_method
      "foobar"
    end
  end
end

Chef::Resource.send(:include, MyCookbook::Helper)

recipes/default.rb:

file 'foo' do
  content my_method
end

The key here is Chef::Resource.send(:include, ...) which injects your module directly into the Chef::Resource class, making your module methods available for all of your resources.

like image 167
jayhendren Avatar answered Oct 14 '22 23:10

jayhendren