diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb index de3b88066..f0b8114ff 100644 --- a/lib/vagrant/environment.rb +++ b/lib/vagrant/environment.rb @@ -175,9 +175,7 @@ module Vagrant # Load any global plugins Vagrant::Plugin::Manager.instance.load_plugins(plugins) - if !vagrantfile.config.vagrant.plugins.empty? - plugins = process_configured_plugins - end + plugins = process_configured_plugins # Call the hooks that does not require configurations to be loaded # by using a "clean" action runner @@ -922,6 +920,49 @@ module Vagrant protected + # Attempt to guess the configured provider in use. Will fallback + # to the default provider if an explicit provider name is not + # provided. This can be pretty error prone, but is used during + # initial environment setup to allow loading plugins so it doesn't + # need to be perfect + # + # @return [String] + def guess_provider + gp = nil + ARGV.each_with_index do |val, idx| + if val.start_with?("--provider=") + gp = val.split("=", 2).last + break + elsif val == "--provider" + gp = ARGV[idx+1] + break + end + end + return gp if gp + begin + default_provider + rescue Errors::NoDefaultProvider + # if a provider cannot be determined just return nil + nil + end + end + + # Load any configuration provided by guests defined within + # the Vagrantfile to pull plugin information they may have + # defined. + def find_configured_plugins + plugins = [] + provider = guess_provider + vagrantfile.machine_names.each do |mname| + ldp = @local_data_path.join("machines/#{mname}/#{provider}") if @local_data_path + plugins << vagrantfile.machine_config(mname, guess_provider, boxes, ldp)[:config] + end + result = plugins.reverse.inject(Vagrant::Util::HashWithIndifferentAccess.new) do |memo, val| + Vagrant::Util::DeepMerge.deep_merge(memo, val.vagrant.plugins) + end + Vagrant::Util::DeepMerge.deep_merge(result, vagrantfile.config.vagrant.plugins) + end + # Check for any local plugins defined within the Vagrantfile. If # found, validate they are available. If they are not available, # request to install them, or raise an exception @@ -939,7 +980,7 @@ module Vagrant # Check if defined plugins are installed installed = Plugin::Manager.instance.installed_plugins needs_install = [] - config_plugins = vagrantfile.config.vagrant.plugins + config_plugins = find_configured_plugins config_plugins.each do |name, info| if !installed[name] needs_install << name diff --git a/test/unit/vagrant/environment_test.rb b/test/unit/vagrant/environment_test.rb index 6c92cd5ba..8be6ddeed 100644 --- a/test/unit/vagrant/environment_test.rb +++ b/test/unit/vagrant/environment_test.rb @@ -165,7 +165,7 @@ describe Vagrant::Environment do collection = double("collection") expect(Vagrant::BoxCollection).to receive(:new).with( - env.homedir.join("boxes"), anything).and_return(collection) + env.homedir.join("boxes"), anything).twice.and_return(collection) expect(collection).to receive(:upgrade_v1_1_v1_5).once subject end @@ -761,6 +761,7 @@ VF before do m = Vagrant.plugin("2").manager allow(m).to receive(:providers).and_return(plugin_providers) + allow_any_instance_of(described_class).to receive(:process_configured_plugins) end it "is the highest matching usable provider" do @@ -1431,6 +1432,108 @@ VF end end + describe "guess_provider" do + before { allow_any_instance_of(described_class).to receive(:process_configured_plugins) } + + it "should return the default provider by default" do + expect(subject).to receive(:default_provider).and_return("default_provider") + expect(subject.send(:guess_provider)).to eq("default_provider") + end + + context "when provider is defined via command line argument" do + before { stub_const("ARGV", argv) } + + context "when provider is given as single argument" do + let(:argv) { ["--provider=single_arg"] } + + it "should return the provider name" do + expect(subject.send(:guess_provider)).to eq("single_arg") + end + end + + context "when provider is given as two arguments" do + let(:argv) { ["--provider", "double_arg"] } + + it "should return the provider name" do + expect(subject.send(:guess_provider)).to eq("double_arg") + end + end + end + + context "when no default provider is available" do + before { + expect(subject).to receive(:default_provider). + and_raise(Vagrant::Errors::NoDefaultProvider) } + + it "should return a nil value" do + expect(subject.send(:guess_provider)).to be_nil + end + end + end + + describe "#find_configured_plugins" do + before do + allow_any_instance_of(described_class).to receive(:guess_provider).and_return(:dummy) + allow_any_instance_of(described_class).to receive(:process_configured_plugins) + end + + it "should find no plugins when no plugins are configured" do + expect(subject.send(:find_configured_plugins)).to be_empty + end + + context "when plugins are defined in the Vagrantfile" do + before do + env.vagrantfile <<-VF + Vagrant.configure("2") do |config| + config.vagrant.plugins = "vagrant-plugin" + end + VF + end + + it "should return the vagrant-plugin" do + expect(subject.send(:find_configured_plugins).keys).to include("vagrant-plugin") + end + end + + context "when plugins are defined in the Vagrantfile of a box" do + before do + env.box3("foo", "1.0", :dummy, vagrantfile: <<-VF) + Vagrant.configure("2") do |config| + config.vagrant.plugins = "vagrant-plugin" + end + VF + env.vagrantfile <<-VF + Vagrant.configure("2") do |config| + config.vm.box = "foo" + end + VF + end + + it "should return the vagrant-plugin" do + expect(subject.send(:find_configured_plugins).keys).to include("vagrant-plugin") + end + end + + context "when the box does not match the provider" do + before do + env.box3("foo", "1.0", :other, vagrantfile: <<-VF) + Vagrant.configure("2") do |config| + config.vagrant.plugins = "vagrant-plugin" + end + VF + env.vagrantfile <<-VF + Vagrant.configure("2") do |config| + config.vm.box = "foo" + end + VF + end + + it "should not return the vagrant-plugin" do + expect(subject.send(:find_configured_plugins).keys).not_to include("vagrant-plugin") + end + end + end + describe "#process_configured_plugins" do let(:env) do isolated_environment.tap do |e| diff --git a/test/unit/vagrant/util/ssh_test.rb b/test/unit/vagrant/util/ssh_test.rb index 9d84f0225..88d51539e 100644 --- a/test/unit/vagrant/util/ssh_test.rb +++ b/test/unit/vagrant/util/ssh_test.rb @@ -39,7 +39,7 @@ describe Vagrant::Util::SSH do dsa_authentication: true }} - let(:ssh_path) { "/usr/bin/ssh" } + let(:ssh_path) { /.*ssh/ } it "searches original PATH for executable" do expect(Vagrant::Util::Which).to receive(:which).with("ssh", original_path: true).and_return("valid-return") @@ -97,8 +97,6 @@ describe Vagrant::Util::SSH do dsa_authentication: true }} - let(:ssh_path) { "/usr/bin/ssh" } - it "uses the IdentityFile argument and escapes the '%' character" do allow(Vagrant::Util::SafeExec).to receive(:exec).and_return(nil) described_class.exec(ssh_info) @@ -247,7 +245,7 @@ describe Vagrant::Util::SSH do it "enables ssh config loading" do allow(Vagrant::Util::SafeExec).to receive(:exec).and_return(nil) expect(Vagrant::Util::SafeExec).to receive(:exec) do |exe_path, *args| - expect(exe_path).to eq(ssh_path) + expect(exe_path).to match(ssh_path) config_options = ["-F", "/path/to/config"] expect(args & config_options).to eq(config_options) end