【问题标题】:How to include_recipe inside a ruby_block of a chef recipe如何在厨师食谱的 ruby​​_block 中包含_recipe
【发布时间】:2015-05-04 14:25:55
【问题描述】:

我有一个配方,它在 ruby​​_block 中设置了一个变量,并且需要将该变量用作配方的输入属性。 ruby_block 执行后如何使用 include_recipe?

谢谢

ruby_block "evaluate_config" do #~FC014
 block do

  file = File.read('/opt/config/baselogging.json')
  data = JSON.parse(file)

  node.default['kibana']['apache']['basic_auth_username'] = data['KibanaUser']
  node.default['kibana']['apache']['basic_auth_password'] = data['KibanaPassword']

  include_recipe 'kibana'

 end
end

【问题讨论】:

  • 请看加密数据包,里面有加密密码。 ruby_block 是在资源收集之后执行的代码的一部分,因此只需将 include_recipe 放在此块之外作为下一步。
  • 这行不通。 include_recipe 将在编译阶段被实例化,并且将使用默认的 basic_auth_username 和 basic_auth_password 值。在收敛阶段,将执行 ruby​​_block 并设置值,但不会影响 Included_recipe。
  • 按原样运行代码会发生什么?它会抛出错误吗?您可能需要将 Chef 配方代码包含到您的 ruby​​ 块中。
  • @JoseOlcese 你能接受我的回答吗?

标签: chef-infra chef-recipe


【解决方案1】:

要包含来自 ruby​​_block 的配方,您必须使用 run_context 调用它。

例如:

ruby_block "evaluate_config" do #~FC014
 block do
   ...
   #include_recipe 'kibana'
   run_context.include_recipe "cookbook::recipe"
 end
end

【讨论】:

  • 你能解释一下你的答案吗?
  • 要包含来自 ruby​​_block 的配方,您必须使用 run_context 调用它。
  • 就答案本身而言,它更好;)
【解决方案2】:

您可以从 ruby​​ 块中读取和设置属性,然后您可以包含如下配方:

ruby_block "evaluate_config" do #~FC014
 block do   
  file = File.read('/opt/config/baselogging.json')
  data = JSON.parse(file)

  node.set['kibana']['apache']['basic_auth_username'] = data['KibanaUser']
  node.set['kibana']['apache']['basic_auth_password'] = data['KibanaPassword']   
 end
end

include_recipe 'kibana'

【讨论】:

  • 这行不通。 include_recipe 将在编译阶段被实例化,并且将使用默认的 basic_auth_username 和 basic_auth_password 值。在收敛阶段,将执行 ruby​​_block 并设置值,但不会影响 Included_recipe。
  • 哦,我明白了,我找到了这个gist.github.com/arangamani/4659646,它似乎与你的问题有关
  • Lazya 属性评估也是不错的选择 docs.chef.io/resource_common.html#lazy-attribute-evaluation
  • 问题是我不应该修改 'kibana' 配方来指定一个惰性属性,无论它在哪里使用或知道内部使用 run_context.resource_collection.find(...)。食谱应该是独立的
【解决方案3】:

这里的问题似乎是 kibana 食谱有一个默认配方,它在使用 node['kibana']['apache']['basic_auth_username'] 和密码节点属性时没有 lazy {} 修饰符。

看起来这里有很多工作要做,以便懒惰一切并使用ruby_block,原因我不明白。更好的方法是不使用 ruby​​_block:

file = File.read('/opt/config/baselogging.json')
data = JSON.parse(file)

node.default['kibana']['apache']['basic_auth_username'] = data['KibanaUser']
node.default['kibana']['apache']['basic_auth_password'] = data['KibanaPassword']

include_recipe 'kibana'

如果厨师本身负责生成baselogging.json,而您尝试生成baselogging.json,然后从baselogging.json 中读取,我想出的解决方案是重构并删除它:

data = ... stuff to populate the data ...

file "/opt/config/baselogging.json" do
  content JSON.generate(data)
end

[...]

node.default['kibana']['apache']['basic_auth_username'] = data['KibanaUser']
node.default['kibana']['apache']['basic_auth_password'] = data['KibanaPassword']

include_recipe 'kibana'

即使当前某处有一个 remote_file 资源可以创建 baselogging.json,您最好还是这样做:

# "cheat" and download the file at compile-time
remote_file "/opt/config/baselogging.json" do
   source "http://example.org/baselogging.json"
   action :nothing
end.run_action(:create)

file = File.read('/opt/config/baselogging.json')
data = JSON.parse(file)

node.default['kibana']['apache']['basic_auth_username'] = data['KibanaUser']
node.default['kibana']['apache']['basic_auth_password'] = data['KibanaPassword']

include_recipe 'kibana'

这里更重要的一点是lazy {} 越来越多地为懒惰的行为制造了一场军备竞赛,如果你消费超出你控制范围的食谱,那么它会变得越来越丑陋。整个问题有很多“代码气味”,迫使事情在以后发生,最终导致与一切的架构方式作斗争。你最好回去重构你的假设,这样你就可以在主厨运行中推进更多工作。

一般来说,您会尝试在属性文件解析阶段编译节点属性中的所有信息。在菜谱代码中设置属性会导致类似这样的问题,最后你会发现自己想向现有的每本社区食谱提交 PR,以懒惰他们使用的所有属性。使用资源驱动的库说明书而不是属性和配方驱动程序库说明书可以帮助回避整个过程。除非您应该尽早组装节点数据,这样您就不必延迟对节点数据的所有访问。

如果您必须在配方代码中构造节点数据,那么您必须在编译时构造该数据。尝试在配方收敛时设置节点数据是您有点迷失的症状。

【讨论】:

    猜你喜欢
    • 2015-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多