Search code examples
rubychef-solovagrantfile

Chef template loop: can't convert Chef::Node::immutableMash into String


I've got a Vagrant setup in which I'm trying to use Chef-solo to generate an conf file which loops though defined variables to pass to the application. Everything is working except the loop and I'm not familiar enough with Ruby/Chef to spot the error.

I'm going to lay out the whole chain of events in case there is something along the way that is the problem, but the first portions of this process seem to work fine.

A config file is written in yaml and includes env variable definitions to be passed:

...

variables:
    - DEBUG: 2

...

The config file is read in by the Vagrantfile into a ruby hash and used to create the Chef json nodes:

...

settings = YAML::load(File.read("config.yaml"))

# Provision The Virtual Machine Using Chef
config.vm.provision "chef_solo" do |chef|

    chef.json = {
        "mysql" => {"server_root_password" => "secret"},
        "postgresql" => {"password" => {"postgres" => "secret"}},
        "nginx" => {"pid" => "/run/nginx.pid"},
        "php-fpm" => {"pid" => "/run/php5-fpm.pid"},
        "databases" => settings["databases"] || [],
        "sites" => settings["sites"] || [],
        "variables" => settings["variables"] || []
    }

...

A bunch of chef cookbooks are run (apt, php, nginx, mysql etc) and finally my custom cookbook which is whats giving me grief. The portion of the cookbook responsible for creating a the conf file is shown here:

# Configure All Of The Server Environment Variables
template "#{node['php-fpm']['pool_conf_dir']}/vars.conf" do
  source "vars.erb"
  owner "root"
  group "root"
  mode 0644
  variables(
    :vars => node['variables']
  )
  notifies :restart, "service[php-fpm]"
end

And the vars.erb is just a one-liner

<%= @vars.each {|key, value| puts "env[" + key + " = " + value } %>

So, when I run all this chef spits out an error about not being able to convert a hash to a string.

can't convert Chef::Node::immutableMash into String

So for some reason this is coming across as an immutableMash and the value of key ends up being the hash [{"DEBUG"=>2}] and value ends up a nil object, but I'm not sure why or how to correct it.


Solution

  • The hash is ending up as the value of key in your example because the YAML file declares DEBUG: 2 as a list member of variables. This translates to variables being an array with a single hash member.

    Try changing the template code to this:
    <%= @vars[0].each {|key, value| puts "env[" + key + " = " + value } %>

    Or try changing the YAML to this and not changing the template code: variables: DEBUG: 2

    Either change will get your template loop iterating over the hash that you are expecting.