我有一些基于搜索设置节点属性的代码。然后我想在模板中使用这些属性。看来模板是在我计算出值的代码之前编译的。所以需要运行 2 次 chef-client 才能达到我想要的状态
if !node['foo']
search(:node, "recipes:bla").each do |bla|
if bla['bla'] > node['foo']
node['foo'] = bla['bla']
end
end
end
template "/tm/foo" do
source "foo"
end
我已经尝试将此代码放在模板之前和之后的配方中,以及属性文件中。我认为没有search
动作,否则我可以尝试使用 .run_action() 。
有什么方法node['foo']
可以设置要设置的值,以便在模板中使用它?
编辑:澄清
cook_a/attributes/default.rb
default['cook_a']['val_1'] = node['someval']
cook_a/recipes/default.rb
template "/etc/cook_a.conf" do
source "cook_a.conf.erb"
end
cook_a/templates/default/cook_a.conf.erb
some_var = <% node['cook_a']['val_1'] %>
现在在另一本食谱中,我将覆盖该值
coob_b/recipes/default.rb
node.set['someval'] = "foo"
include "cook_a"
但是现在更改为时已晚,因此模板在第一次运行期间node['cook_a']['val_1']
写入原始值。node['someval']
在第二次运行期间,我得到了正确的值。
我不愿意设置node['cook_a']['val_1']
,因为该名称可能会更改,并且我正在尝试从 cook_a 的细节中抽象出来。
这有点难以理解,由于过度使用
bla
,并且缺少模板使用的内容。假设模板中包含类似于以下内容的语句:
并且您没有
node['foo']
在模板中获得覆盖的值(这似乎是需要的bla['bla']
?)我有几种方法可以解决这个问题。node['foo']
当试图替换没有属性优先级的配方中的值时,Chef 实际上应该警告您。因此,在您的配方中,您可以更改该方法以
node.default['foo'] = ...
在显式属性级别设置结果。将 node 属性扩展为 Ruby 变量,并将其显式传递给模板,以防止覆盖和编译时间与渲染时间冲突。
这看起来像这样:
模板将变为:
还有其他编写条件逻辑的方法,但总的来说,这意味着我们在配方中扩展节点属性,并且只将我们想要的变量传递给模板,而不是更多的节点属性。
最后,我与这个秘诀有关的一点是,搜索的条件是
node['foo']
返回一个 nil 值,然后在赋值块中使用相同的已知 nil 值作为比较。我认为这并没有多大作用,好像进入块一样,它总是为零,因此比较没有多大作用。编辑:
问题后澄清,如前所述,我相信您遇到了编译时间与渲染时间属性评估的“鸡和蛋”问题。
在第二次运行期间检索到正确值的唯一原因是由于将
node.set
属性保存在 Chef 服务器上的节点对象本身中的操作,这意味着在属性中设置任何内容或稍后在任何地方覆盖都无关紧要,因为节点属性通常会赢得这些,因为它是最明确的。请注意如何设置以及如何删除它们 - 如果滥用它们可能会导致混乱。阅读Attribute Precedence。
关于你的属性。
属性文件是按照依赖关系和词法排序的顺序加载的,所以cook_b总是在cook_a之后被评估,你最好把它
node.set
作为一个属性移动到cook_b的attributes/default.rboverride
,并确保属性文件正确加载命令。您可能还想尝试在呈现模板时强制属性进行惰性评估,如下所示:
cook_a/recipes/default.rb
cook_a/templates/default/cook_a.conf.erb
更多关于惰性属性评估的信息。