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