7

I'm wondering if there is a way to specify defaults for provisioners when creating a multi-machine environment with Vagrant?

I was trying to do something like the following:

Vagrant.configure("2") do |config|
  config.vm.box = "andyshinn/ubuntu-precise64"

  config.vm.provision :chef_client do |chef|
    chef.chef_server_url = "https://api.opscode.com/organizations/myorg"
    chef.validation_key_path = "~/.chef/myorg-validator.pem"
    chef.delete_node = true
    chef.delete_client = true
    chef.validation_client_name = "myorg-validator"
  end

  config.vm.define :app do |app|
    app.vm.network "private_network", ip: "172.16.64.61"
    app.vm.host_name = "vagrant-app-#{ENV['USER']}"

    app.vm.provision :chef_client do |chef|
      chef.add_recipe "myrecipe1"
      chef.add_recipe "myrecipe2"
      chef.add_recipe "sudo"
    end
  end

  config.vm.define :web do |web|
    web.vm.network "private_network", ip: "172.16.64.62"
    web.vm.host_name = "vagrant-web-#{ENV['USER']}"

    web.vm.provision :chef_client do |chef|
      chef.add_recipe "myrecipe3"
      chef.add_recipe "myrecipe4"
      chef.add_recipe "sudo"
    end
  end
end

But each VM block does not appear to pick up any of the main config block settings. I get this error:

There are errors in the configuration of this machine. Please fix
the following errors and try again:

chef client provisioner:
* Chef server URL must be populated.
* Validation key path must be valid path to your chef server validation key.

Possible via another method?

Andy Shinn
  • 26,561
  • 8
  • 75
  • 93
  • I think a `.Vagrantfile` typically describes one self contained box. It seems suspect when you speak of a `multi-machine` environment because the answer to that would be multiple `.Vagrantfile`s. Do you think your might be trying to do something vagrant really isn't intended to do? – nsfyn55 May 23 '14 at 19:34
  • I understand where you are coming from. But was thinking the multi-machine setup was intended for applications that scale multiple nodes. To scale out properly, the application is modularized in to different components that run on different nodes. So to simulate that environment locally and keep development and production parity, I want to run it the same way. Vagrant is great at this and it does work. It just becomes very unDRY (wet?) when you have to repeat the same configuration for each box. – Andy Shinn May 23 '14 at 21:20
  • Ahhhh that was actually a google fail on my part. I wasn't aware they'd added that multi-machine config. – nsfyn55 May 23 '14 at 23:02
  • Lemme look at this for a few I think there are just some issues with your configuration. – nsfyn55 May 23 '14 at 23:08

3 Answers3

1

Your issue is one of scope. The variable chef has block scope in the config.vm.provision do block.

once this block exits your changes disappear. You should follow the example in the multi-machine docs on the vagrant site.

config.vm.provision "shell", inline: "echo Hello"

Vagrant.configure("2") do |config|
  config.vm.box = "andyshinn/ubuntu-precise64"


  config.vm.provision "chef_client", chef_server_url: "https://api.opscode.com/organizations/myorg"
  config.vm.provision "chef_client", validation_key_path:  "~/.chef/myorg-validator.pem                
  config.vm.provision "chef_client", delete_node: true
  config.vm.provision "chef_client", delete_client: true
  config.vm.provision "chef_client", validation_client_name: "myorg-validator"


  config.vm.define :app do |app|
    app.vm.network "private_network", ip: "172.16.64.61"
    app.vm.host_name = "vagrant-app-#{ENV['USER']}"

    app.vm.provision :chef_client do |chef|
      chef.add_recipe "myrecipe1"
      chef.add_recipe "myrecipe2"
      chef.add_recipe "sudo"
    end
  end

Should do the trick

nsfyn55
  • 14,875
  • 8
  • 50
  • 77
  • Thanks for the suggestion! I will try this out in the next week and accept if it works. – Andy Shinn May 26 '14 at 17:14
  • I finally tried this out and it doesn't work. Each machine block errors that it cannot find required params like Chef server URL and validation key. It doesn't seem to inherit this. – Andy Shinn Sep 15 '14 at 19:02
0

Maybe you already have this working, but in case not, check this out:

It partially solved my problem; maybe it will help you.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Lukino
  • 1,407
  • 13
  • 14
  • It would have been nice to point out the part in the configuration. I eventually saw what you were getting at and the custom method does help get closer to this. Not the most elegant. But it works. – Andy Shinn Sep 15 '14 at 19:08
  • Yeap, not nice but works. I trying this complicated case with many different configuration but in different files: - Vagrant file inside Box - Vagrant file in home dir - Custom Vagrant file And I want to have chef related stuff (URL, Keys, etc) in one place. I managed to have instance variables in VAGRANT_HOME/Vagrantfile and I was able to reference them in custom Vagrantfile – Lukino Sep 16 '14 at 19:28
0

I think the inner block "overrides" the outer one. You can, however, do something like I ended up doing in my answer (to my own question) to fake inside out ordering of provisioners rather than outside-in as Vagrant provides. In your case you wouldn't have a shell and puppet provisioner like I had, but you'd apply something like a template method pattern to extend a chef provisioner with more recipes. Perhaps something like:

module Vagrant
  module Config
    module V2
      class Root
        def provision(extra_recipes)
          config.vm.provision :chef_client do |chef|
            chef.chef_server_url = "https://api.opscode.com/organizations/myorg"
            chef.validation_key_path = "~/.chef/myorg-validator.pem"
            chef.delete_node = true
            chef.delete_client = true
            chef.validation_client_name = "myorg-validator"
            extra_recipes.each { |recipe| chef.add_recipe(recipe) }
          end
        end
      end
    end
  end
end

Vagrant.configure("2") do |config|
  config.vm.box = "andyshinn/ubuntu-precise64"

  config.vm.define :app do |app|
    app.vm.network "private_network", ip: "172.16.64.61"
    app.vm.host_name = "vagrant-app-#{ENV['USER']}"

    app.provision("myrecipe1", "myrecipe2", "sudo")
  end

  config.vm.define :web do |web|
    web.vm.network "private_network", ip: "172.16.64.62"
    web.vm.host_name = "vagrant-web-#{ENV['USER']}"

    app.provision("myrecipe3", "myrecipe4", "sudo")
  end
end
Community
  • 1
  • 1
Stig Brautaset
  • 2,602
  • 1
  • 22
  • 39