Merge pull request #6490 from mitchellh/f-provider-install
Add provider install to `vagrant up`
This commit is contained in:
commit
20e3bdc1d7
|
@ -309,6 +309,7 @@ module Vagrant
|
|||
def default_provider(**opts)
|
||||
opts[:exclude] = Set.new(opts[:exclude]) if opts[:exclude]
|
||||
opts[:force_default] = true if !opts.key?(:force_default)
|
||||
opts[:check_usable] = true if !opts.key?(:check_usable)
|
||||
|
||||
default = ENV["VAGRANT_DEFAULT_PROVIDER"]
|
||||
default = nil if default == ""
|
||||
|
@ -376,6 +377,7 @@ module Vagrant
|
|||
|
||||
# Find the matching implementation
|
||||
ordered.each do |_, key, impl, _|
|
||||
return key if !opts[:check_usable]
|
||||
return key if impl.usable?(false)
|
||||
end
|
||||
|
||||
|
@ -383,6 +385,26 @@ module Vagrant
|
|||
raise Errors::NoDefaultProvider
|
||||
end
|
||||
|
||||
# Returns whether or not we know how to install the provider with
|
||||
# the given name.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def can_install_provider?(name)
|
||||
host.capability?(provider_install_key(name))
|
||||
end
|
||||
|
||||
# Installs the provider with the given name.
|
||||
#
|
||||
# This will raise an exception if we don't know how to install the
|
||||
# provider with the given name. You should guard this call with
|
||||
# `can_install_provider?` for added safety.
|
||||
#
|
||||
# An exception will be raised if there are any failures installing
|
||||
# the provider.
|
||||
def install_provider(name)
|
||||
host.capability(provider_install_key(name))
|
||||
end
|
||||
|
||||
# Returns the collection of boxes for the environment.
|
||||
#
|
||||
# @return [BoxCollection]
|
||||
|
@ -883,6 +905,12 @@ module Vagrant
|
|||
nil
|
||||
end
|
||||
|
||||
# Returns the key used for the host capability for provider installs
|
||||
# of the given name.
|
||||
def provider_install_key(name)
|
||||
"provider_install_#{name}".to_sym
|
||||
end
|
||||
|
||||
# This upgrades a home directory that was in the v1.1 format to the
|
||||
# v1.5 format. It will raise exceptions if anything fails.
|
||||
def upgrade_home_path_v1_1
|
||||
|
|
|
@ -24,6 +24,21 @@ module Vagrant
|
|||
true
|
||||
end
|
||||
|
||||
# This is called early, before a machine is instantiated, to check
|
||||
# if this provider is installed. This should return true or false.
|
||||
#
|
||||
# If the provider is not installed and Vagrant determines it is
|
||||
# able to install this provider, then it will do so. Installation
|
||||
# is done by calling Environment.install_provider.
|
||||
#
|
||||
# If Environment.can_install_provider? returns false, then an error
|
||||
# will be shown to the user.
|
||||
def self.installed?
|
||||
# By default return true for backwards compat so all providers
|
||||
# continue to work.
|
||||
true
|
||||
end
|
||||
|
||||
# Initialize the provider to represent the given machine.
|
||||
#
|
||||
# @param [Vagrant::Machine] machine The machine that this provider
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'optparse'
|
||||
require 'set'
|
||||
|
||||
require "vagrant"
|
||||
|
||||
|
@ -16,6 +17,7 @@ module VagrantPlugins
|
|||
def execute
|
||||
options = {}
|
||||
options[:destroy_on_error] = true
|
||||
options[:install_provider] = true
|
||||
options[:parallel] = true
|
||||
options[:provision_ignore_sentinel] = false
|
||||
|
||||
|
@ -41,6 +43,11 @@ module VagrantPlugins
|
|||
"Back the machine with a specific provider") do |provider|
|
||||
options[:provider] = provider
|
||||
end
|
||||
|
||||
o.on("--[no-]install-provider",
|
||||
"If possible, install the provider if it isn't installed") do |p|
|
||||
options[:install_provider] = p
|
||||
end
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
|
@ -53,24 +60,32 @@ module VagrantPlugins
|
|||
# Go over each VM and bring it up
|
||||
@logger.debug("'Up' each target VM...")
|
||||
|
||||
# Build up the batch job of what we'll do
|
||||
machines = []
|
||||
@env.batch(options[:parallel]) do |batch|
|
||||
names = argv
|
||||
if names.empty?
|
||||
autostart = false
|
||||
@env.vagrantfile.machine_names_and_options.each do |n, o|
|
||||
autostart = true if o.key?(:autostart)
|
||||
o[:autostart] = true if !o.key?(:autostart)
|
||||
names << n.to_s if o[:autostart]
|
||||
end
|
||||
|
||||
# If we have an autostart key but no names, it means that
|
||||
# all machines are autostart: false and we don't start anything.
|
||||
names = nil if autostart && names.empty?
|
||||
# Get the names of the machines we want to bring up
|
||||
names = argv
|
||||
if names.empty?
|
||||
autostart = false
|
||||
@env.vagrantfile.machine_names_and_options.each do |n, o|
|
||||
autostart = true if o.key?(:autostart)
|
||||
o[:autostart] = true if !o.key?(:autostart)
|
||||
names << n.to_s if o[:autostart]
|
||||
end
|
||||
|
||||
if names
|
||||
# If we have an autostart key but no names, it means that
|
||||
# all machines are autostart: false and we don't start anything.
|
||||
names = nil if autostart && names.empty?
|
||||
end
|
||||
|
||||
# Build up the batch job of what we'll do
|
||||
machines = []
|
||||
if names
|
||||
# If we're installing providers, then do that. We don't
|
||||
# parallelize this step because it is likely the same provider
|
||||
# anyways.
|
||||
if options[:install_provider]
|
||||
install_providers(names)
|
||||
end
|
||||
|
||||
@env.batch(options[:parallel]) do |batch|
|
||||
with_target_vms(names, provider: options[:provider]) do |machine|
|
||||
@env.ui.info(I18n.t(
|
||||
"vagrant.commands.up.upping",
|
||||
|
@ -106,6 +121,44 @@ module VagrantPlugins
|
|||
# Success, exit status 0
|
||||
0
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def install_providers(names)
|
||||
# First create a set of all the providers we need to check for.
|
||||
# Most likely this will be a set of one.
|
||||
providers = Set.new
|
||||
names.each do |name|
|
||||
providers.add(@env.default_provider(machine: name.to_sym, check_usable: false))
|
||||
end
|
||||
|
||||
# Go through and determine if we can install the providers
|
||||
providers.delete_if do |name|
|
||||
!@env.can_install_provider?(name)
|
||||
end
|
||||
|
||||
# Install the providers if we have to
|
||||
providers.each do |name|
|
||||
# Find the provider. Ignore if we can't find it, this error
|
||||
# will pop up later in the process.
|
||||
parts = Vagrant.plugin("2").manager.providers[name]
|
||||
next if !parts
|
||||
|
||||
# If the provider is already installed, then our work here is done
|
||||
cls = parts[0]
|
||||
next if cls.installed?
|
||||
|
||||
# Some human-friendly output
|
||||
ui = Vagrant::UI::Prefixed.new(@env.ui, "")
|
||||
ui.output(I18n.t(
|
||||
"vagrant.installing_provider",
|
||||
provider: name.to_s))
|
||||
ui.detail(I18n.t("vagrant.installing_provider_detail"))
|
||||
|
||||
# Install the provider
|
||||
@env.install_provider(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,15 @@ module VagrantPlugins
|
|||
class Provider < Vagrant.plugin("2", :provider)
|
||||
attr_reader :driver
|
||||
|
||||
def self.installed?
|
||||
Driver::Meta.new
|
||||
true
|
||||
rescue Vagrant::Errors::VirtualBoxInvalidVersion
|
||||
return false
|
||||
rescue Vagrant::Errors::VirtualBoxNotDetected
|
||||
return false
|
||||
end
|
||||
|
||||
def self.usable?(raise_error=false)
|
||||
# Instantiate the driver, which will determine the VirtualBox
|
||||
# version and all that, which checks for VirtualBox being present
|
||||
|
|
|
@ -154,6 +154,13 @@ en:
|
|||
Inserting generated public key within guest...
|
||||
inserting_remove_key: |-
|
||||
Removing insecure key from the guest if it's present...
|
||||
installing_provider: |-
|
||||
Provider '%{provider}' not found. We'll automatically install it now...
|
||||
installing_provider_detail: |-
|
||||
The installation process will start below. Human interaction may be
|
||||
required at some points. If you're uncomfortable with automatically
|
||||
installing this provider, you can safely Ctrl-C this process and install
|
||||
it manually.
|
||||
list_commands: |-
|
||||
Below is a listing of all available Vagrant commands and a brief
|
||||
description of what they do.
|
||||
|
|
|
@ -25,6 +25,48 @@ describe Vagrant::Environment do
|
|||
let(:instance) { env.create_vagrant_env }
|
||||
subject { instance }
|
||||
|
||||
describe "#can_install_provider?" do
|
||||
let(:plugin_hosts) { {} }
|
||||
let(:plugin_host_caps) { {} }
|
||||
|
||||
before do
|
||||
m = Vagrant.plugin("2").manager
|
||||
m.stub(hosts: plugin_hosts)
|
||||
m.stub(host_capabilities: plugin_host_caps)
|
||||
|
||||
# Detect the host
|
||||
env.vagrantfile <<-VF
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vagrant.host = nil
|
||||
end
|
||||
VF
|
||||
|
||||
# Setup the foo host by default
|
||||
plugin_hosts[:foo] = [detect_class(true), nil]
|
||||
end
|
||||
|
||||
it "should return whether it can install or not" do
|
||||
plugin_host_caps[:foo] = { provider_install_foo: Class }
|
||||
|
||||
expect(subject.can_install_provider?(:foo)).to be_true
|
||||
expect(subject.can_install_provider?(:bar)).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#install_provider" do
|
||||
let(:host) { double(:host) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:host).and_return(host)
|
||||
end
|
||||
|
||||
it "should install the correct provider" do
|
||||
expect(host).to receive(:capability).with(:provider_install_foo)
|
||||
|
||||
subject.install_provider(:foo)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#home_path" do
|
||||
it "is set to the home path given" do
|
||||
Dir.mktmpdir do |dir|
|
||||
|
|
|
@ -12,6 +12,10 @@ describe Vagrant::Plugin::V2::Provider do
|
|||
expect(described_class).to be_usable
|
||||
end
|
||||
|
||||
it "should be installed by default" do
|
||||
expect(described_class).to be_installed
|
||||
end
|
||||
|
||||
it "should return nil by default for actions" do
|
||||
expect(instance.action(:whatever)).to be_nil
|
||||
end
|
||||
|
|
|
@ -20,6 +20,10 @@ on a day-to-day basis.
|
|||
unexpected error occurs. This will only happen on the first `vagrant up`.
|
||||
By default this is set.
|
||||
|
||||
* `--[no-]install-provider` - If the requested provider is not installed,
|
||||
Vagrant will attempt to automatically install it if it can. By default this
|
||||
is enabled.
|
||||
|
||||
* `--[no-]parallel` - Bring multiple machines up in parallel if the provider
|
||||
supports it. Please consult the provider documentation to see if this feature
|
||||
is supported.
|
||||
|
|
Loading…
Reference in New Issue