Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chef Recipes - Setting node attributes in ruby_block

I have a Chef recipe for a multi-node web service, each node of which needs to get the hostname and IP of the other nodes, to put it into its own local configuration.

The code is shown below. The problem is that when the node.set[][] assignments are made in the ruby_block as shown, the values are empty when the template that relies upon them is created. If I want to create that template, I have to move all of the ruby_block code outside, and have it "loose" in the recipe. Which makes it harder to do unit-testing with Chefspec and the like.

Can any Chef guru set me straight? Is it just impossible to do node.set[] like this inside of a ruby_block? And if so, why doesn't it say so in the docs?

$cm = { :name => "web", :hostname => "" , :ip_addr => "" }
$ca = { :name => "data", :hostname => "" , :ip_addr => "" }
$cg = { :name => "gateway", :hostname => "" , :ip_addr => "" }
$component_list = [$cm, $ca, $cg]

ruby_block "get host addresses" do
  block do
    for cmpnt in $component_list
       # do REST calls to external service to get cmpnt.hostname, ip_addr
       # .......
       node.set[cmpnt.name]['name'] = cmpnt.name
       node.set[cmpnt.name]['host'] = cmpnt.hostname
       node.set[cmpnt.name]['ip'] = cmpnt.ip_addr   
    end
  end
end

template "/etc/app/configuration/config.xml" do
  source "config.xml.erb"
  variables( :dataHost => node['data']['host'],
       :webHost =>  node['web']['host'],
       :gatewayHost =>  node['gateway']['host'] )
  action :create
end

I also added

  subscribes  :create, "ruby_block[get host addresses]", :immediately

to the template definition to ensure that the ruby_block ran before the template was created. This didn't make a difference.

like image 484
danzvash Avatar asked Apr 04 '13 16:04

danzvash


1 Answers

I realize this is an old post, however for future reference, I just ran across this gist which gives a nice example of node variable assignments in the Compile vs. Converge phases. To adapt the gist to your example, you'll need to add code like the following to your ruby_block:

       template_r = run_context.resource_collection.find(:template => "/etc/app/configuration/config.xml")

       template_r.content node['data']['host']
       template_r.content node['web']['host']
       template_r.content node['gateway']['host']

For Chef 11, also see Lazy Attribute Evaluation.

like image 179
Alan Avatar answered Oct 03 '22 06:10

Alan