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 # OS-specific
.DS_Store .DS_Store
# Editor swapfiles
.*.sw?
*~
# Vagrant stuff # Vagrant stuff
acceptance_config.yml acceptance_config.yml
boxes/* boxes/*

View File

@ -2,22 +2,162 @@
FEATURES: 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**: VirtualBox and VMware providers now support
linked clones for very fast (millisecond) imports on up. [GH-4484] linked clones for very fast (millisecond) imports on up. [GH-4484]
- **Snapshots**: The `vagrant snapshot` command can be used to checkpoint - **Snapshots**: The `vagrant snapshot` command can be used to checkpoint
and restore point-in-time snapshots. and restore point-in-time snapshots.
- **IPv6 Private Networks**: Private networking now supports IPv6. This - **IPv6 Private Networks**: Private networking now supports IPv6. This
only works with VirtualBox and VMware at this point. [GH-6342] 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: IMPROVEMENTS:
- core: allow removal of all box versions with `--all` flag [GH-3462] - 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: 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: 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` - provisioners/ansible: use quotes for the `ansible_ssh_private_key_file`
value in the generated inventory [GH-6209] 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) ## 1.7.4 (July 17, 2015)

View File

@ -1,6 +1,6 @@
# Vagrant # 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) * Source: [https://github.com/mitchellh/vagrant](https://github.com/mitchellh/vagrant)
* IRC: `#vagrant` on Freenode * IRC: `#vagrant` on Freenode
* Mailing list: [Google Groups](http://groups.google.com/group/vagrant-up) * Mailing list: [Google Groups](http://groups.google.com/group/vagrant-up)
@ -19,12 +19,12 @@ between Windows, Mac OS X, and Linux.
## Quick Start ## Quick Start
For the quick-start, we'll bring up a development machine on 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 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 First, make sure your development machine has
[VirtualBox](http://www.virtualbox.org) [VirtualBox](https://www.virtualbox.org/)
installed. After this, installed. After this,
[download and install the appropriate Vagrant package for your OS](http://www.vagrantup.com/downloads). [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 ### 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: be installed with a simple `gem install bundler`. Afterwards, do the following:
bundle install 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`. * `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 * `st` - Contains a `.sublime-settings` file for enabling Ruby syntax highlighting
for `Vagrantfile`s in Sublime Text. 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 * `vim` - Contains a `.vim` file for enabling Ruby syntax highlighting
for `Vagrantfile`s in `vim`. 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_CHECK = /usr/bin/systemctl status nfs-server.service
Cmnd_Alias VAGRANT_NFSD_START = /usr/bin/systemctl start 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_NFSD_APPLY = /usr/sbin/exportfs -ar
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /etc/exports Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /*/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_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_CHECK = /etc/init.d/nfs-kernel-server status
Cmnd_Alias VAGRANT_NFSD_START = /etc/init.d/nfs-kernel-server start Cmnd_Alias VAGRANT_NFSD_START = /etc/init.d/nfs-kernel-server start
Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /etc/exports Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /*/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_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.") @logger.info("URL is a file or protocol not found and assuming file.")
file_path = File.expand_path(url) file_path = File.expand_path(url)
file_path = Util::Platform.cygwin_windows_path(file_path) 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 end
# If the temporary path exists, verify it is not too old. If its # If the temporary path exists, verify it is not too old. If its
@ -491,6 +493,12 @@ module Vagrant
end end
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 output = d.head
match = output.scan(/^Content-Type: (.+?)$/i).last match = output.scan(/^Content-Type: (.+?)$/i).last
return false if !match return false if !match
@ -507,14 +515,14 @@ module Vagrant
Digest::SHA2 Digest::SHA2
else else
raise Errors::BoxChecksumInvalidType, raise Errors::BoxChecksumInvalidType,
type: env[:box_checksum_type].to_s type: checksum_type.to_s
end end
@logger.info("Validating checksum with #{checksum_klass}") @logger.info("Validating checksum with #{checksum_klass}")
@logger.info("Expected checksum: #{checksum}") @logger.info("Expected checksum: #{checksum}")
actual = FileChecksum.new(path, checksum_klass).checksum actual = FileChecksum.new(path, checksum_klass).checksum
if actual != checksum if actual.casecmp(checksum) != 0
raise Errors::BoxChecksumMismatch, raise Errors::BoxChecksumMismatch,
actual: actual, actual: actual,
expected: checksum expected: checksum

View File

@ -37,13 +37,23 @@ module Vagrant
end end
constraints = machine.config.vm.box_version 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( env[:ui].output(I18n.t(
"vagrant.box_outdated_checking_with_refresh", "vagrant.box_outdated_checking_with_refresh",
name: box.name)) name: box.name))
update = nil update = nil
begin begin
update = box.has_update?(constraints) update = box.has_update?(constraints, download_options: download_options)
rescue Errors::BoxMetadataDownloadError => e rescue Errors::BoxMetadataDownloadError => e
env[:ui].warn(I18n.t( env[:ui].warn(I18n.t(
"vagrant.box_outdated_metadata_download_error", "vagrant.box_outdated_metadata_download_error",

View File

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

View File

@ -128,7 +128,7 @@ module Vagrant
port_checker[repaired_port] || port_checker[repaired_port] ||
lease_check(repaired_port) lease_check(repaired_port)
if in_use 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 next
end end
@ -156,8 +156,6 @@ module Vagrant
new_port: repaired_port.to_s)) new_port: repaired_port.to_s))
end end
end end
@app.call(env)
end end
def lease_check(port) def lease_check(port)

View File

@ -76,6 +76,16 @@ module Vagrant
if opts[:merge] if opts[:merge]
existing = cached_synced_folders(machine) existing = cached_synced_folders(machine)
if existing 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| folders.each do |impl, fs|
existing[impl] ||= {} existing[impl] ||= {}
fs.each do |id, data| fs.each do |id, data|
@ -101,7 +111,12 @@ module Vagrant
return cached_synced_folders(machine) if opts[:cached] return cached_synced_folders(machine) if opts[:cached]
config = opts[:config] config = opts[:config]
config ||= machine.config.vm root = false
if !config
config = machine.config.vm
root = true
end
config_folders = config.synced_folders config_folders = config.synced_folders
folders = {} folders = {}
@ -131,9 +146,17 @@ module Vagrant
end end
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. # Keep track of this shared folder by the implementation.
folders[impl] ||= {} folders[impl] ||= {}
folders[impl][id] = data.dup folders[impl][id] = data
end end
# If we have folders with the "default" key, then determine the # 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) def initialize(app, env, place=nil)
@app = app @app = app
@logger = Log4r::Logger.new("vagrant::action::builtin::provision_cleanup") @logger = Log4r::Logger.new("vagrant::action::builtin::provision_cleanup")
@place ||= :after
@place = @place.to_sym place ||= :after
@place = place.to_sym
end end
def call(env) def call(env)
@ -31,10 +32,20 @@ module Vagrant
# Ask the provisioners to modify the configuration if needed # Ask the provisioners to modify the configuration if needed
provisioner_instances(env).each do |p, _| provisioner_instances(env).each do |p, _|
env[:ui].info(I18n.t( name = type_map[p].to_s
"vagrant.provisioner_cleanup",
name: type_map[p].to_s)) # Check if the subclass defined a cleanup method. The parent
p.cleanup # 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 end
end end

View File

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

View File

@ -30,7 +30,7 @@ module Vagrant
def call(env) def call(env)
@env = env @env = env
file_name = File.basename(@env["package.output"].to_s) file_name = File.basename(@env["package.output"].to_s)
raise Errors::PackageOutputDirectory if File.directory?(tar_path) raise Errors::PackageOutputDirectory if File.directory?(tar_path)
raise Errors::PackageOutputExists, file_name:file_name if File.exist?(tar_path) raise Errors::PackageOutputExists, file_name:file_name if File.exist?(tar_path)
raise Errors::PackageRequiresDirectory if !env["package.directory"] || raise Errors::PackageRequiresDirectory if !env["package.directory"] ||
@ -113,6 +113,21 @@ module Vagrant
# If we don't have a generated private key, we do nothing # If we don't have a generated private key, we do nothing
path = @env[:machine].data_dir.join("private_key") 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? return if !path.file?
# Copy it into our box directory # Copy it into our box directory

View File

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

View File

@ -12,7 +12,9 @@ module Vagrant
# for accessing/finding individual boxes, adding new boxes, or deleting # for accessing/finding individual boxes, adding new boxes, or deleting
# boxes. # boxes.
class BoxCollection 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. # The directory where the boxes in this collection are stored.
# #
@ -346,6 +348,14 @@ module Vagrant
end end
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 protected
# Returns the directory name for the box of the given name. # Returns the directory name for the box of the given name.
@ -354,16 +364,16 @@ module Vagrant
# @return [String] # @return [String]
def dir_name(name) def dir_name(name)
name = name.dup name = name.dup
name.gsub!(":", "-VAGRANTCOLON-") if Util::Platform.windows? name.gsub!(":", VAGRANT_COLON) if Util::Platform.windows?
name.gsub!("/", "-VAGRANTSLASH-") name.gsub!("/", VAGRANT_SLASH)
name name
end end
# Returns the directory name for the box cleaned up # Returns the directory name for the box cleaned up
def undir_name(name) def undir_name(name)
name = name.dup name = name.dup
name.gsub!("-VAGRANTCOLON-", ":") name.gsub!(VAGRANT_COLON, ":")
name.gsub!("-VAGRANTSLASH-", "/") name.gsub!(VAGRANT_SLASH, "/")
name name
end end
@ -440,5 +450,10 @@ module Vagrant
ensure ensure
dir.rmtree if dir.exist? dir.rmtree if dir.exist?
end 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
end end

View File

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

View File

@ -221,7 +221,12 @@ module Vagrant
line = "(unknown)" line = "(unknown)"
if e.backtrace && e.backtrace[0] 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 end
# Report the generic exception # Report the generic exception

View File

@ -832,7 +832,7 @@ module Vagrant
# This creates the local data directory and show an error if it # This creates the local data directory and show an error if it
# couldn't properly be created. # couldn't properly be created.
def setup_local_data_path def setup_local_data_path(force=false)
if @local_data_path.nil? if @local_data_path.nil?
@logger.warn("No local data path is set. Local data cannot be stored.") @logger.warn("No local data path is set. Local data cannot be stored.")
return return
@ -847,6 +847,9 @@ module Vagrant
upgrade_v1_dotfile(@local_data_path) upgrade_v1_dotfile(@local_data_path)
end end
# If we don't have a root path, we don't setup anything
return if !force && root_path.nil?
begin begin
@logger.debug("Creating: #{@local_data_path}") @logger.debug("Creating: #{@local_data_path}")
FileUtils.mkdir_p(@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 # Now, we create the actual local data directory. This should succeed
# this time since we renamed the old conflicting V1. # this time since we renamed the old conflicting V1.
setup_local_data_path setup_local_data_path(true)
if json_data["active"] if json_data["active"]
@logger.debug("Upgrading to V2 style for each active VM") @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) error_key(:active_machine_with_different_provider)
end end
class AnsibleFailed < VagrantError
error_key(:ansible_failed)
end
class AnsiblePlaybookAppNotFound < VagrantError
error_key(:ansible_playbook_app_not_found)
end
class BatchMultiError < VagrantError class BatchMultiError < VagrantError
error_key(:batch_multi_error) error_key(:batch_multi_error)
end end
@ -248,6 +240,10 @@ module Vagrant
error_key(:bundler_error) error_key(:bundler_error)
end end
class CantReadMACAddresses < VagrantError
error_key(:cant_read_mac_addresses)
end
class CapabilityHostExplicitNotDetected < VagrantError class CapabilityHostExplicitNotDetected < VagrantError
error_key(:capability_host_explicit_not_detected) error_key(:capability_host_explicit_not_detected)
end end
@ -348,6 +344,10 @@ module Vagrant
error_key(:downloader_interrupted) error_key(:downloader_interrupted)
end end
class EnvInval < VagrantError
error_key(:env_inval)
end
class EnvironmentNonExistentCWD < VagrantError class EnvironmentNonExistentCWD < VagrantError
error_key(:environment_non_existent_cwd) error_key(:environment_non_existent_cwd)
end end
@ -408,8 +408,8 @@ module Vagrant
error_key(:linux_nfs_mount_failed) error_key(:linux_nfs_mount_failed)
end end
class LinuxRDesktopNotFound < VagrantError class LinuxRDPClientNotFound < VagrantError
error_key(:linux_rdesktop_not_found) error_key(:linux_rdp_client_not_found)
end end
class LocalDataDirectoryNotAccessible < VagrantError class LocalDataDirectoryNotAccessible < VagrantError
@ -524,6 +524,10 @@ module Vagrant
error_key(:provider_cant_install) error_key(:provider_cant_install)
end end
class ProviderChecksumMismatch < VagrantError
error_key(:provider_checksum_mismatch)
end
class ProviderInstallFailed < VagrantError class ProviderInstallFailed < VagrantError
error_key(:provider_install_failed) error_key(:provider_install_failed)
end end

View File

@ -116,6 +116,9 @@ module Vagrant
# XXX: This is temporary. This will be removed very soon. # XXX: This is temporary. This will be removed very soon.
if base if base
@id = name @id = name
# For base setups, we don't want to insert the key
@config.ssh.insert_key = false
else else
reload reload
end end
@ -141,6 +144,10 @@ module Vagrant
if state.id == MachineState::NOT_CREATED_ID if state.id == MachineState::NOT_CREATED_ID
self.id = nil self.id = nil
end 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 end
# This calls an action on the provider. The provider may or may not # This calls an action on the provider. The provider may or may not
@ -188,7 +195,10 @@ module Vagrant
end end
# Call the action # 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 end
rescue Errors::EnvironmentLockedError rescue Errors::EnvironmentLockedError
raise Errors::MachineActionLockedError, raise Errors::MachineActionLockedError,
@ -436,6 +446,7 @@ module Vagrant
# We also set some fields that are purely controlled by Varant # We also set some fields that are purely controlled by Varant
info[:forward_agent] = @config.ssh.forward_agent info[:forward_agent] = @config.ssh.forward_agent
info[:forward_x11] = @config.ssh.forward_x11 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 info[:ssh_command] = @config.ssh.ssh_command if @config.ssh.ssh_command

View File

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

View File

@ -133,8 +133,17 @@ module Vagrant
# machine in that environment. We silence warnings here because # machine in that environment. We silence warnings here because
# Vagrantfiles often have constants, so people would otherwise # Vagrantfiles often have constants, so people would otherwise
# constantly (heh) get "already initialized constant" warnings. # constantly (heh) get "already initialized constant" warnings.
env = entry.vagrant_env( begin
@env.home_path, ui_class: @env.ui_class) 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) next env.machine(entry.name.to_sym, entry.provider.to_sym)
end end

View File

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

View File

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

View File

@ -10,10 +10,17 @@ module Vagrant
class Platform class Platform
class << self class << self
def cygwin? def cygwin?
# Installer detects Cygwin
return true if ENV["VAGRANT_DETECTED_OS"] && return true if ENV["VAGRANT_DETECTED_OS"] &&
ENV["VAGRANT_DETECTED_OS"].downcase.include?("cygwin") 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 end
[:darwin, :bsd, :freebsd, :linux, :solaris].each do |type| [:darwin, :bsd, :freebsd, :linux, :solaris].each do |type|
@ -45,10 +52,32 @@ module Vagrant
# detect-if-running-with-administrator-privileges-under-windows-xp # detect-if-running-with-administrator-privileges-under-windows-xp
begin begin
Win32::Registry::HKEY_USERS.open("S-1-5-19") {} Win32::Registry::HKEY_USERS.open("S-1-5-19") {}
return true
rescue Win32::Registry::Error rescue Win32::Registry::Error
return false return false
end 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 end
# This takes any path and converts it from a Windows path to a # 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)) path = Pathname.new(File.expand_path(path))
if path.exist? && !fs_case_sensitive? 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 # Build up all the parts of the path
original = [] original = []
while !path.root? 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]}"] command_options += ["-o", "ProxyCommand=#{ssh_info[:proxy_command]}"]
end 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 # 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, # 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 # 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}") LOGGER.info("Executing SSH in subprocess: #{ssh} #{command_options.inspect}")
process = ChildProcess.build(ssh, *command_options) process = ChildProcess.build(ssh, *command_options)
process.io.inherit! 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.start
process.wait process.wait
return process.exit_code 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 'optparse'
require_relative 'download_mixins'
module VagrantPlugins module VagrantPlugins
module CommandBox module CommandBox
module Command module Command
class Add < Vagrant.plugin("2", :command) class Add < Vagrant.plugin("2", :command)
include DownloadMixins
def execute def execute
options = {} options = {}
@ -21,22 +25,7 @@ module VagrantPlugins
options[:force] = f options[:force] = f
end end
o.on("--insecure", "Do not validate SSL certificates") do |i| build_download_options(o, options)
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
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| 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 options[:location_trusted] = l
@ -97,7 +86,7 @@ module VagrantPlugins
box_force: options[:force], box_force: options[:force],
box_download_ca_cert: options[:ca_cert], box_download_ca_cert: options[:ca_cert],
box_download_ca_path: options[:ca_path], 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_insecure: options[:insecure],
box_download_location_trusted: options[:location_trusted], box_download_location_trusted: options[:location_trusted],
ui: Vagrant::UI::Prefixed.new(@env.ui, "box"), 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 'optparse'
require_relative 'download_mixins'
module VagrantPlugins module VagrantPlugins
module CommandBox module CommandBox
module Command module Command
class Outdated < Vagrant.plugin("2", :command) class Outdated < Vagrant.plugin("2", :command)
include DownloadMixins
def execute def execute
options = {} options = {}
download_options = {}
opts = OptionParser.new do |o| opts = OptionParser.new do |o|
o.banner = "Usage: vagrant box outdated [options]" o.banner = "Usage: vagrant box outdated [options]"
@ -20,6 +25,8 @@ module VagrantPlugins
o.on("--global", "Check all boxes installed") do |g| o.on("--global", "Check all boxes installed") do |g|
options[:global] = g options[:global] = g
end end
build_download_options(o, download_options)
end end
argv = parse_options(opts) argv = parse_options(opts)
@ -27,7 +34,7 @@ module VagrantPlugins
# If we're checking the boxes globally, then do that. # If we're checking the boxes globally, then do that.
if options[:global] if options[:global]
outdated_global outdated_global(download_options)
return 0 return 0
end end
@ -37,11 +44,11 @@ module VagrantPlugins
box_outdated_refresh: true, box_outdated_refresh: true,
box_outdated_success_ui: true, box_outdated_success_ui: true,
machine: machine, machine: machine,
}) }.merge(download_options))
end end
end end
def outdated_global def outdated_global(download_options)
boxes = {} boxes = {}
@env.boxes.all.reverse.each do |name, version, provider| @env.boxes.all.reverse.each do |name, version, provider|
next if boxes[name] next if boxes[name]
@ -58,8 +65,8 @@ module VagrantPlugins
md = nil md = nil
begin begin
md = box.load_metadata md = box.load_metadata(download_options)
rescue Vagrant::Errors::DownloaderError => e rescue Vagrant::Errors::BoxMetadataDownloadError => e
@env.ui.error(I18n.t( @env.ui.error(I18n.t(
"vagrant.box_outdated_metadata_error", "vagrant.box_outdated_metadata_error",
name: box.name, name: box.name,

View File

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

View File

@ -1,4 +1,5 @@
require "rest_client" require "rest_client"
require "vagrant/util/downloader"
module VagrantPlugins module VagrantPlugins
module LoginCommand module LoginCommand
@ -45,8 +46,23 @@ module VagrantPlugins
with_error_handling do with_error_handling do
url = "#{Vagrant.server_url}/api/v1/authenticate" url = "#{Vagrant.server_url}/api/v1/authenticate"
request = { "user" => { "login" => user, "password" => pass } } 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 = JSON.load(response.to_s)
data["token"] data["token"]
end end

View File

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

View File

@ -3,6 +3,11 @@ module VagrantPlugins
module Command module Command
module MixinInstallOpts module MixinInstallOpts
def build_install_opts(o, options) def build_install_opts(o, options)
options[:plugin_sources] = [
"https://rubygems.org",
"http://gems.hashicorp.com",
]
o.on("--entry-point NAME", String, o.on("--entry-point NAME", String,
"The name of the entry point file for loading the plugin.") do |entry_point| "The name of the entry point file for loading the plugin.") do |entry_point|
options[:entry_point] = entry_point options[:entry_point] = entry_point
@ -17,9 +22,13 @@ module VagrantPlugins
puts puts
end 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, o.on("--plugin-source PLUGIN_SOURCE", String,
"Add a RubyGems repository source") do |plugin_source| "Add a RubyGems repository source") do |plugin_source|
options[:plugin_sources] ||= []
options[:plugin_sources] << plugin_source options[:plugin_sources] << plugin_source
end 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.banner = "Usage: vagrant provision [vm-name] [--provision-with x,y,z]"
o.on("--provision-with x,y,z", Array, 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 } options[:provision_types] = list.map { |type| type.to_sym }
end end
end end

View File

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

View File

@ -41,12 +41,15 @@ module VagrantPlugins
forward_agent: ssh_info[:forward_agent], forward_agent: ssh_info[:forward_agent],
forward_x11: ssh_info[:forward_x11], forward_x11: ssh_info[:forward_x11],
proxy_command: ssh_info[:proxy_command], 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 # Render the template and output directly to STDOUT
template = "commands/ssh_config/config" 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 safe_puts
end end

View File

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

View File

@ -1,3 +1,5 @@
require "set"
module VagrantPlugins module VagrantPlugins
module CommandUp module CommandUp
module StartMixins module StartMixins
@ -17,7 +19,7 @@ module VagrantPlugins
end end
parser.on("--provision-with x,y,z", Array, 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_types] = list.map { |type| type.to_sym }
options[:provision_enabled] = true options[:provision_enabled] = true
options[:provision_ignore_sentinel] = true options[:provision_ignore_sentinel] = true
@ -26,13 +28,26 @@ module VagrantPlugins
# This validates the provisioner flags and raises an exception # This validates the provisioner flags and raises an exception
# if there are invalid ones. # if there are invalid ones.
def validate_provisioner_flags!(options) def validate_provisioner_flags!(options, argv)
(options[:provision_types] || []).each do |type| if options[:provision_types].nil?
klass = Vagrant.plugin("2").manager.provisioners[type] return
if !klass end
raise Vagrant::Errors::ProvisionerFlagInvalid,
name: type.to_s provisioner_names = Set.new
end 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
raise Vagrant::Errors::ProvisionerFlagInvalid,
name: type.to_s
end
end
end end
end end
end end

View File

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

View File

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

View File

@ -11,6 +11,7 @@ module VagrantPlugins
attr_accessor :timeout attr_accessor :timeout
attr_accessor :transport attr_accessor :transport
attr_accessor :ssl_peer_verification attr_accessor :ssl_peer_verification
attr_accessor :execution_time_limit
def initialize def initialize
@username = UNSET_VALUE @username = UNSET_VALUE
@ -23,6 +24,7 @@ module VagrantPlugins
@timeout = UNSET_VALUE @timeout = UNSET_VALUE
@transport = UNSET_VALUE @transport = UNSET_VALUE
@ssl_peer_verification = UNSET_VALUE @ssl_peer_verification = UNSET_VALUE
@execution_time_limit = UNSET_VALUE
end end
def finalize! def finalize!
@ -37,6 +39,7 @@ module VagrantPlugins
@retry_delay = 2 if @retry_delay == UNSET_VALUE @retry_delay = 2 if @retry_delay == UNSET_VALUE
@timeout = 1800 if @timeout == UNSET_VALUE @timeout = 1800 if @timeout == UNSET_VALUE
@ssl_peer_verification = true if @ssl_peer_verification == UNSET_VALUE @ssl_peer_verification = true if @ssl_peer_verification == UNSET_VALUE
@execution_time_limit = "PT2H" if @execution_time_limit == UNSET_VALUE
end end
def validate(machine) def validate(machine)
@ -49,6 +52,7 @@ module VagrantPlugins
errors << "winrm.max_tries cannot be nil." if @max_tries.nil? errors << "winrm.max_tries cannot be nil." if @max_tries.nil?
errors << "winrm.retry_delay 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.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 unless @ssl_peer_verification == true || @ssl_peer_verification == false
errors << "winrm.ssl_peer_verification must be a boolean." errors << "winrm.ssl_peer_verification must be a boolean."
end 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" $task_name = "WinRM_Elevated_Shell"
$out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell.log" $out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell.log"
@ -13,7 +25,7 @@ $task_xml = @'
<Principals> <Principals>
<Principal id="Author"> <Principal id="Author">
<UserId>{username}</UserId> <UserId>{username}</UserId>
<LogonType>Password</LogonType> <LogonType><%= options[:interactive] ? 'InteractiveTokenOrPassword' : 'Password' %></LogonType>
<RunLevel>HighestAvailable</RunLevel> <RunLevel>HighestAvailable</RunLevel>
</Principal> </Principal>
</Principals> </Principals>
@ -33,7 +45,7 @@ $task_xml = @'
<Hidden>false</Hidden> <Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle> <RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun> <WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT2H</ExecutionTimeLimit> <ExecutionTimeLimit>{execution_time_limit}</ExecutionTimeLimit>
<Priority>4</Priority> <Priority>4</Priority>
</Settings> </Settings>
<Actions Context="Author"> <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("{arguments}", $arguments)
$task_xml = $task_xml.Replace("{username}", $username) $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() $schedule.Connect()
$task = $schedule.NewTask($null) $task = $schedule.NewTask($null)
$task.XmlText = $task_xml $task.XmlText = $task_xml
$folder = $schedule.GetFolder("\") $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 = $folder.GetTask("\$task_name")
$registered_task.Run($null) | Out-Null $registered_task.Run($null) | Out-Null
@ -71,7 +83,7 @@ function SlurpOutput($out_file, $cur_line) {
if (Test-Path $out_file) { if (Test-Path $out_file) {
get-content $out_file | select -skip $cur_line | ForEach { get-content $out_file | select -skip $cur_line | ForEach {
$cur_line += 1 $cur_line += 1
Write-Host "$_" Write-Host "$_"
} }
} }
return $cur_line return $cur_line

View File

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

View File

@ -27,7 +27,7 @@ module VagrantPlugins
machine.communicate.upload(temp.path, "/tmp/vagrant_network") machine.communicate.upload(temp.path, "/tmp/vagrant_network")
machine.communicate.sudo("mv /tmp/vagrant_network /etc/netctl/#{network[:device]}") 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 end
end end

View File

@ -6,45 +6,109 @@ module VagrantPlugins
module GuestDarwin module GuestDarwin
module Cap module Cap
class ConfigureNetworks class ConfigureNetworks
@@logger = Log4r::Logger.new("vagrant::guest::darwin::configure_networks")
include Vagrant::Util include Vagrant::Util
def self.configure_networks(machine, networks) def self.configure_networks(machine, networks)
# Slightly different than other plugins, using the template to build commands if !machine.provider.capability?(:nic_mac_addresses)
# rather than templating the files. raise Vagrant::Errors::CantReadMACAddresses,
provider: machine.provider_name.to_s
end
machine.communicate.sudo("networksetup -detectnewhardware") nic_mac_addresses = machine.provider.capability(:nic_mac_addresses)
machine.communicate.sudo("networksetup -listnetworkserviceorder > /tmp/vagrant.interfaces") @@logger.debug("mac addresses: #{nic_mac_addresses.inspect}")
tmpints = File.join(Dir.tmpdir, File.basename("#{machine.id}.interfaces"))
machine.communicate.download("/tmp/vagrant.interfaces",tmpints)
devlist = [] mac_service_map = create_mac_service_map(machine)
ints = ::IO.read(tmpints)
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| ints.split(/\n\n/m).each do |i|
if i.match(/Hardware/) and not i.match(/Ethernet/).nil? if i.match(/Hardware/) && i.match(/Ethernet/)
devmap = {}
# Ethernet, should be 2 lines, # Ethernet, should be 2 lines,
# (3) Thunderbolt Ethernet # (3) Thunderbolt Ethernet
# (Hardware Port: Thunderbolt Ethernet, Device: en1) # (Hardware Port: Thunderbolt Ethernet, Device: en1)
# multiline, should match "Thunderbolt Ethernet", "en1" # multiline, should match "Thunderbolt Ethernet", "en1"
devicearry = i.match(/\([0-9]+\) (.+)\n.*Device: (.+)\)/m) devicearry = i.match(/\([0-9]+\) (.+)\n.*Device: (.+)\)/m)
devmap[:interface] = devicearry[2] service = devicearry[1]
devmap[:service] = devicearry[1] interface = devicearry[2]
devlist << devmap
# Should map interface to service { "en1" => "Thunderbolt Ethernet" }
interface_map[interface] = service
end end
end end
File.delete(tmpints) File.delete(tmp_ints)
networks.each do |network| mac_service_map = {}
service_name = devlist[network[:interface]][:service] macs = ::IO.read(tmp_hw)
if network[:type].to_sym == :static macs.split(/\n\n/m).each do |i|
command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}" if i.match(/Hardware/) && i.match(/Ethernet/)
elsif network[:type].to_sym == :dhcp # Ethernet, should be 3 lines,
command = "networksetup -setdhcp \"#{service_name}\"" # 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
# Should map MAC to service, { "00C100A1B2C3" => "Thunderbolt Ethernet" }
mac_service_map[naked_mac] = interface_map[interface]
end end
machine.communicate.sudo(command)
end end
File.delete(tmp_hw)
mac_service_map
end end
end 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 module GuestDebian
class Guest < Vagrant.plugin("2", :guest) class Guest < Vagrant.plugin("2", :guest)
def detect?(machine) 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 end
end end

View File

@ -30,6 +30,11 @@ module VagrantPlugins
require_relative "cap/rsync" require_relative "cap/rsync"
Cap::RSync Cap::RSync
end end
guest_capability("debian", "smb_install") do
require_relative "cap/smb"
Cap::SMB
end
end end
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 def update_etc_hosts
ip_address = '([0-9]{1,3}\.){3}[0-9]{1,3}' ip_address = '([0-9]{1,3}\.){3}[0-9]{1,3}'
search = "^(#{ip_address})\\s+#{Regexp.escape(current_hostname)}(\\s.*)?$" 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('@') expression = ['s', search, replace, 'g'].join('@')
sudo("sed -ri '#{expression}' /etc/hosts") sudo("sed -ri '#{expression}' /etc/hosts")
@ -72,4 +72,4 @@ module VagrantPlugins
end end
end end
end end
end end

View File

@ -109,13 +109,23 @@ module VagrantPlugins
# SSH never dies. # SSH never dies.
interfaces.each do |interface| interfaces.each do |interface|
retryable(on: Vagrant::Errors::VagrantError, tries: 3, sleep: 2) do 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(<<-SCRIPT, error_check: true)
machine.communicate.sudo("! which nmcli >/dev/null 2>&1 || nmcli c reload #{interface}") cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-#{interface}
machine.communicate.sudo("/sbin/ifdown #{interface}", error_check: true)
machine.communicate.sudo("/sbin/ifup #{interface}")
end
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 end
end end

View File

@ -4,7 +4,7 @@ module VagrantPlugins
module GuestFedora module GuestFedora
class Guest < Vagrant.plugin("2", :guest) class Guest < Vagrant.plugin("2", :guest)
def detect?(machine) 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 end
end end

View File

@ -33,10 +33,11 @@ module VagrantPlugins
end end
# Emit an upstart event if we can # 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 <<-SCRIPT
machine.communicate.sudo( 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}") /sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT='#{expanded_guest_path}'
end fi
SCRIPT
end end
end end
end end

View File

@ -24,17 +24,14 @@ module VagrantPlugins
mount_gid = "`getent group #{options[:group]} | cut -d: -f3`" mount_gid = "`getent group #{options[:group]} | cut -d: -f3`"
mount_gid_old = "`id -g #{options[:group]}`" mount_gid_old = "`id -g #{options[:group]}`"
end end
smb_password = Shellwords.shellescape(options[:smb_password])
# If a domain is provided in the username, separate it # If a domain is provided in the username, separate it
username, domain = (options[:smb_username] || '').split('@', 2) username, domain = (options[:smb_username] || '').split('@', 2)
smb_password = options[:smb_password]
options[:mount_options] ||= [] options[:mount_options] ||= []
options[:mount_options] << "sec=ntlm" options[:mount_options] << "sec=ntlm"
options[:mount_options] << "username=#{username}" options[:mount_options] << "credentials=/etc/smb_creds_#{name}"
options[:mount_options] << "password=#{smb_password}"
options[:mount_options] << "domain=#{domain}" if domain
# First mount command uses getent to get the group # First mount command uses getent to get the group
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}" mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}"
@ -49,6 +46,16 @@ module VagrantPlugins
# Create the guest path if it doesn't exist # Create the guest path if it doesn't exist
machine.communicate.sudo("mkdir -p #{expanded_guest_path}") 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 # Attempt to mount the folder. We retry here a few times because
# it can fail early on. # it can fail early on.
attempts = 0 attempts = 0
@ -86,10 +93,11 @@ module VagrantPlugins
end end
# Emit an upstart event if we can # 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 <<-SCRIPT
machine.communicate.sudo( 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}") /sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT='#{expanded_guest_path}'
end fi
SCRIPT
end end
end end
end end

View File

@ -80,10 +80,11 @@ module VagrantPlugins
end end
# Emit an upstart event if we can # 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 <<-SCRIPT
machine.communicate.sudo( 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}") /sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT='#{expanded_guest_path}'
end fi
SCRIPT
end end
def self.unmount_virtualbox_shared_folder(machine, guestpath, options) def self.unmount_virtualbox_shared_folder(machine, guestpath, options)

View File

@ -10,8 +10,11 @@ module VagrantPlugins
machine.communicate.tap do |comm| machine.communicate.tap do |comm|
if comm.test("test -f ~/.ssh/authorized_keys") if comm.test("test -f ~/.ssh/authorized_keys")
comm.execute( comm.execute(<<SCRIPT)
"sed -i '/^.*#{contents}.*$/d' ~/.ssh/authorized_keys") 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 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" require_relative "cap/network_scripts_dir"
Cap::NetworkScriptsDir Cap::NetworkScriptsDir
end end
guest_capability("pld", "flavor") do
require_relative "cap/flavor"
Cap::Flavor
end
end end
end end
end end

View File

@ -3,7 +3,11 @@ module VagrantPlugins
module Cap module Cap
class NFSClient class NFSClient
def self.nfs_client_install(machine) def self.nfs_client_install(machine)
machine.communicate.sudo("yum -y install nfs-utils nfs-utils-lib") 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) restart_nfs(machine)
end end

View File

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

View File

@ -45,6 +45,10 @@ module VagrantPlugins
require_relative "cap/rsync" require_relative "cap/rsync"
Cap::RSync Cap::RSync
end end
def self.dnf?(machine)
machine.communicate.test("/usr/bin/which -s dnf")
end
end end
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 VagrantPlugins
module GuestDebian8 module GuestSlackware
class Guest < Vagrant.plugin("2", :guest) class Guest < Vagrant.plugin("2", :guest)
def detect?(machine) def detect?(machine)
machine.communicate.test("cat /etc/issue | grep 'Debian' | grep '8'") machine.communicate.test("cat /etc/slackware-version")
end end
end 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 end
def update_etc_hostname def update_etc_hostname
return super unless vivid? return super unless systemd?
sudo("hostnamectl set-hostname '#{short_hostname}'") sudo("hostnamectl set-hostname '#{short_hostname}'")
end end
@ -15,7 +15,7 @@ module VagrantPlugins
if hardy? if hardy?
# hostname.sh returns 1, so use `true` to get a 0 exitcode # hostname.sh returns 1, so use `true` to get a 0 exitcode
sudo("/etc/init.d/hostname.sh start; true") sudo("/etc/init.d/hostname.sh start; true")
elsif vivid? elsif systemd?
# Service runs via hostnamectl # Service runs via hostnamectl
else else
sudo("service hostname start") sudo("service hostname start")
@ -26,19 +26,25 @@ module VagrantPlugins
os_version("hardy") os_version("hardy")
end end
def vivid?
os_version("vivid")
end
def renew_dhcp def renew_dhcp
sudo("ifdown -a; ifup -a; ifup -a --allow=hotplug") sudo("ifdown -a; ifup -a; ifup -a --allow=hotplug")
end end
private 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) def os_version(name)
machine.communicate.test("[ `lsb_release -c -s` = #{name} ]") machine.communicate.test("[ `lsb_release -c -s` = #{name} ]")
end end
def systemd?
init_package == 'systemd'
end
end end
end end
end end

View File

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

View File

@ -2,8 +2,17 @@ module VagrantPlugins
module GuestWindows module GuestWindows
module Cap module Cap
class RSync 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) def self.rsync_pre(machine, opts)
machine.communicate.tap do |comm| 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]}'") comm.execute("mkdir '#{opts[:guestpath]}'")
end end
end end

View File

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

View File

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

View File

@ -2,6 +2,7 @@ require "pathname"
require "tempfile" require "tempfile"
require "vagrant/util/downloader" require "vagrant/util/downloader"
require "vagrant/util/file_checksum"
require "vagrant/util/subprocess" require "vagrant/util/subprocess"
module VagrantPlugins module VagrantPlugins
@ -10,8 +11,9 @@ module VagrantPlugins
class ProviderInstallVirtualBox class ProviderInstallVirtualBox
# The URL to download VirtualBox is hardcoded so we can have a # The URL to download VirtualBox is hardcoded so we can have a
# known-good version to download. # known-good version to download.
URL = "http://download.virtualbox.org/virtualbox/5.0.8/VirtualBox-5.0.8-103449-OSX.dmg".freeze URL = "http://download.virtualbox.org/virtualbox/5.0.10/VirtualBox-5.0.10-104061-OSX.dmg".freeze
VERSION = "5.0.8".freeze VERSION = "5.0.10".freeze
SHA256SUM = "62f933115498e51ddf5f2dab47dc1eebb42eb78ea1a7665cb91c53edacc847c6".freeze
def self.provider_install_virtualbox(env) def self.provider_install_virtualbox(env)
tf = Tempfile.new("vagrant") tf = Tempfile.new("vagrant")
@ -29,6 +31,15 @@ module VagrantPlugins
dl = Vagrant::Util::Downloader.new(URL, tf.path, ui: ui) dl = Vagrant::Util::Downloader.new(URL, tf.path, ui: ui)
dl.download! 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 # Launch it
ui.output(I18n.t( ui.output(I18n.t(
"vagrant.hosts.darwin.virtualbox_install_install")) "vagrant.hosts.darwin.virtualbox_install_install"))

View File

@ -5,17 +5,35 @@ module VagrantPlugins
module Cap module Cap
class RDP class RDP
def self.rdp_client(env, rdp_info) def self.rdp_client(env, rdp_info)
if !Vagrant::Util::Which.which("rdesktop") # Detect if an RDP client is available.
raise Vagrant::Errors::LinuxRDesktopNotFound # Prefer xfreerdp as it supports newer versions of RDP.
end rdp_client =
if Vagrant::Util::Which.which("xfreerdp")
"xfreerdp"
elsif Vagrant::Util::Which.which("rdesktop")
"rdesktop"
else
raise Vagrant::Errors::LinuxRDPClientNotFound
end
args = [] args = []
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]}"
Vagrant::Util::Subprocess.execute("rdesktop", *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
# Finally, run the client.
Vagrant::Util::Subprocess.execute(rdp_client, *args)
end end
end end
end end

View File

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

View File

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

View File

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

View File

@ -2,6 +2,8 @@ require "pathname"
require "tempfile" require "tempfile"
require "vagrant/util/downloader" require "vagrant/util/downloader"
require "vagrant/util/file_checksum"
require "vagrant/util/powershell"
require "vagrant/util/subprocess" require "vagrant/util/subprocess"
module VagrantPlugins module VagrantPlugins
@ -10,8 +12,9 @@ module VagrantPlugins
class ProviderInstallVirtualBox class ProviderInstallVirtualBox
# The URL to download VirtualBox is hardcoded so we can have a # The URL to download VirtualBox is hardcoded so we can have a
# known-good version to download. # known-good version to download.
URL = "http://download.virtualbox.org/virtualbox/5.0.8/VirtualBox-5.0.8-103449-Win.exe".freeze URL = "http://download.virtualbox.org/virtualbox/5.0.10/VirtualBox-5.0.10-104061-Win.exe".freeze
VERSION = "5.0.8".freeze VERSION = "5.0.10".freeze
SHA256SUM = "3e5ed8fe4ada6eef8dfb4fe6fd79fcab4b242acf799f7d3ab4a17b43838b1e04".freeze
def self.provider_install_virtualbox(env) def self.provider_install_virtualbox(env)
tf = Tempfile.new("vagrant") tf = Tempfile.new("vagrant")
@ -29,13 +32,22 @@ module VagrantPlugins
dl = Vagrant::Util::Downloader.new(URL, tf.path, ui: ui) dl = Vagrant::Util::Downloader.new(URL, tf.path, ui: ui)
dl.download! 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 # Launch it
ui.output(I18n.t( ui.output(I18n.t(
"vagrant.hosts.windows.virtualbox_install_install")) "vagrant.hosts.windows.virtualbox_install_install"))
ui.detail(I18n.t( ui.detail(I18n.t(
"vagrant.hosts.windows.virtualbox_install_install_detail")) "vagrant.hosts.windows.virtualbox_install_install_detail"))
script = File.expand_path("../../scripts/install_virtualbox.ps1", __FILE__) 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 if result.exit_code != 0
raise Vagrant::Errors::ProviderInstallFailed, raise Vagrant::Errors::ProviderInstallFailed,
provider: "virtualbox", 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" require_relative "cap/rdp"
Cap::RDP Cap::RDP
end end
host_capability("windows", "ps_client") do
require_relative "cap/ps"
Cap::PS
end
end end
end end
end end

View File

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

View File

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

View File

@ -416,7 +416,8 @@ module VagrantPlugins
host_ip: "127.0.0.1", host_ip: "127.0.0.1",
id: "winrm", id: "winrm",
auto_correct: true auto_correct: true
end
if !@__networks["forwarded_port-winrm-ssl"]
network :forwarded_port, network :forwarded_port,
guest: 5986, guest: 5986,
host: 55986, host: 55986,
@ -697,7 +698,7 @@ module VagrantPlugins
end end
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( machine.ui.warn(I18n.t(
"vagrant.config.vm.network_ip_ends_in_one")) "vagrant.config.vm.network_ip_ends_in_one"))
end end

View File

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

View File

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

View File

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

View File

@ -7,9 +7,19 @@ Param(
$Dir = Split-Path $script:MyInvocation.MyCommand.Path $Dir = Split-Path $script:MyInvocation.MyCommand.Path
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1")) . ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
$ip_address = ""
$vm = Get-VM -Id $VmId -ErrorAction "Stop" $vm = Get-VM -Id $VmId -ErrorAction "Stop"
$network = Get-VMNetworkAdapter -VM $vm $networks = Get-VMNetworkAdapter -VM $vm
$ip_address = $network.IpAddresses[0] 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 = @{ $resultHash = @{
ip = "$ip_address" ip = "$ip_address"
} }

View File

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

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