diff --git a/lib/vagrant/action/vm/provision.rb b/lib/vagrant/action/vm/provision.rb index 6977634ea..1c3bdf873 100644 --- a/lib/vagrant/action/vm/provision.rb +++ b/lib/vagrant/action/vm/provision.rb @@ -2,42 +2,38 @@ module Vagrant class Action module VM class Provision + attr_reader :provisioners + def initialize(app, env) @app = app @env = env @env["provision.enabled"] = true if !@env.has_key?("provision.enabled") + @provisioners = [] - load_provisioner if provisioning_enabled? + load_provisioners if provisioning_enabled? end def call(env) @app.call(env) - if provisioning_enabled? - @env.ui.info I18n.t("vagrant.actions.vm.provision.beginning") - @provisioner.provision! + @provisioners.each do |instance| + @env.ui.info I18n.t("vagrant.actions.vm.provision.beginning", :provisioner => instance.class) + instance.provision! end end def provisioning_enabled? - !@env["config"].vm.provisioner.nil? && @env["provision.enabled"] + !@env["config"].vm.provisioners.empty? && @env["provision.enabled"] end - def load_provisioner - provisioner = @env["config"].vm.provisioner + def load_provisioners + @env["config"].vm.provisioners.each do |provisioner| + @env.ui.info I18n.t("vagrant.actions.vm.provision.enabled", :provisioner => provisioner.shortcut) - if provisioner.is_a?(Class) - @provisioner = provisioner.new(@env) - raise Errors::ProvisionInvalidClass if !@provisioner.is_a?(Provisioners::Base) - elsif provisioner.is_a?(Symbol) - provisioner_klass = Provisioners::Base.registered[provisioner] - raise Errors::ProvisionUnknownType, :provisioner => provisioner.to_s if provisioner_klass.nil? - @provisioner = provisioner_klass.new(@env) + instance = provisioner.provisioner.new(@env) + instance.prepare + @provisioners << instance end - - @env.ui.info I18n.t("vagrant.actions.vm.provision.enabled", :provisioner => @provisioner.class.to_s) - @provisioner.prepare - @provisioner end end end diff --git a/lib/vagrant/config/vm.rb b/lib/vagrant/config/vm.rb index 552dcc4f8..5489a9dbd 100644 --- a/lib/vagrant/config/vm.rb +++ b/lib/vagrant/config/vm.rb @@ -60,7 +60,7 @@ module Vagrant @network_options[options[:adapter]] = options end - def provisioner(name, options=nil, &block) + def provision(name, options=nil, &block) @provisioners << Provisioner.new(name, options, &block) end diff --git a/lib/vagrant/config/vm/provisioner.rb b/lib/vagrant/config/vm/provisioner.rb index 939100013..9fc74bdab 100644 --- a/lib/vagrant/config/vm/provisioner.rb +++ b/lib/vagrant/config/vm/provisioner.rb @@ -35,6 +35,10 @@ module Vagrant return end + if !(provisioner <= Provisioners::Base) + errors.add(I18n.t("vagrant.config.vm.provisioner_invalid_class", :shortcut => shortcut)) + end + # Pass on validation to the provisioner config config.validate(errors) if config end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index b5f6d4d98..37ad7a82a 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -141,6 +141,7 @@ en: box_not_found: "The box '%{name}' could not be found." shared_folder_hostpath_missing: "Shared folder host path for '%{name}' doesn't exist: %{path}" provisioner_not_found: "The provisioner '%{shortcut}' doesn't exist." + provisioner_invalid_class: "The provisioner '%{shortcut}' must inherit from `Vagrant::Provisioners::Base`." #------------------------------------------------------------------------------- # Translations for commands. e.g. `vagrant x` @@ -350,7 +351,7 @@ en: key. persisting: "Persisting the VM UUID (%{uuid})..." provision: - beginning: "Beginning provisioning process..." + beginning: "Running provisioner: %{provisioner}..." enabled: "Provisioning enabled with %{provisioner}..." invalid_class: "Provisioners must be an instance of Vagrant::Provisioners::Base" unknown_type: "Unknown provisioner type: %{provisioner}" diff --git a/test/vagrant/action/vm/provision_test.rb b/test/vagrant/action/vm/provision_test.rb index 442611c0c..c71d870bc 100644 --- a/test/vagrant/action/vm/provision_test.rb +++ b/test/vagrant/action/vm/provision_test.rb @@ -17,24 +17,23 @@ class ProvisionVMActionTest < Test::Unit::TestCase context "initializing" do setup do - @klass.any_instance.stubs(:load_provisioner) + @klass.any_instance.stubs(:load_provisioners) end should "load provisioner if provisioning enabled" do - @env["config"].vm.provisioner = :chef_solo - @klass.any_instance.expects(:load_provisioner).once + @env["config"].vm.provision :chef_solo + @klass.any_instance.expects(:load_provisioners).once @klass.new(@app, @env) end should "not load provisioner if disabled" do - @env["config"].vm.provisioner = nil - @klass.any_instance.expects(:load_provisioner).never + @klass.any_instance.expects(:load_provisioners).never @klass.new(@app, @env) end should "not load provisioner if disabled through env hash" do @env["provision.enabled"] = false - @klass.any_instance.expects(:load_provisioner).never + @klass.any_instance.expects(:load_provisioners).never @klass.new(@app, @env) end end @@ -42,105 +41,34 @@ class ProvisionVMActionTest < Test::Unit::TestCase context "with an instance" do setup do # Set provisioner to nil so the provisioner isn't loaded on init - @env["config"].vm.provisioner = nil + @env["config"].vm.provisioners.clear @instance = @klass.new(@app, @env) end context "loading a provisioner" do - context "with a Class provisioner" do - setup do - @prov = mock("instance") - @prov.stubs(:is_a?).with(Vagrant::Provisioners::Base).returns(true) - @prov.stubs(:prepare) - @klass = mock("klass") - @klass.stubs(:is_a?).with(Class).returns(true) - @klass.stubs(:new).with(@env).returns(@prov) + should "instantiate and prepare each provisioner" do + Vagrant::Provisioners::ChefSolo.any_instance.expects(:prepare).times(2) + @env["config"].vm.provision :chef_solo + @env["config"].vm.provision :chef_solo + @instance.load_provisioners - @env["config"].vm.provisioner = @klass - end - - should "set the provisioner to an instantiation of the class" do - @klass.expects(:new).with(@env).once.returns(@prov) - assert_equal @prov, @instance.load_provisioner - end - - should "call prepare on the instance" do - @prov.expects(:prepare).once - @instance.load_provisioner - end - - should "error environment if the class is not a subclass of the provisioner base" do - @prov.expects(:is_a?).with(Vagrant::Provisioners::Base).returns(false) - - assert_raises(Vagrant::Errors::ProvisionInvalidClass) { - @instance.load_provisioner - } - end - end - - context "with a Symbol provisioner" do - def provisioner_expectation(symbol, provisioner) - @env[:config].vm.provisioner = symbol - - instance = mock("instance") - instance.expects(:prepare).once - provisioner.expects(:new).with(@env).returns(instance) - assert_equal instance, @instance.load_provisioner - end - - should "raise an error if its an unknown symbol" do - @env["config"].vm.provisioner = :this_will_never_exist - - assert_raises(Vagrant::Errors::ProvisionUnknownType) { - @instance.load_provisioner - } - end - - should "set :chef_solo to the ChefSolo provisioner" do - provisioner_expectation(:chef_solo, Vagrant::Provisioners::ChefSolo) - end - - should "set :chef_server to the ChefServer provisioner" do - provisioner_expectation(:chef_server, Vagrant::Provisioners::ChefServer) - end - - should "set :puppet to the Puppet provisioner" do - provisioner_expectation(:puppet, Vagrant::Provisioners::Puppet) - end - - should "set :puppet_server to the Puppet Server provisioner" do - provisioner_expectation(:puppet_server, Vagrant::Provisioners::PuppetServer) - end + assert_equal 2, @instance.provisioners.length end end context "calling" do setup do Vagrant::Provisioners::ChefSolo.any_instance.stubs(:prepare) - @env["config"].vm.provisioner = :chef_solo - @prov = @instance.load_provisioner + @env["config"].vm.provision :chef_solo + @instance.load_provisioners end should "provision and continue chain" do seq = sequence("seq") @app.expects(:call).with(@env).in_sequence(seq) - @prov.expects(:provision!).in_sequence(seq) - - @instance.call(@env) - end - - should "continue chain and not provision if not enabled" do - @env["config"].vm.provisioner = nil - @prov.expects(:provision!).never - @app.expects(:call).with(@env).once - - @instance.call(@env) - end - - should "continue chain and not provision if not enabled through env hash" do - @env["provision.enabled"] = false - @prov.expects(:provision!).never - @app.expects(:call).with(@env).once + @instance.provisioners.each do |prov| + prov.expects(:provision!).in_sequence(seq) + end @instance.call(@env) end