在厨师资源之间传递变量

时间:2013-07-17 10:11:22

标签: ruby variables chef chef-solo

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

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

所以食谱“a”看起来像:

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

(脚本只是回显“stdout”的东西)

和食谱“b”看起来像:

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

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

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

user "#{node[:var]}"

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

问题B:我遇到了“ruby_block”的想法。显然,这是一种资源,因此它将与其他资源一起进行评估。我说好了,然后我想创建脚本,在“ruby_block”中获取输出,然后将其传递给“user”。所以食谱“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?

3 个答案:

答案 0 :(得分: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)

如果遵循此行动方案,请确保:

    在Chef的编译阶段
  • /usr/local/bin存在;
  • 或者:
    • stuff.sh是可执行的; OR
    • 通过shell执行它(例如:var=`sh /usr/local/bin/stuff.sh`

答案 1 :(得分:1)

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

在Cookbooks / 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:

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

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

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

create_script node['script_location']

user node['script_location']

通过这种方法,无需懒惰或使用ruby_block。

答案 2 :(得分: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一起注意到,对于这种情况,它具有所有默认假设的替代。