如何在Chef配方的ruby_block中使用include_recipe

7
我有一个方案,在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放在该块之外作为下一步。 - WBAR
2
这样做不行。include_recipe将在编译阶段实例化,并使用默认的basic_auth_username和basic_auth_password值。在收敛阶段,ruby_block将被执行并设置这些值,但对included_recipe没有影响。 - JoseOlcese
当您按照当前代码运行时会发生什么?它是否会抛出错误?您可能需要将Chef配方代码包含到您的Ruby块中。 - Tejay Cardon
@JoseOlcese,您能接受我的答案吗? - manoelhc
3个回答

14

如果要在 ruby_block 中包含一个配方(recipe),必须使用 run_context 调用它。

例如:

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

你能解释一下你的答案吗? - Zulu
1
要在ruby_block中包含一个recipe,你必须使用run_context来调用它。 - manoelhc
在答案本身中,这样更好 ;) - Zulu

1
你可以从 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没有影响。 - JoseOlcese
哦,我明白了,我找到了这个 https://gist.github.com/arangamani/4659646 它似乎与你的问题有关。 - rastasheep
惰性属性评估也是一个很好的选择 https://docs.chef.io/resource_common.html#lazy-attribute-evaluation - rastasheep
问题在于我不应该修改“kibana”配方来指定惰性属性,无论在哪里使用它,也不需要知道内部情况才能使用run_context.resource_collection.find(...)。配方应该是独立的。 - JoseOlcese

0

看起来问题在于kibana cookbook有一个默认的recipe,它在使用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'

如果 Chef 本身负责生成 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'

即使当前有一个创建baselogging.json的remote_file资源,你最好做这样的事情:

# "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 {}会导致越来越多的惰性操作,如果你在控制范围之外使用烹饪书,则变得越来越丑陋。整个问题有很多“代码异味”,强制推迟事情的发生时间会导致与架构的设计相抵触。最好回过头来重新审视你的假设,以便在chef运行中推进更多的工作。
通常,您会尝试在属性文件解析阶段编译节点属性中的所有信息。在配方代码中设置属性会导致像这样的问题,并最终导致您希望提交PR以使它们使用的所有属性都变为惰性。使用基于资源驱动的库烹饪书而不是基于属性和配方驱动的库烹饪书可以帮助避免整个过程。除此之外,您应该尽早组装节点数据,以便您不必惰性访问节点数据。
如果您必须在配方代码中构建节点数据,则必须在编译时构建该数据。试图在配方收敛时间设置节点数据是您已经有点迷失的症状。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接