Merge pull request #6485 from mitchellh/f-provider-cmd
command/provider: non-primary command to check and install providers
This commit is contained in:
commit
f45c5c4536
|
@ -520,6 +520,14 @@ module Vagrant
|
||||||
error_key(:requires_directory, "vagrant.actions.general.package")
|
error_key(:requires_directory, "vagrant.actions.general.package")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class ProviderCantInstall < VagrantError
|
||||||
|
error_key(:provider_cant_install)
|
||||||
|
end
|
||||||
|
|
||||||
|
class ProviderInstallFailed < VagrantError
|
||||||
|
error_key(:provider_install_failed)
|
||||||
|
end
|
||||||
|
|
||||||
class ProviderNotFound < VagrantError
|
class ProviderNotFound < VagrantError
|
||||||
error_key(:provider_not_found)
|
error_key(:provider_not_found)
|
||||||
end
|
end
|
||||||
|
|
|
@ -319,6 +319,7 @@ module Vagrant
|
||||||
|
|
||||||
target = @prefix
|
target = @prefix
|
||||||
target = opts[:target] if opts.key?(:target)
|
target = opts[:target] if opts.key?(:target)
|
||||||
|
target = "#{target}:" if target != ""
|
||||||
|
|
||||||
# Get the lines. The first default is because if the message
|
# Get the lines. The first default is because if the message
|
||||||
# is an empty string, then we want to still use the empty string.
|
# is an empty string, then we want to still use the empty string.
|
||||||
|
@ -327,7 +328,7 @@ module Vagrant
|
||||||
|
|
||||||
# Otherwise, make sure to prefix every line properly
|
# Otherwise, make sure to prefix every line properly
|
||||||
lines.map do |line|
|
lines.map do |line|
|
||||||
"#{prefix}#{target}: #{line}"
|
"#{prefix}#{target} #{line}"
|
||||||
end.join("\n")
|
end.join("\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandProvider
|
||||||
|
class Command < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"show provider for this environment"
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
options[:install] = false
|
||||||
|
options[:usable] = false
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant provider [options] [args]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "This command interacts with the provider for this environment."
|
||||||
|
o.separator "With no arguments, it'll output the default provider for this"
|
||||||
|
o.separator "environment."
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("--install", "Installs the provider if possible") do |f|
|
||||||
|
options[:install] = f
|
||||||
|
end
|
||||||
|
|
||||||
|
o.on("--usable", "Checks if the named provider is usable") do |f|
|
||||||
|
options[:usable] = f
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
# Get the machine
|
||||||
|
machine = nil
|
||||||
|
with_target_vms(argv, single_target: true) do |m|
|
||||||
|
machine = m
|
||||||
|
end
|
||||||
|
|
||||||
|
# Output some machine readable stuff
|
||||||
|
@env.ui.machine("provider-name", machine.provider_name, target: machine.name.to_s)
|
||||||
|
|
||||||
|
# Check if we're just doing a usability check
|
||||||
|
if options[:usable]
|
||||||
|
@env.ui.output(machine.provider_name.to_s)
|
||||||
|
return 0 if machine.provider.class.usable?(false)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if we're requesting installation
|
||||||
|
if options[:install]
|
||||||
|
key = "provider_install_#{machine.provider_name}".to_sym
|
||||||
|
if !@env.host.capability?(key)
|
||||||
|
raise Vagrant::Errors::ProviderCantInstall,
|
||||||
|
provider: machine.provider_name.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.host.capability(key)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# No subtask, just output the provider name
|
||||||
|
@env.ui.output(machine.provider_name.to_s)
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,18 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandProvider
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "provider command"
|
||||||
|
description <<-DESC
|
||||||
|
The `provider` command is used to interact with the various providers
|
||||||
|
that are installed with Vagrant.
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command("provider", primary: false) do
|
||||||
|
require_relative "command"
|
||||||
|
Command
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,51 @@
|
||||||
|
require "pathname"
|
||||||
|
require "tempfile"
|
||||||
|
|
||||||
|
require "vagrant/util/downloader"
|
||||||
|
require "vagrant/util/subprocess"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HostDarwin
|
||||||
|
module Cap
|
||||||
|
class ProviderInstallVirtualBox
|
||||||
|
# The URL to download VirtualBox is hardcoded so we can have a
|
||||||
|
# known-good version to download.
|
||||||
|
URL = "http://download.virtualbox.org/virtualbox/5.0.8/VirtualBox-5.0.8-103449-OSX.dmg".freeze
|
||||||
|
VERSION = "5.0.8".freeze
|
||||||
|
|
||||||
|
def self.provider_install_virtualbox(env)
|
||||||
|
tf = Tempfile.new("vagrant")
|
||||||
|
tf.close
|
||||||
|
|
||||||
|
# Prefixed UI for prettiness
|
||||||
|
ui = Vagrant::UI::Prefixed.new(env.ui, "")
|
||||||
|
|
||||||
|
# Start by downloading the file using the standard mechanism
|
||||||
|
ui.output(I18n.t(
|
||||||
|
"vagrant.hosts.darwin.virtualbox_install_download",
|
||||||
|
version: VERSION))
|
||||||
|
ui.detail(I18n.t(
|
||||||
|
"vagrant.hosts.darwin.virtualbox_install_detail"))
|
||||||
|
dl = Vagrant::Util::Downloader.new(URL, tf.path, ui: ui)
|
||||||
|
dl.download!
|
||||||
|
|
||||||
|
# Launch it
|
||||||
|
ui.output(I18n.t(
|
||||||
|
"vagrant.hosts.darwin.virtualbox_install_install"))
|
||||||
|
ui.detail(I18n.t(
|
||||||
|
"vagrant.hosts.darwin.virtualbox_install_install_detail"))
|
||||||
|
script = File.expand_path("../../scripts/install_virtualbox.sh", __FILE__)
|
||||||
|
result = Vagrant::Util::Subprocess.execute("bash", script, tf.path)
|
||||||
|
if result.exit_code != 0
|
||||||
|
raise Vagrant::Errors::ProviderInstallFailed,
|
||||||
|
provider: "virtualbox",
|
||||||
|
stdout: result.stdout,
|
||||||
|
stderr: result.stderr
|
||||||
|
end
|
||||||
|
|
||||||
|
ui.success(I18n.t("vagrant.hosts.darwin.virtualbox_install_success"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,6 +11,11 @@ module VagrantPlugins
|
||||||
Host
|
Host
|
||||||
end
|
end
|
||||||
|
|
||||||
|
host_capability("darwin", "provider_install_virtualbox") do
|
||||||
|
require_relative "cap/provider_install_virtualbox"
|
||||||
|
Cap::ProviderInstallVirtualBox
|
||||||
|
end
|
||||||
|
|
||||||
host_capability("darwin", "rdp_client") do
|
host_capability("darwin", "rdp_client") do
|
||||||
require_relative "cap/rdp"
|
require_relative "cap/rdp"
|
||||||
Cap::RDP
|
Cap::RDP
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
hdiutil attach $1
|
||||||
|
cd /Volumes/VirtualBox/
|
||||||
|
sudo installer -pkg VirtualBox.pkg -target "/"
|
||||||
|
cd /tmp
|
||||||
|
flag=1
|
||||||
|
while [ $flag -ne 0 ]; do
|
||||||
|
sleep 1
|
||||||
|
set +e
|
||||||
|
hdiutil detach /Volumes/VirtualBox/
|
||||||
|
flag=$?
|
||||||
|
set -e
|
||||||
|
done
|
|
@ -0,0 +1,51 @@
|
||||||
|
require "pathname"
|
||||||
|
require "tempfile"
|
||||||
|
|
||||||
|
require "vagrant/util/downloader"
|
||||||
|
require "vagrant/util/subprocess"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HostWindows
|
||||||
|
module Cap
|
||||||
|
class ProviderInstallVirtualBox
|
||||||
|
# The URL to download VirtualBox is hardcoded so we can have a
|
||||||
|
# known-good version to download.
|
||||||
|
URL = "http://download.virtualbox.org/virtualbox/5.0.8/VirtualBox-5.0.8-103449-Win.exe".freeze
|
||||||
|
VERSION = "5.0.8".freeze
|
||||||
|
|
||||||
|
def self.provider_install_virtualbox(env)
|
||||||
|
tf = Tempfile.new("vagrant")
|
||||||
|
tf.close
|
||||||
|
|
||||||
|
# Prefixed UI for prettiness
|
||||||
|
ui = Vagrant::UI::Prefixed.new(env.ui, "")
|
||||||
|
|
||||||
|
# Start by downloading the file using the standard mechanism
|
||||||
|
ui.output(I18n.t(
|
||||||
|
"vagrant.hosts.windows.virtualbox_install_download",
|
||||||
|
version: VERSION))
|
||||||
|
ui.detail(I18n.t(
|
||||||
|
"vagrant.hosts.windows.virtualbox_install_detail"))
|
||||||
|
dl = Vagrant::Util::Downloader.new(URL, tf.path, ui: ui)
|
||||||
|
dl.download!
|
||||||
|
|
||||||
|
# Launch it
|
||||||
|
ui.output(I18n.t(
|
||||||
|
"vagrant.hosts.windows.virtualbox_install_install"))
|
||||||
|
ui.detail(I18n.t(
|
||||||
|
"vagrant.hosts.windows.virtualbox_install_install_detail"))
|
||||||
|
script = File.expand_path("../../scripts/install_virtualbox.ps1", __FILE__)
|
||||||
|
result = Vagrant::Util::Powershell.execute(script, tf.path)
|
||||||
|
if result.exit_code != 0
|
||||||
|
raise Vagrant::Errors::ProviderInstallFailed,
|
||||||
|
provider: "virtualbox",
|
||||||
|
stdout: result.stdout,
|
||||||
|
stderr: result.stderr
|
||||||
|
end
|
||||||
|
|
||||||
|
ui.success(I18n.t("vagrant.hosts.windows.virtualbox_install_success"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,6 +11,11 @@ module VagrantPlugins
|
||||||
Host
|
Host
|
||||||
end
|
end
|
||||||
|
|
||||||
|
host_capability("windows", "provider_install_virtualbox") do
|
||||||
|
require_relative "cap/provider_install_virtualbox"
|
||||||
|
Cap::ProviderInstallVirtualBox
|
||||||
|
end
|
||||||
|
|
||||||
host_capability("windows", "nfs_installed") do
|
host_capability("windows", "nfs_installed") do
|
||||||
require_relative "cap/nfs"
|
require_relative "cap/nfs"
|
||||||
Cap::NFS
|
Cap::NFS
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$True)]
|
||||||
|
[string]$path
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stop on first error
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# Make the path complete
|
||||||
|
$path = Resolve-Path $path
|
||||||
|
|
||||||
|
# Determine if this is a 64-bit or 32-bit CPU
|
||||||
|
$architecture="x86"
|
||||||
|
if ((Get-WmiObject -Class Win32_OperatingSystem).OSArchitecture -eq "64-bit") {
|
||||||
|
$architecture = "amd64"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract the contents of the installer
|
||||||
|
Start-Process -FilePath $path `
|
||||||
|
-ArgumentList ('--extract','--silent','--path','.') `
|
||||||
|
-Wait `
|
||||||
|
-NoNewWindow
|
||||||
|
|
||||||
|
# Find the installer
|
||||||
|
$matches = Get-ChildItem | Where-Object { $_.Name -match "VirtualBox-.*_$($architecture).msi" }
|
||||||
|
if ($matches.Count -ne 1) {
|
||||||
|
Write-Host "Multiple matches for VirtualBox MSI found: $($matches.Count)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$installerPath = Resolve-Path $matches[0]
|
||||||
|
|
||||||
|
# Run the installer
|
||||||
|
Start-Process -FilePath "$($env:systemroot)\System32\msiexec.exe" `
|
||||||
|
-ArgumentList "/i `"$installerPath`" /qn /norestart /l*v `"$($pwd)\install.log`"" `
|
||||||
|
-Verb RunAs `
|
||||||
|
-Wait `
|
||||||
|
-WorkingDirectory "$pwd"
|
|
@ -280,6 +280,7 @@ en:
|
||||||
CHANGELOG below:
|
CHANGELOG below:
|
||||||
|
|
||||||
https://github.com/mitchellh/vagrant/blob/v%{version}/CHANGELOG.md
|
https://github.com/mitchellh/vagrant/blob/v%{version}/CHANGELOG.md
|
||||||
|
|
||||||
cfengine_config:
|
cfengine_config:
|
||||||
classes_array: |-
|
classes_array: |-
|
||||||
The 'classes' configuration must be an array.
|
The 'classes' configuration must be an array.
|
||||||
|
@ -1001,6 +1002,19 @@ en:
|
||||||
A file or directory you're attempting to include with your packaged
|
A file or directory you're attempting to include with your packaged
|
||||||
box has symlinks in it. Vagrant cannot include symlinks in the
|
box has symlinks in it. Vagrant cannot include symlinks in the
|
||||||
resulting package. Please remove the symlinks and try again.
|
resulting package. Please remove the symlinks and try again.
|
||||||
|
provider_cant_install: |-
|
||||||
|
The provider '%{provider}' doesn't support automatic installation.
|
||||||
|
This is a limitation of this provider. Please report this as a feature
|
||||||
|
request to the provider in question. To install this provider, you'll
|
||||||
|
have to do so manually.
|
||||||
|
provider_install_failed: |-
|
||||||
|
Installation of the provider '%{provider}' failed! The stdout
|
||||||
|
and stderr are shown below. Please read the error output, resolve it,
|
||||||
|
and try again. If problem persists, please install the provider
|
||||||
|
manually.
|
||||||
|
|
||||||
|
Stdout: %{stdout}
|
||||||
|
Stderr: %{stderr}
|
||||||
provider_not_found: |-
|
provider_not_found: |-
|
||||||
The provider '%{provider}' could not be found, but was requested to
|
The provider '%{provider}' could not be found, but was requested to
|
||||||
back the machine '%{machine}'. Please use a provider that exists.
|
back the machine '%{machine}'. Please use a provider that exists.
|
||||||
|
@ -1862,6 +1876,21 @@ en:
|
||||||
Preparing to edit /etc/exports. Administrator privileges will be required...
|
Preparing to edit /etc/exports. Administrator privileges will be required...
|
||||||
nfs_prune: |-
|
nfs_prune: |-
|
||||||
Pruning invalid NFS exports. Administrator privileges will be required...
|
Pruning invalid NFS exports. Administrator privileges will be required...
|
||||||
|
darwin:
|
||||||
|
virtualbox_install_download: |-
|
||||||
|
Downloading VirtualBox %{version}...
|
||||||
|
virtualbox_install_detail: |-
|
||||||
|
This may not be the latest version of VirtualBox, but it is a version
|
||||||
|
that is known to work well. Over time, we'll update the version that
|
||||||
|
is installed.
|
||||||
|
virtualbox_install_install: |-
|
||||||
|
Installing VirtualBox. This will take a few minutes...
|
||||||
|
virtualbox_install_install_detail: |-
|
||||||
|
You may be asked for your administrator password during this time.
|
||||||
|
If you're uncomfortable entering your password here, please install
|
||||||
|
VirtualBox manually.
|
||||||
|
virtualbox_install_success: |-
|
||||||
|
VirtualBox has successfully been installed!
|
||||||
linux:
|
linux:
|
||||||
nfs_export: |-
|
nfs_export: |-
|
||||||
Preparing to edit /etc/exports. Administrator privileges will be required...
|
Preparing to edit /etc/exports. Administrator privileges will be required...
|
||||||
|
@ -1870,6 +1899,22 @@ en:
|
||||||
arch:
|
arch:
|
||||||
nfs_export:
|
nfs_export:
|
||||||
prepare: "Preparing to edit /etc/exports. Administrator privileges will be required..."
|
prepare: "Preparing to edit /etc/exports. Administrator privileges will be required..."
|
||||||
|
windows:
|
||||||
|
virtualbox_install_download: |-
|
||||||
|
Downloading VirtualBox %{version}...
|
||||||
|
virtualbox_install_detail: |-
|
||||||
|
This may not be the latest version of VirtualBox, but it is a version
|
||||||
|
that is known to work well. Over time, we'll update the version that
|
||||||
|
is installed.
|
||||||
|
virtualbox_install_install: |-
|
||||||
|
Installing VirtualBox. This will take a few minutes...
|
||||||
|
virtualbox_install_install_detail: |-
|
||||||
|
A couple pop-ups will occur during this installation process to
|
||||||
|
ask for admin privileges as well as to install Oracle drivers.
|
||||||
|
Please say yes to both. If you're uncomfortable with this, please
|
||||||
|
install VirtualBox manually.
|
||||||
|
virtualbox_install_success: |-
|
||||||
|
VirtualBox has successfully been installed!
|
||||||
|
|
||||||
provisioners:
|
provisioners:
|
||||||
chef:
|
chef:
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/provider/command")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CommandProvider::Command do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:guest) { double("guest") }
|
||||||
|
let(:host) { double("host") }
|
||||||
|
let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "execute" do
|
||||||
|
context "no arguments" do
|
||||||
|
it "exits with the provider name" do
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "--usable" do
|
||||||
|
let(:argv) { ["--usable"] }
|
||||||
|
|
||||||
|
it "exits 0 if it is usable" do
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "exits 1 if it is not usable" do
|
||||||
|
expect(machine.provider.class).to receive(:usable?).and_return(false)
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue