Vagrant provisioning with chef-solo
vagrant is a wonderful tool when you want to manage virtual machines in a development context. It even supports chef-solo provisioning.
Today I wanted to run a vagrant VM with the same chef-solo configuration I have on the host. So here’s the first Vagrantfile
I wrote:
config.vm.box = "debian_squeeze_32" config.vm.share_folder "chef-cookbooks", "/var/chef", "/var/chef" config.vm.provision :chef_solo do |chef| chef.cookbooks_path = "/var/chef/cookbooks" chef.json.merge!(JSON.parse(File.read("/etc/chef/dna.json"))) end
But it ended up with:
% vagrant up There was a problem with the configuration of Vagrant. The error message(s) are printed below: vm: * Run list must not be empty.
When you read the documentation, it seems vagrant assumes you add some recipes explicitly through the add_recipe
method:
dna = JSON.parse(File.read("/etc/chef/dna.json")) dna["recipes"].each do |recipe| chef.add_recipe(recipe) chef.json.merge!(dna)
…which ends with a Chef error:
[default] /usr/lib/ruby/1.8/chef/node.rb:382:in `consume_run_list': stderr [default] : please set the node's run list using the 'run_list' attribute only. (Chef::Exceptions::AmbiguousRunlistSpecification)
Ok, let’s remove the recipes
key in our json file:
dna = JSON.parse(File.read("/etc/chef/dna.json")) dna.delete("recipes").each do |recipe| chef.add_recipe(recipe) chef.json.merge!(dna)
It works. But it’s not really clean. After a research in the vagrant gem source code, I found that json[:run_list]
does exactly what I want,
so here’s the final Vagrantfile:
config.vm.box = "debian_squeeze_32" config.vm.share_folder "chef-cookbooks", "/var/chef", "/var/chef" config.vm.provision :chef_solo do |chef| dna = JSON.parse(File.read("/etc/chef/dna.json")) dna[:run_list] = dna.delete("recipes") chef.cookbooks_path = "/var/chef/cookbooks" chef.json.merge!(dna) end
Next!