编辑:澄清

编辑:澄清

我有一些代码可以根据搜索设置节点属性。然后我想在模板中使用这些属性。看来模板是在我计算出值的代码之前编译的。因此需要运行 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']?)我可以通过几种方式来解决这个问题。

  1. 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'] = ...在明确的属性级别设置结果。

  2. 将节点属性扩展为 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 %>

有关惰性属性评估的更多信息这里

相关内容