merge with upstream master / fix conflickt in layout

This commit is contained in:
captainill 2015-12-20 13:06:30 -08:00
commit b98db9ce59
282 changed files with 6347 additions and 1728 deletions

4
.gitignore vendored
View File

@ -1,6 +1,10 @@
# OS-specific
.DS_Store
# Editor swapfiles
.*.sw?
*~
# Vagrant stuff
acceptance_config.yml
boxes/*

View File

@ -2,22 +2,162 @@
FEATURES:
- **New Command: `vagrant powershell`**: For machines that support it,
this will open a PowerShell prompt.
- **New Command: `vagrant port`**: For machines that support it, this will
display the list of forwarded ports from the guest to the host.
- **Linked Clones**: VirtualBox and VMware providers now support
linked clones for very fast (millisecond) imports on up. [GH-4484]
- **Snapshots**: The `vagrant snapshot` command can be used to checkpoint
and restore point-in-time snapshots.
- **IPv6 Private Networks**: Private networking now supports IPv6. This
only works with VirtualBox and VMware at this point. [GH-6342]
- New provisioner: `ansible_local` to execute Ansible from the guest
machine. [GH-2103]
BREAKING CHANGES:
- The `ansible` provisioner now can override the effective ansible remote user
(i.e. `ansible_ssh_user` setting) to always correspond to the vagrant ssh
username. This change is enabled by default, but we expect this to affect
only a tiny number of people as it corresponds to the common usage.
If you however use multiple remote usernames in your Ansible plays, tasks,
or custom inventories, you can simply set the option `force_remote_user` to
false to make Vagrant behave the same as before.
- provisioners/salt: the "config_dir" option has been removed. It has no
effect in Vagrant 1.8. [GH-6073]
IMPROVEMENTS:
- core: allow removal of all box versions with `--all` flag [GH-3462]
- core: prune entries from global status on non-existent cwd [GH-6535]
- core: networking: allow specifying a DHCP IP [GH-6325]
- core: run provisioner cleanup tasks before powering off the VM [GH-6553]
- core: only run provisioner cleanup tasks if they're implemented [GH-6603]
This improves UX, but wasn't a bug before.
- command/plugin: Add `--plugin-clean-sources` flag to reset plugin install
sources, primarily for corp firewalls. [GH-4738]
- command/rsync-auto: SSH connection is cached for faster sync times [GH-6399]
- command/up: provisioners are run on suspend resume [GH-5815]
- communicators/ssh: allow specifying host environment variables to forward
to guests [GH-4132, GH-6562]
- communicators/winrm: Configurable execution time limit [GH-6213]
- providers/virtualbox: cache version lookup, which caused significant
slowdown on some Windows hosts [GH-6552]
- providers/virtualbox: add `public_address` capability for virtualbox
[GH-6583, GH-5978]
- provisioners/chef: perform cleanup tasks on the guest instead of the host
- provisioners/chef: automatically generate a node_name if one was not given
[GH-6555]
- provisioners/chef: install Chef automatically on Windows [GH-6557]
- provisioners/chef: allow the user to specify the Chef product (such as
the Chef Development Kit) [GH-6557]
- provisioners/chef: allow data_bags_path to be an array [GH-5988, GH-6561]
- provisioners/shell: Support interactive mode for elevated PowerShell
scripts [GH-6185]
- provisioners/shell: add `env` option [GH-6588, GH-6516]
- provisioners/ansible+ansible_local: add support for ansible-galaxy [GH-2718]
- provisioners/ansible+ansible_local: add support for group and host variables
in the generated inventory [GH-6619]
- provisioners/ansible+ansible_local: add support for alphanumeric patterns
for groups in the generated inventory [GH-3539]
- provisioners/ansible: add support for WinRM settings [GH-5086]
- provisioners/ansible: add new `force_remote_user` option to control whether
`ansible_ssh_user` parameter should be applied or not [GH-6348]
- provisioners/ansible: show a warning when running from a Windows Host [GH-5292]
- pushes/local-exec: add support for specifying script args [GH-6661, GH-6660]
- guests/slackware: add support for networking [GH-6514]
BUG FIXES:
- core: Ctrl-C weirdness fixed where it would exit parent process
before Vagrant finished cleaning up [GH-6085]
- core: DHCP network configurations don't warn on IP addresses ending
in ".1" [GH-6150]
- core: only append `access_token` when it does not exist in the URL
[GH-6395, GH-6534]
- core: use the correct private key when packaging a box [GH-6406]
- core: fix crash when using invalid box checksum type [GH-6327]
- core: don't check for metadata if the download URL is not HTTP [GH-6540]
- core: don't make custom dotfile path if there is no Vagrantfile [GH-6542]
- core: more robust check for admin privs on Windows [GH-5616]
- core: properly detect when HTTP server doesn't support byte ranges and
retry from scratch [GH-4479]
- core: line numbers show properly in Vagrantfile syntax errors
on Windows [GH-6445]
- core: catch errors setting env vars on Windows [GH-6017]
- core: remove cached synced folders when they're removed from the
Vagrantfile [GH-6567]
- core: use case-insensitive comparison for box checksum validations
[GH-6648, GH-6650]
- commands/box: add command with `~` paths on Windows works [GH-5747]
- commands/box: the update command supports CA settings [GH-4473]
- commands/box: removing all versions and providers of a box will properly
clean all directories in `~/.vagrant.d/boxes` [GH-3570]
- commands/box: outdated global won't halt on metadata download failure [GH-6453]
- commands/login: respect environment variables in `vagrant login` command
[GH-6590, GH-6422]
- commands/package: when re-packaging a packaged box, preserve the
generated SSH key [GH-5780]
- commands/plugin: retry plugin install automatically a few times to
avoid network issues [GH-6097]
- commands/rdp: prefer `xfreerdp` if it is available on Linux [GH-6475]
- commands/up: the `--provision-with` flag works with provisioner names [GH-5981]
- communicator/ssh: fix potential crash case with PTY [GH-6225]
- communicator/ssh: escape IdentityFile path [GH-6428, GH-6589]
- communicator/winrm: respect `boot_timeout` setting [GH-6229]
- communicator/winrm: execute scheduled tasks immediately on Windows XP
since elevation isn't required [GH-6195]
- communicator/winrm: Decouple default port forwarding rules for "winrm" and
"winrm-ssl" [GH-6581]
- communicator/winrm: Hide progress bars from PowerShell v5 [GH-6309]
- guests/arch: enable network device after setting it up [GH-5737]
- guests/darwin: advanced networking works with more NICs [GH-6386]
- guests/debian: graceful shutdown works properly with newer releases [GH-5986]
- guests/fedora: Preserve `localhost` entry when changing hostname [GH-6203]
- guests/fedora: Use dnf if it is available [GH-6288]
- guests/linux: when replacing a public SSH key, use POSIX-compliant
sed flags [GH-6565]
- guests/suse: DHCP network interfaces properly configured [GH-6502]
- hosts/slackware: Better detection of NFS [GH-6367]
- providers/hyper-v: support generation 2 VMs [GH-6372]
- providers/hyper-v: support VMs with more than one NIC [GH-4346]
- providers/hyper-v: check if user is in the Hyper-V admin group if
they're not a Windows admin [GH-6662]
- providers/virtualbox: ignore "Unknown" status bridge interfaces [GH-6061]
- providers/virtualbox: only fix ipv6 interfaces that are in use
[GH-6586, GH-6552]
- provisioners/ansible: use quotes for the `ansible_ssh_private_key_file`
value in the generated inventory [GH-6209]
- provisioners/ansible: use quotes when passing the private key files via
OpenSSH `-i` command line arguments [GH-6671]
- provisioners/ansible: don't show the `ansible-playbook` command when verbose
option is an empty string
- provisioners/chef: fix `nodes_path` for Chef Zero [GH-6025, GH-6049]
- provisioners/chef: do not error when the `node_name` is unset
[GH-6005, GH-6064, GH-6541]
- provisioners/chef: only force the formatter on Chef 11 or higher
[GH-6278, GH-6556]
- provisioners/chef: require `nodes_path` to be set for Chef Zero
[GH-6110, GH-6559]
- provisioners/puppet: apply provisioner uses correct default manifests
with environments. [GH-5987]
- provisioners/puppet: remove broken backticks [GH-6404]
- provisioners/puppet: find Puppet binary properly on Windows [GH-6259]
- provisioners/puppet-server: works with Puppet Collection 1 [GH-6389]
- provisioners/salt: call correct executables on Windows [GH-5999]
- provisioners/salt: log level and colorize works for masterless [GH-6474]
- push/local-exec: use subprocess on windows when fork does not exist
[GH-5307, GH-6563]
- push/heroku: use current branch [GH-6554]
- synced\_folders/rsync: on Windows, replace all paths with Cygwin
paths since all rsync implementations require this [GH-6160]
- synced\_folders/smb: use credentials files to allow for more characters
in password [GH-4230]
PLUGIN AUTHOR CHANGES:
- installer: Upgrade to Ruby 2.2.3
## 1.7.4 (July 17, 2015)

View File

@ -1,6 +1,6 @@
# Vagrant
* Website: [http://www.vagrantup.com](http://www.vagrantup.com)
* Website: [https://www.vagrantup.com/](https://www.vagrantup.com/)
* Source: [https://github.com/mitchellh/vagrant](https://github.com/mitchellh/vagrant)
* IRC: `#vagrant` on Freenode
* Mailing list: [Google Groups](http://groups.google.com/group/vagrant-up)
@ -19,12 +19,12 @@ between Windows, Mac OS X, and Linux.
## Quick Start
For the quick-start, we'll bring up a development machine on
[VirtualBox](http://www.virtualbox.org) because it is free and works
[VirtualBox](https://www.virtualbox.org/) because it is free and works
on all major platforms. Vagrant can, however, work with almost any
system such as OpenStack, VMware, Docker, etc.
system such as [OpenStack] (https://www.openstack.org/), [VMware] (http://www.vmware.com/), [Docker] (https://docs.docker.com/), etc.
First, make sure your development machine has
[VirtualBox](http://www.virtualbox.org)
[VirtualBox](https://www.virtualbox.org/)
installed. After this,
[download and install the appropriate Vagrant package for your OS](http://www.vagrantup.com/downloads).
@ -55,7 +55,7 @@ Ruby 2.0 is needed.
### Dependencies and Unit Tests
To hack on Vagrant, you'll need [bundler](http://github.com/carlhuda/bundler) which can
To hack on Vagrant, you'll need [bundler](https://github.com/bundler/bundler) which can
be installed with a simple `gem install bundler`. Afterwards, do the following:
bundle install

View File

@ -10,5 +10,7 @@ for each item will be kept below.
* `emacs` - Contains a file for enabling Ruby syntax highlighting for `Vagrantfile`s in `emacs`.
* `st` - Contains a `.sublime-settings` file for enabling Ruby syntax highlighting
for `Vagrantfile`s in Sublime Text.
* `sudoers` - Contains the pieces of `/etc/sudoers` configuration to avoid password entry when
starting machines.
* `vim` - Contains a `.vim` file for enabling Ruby syntax highlighting
for `Vagrantfile`s in `vim`.

View File

@ -2,5 +2,6 @@ Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
Cmnd_Alias VAGRANT_NFSD_CHECK = /usr/bin/systemctl status nfs-server.service
Cmnd_Alias VAGRANT_NFSD_START = /usr/bin/systemctl start nfs-server.service
Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /etc/exports
%vagrant ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /*/exports
Cmnd_Alias VAGRANT_EXPORTS_REMOVE_2 = /bin/cp /*/exports /etc/exports
%vagrant ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE, VAGRANT_EXPORTS_REMOVE_2

View File

@ -0,0 +1,7 @@
Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
Cmnd_Alias VAGRANT_NFSD_CHECK = /sbin/service nfsserver status
Cmnd_Alias VAGRANT_NFSD_START = /sbin/service nfsserver start
Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -r -e * d -ibak /*/exports
Cmnd_Alias VAGRANT_EXPORTS_REMOVE_2 = /usr/bin/cp /*/exports /etc/exports
%vagrant ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE, VAGRANT_EXPORTS_REMOVE_2

View File

@ -4,5 +4,6 @@ Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
Cmnd_Alias VAGRANT_NFSD_CHECK = /etc/init.d/nfs-kernel-server status
Cmnd_Alias VAGRANT_NFSD_START = /etc/init.d/nfs-kernel-server start
Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /etc/exports
%sudo ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /*/exports
Cmnd_Alias VAGRANT_EXPORTS_REMOVE_2 = /bin/cp /*/exports /etc/exports
%sudo ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE, VAGRANT_EXPORTS_REMOVE_2

View File

@ -381,7 +381,9 @@ module Vagrant
@logger.info("URL is a file or protocol not found and assuming file.")
file_path = File.expand_path(url)
file_path = Util::Platform.cygwin_windows_path(file_path)
url = "file:#{file_path}"
file_path = file_path.gsub("\\", "/")
file_path = "/#{file_path}" if !file_path.start_with?("/")
url = "file://#{file_path}"
end
# If the temporary path exists, verify it is not too old. If its
@ -491,6 +493,12 @@ module Vagrant
end
end
# If this isn't HTTP, then don't do the HEAD request
if !uri.scheme.downcase.start_with?("http")
@logger.info("not checking metadata since box URI isn't HTTP")
return false
end
output = d.head
match = output.scan(/^Content-Type: (.+?)$/i).last
return false if !match
@ -507,14 +515,14 @@ module Vagrant
Digest::SHA2
else
raise Errors::BoxChecksumInvalidType,
type: env[:box_checksum_type].to_s
type: checksum_type.to_s
end
@logger.info("Validating checksum with #{checksum_klass}")
@logger.info("Expected checksum: #{checksum}")
actual = FileChecksum.new(path, checksum_klass).checksum
if actual != checksum
if actual.casecmp(checksum) != 0
raise Errors::BoxChecksumMismatch,
actual: actual,
expected: checksum

View File

@ -37,13 +37,23 @@ module Vagrant
end
constraints = machine.config.vm.box_version
# Have download options specified in the environment override
# options specified for the machine.
download_options = {
ca_cert: env[:ca_cert] || machine.config.vm.box_download_ca_cert,
ca_path: env[:ca_path] || machine.config.vm.box_download_ca_path,
client_cert: env[:client_cert] ||
machine.config.vm.box_download_client_cert,
insecure: !env[:insecure].nil? ?
env[:insecure] : machine.config.vm.box_download_insecure
}
env[:ui].output(I18n.t(
"vagrant.box_outdated_checking_with_refresh",
name: box.name))
update = nil
begin
update = box.has_update?(constraints)
update = box.has_update?(constraints, download_options: download_options)
rescue Errors::BoxMetadataDownloadError => e
env[:ui].warn(I18n.t(
"vagrant.box_outdated_metadata_download_error",

View File

@ -111,6 +111,7 @@ module Vagrant
provider: box.provider,
version: box.version))
box.destroy!
env[:box_collection].clean(box.name)
# Passes on the removed box to the rest of the middleware chain
env[:box_removed] = box

View File

@ -128,7 +128,7 @@ module Vagrant
port_checker[repaired_port] ||
lease_check(repaired_port)
if in_use
@logger.info("Reparied port also in use: #{repaired_port}. Trying another...")
@logger.info("Repaired port also in use: #{repaired_port}. Trying another...")
next
end
@ -156,8 +156,6 @@ module Vagrant
new_port: repaired_port.to_s))
end
end
@app.call(env)
end
def lease_check(port)

View File

@ -76,6 +76,16 @@ module Vagrant
if opts[:merge]
existing = cached_synced_folders(machine)
if existing
if opts[:vagrantfile]
# Go through and find any cached that were from the
# Vagrantfile itself. We remove those if it was requested.
existing.each do |impl, fs|
fs.each do |id, data|
fs.delete(id) if data[:__vagrantfile]
end
end
end
folders.each do |impl, fs|
existing[impl] ||= {}
fs.each do |id, data|
@ -101,7 +111,12 @@ module Vagrant
return cached_synced_folders(machine) if opts[:cached]
config = opts[:config]
config ||= machine.config.vm
root = false
if !config
config = machine.config.vm
root = true
end
config_folders = config.synced_folders
folders = {}
@ -131,9 +146,17 @@ module Vagrant
end
end
# Get the data to store
data = data.dup
if root
# If these are the root synced folders (attached directly)
# to the Vagrantfile, then we mark it as such.
data[:__vagrantfile] = true
end
# Keep track of this shared folder by the implementation.
folders[impl] ||= {}
folders[impl][id] = data.dup
folders[impl][id] = data
end
# If we have folders with the "default" key, then determine the

View File

@ -13,8 +13,9 @@ module Vagrant
def initialize(app, env, place=nil)
@app = app
@logger = Log4r::Logger.new("vagrant::action::builtin::provision_cleanup")
@place ||= :after
@place = @place.to_sym
place ||= :after
@place = place.to_sym
end
def call(env)
@ -31,10 +32,20 @@ module Vagrant
# Ask the provisioners to modify the configuration if needed
provisioner_instances(env).each do |p, _|
env[:ui].info(I18n.t(
"vagrant.provisioner_cleanup",
name: type_map[p].to_s))
name = type_map[p].to_s
# Check if the subclass defined a cleanup method. The parent
# provisioning class defines a `cleanup` method, so we cannot use
# `respond_to?` here. Instead, we have to check if _this_ instance
# defines a cleanup task.
if p.public_methods(false).include?(:cleanup)
env[:ui].info(I18n.t("vagrant.provisioner_cleanup",
name: name,
))
p.cleanup
else
@logger.debug("Skipping cleanup tasks for `#{name}' - not defined")
end
end
end
end

View File

@ -23,6 +23,7 @@ module Vagrant
config: env[:synced_folders_config],
}
@logger.info("SyncedFolders loading from cache: #{opts[:cached]}")
folders = synced_folders(env[:machine], **opts)
original_folders = folders
@ -121,8 +122,11 @@ module Vagrant
save_synced_folders(env[:machine], all)
else
save_opts = { merge: true }
save_opts[:vagrantfile] = true if !opts[:config]
# Save the synced folders
save_synced_folders(env[:machine], original_folders, merge: true)
save_synced_folders(env[:machine], original_folders, **save_opts)
end
end
end

View File

@ -113,6 +113,21 @@ module Vagrant
# If we don't have a generated private key, we do nothing
path = @env[:machine].data_dir.join("private_key")
if !path.file?
# If we have a private key that was copied into this box,
# then we copy that. This is a bit of a heuristic and can be a
# security risk if the key is named the correct thing, but
# we'll take that risk for dev environments.
(@env[:machine].config.ssh.private_key_path || []).each do |p|
# If we have the correctly named key, copy it
if File.basename(p) == "vagrant_private_key"
path = Pathname.new(p)
break
end
end
end
# If we still have no matching key, do nothing
return if !path.file?
# Copy it into our box directory

View File

@ -115,8 +115,9 @@ module Vagrant
# Loads the metadata URL and returns the latest metadata associated
# with this box.
#
# @param [Hash] download_options Options to pass to the downloader.
# @return [BoxMetadata]
def load_metadata
def load_metadata(**download_options)
tf = Tempfile.new("vagrant")
tf.close
@ -127,7 +128,7 @@ module Vagrant
url = "file:#{url}"
end
opts = { headers: ["Accept: application/json"] }
opts = { headers: ["Accept: application/json"] }.merge(download_options)
Util::Downloader.new(url, tf.path, **opts).download!
BoxMetadata.new(File.open(tf.path, "r"))
rescue Errors::DownloaderError => e
@ -148,7 +149,7 @@ module Vagrant
# satisfy. If nil, the version constrain defaults to being a
# larger version than this box.
# @return [Array]
def has_update?(version=nil)
def has_update?(version=nil, download_options: {})
if !@metadata_url
raise Errors::BoxUpdateNoMetadata, name: @name
end
@ -156,7 +157,7 @@ module Vagrant
version += ", " if version
version ||= ""
version += "> #{@version}"
md = self.load_metadata
md = self.load_metadata(download_options)
newer = md.version(version, provider: @provider)
return nil if !newer

View File

@ -12,7 +12,9 @@ module Vagrant
# for accessing/finding individual boxes, adding new boxes, or deleting
# boxes.
class BoxCollection
TEMP_PREFIX = "vagrant-box-add-temp-"
TEMP_PREFIX = "vagrant-box-add-temp-".freeze
VAGRANT_SLASH = "-VAGRANTSLASH-".freeze
VAGRANT_COLON = "-VAGRANTCOLON-".freeze
# The directory where the boxes in this collection are stored.
#
@ -346,6 +348,14 @@ module Vagrant
end
end
# Cleans the directory for a box by removing the folders that are
# empty.
def clean(name)
return false if exists?(name)
path = File.join(directory, dir_name(name))
FileUtils.rm_rf(path)
end
protected
# Returns the directory name for the box of the given name.
@ -354,16 +364,16 @@ module Vagrant
# @return [String]
def dir_name(name)
name = name.dup
name.gsub!(":", "-VAGRANTCOLON-") if Util::Platform.windows?
name.gsub!("/", "-VAGRANTSLASH-")
name.gsub!(":", VAGRANT_COLON) if Util::Platform.windows?
name.gsub!("/", VAGRANT_SLASH)
name
end
# Returns the directory name for the box cleaned up
def undir_name(name)
name = name.dup
name.gsub!("-VAGRANTCOLON-", ":")
name.gsub!("-VAGRANTSLASH-", "/")
name.gsub!(VAGRANT_COLON, ":")
name.gsub!(VAGRANT_SLASH, "/")
name
end
@ -440,5 +450,10 @@ module Vagrant
ensure
dir.rmtree if dir.exist?
end
# Checks if a box with a given name exists.
def exists?(box_name)
all.any? { |box| box.first.eql?(box_name) }
end
end
end

View File

@ -7,6 +7,7 @@ require "bundler"
require_relative "shared_helpers"
require_relative "version"
require_relative "util/safe_env"
module Vagrant
# This class manages Vagrant's interaction with Bundler. Vagrant uses
@ -42,6 +43,9 @@ module Vagrant
yield
end
end
# Configure Bundler to retry
::Bundler.settings[:retry] = 3
end
# Initializes Bundler and the various gem paths so that we can begin
@ -68,12 +72,15 @@ module Vagrant
# we add all our plugin dependencies.
@gemfile = build_gemfile(plugins)
Util::SafeEnv.change_env do |env|
# Set the environmental variables for Bundler
ENV["BUNDLE_APP_CONFIG"] = @appconfigpath
ENV["BUNDLE_CONFIG"] = @configfile.path
ENV["BUNDLE_GEMFILE"] = @gemfile.path
ENV["GEM_PATH"] =
env["BUNDLE_APP_CONFIG"] = @appconfigpath
env["BUNDLE_CONFIG"] = @configfile.path
env["BUNDLE_GEMFILE"] = @gemfile.path
env["GEM_PATH"] =
"#{bundle_path}#{::File::PATH_SEPARATOR}#{@gem_path}"
end
Gem.clear_paths
end
@ -178,11 +185,6 @@ module Vagrant
f = File.open(Tempfile.new("vagrant").path + "2", "w+")
f.tap do |gemfile|
if !sources.include?("http://rubygems.org")
gemfile.puts(%Q[source "https://rubygems.org"])
end
gemfile.puts(%Q[source "http://gems.hashicorp.com"])
sources.each do |source|
next if source == ""
gemfile.puts(%Q[source "#{source}"])

View File

@ -221,7 +221,12 @@ module Vagrant
line = "(unknown)"
if e.backtrace && e.backtrace[0]
line = e.backtrace[0].split(":")[1]
e.backtrace[0].split(":").each do |part|
if part =~ /\d+/
line = part.to_i
break
end
end
end
# Report the generic exception

View File

@ -832,7 +832,7 @@ module Vagrant
# This creates the local data directory and show an error if it
# couldn't properly be created.
def setup_local_data_path
def setup_local_data_path(force=false)
if @local_data_path.nil?
@logger.warn("No local data path is set. Local data cannot be stored.")
return
@ -847,6 +847,9 @@ module Vagrant
upgrade_v1_dotfile(@local_data_path)
end
# If we don't have a root path, we don't setup anything
return if !force && root_path.nil?
begin
@logger.debug("Creating: #{@local_data_path}")
FileUtils.mkdir_p(@local_data_path)
@ -965,7 +968,7 @@ module Vagrant
# Now, we create the actual local data directory. This should succeed
# this time since we renamed the old conflicting V1.
setup_local_data_path
setup_local_data_path(true)
if json_data["active"]
@logger.debug("Upgrading to V2 style for each active VM")

View File

@ -108,14 +108,6 @@ module Vagrant
error_key(:active_machine_with_different_provider)
end
class AnsibleFailed < VagrantError
error_key(:ansible_failed)
end
class AnsiblePlaybookAppNotFound < VagrantError
error_key(:ansible_playbook_app_not_found)
end
class BatchMultiError < VagrantError
error_key(:batch_multi_error)
end
@ -248,6 +240,10 @@ module Vagrant
error_key(:bundler_error)
end
class CantReadMACAddresses < VagrantError
error_key(:cant_read_mac_addresses)
end
class CapabilityHostExplicitNotDetected < VagrantError
error_key(:capability_host_explicit_not_detected)
end
@ -348,6 +344,10 @@ module Vagrant
error_key(:downloader_interrupted)
end
class EnvInval < VagrantError
error_key(:env_inval)
end
class EnvironmentNonExistentCWD < VagrantError
error_key(:environment_non_existent_cwd)
end
@ -408,8 +408,8 @@ module Vagrant
error_key(:linux_nfs_mount_failed)
end
class LinuxRDesktopNotFound < VagrantError
error_key(:linux_rdesktop_not_found)
class LinuxRDPClientNotFound < VagrantError
error_key(:linux_rdp_client_not_found)
end
class LocalDataDirectoryNotAccessible < VagrantError
@ -524,6 +524,10 @@ module Vagrant
error_key(:provider_cant_install)
end
class ProviderChecksumMismatch < VagrantError
error_key(:provider_checksum_mismatch)
end
class ProviderInstallFailed < VagrantError
error_key(:provider_install_failed)
end

View File

@ -116,6 +116,9 @@ module Vagrant
# XXX: This is temporary. This will be removed very soon.
if base
@id = name
# For base setups, we don't want to insert the key
@config.ssh.insert_key = false
else
reload
end
@ -141,6 +144,10 @@ module Vagrant
if state.id == MachineState::NOT_CREATED_ID
self.id = nil
end
# Output a bunch of information about this machine in
# machine-readable format in case someone is listening.
@ui.machine("metadata", "provider", provider_name)
end
# This calls an action on the provider. The provider may or may not
@ -188,7 +195,10 @@ module Vagrant
end
# Call the action
action_raw(name, callable, extra_env)
ui.machine("action", name.to_s, "start")
action_result = action_raw(name, callable, extra_env)
ui.machine("action", name.to_s, "end")
action_result
end
rescue Errors::EnvironmentLockedError
raise Errors::MachineActionLockedError,
@ -436,6 +446,7 @@ module Vagrant
# We also set some fields that are purely controlled by Varant
info[:forward_agent] = @config.ssh.forward_agent
info[:forward_x11] = @config.ssh.forward_x11
info[:forward_env] = @config.ssh.forward_env
info[:ssh_command] = @config.ssh.ssh_command if @config.ssh.ssh_command

View File

@ -78,7 +78,7 @@ module Vagrant
@machines.delete(entry.id)
unlocked_save
# Release acccess on this machine
# Release access on this machine
unlocked_release(entry.id)
end
end

View File

@ -133,8 +133,17 @@ module Vagrant
# machine in that environment. We silence warnings here because
# Vagrantfiles often have constants, so people would otherwise
# constantly (heh) get "already initialized constant" warnings.
begin
env = entry.vagrant_env(
@env.home_path, ui_class: @env.ui_class)
rescue Vagrant::Errors::EnvironmentNonExistentCWD
# This means that this environment working directory
# no longer exists, so delete this entry.
entry = @env.machine_index.get(name.to_s)
@env.machine_index.delete(entry) if entry
raise
end
next env.machine(entry.name.to_sym, entry.provider.to_sym)
end

View File

@ -104,8 +104,8 @@ module Vagrant
end
[:detail, :warn, :error, :info, :output, :success].each do |method|
define_method(method) do |message, *opts|
machine("ui", method.to_s, message)
define_method(method) do |message, *args, **opts|
machine("ui", method.to_s, message, *args, **opts)
end
end
@ -123,9 +123,12 @@ module Vagrant
data[i].gsub!("\r", "\\r")
end
# Avoid locks in a trap context introduced from Ruby 2.0
Thread.new do
@lock.synchronize do
safe_puts("#{Time.now.utc.to_i},#{target},#{type},#{data.join(",")}")
end
end.join
end
end
@ -156,7 +159,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.windows?
# Setup the options so that the new line is suppressed
opts ||= {}
@ -277,6 +280,9 @@ module Vagrant
opts[:bold] = #{method.inspect} != :detail && \
#{method.inspect} != :ask
end
if !opts.key?(:target)
opts[:target] = @prefix
end
@ui.#{method}(format_message(#{method.inspect}, message, **opts), *args, **opts)
end
CODE

View File

@ -138,11 +138,14 @@ module Vagrant
# If we already retried, raise it.
raise if retried
@logger.error("Exit code: #{e.extra_data[:code]}")
# If its any error other than 33, it is an error.
raise if e.extra_data[:exit_code].to_i != 33
raise if e.extra_data[:code].to_i != 33
# Exit code 33 means that the server doesn't support ranges.
# In this case, try again without resume.
@logger.error("Error is server doesn't support byte ranges. Retrying from scratch.")
@continue = false
retried = true
retry

View File

@ -10,10 +10,17 @@ module Vagrant
class Platform
class << self
def cygwin?
# Installer detects Cygwin
return true if ENV["VAGRANT_DETECTED_OS"] &&
ENV["VAGRANT_DETECTED_OS"].downcase.include?("cygwin")
platform.include?("cygwin")
# Ruby running in Cygwin
return true if platform.include?("cygwin")
# Heuristic. If the path contains Cygwin, we just assume we're
# in Cygwin. It is generally a safe bet.
path = ENV["PATH"] || ""
return path.include?("cygwin")
end
[:darwin, :bsd, :freebsd, :linux, :solaris].each do |type|
@ -45,10 +52,32 @@ module Vagrant
# detect-if-running-with-administrator-privileges-under-windows-xp
begin
Win32::Registry::HKEY_USERS.open("S-1-5-19") {}
return true
rescue Win32::Registry::Error
return false
end
# If we made it this far then we try a fallback approach
# since the above doesn't seem to be bullet proof. See GH-5616
(`reg query HKU\\S-1-5-19 2>&1` =~ /ERROR/).nil?
end
# Checks if the user running Vagrant on Windows is a member of the
# "Hyper-V Administrators" group.
#
# From: https://support.microsoft.com/en-us/kb/243330
# SID: S-1-5-32-578
# Name: BUILTIN\Hyper-V Administrators
#
# @return [Boolean]
def windows_hyperv_admin?
begin
username = ENV["USERNAME"]
process = Subprocess.execute("net", "localgroup", "Hyper-V Administrators")
output = process.stdout.chomp
return output.include?(username)
rescue Errors::CommandUnavailableWindows
return false
end
end
# This takes any path and converts it from a Windows path to a
@ -114,6 +143,14 @@ module Vagrant
path = Pathname.new(File.expand_path(path))
if path.exist? && !fs_case_sensitive?
# If the path contains a Windows short path, then we attempt to
# expand. The require below is embedded here since it requires
# windows to work.
if windows? && path.to_s =~ /~\d(\/|\\)/
require_relative "windows_path"
path = Pathname.new(WindowsPath.longname(path.to_s))
end
# Build up all the parts of the path
original = []
while !path.root?

View File

@ -0,0 +1,45 @@
module Vagrant
module Util
module Presence
extend self
# Determines if the given object is "present". A String is considered
# present if the stripped contents are not empty. An Array/Hash is
# considered present if they have a length of more than 1. "true" is
# always present and `false` and `nil` are always not present. Any other
# object is considered to be present.
#
# @return [true, false]
def present?(obj)
case obj
when String
!obj.strip.empty?
when Symbol
!obj.to_s.strip.empty?
when Array
!obj.compact.empty?
when Hash
!obj.empty?
when TrueClass, FalseClass
obj
when NilClass
false
when Object
true
end
end
# Returns the presence of the object. If the object is {present?}, it is
# returned. Otherwise `false` is returned.
#
# @return [Object, false]
def presence(obj)
if present?(obj)
obj
else
false
end
end
end
end
end

View File

@ -0,0 +1,14 @@
module Vagrant
module Util
class SafeEnv
# This yields an environment hash to change and catches any issues
# while changing the environment variables and raises a helpful error
# to end users.
def self.change_env
yield ENV
rescue Errno::EINVAL
raise Errors::EnvInval
end
end
end
end

View File

@ -138,6 +138,10 @@ module Vagrant
command_options += ["-o", "ProxyCommand=#{ssh_info[:proxy_command]}"]
end
if ssh_info[:forward_env]
command_options += ["-o", "SendEnv=#{ssh_info[:forward_env].join(" ")}"]
end
# Configurables -- extra_args should always be last due to the way the
# ssh args parser works. e.g. if the user wants to use the -t option,
# any shell command(s) she'd like to run on the remote server would
@ -172,6 +176,14 @@ module Vagrant
LOGGER.info("Executing SSH in subprocess: #{ssh} #{command_options.inspect}")
process = ChildProcess.build(ssh, *command_options)
process.io.inherit!
# Forward configured environment variables.
if ssh_info[:forward_env]
ssh_info[:forward_env].each do |key|
process.environment[key] = ENV[key]
end
end
process.start
process.wait
return process.exit_code

View File

@ -0,0 +1,38 @@
require "fiddle/import"
module Vagrant
module Util
module WindowsPath
module API
extend Fiddle::Importer
dlload 'kernel32.dll'
extern("int GetLongPathNameA(char*, char*, int)", :stdcall)
end
# Converts a Windows shortname to a long name. This only works
# for ASCII paths currently and doesn't use the wide character
# support.
def self.longname(name)
# We loop over the API call in case we didn't allocate enough
# buffer space. In general it is usually enough.
bufferlen = 250
buffer = nil
while true
buffer = ' ' * bufferlen
len = API.GetLongPathNameA(name.to_s, buffer, buffer.size)
if bufferlen < len
# If the length returned is larger than our buffer length,
# it is the API telling us it needs more space. Allocate it
# and retry.
bufferlen = len
continue
end
break
end
return buffer.rstrip.chomp("\0")
end
end
end
end

View File

@ -1,9 +1,13 @@
require 'optparse'
require_relative 'download_mixins'
module VagrantPlugins
module CommandBox
module Command
class Add < Vagrant.plugin("2", :command)
include DownloadMixins
def execute
options = {}
@ -21,22 +25,7 @@ module VagrantPlugins
options[:force] = f
end
o.on("--insecure", "Do not validate SSL certificates") do |i|
options[:insecure] = i
end
o.on("--cacert FILE", String, "CA certificate for SSL download") do |c|
options[:ca_cert] = c
end
o.on("--capath DIR", String, "CA certificate directory for SSL download") do |c|
options[:ca_path] = c
end
o.on("--cert FILE", String,
"A client SSL cert, if needed") do |c|
options[:client_cert] = c
end
build_download_options(o, options)
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
@ -97,7 +86,7 @@ module VagrantPlugins
box_force: options[:force],
box_download_ca_cert: options[:ca_cert],
box_download_ca_path: options[:ca_path],
box_download_client_cert: options[:client_cert],
box_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"),

View File

@ -0,0 +1,29 @@
module VagrantPlugins
module CommandBox
module DownloadMixins
# This adds common download command line flags to the given
# OptionParser, storing the result in the `options` dictionary.
#
# @param [OptionParser] parser
# @param [Hash] options
def build_download_options(parser, options)
# Add the options
parser.on("--insecure", "Do not validate SSL certificates") do |i|
options[:insecure] = i
end
parser.on("--cacert FILE", String, "CA certificate for SSL download") do |c|
options[:ca_cert] = c
end
parser.on("--capath DIR", String, "CA certificate directory for SSL download") do |c|
options[:ca_path] = c
end
parser.on("--cert FILE", String, "A client SSL cert, if needed") do |c|
options[:client_cert] = c
end
end
end
end
end

View File

@ -1,11 +1,16 @@
require 'optparse'
require_relative 'download_mixins'
module VagrantPlugins
module CommandBox
module Command
class Outdated < Vagrant.plugin("2", :command)
include DownloadMixins
def execute
options = {}
download_options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant box outdated [options]"
@ -20,6 +25,8 @@ module VagrantPlugins
o.on("--global", "Check all boxes installed") do |g|
options[:global] = g
end
build_download_options(o, download_options)
end
argv = parse_options(opts)
@ -27,7 +34,7 @@ module VagrantPlugins
# If we're checking the boxes globally, then do that.
if options[:global]
outdated_global
outdated_global(download_options)
return 0
end
@ -37,11 +44,11 @@ module VagrantPlugins
box_outdated_refresh: true,
box_outdated_success_ui: true,
machine: machine,
})
}.merge(download_options))
end
end
def outdated_global
def outdated_global(download_options)
boxes = {}
@env.boxes.all.reverse.each do |name, version, provider|
next if boxes[name]
@ -58,8 +65,8 @@ module VagrantPlugins
md = nil
begin
md = box.load_metadata
rescue Vagrant::Errors::DownloaderError => e
md = box.load_metadata(download_options)
rescue Vagrant::Errors::BoxMetadataDownloadError => e
@env.ui.error(I18n.t(
"vagrant.box_outdated_metadata_error",
name: box.name,

View File

@ -1,11 +1,16 @@
require 'optparse'
require_relative 'download_mixins'
module VagrantPlugins
module CommandBox
module Command
class Update < Vagrant.plugin("2", :command)
include DownloadMixins
def execute
options = {}
download_options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant box update [options]"
@ -27,21 +32,23 @@ module VagrantPlugins
o.on("--provider PROVIDER", String, "Update box with specific provider") do |p|
options[:provider] = p.to_sym
end
build_download_options(o, download_options)
end
argv = parse_options(opts)
return if !argv
if options[:box]
update_specific(options[:box], options[:provider])
update_specific(options[:box], options[:provider], download_options)
else
update_vms(argv, options[:provider])
update_vms(argv, options[:provider], download_options)
end
0
end
def update_specific(name, provider)
def update_specific(name, provider, download_options)
boxes = {}
@env.boxes.all.each do |n, v, p|
boxes[n] ||= {}
@ -74,11 +81,11 @@ module VagrantPlugins
to_update.each do |n, p, v|
box = @env.boxes.find(n, p, v)
box_update(box, "> #{v}", @env.ui)
box_update(box, "> #{v}", @env.ui, download_options)
end
end
def update_vms(argv, provider)
def update_vms(argv, provider, download_options)
with_target_vms(argv, provider: provider) do |machine|
if !machine.config.vm.box
machine.ui.output(I18n.t(
@ -95,17 +102,25 @@ module VagrantPlugins
box = machine.box
version = machine.config.vm.box_version
box_update(box, version, machine.ui)
# Get download options from machine configuration if not specified
# on the command line.
download_options[:ca_cert] ||= machine.config.vm.box_download_ca_cert
download_options[:ca_path] ||= machine.config.vm.box_download_ca_path
download_options[:client_cert] ||= machine.config.vm.box_download_client_cert
if download_options[:insecure].nil?
download_options[:insecure] = machine.config.vm.box_download_insecure
end
box_update(box, version, machine.ui, download_options)
end
end
def box_update(box, version, ui)
def box_update(box, version, ui, download_options)
ui.output(I18n.t("vagrant.box_update_checking", name: box.name))
ui.detail("Latest installed version: #{box.version}")
ui.detail("Version constraints: #{version}")
ui.detail("Provider: #{box.provider}")
update = box.has_update?(version)
update = box.has_update?(version, download_options: download_options)
if !update
ui.success(I18n.t(
"vagrant.box_up_to_date_single",
@ -124,6 +139,10 @@ module VagrantPlugins
box_provider: update[2].name,
box_version: update[1].version,
ui: ui,
box_client_cert: download_options[:client_cert],
box_download_ca_cert: download_options[:ca_cert],
box_download_ca_path: download_options[:ca_path],
box_download_insecure: download_options[:insecure]
})
end
end

View File

@ -1,4 +1,5 @@
require "rest_client"
require "vagrant/util/downloader"
module VagrantPlugins
module LoginCommand
@ -45,8 +46,23 @@ module VagrantPlugins
with_error_handling do
url = "#{Vagrant.server_url}/api/v1/authenticate"
request = { "user" => { "login" => user, "password" => pass } }
response = RestClient.post(
url, JSON.dump(request), content_type: :json)
proxy = nil
proxy ||= ENV["HTTPS_PROXY"] || ENV["https_proxy"]
proxy ||= ENV["HTTP_PROXY"] || ENV["http_proxy"]
response = RestClient::Request.execute(
method: :post,
url: url,
payload: JSON.dump(request),
proxy: proxy,
headers: {
accept: :json,
content_type: :json,
user_agent: Vagrant::Util::Downloader::USER_AGENT,
},
)
data = JSON.load(response.to_s)
data["token"]
end

View File

@ -1,3 +1,4 @@
require "cgi"
require "uri"
require_relative "../client"
@ -5,6 +6,9 @@ require_relative "../client"
module VagrantPlugins
module LoginCommand
class AddAuthentication
VCLOUD = "vagrantcloud.com".freeze
ATLAS = "atlas.hashicorp.com".freeze
def initialize(app, env)
@app = app
end
@ -19,19 +23,26 @@ module VagrantPlugins
env[:box_urls].map! do |url|
u = URI.parse(url)
replace = u.host == server_uri.host
if !replace
# We need this in here for the transition we made from
# Vagrant Cloud to Atlas. This preserves access tokens
# appending to both without leaking access tokens to
# unsavory URLs.
replace = u.host == "vagrantcloud.com" &&
server_uri.host == "atlas.hashicorp.com"
if u.host == VCLOUD && server_uri.host == ATLAS
replace = true
end
end
if replace
u.query ||= ""
u.query += "&" if u.query != ""
u.query += "access_token=#{token}"
q = CGI.parse(u.query || "")
current = q["access_token"]
if current && current.empty?
q["access_token"] = token
end
u.query = URI.encode_www_form(q)
end
u.to_s

View File

@ -3,6 +3,11 @@ module VagrantPlugins
module Command
module MixinInstallOpts
def build_install_opts(o, options)
options[:plugin_sources] = [
"https://rubygems.org",
"http://gems.hashicorp.com",
]
o.on("--entry-point NAME", String,
"The name of the entry point file for loading the plugin.") do |entry_point|
options[:entry_point] = entry_point
@ -17,9 +22,13 @@ module VagrantPlugins
puts
end
o.on("--plugin-clean-sources",
"Remove all plugin sources defined so far (including defaults)") do |clean|
options[:plugin_sources] = [] if clean
end
o.on("--plugin-source PLUGIN_SOURCE", String,
"Add a RubyGems repository source") do |plugin_source|
options[:plugin_sources] ||= []
options[:plugin_sources] << plugin_source
end

View File

@ -0,0 +1,90 @@
require "vagrant/util/presence"
require "optparse"
module VagrantPlugins
module CommandPort
class Command < Vagrant.plugin("2", :command)
include Vagrant::Util::Presence
def self.synopsis
"displays information about guest port mappings"
end
def execute
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant port [options] [name]"
o.separator ""
o.separator "Options:"
o.separator ""
o.on("--guest PORT", "Output the host port that maps to the given guest port") do |port|
options[:guest] = port
end
o.on("--machine-readable", "Display machine-readable output")
end
# Parse the options
argv = parse_options(opts)
return if !argv
with_target_vms(argv, single_target: true) do |vm|
vm.action_raw(:config_validate,
Vagrant::Action::Builtin::ConfigValidate)
if !vm.provider.capability?(:forwarded_ports)
@env.ui.error(I18n.t("port_command.missing_capability",
provider: vm.provider_name,
))
return 1
end
ports = vm.provider.capability(:forwarded_ports)
if !present?(ports)
@env.ui.info(I18n.t("port_command.empty_ports"))
return 0
end
if present?(options[:guest])
return print_single(vm, ports, options[:guest])
else
return print_all(vm, ports)
end
end
end
private
# Print all the guest <=> host port mappings.
# @return [0] the exit code
def print_all(vm, ports)
@env.ui.info(I18n.t("port_command.details"))
@env.ui.info("")
ports.each do |host, guest|
@env.ui.info("#{guest.to_s.rjust(6)} (guest) => #{host} (host)")
@env.ui.machine("forwarded_port", guest, host, target: vm.name.to_s)
end
return 0
end
# Print the host mapping that matches the given guest target.
# @return [0,1] the exit code
def print_single(vm, ports, target)
map = ports.find { |_, guest| "#{guest}" == "#{target}" }
if !present?(map)
@env.ui.error(I18n.t("port_command.no_matching_port",
port: target,
))
return 1
end
@env.ui.info("#{map[0]}")
return 0
end
end
end
end

View File

@ -0,0 +1,20 @@
en:
port_command:
details: |-
The forwarded ports for the machine are listed below. Please note that
these values may differ from values configured in the Vagrantfile if the
provider supports automatic port collision detection and resolution.
empty_ports: |-
The provider reported there are no forwarded ports for this virtual
machine. This can be caused if there are no ports specified in the
Vagrantfile or if the virtual machine is not currently running. Please
check that the virtual machine is running and try again.
missing_capability: |-
The %{provider} provider does not support listing forwarded ports. This is
most likely a limitation of the provider and not a bug in Vagrant. If you
believe this is a bug in Vagrant, please search existing issues before
opening a new one.
no_matching_port: |-
The guest is not currently mapping port %{port} to the host machine. Is
the port configured in the Vagrantfile? You may need to run `vagrant reload`
if changes were made to the port configuration in the Vagrantfile.

View File

@ -0,0 +1,27 @@
require "vagrant"
module VagrantPlugins
module CommandPort
class Plugin < Vagrant.plugin("2")
name "port command"
description <<-DESC
The `port` command displays guest port mappings.
DESC
command("port") do
require_relative "command"
self.init!
Command
end
protected
def self.init!
return if defined?(@_init)
I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
I18n.reload!
@_init = true
end
end
end
end

View File

@ -0,0 +1,119 @@
require "optparse"
require "vagrant/util/powershell"
require_relative "../../communicators/winrm/helper"
module VagrantPlugins
module CommandPS
class Command < Vagrant.plugin("2", :command)
def self.synopsis
"connects to machine via powershell remoting"
end
def execute
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant powershell [-- extra powershell args]"
o.separator ""
o.separator "Options:"
o.separator ""
o.on("-c", "--command COMMAND", "Execute a powershell command directly") do |c|
options[:command] = c
end
end
# Parse out the extra args to send to the ps session, which
# is everything after the "--"
split_index = @argv.index("--")
if split_index
options[:extra_args] = @argv.drop(split_index + 1)
@argv = @argv.take(split_index)
end
# Parse the options and return if we don't have any target.
argv = parse_options(opts)
return if !argv
# Check if the host even supports ps remoting
raise Errors::HostUnsupported if !@env.host.capability?(:ps_client)
# Execute ps session if we can
with_target_vms(argv, single_target: true) do |machine|
if !machine.communicate.ready?
raise Vagrant::Errors::VMNotCreatedError
end
if machine.config.vm.communicator != :winrm
raise VagrantPlugins::CommunicatorWinRM::Errors::WinRMNotReady
end
if !options[:command].nil?
out_code = machine.communicate.execute(options[:command].dup) do |type,data|
machine.ui.detail(data) if type == :stdout
end
if out_code == 0
machine.ui.success("Command: #{options[:command]} executed succesfully with output code #{out_code}.")
end
next
end
ps_info = VagrantPlugins::CommunicatorWinRM::Helper.winrm_info(machine)
ps_info[:username] = machine.config.winrm.username
ps_info[:password] = machine.config.winrm.password
# Extra arguments if we have any
ps_info[:extra_args] = options[:extra_args]
result = ready_ps_remoting_for(machine, ps_info)
machine.ui.detail(
"Creating powershell session to #{ps_info[:host]}:#{ps_info[:port]}")
machine.ui.detail("Username: #{ps_info[:username]}")
begin
@env.host.capability(:ps_client, ps_info)
ensure
if !result["PreviousTrustedHosts"].nil?
reset_ps_remoting_for(machine, ps_info)
end
end
end
end
def ready_ps_remoting_for(machine, ps_info)
machine.ui.output(I18n.t("vagrant_ps.detecting"))
script_path = File.expand_path("../scripts/enable_psremoting.ps1", __FILE__)
args = []
args << "-hostname" << ps_info[:host]
args << "-port" << ps_info[:port].to_s
args << "-username" << ps_info[:username]
args << "-password" << ps_info[:password]
result = Vagrant::Util::PowerShell.execute(script_path, *args)
if result.exit_code != 0
raise Errors::PowerShellError,
script: script_path,
stderr: result.stderr
end
result_output = JSON.parse(result.stdout)
raise Errors::PSRemotingUndetected if !result_output["Success"]
result_output
end
def reset_ps_remoting_for(machine, ps_info)
machine.ui.output(I18n.t("vagrant_ps.reseting"))
script_path = File.expand_path("../scripts/reset_trustedhosts.ps1", __FILE__)
args = []
args << "-hostname" << ps_info[:host]
result = Vagrant::Util::PowerShell.execute(script_path, *args)
if result.exit_code != 0
raise Errors::PowerShellError,
script: script_path,
stderr: result.stderr
end
end
end
end
end

View File

@ -0,0 +1,22 @@
module VagrantPlugins
module CommandPS
module Errors
# A convenient superclass for all our errors.
class PSCommandError < Vagrant::Errors::VagrantError
error_namespace("vagrant_ps.errors")
end
class HostUnsupported < PSCommandError
error_key(:host_unsupported)
end
class PSRemotingUndetected < PSCommandError
error_key(:ps_remoting_undetected)
end
class PowerShellError < PSCommandError
error_key(:powershell_error)
end
end
end
end

View File

@ -0,0 +1,30 @@
require "vagrant"
module VagrantPlugins
module CommandPS
autoload :Errors, File.expand_path("../errors", __FILE__)
class Plugin < Vagrant.plugin("2")
name "powershell command"
description <<-DESC
The powershell command opens a remote PowerShell session to the
machine if it supports powershell remoting.
DESC
command("powershell") do
require_relative "command"
init!
Command
end
protected
def self.init!
return if defined?(@_init)
I18n.load_path << File.expand_path("templates/locales/command_ps.yml", Vagrant.source_root)
I18n.reload!
@_init = true
end
end
end
end

View File

@ -0,0 +1,60 @@
Param(
[string]$hostname,
[string]$port,
[string]$username,
[string]$password
)
# If we are in this script, we know basic winrm is working
# If the user is not using a domain acount and chances are
# they are not, PS Remoting will not work if the guest is not
# listed in the trusted hosts.
$encrypted_password = ConvertTo-SecureString $password -asplaintext -force
$creds = New-Object System.Management.Automation.PSCredential (
"$hostname\\$username", $encrypted_password)
$result = @{
Success = $false
PreviousTrustedHosts = $null
}
try {
invoke-command -computername $hostname `
-Credential $creds `
-Port $port `
-ScriptBlock {} `
-ErrorAction Stop
$result.Success = $true
} catch{}
if(!$result.Success) {
$newHosts = @()
$result.PreviousTrustedHosts=(
Get-Item "wsman:\localhost\client\trustedhosts").Value
$hostArray=$result.PreviousTrustedHosts.Split(",").Trim()
if($hostArray -contains "*") {
$result.PreviousTrustedHosts = $null
}
elseif(!($hostArray -contains $hostname)) {
$strNewHosts = $hostname
if($result.PreviousTrustedHosts.Length -gt 0){
$strNewHosts = $result.PreviousTrustedHosts + "," + $strNewHosts
}
Set-Item -Path "wsman:\localhost\client\trustedhosts" `
-Value $strNewHosts -Force
try {
invoke-command -computername $hostname `
-Credential $creds `
-Port $port `
-ScriptBlock {} `
-ErrorAction Stop
$result.Success = $true
} catch{
Set-Item -Path "wsman:\localhost\client\trustedhosts" `
-Value $result.PreviousTrustedHosts -Force
$result.PreviousTrustedHosts = $null
}
}
}
Write-Output $(ConvertTo-Json $result)

View File

@ -0,0 +1,12 @@
Param(
[string]$hostname
)
$trustedHosts = (
Get-Item "wsman:\localhost\client\trustedhosts").Value.Replace(
$hostname, '')
$trustedHosts = $trustedHosts.Replace(",,","")
if($trustedHosts.EndsWith(",")){
$trustedHosts = $trustedHosts.Substring(0,$trustedHosts.length-1)
}
Set-Item "wsman:\localhost\client\trustedhosts" -Value $trustedHosts -Force

View File

@ -15,7 +15,7 @@ module VagrantPlugins
o.banner = "Usage: vagrant provision [vm-name] [--provision-with x,y,z]"
o.on("--provision-with x,y,z", Array,
"Enable only certain provisioners, by type.") do |list|
"Enable only certain provisioners, by type or by name.") do |list|
options[:provision_types] = list.map { |type| type.to_sym }
end
end

View File

@ -30,7 +30,7 @@ module VagrantPlugins
return if !argv
# Validate the provisioners
validate_provisioner_flags!(options)
validate_provisioner_flags!(options, argv)
@logger.debug("'reload' each target VM...")
machines = []

View File

@ -41,12 +41,15 @@ module VagrantPlugins
forward_agent: ssh_info[:forward_agent],
forward_x11: ssh_info[:forward_x11],
proxy_command: ssh_info[:proxy_command],
ssh_command: ssh_info[:ssh_command]
ssh_command: ssh_info[:ssh_command],
forward_env: ssh_info[:forward_env],
}
# Render the template and output directly to STDOUT
template = "commands/ssh_config/config"
safe_puts(Vagrant::Util::TemplateRenderer.render(template, variables))
config = Vagrant::Util::TemplateRenderer.render(template, variables)
machine.ui.machine("ssh-config", config)
safe_puts(config)
safe_puts
end

View File

@ -55,7 +55,7 @@ module VagrantPlugins
return if !argv
# Validate the provisioners
validate_provisioner_flags!(options)
validate_provisioner_flags!(options, argv)
# Go over each VM and bring it up
@logger.debug("'Up' each target VM...")

View File

@ -1,3 +1,5 @@
require "set"
module VagrantPlugins
module CommandUp
module StartMixins
@ -17,7 +19,7 @@ module VagrantPlugins
end
parser.on("--provision-with x,y,z", Array,
"Enable only certain provisioners, by type.") do |list|
"Enable only certain provisioners, by type or by name.") do |list|
options[:provision_types] = list.map { |type| type.to_sym }
options[:provision_enabled] = true
options[:provision_ignore_sentinel] = true
@ -26,7 +28,19 @@ module VagrantPlugins
# This validates the provisioner flags and raises an exception
# if there are invalid ones.
def validate_provisioner_flags!(options)
def validate_provisioner_flags!(options, argv)
if options[:provision_types].nil?
return
end
provisioner_names = Set.new
with_target_vms(argv) do |machine|
machine.config.vm.provisioners.map(&:name).each do |name|
provisioner_names.add(name)
end
end
if (provisioner_names & options[:provision_types]).empty?
(options[:provision_types] || []).each do |type|
klass = Vagrant.plugin("2").manager.provisioners[type]
if !klass
@ -38,3 +52,4 @@ module VagrantPlugins
end
end
end
end

View File

@ -333,6 +333,7 @@ module VagrantPlugins
auth_methods: auth_methods,
config: false,
forward_agent: ssh_info[:forward_agent],
send_env: ssh_info[:forward_env],
keys: ssh_info[:private_key_path],
keys_only: true,
paranoid: false,
@ -420,7 +421,7 @@ module VagrantPlugins
rescue Errno::EHOSTDOWN
# This is raised if we get an ICMP DestinationUnknown error.
raise Vagrant::Errors::SSHHostDown
rescue Errno::EHOSTUNREACH
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
# This is raised if we can't work out how to route traffic.
raise Vagrant::Errors::SSHNoRoute
rescue Net::SSH::Exception => e
@ -611,6 +612,7 @@ module VagrantPlugins
end
data = pty_stdout[/.*#{PTY_DELIM_START}(.*?)#{PTY_DELIM_END}/m, 1]
data ||= ""
@logger.debug("PTY stdout parsed: #{data}")
yield :stdout, data if block_given?
end

View File

@ -43,6 +43,7 @@ module VagrantPlugins
# Got it! Let the user know what we're connecting to.
@machine.ui.detail("WinRM address: #{shell.host}:#{shell.port}")
@machine.ui.detail("WinRM username: #{shell.username}")
@machine.ui.detail("WinRM execution_time_limit: #{shell.execution_time_limit}")
@machine.ui.detail("WinRM transport: #{shell.config.transport}")
last_message = nil
@ -136,10 +137,11 @@ module VagrantPlugins
error_key: nil, # use the error_class message key
good_exit: 0,
shell: :powershell,
interactive: false,
}.merge(opts || {})
opts[:good_exit] = Array(opts[:good_exit])
command = wrap_in_scheduled_task(command) if opts[:elevated]
command = wrap_in_scheduled_task(command, opts[:interactive]) if opts[:elevated]
output = shell.send(opts[:shell], command, &block)
execution_output(output, opts)
end
@ -193,9 +195,11 @@ module VagrantPlugins
# in place.
#
# @return The wrapper command to execute
def wrap_in_scheduled_task(command)
def wrap_in_scheduled_task(command, interactive)
path = File.expand_path("../scripts/elevated_shell.ps1", __FILE__)
script = Vagrant::Util::TemplateRenderer.render(path)
script = Vagrant::Util::TemplateRenderer.render(path, options: {
interactive: interactive,
})
guest_script_path = "c:/tmp/vagrant-elevated-shell.ps1"
file = Tempfile.new(["vagrant-elevated-shell", "ps1"])
begin
@ -208,14 +212,16 @@ module VagrantPlugins
file.unlink
end
# convert to double byte unicode string then base64 encode
# just like PowerShell -EncodedCommand expects
# Convert to double byte unicode string then base64 encode
# just like PowerShell -EncodedCommand expects.
# Suppress the progress stream from leaking to stderr.
wrapped_encoded_command = Base64.strict_encode64(
"#{command}; exit $LASTEXITCODE".encode('UTF-16LE', 'UTF-8'))
"$ProgressPreference='SilentlyContinue'; #{command}; exit $LASTEXITCODE".encode('UTF-16LE', 'UTF-8'))
"powershell -executionpolicy bypass -file \"#{guest_script_path}\" " +
"-username \"#{shell.username}\" -password \"#{shell.password}\" " +
"-encoded_command \"#{wrapped_encoded_command}\""
"powershell -executionpolicy bypass -file '#{guest_script_path}' " +
"-username '#{shell.username}' -password '#{shell.password}' " +
"-encoded_command '#{wrapped_encoded_command}' " +
"-execution_time_limit '#{shell.execution_time_limit}'"
end
# Handles the raw WinRM shell result and converts it to a

View File

@ -11,6 +11,7 @@ module VagrantPlugins
attr_accessor :timeout
attr_accessor :transport
attr_accessor :ssl_peer_verification
attr_accessor :execution_time_limit
def initialize
@username = UNSET_VALUE
@ -23,6 +24,7 @@ module VagrantPlugins
@timeout = UNSET_VALUE
@transport = UNSET_VALUE
@ssl_peer_verification = UNSET_VALUE
@execution_time_limit = UNSET_VALUE
end
def finalize!
@ -37,6 +39,7 @@ module VagrantPlugins
@retry_delay = 2 if @retry_delay == UNSET_VALUE
@timeout = 1800 if @timeout == UNSET_VALUE
@ssl_peer_verification = true if @ssl_peer_verification == UNSET_VALUE
@execution_time_limit = "PT2H" if @execution_time_limit == UNSET_VALUE
end
def validate(machine)
@ -49,6 +52,7 @@ module VagrantPlugins
errors << "winrm.max_tries cannot be nil." if @max_tries.nil?
errors << "winrm.retry_delay cannot be nil." if @max_tries.nil?
errors << "winrm.timeout cannot be nil." if @timeout.nil?
errors << "winrm.execution_time_limit cannot be nil." if @execution_time_limit.nil?
unless @ssl_peer_verification == true || @ssl_peer_verification == false
errors << "winrm.ssl_peer_verification must be a boolean."
end

View File

@ -1,5 +1,17 @@
param([String]$username, [String]$password, [String]$encoded_command)
param([String]$username, [String]$password, [String]$encoded_command, [String]$execution_time_limit)
# Try to get the Schedule.Service object. If it fails, we are probably
# on an older version of Windows. On old versions, we can just execute
# directly since priv. escalation isn't a thing.
$schedule = $null
Try {
$schedule = New-Object -ComObject "Schedule.Service"
} Catch [System.Management.Automation.PSArgumentException] {
powershell.exe -EncodedCommand $encoded_command
exit $LASTEXITCODE
}
$ProgressPreference = "SilentlyContinue"
$task_name = "WinRM_Elevated_Shell"
$out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell.log"
@ -13,7 +25,7 @@ $task_xml = @'
<Principals>
<Principal id="Author">
<UserId>{username}</UserId>
<LogonType>Password</LogonType>
<LogonType><%= options[:interactive] ? 'InteractiveTokenOrPassword' : 'Password' %></LogonType>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
@ -33,7 +45,7 @@ $task_xml = @'
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT2H</ExecutionTimeLimit>
<ExecutionTimeLimit>{execution_time_limit}</ExecutionTimeLimit>
<Priority>4</Priority>
</Settings>
<Actions Context="Author">
@ -49,13 +61,13 @@ $arguments = "/c powershell.exe -EncodedCommand $encoded_command &gt; $out_file
$task_xml = $task_xml.Replace("{arguments}", $arguments)
$task_xml = $task_xml.Replace("{username}", $username)
$task_xml = $task_xml.Replace("{execution_time_limit}", $execution_time_limit)
$schedule = New-Object -ComObject "Schedule.Service"
$schedule.Connect()
$task = $schedule.NewTask($null)
$task.XmlText = $task_xml
$folder = $schedule.GetFolder("\")
$folder.RegisterTaskDefinition($task_name, $task, 6, $username, $password, 1, $null) | Out-Null
$folder.RegisterTaskDefinition($task_name, $task, 6, $username, $password, <%= options[:interactive] ? 3 : 1 %>, $null) | Out-Null
$registered_task = $folder.GetTask("\$task_name")
$registered_task.Run($null) | Out-Null

View File

@ -9,7 +9,7 @@ Vagrant::Util::SilenceWarnings.silence! do
require "winrm"
end
require "winrm-fs/file_manager"
require "winrm-fs"
module VagrantPlugins
module CommunicatorWinRM
@ -23,6 +23,7 @@ module VagrantPlugins
HTTPClient::KeepAliveDisconnected,
WinRM::WinRMHTTPTransportError,
WinRM::WinRMAuthorizationError,
WinRM::WinRMWSManFault,
Errno::EACCES,
Errno::EADDRINUSE,
Errno::ECONNREFUSED,
@ -37,6 +38,7 @@ module VagrantPlugins
attr_reader :port
attr_reader :username
attr_reader :password
attr_reader :execution_time_limit
attr_reader :config
def initialize(host, port, config)
@ -47,12 +49,15 @@ module VagrantPlugins
@port = port
@username = config.username
@password = config.password
@execution_time_limit = config.execution_time_limit
@config = config
end
def powershell(command, &block)
# ensure an exit code
# Suppress the progress stream from leaking to stderr
command = "$ProgressPreference='SilentlyContinue';\r\n" + command
command << "\r\n"
# Ensure an exit code
command << "if ($?) { exit 0 } else { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }"
execute_shell(command, :powershell, &block)
end

View File

@ -27,7 +27,7 @@ module VagrantPlugins
machine.communicate.upload(temp.path, "/tmp/vagrant_network")
machine.communicate.sudo("mv /tmp/vagrant_network /etc/netctl/#{network[:device]}")
machine.communicate.sudo("ip link set #{network[:device]} down && netctl start #{network[:device]}")
machine.communicate.sudo("ip link set #{network[:device]} down && netctl start #{network[:device]} && netctl enable #{network[:device]}")
end
end
end

View File

@ -6,45 +6,109 @@ module VagrantPlugins
module GuestDarwin
module Cap
class ConfigureNetworks
@@logger = Log4r::Logger.new("vagrant::guest::darwin::configure_networks")
include Vagrant::Util
def self.configure_networks(machine, networks)
# Slightly different than other plugins, using the template to build commands
# rather than templating the files.
if !machine.provider.capability?(:nic_mac_addresses)
raise Vagrant::Errors::CantReadMACAddresses,
provider: machine.provider_name.to_s
end
machine.communicate.sudo("networksetup -detectnewhardware")
machine.communicate.sudo("networksetup -listnetworkserviceorder > /tmp/vagrant.interfaces")
tmpints = File.join(Dir.tmpdir, File.basename("#{machine.id}.interfaces"))
machine.communicate.download("/tmp/vagrant.interfaces",tmpints)
nic_mac_addresses = machine.provider.capability(:nic_mac_addresses)
@@logger.debug("mac addresses: #{nic_mac_addresses.inspect}")
devlist = []
ints = ::IO.read(tmpints)
mac_service_map = create_mac_service_map(machine)
networks.each do |network|
mac_address = nic_mac_addresses[network[:interface]+1]
if mac_address.nil?
@@logger.warn("Could not find mac address for network #{network.inspect}")
next
end
service_name = mac_service_map[mac_address]
if service_name.nil?
@@logger.warn("Could not find network service for mac address #{mac_address}")
next
end
network_type = network[:type].to_sym
if network_type == :static
command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}"
elsif network_type == :dhcp
command = "networksetup -setdhcp \"#{service_name}\""
else
raise "#{network_type} network type is not supported, try static or dhcp"
end
machine.communicate.sudo(command)
end
end
# Creates a hash mapping MAC addresses to network service name
# Example: { "00C100A1B2C3" => "Thunderbolt Ethernet" }
def self.create_mac_service_map(machine)
tmp_ints = File.join(Dir.tmpdir, File.basename("#{machine.id}.interfaces"))
tmp_hw = File.join(Dir.tmpdir, File.basename("#{machine.id}.hardware"))
machine.communicate.tap do |comm|
comm.sudo("networksetup -detectnewhardware")
comm.sudo("networksetup -listnetworkserviceorder > /tmp/vagrant.interfaces")
comm.sudo("networksetup -listallhardwareports > /tmp/vagrant.hardware")
comm.download("/tmp/vagrant.interfaces", tmp_ints)
comm.download("/tmp/vagrant.hardware", tmp_hw)
end
interface_map = {}
ints = ::IO.read(tmp_ints)
ints.split(/\n\n/m).each do |i|
if i.match(/Hardware/) and not i.match(/Ethernet/).nil?
devmap = {}
if i.match(/Hardware/) && i.match(/Ethernet/)
# Ethernet, should be 2 lines,
# (3) Thunderbolt Ethernet
# (Hardware Port: Thunderbolt Ethernet, Device: en1)
# multiline, should match "Thunderbolt Ethernet", "en1"
devicearry = i.match(/\([0-9]+\) (.+)\n.*Device: (.+)\)/m)
devmap[:interface] = devicearry[2]
devmap[:service] = devicearry[1]
devlist << devmap
end
end
File.delete(tmpints)
service = devicearry[1]
interface = devicearry[2]
networks.each do |network|
service_name = devlist[network[:interface]][:service]
if network[:type].to_sym == :static
command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}"
elsif network[:type].to_sym == :dhcp
command = "networksetup -setdhcp \"#{service_name}\""
# Should map interface to service { "en1" => "Thunderbolt Ethernet" }
interface_map[interface] = service
end
end
File.delete(tmp_ints)
mac_service_map = {}
macs = ::IO.read(tmp_hw)
macs.split(/\n\n/m).each do |i|
if i.match(/Hardware/) && i.match(/Ethernet/)
# Ethernet, should be 3 lines,
# Hardware Port: Thunderbolt 1
# Device: en1
# Ethernet Address: a1:b2:c3:d4:e5:f6
# multiline, should match "en1", "00:c1:00:a1:b2:c3"
devicearry = i.match(/Device: (.+)\nEthernet Address: (.+)/m)
interface = devicearry[1]
naked_mac = devicearry[2].gsub(':','').upcase
# Skip hardware ports without MAC (bridges, bluetooth, etc.)
next if naked_mac == "N/A"
if !interface_map[interface]
@@logger.warn("Could not find network service for interface #{interface}")
next
end
machine.communicate.sudo(command)
end
# Should map MAC to service, { "00C100A1B2C3" => "Thunderbolt Ethernet" }
mac_service_map[naked_mac] = interface_map[interface]
end
end
File.delete(tmp_hw)
mac_service_map
end
end
end

View File

@ -0,0 +1,18 @@
module VagrantPlugins
module GuestDebian
module Cap
class SMB
def self.smb_install(machine)
# Deb/Ubuntu require mount.cifs which doesn't come by default.
machine.communicate.tap do |comm|
if !comm.test("test -f /sbin/mount.cifs")
machine.ui.detail(I18n.t("vagrant.guest_deb_installing_smb"))
comm.sudo("apt-get -y update")
comm.sudo("apt-get -y install cifs-utils")
end
end
end
end
end
end
end

View File

@ -2,7 +2,7 @@ module VagrantPlugins
module GuestDebian
class Guest < Vagrant.plugin("2", :guest)
def detect?(machine)
machine.communicate.test("cat /etc/issue | grep 'Debian' | grep -v '8'")
machine.communicate.test("cat /etc/issue | grep 'Debian'")
end
end
end

View File

@ -30,6 +30,11 @@ module VagrantPlugins
require_relative "cap/rsync"
Cap::RSync
end
guest_capability("debian", "smb_install") do
require_relative "cap/smb"
Cap::SMB
end
end
end
end

View File

@ -1,16 +0,0 @@
module VagrantPlugins
module GuestDebian8
module Cap
class Halt
def self.halt(machine)
begin
machine.communicate.sudo("shutdown -h -H")
rescue IOError
# Do nothing, because it probably means the machine shut down
# and SSH connection was lost.
end
end
end
end
end
end

View File

@ -1,21 +0,0 @@
require "vagrant"
module VagrantPlugins
module GuestDebian8
class Plugin < Vagrant.plugin("2")
name "Debian Jessie guest"
description "Debian Jessie guest support."
guest("debian8", "debian") do
require File.expand_path("../guest", __FILE__)
Guest
end
guest_capability("debian8", "halt") do
require_relative "cap/halt"
Cap::Halt
end
end
end
end

View File

@ -48,7 +48,7 @@ module VagrantPlugins
def update_etc_hosts
ip_address = '([0-9]{1,3}\.){3}[0-9]{1,3}'
search = "^(#{ip_address})\\s+#{Regexp.escape(current_hostname)}(\\s.*)?$"
replace = "\\1 #{fqdn} #{short_hostname}"
replace = "\\1 #{fqdn} #{short_hostname} \\3"
expression = ['s', search, replace, 'g'].join('@')
sudo("sed -ri '#{expression}' /etc/hosts")

View File

@ -109,13 +109,23 @@ module VagrantPlugins
# SSH never dies.
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
machine.communicate.sudo(<<-SCRIPT, error_check: true)
cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-#{interface}
machine.communicate.sudo("rm -f /tmp/vagrant-network-entry_#{interface}")
if command -v nmcli &>/dev/null; then
if command -v systemctl &>/dev/null && systemctl -q is-enabled NetworkManager &>/dev/null; then
nmcli c reload #{interface}
elif command -v service &>/dev/null && service NetworkManager status &>/dev/null; then
nmcli c reload #{interface}
fi
fi
/sbin/ifdown #{interface}
/sbin/ifup #{interface}
rm -f /tmp/vagrant-network-entry_#{interface}
SCRIPT
end
end
end
end

View File

@ -4,7 +4,7 @@ module VagrantPlugins
module GuestFedora
class Guest < Vagrant.plugin("2", :guest)
def detect?(machine)
machine.communicate.test("grep 'Fedora release 1[6789]\\|Fedora release 2[0-9]' /etc/redhat-release")
machine.communicate.test("grep 'Fedora release' /etc/redhat-release")
end
end
end

View File

@ -33,10 +33,11 @@ module VagrantPlugins
end
# Emit an upstart event if we can
if machine.communicate.test("test -x /sbin/initctl && test 'upstart' = $(basename $(sudo readlink /proc/1/exe))")
machine.communicate.sudo(
"/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{expanded_guest_path}")
end
machine.communicate.sudo <<-SCRIPT
if command -v /sbin/init &>/dev/null && /sbin/init --version | grep upstart &>/dev/null; then
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT='#{expanded_guest_path}'
fi
SCRIPT
end
end
end

View File

@ -25,16 +25,13 @@ module VagrantPlugins
mount_gid_old = "`id -g #{options[:group]}`"
end
smb_password = Shellwords.shellescape(options[:smb_password])
# If a domain is provided in the username, separate it
username, domain = (options[:smb_username] || '').split('@', 2)
smb_password = options[:smb_password]
options[:mount_options] ||= []
options[:mount_options] << "sec=ntlm"
options[:mount_options] << "username=#{username}"
options[:mount_options] << "password=#{smb_password}"
options[:mount_options] << "domain=#{domain}" if domain
options[:mount_options] << "credentials=/etc/smb_creds_#{name}"
# First mount command uses getent to get the group
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}"
@ -49,6 +46,16 @@ module VagrantPlugins
# Create the guest path if it doesn't exist
machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
# Write the credentials file
machine.communicate.sudo(<<-SCRIPT)
cat <<EOF >/etc/smb_creds_#{name}
username=#{username}
password=#{smb_password}
#{domain ? "domain=#{domain}" : ""}
EOF
chmod 0600 /etc/smb_creds_#{name}
SCRIPT
# Attempt to mount the folder. We retry here a few times because
# it can fail early on.
attempts = 0
@ -86,10 +93,11 @@ module VagrantPlugins
end
# Emit an upstart event if we can
if machine.communicate.test("test -x /sbin/initctl && test 'upstart' = $(basename $(sudo readlink /proc/1/exe))")
machine.communicate.sudo(
"/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{expanded_guest_path}")
end
machine.communicate.sudo <<-SCRIPT
if command -v /sbin/init &>/dev/null && /sbin/init --version | grep upstart &>/dev/null; then
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT='#{expanded_guest_path}'
fi
SCRIPT
end
end
end

View File

@ -80,10 +80,11 @@ module VagrantPlugins
end
# Emit an upstart event if we can
if machine.communicate.test("test -x /sbin/initctl && test 'upstart' = $(basename $(sudo readlink /proc/1/exe))")
machine.communicate.sudo(
"/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{expanded_guest_path}")
end
machine.communicate.sudo <<-SCRIPT
if command -v /sbin/init &>/dev/null && /sbin/init --version | grep upstart &>/dev/null; then
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT='#{expanded_guest_path}'
fi
SCRIPT
end
def self.unmount_virtualbox_shared_folder(machine, guestpath, options)

View File

@ -10,8 +10,11 @@ module VagrantPlugins
machine.communicate.tap do |comm|
if comm.test("test -f ~/.ssh/authorized_keys")
comm.execute(
"sed -i '/^.*#{contents}.*$/d' ~/.ssh/authorized_keys")
comm.execute(<<SCRIPT)
sed -e '/^.*#{contents}.*$/d' ~/.ssh/authorized_keys > ~/.ssh/authorized_keys.new
mv ~/.ssh/authorized_keys.new ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
SCRIPT
end
end
end

View File

@ -0,0 +1,11 @@
module VagrantPlugins
module GuestPld
module Cap
class Flavor
def self.flavor(machine)
return :pld
end
end
end
end
end

View File

@ -20,6 +20,11 @@ module VagrantPlugins
require_relative "cap/network_scripts_dir"
Cap::NetworkScriptsDir
end
guest_capability("pld", "flavor") do
require_relative "cap/flavor"
Cap::Flavor
end
end
end
end

View File

@ -3,7 +3,11 @@ module VagrantPlugins
module Cap
class NFSClient
def self.nfs_client_install(machine)
if VagrantPlugins::GuestRedHat::Plugin.dnf?(machine)
machine.communicate.sudo("dnf -y install nfs-utils nfs-utils-lib")
else
machine.communicate.sudo("yum -y install nfs-utils nfs-utils-lib")
end
restart_nfs(machine)
end

View File

@ -4,6 +4,9 @@ module VagrantPlugins
class RSync
def self.rsync_install(machine)
machine.communicate.tap do |comm|
if VagrantPlugins::GuestRedHat::Plugin.dnf?(machine)
comm.sudo("dnf -y install rsync")
else
comm.sudo("yum -y install rsync")
end
end
@ -11,3 +14,4 @@ module VagrantPlugins
end
end
end
end

View File

@ -45,6 +45,10 @@ module VagrantPlugins
require_relative "cap/rsync"
Cap::RSync
end
def self.dnf?(machine)
machine.communicate.test("/usr/bin/which -s dnf")
end
end
end
end

View File

@ -0,0 +1,19 @@
module VagrantPlugins
module GuestSlackware
module Cap
class ChangeHostName
def self.change_host_name(machine, name)
machine.communicate.tap do |comm|
# Only do this if the hostname is not already set
if !comm.test("sudo hostname | grep '#{name}'")
comm.sudo("chmod o+w /etc/hostname")
comm.sudo("echo #{name} > /etc/hostname")
comm.sudo("chmod o-w /etc/hostname")
comm.sudo("hostname -F /etc/hostname")
end
end
end
end
end
end
end

View File

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
require "tempfile"
require "vagrant/util/template_renderer"
module VagrantPlugins
module GuestSlackware
module Cap
class ConfigureNetworks
include Vagrant::Util
def self.configure_networks(machine, networks)
interfaces = Array.new
machine.communicate.sudo("ip -o -0 addr | grep -v LOOPBACK | awk '{print $2}' | sed 's/://'") do |_, result|
interfaces = result.split("\n")
end
networks.each do |network|
network[:device] = interfaces[network[:interface]]
entry = TemplateRenderer.render("guests/slackware/network_#{network[:type]}", options: network)
temp = Tempfile.new("vagrant")
temp.binmode
temp.write(entry)
temp.close
machine.communicate.upload(temp.path, "/tmp/vagrant_network")
machine.communicate.sudo("mv /tmp/vagrant_network /etc/rc.d/rc.inet1.conf")
machine.communicate.sudo("/etc/rc.d/rc.inet1")
end
end
end
end
end
end

View File

@ -1,8 +1,10 @@
require "vagrant"
module VagrantPlugins
module GuestDebian8
module GuestSlackware
class Guest < Vagrant.plugin("2", :guest)
def detect?(machine)
machine.communicate.test("cat /etc/issue | grep 'Debian' | grep '8'")
machine.communicate.test("cat /etc/slackware-version")
end
end
end

View File

@ -0,0 +1,25 @@
require "vagrant"
module VagrantPlugins
module GuestSlackware
class Plugin < Vagrant.plugin("2")
name "Slackware guest"
description "Slackware guest support."
guest("slackware", "linux") do
require File.expand_path("../guest", __FILE__)
Guest
end
guest_capability("slackware", "change_host_name") do
require_relative "cap/change_host_name"
Cap::ChangeHostName
end
guest_capability("slackware", "configure_networks") do
require_relative "cap/configure_networks"
Cap::ConfigureNetworks
end
end
end
end

View File

@ -7,7 +7,7 @@ module VagrantPlugins
end
def update_etc_hostname
return super unless vivid?
return super unless systemd?
sudo("hostnamectl set-hostname '#{short_hostname}'")
end
@ -15,7 +15,7 @@ module VagrantPlugins
if hardy?
# hostname.sh returns 1, so use `true` to get a 0 exitcode
sudo("/etc/init.d/hostname.sh start; true")
elsif vivid?
elsif systemd?
# Service runs via hostnamectl
else
sudo("service hostname start")
@ -26,19 +26,25 @@ module VagrantPlugins
os_version("hardy")
end
def vivid?
os_version("vivid")
end
def renew_dhcp
sudo("ifdown -a; ifup -a; ifup -a --allow=hotplug")
end
private
def init_package
machine.communicate.execute('cat /proc/1/comm') do |type, data|
return data.chomp if type == :stdout
end
end
def os_version(name)
machine.communicate.test("[ `lsb_release -c -s` = #{name} ]")
end
def systemd?
init_package == 'systemd'
end
end
end
end

View File

@ -53,7 +53,7 @@ module VagrantPlugins
def self.create_vm_interface_map(machine, guest_network)
if !machine.provider.capability?(:nic_mac_addresses)
raise Errors::CantReadMACAddresses,
raise Vagrant::Errors::CantReadMACAddresses,
provider: machine.provider_name.to_s
end

View File

@ -2,8 +2,17 @@ module VagrantPlugins
module GuestWindows
module Cap
class RSync
def self.rsync_scrub_guestpath( machine, opts )
# Windows guests most often use cygwin-dependent rsync utilities
# that expect "/cygdrive/c" instead of "c:" as the path prefix
# some vagrant code may pass guest paths with drive-lettered paths here
opts[:guestpath].gsub( /^([a-zA-Z]):/, '/cygdrive/\1' )
end
def self.rsync_pre(machine, opts)
machine.communicate.tap do |comm|
# rsync does not construct any gaps in the path to the target directory
# make sure that all subdirectories are created
comm.execute("mkdir '#{opts[:guestpath]}'")
end
end

View File

@ -6,10 +6,6 @@ module VagrantPlugins
error_namespace("vagrant_windows.errors")
end
class CantReadMACAddresses < WindowsError
error_key(:cant_read_mac_addresses)
end
class NetworkWinRMRequired < WindowsError
error_key(:network_winrm_required)
end

View File

@ -64,6 +64,11 @@ module VagrantPlugins
Cap::MountSharedFolder
end
guest_capability(:windows, :rsync_scrub_guestpath) do
require_relative "cap/rsync"
Cap::RSync
end
guest_capability(:windows, :rsync_pre) do
require_relative "cap/rsync"
Cap::RSync

View File

@ -2,6 +2,7 @@ require "pathname"
require "tempfile"
require "vagrant/util/downloader"
require "vagrant/util/file_checksum"
require "vagrant/util/subprocess"
module VagrantPlugins
@ -10,8 +11,9 @@ module VagrantPlugins
class ProviderInstallVirtualBox
# The URL to download VirtualBox is hardcoded so we can have a
# known-good version to download.
URL = "http://download.virtualbox.org/virtualbox/5.0.8/VirtualBox-5.0.8-103449-OSX.dmg".freeze
VERSION = "5.0.8".freeze
URL = "http://download.virtualbox.org/virtualbox/5.0.10/VirtualBox-5.0.10-104061-OSX.dmg".freeze
VERSION = "5.0.10".freeze
SHA256SUM = "62f933115498e51ddf5f2dab47dc1eebb42eb78ea1a7665cb91c53edacc847c6".freeze
def self.provider_install_virtualbox(env)
tf = Tempfile.new("vagrant")
@ -29,6 +31,15 @@ module VagrantPlugins
dl = Vagrant::Util::Downloader.new(URL, tf.path, ui: ui)
dl.download!
# Validate that the file checksum matches
actual = Vagrant::Util::FileChecksum.new(tf.path, Digest::SHA2).checksum
if actual != SHA256SUM
raise Vagrant::Errors::ProviderChecksumMismatch,
provider: "virtualbox",
actual: actual,
expected: SHA256SUM
end
# Launch it
ui.output(I18n.t(
"vagrant.hosts.darwin.virtualbox_install_install"))

View File

@ -5,17 +5,35 @@ module VagrantPlugins
module Cap
class RDP
def self.rdp_client(env, rdp_info)
if !Vagrant::Util::Which.which("rdesktop")
raise Vagrant::Errors::LinuxRDesktopNotFound
# Detect if an RDP client is available.
# Prefer xfreerdp as it supports newer versions of RDP.
rdp_client =
if Vagrant::Util::Which.which("xfreerdp")
"xfreerdp"
elsif Vagrant::Util::Which.which("rdesktop")
"rdesktop"
else
raise Vagrant::Errors::LinuxRDPClientNotFound
end
args = []
# Build appropriate arguments for the RDP client.
case rdp_client
when "xfreerdp"
args << "/u:#{rdp_info[:username]}"
args << "/p:#{rdp_info[:password]}" if rdp_info[:password]
args << "/v:#{rdp_info[:host]}:#{rdp_info[:port]}"
args += rdp_info[:extra_args] if rdp_info[:extra_args]
when "rdesktop"
args << "-u" << rdp_info[:username]
args << "-p" << rdp_info[:password] if rdp_info[:password]
args += rdp_info[:extra_args] if rdp_info[:extra_args]
args << "#{rdp_info[:host]}:#{rdp_info[:port]}"
end
Vagrant::Util::Subprocess.execute("rdesktop", *args)
# Finally, run the client.
Vagrant::Util::Subprocess.execute(rdp_client, *args)
end
end
end

View File

@ -3,7 +3,7 @@ module VagrantPlugins
module Cap
class NFS
def self.nfs_check_command(env)
"pidof nfsd >/dev/null"
"/sbin/pidof nfsd >/dev/null"
end
def self.nfs_start_command(env)

View File

@ -4,7 +4,7 @@ module VagrantPlugins
module HostSlackware
class Host < Vagrant.plugin("2", :host)
def detect?(env)
return File.exists?("/etc/slackware-release") ||
return File.exists?("/etc/slackware-version") ||
!Dir.glob("/usr/lib/setup/Plamo-*").empty?
end
end

View File

@ -7,7 +7,7 @@ module VagrantPlugins
end
def self.nfs_check_command(env)
"pidof nfsd > /dev/null"
"/sbin/service nfsserver status"
end
def self.nfs_start_command(env)

View File

@ -2,6 +2,8 @@ require "pathname"
require "tempfile"
require "vagrant/util/downloader"
require "vagrant/util/file_checksum"
require "vagrant/util/powershell"
require "vagrant/util/subprocess"
module VagrantPlugins
@ -10,8 +12,9 @@ module VagrantPlugins
class ProviderInstallVirtualBox
# The URL to download VirtualBox is hardcoded so we can have a
# known-good version to download.
URL = "http://download.virtualbox.org/virtualbox/5.0.8/VirtualBox-5.0.8-103449-Win.exe".freeze
VERSION = "5.0.8".freeze
URL = "http://download.virtualbox.org/virtualbox/5.0.10/VirtualBox-5.0.10-104061-Win.exe".freeze
VERSION = "5.0.10".freeze
SHA256SUM = "3e5ed8fe4ada6eef8dfb4fe6fd79fcab4b242acf799f7d3ab4a17b43838b1e04".freeze
def self.provider_install_virtualbox(env)
tf = Tempfile.new("vagrant")
@ -29,13 +32,22 @@ module VagrantPlugins
dl = Vagrant::Util::Downloader.new(URL, tf.path, ui: ui)
dl.download!
# Validate that the file checksum matches
actual = Vagrant::Util::FileChecksum.new(tf.path, Digest::SHA2).checksum
if actual != SHA256SUM
raise Vagrant::Errors::ProviderChecksumMismatch,
provider: "virtualbox",
actual: actual,
expected: SHA256SUM
end
# Launch it
ui.output(I18n.t(
"vagrant.hosts.windows.virtualbox_install_install"))
ui.detail(I18n.t(
"vagrant.hosts.windows.virtualbox_install_install_detail"))
script = File.expand_path("../../scripts/install_virtualbox.ps1", __FILE__)
result = Vagrant::Util::Powershell.execute(script, tf.path)
result = Vagrant::Util::PowerShell.execute(script, tf.path)
if result.exit_code != 0
raise Vagrant::Errors::ProviderInstallFailed,
provider: "virtualbox",

View File

@ -0,0 +1,42 @@
require "pathname"
require "tmpdir"
require "vagrant/util/subprocess"
module VagrantPlugins
module HostWindows
module Cap
class PS
def self.ps_client(env, ps_info)
logger = Log4r::Logger.new("vagrant::hosts::windows")
command = <<-EOS
$plain_password = "#{ps_info[:password]}"
$username = "#{ps_info[:username]}"
$port = "#{ps_info[:port]}"
$hostname = "#{ps_info[:host]}"
$password = ConvertTo-SecureString $plain_password -asplaintext -force
$creds = New-Object System.Management.Automation.PSCredential ("$hostname\\$username", $password)
function prompt { kill $PID }
Enter-PSSession -ComputerName $hostname -Credential $creds -Port $port
EOS
logger.debug("Starting remote powershell with command:\n#{command}")
args = ["-NoProfile"]
args << "-ExecutionPolicy"
args << "Bypass"
args << "-NoExit"
args << "-EncodedCommand"
args << ::WinRM::PowershellScript.new(command).encoded
if ps_info[:extra_args]
args << ps_info[:extra_args]
end
# Launch it
Vagrant::Util::Subprocess.execute("powershell", *args)
end
end
end
end
end

View File

@ -25,6 +25,11 @@ module VagrantPlugins
require_relative "cap/rdp"
Cap::RDP
end
host_capability("windows", "ps_client") do
require_relative "cap/ps"
Cap::PS
end
end
end
end

View File

@ -13,6 +13,7 @@ module VagrantPlugins
attr_accessor :private_key_path
attr_accessor :forward_agent
attr_accessor :forward_x11
attr_accessor :forward_env
attr_accessor :shell
def initialize
@ -26,6 +27,7 @@ module VagrantPlugins
@private_key_path = UNSET_VALUE
@forward_agent = UNSET_VALUE
@forward_x11 = UNSET_VALUE
@forward_env = UNSET_VALUE
@shell = UNSET_VALUE
end
@ -37,6 +39,7 @@ module VagrantPlugins
new.ssh.private_key_path = @private_key_path if @private_key_path != UNSET_VALUE
new.ssh.forward_agent = @forward_agent if @forward_agent != UNSET_VALUE
new.ssh.forward_x11 = @forward_x11 if @forward_x11 != UNSET_VALUE
new.ssh.forward_env = @forward_env if @forward_env != UNSET_VALUE
new.ssh.shell = @shell if @shell != UNSET_VALUE
end
end

View File

@ -7,6 +7,7 @@ module VagrantPlugins
class SSHConfig < SSHConnectConfig
attr_accessor :forward_agent
attr_accessor :forward_x11
attr_accessor :forward_env
attr_accessor :guest_port
attr_accessor :keep_alive
attr_accessor :shell
@ -22,6 +23,7 @@ module VagrantPlugins
@forward_agent = UNSET_VALUE
@forward_x11 = UNSET_VALUE
@forward_env = UNSET_VALUE
@guest_port = UNSET_VALUE
@keep_alive = UNSET_VALUE
@proxy_command = UNSET_VALUE
@ -45,6 +47,7 @@ module VagrantPlugins
@forward_agent = false if @forward_agent == UNSET_VALUE
@forward_x11 = false if @forward_x11 == UNSET_VALUE
@forward_env = false if @forward_env == UNSET_VALUE
@guest_port = 22 if @guest_port == UNSET_VALUE
@keep_alive = true if @keep_alive == UNSET_VALUE
@proxy_command = nil if @proxy_command == UNSET_VALUE

View File

@ -416,7 +416,8 @@ module VagrantPlugins
host_ip: "127.0.0.1",
id: "winrm",
auto_correct: true
end
if !@__networks["forwarded_port-winrm-ssl"]
network :forwarded_port,
guest: 5986,
host: 55986,
@ -697,7 +698,7 @@ module VagrantPlugins
end
end
if options[:ip] && options[:ip].end_with?(".1")
if options[:ip] && options[:ip].end_with?(".1") && options[:type].to_sym != :dhcp
machine.ui.warn(I18n.t(
"vagrant.config.vm.network_ip_ends_in_one"))
end

View File

@ -156,12 +156,12 @@ module VagrantPlugins
b3.use Call, DestroyConfirm do |env3, b4|
if env3[:result]
b4.use ConfigValidate
b4.use ProvisionerCleanup, :before
b4.use EnvSet, force_halt: true
b4.use action_halt
b4.use HostMachineSyncFoldersDisable
b4.use Destroy
b4.use DestroyBuildImage
b4.use ProvisionerCleanup
else
b4.use Message,
I18n.t("docker_provider.messages.will_not_destroy")

View File

@ -38,6 +38,7 @@ module VagrantPlugins
end
b2.use ConfigValidate
b2.use ProvisionerCleanup, :before
b2.use StopInstance
b2.use DeleteVM
end

View File

@ -16,7 +16,8 @@ module VagrantPlugins
raise Errors::WindowsRequired
end
if !Vagrant::Util::Platform.windows_admin?
if !Vagrant::Util::Platform.windows_admin? and
!Vagrant::Util::Platform.windows_hyperv_admin?
raise Errors::AdminRequired
end

View File

@ -7,9 +7,19 @@ Param(
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
$ip_address = ""
$vm = Get-VM -Id $VmId -ErrorAction "Stop"
$network = Get-VMNetworkAdapter -VM $vm
$networks = Get-VMNetworkAdapter -VM $vm
foreach ($network in $networks) {
if ($network.IpAddresses.Length -gt 0) {
$ip_address = $network.IpAddresses[0]
if (-Not ([string]::IsNullOrEmpty($ip_address))) {
# We found our IP address!
break
}
}
}
$resultHash = @{
ip = "$ip_address"
}

View File

@ -12,7 +12,7 @@ try {
$VM = Get-VM -Id $VmId -ErrorAction "Stop"
$State = $VM.state
$Status = $VM.status
} catch [Microsoft.HyperV.PowerShell.VirtualizationOperationFailedException] {
} catch [Microsoft.HyperV.PowerShell.VirtualizationException] {
$State = "not_created"
$Status = $State
}

Some files were not shown because too many files have changed in this diff Show More