2013-04-04 134 views
4

我有一个多节点Web服务的厨师食谱,其中的每个节点需要获取其他节点的主机名和IP,以将其放入其自己的本地配置中。厨师食谱 - 在ruby_block中设置节点属性

代码如下所示。问题在于,如图所示,在ruby_block中进行node.set [] []赋值时,创建依赖于它们的模板时,值为空。如果我想创建这个模板,我必须将所有的ruby_block代码移到外面,并且让它在配方中“松散”。这使得用Chefspec等进行单元测试变得更加困难。

任何厨师大师都可以让我变直吗?在ruby_block中,像这样做node.set []是不可能的吗?如果是这样,为什么没有在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 

这么说我还添加了

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

的模板定义,以确保创建模板之前的ruby_block跑。这没有什么区别。

回答

2

问题似乎是在实际调用任何资源之前,您的模板资源定义中的属性值得到评估。 也就是说该文件首先作为简单的Ruby执行,编译资源,并且只有资源操作被调用。那时已经太迟了。 当试图将某些属性操作封装到资源中时遇到了同样的问题。它根本不起作用。如果有人知道这个问题的解决方案,我会非常感激。

编辑:

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

能可能做的伎俩。它立即调用资源。

5

我意识到这是一个旧帖子,但是为了将来的参考,我只是碰到了this gist,它给出了编译阶段和收敛阶段中节点变量赋值的一个很好的例子。为了要点适应你的榜样,你需要添加像下面这样的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'] 

对于厨师11,也看Lazy Attribute Evaluation

0

它一直以来这个问题一段时间,但万一有人还在寻找它,懒惰评估是你的朋友:

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