如何使用Chef懒惰地评估任意变量

时间:2013-12-16 20:55:23

标签: ruby variables chef chef-recipe

我正在编写一个Chef配方来安装我们的应用程序代码并执行它。配方需要特别关注此代码最终的目录(用于运行模板,设置日志转发等)。因此,目录本身会在不同的食谱中弹出很多地方。

我正在尝试获取/定义变量,因此我可以在我的资源块中使用字符串插值重新使用它。这非常简单:

home = node['etc']['passwd'][node['nodejs']['user']]['dir']

使用示例用法运行npm install,同时告诉它在主目录中插入repo下载,如下所示:

execute "npm install" do
  command "npm install #{prefix}#{app} --prefix #{home}"
end

除了定义home变量的第一个块将在编译时运行。在新的服务器上,我的nodejs用户帐户可能尚不存在,这是一个问题,给出了

NoMethodError undefined method '[]' for nil:NilClass

我有一些解决方法,但我想要一个特定的解决方案,使 home 变量只能在配方执行时获取,而不是在编译时获取。


解决方法1

动态评估ruby块内的home变量,如下所示:

ruby_block "fetch home dir" do
  block do
    home = node['etc']['passwd'][node['nodejs']['user']]['dir']
  end
end

这似乎不起作用,当您尝试执行以下操作时,为Chef :: Resource :: Directory 提供 NoMethodError未定义方法主页:

directory ".npm" do
  path "#{home}/.npm"
end

我觉得我必须在这里做错事。

解决方法2

懒惰地评估每个需要它的资源的参数。所以请这样做:

directory ".npm" do
  path lazy "#{node['etc']['passwd'][node['nodejs']['user']]['dir']}/.npm"
end

但是,只需要维护一行代码,将其存储在变量中并完成它就会非常棒。

解决方法3

在编译时创建用户。这当然可以使用notify trick linked here,如下所示:

u = user node['nodejs']['user'] do
  comment "The #{node['nodejs']['user']} is the user we want all our nodejs apps will run under."
  username node['nodejs']['user']
  home "/home/#{node['nodejs']['user']}"
end

u.run_action(:create)

这完全解决了我的问题,但是在其他情况下我可以想象想要延迟评估变量的能力,所以我让我的问题保持不变。

我想要什么

我真的希望能够做到

home lazy = node['etc']['passwd'][node['nodejs']['user']]['dir']

但这不是合法的语法,给出 NameError无法在ubuntu版本13.10上找到home的资源(这是一个奇怪的语法错误,但无论如何)。有没有合法的方法来实现这个目标?

3 个答案:

答案 0 :(得分:18)

我没有测试过这个特殊的代码,但我在cookbook中做了类似的事情,并使用lambda来推迟评估,如下所示:

home = lambda {node['etc']['passwd'][node['nodejs']['user']]['dir']}

execute "npm install" do
  command "npm install #{prefix}#{app} --prefix #{home.call}"
end

答案 1 :(得分:1)

对于ruby_block,块中的任何变量都需要是全局的,因为块中定义的任何变量都是本地变量。

您无法在库中使用lambda延迟执行,因此ruby_block在这种情况下效果很好。

答案 2 :(得分:1)

@thoughtcroft回答不适合我在chef-client 12.8.1

在这种情况下,我将所需的代码放入自定义资源中,并使用惰性属性调用它。

mycookbook_myresource "name" do
  attribute lazy { myvar }
end

不是优雅的解决方案,但它对我有用。