Chef recipes - setting node attributes in ruby_block

I have a chef recipe for a multi-node web service, each of which node must get the host name and IP of the other nodes in order to put it in its local configuration.

The code is shown below. The problem is that when assigning node.set [] [] to ruby_block, as shown, the values ​​are empty when a template is created that relies on them. If I want to create this template, I will have to move the entire ruby_block code outside, and it will be “free” in the recipe. This makes unit testing difficult with Chefspec, etc.

Can any chef ask me directly? Is it just impossible to make node.set [] like inside ruby_block? And if so, why doesn't he talk about it in 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 ruby_block works before creating the template. It didn’t matter.

+4
source share
3 answers

I understand that this is an old post, however, for future reference, I just stumbled upon this meaning , which gives a good example of node assignment variables in the compilation and conversion phases. To adapt the essence to your example, you need to add the following code 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 Evaluating a Lazy Attribute .

+5
source

The problem is that the attribute values ​​inside your template resource definition are evaluated before any resources are actually called. That is, the file is first executed as simple Ruby, compiling the resources, and only the actions of the resource are activated. By then it is too late. I encountered the same problem when trying to encapsulate certain manipulations with attributes in a resource. It just doesn't work. If anyone knows a solution to this problem, I would really appreciate it.

EDIT:

 b = ruby_block... ... end b.run_action(:create) 

Perhaps this trick. It immediately starts the resource.

+2
source

Some time has passed since this question, but if someone is still looking for it, lazy to evaluate - your friend:

 template '/tmp/sql_file.sql' do source "sql_file.sql.erb" mode 0700 variables lazy { # Create a new instance of MySQL library mysql_lib = Acx::MySQL.new( '127.0.0.1', 'root', node['mysql']['service']['pass'] ) password = node['mysql']['service']['support_admin']['ct_password'] # It returns the encrypted password after evaluate it, to # be used in template variables { admin_password: mysql_lib.encrypted_password(password) } } end 

https://docs.chef.io/resource_common.html#lazy-evaluation

0
source

All Articles