我正在写一个厨师食谱来安装我们的应用程序代码并执行它.该配方需要特别关于此代码最终的目录(运行模板,设置日志转发等).因此,目录本身在不同配方的很多地方弹出.
我试图获取/定义一个变量,所以我可以重新使用它在我的资源块与字符串插值.这很简单:
home = node['etc']['passwd'][node['nodejs']['user']]['dir']
以示例的用法来运行npm安装,同时告诉它在主目录中下载repo,如下所示:
execute "npm install" do command "npm install #{prefix}#{app} --prefix #{home}" end
除了定义home变量的第一个块将在编译时运行.在一个新的服务器上,我的nodejs用户帐户可能不存在,这是一个问题,给出了一个
NoMethodError undefined method '[]' for nil:NilClass
我有几个解决方法,但我想要一个具体的解决方案,使家庭变量只在食谱执行时,而不是编译时提取.
解决方法1
动态评估一个红宝石块内的home变量,就像这样:
ruby_block "fetch home dir" do block do home = node['etc']['passwd'][node['nodejs']['user']]['dir'] end end
这似乎实际上不起作用,当您尝试执行以下操作时,为Chef :: Resource :: Directory提供一个NoMethodError undefined方法:
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版找不到一个资源(这是一个奇怪的语法错误,但是无论如何).有没有法律的方式来实现这一点?
解决方法
我没有测试过这个特定的代码,但是我在烹饪书中做了类似的操作,并使用lambda来延迟评估,如下所示:
home = lambda {node['etc']['passwd'][node['nodejs']['user']]['dir']} execute "npm install" do command "npm install #{prefix}#{app} --prefix #{home.call}" end