9

我在厨师食谱上遇到了一些挑战。我是新来的厨师,所以请多多包涵。

第 1 步:我的主厨食谱安装了 Ruby Passenger,然后将 Passenger nginx 模块与 Nginx 一起编译。

# Install passenger and nginx module
bash "Install Passenger" do
  code <<-EOF
  source /usr/local/rvm/scripts/rvm
  gem install passenger
  EOF
  user "root"
  not_if { `gem list`.lines.grep(/^passenger \(.*\)/).count > 0 }
end

# Install passenger
# Note that we have to explicitly include the RVM script otherwise it won't setup the environment correctly
bash "Install passenger nginx module and nginx from source" do
  code <<-EOF
  source /usr/local/rvm/scripts/rvm
  passenger-install-nginx-module --auto --prefix=/opt/nginx --auto-download
  EOF
  user "root"
  not_if { File.directory? "/opt/nginx" }
end

第 2 步:之后,我使用模板创建 nginx 配置文件。此配置需要乘客的位置,这取决于步骤 1 的完成情况。

template "/opt/nginx/conf/nginx.conf" do
  source "nginx.conf.erb"
  action :create
  variables(
    deploy_user: deploy_user,
    passenger_root: `bash -c "source /usr/local/rvm/scripts/rvm; passenger-config --root"`.chomp,
    passenger_ruby: `bash -c "source /usr/local/rvm/scripts/rvm; which ruby"`.chomp,
    passenger: node[:passenger]
  )
end

问题:Chef 似乎在运行开始时编译模板。所以最终发生的是,步骤 2 实际上是在步骤 1 运行之前编译的。这意味着passenger_root 变量为空。它需要先完成第 1 步,然后才能获取passenger_root,然后运行模板。

我尝试将步骤 2 代码包装在 a 中,ruby_block但这不起作用:undefined methodChef::Resource::RubyBlock` 的模板'。

不知道在这里做什么,或者对于这样的事情,厨师的最佳做法是什么?

提前致谢,

伦纳德

4

3 回答 3

12

一种更简洁且推荐的方法是使用Lazy Attribute Evaluation

template "/opt/nginx/conf/nginx.conf" do
  source "nginx.conf.erb"
  action :create
  variables lazy {
    { 
      deploy_user: deploy_user,
      passenger_root: `bash -c "source /usr/local/rvm/scripts/rvm; passenger-config --root"`.strip,
      passenger_ruby: `bash -c "source /usr/local/rvm/scripts/rvm; which ruby"`.strip,
      passenger: node[:passenger]
    }
  }
end

另外,我建议使用strip而不是chomp[感谢 Draco]。

于 2013-11-20T00:24:56.837 回答
3

一旦将代码包装进去ruby_block,就不能再使用普通的配方资源声明了。你必须编写纯 ruby​​ 代码:

ruby_block "create /opt/nginx/conf/nginx.conf from template" do
  block do
    res = Chef::Resource::Template.new "/opt/nginx/conf/nginx.conf", run_context
    res.source "nginx.conf.erb"
    res.variables(
      deploy_user: deploy_user,
      passenger_root: `bash -c "source /usr/local/rvm/scripts/rvm; passenger-config --root"`.chomp,
      passenger_ruby: `bash -c "source /usr/local/rvm/scripts/rvm; which ruby"`.chomp,
      passenger: node[:passenger]
    )
    res.run_action :create
  end
end

PS。而且我猜您想使用strip而不是chomp删除空格。

于 2013-04-03T14:26:05.163 回答
1

是的,厨师是个野兽。我认为问题的一部分是有一百万种方法可以做同样的事情,但实际上没有详细说明最佳方法的文档。您可能想要的是使用Notifications,以便块 1 先运行,而不是通知块 2 运行。这意味着块 2 需要action :none在收到通知之前不会触发。

我在块 1 中将通知添加到您的示例,并将操作 :none 添加到块 2。

bash "Install Passenger" do
  code <<-EOF
  source /usr/local/rvm/scripts/rvm
  gem install passenger
  EOF
  user "root"
  not_if { `gem list`.lines.grep(/^passenger \(.*\)/).count > 0 }
  notifies :run, 'bash[Install passenger nginx module and nginx from source]', :immediately
end

bash "Install passenger nginx module and nginx from source" do
  code <<-EOF
  source /usr/local/rvm/scripts/rvm
  passenger-install-nginx-module --auto --prefix=/opt/nginx --auto-download
  EOF
  user "root"
  action :none
end
于 2013-04-01T13:16:57.387 回答