Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chef - create template with dynamic variable?

I'm having a bit of a challenge on a Chef recipe. I'm new to Chef, so please bear with me.

Step 1: My chef recipe installs Ruby Passenger, then compiles the Passenger nginx module along with 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

Step 2: After that, I create the nginx config file using a template. This configuration requires the location of Passenger, which is dependent on step 1 completing.

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

Problem: Chef appears to compile templates at th ebeginning of the run. So what ends up happening is that Step 2 is actually compiled before Step 1 is run. This means that the passenger_root variable is blank. It needs Step 1 to complete before being able to get the passenger_root, then run the template.

I tried wrapping the step 2 code in a ruby_block but that doesn't work: undefined methodtemplate' for Chef::Resource::RubyBlock`.

Not sure what to do here, or what is the best practice for Chef for something like this?

Thanks in advance,

Leonard

like image 842
Leonard Teo Avatar asked Apr 01 '13 12:04

Leonard Teo


1 Answers

A cleaner and recommended way is to use 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

Also, I'd suggest using strip instead of chomp [thanks Draco].

like image 161
Greg Avatar answered Oct 03 '22 17:10

Greg