我正在编写一个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变量只在配方执行时获取,而不是编译时.
动态评估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
我觉得我必须在这里做错事.
懒惰地评估每个需要它的资源的参数.所以改为:
directory ".npm" do path lazy "#{node['etc']['passwd'][node['nodejs']['user']]['dir']}/.npm" end
但是,只需要维护一行代码,将其存储在变量中并完成它就会非常棒.
在编译时创建用户.这当然有效,使用此处链接的通知技巧,如下所示:
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的资源(这是一个奇怪的语法错误,但无论如何).有没有合法的方法来实现这一目标?