Chef - create template with dynamic variable?

chef-infra, knife, ruby

Solution

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].

Problem

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 method`template' 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

Original source