diff --git a/.gitignore b/.gitignore
index 801132d2d..b1274f4d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ pkg/*
tags
/Gemfile.lock
test/tmp/
+vendor/
# Documentation
_site/*
diff --git a/.travis.yml b/.travis.yml
index 6fb40430b..a810bf759 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,21 @@
language: ruby
+
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq -y bsdtar
- rvm @global do gem uninstall bundler --all --executables
- gem uninstall bundler --all --executables
- gem install bundler --version '< 1.7.0'
+
rvm:
- 2.0.0
+
+branches:
+ only:
+ - master
+
env:
global:
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
+
script: rake test:unit
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd657fa48..6d74712ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,44 +2,91 @@
IMPROVEMENTS:
- - guests/darwin: Support inserting generated key. [GH-5204]
- - guests/fedora: Support Fedora 21. [GH-5277]
- - guests/redhat: Support Scientific Linux 7 [GH-5303]
- - guests/solaris,solaris11: Support inserting generated key. [GH-5182]
+ - core: add password authentication to rdp_info hash [GH-4726]
+ - core: improve error message when packaging fails [GH-5399]
+ - core: improve message when adding a box from a file path [GH-5395]
+ - core: add support for network gateways [GH-5721]
+ - core: allow redirecting stdout and stderr in the UI [GH-5433]
+ - core: update version of winrm-fs to 0.2.0 [GH-5738]
+ - core: add option to enabled trusted http(s) redirects [GH-4422]
+ - core: capture additional information such as line numbers during
+ Vagrantfile loading [GH-4711, GH-5769]
+ - guests/darwin: support inserting generated key [GH-5204]
+ - guests/darwin: support mounting SMB shares [GH-5750]
+ - guests/fedora: support Fedora 21 [GH-5277]
+ - guests/fedora: add capabilities for nfs and flavor [GH-5770, GH-4847]
+ - guests/linux: specify user's domain as separate parameter [GH-3620, GH-5512]
+ - guests/redhat: support Scientific Linux 7 [GH-5303]
+ - guests/photon: initial support [GH-5612]
+ - guests/solaris,solaris11: support inserting generated key [GH-5182]
[GH-5290]
- - providers/virtualbox: regexp supported for bridge configuration. [GH-5320]
+ - provisioners/chef: add capability for checking if Chef is installed on Windows [GH-5669]
+ - provisioners/puppet: add support for Puppet 4 and configuration options [GH-5601]
+ - provisioners/puppet: add support for `synced_folder_args` in apply [GH-5359]
+ - provisioners/salt: add configurable `config_dir` [GH-3138]
+ - provisioners/salt: add support for masterless configuration [GH-3235]
+ - provisioners/salt: provider path to missing file in errors [GH-5637]
+ - provisioners/salt: add ability to run salt orchestrations [GH-4371]
+ - provisioners/salt: update to 2014.7.1 [GH-4152, GH-5437]
+ - provisioners/shell: add :name attribute to shell provisioner [GH-5607]
+ - providers/hyperv: select a Hyper-V switch based on a network_name [GH-5207]
+ - providers/hyperv: allow configuring VladID [GH-5539]
+ - providers/virtualbox: regexp supported for bridge configuration [GH-5320]
+ - providers/virtualbox: add support for 5.0 [GH-5647]
+ - providers/virtualbox: handle a list of bridged NICs [GH-5691]
+ - synced_folders/rsync: allow showing rsync output in debug mode [GH-4867]
BUG FIXES:
- core: push configurations are validated with global configs [GH-5130]
- core: remove executable permissions on internal file [GH-5220]
- core: check name and version in `has_plugin?` [GH-5218]
+ - core: do not create duplicates when defining two private network addresses [GH-5325]
+ - core: update ssh to check for Plink [GH-5604]
+ - core: do not report plugins as installed when plugins are disabled [GH-5698, GH-5430]
+ - core: Only take files when packaging a box to avoid duplicates [GH-5658, GH-5657]
+ - core: escape curl urls and authentication [GH-5677]
- core/cli: fix box checksum validation [GH-4665, GH-5221]
+ - core/windows: allow Windows UNC paths to allow more than 256
+ characters [GH-4815]
- communicators/winrm: improve error handling significantly and improve
the error messages shown to be more human-friendly. [GH-4943]
- hosts/nfs: allow colons (`:`) in NFS IDs [GH-5222]
+ - guests/darwin: remove dots from LocalHostName [GH-5558]
- guests/debian: Halt works properly on Debian 8. [GH-5369]
+ - guests/fedora: recognize future fedora releases [GH-5730]
+ - guests/fedora: reload iface connection by NetworkManager [GH-5709]
+ - guests/fedora: do not use biosdevname if it is not installed [GH-5707]
+ - guests/freebsd: provide an argument to the backup file [GH-5516, GH-5517]
- guests/funtoo: fix incorrect path in configure networks [GH-4812]
+ - guests/tinycore: fix change hostname functionality [GH-5623]
- guests/windows: Create rsync folder prior to rsync-ing. [GH-5282]
- guests/windows: Changing hostname requires reboot again since
the non-reboot code path was crashing Windows server. [GH-5261]
+ - guests/windows: ignore virtual NICs [GH-5478]
- hosts/windows: More accurately get host IP address in VPNs. [GH-5349]
- plugins/login: allow users to login with a token [GH-5145]
- providers/docker: Build image from `/var/lib/docker` for more disk
space on some systems. [GH-5302]
- providers/hyperv: allow users to configure memory, cpu count, and vmname [GH-5183]
- providers/hyperv: import respects secure boot. [GH-5209]
+ - providers/hyperv: only set EFI secure boot for gen 2 machines [GH-5538]
- providers/virtualbox: read netmask from dhcpservers [GH-5233]
- providers/virtualbox: Fix exception when VirtualBox version is empty. [GH-5308]
- provisioners/ansible: fix SSH settings to support more than 5 ssh keys [GH-5017]
- provisioners/ansible: increase ansible connection timeout to 30 seconds [GH-5018]
+ - provisioners/ansible: disable color if Vagrant is not colored [GH-5531, GH-5532]
+ - provisioners/docker: use `service` to restart Docker instad of upstart [GH-5245, GH-5577]
- provisioners/docker: Only add docker user to group if exists. [GH-5315]
+ - provisioners/docker: Use https for repo [GH-5749]
- provisioners/chef: Use `command -v` to check for binary instead of
`which` since that doesn't exist on some systems. [GH-5170]
- provisioners/chef-zero: support more chef-zero/local mode attributes [GH-5339]
- provisioners/docker: use docker.com instead of docker.io [GH-5216]
- pushes/atlas: send additional box metadata [GH-5283]
- - synced\_folders/rsync: Add `IdentitiesOnly=yes` to the rsync command. [GH-5175]
+ - pushes/ftp: improve check for remote directory existence [GH-5549]
+ - synced\_folders/rsync: add `IdentitiesOnly=yes` to the rsync command. [GH-5175]
+ - virtualbox/config: fix misleading error message for private_network [GH-5536, GH-5418]
## 1.7.2 (January 6, 2015)
@@ -133,7 +180,7 @@ IMPROVEMENTS:
- core: `has_plugin?` function now takes a second argument which is a
version constraint requirement. [GH-4650]
- - core: ".vagrantplugins" file in the same file as your Vagrantfile
+ - core: ".vagrantplugins" file in the same folder as your Vagrantfile
will be loaded for defining inline plugins. [GH-3775]
- commands/plugin: Plugin list machine-readable output contains the plugin
name as the target for versions and other info. [GH-4506]
diff --git a/Vagrantfile b/Vagrantfile
index e928b3c6b..1e20fca33 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -5,6 +5,8 @@
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
+ config.vm.hostname = "vagrant"
+ config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"
["vmware_fusion", "vmware_workstation", "virtualbox"].each do |provider|
config.vm.provider provider do |v, override|
@@ -24,6 +26,7 @@ Vagrant.configure("2") do |config|
end
$shell = <<-CONTENTS
+export DEBIAN_FRONTEND=noninteractive
MARKER_FILE="/usr/local/etc/vagrant_provision_marker"
# Only provision once
@@ -37,8 +40,11 @@ apt-get update
# Install basic dependencies
apt-get install -y build-essential bsdtar curl
+# Import the mpapis public key to verify downloaded releases
+su -l -c 'curl -sSL https://rvm.io/mpapis.asc | gpg -q --import -' vagrant
+
# Install RVM
-su -l -c 'curl -L https://get.rvm.io | bash -s stable' vagrant
+su -l -c 'curl -sL https://get.rvm.io | bash -s stable' vagrant
# Add the vagrant user to the RVM group
#usermod -a -G rvm vagrant
diff --git a/contrib/bash/completion.sh b/contrib/bash/completion.sh
index e21dc8dcf..2b201d1ba 100644
--- a/contrib/bash/completion.sh
+++ b/contrib/bash/completion.sh
@@ -70,8 +70,13 @@ _vagrant() {
return 0
;;
"up")
+ vagrant_state_file=$(__vagrantinvestigate) || return 1
+ if [[ -d $vagrant_state_file ]]
+ then
+ local vm_list=$(find $vagrant_state_file/machines -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
+ fi
local up_commands="--no-provision"
- COMPREPLY=($(compgen -W "${up_commands}" -- ${cur}))
+ COMPREPLY=($(compgen -W "${up_commands} ${vm_list}" -- ${cur}))
return 0
;;
"ssh"|"provision"|"reload"|"halt"|"suspend"|"resume"|"ssh-config")
@@ -107,18 +112,32 @@ _vagrant() {
if [ $COMP_CWORD == 3 ]
then
action="${COMP_WORDS[COMP_CWORD-2]}"
- if [ $action == 'box' ]
- then
- case "$prev" in
+ case "$action" in
+ "up")
+ if [ "$prev" == "--no-provision" ]
+ then
+ if [[ -d $vagrant_state_file ]]
+ then
+ local vm_list=$(find $vagrant_state_file/machines -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
+ fi
+ COMPREPLY=($(compgen -W "${vm_list}" -- ${cur}))
+ return 0
+ fi
+ ;;
+ "box")
+ case "$prev" in
"remove"|"repackage")
local box_list=$(find "${VAGRANT_HOME:-${HOME}/.vagrant.d}/boxes" -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
COMPREPLY=($(compgen -W "${box_list}" -- ${cur}))
return 0
;;
*)
- ;;
- esac
- fi
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
fi
}
diff --git a/lib/vagrant.rb b/lib/vagrant.rb
index 1fb9c49d6..eba026c51 100644
--- a/lib/vagrant.rb
+++ b/lib/vagrant.rb
@@ -139,10 +139,12 @@ module Vagrant
Config.run(version, &block)
end
- # This checks if a plugin with the given name is installed. This can
- # be used from the Vagrantfile to easily branch based on plugin
- # availability.
+ # This checks if a plugin with the given name is available (installed
+ # and enabled). This can be used from the Vagrantfile to easily branch
+ # based on plugin availability.
def self.has_plugin?(name, version=nil)
+ return false unless Vagrant.plugins_enabled?
+
if !version
# We check the plugin names first because those are cheaper to check
return true if plugin("2").manager.registered.any? { |p| p.name == name }
diff --git a/lib/vagrant/action/builtin/box_add.rb b/lib/vagrant/action/builtin/box_add.rb
index deed8b9ef..00c88f8c8 100644
--- a/lib/vagrant/action/builtin/box_add.rb
+++ b/lib/vagrant/action/builtin/box_add.rb
@@ -404,6 +404,7 @@ module Vagrant
downloader_options[:client_cert] = env[:box_download_client_cert]
downloader_options[:headers] = ["Accept: application/json"] if opts[:json]
downloader_options[:ui] = env[:ui] if opts[:ui]
+ downloader_options[:location_trusted] = env[:box_download_location_trusted]
Util::Downloader.new(url, temp_path, downloader_options)
end
@@ -420,8 +421,15 @@ module Vagrant
show_url = opts[:show_url]
show_url ||= url
+ translation = "vagrant.box_downloading"
+
+ # Adjust status message when 'downloading' a local box.
+ if show_url.start_with?("file://")
+ translation = "vagrant.box_unpacking"
+ end
+
env[:ui].detail(I18n.t(
- "vagrant.box_downloading",
+ translation,
url: show_url))
if File.file?(d.destination)
env[:ui].info(I18n.t("vagrant.actions.box.download.resuming"))
diff --git a/lib/vagrant/action/builtin/handle_box.rb b/lib/vagrant/action/builtin/handle_box.rb
index 8cbdd413c..5d7f6cf68 100644
--- a/lib/vagrant/action/builtin/handle_box.rb
+++ b/lib/vagrant/action/builtin/handle_box.rb
@@ -66,6 +66,7 @@ module Vagrant
box_download_insecure = machine.config.vm.box_download_insecure
box_download_checksum_type = machine.config.vm.box_download_checksum_type
box_download_checksum = machine.config.vm.box_download_checksum
+ box_download_location_trusted = machine.config.vm.box_download_location_trusted
box_formats = machine.provider_options[:box_format] ||
machine.provider_name
@@ -90,6 +91,7 @@ module Vagrant
box_download_insecure: box_download_insecure,
box_checksum_type: box_download_checksum_type,
box_checksum: box_download_checksum,
+ box_download_location_trusted: box_download_location_trusted,
}))
rescue Errors::BoxAlreadyExists
# Just ignore this, since it means the next part will succeed!
diff --git a/lib/vagrant/action/general/package.rb b/lib/vagrant/action/general/package.rb
index 99c0002ec..58991222c 100644
--- a/lib/vagrant/action/general/package.rb
+++ b/lib/vagrant/action/general/package.rb
@@ -29,9 +29,10 @@ module Vagrant
def call(env)
@env = env
-
+ file_name = File.basename(@env["package.output"].to_s)
+
raise Errors::PackageOutputDirectory if File.directory?(tar_path)
- raise Errors::PackageOutputExists if File.exist?(tar_path)
+ raise Errors::PackageOutputExists, file_name:file_name if File.exist?(tar_path)
raise Errors::PackageRequiresDirectory if !env["package.directory"] ||
!File.directory?(env["package.directory"])
diff --git a/lib/vagrant/box.rb b/lib/vagrant/box.rb
index 537c94e2a..ce829870a 100644
--- a/lib/vagrant/box.rb
+++ b/lib/vagrant/box.rb
@@ -173,7 +173,7 @@ module Vagrant
Util::SafeChdir.safe_chdir(@directory) do
# Find all the files in our current directory and tar it up!
- files = Dir.glob(File.join(".", "**", "*"))
+ files = Dir.glob(File.join(".", "**", "*")).select { |f| File.file?(f) }
# Package!
Util::Subprocess.execute("bsdtar", "-czf", path.to_s, *files)
diff --git a/lib/vagrant/config/loader.rb b/lib/vagrant/config/loader.rb
index 35b0d0828..e3f80a579 100644
--- a/lib/vagrant/config/loader.rb
+++ b/lib/vagrant/config/loader.rb
@@ -209,9 +209,16 @@ module Vagrant
@logger.error("Vagrantfile load error: #{e.message}")
@logger.error(e.backtrace.join("\n"))
+ line = "(unknown)"
+ if e.backtrace && e.backtrace[0]
+ line = e.backtrace[0].split(":")[1]
+ end
+
# Report the generic exception
raise Errors::VagrantfileLoadError,
path: path,
+ line: line,
+ exception_class: e.class,
message: e.message
end
end
diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb
index de002ffed..3072d50ff 100644
--- a/lib/vagrant/errors.rb
+++ b/lib/vagrant/errors.rb
@@ -316,6 +316,10 @@ module Vagrant
error_key(:corrupt_machine_index)
end
+ class DarwinMountFailed < VagrantError
+ error_key(:darwin_mount_failed)
+ end
+
class DarwinNFSMountFailed < VagrantError
error_key(:darwin_nfs_mount_failed)
end
diff --git a/lib/vagrant/ui.rb b/lib/vagrant/ui.rb
index a84448a1c..d26633f2f 100644
--- a/lib/vagrant/ui.rb
+++ b/lib/vagrant/ui.rb
@@ -21,9 +21,22 @@ module Vagrant
# specific. See the implementation for more docs.
attr_accessor :opts
+ # @return [IO] UI input. Defaults to `$stdin`.
+ attr_accessor :stdin
+
+ # @return [IO] UI output. Defaults to `$stdout`.
+ attr_accessor :stdout
+
+ # @return [IO] UI error output. Defaults to `$stderr`.
+ attr_accessor :stderr
+
def initialize
@logger = Log4r::Logger.new("vagrant::ui::interface")
@opts = {}
+
+ @stdin = $stdin
+ @stdout = $stdout
+ @stderr = $stderr
end
def initialize_copy(original)
@@ -132,7 +145,7 @@ module Vagrant
super(message)
# We can't ask questions when the output isn't a TTY.
- raise Errors::UIExpectsTTY if !$stdin.tty? && !Vagrant::Util::Platform.cygwin?
+ raise Errors::UIExpectsTTY if !@stdin.tty? && !Vagrant::Util::Platform.cygwin?
# Setup the options so that the new line is suppressed
opts ||= {}
@@ -144,11 +157,11 @@ module Vagrant
say(:info, message, opts)
input = nil
- if opts[:echo]
- input = $stdin.gets
+ if opts[:echo] || !@stdin.respond_to?(:noecho)
+ input = @stdin.gets
else
begin
- input = $stdin.noecho(&:gets)
+ input = @stdin.noecho(&:gets)
# Output a newline because without echo, the newline isn't
# echoed either.
@@ -206,7 +219,7 @@ module Vagrant
# Determine the proper IO channel to send this message
# to based on the type of the message
- channel = type == :error || opts[:channel] == :error ? $stderr : $stdout
+ channel = type == :error || opts[:channel] == :error ? @stderr : @stdout
# Output! We wrap this in a lock so that it safely outputs only
# one line at a time. We wrap this in a thread because as of Ruby 2.0
diff --git a/lib/vagrant/util/downloader.rb b/lib/vagrant/util/downloader.rb
index dd3abaa72..e03869351 100644
--- a/lib/vagrant/util/downloader.rb
+++ b/lib/vagrant/util/downloader.rb
@@ -27,10 +27,10 @@ module Vagrant
@destination = destination.to_s
begin
- url = URI.parse(@source)
+ url = URI.parse(URI.escape(@source))
if url.scheme && url.scheme.start_with?("http") && url.user
- auth = "#{url.user}"
- auth += ":#{url.password}" if url.password
+ auth = "#{URI.unescape(url.user)}"
+ auth += ":#{URI.unescape(url.password)}" if url.password
url.user = nil
url.password = nil
options[:auth] ||= auth
@@ -49,6 +49,7 @@ module Vagrant
@insecure = options[:insecure]
@ui = options[:ui]
@client_cert = options[:client_cert]
+ @location_trusted = options[:location_trusted]
end
# This executes the actual download, downloading the source file
@@ -224,6 +225,7 @@ module Vagrant
options << "--insecure" if @insecure
options << "--cert" << @client_cert if @client_cert
options << "-u" << @auth if @auth
+ options << "--location-trusted" if @location_trusted
if @headers
Array(@headers).each do |header|
diff --git a/lib/vagrant/util/platform.rb b/lib/vagrant/util/platform.rb
index c452eb295..706445c3b 100644
--- a/lib/vagrant/util/platform.rb
+++ b/lib/vagrant/util/platform.rb
@@ -144,6 +144,13 @@ module Vagrant
path
end
+ # Converts a given path to UNC format by adding a prefix and converting slashes.
+ # @param [String] path Path to convert to UNC for Windows
+ # @return [String]
+ def windows_unc_path(path)
+ "\\\\?\\" + path.gsub("/", "\\")
+ end
+
# Returns a boolean noting whether the terminal supports color.
# output.
def terminal_supports_colors?
diff --git a/lib/vagrant/util/ssh.rb b/lib/vagrant/util/ssh.rb
index 0a71613c7..586c66c6d 100644
--- a/lib/vagrant/util/ssh.rb
+++ b/lib/vagrant/util/ssh.rb
@@ -83,7 +83,7 @@ module Vagrant
# underneath the covers. In this case, we tell the user.
if Platform.windows?
r = Subprocess.execute(ssh_path)
- if r.stdout.include?("PuTTY Link")
+ if r.stdout.include?("PuTTY Link") || r.stdout.include?("Plink: command-line connection utility")
raise Errors::SSHIsPuttyLink,
host: ssh_info[:host],
port: ssh_info[:port],
diff --git a/plugins/commands/box/command/add.rb b/plugins/commands/box/command/add.rb
index d82d441a8..114601024 100644
--- a/plugins/commands/box/command/add.rb
+++ b/plugins/commands/box/command/add.rb
@@ -38,6 +38,10 @@ module VagrantPlugins
options[:client_cert] = c
end
+ o.on("--location-trusted", "Trust 'Location' header from HTTP redirects and use the same credentials for subsequent urls as for the initial one") do |l|
+ options[:location_trusted] = l
+ end
+
o.on("--provider PROVIDER", String, "Provider the box should satisfy") do |p|
options[:provider] = p
end
@@ -95,6 +99,7 @@ module VagrantPlugins
box_download_ca_path: options[:ca_path],
box_download_client_cert: options[:client_cert],
box_download_insecure: options[:insecure],
+ box_download_location_trusted: options[:location_trusted],
ui: Vagrant::UI::Prefixed.new(@env.ui, "box"),
})
diff --git a/plugins/commands/rdp/command.rb b/plugins/commands/rdp/command.rb
index 156312dd2..e41c177fc 100644
--- a/plugins/commands/rdp/command.rb
+++ b/plugins/commands/rdp/command.rb
@@ -69,7 +69,15 @@ module VagrantPlugins
end
rdp_info[:username] = username
end
-
+
+ if !rdp_info[:password]
+ password = ssh_info[:password]
+ if machine.config.vm.communicator == :winrm
+ password = machine.config.winrm.password
+ end
+ rdp_info[:password] = password
+ end
+
rdp_info[:host] ||= ssh_info[:host]
rdp_info[:port] ||= machine.config.rdp.port
diff --git a/plugins/communicators/ssh/communicator.rb b/plugins/communicators/ssh/communicator.rb
index 64455042b..4109a66ff 100644
--- a/plugins/communicators/ssh/communicator.rb
+++ b/plugins/communicators/ssh/communicator.rb
@@ -434,6 +434,21 @@ module VagrantPlugins
return yield connection if block_given?
end
+ # The shell wrapper command used in shell_execute defined by
+ # the sudo and shell options.
+ def shell_cmd(opts)
+ sudo = opts[:sudo]
+ shell = opts[:shell]
+
+ # Determine the shell to execute. Prefer the explicitly passed in shell
+ # over the default configured shell. If we are using `sudo` then we
+ # need to wrap the shell in a `sudo` call.
+ cmd = @machine.config.ssh.shell
+ cmd = shell if shell
+ cmd = "sudo -E -H #{cmd}" if sudo
+ cmd
+ end
+
# Executes the command on an SSH connection within a login shell.
def shell_execute(connection, command, **opts)
opts = {
@@ -442,18 +457,10 @@ module VagrantPlugins
}.merge(opts)
sudo = opts[:sudo]
- shell = opts[:shell]
@logger.info("Execute: #{command} (sudo=#{sudo.inspect})")
exit_status = nil
- # Determine the shell to execute. Prefer the explicitly passed in shell
- # over the default configured shell. If we are using `sudo` then we
- # need to wrap the shell in a `sudo` call.
- shell_cmd = @machine.config.ssh.shell
- shell_cmd = shell if shell
- shell_cmd = "sudo -E -H #{shell_cmd}" if sudo
-
# These variables are used to scrub PTY output if we're in a PTY
pty = false
pty_stdout = ""
@@ -472,7 +479,7 @@ module VagrantPlugins
end
end
- ch.exec(shell_cmd) do |ch2, _|
+ ch.exec(shell_cmd(opts)) do |ch2, _|
# Setup the channel callbacks so we can get data and exit status
ch2.on_data do |ch3, data|
# Filter out the clear screen command
diff --git a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
index 454e5e874..923f034bb 100644
--- a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
+++ b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
@@ -27,7 +27,7 @@ $task_xml = @'
false
false
- true
+ false
false
true
diff --git a/plugins/guests/darwin/cap/change_host_name.rb b/plugins/guests/darwin/cap/change_host_name.rb
index ad7242c91..c65c32642 100644
--- a/plugins/guests/darwin/cap/change_host_name.rb
+++ b/plugins/guests/darwin/cap/change_host_name.rb
@@ -6,7 +6,9 @@ module VagrantPlugins
if !machine.communicate.test("hostname -f | grep '^#{name}$' || hostname -s | grep '^#{name}$'")
machine.communicate.sudo("scutil --set ComputerName #{name}")
machine.communicate.sudo("scutil --set HostName #{name}")
- machine.communicate.sudo("scutil --set LocalHostName #{name}")
+ # LocalHostName shouldn't contain dots.
+ # It is used by Bonjour and visible through file sharing services.
+ machine.communicate.sudo("scutil --set LocalHostName #{name.gsub(/\.+/, '')}")
machine.communicate.sudo("hostname #{name}")
end
end
diff --git a/plugins/guests/darwin/cap/choose_addressable_ip_addr.rb b/plugins/guests/darwin/cap/choose_addressable_ip_addr.rb
new file mode 100644
index 000000000..f5b578ebd
--- /dev/null
+++ b/plugins/guests/darwin/cap/choose_addressable_ip_addr.rb
@@ -0,0 +1,20 @@
+module VagrantPlugins
+ module GuestDarwin
+ module Cap
+ module ChooseAddressableIPAddr
+ def self.choose_addressable_ip_addr(machine, possible)
+ machine.communicate.tap do |comm|
+ possible.each do |ip|
+ command = "ping -c1 -t1 #{ip}"
+ if comm.test(command)
+ return ip
+ end
+ end
+ end
+
+ nil
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/darwin/cap/mount_smb_shared_folder.rb b/plugins/guests/darwin/cap/mount_smb_shared_folder.rb
new file mode 100644
index 000000000..5f1cdaec4
--- /dev/null
+++ b/plugins/guests/darwin/cap/mount_smb_shared_folder.rb
@@ -0,0 +1,37 @@
+require "vagrant/util/retryable"
+require "shellwords"
+
+module VagrantPlugins
+ module GuestDarwin
+ module Cap
+ class MountSMBSharedFolder
+ extend Vagrant::Util::Retryable
+ def self.mount_smb_shared_folder(machine, name, guestpath, options)
+ expanded_guest_path = machine.guest.capability(:shell_expand_guest_path, guestpath)
+
+ mount_point_owner = options[:owner];
+ if mount_point_owner
+ machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
+ machine.communicate.sudo("chown #{mount_point_owner} #{expanded_guest_path}")
+ else
+ # fallback to assumption that user has permission
+ # to create the specified mountpoint
+ machine.communicate.execute("mkdir -p #{expanded_guest_path}")
+ end
+
+ smb_password = Shellwords.shellescape(options[:smb_password])
+ mount_options = options[:mount_options];
+ mount_command = "mount -t smbfs " +
+ (mount_options ? "-o '#{mount_options.join(",")}' " : "") +
+ "'//#{options[:smb_username]}:#{smb_password}@#{options[:smb_host]}/#{name}' " +
+ "#{expanded_guest_path}"
+ retryable(on: Vagrant::Errors::DarwinMountFailed, tries: 10, sleep: 2) do
+ machine.communicate.execute(
+ mount_command,
+ error_class: Vagrant::Errors::DarwinMountFailed)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/darwin/plugin.rb b/plugins/guests/darwin/plugin.rb
index 305154fde..8e6dc279b 100644
--- a/plugins/guests/darwin/plugin.rb
+++ b/plugins/guests/darwin/plugin.rb
@@ -16,6 +16,11 @@ module VagrantPlugins
Cap::ChangeHostName
end
+ guest_capability("darwin", "choose_addressable_ip_addr") do
+ require_relative "cap/choose_addressable_ip_addr"
+ Cap::ChooseAddressableIPAddr
+ end
+
guest_capability("darwin", "configure_networks") do
require_relative "cap/configure_networks"
Cap::ConfigureNetworks
@@ -36,6 +41,11 @@ module VagrantPlugins
Cap::MountNFSFolder
end
+ guest_capability("darwin", "mount_smb_shared_folder") do
+ require_relative "cap/mount_smb_shared_folder"
+ Cap::MountSMBSharedFolder
+ end
+
guest_capability("darwin", "mount_vmware_shared_folder") do
require_relative "cap/mount_vmware_shared_folder"
Cap::MountVmwareSharedFolder
diff --git a/plugins/guests/debian/cap/configure_networks.rb b/plugins/guests/debian/cap/configure_networks.rb
index 3cb896b15..cf416ec09 100644
--- a/plugins/guests/debian/cap/configure_networks.rb
+++ b/plugins/guests/debian/cap/configure_networks.rb
@@ -14,7 +14,7 @@ module VagrantPlugins
# First, remove any previous network modifications
# from the interface file.
comm.sudo("sed -e '/^#VAGRANT-BEGIN/,$ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces.pre")
- comm.sudo("sed -ne '/^#VAGRANT-END/,$ p' /etc/network/interfaces | tail -n +2 > /tmp/vagrant-network-interfaces.post")
+ comm.sudo("sed -ne '/^#VAGRANT-END/,$ p' /etc/network/interfaces | tac | sed -e '/^#VAGRANT-END/,$ d' | tac > /tmp/vagrant-network-interfaces.post")
# Accumulate the configurations to add to the interfaces file as
# well as what interfaces we're actually configuring since we use that
diff --git a/plugins/guests/fedora/cap/configure_networks.rb b/plugins/guests/fedora/cap/configure_networks.rb
index 2f67099cd..031a77586 100644
--- a/plugins/guests/fedora/cap/configure_networks.rb
+++ b/plugins/guests/fedora/cap/configure_networks.rb
@@ -17,7 +17,7 @@ module VagrantPlugins
virtual = false
interface_names = Array.new
machine.communicate.sudo("/usr/sbin/biosdevname; echo $?") do |_, result|
- virtual = true if result.chomp == '4'
+ virtual = true if ['4', '127'].include? result.chomp
end
if virtual
@@ -85,6 +85,7 @@ module VagrantPlugins
interfaces.each do |interface|
retryable(on: Vagrant::Errors::VagrantError, tries: 3, sleep: 2) do
machine.communicate.sudo("cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-#{interface}")
+ machine.communicate.sudo("which nmcli >/dev/null 2>&1 && nmcli c reload #{interface}")
machine.communicate.sudo("/sbin/ifdown #{interface}", error_check: true)
machine.communicate.sudo("/sbin/ifup #{interface}")
end
diff --git a/plugins/guests/fedora/cap/flavor.rb b/plugins/guests/fedora/cap/flavor.rb
new file mode 100644
index 000000000..2a29f50b5
--- /dev/null
+++ b/plugins/guests/fedora/cap/flavor.rb
@@ -0,0 +1,23 @@
+module VagrantPlugins
+ module GuestFedora
+ module Cap
+ class Flavor
+ def self.flavor(machine)
+ # Read the version file
+ version = nil
+ machine.communicate.sudo("grep VERSION_ID /etc/os-release") do |type, data|
+ if type == :stdout
+ version = data.split("=")[1].chomp.to_i
+ end
+ end
+
+ if version.nil?
+ return :fedora
+ else
+ return "fedora_#{version}".to_sym
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/fedora/cap/nfs_client.rb b/plugins/guests/fedora/cap/nfs_client.rb
new file mode 100644
index 000000000..58e084510
--- /dev/null
+++ b/plugins/guests/fedora/cap/nfs_client.rb
@@ -0,0 +1,11 @@
+module VagrantPlugins
+ module GuestFedora
+ module Cap
+ class NFSClient
+ def self.nfs_client_install(machine)
+ machine.communicate.sudo("yum -y install nfs-utils nfs-utils-lib")
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/fedora/guest.rb b/plugins/guests/fedora/guest.rb
index 64a5e3d86..c1b48d4ab 100644
--- a/plugins/guests/fedora/guest.rb
+++ b/plugins/guests/fedora/guest.rb
@@ -4,7 +4,7 @@ module VagrantPlugins
module GuestFedora
class Guest < Vagrant.plugin("2", :guest)
def detect?(machine)
- machine.communicate.test("grep 'Fedora release [12][678901]' /etc/redhat-release")
+ machine.communicate.test("grep 'Fedora release 1[6789]\\|Fedora release 2[0-9]' /etc/redhat-release")
end
end
end
diff --git a/plugins/guests/fedora/plugin.rb b/plugins/guests/fedora/plugin.rb
index 66b2d111f..78e376f96 100644
--- a/plugins/guests/fedora/plugin.rb
+++ b/plugins/guests/fedora/plugin.rb
@@ -25,6 +25,16 @@ module VagrantPlugins
require_relative "cap/network_scripts_dir"
Cap::NetworkScriptsDir
end
+
+ guest_capability("fedora", "flavor") do
+ require_relative "cap/flavor"
+ Cap::Flavor
+ end
+
+ guest_capability("fedora", "nfs_client_install") do
+ require_relative "cap/nfs_client"
+ Cap::NFSClient
+ end
end
end
end
diff --git a/plugins/guests/freebsd/cap/remove_public_key.rb b/plugins/guests/freebsd/cap/remove_public_key.rb
index 13abc864b..8d5526ca4 100644
--- a/plugins/guests/freebsd/cap/remove_public_key.rb
+++ b/plugins/guests/freebsd/cap/remove_public_key.rb
@@ -11,7 +11,7 @@ module VagrantPlugins
machine.communicate.tap do |comm|
if comm.test("test -f ~/.ssh/authorized_keys")
comm.execute(
- "sed -i '/^.*#{contents}.*$/d' ~/.ssh/authorized_keys")
+ "sed -i .bak '/^.*#{contents}.*$/d' ~/.ssh/authorized_keys")
end
end
end
diff --git a/plugins/guests/linux/cap/mount_smb_shared_folder.rb b/plugins/guests/linux/cap/mount_smb_shared_folder.rb
index 424982520..ca14cf148 100644
--- a/plugins/guests/linux/cap/mount_smb_shared_folder.rb
+++ b/plugins/guests/linux/cap/mount_smb_shared_folder.rb
@@ -27,10 +27,14 @@ module VagrantPlugins
smb_password = Shellwords.shellescape(options[:smb_password])
+ # If a domain is provided in the username, separate it
+ username, domain = (options[:smb_username] || '').split('@', 2)
+
options[:mount_options] ||= []
options[:mount_options] << "sec=ntlm"
- options[:mount_options] << "username=#{options[:smb_username]}"
+ options[:mount_options] << "username=#{username}"
options[:mount_options] << "pass=#{smb_password}"
+ options[:mount_options] << "domain=#{domain}" if domain
# First mount command uses getent to get the group
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}"
diff --git a/plugins/guests/photon/cap/change_host_name.rb b/plugins/guests/photon/cap/change_host_name.rb
new file mode 100644
index 000000000..5249dadba
--- /dev/null
+++ b/plugins/guests/photon/cap/change_host_name.rb
@@ -0,0 +1,15 @@
+module VagrantPlugins
+ module GuestPhoton
+ module Cap
+ class ChangeHostName
+ def self.change_host_name(machine, name)
+ machine.communicate.tap do |comm|
+ unless comm.test("sudo hostname --fqdn | grep '#{name}'")
+ comm.sudo("hostname #{name.split('.')[0]}")
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/photon/cap/configure_networks.rb b/plugins/guests/photon/cap/configure_networks.rb
new file mode 100644
index 000000000..50f4737b8
--- /dev/null
+++ b/plugins/guests/photon/cap/configure_networks.rb
@@ -0,0 +1,42 @@
+require 'tempfile'
+require 'vagrant/util/template_renderer'
+
+module VagrantPlugins
+ module GuestPhoton
+ module Cap
+ class ConfigureNetworks
+ include Vagrant::Util
+
+ def self.configure_networks(machine, networks)
+ machine.communicate.tap do |comm|
+ # Read network interface names
+ interfaces = []
+ comm.sudo("ifconfig | grep 'eth' | cut -f1 -d' '") do |_, result|
+ interfaces = result.split("\n")
+ end
+
+ # Configure interfaces
+ networks.each do |network|
+ comm.sudo("ifconfig #{interfaces[network[:interface].to_i]} #{network[:ip]} netmask #{network[:netmask]}")
+ end
+
+ primary_machine_config = machine.env.active_machines.first
+ primary_machine = machine.env.machine(*primary_machine_config, true)
+
+ get_ip = lambda do |machine|
+ ip = nil
+ machine.config.vm.networks.each do |type, opts|
+ if type == :private_network && opts[:ip]
+ ip = opts[:ip]
+ break
+ end
+ end
+
+ ip
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/photon/cap/docker.rb b/plugins/guests/photon/cap/docker.rb
new file mode 100644
index 000000000..954777908
--- /dev/null
+++ b/plugins/guests/photon/cap/docker.rb
@@ -0,0 +1,11 @@
+module VagrantPlugins
+ module GuestPhoton
+ module Cap
+ module Docker
+ def self.docker_daemon_running(machine)
+ machine.communicate.test('test -S /run/docker.sock')
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/photon/guest.rb b/plugins/guests/photon/guest.rb
new file mode 100644
index 000000000..c33a9f8a2
--- /dev/null
+++ b/plugins/guests/photon/guest.rb
@@ -0,0 +1,9 @@
+module VagrantPlugins
+ module GuestPhoton
+ class Guest < Vagrant.plugin('2', :guest)
+ def detect?(machine)
+ machine.communicate.test("cat /etc/photon-release | grep 'VMware Photon Linux'")
+ end
+ end
+ end
+end
diff --git a/plugins/guests/photon/plugin.rb b/plugins/guests/photon/plugin.rb
new file mode 100644
index 000000000..a56a0f44f
--- /dev/null
+++ b/plugins/guests/photon/plugin.rb
@@ -0,0 +1,30 @@
+require 'vagrant'
+
+module VagrantPlugins
+ module GuestPhoton
+ class Plugin < Vagrant.plugin('2')
+ name 'VMware Photon guest'
+ description 'VMware Photon guest support.'
+
+ guest('photon', 'linux') do
+ require File.expand_path("../guest", __FILE__)
+ Guest
+ end
+
+ guest_capability('photon', 'change_host_name') do
+ require_relative 'cap/change_host_name'
+ Cap::ChangeHostName
+ end
+
+ guest_capability('photon', 'configure_networks') do
+ require_relative 'cap/configure_networks'
+ Cap::ConfigureNetworks
+ end
+
+ guest_capability('photon', 'docker_daemon_running') do
+ require_relative 'cap/docker'
+ Cap::Docker
+ end
+ end
+ end
+end
diff --git a/plugins/guests/tinycore/cap/change_host_name.rb b/plugins/guests/tinycore/cap/change_host_name.rb
index 2c16af362..1c4ec8590 100644
--- a/plugins/guests/tinycore/cap/change_host_name.rb
+++ b/plugins/guests/tinycore/cap/change_host_name.rb
@@ -4,7 +4,6 @@ module VagrantPlugins
class ChangeHostName
def self.change_host_name(machine, name)
if !machine.communicate.test("hostname | grep '^#{name}$'")
- machine.communicate.sudo("sh -c 'echo \"#{name}\" > /etc/hostname'")
machine.communicate.sudo("/usr/bin/sethostname #{name}")
end
end
diff --git a/plugins/guests/tinycore/plugin.rb b/plugins/guests/tinycore/plugin.rb
index b7553fa0a..3febbb16f 100644
--- a/plugins/guests/tinycore/plugin.rb
+++ b/plugins/guests/tinycore/plugin.rb
@@ -16,6 +16,11 @@ module VagrantPlugins
Cap::ConfigureNetworks
end
+ guest_capability("tinycore", "change_host_name") do
+ require_relative "cap/change_host_name"
+ Cap::ChangeHostName
+ end
+
guest_capability("tinycore", "halt") do
require_relative "cap/halt"
Cap::Halt
diff --git a/plugins/guests/windows/cap/configure_networks.rb b/plugins/guests/windows/cap/configure_networks.rb
index 8130cef77..8e766a319 100644
--- a/plugins/guests/windows/cap/configure_networks.rb
+++ b/plugins/guests/windows/cap/configure_networks.rb
@@ -64,7 +64,9 @@ module VagrantPlugins
guest_network.network_adapters.each do |nic|
@@logger.debug("nic: #{nic.inspect}")
naked_mac = nic[:mac_address].gsub(':','')
- if driver_mac_address[naked_mac]
+ # If the :net_connection_id entry is nil then it is probably a virtual connection
+ # and should be ignored.
+ if driver_mac_address[naked_mac] && !nic[:net_connection_id].nil?
vm_interface_map[driver_mac_address[naked_mac]] = {
net_connection_id: nic[:net_connection_id],
mac_address: naked_mac,
diff --git a/plugins/kernel_v2/config/vm.rb b/plugins/kernel_v2/config/vm.rb
index 11947a30c..294a63e19 100644
--- a/plugins/kernel_v2/config/vm.rb
+++ b/plugins/kernel_v2/config/vm.rb
@@ -27,6 +27,7 @@ module VagrantPlugins
attr_accessor :box_download_checksum_type
attr_accessor :box_download_client_cert
attr_accessor :box_download_insecure
+ attr_accessor :box_download_location_trusted
attr_accessor :communicator
attr_accessor :graceful_halt_timeout
attr_accessor :guest
@@ -36,25 +37,28 @@ module VagrantPlugins
attr_reader :provisioners
def initialize
- @base_mac = UNSET_VALUE
- @boot_timeout = UNSET_VALUE
- @box = UNSET_VALUE
- @box_check_update = UNSET_VALUE
- @box_download_ca_cert = UNSET_VALUE
- @box_download_ca_path = UNSET_VALUE
- @box_download_checksum = UNSET_VALUE
- @box_download_checksum_type = UNSET_VALUE
- @box_download_client_cert = UNSET_VALUE
- @box_download_insecure = UNSET_VALUE
- @box_url = UNSET_VALUE
- @box_version = UNSET_VALUE
- @communicator = UNSET_VALUE
- @graceful_halt_timeout = UNSET_VALUE
- @guest = UNSET_VALUE
- @hostname = UNSET_VALUE
- @post_up_message = UNSET_VALUE
- @provisioners = []
- @usable_port_range = UNSET_VALUE
+ @logger = Log4r::Logger.new("vagrant::config::vm")
+
+ @base_mac = UNSET_VALUE
+ @boot_timeout = UNSET_VALUE
+ @box = UNSET_VALUE
+ @box_check_update = UNSET_VALUE
+ @box_download_ca_cert = UNSET_VALUE
+ @box_download_ca_path = UNSET_VALUE
+ @box_download_checksum = UNSET_VALUE
+ @box_download_checksum_type = UNSET_VALUE
+ @box_download_client_cert = UNSET_VALUE
+ @box_download_insecure = UNSET_VALUE
+ @box_download_location_trusted = UNSET_VALUE
+ @box_url = UNSET_VALUE
+ @box_version = UNSET_VALUE
+ @communicator = UNSET_VALUE
+ @graceful_halt_timeout = UNSET_VALUE
+ @guest = UNSET_VALUE
+ @hostname = UNSET_VALUE
+ @post_up_message = UNSET_VALUE
+ @provisioners = []
+ @usable_port_range = UNSET_VALUE
# Internal state
@__compiled_provider_configs = {}
@@ -357,6 +361,7 @@ module VagrantPlugins
@box_download_checksum_type = nil if @box_download_checksum_type == UNSET_VALUE
@box_download_client_cert = nil if @box_download_client_cert == UNSET_VALUE
@box_download_insecure = false if @box_download_insecure == UNSET_VALUE
+ @box_download_location_trusted = false if @box_download_location_trusted == UNSET_VALUE
@box_url = nil if @box_url == UNSET_VALUE
@box_version = nil if @box_version == UNSET_VALUE
@communicator = nil if @communicator == UNSET_VALUE
@@ -443,8 +448,20 @@ module VagrantPlugins
config = config.merge(new_config)
end
rescue Exception => e
+ @logger.error("Vagrantfile load error: #{e.message}")
+ @logger.error(e.inspect)
+ @logger.error(e.message)
+ @logger.error(e.backtrace.join("\n"))
+
+ line = "(unknown)"
+ if e.backtrace && e.backtrace[0]
+ line = e.backtrace[0].split(":")[1]
+ end
+
raise Vagrant::Errors::VagrantfileLoadError,
path: "",
+ line: line,
+ exception_class: e.class,
message: e.message
end
diff --git a/plugins/providers/hyperv/action.rb b/plugins/providers/hyperv/action.rb
index 49e2be33f..64fbec180 100644
--- a/plugins/providers/hyperv/action.rb
+++ b/plugins/providers/hyperv/action.rb
@@ -116,6 +116,7 @@ module VagrantPlugins
end
b2.use Provision
+ b2.use NetSetVLan
b2.use StartInstance
b2.use WaitForIPAddress
b2.use WaitForCommunicator, [:running]
@@ -216,6 +217,7 @@ module VagrantPlugins
autoload :StopInstance, action_root.join('stop_instance')
autoload :SuspendVM, action_root.join("suspend_vm")
autoload :WaitForIPAddress, action_root.join("wait_for_ip_address")
+ autoload :NetSetVLan, action_root.join("net_set_vlan")
autoload :MessageWillNotDestroy, action_root.join("message_will_not_destroy")
end
end
diff --git a/plugins/providers/hyperv/action/import.rb b/plugins/providers/hyperv/action/import.rb
index 468a55c57..0b617ad54 100644
--- a/plugins/providers/hyperv/action/import.rb
+++ b/plugins/providers/hyperv/action/import.rb
@@ -55,23 +55,39 @@ module VagrantPlugins
switches = env[:machine].provider.driver.execute("get_switches.ps1", {})
raise Errors::NoSwitches if switches.empty?
- switch = switches[0]["Name"]
- if switches.length > 1
- env[:ui].detail(I18n.t("vagrant_hyperv.choose_switch") + "\n ")
- switches.each_index do |i|
- switch = switches[i]
- env[:ui].detail("#{i+1}) #{switch["Name"]}")
- end
- env[:ui].detail(" ")
+ switch = nil
+ env[:machine].config.vm.networks.each do |type, opts|
+ next if type != :public_network && type != :private_network
- switch = nil
- while !switch
- switch = env[:ui].ask("What switch would you like to use? ")
- next if !switch
- switch = switch.to_i - 1
- switch = nil if switch < 0 || switch >= switches.length
+ switchToFind = opts[:bridge]
+
+ if switchToFind
+ puts "Looking for switch with name: #{switchToFind}"
+ switch = switches.find { |s| s["Name"].downcase == switchToFind.downcase }["Name"]
+ puts "Found switch: #{switch}"
+ end
+ end
+
+ if switch.nil?
+ if switches.length > 1
+ env[:ui].detail(I18n.t("vagrant_hyperv.choose_switch") + "\n ")
+ switches.each_index do |i|
+ switch = switches[i]
+ env[:ui].detail("#{i+1}) #{switch["Name"]}")
+ end
+ env[:ui].detail(" ")
+
+ switch = nil
+ while !switch
+ switch = env[:ui].ask("What switch would you like to use? ")
+ next if !switch
+ switch = switch.to_i - 1
+ switch = nil if switch < 0 || switch >= switches.length
+ end
+ switch = switches[switch]["Name"]
+ else
+ switch = switches[0]["Name"]
end
- switch = switches[switch]["Name"]
end
env[:ui].detail("Cloning virtual hard drive...")
diff --git a/plugins/providers/hyperv/action/net_set_vlan.rb b/plugins/providers/hyperv/action/net_set_vlan.rb
new file mode 100644
index 000000000..c65f5a7cb
--- /dev/null
+++ b/plugins/providers/hyperv/action/net_set_vlan.rb
@@ -0,0 +1,20 @@
+module VagrantPlugins
+ module HyperV
+ module Action
+ class NetSetVLan
+ def initialize(app, env)
+ @app = app
+ end
+
+ def call(env)
+ vlan_id = env[:machine].provider_config.vlan_id
+ if vlan_id
+ env[:ui].info("[Settings] [Network Adapter] Setting Vlan ID to: #{vlan_id}")
+ env[:machine].provider.driver.net_set_vlan(vlan_id)
+ end
+ @app.call(env)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/hyperv/config.rb b/plugins/providers/hyperv/config.rb
index 89b51c0a6..fe247a242 100644
--- a/plugins/providers/hyperv/config.rb
+++ b/plugins/providers/hyperv/config.rb
@@ -3,15 +3,13 @@ require "vagrant"
module VagrantPlugins
module HyperV
class Config < Vagrant.plugin("2", :config)
- # The timeout to wait for an IP address when booting the machine,
- # in seconds.
- #
- # @return [Integer]
- attr_accessor :ip_address_timeout
- attr_accessor :memory
- attr_accessor :maxmemory
- attr_accessor :cpus
- attr_accessor :vmname
+
+ attr_accessor :ip_address_timeout # Time to wait for an IP address when booting, in seconds @return [Integer]
+ attr_accessor :memory # Memory size in mb @return [Integer]
+ attr_accessor :maxmemory # Maximal memory size in mb enables dynamical memory allocation @return [Integer]
+ attr_accessor :cpus # Number of cpu's @return [Integer]
+ attr_accessor :vmname # Name that will be shoen in Hyperv Manager @return [String]
+ attr_accessor :vlan_id # VLAN ID for network interface for the virtual machine. @return [Integer]
def initialize
@ip_address_timeout = UNSET_VALUE
@@ -19,6 +17,7 @@ module VagrantPlugins
@maxmemory = UNSET_VALUE
@cpus = UNSET_VALUE
@vmname = UNSET_VALUE
+ @vlan_id = UNSET_VALUE
end
def finalize!
@@ -29,6 +28,7 @@ module VagrantPlugins
@maxmemory = nil if @maxmemory == UNSET_VALUE
@cpus = nil if @cpus == UNSET_VALUE
@vmname = nil if @vmname == UNSET_VALUE
+ @vlan_id = nil if @vlan_id == UNSET_VALUE
end
def validate(machine)
diff --git a/plugins/providers/hyperv/driver.rb b/plugins/providers/hyperv/driver.rb
index 9f11881e6..db99d5dfe 100644
--- a/plugins/providers/hyperv/driver.rb
+++ b/plugins/providers/hyperv/driver.rb
@@ -77,6 +77,10 @@ module VagrantPlugins
execute('import_vm.ps1', options)
end
+ def net_set_vlan(vlan_id)
+ execute("set_network_vlan.ps1", { VmId: vm_id, VlanId: vlan_id })
+ end
+
protected
def execute_powershell(path, options, &block)
diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1
index 791daecd7..3e8664eb2 100644
--- a/plugins/providers/hyperv/scripts/import_vm.ps1
+++ b/plugins/providers/hyperv/scripts/import_vm.ps1
@@ -136,11 +136,14 @@ $vm | Set-VM @more_vm_params -Passthru
# Add drives to the virtual machine
$controllers = Select-Xml -xml $vmconfig -xpath "//*[starts-with(name(.),'controller')]"
-# Set EFI secure boot
-if ($secure_boot_enabled -eq "True") {
- Set-VMFirmware -VM $vm -EnableSecureBoot On
-} else {
- Set-VMFirmware -VM $vm -EnableSecureBoot Off
+# Only set EFI secure boot for Gen 2 machines, not gen 1
+if ($generation -ne 1) {
+ # Set EFI secure boot
+ if ($secure_boot_enabled -eq "True") {
+ Set-VMFirmware -VM $vm -EnableSecureBoot On
+ } else {
+ Set-VMFirmware -VM $vm -EnableSecureBoot Off
+ }
}
# A regular expression pattern to pull the number from controllers
diff --git a/plugins/providers/hyperv/scripts/set_network_vlan.ps1 b/plugins/providers/hyperv/scripts/set_network_vlan.ps1
new file mode 100644
index 000000000..a2b271b91
--- /dev/null
+++ b/plugins/providers/hyperv/scripts/set_network_vlan.ps1
@@ -0,0 +1,18 @@
+param (
+ [string]$VmId = $(throw "-VmId is required."),
+ [int]$VlanId = $(throw "-VlanId ")
+ )
+
+# Include the following modules
+$presentDir = Split-Path -parent $PSCommandPath
+$modules = @()
+$modules += $presentDir + "\utils\write_messages.ps1"
+forEach ($module in $modules) { . $module }
+
+try {
+ $vm = Get-VM -Id $VmId -ErrorAction "stop"
+ Set-VMNetworkAdapterVlan $vm -Access -Vlanid $VlanId
+}
+catch {
+ Write-Error-Message "Failed to set VM's Vlan ID $_"
+}
diff --git a/plugins/providers/virtualbox/action/network.rb b/plugins/providers/virtualbox/action/network.rb
index f1beff00b..a95b79857 100644
--- a/plugins/providers/virtualbox/action/network.rb
+++ b/plugins/providers/virtualbox/action/network.rb
@@ -157,14 +157,16 @@ module VagrantPlugins
@logger.debug("Bridge was directly specified in config, searching for: #{config[:bridge]}")
# Search for a matching bridged interface
- bridge = config[:bridge]
- bridge = bridge.downcase if bridge.respond_to?(:downcase)
- bridgedifs.each do |interface|
- if bridge === interface[:name].downcase
- @logger.debug("Specific bridge found as configured in the Vagrantfile. Using it.")
- chosen_bridge = interface[:name]
- break
+ Array(config[:bridge]).each do |bridge|
+ bridge = bridge.downcase if bridge.respond_to?(:downcase)
+ bridgedifs.each do |interface|
+ if bridge === interface[:name].downcase
+ @logger.debug("Specific bridge found as configured in the Vagrantfile. Using it.")
+ chosen_bridge = interface[:name]
+ break
+ end
end
+ break if chosen_bridge
end
# If one wasn't found, then we notify the user here.
diff --git a/plugins/providers/virtualbox/driver/meta.rb b/plugins/providers/virtualbox/driver/meta.rb
index 8fb8867f1..10bef3f8f 100644
--- a/plugins/providers/virtualbox/driver/meta.rb
+++ b/plugins/providers/virtualbox/driver/meta.rb
@@ -49,7 +49,8 @@ module VagrantPlugins
"4.0" => Version_4_0,
"4.1" => Version_4_1,
"4.2" => Version_4_2,
- "4.3" => Version_4_3
+ "4.3" => Version_4_3,
+ "5.0" => Version_5_0,
}
if @version.start_with?("4.2.14")
diff --git a/plugins/providers/virtualbox/driver/version_4_3.rb b/plugins/providers/virtualbox/driver/version_4_3.rb
index 2d257a8c1..07c17cef8 100644
--- a/plugins/providers/virtualbox/driver/version_4_3.rb
+++ b/plugins/providers/virtualbox/driver/version_4_3.rb
@@ -496,10 +496,14 @@ module VagrantPlugins
def share_folders(folders)
folders.each do |folder|
+ hostpath = folder[:hostpath]
+ if Vagrant::Util::Platform.windows?
+ hostpath = Vagrant::Util::Platform.windows_unc_path(hostpath)
+ end
args = ["--name",
folder[:name],
"--hostpath",
- folder[:hostpath]]
+ hostpath]
args << "--transient" if folder.key?(:transient) && folder[:transient]
# Enable symlinks on the shared folder
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
new file mode 100644
index 000000000..d7d3b58df
--- /dev/null
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -0,0 +1,619 @@
+require 'log4r'
+
+require "vagrant/util/platform"
+
+require File.expand_path("../base", __FILE__)
+
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Driver
+ # Driver for VirtualBox 5.0.x
+ class Version_5_0 < Base
+ def initialize(uuid)
+ super()
+
+ @logger = Log4r::Logger.new("vagrant::provider::virtualbox_5_0")
+ @uuid = uuid
+ end
+
+ def clear_forwarded_ports
+ args = []
+ read_forwarded_ports(@uuid).each do |nic, name, _, _|
+ args.concat(["--natpf#{nic}", "delete", name])
+ end
+
+ execute("modifyvm", @uuid, *args) if !args.empty?
+ end
+
+ def clear_shared_folders
+ info = execute("showvminfo", @uuid, "--machinereadable", retryable: true)
+ info.split("\n").each do |line|
+ if line =~ /^SharedFolderNameMachineMapping\d+="(.+?)"$/
+ execute("sharedfolder", "remove", @uuid, "--name", $1.to_s)
+ end
+ end
+ end
+
+ def create_dhcp_server(network, options)
+ execute("dhcpserver", "add", "--ifname", network,
+ "--ip", options[:dhcp_ip],
+ "--netmask", options[:netmask],
+ "--lowerip", options[:dhcp_lower],
+ "--upperip", options[:dhcp_upper],
+ "--enable")
+ end
+
+ def create_host_only_network(options)
+ # Create the interface
+ execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
+ name = $1.to_s
+
+ # Configure it
+ execute("hostonlyif", "ipconfig", name,
+ "--ip", options[:adapter_ip],
+ "--netmask", options[:netmask])
+
+ # Return the details
+ return {
+ name: name,
+ ip: options[:adapter_ip],
+ netmask: options[:netmask],
+ dhcp: nil
+ }
+ end
+
+ def delete
+ execute("unregistervm", @uuid, "--delete")
+ end
+
+ def delete_unused_host_only_networks
+ networks = []
+ execute("list", "hostonlyifs", retryable: true).split("\n").each do |line|
+ networks << $1.to_s if line =~ /^Name:\s+(.+?)$/
+ end
+
+ execute("list", "vms", retryable: true).split("\n").each do |line|
+ if line =~ /^".+?"\s+\{(.+?)\}$/
+ info = execute("showvminfo", $1.to_s, "--machinereadable", retryable: true)
+ info.split("\n").each do |inner_line|
+ if inner_line =~ /^hostonlyadapter\d+="(.+?)"$/
+ networks.delete($1.to_s)
+ end
+ end
+ end
+ end
+
+ networks.each do |name|
+ # First try to remove any DHCP servers attached. We use `raw` because
+ # it is okay if this fails. It usually means that a DHCP server was
+ # never attached.
+ raw("dhcpserver", "remove", "--ifname", name)
+
+ # Delete the actual host only network interface.
+ execute("hostonlyif", "remove", name)
+ end
+ end
+
+ def discard_saved_state
+ execute("discardstate", @uuid)
+ end
+
+ def enable_adapters(adapters)
+ args = []
+ adapters.each do |adapter|
+ args.concat(["--nic#{adapter[:adapter]}", adapter[:type].to_s])
+
+ if adapter[:bridge]
+ args.concat(["--bridgeadapter#{adapter[:adapter]}",
+ adapter[:bridge], "--cableconnected#{adapter[:adapter]}", "on"])
+ end
+
+ if adapter[:hostonly]
+ args.concat(["--hostonlyadapter#{adapter[:adapter]}",
+ adapter[:hostonly], "--cableconnected#{adapter[:adapter]}", "on"])
+ end
+
+ if adapter[:intnet]
+ args.concat(["--intnet#{adapter[:adapter]}",
+ adapter[:intnet], "--cableconnected#{adapter[:adapter]}", "on"])
+ end
+
+ if adapter[:mac_address]
+ args.concat(["--macaddress#{adapter[:adapter]}",
+ adapter[:mac_address]])
+ end
+
+ if adapter[:nic_type]
+ args.concat(["--nictype#{adapter[:adapter]}", adapter[:nic_type].to_s])
+ end
+ end
+
+ execute("modifyvm", @uuid, *args)
+ end
+
+ def execute_command(command)
+ execute(*command)
+ end
+
+ def export(path)
+ execute("export", @uuid, "--output", path.to_s)
+ end
+
+ def forward_ports(ports)
+ args = []
+ ports.each do |options|
+ pf_builder = [options[:name],
+ options[:protocol] || "tcp",
+ options[:hostip] || "",
+ options[:hostport],
+ options[:guestip] || "",
+ options[:guestport]]
+
+ args.concat(["--natpf#{options[:adapter] || 1}",
+ pf_builder.join(",")])
+ end
+
+ execute("modifyvm", @uuid, *args) if !args.empty?
+ end
+
+ def halt
+ execute("controlvm", @uuid, "poweroff")
+ end
+
+ def import(ovf)
+ ovf = Vagrant::Util::Platform.cygwin_windows_path(ovf)
+
+ output = ""
+ total = ""
+ last = 0
+
+ # Dry-run the import to get the suggested name and path
+ @logger.debug("Doing dry-run import to determine parallel-safe name...")
+ output = execute("import", "-n", ovf)
+ result = /Suggested VM name "(.+?)"/.match(output)
+ if !result
+ raise Vagrant::Errors::VirtualBoxNoName, output: output
+ end
+ suggested_name = result[1].to_s
+
+ # Append millisecond plus a random to the path in case we're
+ # importing the same box elsewhere.
+ specified_name = "#{suggested_name}_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
+ @logger.debug("-- Parallel safe name: #{specified_name}")
+
+ # Build the specified name param list
+ name_params = [
+ "--vsys", "0",
+ "--vmname", specified_name,
+ ]
+
+ # Extract the disks list and build the disk target params
+ disk_params = []
+ disks = output.scan(/(\d+): Hard disk image: source image=.+, target path=(.+),/)
+ disks.each do |unit_num, path|
+ disk_params << "--vsys"
+ disk_params << "0"
+ disk_params << "--unit"
+ disk_params << unit_num
+ disk_params << "--disk"
+ if Vagrant::Util::Platform.windows?
+ # we use the block form of sub here to ensure that if the specified_name happens to end with a number (which is fairly likely) then
+ # we won't end up having the character sequence of a \ followed by a number be interpreted as a back reference. For example, if
+ # specified_name were "abc123", then "\\abc123\\".reverse would be "\\321cba\\", and the \3 would be treated as a back reference by the sub
+ disk_params << path.reverse.sub("\\#{suggested_name}\\".reverse) { "\\#{specified_name}\\".reverse }.reverse # Replace only last occurrence
+ else
+ disk_params << path.reverse.sub("/#{suggested_name}/".reverse, "/#{specified_name}/".reverse).reverse # Replace only last occurrence
+ end
+ end
+
+ execute("import", ovf , *name_params, *disk_params) do |type, data|
+ if type == :stdout
+ # Keep track of the stdout so that we can get the VM name
+ output << data
+ elsif type == :stderr
+ # Append the data so we can see the full view
+ total << data.gsub("\r", "")
+
+ # Break up the lines. We can't get the progress until we see an "OK"
+ lines = total.split("\n")
+ if lines.include?("OK.")
+ # The progress of the import will be in the last line. Do a greedy
+ # regular expression to find what we're looking for.
+ match = /.+(\d{2})%/.match(lines.last)
+ if match
+ current = match[1].to_i
+ if current > last
+ last = current
+ yield current if block_given?
+ end
+ end
+ end
+ end
+ end
+
+ output = execute("list", "vms", retryable: true)
+ match = /^"#{Regexp.escape(specified_name)}" \{(.+?)\}$/.match(output)
+ return match[1].to_s if match
+ nil
+ end
+
+ def max_network_adapters
+ 36
+ end
+
+ def read_forwarded_ports(uuid=nil, active_only=false)
+ uuid ||= @uuid
+
+ @logger.debug("read_forward_ports: uuid=#{uuid} active_only=#{active_only}")
+
+ results = []
+ current_nic = nil
+ info = execute("showvminfo", uuid, "--machinereadable", retryable: true)
+ info.split("\n").each do |line|
+ # This is how we find the nic that a FP is attached to,
+ # since this comes first.
+ current_nic = $1.to_i if line =~ /^nic(\d+)=".+?"$/
+
+ # If we care about active VMs only, then we check the state
+ # to verify the VM is running.
+ if active_only && line =~ /^VMState="(.+?)"$/ && $1.to_s != "running"
+ return []
+ end
+
+ # Parse out the forwarded port information
+ if line =~ /^Forwarding.+?="(.+?),.+?,.*?,(.+?),.*?,(.+?)"$/
+ result = [current_nic, $1.to_s, $2.to_i, $3.to_i]
+ @logger.debug(" - #{result.inspect}")
+ results << result
+ end
+ end
+
+ results
+ end
+
+ def read_bridged_interfaces
+ execute("list", "bridgedifs").split("\n\n").collect do |block|
+ info = {}
+
+ block.split("\n").each do |line|
+ if line =~ /^Name:\s+(.+?)$/
+ info[:name] = $1.to_s
+ elsif line =~ /^IPAddress:\s+(.+?)$/
+ info[:ip] = $1.to_s
+ elsif line =~ /^NetworkMask:\s+(.+?)$/
+ info[:netmask] = $1.to_s
+ elsif line =~ /^Status:\s+(.+?)$/
+ info[:status] = $1.to_s
+ end
+ end
+
+ # Return the info to build up the results
+ info
+ end
+ end
+
+ def read_dhcp_servers
+ execute("list", "dhcpservers", retryable: true).split("\n\n").collect do |block|
+ info = {}
+
+ block.split("\n").each do |line|
+ if network = line[/^NetworkName:\s+HostInterfaceNetworking-(.+?)$/, 1]
+ info[:network] = network
+ info[:network_name] = "HostInterfaceNetworking-#{network}"
+ elsif ip = line[/^IP:\s+(.+?)$/, 1]
+ info[:ip] = ip
+ elsif netmask = line[/^NetworkMask:\s+(.+?)$/, 1]
+ info[:netmask] = netmask
+ elsif lower = line[/^lowerIPAddress:\s+(.+?)$/, 1]
+ info[:lower] = lower
+ elsif upper = line[/^upperIPAddress:\s+(.+?)$/, 1]
+ info[:upper] = upper
+ end
+ end
+
+ info
+ end
+ end
+
+ def read_guest_additions_version
+ output = execute("guestproperty", "get", @uuid, "/VirtualBox/GuestAdd/Version",
+ retryable: true)
+ if output =~ /^Value: (.+?)$/
+ # Split the version by _ since some distro versions modify it
+ # to look like this: 4.1.2_ubuntu, and the distro part isn't
+ # too important.
+ value = $1.to_s
+ return value.split("_").first
+ end
+
+ # If we can't get the guest additions version by guest property, try
+ # to get it from the VM info itself.
+ info = execute("showvminfo", @uuid, "--machinereadable", retryable: true)
+ info.split("\n").each do |line|
+ return $1.to_s if line =~ /^GuestAdditionsVersion="(.+?)"$/
+ end
+
+ return nil
+ end
+
+ def read_guest_ip(adapter_number)
+ ip = read_guest_property("/VirtualBox/GuestInfo/Net/#{adapter_number}/V4/IP")
+ if !valid_ip_address?(ip)
+ raise Vagrant::Errors::VirtualBoxGuestPropertyNotFound,
+ guest_property: "/VirtualBox/GuestInfo/Net/#{adapter_number}/V4/IP"
+ end
+
+ return ip
+ end
+
+ def read_guest_property(property)
+ output = execute("guestproperty", "get", @uuid, property)
+ if output =~ /^Value: (.+?)$/
+ $1.to_s
+ else
+ raise Vagrant::Errors::VirtualBoxGuestPropertyNotFound, guest_property: property
+ end
+ end
+
+ def read_host_only_interfaces
+ execute("list", "hostonlyifs", retryable: true).split("\n\n").collect do |block|
+ info = {}
+
+ block.split("\n").each do |line|
+ if line =~ /^Name:\s+(.+?)$/
+ info[:name] = $1.to_s
+ elsif line =~ /^IPAddress:\s+(.+?)$/
+ info[:ip] = $1.to_s
+ elsif line =~ /^NetworkMask:\s+(.+?)$/
+ info[:netmask] = $1.to_s
+ elsif line =~ /^Status:\s+(.+?)$/
+ info[:status] = $1.to_s
+ end
+ end
+
+ info
+ end
+ end
+
+ def read_mac_address
+ info = execute("showvminfo", @uuid, "--machinereadable", retryable: true)
+ info.split("\n").each do |line|
+ return $1.to_s if line =~ /^macaddress1="(.+?)"$/
+ end
+
+ nil
+ end
+
+ def read_mac_addresses
+ macs = {}
+ info = execute("showvminfo", @uuid, "--machinereadable", retryable: true)
+ info.split("\n").each do |line|
+ if matcher = /^macaddress(\d+)="(.+?)"$/.match(line)
+ adapter = matcher[1].to_i
+ mac = matcher[2].to_s
+ macs[adapter] = mac
+ end
+ end
+ macs
+ end
+
+ def read_machine_folder
+ execute("list", "systemproperties", retryable: true).split("\n").each do |line|
+ if line =~ /^Default machine folder:\s+(.+?)$/i
+ return $1.to_s
+ end
+ end
+
+ nil
+ end
+
+ def read_network_interfaces
+ nics = {}
+ info = execute("showvminfo", @uuid, "--machinereadable", retryable: true)
+ info.split("\n").each do |line|
+ if line =~ /^nic(\d+)="(.+?)"$/
+ adapter = $1.to_i
+ type = $2.to_sym
+
+ nics[adapter] ||= {}
+ nics[adapter][:type] = type
+ elsif line =~ /^hostonlyadapter(\d+)="(.+?)"$/
+ adapter = $1.to_i
+ network = $2.to_s
+
+ nics[adapter] ||= {}
+ nics[adapter][:hostonly] = network
+ elsif line =~ /^bridgeadapter(\d+)="(.+?)"$/
+ adapter = $1.to_i
+ network = $2.to_s
+
+ nics[adapter] ||= {}
+ nics[adapter][:bridge] = network
+ end
+ end
+
+ nics
+ end
+
+ def read_state
+ output = execute("showvminfo", @uuid, "--machinereadable", retryable: true)
+ if output =~ /^name=""$/
+ return :inaccessible
+ elsif output =~ /^VMState="(.+?)"$/
+ return $1.to_sym
+ end
+
+ nil
+ end
+
+ def read_used_ports
+ ports = []
+ execute("list", "vms", retryable: true).split("\n").each do |line|
+ if line =~ /^".+?" \{(.+?)\}$/
+ uuid = $1.to_s
+
+ # Ignore our own used ports
+ next if uuid == @uuid
+
+ read_forwarded_ports(uuid, true).each do |_, _, hostport, _|
+ ports << hostport
+ end
+ end
+ end
+
+ ports
+ end
+
+ def read_vms
+ results = {}
+ execute("list", "vms", retryable: true).split("\n").each do |line|
+ if line =~ /^"(.+?)" \{(.+?)\}$/
+ results[$1.to_s] = $2.to_s
+ end
+ end
+
+ results
+ end
+
+ def remove_dhcp_server(network_name)
+ execute("dhcpserver", "remove", "--netname", network_name)
+ end
+
+ def set_mac_address(mac)
+ execute("modifyvm", @uuid, "--macaddress1", mac)
+ end
+
+ def set_name(name)
+ execute("modifyvm", @uuid, "--name", name, retryable: true)
+ rescue Vagrant::Errors::VBoxManageError => e
+ raise if !e.extra_data[:stderr].include?("VERR_ALREADY_EXISTS")
+
+ # We got VERR_ALREADY_EXISTS. This means that we're renaming to
+ # a VM name that already exists. Raise a custom error.
+ raise Vagrant::Errors::VirtualBoxNameExists,
+ stderr: e.extra_data[:stderr]
+ end
+
+ def share_folders(folders)
+ folders.each do |folder|
+ hostpath = folder[:hostpath]
+ if Vagrant::Util::Platform.windows?
+ hostpath = Vagrant::Util::Platform.windows_unc_path(hostpath)
+ end
+ args = ["--name",
+ folder[:name],
+ "--hostpath",
+ hostpath]
+ args << "--transient" if folder.key?(:transient) && folder[:transient]
+
+ # Enable symlinks on the shared folder
+ execute("setextradata", @uuid, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/#{folder[:name]}", "1")
+
+ # Add the shared folder
+ execute("sharedfolder", "add", @uuid, *args)
+ end
+ end
+
+ def ssh_port(expected_port)
+ @logger.debug("Searching for SSH port: #{expected_port.inspect}")
+
+ # Look for the forwarded port only by comparing the guest port
+ read_forwarded_ports.each do |_, _, hostport, guestport|
+ return hostport if guestport == expected_port
+ end
+
+ nil
+ end
+
+ def resume
+ @logger.debug("Resuming paused VM...")
+ execute("controlvm", @uuid, "resume")
+ end
+
+ def start(mode)
+ command = ["startvm", @uuid, "--type", mode.to_s]
+ r = raw(*command)
+
+ if r.exit_code == 0 || r.stdout =~ /VM ".+?" has been successfully started/
+ # Some systems return an exit code 1 for some reason. For that
+ # we depend on the output.
+ return true
+ end
+
+ # If we reached this point then it didn't work out.
+ raise Vagrant::Errors::VBoxManageError,
+ command: command.inspect,
+ stderr: r.stderr
+ end
+
+ def suspend
+ execute("controlvm", @uuid, "savestate")
+ end
+
+ def unshare_folders(names)
+ names.each do |name|
+ begin
+ execute(
+ "sharedfolder", "remove", @uuid,
+ "--name", name,
+ "--transient")
+
+ execute(
+ "setextradata", @uuid,
+ "VBoxInternal2/SharedFoldersEnableSymlinksCreate/#{name}")
+ rescue Vagrant::Errors::VBoxManageError => e
+ if e.extra_data[:stderr].include?("VBOX_E_FILE_ERROR")
+ # The folder doesn't exist. ignore.
+ else
+ raise
+ end
+ end
+ end
+ end
+
+ def verify!
+ # This command sometimes fails if kernel drivers aren't properly loaded
+ # so we just run the command and verify that it succeeded.
+ execute("list", "hostonlyifs", retryable: true)
+ end
+
+ def verify_image(path)
+ r = raw("import", path.to_s, "--dry-run")
+ return r.exit_code == 0
+ end
+
+ def vm_exists?(uuid)
+ 5.times do |i|
+ result = raw("showvminfo", uuid)
+ return true if result.exit_code == 0
+
+ # GH-2479: Sometimes this happens. In this case, retry. If
+ # we don't see this text, the VM really probably doesn't exist.
+ return false if !result.stderr.include?("CO_E_SERVER_EXEC_FAILURE")
+
+ # Sleep a bit though to give VirtualBox time to fix itself
+ sleep 2
+ end
+
+ # If we reach this point, it means that we consistently got the
+ # failure, do a standard vboxmanage now. This will raise an
+ # exception if it fails again.
+ execute("showvminfo", uuid)
+ return true
+ end
+
+ protected
+
+ def valid_ip_address?(ip)
+ # Filter out invalid IP addresses
+ # GH-4658 VirtualBox can report an IP address of 0.0.0.0 for FreeBSD guests.
+ if ip == "0.0.0.0"
+ return false
+ else
+ return true
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/virtualbox/plugin.rb b/plugins/providers/virtualbox/plugin.rb
index 7fc0ea039..18e33d4bb 100644
--- a/plugins/providers/virtualbox/plugin.rb
+++ b/plugins/providers/virtualbox/plugin.rb
@@ -45,6 +45,7 @@ module VagrantPlugins
autoload :Version_4_1, File.expand_path("../driver/version_4_1", __FILE__)
autoload :Version_4_2, File.expand_path("../driver/version_4_2", __FILE__)
autoload :Version_4_3, File.expand_path("../driver/version_4_3", __FILE__)
+ autoload :Version_5_0, File.expand_path("../driver/version_5_0", __FILE__)
end
module Model
diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb
index 9e2cb155b..b328e13d8 100644
--- a/plugins/provisioners/ansible/provisioner.rb
+++ b/plugins/provisioners/ansible/provisioner.rb
@@ -68,9 +68,16 @@ module VagrantPlugins
# Some Ansible options must be passed as environment variables,
# as there is no equivalent command line arguments
- "ANSIBLE_FORCE_COLOR" => "true",
"ANSIBLE_HOST_KEY_CHECKING" => "#{config.host_key_checking}",
}
+
+ # When Ansible output is piped in Vagrant integration, its default colorization is
+ # automatically disabled and the only way to re-enable colors is to use ANSIBLE_FORCE_COLOR.
+ env["ANSIBLE_FORCE_COLOR"] = "true" if @machine.env.ui.is_a?(Vagrant::UI::Colored)
+ # Setting ANSIBLE_NOCOLOR is "unnecessary" at the moment, but this could change in the future
+ # (e.g. local provisioner [GH-2103], possible change in vagrant/ansible integration, etc.)
+ env["ANSIBLE_NOCOLOR"] = "true" unless @machine.env.ui.is_a?(Vagrant::UI::Colored)
+
# ANSIBLE_SSH_ARGS is required for Multiple SSH keys, SSH forwarding and custom SSH settings
env["ANSIBLE_SSH_ARGS"] = ansible_ssh_args unless ansible_ssh_args.empty?
diff --git a/plugins/provisioners/chef/cap/windows/chef_installed.rb b/plugins/provisioners/chef/cap/windows/chef_installed.rb
new file mode 100644
index 000000000..c95ea8498
--- /dev/null
+++ b/plugins/provisioners/chef/cap/windows/chef_installed.rb
@@ -0,0 +1,20 @@
+module VagrantPlugins
+ module Chef
+ module Cap
+ module Windows
+ module ChefInstalled
+ # Check if Chef is installed at the given version.
+ # @return [true, false]
+ def self.chef_installed(machine, version)
+ if version != :latest
+ command = 'if ((&knife --version) -Match "Chef: "' + version + '"){ exit 0 } else { exit 1 }'
+ else
+ command = 'if ((&knife --version) -Match "Chef: *"){ exit 0 } else { exit 1 }'
+ end
+ machine.communicate.test(command, sudo: true)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/provisioners/chef/plugin.rb b/plugins/provisioners/chef/plugin.rb
index 5a1b2876f..540429fad 100644
--- a/plugins/provisioners/chef/plugin.rb
+++ b/plugins/provisioners/chef/plugin.rb
@@ -58,6 +58,11 @@ module VagrantPlugins
Cap::Linux::ChefInstalled
end
+ guest_capability(:windows, :chef_installed) do
+ require_relative "cap/windows/chef_installed"
+ Cap::Windows::ChefInstalled
+ end
+
guest_capability(:debian, :chef_install) do
require_relative "cap/debian/chef_install"
Cap::Debian::ChefInstall
diff --git a/plugins/provisioners/chef/provisioner/base.rb b/plugins/provisioners/chef/provisioner/base.rb
index a5efb5be4..aed44eaf0 100644
--- a/plugins/provisioners/chef/provisioner/base.rb
+++ b/plugins/provisioners/chef/provisioner/base.rb
@@ -37,8 +37,14 @@ module VagrantPlugins
def verify_binary(binary)
# Checks for the existence of chef binary and error if it
# doesn't exist.
+ if windows?
+ command = "if ((&'#{binary}' -v) -Match 'Chef: *'){ exit 0 } else { exit 1 }"
+ else
+ command = "sh -c 'command -v #{binary}'"
+ end
+
@machine.communicate.sudo(
- "sh -c 'command -v #{binary}'",
+ command,
error_class: ChefError,
error_key: :chef_not_detected,
binary: binary,
@@ -66,8 +72,12 @@ module VagrantPlugins
@machine.communicate.tap do |comm|
paths.each do |path|
- comm.sudo("mkdir -p #{path}")
- comm.sudo("chown -h #{@machine.ssh_info[:username]} #{path}")
+ if windows?
+ comm.sudo("mkdir ""#{path}"" -f")
+ else
+ comm.sudo("mkdir -p #{path}")
+ comm.sudo("chown -h #{@machine.ssh_info[:username]} #{path}")
+ end
end
end
end
@@ -133,7 +143,13 @@ module VagrantPlugins
remote_file = File.join(@config.provisioning_path, "dna.json")
@machine.communicate.tap do |comm|
- comm.sudo("rm -f #{remote_file}", error_check: false)
+ if windows?
+ command = "if (test-path '#{remote_file}') {rm '#{remote_file}' -force -recurse}"
+ else
+ command = "rm -f #{remote_file}"
+ end
+
+ comm.sudo(command, error_check: false)
comm.upload(temp.path, remote_file)
end
end
@@ -146,7 +162,13 @@ module VagrantPlugins
"vagrant.provisioners.chef.upload_encrypted_data_bag_secret_key")
@machine.communicate.tap do |comm|
- comm.sudo("rm -f #{remote_file}", error_check: false)
+ if windows?
+ command = "if (test-path ""#{remote_file}"") {rm ""#{remote_file}"" -force -recurse}"
+ else
+ command = "rm -f #{remote_file}"
+ end
+
+ comm.sudo(command, error_check: false)
comm.upload(encrypted_data_bag_secret_key_path, remote_file)
end
end
@@ -154,7 +176,13 @@ module VagrantPlugins
def delete_encrypted_data_bag_secret
remote_file = guest_encrypted_data_bag_secret_key_path
if remote_file
- @machine.communicate.sudo("rm -f #{remote_file}", error_check: false)
+ if windows?
+ command = "if (test-path ""#{remote_file}"") {rm ""#{remote_file}"" -force -recurse}"
+ else
+ command = "rm -f #{remote_file}"
+ end
+
+ @machine.communicate.sudo(command, error_check: false)
end
end
diff --git a/plugins/provisioners/chef/provisioner/chef_apply.rb b/plugins/provisioners/chef/provisioner/chef_apply.rb
index 1ff4790b6..602c81f3d 100644
--- a/plugins/provisioners/chef/provisioner/chef_apply.rb
+++ b/plugins/provisioners/chef/provisioner/chef_apply.rb
@@ -18,8 +18,12 @@ module VagrantPlugins
user = @machine.ssh_info[:username]
# Reset upload path permissions for the current ssh user
- @machine.communicate.sudo("mkdir -p #{config.upload_path}")
- @machine.communicate.sudo("chown -R #{user} #{config.upload_path}")
+ if windows?
+ @machine.communicate.sudo("mkdir ""#{config.upload_path}"" -f")
+ else
+ @machine.communicate.sudo("mkdir -p #{config.upload_path}")
+ @machine.communicate.sudo("chown -R #{user} #{config.upload_path}")
+ end
# Upload the recipe
upload_recipe
diff --git a/plugins/provisioners/chef/provisioner/chef_client.rb b/plugins/provisioners/chef/provisioner/chef_client.rb
index c9b0ab6c0..f0209d2a0 100644
--- a/plugins/provisioners/chef/provisioner/chef_client.rb
+++ b/plugins/provisioners/chef/provisioner/chef_client.rb
@@ -39,7 +39,11 @@ module VagrantPlugins
@machine.ui.info I18n.t("vagrant.provisioners.chef.client_key_folder")
path = Pathname.new(@config.client_key_path)
- @machine.communicate.sudo("mkdir -p #{path.dirname}")
+ if windows?
+ @machine.communicate.sudo("mkdir ""#{path.dirname}"" -f")
+ else
+ @machine.communicate.sudo("mkdir -p #{path.dirname}")
+ end
end
def upload_validation_key
diff --git a/plugins/provisioners/docker/cap/debian/docker_configure_auto_start.rb b/plugins/provisioners/docker/cap/debian/docker_configure_auto_start.rb
index 1c29d7d6c..32a8defd2 100644
--- a/plugins/provisioners/docker/cap/debian/docker_configure_auto_start.rb
+++ b/plugins/provisioners/docker/cap/debian/docker_configure_auto_start.rb
@@ -7,8 +7,7 @@ module VagrantPlugins
machine.communicate.tap do |comm|
if !comm.test('grep -q \'\-r=true\' /etc/default/docker')
comm.sudo("echo 'DOCKER_OPTS=\"-r=true ${DOCKER_OPTS}\"' >> /etc/default/docker")
- comm.sudo("stop docker")
- comm.sudo("start docker")
+ comm.sudo("service docker restart")
# Wait some amount time for the pid to become available
# so that we don't start executing Docker commands until
diff --git a/plugins/provisioners/docker/cap/debian/docker_install.rb b/plugins/provisioners/docker/cap/debian/docker_install.rb
index 4e4a2ae6e..2ab526b51 100644
--- a/plugins/provisioners/docker/cap/debian/docker_install.rb
+++ b/plugins/provisioners/docker/cap/debian/docker_install.rb
@@ -15,7 +15,7 @@ module VagrantPlugins
comm.sudo("apt-get update -y")
comm.sudo("apt-get install -y --force-yes -q curl")
comm.sudo("curl -sSL https://get.docker.com/gpg | apt-key add -")
- comm.sudo("echo deb http://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list")
+ comm.sudo("echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list")
comm.sudo("apt-get update")
comm.sudo("echo lxc lxc/directory string /var/lib/lxc | debconf-set-selections")
comm.sudo("apt-get install -y --force-yes -q xz-utils #{package} -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'")
diff --git a/plugins/provisioners/puppet/config/puppet.rb b/plugins/provisioners/puppet/config/puppet.rb
index 1810b989b..9910c6e05 100644
--- a/plugins/provisioners/puppet/config/puppet.rb
+++ b/plugins/provisioners/puppet/config/puppet.rb
@@ -2,28 +2,39 @@ module VagrantPlugins
module Puppet
module Config
class Puppet < Vagrant.plugin("2", :config)
+
+ # The path to Puppet's bin/ directory.
+ # @return [String]
+ attr_accessor :binary_path
+
attr_accessor :facter
attr_accessor :hiera_config_path
attr_accessor :manifest_file
attr_accessor :manifests_path
+ attr_accessor :environment
+ attr_accessor :environment_path
attr_accessor :module_path
attr_accessor :options
attr_accessor :synced_folder_type
+ attr_accessor :synced_folder_args
attr_accessor :temp_dir
attr_accessor :working_directory
def initialize
super
- @hiera_config_path = UNSET_VALUE
- @manifest_file = UNSET_VALUE
- @manifests_path = UNSET_VALUE
- @module_path = UNSET_VALUE
- @options = []
- @facter = {}
+ @binary_path = UNSET_VALUE
+ @hiera_config_path = UNSET_VALUE
+ @manifest_file = UNSET_VALUE
+ @manifests_path = UNSET_VALUE
+ @environment = UNSET_VALUE
+ @environment_path = UNSET_VALUE
+ @module_path = UNSET_VALUE
+ @options = []
+ @facter = {}
@synced_folder_type = UNSET_VALUE
- @temp_dir = UNSET_VALUE
- @working_directory = UNSET_VALUE
+ @temp_dir = UNSET_VALUE
+ @working_directory = UNSET_VALUE
end
def nfs=(value)
@@ -41,28 +52,49 @@ module VagrantPlugins
def merge(other)
super.tap do |result|
result.facter = @facter.merge(other.facter)
+ result.environment_path = @facter.merge(other.environment_path)
+ result.environment = @facter.merge(other.environment)
end
end
def finalize!
super
- if @manifests_path == UNSET_VALUE
+ if @environment_path == UNSET_VALUE && @manifests_path == UNSET_VALUE
+ #If both are unset, assume 'manifests' mode for now. TBD: Switch to environments by default?
@manifests_path = [:host, "manifests"]
end
- if @manifests_path && !@manifests_path.is_a?(Array)
+ # If the paths are just strings, assume they are 'host' paths (rather than guest)
+ if @environment_path != UNSET_VALUE && !@environment_path.is_a?(Array)
+ @environment_path = [:host, @environment_path]
+ end
+ if @manifests_path != UNSET_VALUE && !@manifests_path.is_a?(Array)
@manifests_path = [:host, @manifests_path]
end
-
- @manifests_path[0] = @manifests_path[0].to_sym
-
@hiera_config_path = nil if @hiera_config_path == UNSET_VALUE
- @manifest_file = "default.pp" if @manifest_file == UNSET_VALUE
- @module_path = nil if @module_path == UNSET_VALUE
- @synced_folder_type = nil if @synced_folder_type == UNSET_VALUE
- @temp_dir = "/tmp/vagrant-puppet" if @temp_dir == UNSET_VALUE
- @working_directory = nil if @working_directory == UNSET_VALUE
+
+ if @environment_path == UNSET_VALUE
+ @manifests_path[0] = @manifests_path[0].to_sym
+ @environment_path = nil
+ @manifest_file = "default.pp" if @manifest_file == UNSET_VALUE
+ else
+ @environment_path[0] = @environment_path[0].to_sym
+ @environment = "production" if @environment == UNSET_VALUE
+ if @manifests_path == UNSET_VALUE
+ @manifests_path = nil
+ end
+ if @manifest_file == UNSET_VALUE
+ @manifest_file = nil
+ end
+ end
+
+ @binary_path = nil if @binary_path == UNSET_VALUE
+ @module_path = nil if @module_path == UNSET_VALUE
+ @synced_folder_type = nil if @synced_folder_type == UNSET_VALUE
+ @synced_folder_args = nil if @synced_folder_args == UNSET_VALUE
+ @temp_dir = "/tmp/vagrant-puppet" if @temp_dir == UNSET_VALUE
+ @working_directory = nil if @working_directory == UNSET_VALUE
end
# Returns the module paths as an array of paths expanded relative to the
@@ -86,7 +118,7 @@ module VagrantPlugins
this_expanded_module_paths = expanded_module_paths(machine.env.root_path)
# Manifests path/file validation
- if manifests_path[0].to_sym == :host
+ if manifests_path != nil && manifests_path[0].to_sym == :host
expanded_path = Pathname.new(manifests_path[1]).
expand_path(machine.env.root_path)
if !expanded_path.directory?
@@ -99,6 +131,25 @@ module VagrantPlugins
manifest: expanded_manifest_file.to_s)
end
end
+ elsif environment_path != nil && environment_path[0].to_sym == :host
+ # Environments path/file validation
+ expanded_path = Pathname.new(environment_path[1]).
+ expand_path(machine.env.root_path)
+ if !expanded_path.directory?
+ errors << I18n.t("vagrant.provisioners.puppet.environment_path_missing",
+ path: expanded_path.to_s)
+ else
+ expanded_environment_file = expanded_path.join(environment)
+ if !expanded_environment_file.file? && !expanded_environment_file.directory?
+ errors << I18n.t("vagrant.provisioners.puppet.environment_missing",
+ environment: environment.to_s,
+ environment_path: expanded_path.to_s)
+ end
+ end
+ end
+
+ if environment_path == nil && manifests_path == nil
+ errors << "Please specify either a Puppet environment_path + environment (preferred) or manifests_path (deprecated)."
end
# Module paths validation
@@ -108,7 +159,6 @@ module VagrantPlugins
path: path)
end
end
-
{ "puppet provisioner" => errors }
end
end
diff --git a/plugins/provisioners/puppet/plugin.rb b/plugins/provisioners/puppet/plugin.rb
index 362a1c421..4d2b74bbe 100644
--- a/plugins/provisioners/puppet/plugin.rb
+++ b/plugins/provisioners/puppet/plugin.rb
@@ -10,22 +10,22 @@ module VagrantPlugins
DESC
config(:puppet, :provisioner) do
- require File.expand_path("../config/puppet", __FILE__)
+ require_relative "config/puppet"
Config::Puppet
end
config(:puppet_server, :provisioner) do
- require File.expand_path("../config/puppet_server", __FILE__)
+ require_relative "config/puppet_server"
Config::PuppetServer
end
provisioner(:puppet) do
- require File.expand_path("../provisioner/puppet", __FILE__)
+ require_relative "provisioner/puppet"
Provisioner::Puppet
end
provisioner(:puppet_server) do
- require File.expand_path("../provisioner/puppet_server", __FILE__)
+ require_relative "provisioner/puppet_server"
Provisioner::PuppetServer
end
end
diff --git a/plugins/provisioners/puppet/provisioner/puppet.rb b/plugins/provisioners/puppet/provisioner/puppet.rb
index c1e01c966..36b5261f9 100644
--- a/plugins/provisioners/puppet/provisioner/puppet.rb
+++ b/plugins/provisioners/puppet/provisioner/puppet.rb
@@ -20,7 +20,6 @@ module VagrantPlugins
# Calculate the paths we're going to use based on the environment
root_path = @machine.env.root_path
@expanded_module_paths = @config.expanded_module_paths(root_path)
- @manifest_file = File.join(manifests_guest_path, @config.manifest_file)
# Setup the module paths
@module_paths = []
@@ -32,12 +31,24 @@ module VagrantPlugins
folder_opts = {}
folder_opts[:type] = @config.synced_folder_type if @config.synced_folder_type
folder_opts[:owner] = "root" if !@config.synced_folder_type
+ folder_opts[:args] = @config.synced_folder_args if @config.synced_folder_args
- # Share the manifests directory with the guest
- if @config.manifests_path[0].to_sym == :host
- root_config.vm.synced_folder(
- File.expand_path(@config.manifests_path[1], root_path),
- manifests_guest_path, folder_opts)
+ if @config.environment_path.is_a?(Array)
+ # Share the environments directory with the guest
+ if @config.environment_path[0].to_sym == :host
+ root_config.vm.synced_folder(
+ File.expand_path(@config.environment_path[1], root_path),
+ environments_guest_path, folder_opts)
+ end
+ end
+ if @config.manifest_file
+ @manifest_file = File.join(manifests_guest_path, @config.manifest_file)
+ # Share the manifests directory with the guest
+ if @config.manifests_path[0].to_sym == :host
+ root_config.vm.synced_folder(
+ File.expand_path(@config.manifests_path[1], root_path),
+ manifests_guest_path, folder_opts)
+ end
end
# Share the module paths
@@ -46,6 +57,24 @@ module VagrantPlugins
end
end
+ def parse_environment_metadata
+ # Parse out the environment manifest path since puppet apply doesnt do that for us.
+ environment_conf = File.join(environments_guest_path, @config.environment, "environment.conf")
+ if @machine.communicate.test("test -e #{environment_conf}", sudo: true)
+ conf = @machine.communicate.sudo("cat #{environment_conf}") do | type, data|
+ if type == :stdout
+ data.each_line do |line|
+ if line =~ /^\s*manifest\s+=\s+([^\s]+)/
+ @manifest_file = $1
+ @manifest_file.gsub! '$basemodulepath:', "#{environments_guest_path}/#{@config.environment}/"
+ @logger.debug("Using manifest from environment.conf: #{@manifest_file}")
+ end
+ end
+ end
+ end
+ end
+ end
+
def provision
# If the machine has a wait for reboot functionality, then
# do that (primarily Windows)
@@ -53,11 +82,19 @@ module VagrantPlugins
@machine.guest.capability(:wait_for_reboot)
end
+ # In environment mode we still need to specify a manifest file, if its not, use the one from env config if specified.
+ if !@manifest_file
+ @manifest_file = "#{environments_guest_path}/#{@config.environment}/manifests/site.pp"
+ parse_environment_metadata
+ end
# Check that the shared folders are properly shared
check = []
- if @config.manifests_path[0] == :host
+ if @config.manifests_path.is_a?(Array) && @config.manifests_path[0] == :host
check << manifests_guest_path
end
+ if @config.environment_path.is_a?(Array) && @config.environment_path[0] == :host
+ check << environments_guest_path
+ end
@module_paths.each do |host_path, guest_path|
check << guest_path
end
@@ -71,7 +108,7 @@ module VagrantPlugins
verify_shared_folders(check)
# Verify Puppet is installed and run it
- verify_binary("puppet")
+ verify_binary(puppet_binary_path("puppet"))
# Upload Hiera configuration if we have it
@hiera_config_path = nil
@@ -96,12 +133,32 @@ module VagrantPlugins
end
end
+ def environments_guest_path
+ if config.environment_path[0] == :host
+ # The path is on the host, so point to where it is shared
+ File.join(config.temp_dir, "environments")
+ else
+ # The path is on the VM, so just point directly to it
+ config.environment_path[1]
+ end
+ end
+
+ # Returns the path to the Puppet binary, taking into account the
+ # `binary_path` configuration option.
+ def puppet_binary_path(binary)
+ return binary if !@config.binary_path
+ return File.join(@config.binary_path, binary)
+ end
+
def verify_binary(binary)
- @machine.communicate.sudo(
- "which #{binary}",
- error_class: PuppetError,
- error_key: :not_detected,
- binary: binary)
+ if !machine.communicate.test("sh -c 'command -v #{binary}'")
+ @config.binary_path = "/opt/puppetlabs/bin/"
+ @machine.communicate.sudo(
+ "test -x /opt/puppetlabs/bin/#{binary}",
+ error_class: PuppetError,
+ error_key: :not_detected,
+ binary: binary)
+ end
end
def run_puppet_apply
@@ -129,8 +186,14 @@ module VagrantPlugins
options << "--color=false"
end
- options << "--manifestdir #{manifests_guest_path}"
options << "--detailed-exitcodes"
+ if config.environment_path
+ options << "--environmentpath #{environments_guest_path}/"
+ options << "--environment #{@config.environment}"
+ else
+ options << "--manifestdir #{manifests_guest_path}"
+ end
+
options << @manifest_file
options = options.join(" ")
@@ -150,7 +213,7 @@ module VagrantPlugins
facter = "#{facts.join(" ")} "
end
- command = "#{facter}puppet apply #{options}"
+ command = "#{facter} #{config.binary_path}puppet apply #{options}"
if config.working_directory
if windows?
command = "cd #{config.working_directory}; if (`$?) \{ #{command} \}"
@@ -159,9 +222,15 @@ module VagrantPlugins
end
end
- @machine.ui.info(I18n.t(
- "vagrant.provisioners.puppet.running_puppet",
- manifest: config.manifest_file))
+ if config.environment_path
+ @machine.ui.info(I18n.t(
+ "vagrant.provisioners.puppet.running_puppet_env",
+ environment: config.environment))
+ else
+ @machine.ui.info(I18n.t(
+ "vagrant.provisioners.puppet.running_puppet",
+ manifest: config.manifest_file))
+ end
opts = {
elevated: true,
diff --git a/plugins/provisioners/salt/bootstrap-salt.ps1 b/plugins/provisioners/salt/bootstrap-salt.ps1
index c8d7e7ab2..d85923a12 100644
--- a/plugins/provisioners/salt/bootstrap-salt.ps1
+++ b/plugins/provisioners/salt/bootstrap-salt.ps1
@@ -1,11 +1,11 @@
# Salt version to install
-$version = '2014.1.10'
+$version = '2014.7.1'
# Create C:\tmp\ - if Vagrant doesn't upload keys and/or config it might not exist
-New-Item C:\tmp\ -ItemType directory | out-null
+New-Item C:\tmp\ -ItemType directory -force | out-null
# Copy minion keys & config to correct location
-New-Item C:\salt\conf\pki\minion\ -ItemType directory | out-null
+New-Item C:\salt\conf\pki\minion\ -ItemType directory -force | out-null
# Check if minion keys have been uploaded
if (Test-Path C:\tmp\minion.pem) {
@@ -13,14 +13,9 @@ if (Test-Path C:\tmp\minion.pem) {
cp C:\tmp\minion.pub C:\salt\conf\pki\minion\
}
-# Check if minion config has been uploaded
-if (Test-Path C:\tmp\minion) {
- cp C:\tmp\minion C:\salt\conf\
-}
-
# Detect architecture
if ([IntPtr]::Size -eq 4) {
- $arch = "win32"
+ $arch = "x86"
} else {
$arch = "AMD64"
}
@@ -34,7 +29,13 @@ $webclient.DownloadFile($url, $file)
# Install minion silently
Write-Host "Installing Salt minion..."
-C:\tmp\salt.exe /S
+#Wait for process to exit before continuing...
+C:\tmp\salt.exe /S | Out-Null
+
+# Check if minion config has been uploaded
+if (Test-Path C:\tmp\minion) {
+ cp C:\tmp\minion C:\salt\conf\
+}
# Wait for salt-minion service to be registered before trying to start it
$service = Get-Service salt-minion -ErrorAction SilentlyContinue
diff --git a/plugins/provisioners/salt/config.rb b/plugins/provisioners/salt/config.rb
index 4d97d942c..12f3d38dd 100644
--- a/plugins/provisioners/salt/config.rb
+++ b/plugins/provisioners/salt/config.rb
@@ -15,13 +15,17 @@ module VagrantPlugins
attr_accessor :grains_config
attr_accessor :run_highstate
attr_accessor :run_overstate
+ attr_accessor :orchestrations
attr_accessor :always_install
attr_accessor :bootstrap_script
attr_accessor :verbose
attr_accessor :seed_master
+ attr_accessor :config_dir
attr_reader :pillar_data
attr_accessor :colorize
attr_accessor :log_level
+ attr_accessor :masterless
+ attr_accessor :minion_id
## bootstrap options
attr_accessor :temp_config_dir
@@ -56,6 +60,9 @@ module VagrantPlugins
@install_syndic = UNSET_VALUE
@no_minion = UNSET_VALUE
@bootstrap_options = UNSET_VALUE
+ @config_dir = UNSET_VALUE
+ @masterless = UNSET_VALUE
+ @minion_id = UNSET_VALUE
end
def finalize!
@@ -82,7 +89,9 @@ module VagrantPlugins
@install_syndic = nil if @install_syndic == UNSET_VALUE
@no_minion = nil if @no_minion == UNSET_VALUE
@bootstrap_options = nil if @bootstrap_options == UNSET_VALUE
-
+ @config_dir = nil if @config_dir == UNSET_VALUE
+ @masterless = false if @masterless == UNSET_VALUE
+ @minion_id = nil if @minion_id == UNSET_VALUE
end
def pillar(data)
@@ -90,19 +99,30 @@ module VagrantPlugins
@pillar_data = Vagrant::Util::DeepMerge.deep_merge(@pillar_data, data)
end
+ def default_config_dir(machine)
+ guest_type = machine.config.vm.guest || :linux
+
+ # FIXME: there should be a way to do that a bit smarter
+ if guest_type == :windows
+ return "C:\\salt"
+ else
+ return "/etc/salt"
+ end
+ end
+
def validate(machine)
errors = _detected_errors
if @minion_config
expanded = Pathname.new(@minion_config).expand_path(machine.env.root_path)
if !expanded.file?
- errors << I18n.t("vagrant.provisioners.salt.minion_config_nonexist")
+ errors << I18n.t("vagrant.provisioners.salt.minion_config_nonexist", missing_config_file: expanded)
end
end
if @master_config
expanded = Pathname.new(@master_config).expand_path(machine.env.root_path)
if !expanded.file?
- errors << I18n.t("vagrant.provisioners.salt.master_config_nonexist")
+ errors << I18n.t("vagrant.provisioners.salt.master_config_nonexist", missing_config_file: expanded)
end
end
@@ -129,10 +149,12 @@ module VagrantPlugins
errors << I18n.t("vagrant.provisioners.salt.must_accept_keys")
end
+ if @config_dir.nil?
+ @config_dir = default_config_dir(machine)
+ end
+
return {"salt provisioner" => errors}
end
-
-
end
end
end
diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb
index 497acd6ba..6ec099f1e 100644
--- a/plugins/provisioners/salt/provisioner.rb
+++ b/plugins/provisioners/salt/provisioner.rb
@@ -9,6 +9,7 @@ module VagrantPlugins
run_bootstrap_script
call_overstate
call_highstate
+ call_orchestrate
end
# Return a list of accepted keys
@@ -308,8 +309,29 @@ module VagrantPlugins
end
end
+ def call_masterless
+ @machine.env.ui.info "Calling state.highstate in local mode... (this may take a while)"
+ cmd = "salt-call state.highstate --local"
+ if @config.minion_id
+ cmd += " --id #{@config.minion_id}"
+ end
+ cmd += " -l debug#{get_pillar}"
+ @machine.communicate.sudo(cmd) do |type, data|
+ if @config.verbose
+ @machine.env.ui.info(data)
+ end
+ end
+ end
+
def call_highstate
- if @config.run_highstate
+ if @config.minion_config
+ @machine.env.ui.info "Copying salt minion config to #{@config.config dir}"
+ @machine.communicate.upload(expanded_path(@config.minion_config).to_s, @config.config_dir + "/minion")
+ end
+
+ if @config.masterless
+ call_masterless
+ elsif @config.run_highstate
@machine.env.ui.info "Calling state.highstate... (this may take a while)"
if @config.install_master
@machine.communicate.sudo("salt '*' saltutil.sync_all")
@@ -340,6 +362,34 @@ module VagrantPlugins
@machine.env.ui.info "run_highstate set to false. Not running state.highstate."
end
end
+
+ def call_orchestrate
+ if !@config.orchestrations
+ @machine.env.ui.info "orchestrate is nil. Not running state.orchestrate."
+ return
+ end
+
+ if !@config.install_master
+ @machine.env.ui.info "orchestrate does not make sense on a minion. Not running state.orchestrate."
+ return
+ end
+
+ log_output = lambda do |type, data|
+ if @config.verbose
+ @machine.env.ui.info(data)
+ end
+ end
+
+ @machine.env.ui.info "Running the following orchestrations: #{@config.orchestrations}"
+ @machine.env.ui.info "Running saltutil.sync_all before orchestrating"
+ @machine.communicate.sudo("salt '*' saltutil.sync_all", &log_output)
+
+ @config.orchestrations.each do |orchestration|
+ cmd = "salt-run -l info state.orchestrate #{orchestration}"
+ @machine.env.ui.info "Calling #{cmd}... (this may take a while)"
+ @machine.communicate.sudo(cmd, &log_output)
+ end
+ end
end
end
end
diff --git a/plugins/provisioners/shell/config.rb b/plugins/provisioners/shell/config.rb
index e1d046f2d..2f4957214 100644
--- a/plugins/provisioners/shell/config.rb
+++ b/plugins/provisioners/shell/config.rb
@@ -10,6 +10,7 @@ module VagrantPlugins
attr_accessor :privileged
attr_accessor :binary
attr_accessor :keep_color
+ attr_accessor :name
attr_accessor :powershell_args
def initialize
@@ -20,6 +21,7 @@ module VagrantPlugins
@privileged = UNSET_VALUE
@binary = UNSET_VALUE
@keep_color = UNSET_VALUE
+ @name = UNSET_VALUE
@powershell_args = UNSET_VALUE
end
@@ -31,6 +33,7 @@ module VagrantPlugins
@privileged = true if @privileged == UNSET_VALUE
@binary = false if @binary == UNSET_VALUE
@keep_color = false if @keep_color == UNSET_VALUE
+ @name = nil if @name == UNSET_VALUE
@powershell_args = "-ExecutionPolicy Bypass" if @powershell_args == UNSET_VALUE
if @args && args_valid?
diff --git a/plugins/provisioners/shell/provisioner.rb b/plugins/provisioners/shell/provisioner.rb
index 867de7553..4ee302f5d 100644
--- a/plugins/provisioners/shell/provisioner.rb
+++ b/plugins/provisioners/shell/provisioner.rb
@@ -65,7 +65,10 @@ module VagrantPlugins
comm.upload(path.to_s, config.upload_path)
- if config.path
+ if config.name
+ @machine.ui.detail(I18n.t("vagrant.provisioners.shell.running",
+ script: "script: #{config.name}"))
+ elsif config.path
@machine.ui.detail(I18n.t("vagrant.provisioners.shell.running",
script: path.to_s))
else
@@ -122,7 +125,10 @@ module VagrantPlugins
command = "powershell #{shell_args.to_s} -file #{command}" if
File.extname(exec_path).downcase == '.ps1'
- if config.path
+ if config.name
+ @machine.ui.detail(I18n.t("vagrant.provisioners.shell.running",
+ script: "script: #{config.name}"))
+ elsif config.path
@machine.ui.detail(I18n.t("vagrant.provisioners.shell.runningas",
local: config.path.to_s, remote: exec_path))
else
diff --git a/plugins/pushes/ftp/adapter.rb b/plugins/pushes/ftp/adapter.rb
index 8a9414376..d0d076491 100644
--- a/plugins/pushes/ftp/adapter.rb
+++ b/plugins/pushes/ftp/adapter.rb
@@ -74,7 +74,7 @@ module VagrantPlugins
# Create the parent directories if they does not exist (naive mkdir -p)
fullpath.descend do |path|
- if @server.list(path.to_s).empty?
+ if !directory_exists?(path.to_s)
@server.mkdir(path.to_s)
end
end
@@ -83,6 +83,15 @@ module VagrantPlugins
@server.putbinaryfile(local, remote)
end
+ def directory_exists?(path)
+ begin
+ @server.chdir(path)
+ return true
+ rescue Net::FTPPermError
+ return false
+ end
+ end
+
private
def pwd
diff --git a/plugins/synced_folders/rsync/helper.rb b/plugins/synced_folders/rsync/helper.rb
index c5bf8cbda..9763d77eb 100644
--- a/plugins/synced_folders/rsync/helper.rb
+++ b/plugins/synced_folders/rsync/helper.rb
@@ -122,13 +122,24 @@ module VagrantPlugins
machine.ui.info(I18n.t(
"vagrant.rsync_folder_excludes", excludes: excludes.inspect))
end
+ if opts.include?(:verbose)
+ machine.ui.info(I18n.t("vagrant.rsync_showing_output"));
+ end
# If we have tasks to do before rsyncing, do those.
if machine.guest.capability?(:rsync_pre)
machine.guest.capability(:rsync_pre, opts)
end
- r = Vagrant::Util::Subprocess.execute(*(command + [command_opts]))
+ if opts.include?(:verbose)
+ command_opts[:notify] = [ :stdout, :stderr ];
+ r = Vagrant::Util::Subprocess.execute(*(command + [command_opts])) {
+ |io_name,data| data.each_line { |line| machine.ui.info("rsync[#{io_name}] -> #{line}") }
+ }
+ else
+ r = Vagrant::Util::Subprocess.execute(*(command + [command_opts]))
+ end
+
if r.exit_code != 0
raise Vagrant::Errors::RSyncError,
command: command.join(" "),
diff --git a/templates/guests/arch/network_static.erb b/templates/guests/arch/network_static.erb
index ee58ee75a..f8cb06f1b 100644
--- a/templates/guests/arch/network_static.erb
+++ b/templates/guests/arch/network_static.erb
@@ -3,3 +3,6 @@ Description='A basic static ethernet connection'
Interface=<%= options[:device] %>
IP=static
Address=('<%= options[:ip]%>/24')
+<% if options[:gateway] %>
+Gateway='<%= options[:gateway] %>'
+<% end %>
diff --git a/templates/guests/debian/network_static.erb b/templates/guests/debian/network_static.erb
index fa505afa9..91f0cd62e 100644
--- a/templates/guests/debian/network_static.erb
+++ b/templates/guests/debian/network_static.erb
@@ -4,4 +4,7 @@ auto eth<%= options[:interface] %>
iface eth<%= options[:interface] %> inet static
address <%= options[:ip] %>
netmask <%= options[:netmask] %>
+<% if options[:gateway] %>
+ gateway <%= options[:gateway] %>
+<% end %>
#VAGRANT-END
diff --git a/templates/guests/fedora/network_static.erb b/templates/guests/fedora/network_static.erb
index dc8e85c1e..000ea6150 100644
--- a/templates/guests/fedora/network_static.erb
+++ b/templates/guests/fedora/network_static.erb
@@ -6,7 +6,11 @@ ONBOOT=yes
IPADDR=<%= options[:ip] %>
NETMASK=<%= options[:netmask] %>
DEVICE=<%= options[:device] %>
-<%= options[:gateway] ? "GATEWAY=#{options[:gateway]}" : '' %>
-<%= options[:mac_address] ? "HWADDR=#{options[:mac_address]}" : '' %>
+<% if options[:gateway] %>
+GATEWAY=<%= options[:gateway] %>
+<% end %>
+<% if options[:mac_address] %>
+HWADDR=<%= options[:mac_address] %>
+<% end %>
PEERDNS=no
#VAGRANT-END
diff --git a/templates/guests/freebsd/network_static.erb b/templates/guests/freebsd/network_static.erb
index 0edc518cb..e73c7c124 100644
--- a/templates/guests/freebsd/network_static.erb
+++ b/templates/guests/freebsd/network_static.erb
@@ -1,3 +1,6 @@
#VAGRANT-BEGIN
ifconfig_<%= ifname %>="inet <%= options[:ip] %> netmask <%= options[:netmask] %>"
+<% if options[:gateway] %>
+default_router="<%= options[:gateway] %>"
+<% end %>
#VAGRANT-END
diff --git a/templates/guests/funtoo/network_static.erb b/templates/guests/funtoo/network_static.erb
index ab6a09d10..001df7419 100644
--- a/templates/guests/funtoo/network_static.erb
+++ b/templates/guests/funtoo/network_static.erb
@@ -2,5 +2,9 @@
# The contents below are automatically generated by Vagrant. Do not modify.
template='interface'
ipaddr='<%= options[:ip] %>/<%= options[:netmask] %>'
-<%= [:gateway, :nameservers, :domain, :route, :gateway6, :route6, :mtu].reduce([]) { |a,i| a.push("#{i}=#{options[i]}") if options[i]; a }.join("\n") %>
+<% [:gateway, :nameservers, :domain, :route, :gateway6, :route6, :mtu].each do |key| %>
+<% if options[key] %>
+<%= key %>='<%= options[key] %>'
+<% end %>
+<% end %>
#VAGRANT-END
diff --git a/templates/guests/gentoo/network_static.erb b/templates/guests/gentoo/network_static.erb
index 0df432cb0..fe6c77194 100644
--- a/templates/guests/gentoo/network_static.erb
+++ b/templates/guests/gentoo/network_static.erb
@@ -1,4 +1,7 @@
#VAGRANT-BEGIN
# The contents below are automatically generated by Vagrant. Do not modify.
config_eth<%= options[:interface] %>=("<%= options[:ip] %> netmask <%= options[:netmask] %>")
+<% if options[:gateway] %>
+gateways_eth<%= options[:interface] %>="<%= options[:gateway] %>"
+<% end %>
#VAGRANT-END
diff --git a/templates/guests/redhat/network_static.erb b/templates/guests/redhat/network_static.erb
index c28dd74cb..53ef59571 100644
--- a/templates/guests/redhat/network_static.erb
+++ b/templates/guests/redhat/network_static.erb
@@ -6,5 +6,8 @@ ONBOOT=yes
IPADDR=<%= options[:ip] %>
NETMASK=<%= options[:netmask] %>
DEVICE=eth<%= options[:interface] %>
+<% if options[:gateway] %>
+GATEWAY=<%= options[:gateway] %>
+<% end %>
PEERDNS=no
#VAGRANT-END
diff --git a/templates/guests/suse/network_static.erb b/templates/guests/suse/network_static.erb
index 7388fc355..c9270d7cd 100644
--- a/templates/guests/suse/network_static.erb
+++ b/templates/guests/suse/network_static.erb
@@ -4,7 +4,10 @@ BOOTPROTO='static'
IPADDR='<%= options[:ip] %>'
NETMASK='<%= options[:netmask] %>'
DEVICE='eth<%= options[:interface] %>'
-PEERDNS=no
+<% if options[:gateway] %>
+GATEWAY='<%= options[:gateway] %>'
+<% end %>
+PEERDNS='no'
STARTMODE='auto'
USERCONTROL='no'
#VAGRANT-END
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 155cd77dc..de90c426a 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -24,6 +24,8 @@ en:
Downloading: %{url}
box_download_error: |-
Error downloading: %{message}
+ box_unpacking: |-
+ Unpacking necessary files from: %{url}
box_expanding_url: |-
URL: %{url}
box_loading_metadata: |-
@@ -212,6 +214,7 @@ en:
The provider ('%{provider}') for the machine '%{name}' is
using a proxy machine. RSync will sync to this proxy
instead of directly to the environment itself.
+ rsync_showing_output: "Showing rsync output..."
rsync_ssh_password: |-
The machine you're rsyncing folders to is configured to use
password-based authentication. Vagrant can't script rsync to automatically
@@ -285,7 +288,7 @@ en:
id_in_pre_import: |-
The ':id' parameter is not available in "pre-import" customizations.
intnet_on_bad_type: |-
- VirtualBox internal networks can only be enabled on "private_networks"
+ VirtualBox internal networks can only be enabled on "private_network"
invalid_event: |-
%{event} is not a valid event for customization. Valid events
are: %{valid_events}
@@ -1197,7 +1200,8 @@ en:
a syntax error.
Path: %{path}
- Message: %{message}
+ Line number: %{line}
+ Message: %{exception_class}: %{message}
vagrantfile_syntax_error: |-
There is a syntax error in the following Vagrantfile. The syntax error
message is reproduced below for convenience:
@@ -1696,10 +1700,10 @@ en:
provision:
beginning: "Running provisioner: %{provisioner}..."
disabled_by_config: |-
- Machine not provisioning because `--no-provision` is specified.
+ Machine not provisioned because `--no-provision` is specified.
disabled_by_sentinel: |-
Machine already provisioned. Run `vagrant provision` or use the `--provision`
- to force provisioning. Provisioners marked to run always will still run.
+ flag to force provisioning. Provisioners marked to run always will still run.
resume:
resuming: Resuming suspended VM...
unpausing: |-
@@ -1749,7 +1753,7 @@ en:
packaging: "Packaging additional file: %{file}"
compressing: "Compressing package to: %{tar_path}"
output_exists: |-
- The specified file to save the package as already exists. Please
+ The specified file '%{file_name}' to save the package as already exists. Please
remove this file or specify a different file name for outputting.
output_is_directory: |-
The specified output is a directory. Please specify a path including
@@ -1852,11 +1856,17 @@ en:
installed on this guest. Puppet provisioning can not continue without
Puppet properly installed.
running_puppet: "Running Puppet with %{manifest}..."
+ running_puppet_env: "Running Puppet with environment %{environment}..."
manifest_missing: |-
The configured Puppet manifest is missing. Please specify a path to an
existing manifest:
%{manifest}
+ environment_missing: |-
+ The configured Puppet environment folder %{environment} was not found in the
+ specified environmentpath %{environmentpath}.
+ Please specify a path to an existing Puppet directory environment.
+ environment_path_missing: "The environment path specified for Puppet does not exist: %{path}"
manifests_path_missing: "The manifests path specified for Puppet does not exist: %{path}"
missing_shared_folders: |-
Shared folders that Puppet requires are missing on the virtual machine.
@@ -1908,9 +1918,9 @@ en:
salt:
minion_config_nonexist: |-
- The specified minion_config file could not be found.
+ The specified minion_config '%{missing_config_file}' file could not be found.
master_config_nonexist: |-
- The specified master_config file could not be found.
+ The specified master_config '%{missing_config_file}' file could not be found.
grains_config_nonexist: |-
The specified grains_config file could not be found.
missing_key: |-
diff --git a/test/unit/plugins/guests/linux/cap/mount_shared_folder_test.rb b/test/unit/plugins/guests/linux/cap/mount_shared_folder_test.rb
new file mode 100644
index 000000000..4d591e7fb
--- /dev/null
+++ b/test/unit/plugins/guests/linux/cap/mount_shared_folder_test.rb
@@ -0,0 +1,44 @@
+require File.expand_path("../../../../../base", __FILE__)
+
+describe "VagrantPlugins::GuestLinux::Cap::MountSharedFolder" do
+ let(:machine) { double("machine") }
+ let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
+ let(:guest) { double("guest") }
+
+ before do
+ allow(machine).to receive(:guest).and_return(guest)
+ allow(machine).to receive(:communicate).and_return(communicator)
+ allow(guest).to receive(:capability).and_return(nil)
+ end
+
+ describe "smb" do
+ let(:described_class) do
+ VagrantPlugins::GuestLinux::Plugin.components.guest_capabilities[:linux].get(:mount_smb_shared_folder)
+ end
+
+ describe ".mount_shared_folder" do
+ describe "with a domain" do
+ let(:mount_command) { "mount -t cifs -o uid=`id -u `,gid=`getent group | cut -d: -f3`,sec=ntlm,username=user,pass=pass,domain=domain //host/name " }
+ before do
+ communicator.expect_command mount_command
+ communicator.stub_command mount_command, exit_code: 0
+ end
+ after { communicator.verify_expectations! }
+ it "should call mount with correct args" do
+ described_class.mount_smb_shared_folder(machine, 'name', 'guestpath', {:smb_username => "user@domain", :smb_password => "pass", :smb_host => "host"})
+ end
+ end
+ describe "without a domain" do
+ let(:mount_command) { "mount -t cifs -o uid=`id -u `,gid=`getent group | cut -d: -f3`,sec=ntlm,username=user,pass=pass //host/name " }
+ before do
+ communicator.expect_command mount_command
+ communicator.stub_command mount_command, exit_code: 0
+ end
+ after { communicator.verify_expectations! }
+ it "should call mount with correct args" do
+ described_class.mount_smb_shared_folder(machine, 'name', 'guestpath', {:smb_username => "user", :smb_password => "pass", :smb_host => "host"})
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/test/unit/plugins/guests/photon/cap/change_host_name_test.rb b/test/unit/plugins/guests/photon/cap/change_host_name_test.rb
new file mode 100644
index 000000000..5e9e9e9e1
--- /dev/null
+++ b/test/unit/plugins/guests/photon/cap/change_host_name_test.rb
@@ -0,0 +1,34 @@
+# encoding: UTF-8
+# Copyright (c) 2015 VMware, Inc. All Rights Reserved.
+
+require File.expand_path("../../../../../base", __FILE__)
+
+describe "VagrantPlugins::GuestPhoton::Cap::ChangeHostName" do
+ let(:described_class) do
+ VagrantPlugins::GuestPhoton::Plugin.components.guest_capabilities[:photon].get(:change_host_name)
+ end
+ let(:machine) { double("machine") }
+ let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
+
+ before do
+ allow(machine).to receive(:communicate).and_return(communicator)
+ end
+
+ after do
+ communicator.verify_expectations!
+ end
+
+ it 'should change hostname when hostname is differ from current' do
+ hostname = 'vagrant-photon'
+ expect(communicator).to receive(:test).with("sudo hostname --fqdn | grep 'vagrant-photon'")
+ communicator.should_receive(:sudo).with("hostname #{hostname.split('.')[0]}")
+ described_class.change_host_name(machine, hostname)
+ end
+
+ it 'should not change hostname when hostname equals current' do
+ hostname = 'vagrant-photon'
+ communicator.stub(:test).and_return(true)
+ communicator.should_not_receive(:sudo)
+ described_class.change_host_name(machine, hostname)
+ end
+end
diff --git a/test/unit/plugins/guests/photon/cap/configure_networks_test.rb b/test/unit/plugins/guests/photon/cap/configure_networks_test.rb
new file mode 100644
index 000000000..dc6e9aaf1
--- /dev/null
+++ b/test/unit/plugins/guests/photon/cap/configure_networks_test.rb
@@ -0,0 +1,40 @@
+# encoding: UTF-8
+# Copyright (c) 2015 VMware, Inc. All Rights Reserved.
+
+require File.expand_path("../../../../../base", __FILE__)
+
+describe "VagrantPlugins::GuestPhoton::Cap::ConfigureNetworks" do
+ let(:described_class) do
+ VagrantPlugins::GuestPhoton::Plugin.components.guest_capabilities[:photon].get(:configure_networks)
+ end
+ let(:machine) { double("machine") }
+ let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
+
+ before do
+ allow(machine).to receive(:communicate).and_return(communicator)
+ end
+
+ after do
+ communicator.verify_expectations!
+ end
+
+ it 'should configure networks' do
+ networks = [
+ { :type => :static, :ip => '192.168.10.10', :netmask => '255.255.255.0', :interface => 1, :name => 'eth0' },
+ { :type => :dhcp, :interface => 2, :name => 'eth1' },
+ { :type => :static, :ip => '10.168.10.10', :netmask => '255.255.0.0', :interface => 3, :name => 'docker0' }
+ ]
+ communicator.should_receive(:sudo).with("ifconfig | grep 'eth' | cut -f1 -d' '")
+ communicator.should_receive(:sudo).with('ifconfig 192.168.10.10 netmask 255.255.255.0')
+ communicator.should_receive(:sudo).with('ifconfig netmask ')
+ communicator.should_receive(:sudo).with('ifconfig 10.168.10.10 netmask 255.255.0.0')
+
+ allow_message_expectations_on_nil
+ machine.should_receive(:env).at_least(5).times
+ machine.env.should_receive(:active_machines).at_least(:twice)
+ machine.env.active_machines.should_receive(:first)
+ machine.env.should_receive(:machine)
+
+ described_class.configure_networks(machine, networks)
+ end
+end
diff --git a/test/unit/plugins/guests/photon/cap/docker_test.rb b/test/unit/plugins/guests/photon/cap/docker_test.rb
new file mode 100644
index 000000000..6a1c726ff
--- /dev/null
+++ b/test/unit/plugins/guests/photon/cap/docker_test.rb
@@ -0,0 +1,26 @@
+# encoding: UTF-8
+# Copyright (c) 2015 VMware, Inc. All Rights Reserved.
+
+require File.expand_path("../../../../../base", __FILE__)
+
+describe "VagrantPlugins::GuestPhoton::Cap::Docker" do
+ let(:described_class) do
+ VagrantPlugins::GuestPhoton::Plugin.components.guest_capabilities[:photon].get(:docker_daemon_running)
+ end
+ let(:machine) { double("machine") }
+ let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
+ let(:old_hostname) { 'oldhostname.olddomain.tld' }
+
+ before do
+ allow(machine).to receive(:communicate).and_return(communicator)
+ end
+
+ after do
+ communicator.verify_expectations!
+ end
+
+ it 'should check docker' do
+ expect(communicator).to receive(:test).with('test -S /run/docker.sock')
+ described_class.docker_daemon_running(machine)
+ end
+end
diff --git a/test/unit/plugins/guests/tinycore/cap/change_host_name_test.rb b/test/unit/plugins/guests/tinycore/cap/change_host_name_test.rb
new file mode 100644
index 000000000..ba258261f
--- /dev/null
+++ b/test/unit/plugins/guests/tinycore/cap/change_host_name_test.rb
@@ -0,0 +1,26 @@
+require File.expand_path("../../../../../base", __FILE__)
+
+describe "VagrantPlugins::GuestTinyCore::Cap::ChangeHostName" do
+ let(:described_class) do
+ VagrantPlugins::GuestTinyCore::Plugin.components.guest_capabilities[:tinycore].get(:change_host_name)
+ end
+ let(:machine) { double("machine") }
+ let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
+ let(:old_hostname) { 'boot2docker' }
+
+ before do
+ allow(machine).to receive(:communicate).and_return(communicator)
+ communicator.stub_command('hostname -f', stdout: old_hostname)
+ end
+
+ after do
+ communicator.verify_expectations!
+ end
+
+ describe ".change_host_name" do
+ it "refreshes the hostname service with the sethostname command" do
+ communicator.expect_command(%q(/usr/bin/sethostname newhostname.newdomain.tld))
+ described_class.change_host_name(machine, 'newhostname.newdomain.tld')
+ end
+ end
+end
diff --git a/test/unit/plugins/providers/hyperv/config_test.rb b/test/unit/plugins/providers/hyperv/config_test.rb
index a3c46c619..e7b5a6d71 100644
--- a/test/unit/plugins/providers/hyperv/config_test.rb
+++ b/test/unit/plugins/providers/hyperv/config_test.rb
@@ -14,6 +14,15 @@ describe VagrantPlugins::HyperV::Config do
expect(subject.ip_address_timeout).to eq(120)
end
end
+
+ describe "#vlan_id" do
+ it "can be set" do
+ subject.vlan_id = 100
+ subject.finalize!
+ expect(subject.vlan_id).to eq(100)
+ end
+ end
+
describe "#vmname" do
it "can be set" do
subject.vmname = "test"
@@ -21,6 +30,7 @@ describe VagrantPlugins::HyperV::Config do
expect(subject.vmname).to eq("test")
end
end
+
describe "#memory" do
it "can be set" do
subject.memory = 512
@@ -28,6 +38,7 @@ describe VagrantPlugins::HyperV::Config do
expect(subject.memory).to eq(512)
end
end
+
describe "#maxmemory" do
it "can be set" do
subject.maxmemory = 1024
@@ -35,6 +46,7 @@ describe VagrantPlugins::HyperV::Config do
expect(subject.maxmemory).to eq(1024)
end
end
+
describe "#cpus" do
it "can be set" do
subject.cpus = 2
diff --git a/test/unit/plugins/provisioners/ansible/provisioner_test.rb b/test/unit/plugins/provisioners/ansible/provisioner_test.rb
index 05fa8fae3..ca9a891c8 100644
--- a/test/unit/plugins/provisioners/ansible/provisioner_test.rb
+++ b/test/unit/plugins/provisioners/ansible/provisioner_test.rb
@@ -56,6 +56,10 @@ VF
machine.stub(ssh_info: ssh_info)
machine.env.stub(active_machines: [[iso_env.machine_names[0], :dummy], [iso_env.machine_names[1], :dummy]])
+ stubbed_ui = Vagrant::UI::Colored.new
+ stubbed_ui.stub(detail: "")
+ machine.env.stub(ui: stubbed_ui)
+
config.playbook = 'playbook.yml'
end
@@ -111,6 +115,7 @@ VF
end
expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to include("-o IdentitiesOnly=yes")
expect(cmd_opts[:env]['ANSIBLE_FORCE_COLOR']).to eql("true")
+ expect(cmd_opts[:env]).to_not include("ANSIBLE_NOCOLOR")
expect(cmd_opts[:env]['ANSIBLE_HOST_KEY_CHECKING']).to eql(expected_host_key_checking.to_s)
expect(cmd_opts[:env]['PYTHONUNBUFFERED']).to eql(1)
}
@@ -468,7 +473,7 @@ VF
it "shows the ansible-playbook command" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --timeout=30 --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_FORCE_COLOR=true ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --timeout=30 --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml")
}
end
end
@@ -483,7 +488,21 @@ VF
it "shows the ansible-playbook command" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --timeout=30 --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_FORCE_COLOR=true ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --timeout=30 --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml")
+ }
+ end
+ end
+
+ describe "without colorized output" do
+ before do
+ machine.env.stub(ui: Vagrant::UI::Basic.new)
+ end
+
+ it "disables ansible-playbook colored output" do
+ expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
+ cmd_opts = args.last
+ expect(cmd_opts[:env]).to_not include("ANSIBLE_FORCE_COLOR")
+ expect(cmd_opts[:env]['ANSIBLE_NOCOLOR']).to eql("true")
}
end
end
@@ -541,7 +560,7 @@ VF
it "shows the ansible-playbook command, with additional quotes when required" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
- expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_SSH_ARGS='-o IdentitiesOnly=yes -o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/my/key1 --user=testuser --connection=ssh --timeout=30 --limit='machine*:&vagrant:!that_one' --inventory-file=#{generated_inventory_dir} --extra-vars=@#{File.expand_path(__FILE__)} --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --start-at-task='an awesome task' --why-not --su-user=foot --ask-su-pass --limit='all' playbook.yml")
+ expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_FORCE_COLOR=true ANSIBLE_SSH_ARGS='-o IdentitiesOnly=yes -o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/my/key1 --user=testuser --connection=ssh --timeout=30 --limit='machine*:&vagrant:!that_one' --inventory-file=#{generated_inventory_dir} --extra-vars=@#{File.expand_path(__FILE__)} --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --start-at-task='an awesome task' --why-not --su-user=foot --ask-su-pass --limit='all' playbook.yml")
}
end
end
@@ -551,7 +570,7 @@ VF
#
context "with Docker provider on a non-Linux host" do
-
+
let(:fake_host_ssh_info) {{
private_key_path: ['/path/to/docker/host/key'],
username: 'boot9docker',
@@ -561,7 +580,7 @@ VF
let(:fake_host_vm) {
double("host_vm").tap do |h|
h.stub(ssh_info: fake_host_ssh_info)
- end
+ end
}
before do
diff --git a/test/unit/templates/guests/arch/network_dhcp_test.rb b/test/unit/templates/guests/arch/network_dhcp_test.rb
new file mode 100644
index 000000000..10a3f2c7d
--- /dev/null
+++ b/test/unit/templates/guests/arch/network_dhcp_test.rb
@@ -0,0 +1,19 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/arch/network_dhcp" do
+ let(:template) { "guests/arch/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ Description='A basic dhcp ethernet connection'
+ Interface=en0
+ Connection=ethernet
+ IP=dhcp
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/arch/network_static_test.rb b/test/unit/templates/guests/arch/network_static_test.rb
new file mode 100644
index 000000000..375ec67c5
--- /dev/null
+++ b/test/unit/templates/guests/arch/network_static_test.rb
@@ -0,0 +1,37 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/arch/network_static" do
+ let(:template) { "guests/arch/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ Connection=ethernet
+ Description='A basic static ethernet connection'
+ Interface=en0
+ IP=static
+ Address=('1.1.1.1/24')
+ EOH
+ end
+
+ it "includes the gateway" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ gateway: "1.2.3.4",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ Connection=ethernet
+ Description='A basic static ethernet connection'
+ Interface=en0
+ IP=static
+ Address=('1.1.1.1/24')
+ Gateway='1.2.3.4'
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/debian/network_dhcp_test.rb b/test/unit/templates/guests/debian/network_dhcp_test.rb
new file mode 100644
index 000000000..766227461
--- /dev/null
+++ b/test/unit/templates/guests/debian/network_dhcp_test.rb
@@ -0,0 +1,41 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/debian/network_dhcp" do
+ let(:template) { "guests/debian/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ auto eth
+ iface eth inet dhcp
+ post-up route del default dev $IFACE || true
+ #VAGRANT-END
+ EOH
+ end
+
+ context "when use_dhcp_assigned_default_route is set" do
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ use_dhcp_assigned_default_route: true,
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {8}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ auto eth
+ iface eth inet dhcp
+ # We need to disable eth0, see GH-2648
+ post-up route del default dev eth0
+ post-up dhclient $IFACE
+ pre-down route add default dev eth0
+ #VAGRANT-END
+ EOH
+ end
+ end
+end
diff --git a/test/unit/templates/guests/debian/network_static_test.rb b/test/unit/templates/guests/debian/network_static_test.rb
new file mode 100644
index 000000000..936a6a806
--- /dev/null
+++ b/test/unit/templates/guests/debian/network_static_test.rb
@@ -0,0 +1,43 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/debian/network_static" do
+ let(:template) { "guests/debian/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ auto eth
+ iface eth inet static
+ address 1.1.1.1
+ netmask 255.255.0.0
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the gateway" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ gateway: "1.2.3.4",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ auto eth
+ iface eth inet static
+ address 1.1.1.1
+ netmask 255.255.0.0
+ gateway 1.2.3.4
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/fedora/network_dhcp_test.rb b/test/unit/templates/guests/fedora/network_dhcp_test.rb
new file mode 100644
index 000000000..b257aa76e
--- /dev/null
+++ b/test/unit/templates/guests/fedora/network_dhcp_test.rb
@@ -0,0 +1,21 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/fedora/network_dhcp" do
+ let(:template) { "guests/fedora/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ BOOTPROTO=dhcp
+ ONBOOT=yes
+ DEVICE=en0
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/fedora/network_static_test.rb b/test/unit/templates/guests/fedora/network_static_test.rb
new file mode 100644
index 000000000..f6e879fa2
--- /dev/null
+++ b/test/unit/templates/guests/fedora/network_static_test.rb
@@ -0,0 +1,71 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/fedora/network_static" do
+ let(:template) { "guests/fedora/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ NM_CONTROLLED=no
+ BOOTPROTO=none
+ ONBOOT=yes
+ IPADDR=1.1.1.1
+ NETMASK=255.255.0.0
+ DEVICE=en0
+ PEERDNS=no
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the gateway" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ gateway: "1.2.3.4",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ NM_CONTROLLED=no
+ BOOTPROTO=none
+ ONBOOT=yes
+ IPADDR=1.1.1.1
+ NETMASK=255.255.0.0
+ DEVICE=en0
+ GATEWAY=1.2.3.4
+ PEERDNS=no
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the mac_address" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ mac_address: "abcd1234",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ NM_CONTROLLED=no
+ BOOTPROTO=none
+ ONBOOT=yes
+ IPADDR=1.1.1.1
+ NETMASK=255.255.0.0
+ DEVICE=en0
+ HWADDR=abcd1234
+ PEERDNS=no
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/freebsd/network_dhcp_test.rb b/test/unit/templates/guests/freebsd/network_dhcp_test.rb
new file mode 100644
index 000000000..322de3746
--- /dev/null
+++ b/test/unit/templates/guests/freebsd/network_dhcp_test.rb
@@ -0,0 +1,16 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/freebsd/network_dhcp" do
+ let(:template) { "guests/freebsd/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, ifname: "vtneten0")
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ ifconfig_vtneten0="DHCP"
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/freebsd/network_static_test.rb b/test/unit/templates/guests/freebsd/network_static_test.rb
new file mode 100644
index 000000000..ca9eb0153
--- /dev/null
+++ b/test/unit/templates/guests/freebsd/network_static_test.rb
@@ -0,0 +1,39 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/freebsd/network_static" do
+ let(:template) { "guests/freebsd/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template,
+ ifname: "vtneten0",
+ options: {
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ },
+ )
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ ifconfig_vtneten0="inet 1.1.1.1 netmask 255.255.0.0"
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the gateway" do
+ result = Vagrant::Util::TemplateRenderer.render(template,
+ ifname: "vtneten0",
+ options: {
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ gateway: "1.2.3.4",
+ },
+ )
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ ifconfig_vtneten0="inet 1.1.1.1 netmask 255.255.0.0"
+ default_router="1.2.3.4"
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/funtoo/network_dhcp_test.rb b/test/unit/templates/guests/funtoo/network_dhcp_test.rb
new file mode 100644
index 000000000..0e3cafb1c
--- /dev/null
+++ b/test/unit/templates/guests/funtoo/network_dhcp_test.rb
@@ -0,0 +1,19 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/funtoo/network_dhcp" do
+ let(:template) { "guests/funtoo/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='dhcp'
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/funtoo/network_static_test.rb b/test/unit/templates/guests/funtoo/network_static_test.rb
new file mode 100644
index 000000000..5a14312d2
--- /dev/null
+++ b/test/unit/templates/guests/funtoo/network_static_test.rb
@@ -0,0 +1,141 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/funtoo/network_static" do
+ let(:template) { "guests/funtoo/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='interface'
+ ipaddr='1.1.1.1/255.255.0.0'
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the gateway" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ gateway: "1.2.3.4",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='interface'
+ ipaddr='1.1.1.1/255.255.0.0'
+ gateway='1.2.3.4'
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the nameservers" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ nameservers: "ns1.company.com",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='interface'
+ ipaddr='1.1.1.1/255.255.0.0'
+ nameservers='ns1.company.com'
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the domain" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ domain: "company.com",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='interface'
+ ipaddr='1.1.1.1/255.255.0.0'
+ domain='company.com'
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the route" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ route: "5.6.7.8",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='interface'
+ ipaddr='1.1.1.1/255.255.0.0'
+ route='5.6.7.8'
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the gateway6" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ gateway6: "aaaa:0000",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='interface'
+ ipaddr='1.1.1.1/255.255.0.0'
+ gateway6='aaaa:0000'
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the route6" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ route6: "bbbb:1111",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='interface'
+ ipaddr='1.1.1.1/255.255.0.0'
+ route6='bbbb:1111'
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the mtu" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ device: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ mtu: "1",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ template='interface'
+ ipaddr='1.1.1.1/255.255.0.0'
+ mtu='1'
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/gentoo/network_dhcp_test.rb b/test/unit/templates/guests/gentoo/network_dhcp_test.rb
new file mode 100644
index 000000000..7885c2acc
--- /dev/null
+++ b/test/unit/templates/guests/gentoo/network_dhcp_test.rb
@@ -0,0 +1,19 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/gentoo/network_dhcp" do
+ let(:template) { "guests/gentoo/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ config_ethen0="dhcp"
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/gentoo/network_static_test.rb b/test/unit/templates/guests/gentoo/network_static_test.rb
new file mode 100644
index 000000000..e1eb8ce1a
--- /dev/null
+++ b/test/unit/templates/guests/gentoo/network_static_test.rb
@@ -0,0 +1,37 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/gentoo/network_static" do
+ let(:template) { "guests/gentoo/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ config_ethen0=("1.1.1.1 netmask 255.255.0.0")
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the gateway" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ gateway: "1.2.3.4",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ config_ethen0=("1.1.1.1 netmask 255.255.0.0")
+ gateways_ethen0="1.2.3.4"
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/netbsd/network_dhcp_test.rb b/test/unit/templates/guests/netbsd/network_dhcp_test.rb
new file mode 100644
index 000000000..c2f68d7ba
--- /dev/null
+++ b/test/unit/templates/guests/netbsd/network_dhcp_test.rb
@@ -0,0 +1,18 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/netbsd/network_dhcp" do
+ let(:template) { "guests/netbsd/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ ifconfig_wmen0=dhcp
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/netbsd/network_static_test.rb b/test/unit/templates/guests/netbsd/network_static_test.rb
new file mode 100644
index 000000000..210dc4d30
--- /dev/null
+++ b/test/unit/templates/guests/netbsd/network_static_test.rb
@@ -0,0 +1,20 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/netbsd/network_static" do
+ let(:template) { "guests/netbsd/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ ifconfig_wmen0="media autoselect up;inet 1.1.1.1 netmask 255.255.0.0"
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/redhat/network_dhcp_test.rb b/test/unit/templates/guests/redhat/network_dhcp_test.rb
new file mode 100644
index 000000000..280678a2f
--- /dev/null
+++ b/test/unit/templates/guests/redhat/network_dhcp_test.rb
@@ -0,0 +1,21 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/redhat/network_dhcp" do
+ let(:template) { "guests/redhat/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ BOOTPROTO=dhcp
+ ONBOOT=yes
+ DEVICE=ethen0
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/redhat/network_static_test.rb b/test/unit/templates/guests/redhat/network_static_test.rb
new file mode 100644
index 000000000..443ec2d56
--- /dev/null
+++ b/test/unit/templates/guests/redhat/network_static_test.rb
@@ -0,0 +1,49 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/redhat/network_static" do
+ let(:template) { "guests/redhat/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ NM_CONTROLLED=no
+ BOOTPROTO=none
+ ONBOOT=yes
+ IPADDR=1.1.1.1
+ NETMASK=255.255.0.0
+ DEVICE=ethen0
+ PEERDNS=no
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the gateway" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ ip: "1.1.1.1",
+ gateway: "1.2.3.4",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ NM_CONTROLLED=no
+ BOOTPROTO=none
+ ONBOOT=yes
+ IPADDR=1.1.1.1
+ NETMASK=255.255.0.0
+ DEVICE=ethen0
+ GATEWAY=1.2.3.4
+ PEERDNS=no
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/suse/network_dhcp_test.rb b/test/unit/templates/guests/suse/network_dhcp_test.rb
new file mode 100644
index 000000000..82595db47
--- /dev/null
+++ b/test/unit/templates/guests/suse/network_dhcp_test.rb
@@ -0,0 +1,21 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/suse/network_dhcp" do
+ let(:template) { "guests/suse/network_dhcp" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ BOOTPROTO=dhcp
+ ONBOOT=yes
+ DEVICE=ethen0
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/templates/guests/suse/network_static_test.rb b/test/unit/templates/guests/suse/network_static_test.rb
new file mode 100644
index 000000000..09117268d
--- /dev/null
+++ b/test/unit/templates/guests/suse/network_static_test.rb
@@ -0,0 +1,49 @@
+require_relative "../../../base"
+
+require "vagrant/util/template_renderer"
+
+describe "templates/guests/suse/network_static" do
+ let(:template) { "guests/suse/network_static" }
+
+ it "renders the template" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ ip: "1.1.1.1",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ BOOTPROTO='static'
+ IPADDR='1.1.1.1'
+ NETMASK='255.255.0.0'
+ DEVICE='ethen0'
+ PEERDNS='no'
+ STARTMODE='auto'
+ USERCONTROL='no'
+ #VAGRANT-END
+ EOH
+ end
+
+ it "includes the gateway" do
+ result = Vagrant::Util::TemplateRenderer.render(template, options: {
+ interface: "en0",
+ ip: "1.1.1.1",
+ gateway: "1.2.3.4",
+ netmask: "255.255.0.0",
+ })
+ expect(result).to eq <<-EOH.gsub(/^ {6}/, "")
+ #VAGRANT-BEGIN
+ # The contents below are automatically generated by Vagrant. Do not modify.
+ BOOTPROTO='static'
+ IPADDR='1.1.1.1'
+ NETMASK='255.255.0.0'
+ DEVICE='ethen0'
+ GATEWAY='1.2.3.4'
+ PEERDNS='no'
+ STARTMODE='auto'
+ USERCONTROL='no'
+ #VAGRANT-END
+ EOH
+ end
+end
diff --git a/test/unit/vagrant/ui_test.rb b/test/unit/vagrant/ui_test.rb
index 537161a56..b4a7d7d89 100644
--- a/test/unit/vagrant/ui_test.rb
+++ b/test/unit/vagrant/ui_test.rb
@@ -40,23 +40,37 @@ describe Vagrant::UI::Basic do
subject.output("foo", new_line: false)
end
- it "outputs to stdout" do
+ it "outputs to the assigned stdout" do
+ stdout = StringIO.new
+ subject.stdout = stdout
+
expect(subject).to receive(:safe_puts).with { |message, **opts|
- expect(opts[:io]).to be($stdout)
+ expect(opts[:io]).to be(stdout)
true
}
subject.output("foo")
end
- it "outputs to stderr for errors" do
+ it "outputs to stdout by default" do
+ expect(subject.stdout).to be($stdout)
+ end
+
+ it "outputs to the assigned stderr for errors" do
+ stderr = StringIO.new
+ subject.stderr = stderr
+
expect(subject).to receive(:safe_puts).with { |message, **opts|
- expect(opts[:io]).to be($stderr)
+ expect(opts[:io]).to be(stderr)
true
}
subject.error("foo")
end
+
+ it "outputs to stderr for errors by default" do
+ expect(subject.stderr).to be($stderr)
+ end
end
context "#detail" do
diff --git a/test/unit/vagrant/util/platform_test.rb b/test/unit/vagrant/util/platform_test.rb
index 3e980937f..ae51076ec 100644
--- a/test/unit/vagrant/util/platform_test.rb
+++ b/test/unit/vagrant/util/platform_test.rb
@@ -10,4 +10,10 @@ describe Vagrant::Util::Platform do
expect(described_class.fs_real_path("c:/foo").to_s).to eql("C:/foo")
end
end
+
+ describe "#windows_unc_path" do
+ it "correctly converts a path" do
+ expect(described_class.windows_unc_path("c:/foo").to_s).to eql("\\\\?\\c:\\foo")
+ end
+ end
end
diff --git a/vagrant.gemspec b/vagrant.gemspec
index 0e68a6d08..00b5ebb4c 100644
--- a/vagrant.gemspec
+++ b/vagrant.gemspec
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
s.add_dependency "rest-client", ">= 1.6.0", "< 2.0"
s.add_dependency "wdm", "~> 0.1.0"
s.add_dependency "winrm", "~> 1.3"
- s.add_dependency "winrm-fs", "~> 0.1.0"
+ s.add_dependency "winrm-fs", "~> 0.2.0"
# We lock this down to avoid compilation issues.
s.add_dependency "nokogiri", "= 1.6.3.1"
diff --git a/website/docs/Vagrantfile b/website/docs/Vagrantfile
index 7ce24fe70..34e232f31 100644
--- a/website/docs/Vagrantfile
+++ b/website/docs/Vagrantfile
@@ -4,11 +4,13 @@
$script = <