7

我想向您展示我的用例,然后讨论可能的解决方案:

问题 A:我有 2 个配方,“a”和“b”。“a”在我的文件系统上安装了一些程序(比如在“/usr/local/bin/stuff.sh”和配方“b”需要运行这并对输出做一些事情。

所以配方“a”看起来像:

execute "echo 'echo stuff' > /usr/local/bin/stuff.sh" 

(脚本只是将“stuff”回显到标准输出)

配方“b”看起来像:

include_recipe "a"
var=`/usr/local/bin/stuff.sh` 

(注意反引号,var应该包含stuff

现在我需要用它做点什么,例如用这个用户名创建一个用户。所以在脚本“b”我添加

user "#{node[:var]}"

碰巧,这不起作用..显然厨师运行所有不是资源的东西,然后才运行资源,所以一旦我运行脚本厨师抱怨它无法编译,因为它首先尝试运行“var = ...” 配方“b”中的行并失败,因为配方 a 中的“执行 ...”尚未运行,因此“stuff.sh”脚本尚不存在。不用说,这非常烦人,因为它打破了我在开始使用它时承诺的“厨师从上到下按顺序运行一切”。但是,我不是很挑剔,所以我开始寻找这个问题的替代解决方案,所以:

问题 B:我遇到过“ruby_block”的想法。显然,这是一种资源,因此将与其他资源一起评估。我说好的,然后我想创建脚本,在“ruby_block”中获取输出,然后将其传递给“用户”。所以配方“b”现在看起来像:

include_recipe "a"

ruby_block "a_block" do
  block do
    node.default[:var] = `/usr/local/bin/stuff.sh`
  end
end

user "#{node[:var]}"

然而,事实证明变量 ( var) 没有从“ruby_block”传递到“user”,它仍然是空的。无论我试图用它做什么杂耍我都失败了(或者我只是没有找到正确的杂耍方法)

致周围的厨师/红宝石大师:我如何解决问题 A?如何解决问题 B?

4

3 回答 3

6

您已经用 Ruby 块解决了问题 A。

现在你必须用类似的方法解决问题 B:

ruby_block "create user" do
  block do
    user = Chef::Resource::User.new(node[:var], run_context)
    user.shell '/bin/bash' # Set parameters using this syntax
    user.run_action :create
    user.run_action :manage # Run multiple actions (if needed) by declaring them sequentially
  end
end

您还可以通过在编译阶段创建文件来解决问题 A:

execute "echo 'echo stuff' > /usr/local/bin/stuff.sh" do
  action :nothing
end.run_action(:run)

如果遵循此操作过程,请确保:

  • /usr/local/bin在 Chef 的编译阶段存在;
  • 任何一个:
    • stuff.sh是可执行的;或者
    • 通过外壳执行它(例如:var=`sh /usr/local/bin/stuff.sh`
于 2013-07-18T13:26:50.293 回答
1

执行此操作的现代方法是使用自定义资源:

在食谱/create_script/resources/create_script.rb

provides :create_script
unified_mode true

property :script_name, :name_property: true

action :run do
  execute "creating #{script_name}" do
    command "echo 'echo stuff' > #{script_name}"
    not_if { File.exist?(script_name) }
  end
end

然后在配方代码中:

create_script "/usr/local/bin/stuff.sh"

对于所写的第二种情况,我将完全避免使用节点变量:

script_location = "/usr/local/bin/stuff.sh"

create_script script_location

# note: the user resources takes a username not a file path so the example is a bit
# strange, but that is the way the question was asked.
user script_location 

如果您需要将它移动到一个属性中并从不同的配方中调用它,那么就不需要 ruby​​_blocks 或lazy:

一些食谱的属性/default.rb 文件(或策略文件等):

default['script_location'] = "/usr/local/bin/stuff.sh"

在配方代码或其他自定义资源中:

create_script node['script_location']

user node['script_location']

没有必要偷懒或使用 ruby​​_block 使用这种方法。

于 2020-08-20T22:50:45.103 回答
0

实际上有几种方法可以解决您遇到的问题。

第一种方法是避免您在传递的块中遇到的范围问题并执行类似的操作。

include_recipe "a"
this = self

ruby_block "a_block" do
  block do
    this.user `/usr/local/bin/stuff.sh`
  end
end

假设您计划只使用一次,那会很好用。但是,如果您合法地需要在节点上存储一个变量以供其他用途,您可以依靠 ruby​​ 内部的惰性调用来解决这个问题。

include_recipe "a"

ruby_block "a_block" do
  block do
    node.default[:var] = `/usr/local/bin/stuff.sh`.strip
  end
end

user do
    username lazy { "#{node[:var]}" }
 end

您会很快注意到 Chef 对此类情况的所有默认假设都有覆盖。

于 2020-03-27T22:33:12.860 回答