我有一些代码可以根据搜索设置节点属性。然后我想在模板中使用这些属性。看来模板是在我计算出值的代码之前编译的。因此需要运行 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/属性/默认.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/模板/默认/cook_a.conf.erb
some_var = <% node['cook_a']['val_1'] %>
现在在另一本食谱中,我覆盖了该值
coob_b/recipes/默认.rb
node.set['someval'] = "foo"
include "cook_a"
但现在更改已经太晚了node['cook_a']['val_1']
,所以模板node['someval']
在第一次运行期间写入了原始值。在第二次运行期间,我得到了正确的值。
我不愿意设置,node['cook_a']['val_1']
因为这个名字可能会改变,而且我正试图从 cook_a 的细节中抽象出来。
答案1
这有点难以理解,因为过度使用bla
,并且缺少模板所使用的内容。
假设模板中包含类似于以下内容的语句:
somevalue = <%= node['foo'] %>
并且您没有node['foo']
在模板中获得覆盖的值(这似乎是所希望的bla['bla']
?)我可以通过几种方式来解决这个问题。
node['foo']
当您尝试替换没有属性优先级的配方中的值时,Chef 实际上应该会向您发出警告。Chef::Exceptions::ImmutableAttributeModification: Node attributes are read-only when you do not specify which precedence level to set. To set an attribute use code like `node.default["key"] = "value"'
因此,在您的配方中,您可以改变该方法以
node.default['foo'] = ...
在明确的属性级别设置结果。将节点属性扩展为 Ruby 变量,并将其明确传递给模板,以防止覆盖和编译时与渲染时冲突。
这看起来像这样:
if !node['foo'] search(:node, "recipes:bla").each do |bla| if bla['bla'] > node['foo'] node_foo = bla['bla'] end end end template "/tmp/foo" do source "foo" variables( node_foo: node_foo || node['foo'] ) end
并且模板将变为如下样子:
somevalue = <%= @node_foo %>
还有其他方法可以编写条件逻辑,但总的来说,这意味着我们在配方中扩展节点属性,并且只将我们想要的变量传递给模板,而不是更多的节点属性。
最后,这个配方让我担心的是,搜索的条件是node['foo']
返回一个 nil 值,然后在赋值块中使用相同的已知 nil 值作为比较。我认为这没什么用,因为进入块后,它总是 nil,因此比较没什么用。
编辑:
问题澄清后,我相信您在编译时与渲染时属性评估中遇到了“先有鸡还是先有蛋”的问题,如前所述。
在第二次运行期间检索到正确值的唯一原因是由于node.set
在 Chef Server 上的节点对象本身中保存属性的操作,这意味着设置任何事物在属性中或在任何地方的覆盖都无关紧要,因为节点属性通常会赢得这些,因为它是最明确的。
请注意这些设置方法以及如何删除它们 - 如果滥用它们,可能会造成混乱。阅读属性优先级。
关于你的属性。
属性文件是按照依赖关系和词汇排序的顺序加载的,因此 cook_b 总是在 cook_a 之后进行评估,并且您最好将其移动node.set
到 cook_b 的 attribute/default.rb 作为override
属性,并确保属性文件按正确的顺序加载。
您可能还想尝试在渲染模板时强制对属性进行延迟评估,如下所示:
cook_a/recipes/default.rb
template "/etc/cook_a.conf" do
source "cook_a.conf.erb"
variables lazy {
{ some_var: node['cook_a']['val_1'] }
}
end
cook_a/模板/默认/cook_a.conf.erb
some_var = <%= @some_var %>
有关惰性属性评估的更多信息这里。