Merge pull request #6485 from mitchellh/f-provider-cmd

command/provider: non-primary command to check and install providers
This commit is contained in:
Mitchell Hashimoto 2015-11-04 19:38:47 -08:00
commit f45c5c4536
12 changed files with 358 additions and 1 deletions

View File

@ -520,6 +520,14 @@ module Vagrant
error_key(:requires_directory, "vagrant.actions.general.package")
end
class ProviderCantInstall < VagrantError
error_key(:provider_cant_install)
end
class ProviderInstallFailed < VagrantError
error_key(:provider_install_failed)
end
class ProviderNotFound < VagrantError
error_key(:provider_not_found)
end

View File

@ -319,6 +319,7 @@ module Vagrant
target = @prefix
target = opts[:target] if opts.key?(:target)
target = "#{target}:" if target != ""
# Get the lines. The first default is because if the message
# 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
lines.map do |line|
"#{prefix}#{target}: #{line}"
"#{prefix}#{target} #{line}"
end.join("\n")
end
end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -11,6 +11,11 @@ module VagrantPlugins
Host
end
host_capability("darwin", "provider_install_virtualbox") do
require_relative "cap/provider_install_virtualbox"
Cap::ProviderInstallVirtualBox
end
host_capability("darwin", "rdp_client") do
require_relative "cap/rdp"
Cap::RDP

View File

@ -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

View File

@ -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

View File

@ -11,6 +11,11 @@ module VagrantPlugins
Host
end
host_capability("windows", "provider_install_virtualbox") do
require_relative "cap/provider_install_virtualbox"
Cap::ProviderInstallVirtualBox
end
host_capability("windows", "nfs_installed") do
require_relative "cap/nfs"
Cap::NFS

View File

@ -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"

View File

@ -280,6 +280,7 @@ en:
CHANGELOG below:
https://github.com/mitchellh/vagrant/blob/v%{version}/CHANGELOG.md
cfengine_config:
classes_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
box has symlinks in it. Vagrant cannot include symlinks in the
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: |-
The provider '%{provider}' could not be found, but was requested to
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...
nfs_prune: |-
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:
nfs_export: |-
Preparing to edit /etc/exports. Administrator privileges will be required...
@ -1870,6 +1899,22 @@ en:
arch:
nfs_export:
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:
chef:

View File

@ -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