Merge pull request #10889 from chrisroberts/f-local-plugins-boxfile

Support loading plugin information from nested Vagrantfiles
This commit is contained in:
Chris Roberts 2019-06-05 13:56:29 -07:00 committed by GitHub
commit f5f89f72b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 151 additions and 9 deletions

View File

@ -175,9 +175,7 @@ module Vagrant
# Load any global plugins # Load any global plugins
Vagrant::Plugin::Manager.instance.load_plugins(plugins) Vagrant::Plugin::Manager.instance.load_plugins(plugins)
if !vagrantfile.config.vagrant.plugins.empty? plugins = process_configured_plugins
plugins = process_configured_plugins
end
# Call the hooks that does not require configurations to be loaded # Call the hooks that does not require configurations to be loaded
# by using a "clean" action runner # by using a "clean" action runner
@ -922,6 +920,49 @@ module Vagrant
protected 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 # Check for any local plugins defined within the Vagrantfile. If
# found, validate they are available. If they are not available, # found, validate they are available. If they are not available,
# request to install them, or raise an exception # request to install them, or raise an exception
@ -939,7 +980,7 @@ module Vagrant
# Check if defined plugins are installed # Check if defined plugins are installed
installed = Plugin::Manager.instance.installed_plugins installed = Plugin::Manager.instance.installed_plugins
needs_install = [] needs_install = []
config_plugins = vagrantfile.config.vagrant.plugins config_plugins = find_configured_plugins
config_plugins.each do |name, info| config_plugins.each do |name, info|
if !installed[name] if !installed[name]
needs_install << name needs_install << name

View File

@ -165,7 +165,7 @@ describe Vagrant::Environment do
collection = double("collection") collection = double("collection")
expect(Vagrant::BoxCollection).to receive(:new).with( 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 expect(collection).to receive(:upgrade_v1_1_v1_5).once
subject subject
end end
@ -761,6 +761,7 @@ VF
before do before do
m = Vagrant.plugin("2").manager m = Vagrant.plugin("2").manager
allow(m).to receive(:providers).and_return(plugin_providers) allow(m).to receive(:providers).and_return(plugin_providers)
allow_any_instance_of(described_class).to receive(:process_configured_plugins)
end end
it "is the highest matching usable provider" do it "is the highest matching usable provider" do
@ -1431,6 +1432,108 @@ VF
end end
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 describe "#process_configured_plugins" do
let(:env) do let(:env) do
isolated_environment.tap do |e| isolated_environment.tap do |e|

View File

@ -39,7 +39,7 @@ describe Vagrant::Util::SSH do
dsa_authentication: true dsa_authentication: true
}} }}
let(:ssh_path) { "/usr/bin/ssh" } let(:ssh_path) { /.*ssh/ }
before { before {
allow(Vagrant::Util::Which).to receive(:which).with("ssh", any_args).and_return(ssh_path) allow(Vagrant::Util::Which).to receive(:which).with("ssh", any_args).and_return(ssh_path)
@ -101,8 +101,6 @@ describe Vagrant::Util::SSH do
dsa_authentication: true dsa_authentication: true
}} }}
let(:ssh_path) { "/usr/bin/ssh" }
it "uses the IdentityFile argument and escapes the '%' character" do it "uses the IdentityFile argument and escapes the '%' character" do
allow(Vagrant::Util::SafeExec).to receive(:exec).and_return(nil) allow(Vagrant::Util::SafeExec).to receive(:exec).and_return(nil)
described_class.exec(ssh_info) described_class.exec(ssh_info)
@ -251,7 +249,7 @@ describe Vagrant::Util::SSH do
it "enables ssh config loading" do it "enables ssh config loading" do
allow(Vagrant::Util::SafeExec).to receive(:exec).and_return(nil) allow(Vagrant::Util::SafeExec).to receive(:exec).and_return(nil)
expect(Vagrant::Util::SafeExec).to receive(:exec) do |exe_path, *args| 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"] config_options = ["-F", "/path/to/config"]
expect(args & config_options).to eq(config_options) expect(args & config_options).to eq(config_options)
end end