Search code examples
chef-infrachef-solo

Multiple Chef Templates with a For Each statement and an attribute array


I'm trying to create multiple separate .conf files for an array of vhosts on my webserver using chef 11.10. I want the contents of these files to be slightly different per vhost.

The current implementation creates different file names (1 for each in the array.) but the template contains only the last item in the array each time.

For example, there are 3 vhosts - example1.com,example2.com,example3.com in an array. In my /var/www/conf.d/ directory I have 3 files after the recipe is run

> example1.com.conf 
> example2.com.conf 
> example3.com.conf

Which is a good start, however, the contents of those files are all the same with the last variable in the array being used. All of them have "example3.com" as the host eg.

server {
  listen   80;
  server_name  example3.com;
  return 301 https://$host$request_uri;
}

My recipe containts this

vhosts = node['nginx']['vhosts']

vhosts.each do |vhost|
  node.default['nginx']['hostname'] = vhost

  template "#{node[:nginx][:conf_dir]}/#{vhost}.conf" do
    source "#{node[:nginx][:vhost_template]}"
    owner "root"
    group "root"
    mode 0644
    notifies :restart, resources(:service => "nginx")
  end
end

and in my template the following code

  server {
  listen   443;
  server_name  <%= node[:nginx][:hostname] %>;
  return 301 http://$host$request_uri;
}

and in my attributes/default.rb file i have the following array.

default[:nginx][:vhosts] = [ "example1.com", "example2.com", "example3.com" ]

Solution

  • It doesn't make sense to set a single node attribute in a loop. Because of Chef execution, only the last value holds when the template resource actually gets created. Try dropping this line:

    node.default['nginx']['hostname'] = vhost
    

    and then pass vhost in the template variables attribute and use that in the .erb file.

    (Also, for reference, you normally don't want to set default node attributes in a recipe, which is what using node.default[...] does, but that's not the root issue here.)