commit
6f5d1fc449
|
@ -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/*
|
||||||
|
|
186
CHANGELOG.md
186
CHANGELOG.md
|
@ -1,13 +1,187 @@
|
||||||
## Next Release
|
## Next Version (unreleased)
|
||||||
|
|
||||||
FEATURES:
|
|
||||||
|
|
||||||
IMPROVEMENTS:
|
|
||||||
|
|
||||||
BUG FIXES:
|
BUG FIXES:
|
||||||
|
|
||||||
|
- provisioners/ansible_local: Fix error in `playbook` existence check when
|
||||||
|
running on a Windows host [GH-6740]
|
||||||
|
|
||||||
|
## 1.8.1 (December 21, 2015)
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
|
||||||
|
- core: Don't create ".bundle" directory in pwd [GH-6717]
|
||||||
|
- core: Fix exception on installing VirtualBox [GH-6713]
|
||||||
|
- core: Do not convert standalone drive letters such as "D:" to
|
||||||
|
UNC paths [GH-6598]
|
||||||
|
- core: Fix a crash in parsing the config in some cases with network
|
||||||
|
configurations [GH-6730]
|
||||||
|
- commands/up: Smarter logic about what provider to install, avoiding
|
||||||
|
situations where VirtualBox was installed over the correct provider [GH-6731]
|
||||||
|
- guests/debian: Fix Docker install [GH-6722]
|
||||||
|
- provisioners/chef: convert chef version to a string before comparing for
|
||||||
|
the command builder [GH-6709, GH-6711]
|
||||||
|
- provisioners/shell: convert env var values to strings [GH-6714]
|
||||||
|
|
||||||
|
## 1.8.0 (December 21, 2015)
|
||||||
|
|
||||||
|
FEATURES:
|
||||||
|
|
||||||
|
- **New Command: `vagrant powershell`**: For machines that support it,
|
||||||
|
this will open a PowerShell prompt.
|
||||||
|
- **New Command: `vagrant port`**: For machines that support it, this will
|
||||||
|
display the list of forwarded ports from the guest to the host.
|
||||||
|
- **Linked Clones**: VirtualBox and VMware providers now support
|
||||||
|
linked clones for very fast (millisecond) imports on up. [GH-4484]
|
||||||
|
- **Snapshots**: The `vagrant snapshot` command can be used to checkpoint
|
||||||
|
and restore point-in-time snapshots.
|
||||||
|
- **IPv6 Private Networks**: Private networking now supports IPv6. This
|
||||||
|
only works with VirtualBox and VMware at this point. [GH-6342]
|
||||||
|
- New provisioner: `ansible_local` to execute Ansible from the guest
|
||||||
|
machine. [GH-2103]
|
||||||
|
|
||||||
|
BREAKING CHANGES:
|
||||||
|
|
||||||
|
- The `ansible` provisioner now can override the effective ansible remote user
|
||||||
|
(i.e. `ansible_ssh_user` setting) to always correspond to the vagrant ssh
|
||||||
|
username. This change is enabled by default, but we expect this to affect
|
||||||
|
only a tiny number of people as it corresponds to the common usage.
|
||||||
|
If you however use multiple remote usernames in your Ansible plays, tasks,
|
||||||
|
or custom inventories, you can simply set the option `force_remote_user` to
|
||||||
|
false to make Vagrant behave the same as before.
|
||||||
|
- provisioners/salt: the "config_dir" option has been removed. It has no
|
||||||
|
effect in Vagrant 1.8. [GH-6073]
|
||||||
|
|
||||||
|
IMPROVEMENTS:
|
||||||
|
|
||||||
|
- core: allow removal of all box versions with `--all` flag [GH-3462]
|
||||||
|
- core: prune entries from global status on non-existent cwd [GH-6535]
|
||||||
|
- core: networking: allow specifying a DHCP IP [GH-6325]
|
||||||
|
- core: run provisioner cleanup tasks before powering off the VM [GH-6553]
|
||||||
|
- core: only run provisioner cleanup tasks if they're implemented [GH-6603]
|
||||||
|
This improves UX, but wasn't a bug before.
|
||||||
|
- command/plugin: Add `--plugin-clean-sources` flag to reset plugin install
|
||||||
|
sources, primarily for corp firewalls. [GH-4738]
|
||||||
|
- command/rsync-auto: SSH connection is cached for faster sync times [GH-6399]
|
||||||
|
- command/up: provisioners are run on suspend resume [GH-5815]
|
||||||
|
- communicators/ssh: allow specifying host environment variables to forward
|
||||||
|
to guests [GH-4132, GH-6562]
|
||||||
|
- communicators/winrm: Configurable execution time limit [GH-6213]
|
||||||
|
- providers/virtualbox: cache version lookup, which caused significant
|
||||||
|
slowdown on some Windows hosts [GH-6552]
|
||||||
|
- providers/virtualbox: add `public_address` capability for virtualbox
|
||||||
|
[GH-6583, GH-5978]
|
||||||
|
- provisioners/chef: perform cleanup tasks on the guest instead of the host
|
||||||
|
- provisioners/chef: automatically generate a node_name if one was not given
|
||||||
|
[GH-6555]
|
||||||
|
- provisioners/chef: install Chef automatically on Windows [GH-6557]
|
||||||
|
- provisioners/chef: allow the user to specify the Chef product (such as
|
||||||
|
the Chef Development Kit) [GH-6557]
|
||||||
|
- provisioners/chef: allow data_bags_path to be an array [GH-5988, GH-6561]
|
||||||
|
- provisioners/shell: Support interactive mode for elevated PowerShell
|
||||||
|
scripts [GH-6185]
|
||||||
|
- provisioners/shell: add `env` option [GH-6588, GH-6516]
|
||||||
|
- provisioners/ansible+ansible_local: add support for ansible-galaxy [GH-2718]
|
||||||
|
- provisioners/ansible+ansible_local: add support for group and host variables
|
||||||
|
in the generated inventory [GH-6619]
|
||||||
|
- provisioners/ansible+ansible_local: add support for alphanumeric patterns
|
||||||
|
for groups in the generated inventory [GH-3539]
|
||||||
|
- provisioners/ansible: add support for WinRM settings [GH-5086]
|
||||||
|
- provisioners/ansible: add new `force_remote_user` option to control whether
|
||||||
|
`ansible_ssh_user` parameter should be applied or not [GH-6348]
|
||||||
|
- provisioners/ansible: show a warning when running from a Windows Host [GH-5292]
|
||||||
|
- pushes/local-exec: add support for specifying script args [GH-6661, GH-6660]
|
||||||
|
- guests/slackware: add support for networking [GH-6514]
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
|
||||||
|
- core: Ctrl-C weirdness fixed where it would exit parent process
|
||||||
|
before Vagrant finished cleaning up [GH-6085]
|
||||||
|
- core: DHCP network configurations don't warn on IP addresses ending
|
||||||
|
in ".1" [GH-6150]
|
||||||
|
- core: only append `access_token` when it does not exist in the URL
|
||||||
|
[GH-6395, GH-6534]
|
||||||
|
- core: use the correct private key when packaging a box [GH-6406]
|
||||||
|
- core: fix crash when using invalid box checksum type [GH-6327]
|
||||||
|
- core: don't check for metadata if the download URL is not HTTP [GH-6540]
|
||||||
|
- core: don't make custom dotfile path if there is no Vagrantfile [GH-6542]
|
||||||
|
- core: more robust check for admin privs on Windows [GH-5616]
|
||||||
|
- core: properly detect when HTTP server doesn't support byte ranges and
|
||||||
|
retry from scratch [GH-4479]
|
||||||
|
- core: line numbers show properly in Vagrantfile syntax errors
|
||||||
|
on Windows [GH-6445]
|
||||||
|
- core: catch errors setting env vars on Windows [GH-6017]
|
||||||
|
- core: remove cached synced folders when they're removed from the
|
||||||
|
Vagrantfile [GH-6567]
|
||||||
|
- core: use case-insensitive comparison for box checksum validations
|
||||||
|
[GH-6648, GH-6650]
|
||||||
|
- commands/box: add command with `~` paths on Windows works [GH-5747]
|
||||||
|
- commands/box: the update command supports CA settings [GH-4473]
|
||||||
|
- commands/box: removing all versions and providers of a box will properly
|
||||||
|
clean all directories in `~/.vagrant.d/boxes` [GH-3570]
|
||||||
|
- commands/box: outdated global won't halt on metadata download failure [GH-6453]
|
||||||
|
- commands/login: respect environment variables in `vagrant login` command
|
||||||
|
[GH-6590, GH-6422]
|
||||||
|
- commands/package: when re-packaging a packaged box, preserve the
|
||||||
|
generated SSH key [GH-5780]
|
||||||
|
- commands/plugin: retry plugin install automatically a few times to
|
||||||
|
avoid network issues [GH-6097]
|
||||||
|
- commands/rdp: prefer `xfreerdp` if it is available on Linux [GH-6475]
|
||||||
|
- commands/up: the `--provision-with` flag works with provisioner names [GH-5981]
|
||||||
|
- communicator/ssh: fix potential crash case with PTY [GH-6225]
|
||||||
|
- communicator/ssh: escape IdentityFile path [GH-6428, GH-6589]
|
||||||
|
- communicator/winrm: respect `boot_timeout` setting [GH-6229]
|
||||||
|
- communicator/winrm: execute scheduled tasks immediately on Windows XP
|
||||||
|
since elevation isn't required [GH-6195]
|
||||||
|
- communicator/winrm: Decouple default port forwarding rules for "winrm" and
|
||||||
|
"winrm-ssl" [GH-6581]
|
||||||
|
- communicator/winrm: Hide progress bars from PowerShell v5 [GH-6309]
|
||||||
|
- guests/arch: enable network device after setting it up [GH-5737]
|
||||||
|
- guests/darwin: advanced networking works with more NICs [GH-6386]
|
||||||
|
- guests/debian: graceful shutdown works properly with newer releases [GH-5986]
|
||||||
|
- guests/fedora: Preserve `localhost` entry when changing hostname [GH-6203]
|
||||||
|
- guests/fedora: Use dnf if it is available [GH-6288]
|
||||||
|
- guests/linux: when replacing a public SSH key, use POSIX-compliant
|
||||||
|
sed flags [GH-6565]
|
||||||
|
- guests/suse: DHCP network interfaces properly configured [GH-6502]
|
||||||
|
- hosts/slackware: Better detection of NFS [GH-6367]
|
||||||
|
- providers/hyper-v: support generation 2 VMs [GH-6372]
|
||||||
|
- providers/hyper-v: support VMs with more than one NIC [GH-4346]
|
||||||
|
- providers/hyper-v: check if user is in the Hyper-V admin group if
|
||||||
|
they're not a Windows admin [GH-6662]
|
||||||
|
- providers/virtualbox: ignore "Unknown" status bridge interfaces [GH-6061]
|
||||||
|
- providers/virtualbox: only fix ipv6 interfaces that are in use
|
||||||
|
[GH-6586, GH-6552]
|
||||||
- provisioners/ansible: use quotes for the `ansible_ssh_private_key_file`
|
- 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)
|
||||||
|
|
||||||
|
@ -17,6 +191,7 @@ BUG FIXES:
|
||||||
- communicators/ssh: use the same SSH args for `vagrant ssh` with and without
|
- communicators/ssh: use the same SSH args for `vagrant ssh` with and without
|
||||||
a command [GH-4986, GH-5928]
|
a command [GH-4986, GH-5928]
|
||||||
- guests/fedora: networks can be configured without nmcli [GH-5931]
|
- guests/fedora: networks can be configured without nmcli [GH-5931]
|
||||||
|
- guests/fedora: biosdevname can return 4 or 127 [GH-6139]
|
||||||
- guests/redhat: systemd detection should happen on guest [GH-5948]
|
- guests/redhat: systemd detection should happen on guest [GH-5948]
|
||||||
- guests/ubuntu: setting hostname fixed in 12.04 [GH-5937]
|
- guests/ubuntu: setting hostname fixed in 12.04 [GH-5937]
|
||||||
- hosts/linux: NFS can be configured without `$TMP` set on the host [GH-5954]
|
- hosts/linux: NFS can be configured without `$TMP` set on the host [GH-5954]
|
||||||
|
@ -2681,4 +2856,3 @@ compatibility.
|
||||||
The changelog began with version 0.5.1 so any changes prior to that
|
The changelog began with version 0.5.1 so any changes prior to that
|
||||||
can be seen by checking the tagged releases and reading git commit
|
can be seen by checking the tagged releases and reading git commit
|
||||||
messages.
|
messages.
|
||||||
|
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2010-2015 Mitchell Hashimoto
|
Copyright (c) 2010-2016 Mitchell Hashimoto
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
16
README.md
16
README.md
|
@ -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).
|
||||||
|
|
||||||
|
@ -53,13 +53,11 @@ Ruby 2.0 is needed.
|
||||||
|
|
||||||
## Contributing to Vagrant
|
## Contributing to Vagrant
|
||||||
|
|
||||||
### Dependencies and Unit Tests
|
To install Vagrant from source, please [follow the guide in the Wiki](https://github.com/mitchellh/vagrant/wiki/Installing-Vagrant-from-Source).
|
||||||
|
|
||||||
To hack on Vagrant, you'll need [bundler](http://github.com/carlhuda/bundler) which can
|
You can run the test suite with:
|
||||||
be installed with a simple `gem install bundler`. Afterwards, do the following:
|
|
||||||
|
|
||||||
bundle install
|
bundle exec rake
|
||||||
rake
|
|
||||||
|
|
||||||
This will run the unit test suite, which should come back all green! Then you're good to go!
|
This will run the unit test suite, which should come back all green! Then you're good to go!
|
||||||
|
|
||||||
|
|
|
@ -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`.
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -20,9 +20,11 @@ module Vagrant
|
||||||
autoload :HandleBox, "vagrant/action/builtin/handle_box"
|
autoload :HandleBox, "vagrant/action/builtin/handle_box"
|
||||||
autoload :HandleBoxUrl, "vagrant/action/builtin/handle_box_url"
|
autoload :HandleBoxUrl, "vagrant/action/builtin/handle_box_url"
|
||||||
autoload :HandleForwardedPortCollisions, "vagrant/action/builtin/handle_forwarded_port_collisions"
|
autoload :HandleForwardedPortCollisions, "vagrant/action/builtin/handle_forwarded_port_collisions"
|
||||||
|
autoload :IsEnvSet, "vagrant/action/builtin/is_env_set"
|
||||||
autoload :IsState, "vagrant/action/builtin/is_state"
|
autoload :IsState, "vagrant/action/builtin/is_state"
|
||||||
autoload :Lock, "vagrant/action/builtin/lock"
|
autoload :Lock, "vagrant/action/builtin/lock"
|
||||||
autoload :Message, "vagrant/action/builtin/message"
|
autoload :Message, "vagrant/action/builtin/message"
|
||||||
|
autoload :PrepareClone, "vagrant/action/builtin/prepare_clone"
|
||||||
autoload :Provision, "vagrant/action/builtin/provision"
|
autoload :Provision, "vagrant/action/builtin/provision"
|
||||||
autoload :ProvisionerCleanup, "vagrant/action/builtin/provisioner_cleanup"
|
autoload :ProvisionerCleanup, "vagrant/action/builtin/provisioner_cleanup"
|
||||||
autoload :SetHostname, "vagrant/action/builtin/set_hostname"
|
autoload :SetHostname, "vagrant/action/builtin/set_hostname"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -15,6 +15,7 @@ module Vagrant
|
||||||
box_provider = env[:box_provider]
|
box_provider = env[:box_provider]
|
||||||
box_provider = box_provider.to_sym if box_provider
|
box_provider = box_provider.to_sym if box_provider
|
||||||
box_version = env[:box_version]
|
box_version = env[:box_version]
|
||||||
|
box_remove_all_versions = env[:box_remove_all_versions]
|
||||||
|
|
||||||
boxes = {}
|
boxes = {}
|
||||||
env[:box_collection].all.each do |n, v, p|
|
env[:box_collection].all.each do |n, v, p|
|
||||||
|
@ -53,7 +54,7 @@ module Vagrant
|
||||||
if all_versions.length == 1
|
if all_versions.length == 1
|
||||||
# There is only one version, just use that.
|
# There is only one version, just use that.
|
||||||
box_version = all_versions.first
|
box_version = all_versions.first
|
||||||
else
|
elsif not box_remove_all_versions
|
||||||
# There are multiple versions, we can't choose.
|
# There are multiple versions, we can't choose.
|
||||||
raise Errors::BoxRemoveMultiVersion,
|
raise Errors::BoxRemoveMultiVersion,
|
||||||
name: box_name,
|
name: box_name,
|
||||||
|
@ -68,6 +69,10 @@ module Vagrant
|
||||||
versions: all_versions.sort.map { |k| " * #{k}" }.join("\n")
|
versions: all_versions.sort.map { |k| " * #{k}" }.join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
versions_to_remove = [box_version]
|
||||||
|
versions_to_remove = all_versions if box_remove_all_versions
|
||||||
|
|
||||||
|
versions_to_remove.sort.each do |version_to_remove|
|
||||||
box = env[:box_collection].find(
|
box = env[:box_collection].find(
|
||||||
box_name, box_provider, box_version)
|
box_name, box_provider, box_version)
|
||||||
|
|
||||||
|
@ -96,8 +101,8 @@ module Vagrant
|
||||||
|
|
||||||
result = env[:action_runner].run(stack, env)
|
result = env[:action_runner].run(stack, env)
|
||||||
if !result[:result]
|
if !result[:result]
|
||||||
# They said "no", so just return
|
# They said "no", so continue with the next box
|
||||||
return @app.call(env)
|
next
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -106,9 +111,11 @@ 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
|
||||||
|
end
|
||||||
|
|
||||||
@app.call(env)
|
@app.call(env)
|
||||||
end
|
end
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
module Vagrant
|
||||||
|
module Action
|
||||||
|
module Builtin
|
||||||
|
# This middleware is meant to be used with Call and can check if
|
||||||
|
# a variable in env is set.
|
||||||
|
class IsEnvSet
|
||||||
|
def initialize(app, env, key, **opts)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::action::builtin::is_env_set")
|
||||||
|
@key = key
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@logger.debug("Checking if env is set: '#{@key}'")
|
||||||
|
env[:result] = !!env[@key]
|
||||||
|
@logger.debug(" - Result: #{env[:result].inspect}")
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
require "log4r"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
module Action
|
||||||
|
module Builtin
|
||||||
|
class PrepareClone
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::action::vm::prepare_clone")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
# If we aren't cloning, then do nothing
|
||||||
|
if !env[:machine].config.vm.clone
|
||||||
|
return @app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
# We need to get the machine ID from this Vagrant environment
|
||||||
|
clone_env = env[:machine].env.environment(
|
||||||
|
env[:machine].config.vm.clone)
|
||||||
|
raise Errors::CloneNotFound if !clone_env.root_path
|
||||||
|
|
||||||
|
# Get the machine itself
|
||||||
|
clone_machine = clone_env.machine(
|
||||||
|
clone_env.primary_machine_name, env[:machine].provider_name)
|
||||||
|
raise Errors::CloneMachineNotFound if !clone_machine.id
|
||||||
|
|
||||||
|
# Set the ID of the master so we know what to clone from
|
||||||
|
env[:clone_id] = clone_machine.id
|
||||||
|
env[:clone_machine] = clone_machine
|
||||||
|
|
||||||
|
# Continue
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
||||||
|
# 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
|
p.cleanup
|
||||||
|
else
|
||||||
|
@logger.debug("Skipping cleanup tasks for `#{name}' - not defined")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -68,12 +69,16 @@ module Vagrant
|
||||||
# we add all our plugin dependencies.
|
# we add all our plugin dependencies.
|
||||||
@gemfile = build_gemfile(plugins)
|
@gemfile = build_gemfile(plugins)
|
||||||
|
|
||||||
|
Util::SafeEnv.change_env do |env|
|
||||||
# Set the environmental variables for Bundler
|
# Set the environmental variables for Bundler
|
||||||
ENV["BUNDLE_APP_CONFIG"] = @appconfigpath
|
env["BUNDLE_APP_CONFIG"] = @appconfigpath
|
||||||
ENV["BUNDLE_CONFIG"] = @configfile.path
|
env["BUNDLE_CONFIG"] = @configfile.path
|
||||||
ENV["BUNDLE_GEMFILE"] = @gemfile.path
|
env["BUNDLE_GEMFILE"] = @gemfile.path
|
||||||
ENV["GEM_PATH"] =
|
env["BUNDLE_RETRY"] = "3"
|
||||||
|
env["GEM_PATH"] =
|
||||||
"#{bundle_path}#{::File::PATH_SEPARATOR}#{@gem_path}"
|
"#{bundle_path}#{::File::PATH_SEPARATOR}#{@gem_path}"
|
||||||
|
end
|
||||||
|
|
||||||
Gem.clear_paths
|
Gem.clear_paths
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -178,11 +183,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}"])
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -9,6 +9,7 @@ require 'log4r'
|
||||||
|
|
||||||
require 'vagrant/util/file_mode'
|
require 'vagrant/util/file_mode'
|
||||||
require 'vagrant/util/platform'
|
require 'vagrant/util/platform'
|
||||||
|
require "vagrant/util/silence_warnings"
|
||||||
require "vagrant/vagrantfile"
|
require "vagrant/vagrantfile"
|
||||||
require "vagrant/version"
|
require "vagrant/version"
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ module Vagrant
|
||||||
# Setup the local data directory. If a configuration path is given,
|
# Setup the local data directory. If a configuration path is given,
|
||||||
# then it is expanded relative to the working directory. Otherwise,
|
# then it is expanded relative to the working directory. Otherwise,
|
||||||
# we use the default which is expanded relative to the root path.
|
# we use the default which is expanded relative to the root path.
|
||||||
opts[:local_data_path] ||= ENV["VAGRANT_DOTFILE_PATH"]
|
opts[:local_data_path] ||= ENV["VAGRANT_DOTFILE_PATH"] if !opts[:child]
|
||||||
opts[:local_data_path] ||= root_path.join(DEFAULT_LOCAL_DATA) if !root_path.nil?
|
opts[:local_data_path] ||= root_path.join(DEFAULT_LOCAL_DATA) if !root_path.nil?
|
||||||
if opts[:local_data_path]
|
if opts[:local_data_path]
|
||||||
@local_data_path = Pathname.new(File.expand_path(opts[:local_data_path], @cwd))
|
@local_data_path = Pathname.new(File.expand_path(opts[:local_data_path], @cwd))
|
||||||
|
@ -308,6 +309,7 @@ module Vagrant
|
||||||
def default_provider(**opts)
|
def default_provider(**opts)
|
||||||
opts[:exclude] = Set.new(opts[:exclude]) if opts[:exclude]
|
opts[:exclude] = Set.new(opts[:exclude]) if opts[:exclude]
|
||||||
opts[:force_default] = true if !opts.key?(:force_default)
|
opts[:force_default] = true if !opts.key?(:force_default)
|
||||||
|
opts[:check_usable] = true if !opts.key?(:check_usable)
|
||||||
|
|
||||||
default = ENV["VAGRANT_DEFAULT_PROVIDER"]
|
default = ENV["VAGRANT_DEFAULT_PROVIDER"]
|
||||||
default = nil if default == ""
|
default = nil if default == ""
|
||||||
|
@ -375,6 +377,7 @@ module Vagrant
|
||||||
|
|
||||||
# Find the matching implementation
|
# Find the matching implementation
|
||||||
ordered.each do |_, key, impl, _|
|
ordered.each do |_, key, impl, _|
|
||||||
|
return key if !opts[:check_usable]
|
||||||
return key if impl.usable?(false)
|
return key if impl.usable?(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -382,6 +385,26 @@ module Vagrant
|
||||||
raise Errors::NoDefaultProvider
|
raise Errors::NoDefaultProvider
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns whether or not we know how to install the provider with
|
||||||
|
# the given name.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
def can_install_provider?(name)
|
||||||
|
host.capability?(provider_install_key(name))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Installs the provider with the given name.
|
||||||
|
#
|
||||||
|
# This will raise an exception if we don't know how to install the
|
||||||
|
# provider with the given name. You should guard this call with
|
||||||
|
# `can_install_provider?` for added safety.
|
||||||
|
#
|
||||||
|
# An exception will be raised if there are any failures installing
|
||||||
|
# the provider.
|
||||||
|
def install_provider(name)
|
||||||
|
host.capability(provider_install_key(name))
|
||||||
|
end
|
||||||
|
|
||||||
# Returns the collection of boxes for the environment.
|
# Returns the collection of boxes for the environment.
|
||||||
#
|
#
|
||||||
# @return [BoxCollection]
|
# @return [BoxCollection]
|
||||||
|
@ -413,6 +436,28 @@ module Vagrant
|
||||||
@config_loader
|
@config_loader
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Loads another environment for the given Vagrantfile, sharing as much
|
||||||
|
# useful state from this Environment as possible (such as UI and paths).
|
||||||
|
# Any initialization options can be overidden using the opts hash.
|
||||||
|
#
|
||||||
|
# @param [String] vagrantfile Path to a Vagrantfile
|
||||||
|
# @return [Environment]
|
||||||
|
def environment(vagrantfile, **opts)
|
||||||
|
path = File.expand_path(vagrantfile, root_path)
|
||||||
|
file = File.basename(path)
|
||||||
|
path = File.dirname(path)
|
||||||
|
|
||||||
|
Util::SilenceWarnings.silence! do
|
||||||
|
Environment.new({
|
||||||
|
child: true,
|
||||||
|
cwd: path,
|
||||||
|
home_path: home_path,
|
||||||
|
ui_class: ui_class,
|
||||||
|
vagrantfile_name: file,
|
||||||
|
}.merge(opts))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This defines a hook point where plugin action hooks that are registered
|
# This defines a hook point where plugin action hooks that are registered
|
||||||
# against the given name will be run in the context of this environment.
|
# against the given name will be run in the context of this environment.
|
||||||
#
|
#
|
||||||
|
@ -526,7 +571,13 @@ module Vagrant
|
||||||
if name != "dotlock"
|
if name != "dotlock"
|
||||||
lock("dotlock", retry: true) do
|
lock("dotlock", retry: true) do
|
||||||
f.close
|
f.close
|
||||||
|
begin
|
||||||
File.delete(lock_path)
|
File.delete(lock_path)
|
||||||
|
rescue
|
||||||
|
@logger.error(
|
||||||
|
"Failed to delete lock file #{lock_path} - some other thread " +
|
||||||
|
"might be trying to acquire it. ignoring this error")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -781,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
|
||||||
|
@ -796,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)
|
||||||
|
@ -854,6 +908,12 @@ module Vagrant
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the key used for the host capability for provider installs
|
||||||
|
# of the given name.
|
||||||
|
def provider_install_key(name)
|
||||||
|
"provider_install_#{name}".to_sym
|
||||||
|
end
|
||||||
|
|
||||||
# This upgrades a home directory that was in the v1.1 format to the
|
# This upgrades a home directory that was in the v1.1 format to the
|
||||||
# v1.5 format. It will raise exceptions if anything fails.
|
# v1.5 format. It will raise exceptions if anything fails.
|
||||||
def upgrade_home_path_v1_1
|
def upgrade_home_path_v1_1
|
||||||
|
@ -908,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")
|
||||||
|
|
|
@ -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
|
||||||
|
@ -288,6 +284,14 @@ module Vagrant
|
||||||
error_key(:cli_invalid_options)
|
error_key(:cli_invalid_options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class CloneNotFound < VagrantError
|
||||||
|
error_key(:clone_not_found)
|
||||||
|
end
|
||||||
|
|
||||||
|
class CloneMachineNotFound < VagrantError
|
||||||
|
error_key(:clone_machine_not_found)
|
||||||
|
end
|
||||||
|
|
||||||
class CommandUnavailable < VagrantError
|
class CommandUnavailable < VagrantError
|
||||||
error_key(:command_unavailable)
|
error_key(:command_unavailable)
|
||||||
end
|
end
|
||||||
|
@ -340,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
|
||||||
|
@ -400,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
|
||||||
|
@ -512,6 +520,18 @@ module Vagrant
|
||||||
error_key(:requires_directory, "vagrant.actions.general.package")
|
error_key(:requires_directory, "vagrant.actions.general.package")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class ProviderCantInstall < VagrantError
|
||||||
|
error_key(:provider_cant_install)
|
||||||
|
end
|
||||||
|
|
||||||
|
class ProviderChecksumMismatch < VagrantError
|
||||||
|
error_key(:provider_checksum_mismatch)
|
||||||
|
end
|
||||||
|
|
||||||
|
class ProviderInstallFailed < VagrantError
|
||||||
|
error_key(:provider_install_failed)
|
||||||
|
end
|
||||||
|
|
||||||
class ProviderNotFound < VagrantError
|
class ProviderNotFound < VagrantError
|
||||||
error_key(:provider_not_found)
|
error_key(:provider_not_found)
|
||||||
end
|
end
|
||||||
|
@ -784,6 +804,14 @@ module Vagrant
|
||||||
error_key(:boot_timeout)
|
error_key(:boot_timeout)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class VMCloneFailure < VagrantError
|
||||||
|
error_key(:failure, "vagrant.actions.vm.clone")
|
||||||
|
end
|
||||||
|
|
||||||
|
class VMCreateMasterFailure < VagrantError
|
||||||
|
error_key(:failure, "vagrant.actions.vm.clone.create_master")
|
||||||
|
end
|
||||||
|
|
||||||
class VMCustomizationFailed < VagrantError
|
class VMCustomizationFailed < VagrantError
|
||||||
error_key(:failure, "vagrant.actions.vm.customize")
|
error_key(:failure, "vagrant.actions.vm.customize")
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
begin
|
||||||
env = entry.vagrant_env(
|
env = entry.vagrant_env(
|
||||||
@env.home_path, ui_class: @env.ui_class)
|
@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
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,21 @@ module Vagrant
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This is called early, before a machine is instantiated, to check
|
||||||
|
# if this provider is installed. This should return true or false.
|
||||||
|
#
|
||||||
|
# If the provider is not installed and Vagrant determines it is
|
||||||
|
# able to install this provider, then it will do so. Installation
|
||||||
|
# is done by calling Environment.install_provider.
|
||||||
|
#
|
||||||
|
# If Environment.can_install_provider? returns false, then an error
|
||||||
|
# will be shown to the user.
|
||||||
|
def self.installed?
|
||||||
|
# By default return true for backwards compat so all providers
|
||||||
|
# continue to work.
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
# Initialize the provider to represent the given machine.
|
# Initialize the provider to represent the given machine.
|
||||||
#
|
#
|
||||||
# @param [Vagrant::Machine] machine The machine that this provider
|
# @param [Vagrant::Machine] machine The machine that this provider
|
||||||
|
|
|
@ -103,6 +103,12 @@ module Vagrant
|
||||||
raise Errors::UIExpectsTTY
|
raise Errors::UIExpectsTTY
|
||||||
end
|
end
|
||||||
|
|
||||||
|
[:detail, :warn, :error, :info, :output, :success].each do |method|
|
||||||
|
define_method(method) do |message, *args, **opts|
|
||||||
|
machine("ui", method.to_s, message, *args, **opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def machine(type, *data)
|
def machine(type, *data)
|
||||||
opts = {}
|
opts = {}
|
||||||
opts = data.pop if data.last.kind_of?(Hash)
|
opts = data.pop if data.last.kind_of?(Hash)
|
||||||
|
@ -117,9 +123,12 @@ module Vagrant
|
||||||
data[i].gsub!("\r", "\\r")
|
data[i].gsub!("\r", "\\r")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Avoid locks in a trap context introduced from Ruby 2.0
|
||||||
|
Thread.new do
|
||||||
@lock.synchronize do
|
@lock.synchronize do
|
||||||
safe_puts("#{Time.now.utc.to_i},#{target},#{type},#{data.join(",")}")
|
safe_puts("#{Time.now.utc.to_i},#{target},#{type},#{data.join(",")}")
|
||||||
end
|
end
|
||||||
|
end.join
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -150,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 ||= {}
|
||||||
|
@ -271,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
|
||||||
|
@ -313,6 +325,7 @@ module Vagrant
|
||||||
|
|
||||||
target = @prefix
|
target = @prefix
|
||||||
target = opts[:target] if opts.key?(:target)
|
target = opts[:target] if opts.key?(:target)
|
||||||
|
target = "#{target}:" if target != ""
|
||||||
|
|
||||||
# Get the lines. The first default is because if the message
|
# Get the lines. The first default is because if the message
|
||||||
# is an empty string, then we want to still use the empty string.
|
# is an empty string, then we want to still use the empty string.
|
||||||
|
@ -321,7 +334,7 @@ module Vagrant
|
||||||
|
|
||||||
# Otherwise, make sure to prefix every line properly
|
# Otherwise, make sure to prefix every line properly
|
||||||
lines.map do |line|
|
lines.map do |line|
|
||||||
"#{prefix}#{target}: #{line}"
|
"#{prefix}#{target} #{line}"
|
||||||
end.join("\n")
|
end.join("\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
|
require "ipaddr"
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module Util
|
module Util
|
||||||
module NetworkIP
|
module NetworkIP
|
||||||
# Returns the network address of the given IP and subnet.
|
# Returns the network address of the given IP and subnet.
|
||||||
#
|
#
|
||||||
|
# If the IP address is an IPv6 address, subnet should be a prefix
|
||||||
|
# length such as "64".
|
||||||
|
#
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def network_address(ip, subnet)
|
def network_address(ip, subnet)
|
||||||
|
# If this is an IPv6 address, then just mask it
|
||||||
|
if subnet.to_s =~ /^\d+$/
|
||||||
|
ip = IPAddr.new(ip)
|
||||||
|
return ip.mask(subnet.to_i).to_s
|
||||||
|
end
|
||||||
|
|
||||||
ip = ip_parts(ip)
|
ip = ip_parts(ip)
|
||||||
netmask = ip_parts(subnet)
|
netmask = ip_parts(subnet)
|
||||||
|
|
||||||
|
|
|
@ -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?
|
||||||
|
@ -148,6 +185,12 @@ module Vagrant
|
||||||
# @param [String] path Path to convert to UNC for Windows
|
# @param [String] path Path to convert to UNC for Windows
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def windows_unc_path(path)
|
def windows_unc_path(path)
|
||||||
|
path = path.gsub("/", "\\")
|
||||||
|
|
||||||
|
# If the path is just a drive letter, then return that as-is
|
||||||
|
return path if path =~ /^[a-zA-Z]:\\?$/
|
||||||
|
|
||||||
|
# Convert to UNC path
|
||||||
"\\\\?\\" + path.gsub("/", "\\")
|
"\\\\?\\" + path.gsub("/", "\\")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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"),
|
||||||
|
|
|
@ -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
|
|
@ -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,
|
||||||
|
|
|
@ -27,6 +27,10 @@ module VagrantPlugins
|
||||||
"The specific version of the box to remove") do |v|
|
"The specific version of the box to remove") do |v|
|
||||||
options[:version] = v
|
options[:version] = v
|
||||||
end
|
end
|
||||||
|
|
||||||
|
o.on("--all", "Remove all available versions of the box") do |a|
|
||||||
|
options[:all] = a
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse the options
|
# Parse the options
|
||||||
|
@ -50,6 +54,7 @@ module VagrantPlugins
|
||||||
box_provider: options[:provider],
|
box_provider: options[:provider],
|
||||||
box_version: options[:version],
|
box_version: options[:version],
|
||||||
force_confirm_box_remove: options[:force],
|
force_confirm_box_remove: options[:force],
|
||||||
|
box_remove_all_versions: options[:all],
|
||||||
})
|
})
|
||||||
|
|
||||||
# Success, exit status 0
|
# Success, exit status 0
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandCap
|
||||||
|
class Command < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"checks and executes capability"
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
options[:check] = false
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cap [options] TYPE NAME [args]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "This is an advanced command. If you don't know what this"
|
||||||
|
o.separator "does and you aren't explicitly trying to use it, you probably"
|
||||||
|
o.separator "don't want to use this."
|
||||||
|
o.separator ""
|
||||||
|
o.separator "This command checks or executes arbitrary capabilities that"
|
||||||
|
o.separator "Vagrant has for hosts, guests, and providers."
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("--check", "Only checks for a capability, does not execute") do |f|
|
||||||
|
options[:check] = f
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.length < 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
type = argv.shift.to_sym
|
||||||
|
name = argv.shift.to_sym
|
||||||
|
|
||||||
|
# Get the proper capability host to check
|
||||||
|
cap_host = nil
|
||||||
|
if type == :host
|
||||||
|
cap_host = @env.host
|
||||||
|
else
|
||||||
|
with_target_vms([]) do |vm|
|
||||||
|
cap_host = case type
|
||||||
|
when :provider
|
||||||
|
vm.provider
|
||||||
|
when :guest
|
||||||
|
vm.guest
|
||||||
|
else
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we're just checking, then just return exit codes
|
||||||
|
if options[:check]
|
||||||
|
return 0 if cap_host.capability?(name)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# Otherwise, call it
|
||||||
|
cap_host.capability(name, *argv)
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,17 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandCap
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "cap command"
|
||||||
|
description <<-DESC
|
||||||
|
The `cap` command checks and executes arbitrary capabilities.
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command("cap", primary: false) do
|
||||||
|
require_relative "command"
|
||||||
|
Command
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -0,0 +1,74 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandProvider
|
||||||
|
class Command < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"show provider for this environment"
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
options[:install] = false
|
||||||
|
options[:usable] = false
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant provider [options] [args]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "This command interacts with the provider for this environment."
|
||||||
|
o.separator "With no arguments, it'll output the default provider for this"
|
||||||
|
o.separator "environment."
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("--install", "Installs the provider if possible") do |f|
|
||||||
|
options[:install] = f
|
||||||
|
end
|
||||||
|
|
||||||
|
o.on("--usable", "Checks if the named provider is usable") do |f|
|
||||||
|
options[:usable] = f
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
# Get the machine
|
||||||
|
machine = nil
|
||||||
|
with_target_vms(argv, single_target: true) do |m|
|
||||||
|
machine = m
|
||||||
|
end
|
||||||
|
|
||||||
|
# Output some machine readable stuff
|
||||||
|
@env.ui.machine("provider-name", machine.provider_name, target: machine.name.to_s)
|
||||||
|
|
||||||
|
# Check if we're just doing a usability check
|
||||||
|
if options[:usable]
|
||||||
|
@env.ui.output(machine.provider_name.to_s)
|
||||||
|
return 0 if machine.provider.class.usable?(false)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if we're requesting installation
|
||||||
|
if options[:install]
|
||||||
|
key = "provider_install_#{machine.provider_name}".to_sym
|
||||||
|
if !@env.host.capability?(key)
|
||||||
|
raise Vagrant::Errors::ProviderCantInstall,
|
||||||
|
provider: machine.provider_name.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.host.capability(key)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# No subtask, just output the provider name
|
||||||
|
@env.ui.output(machine.provider_name.to_s)
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,18 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandProvider
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "provider command"
|
||||||
|
description <<-DESC
|
||||||
|
The `provider` command is used to interact with the various providers
|
||||||
|
that are installed with Vagrant.
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command("provider", primary: false) do
|
||||||
|
require_relative "command"
|
||||||
|
Command
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
||||||
|
|
|
@ -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 = []
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Delete < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot delete [options] [vm-name] <name>"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Delete a snapshot taken previously with snapshot save."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
name = argv.pop
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
vm.action(:snapshot_delete, snapshot_name: name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,47 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class List < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot list [options] [vm-name]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "List all snapshots taken for a machine."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
if !vm.id
|
||||||
|
vm.ui.info(I18n.t("vagrant.commands.common.vm_not_created"))
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
if !vm.provider.capability?(:snapshot_list)
|
||||||
|
vm.ui.info(I18n.t("vagrant.commands.snapshot.not_supported"))
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
snapshots = vm.provider.capability(:snapshot_list)
|
||||||
|
if snapshots.empty?
|
||||||
|
vm.ui.output(I18n.t("vagrant.actions.vm.snapshot.list_none"))
|
||||||
|
vm.ui.detail(I18n.t("vagrant.actions.vm.snapshot.list_none_detail"))
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
snapshots.each do |snapshot|
|
||||||
|
vm.ui.output(snapshot, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,28 @@
|
||||||
|
require 'json'
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
require_relative "push_shared"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Pop < Vagrant.plugin("2", :command)
|
||||||
|
include PushShared
|
||||||
|
|
||||||
|
def execute
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot pop [options] [vm-name]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Restore state that was pushed with `vagrant snapshot push`."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
return shared_exec(argv, method(:pop))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,33 @@
|
||||||
|
require 'json'
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
require_relative "push_shared"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Push < Vagrant.plugin("2", :command)
|
||||||
|
include PushShared
|
||||||
|
|
||||||
|
def execute
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot push [options] [vm-name]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Take a snapshot of the current state of the machine and 'push'"
|
||||||
|
o.separator "it onto the stack of states. You can use `vagrant snapshot pop`"
|
||||||
|
o.separator "to restore back to this state at any time."
|
||||||
|
o.separator ""
|
||||||
|
o.separator "If you use `vagrant snapshot save` or restore at any point after"
|
||||||
|
o.separator "a push, pop will still bring you back to this pushed state."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
return shared_exec(argv, method(:push))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,57 @@
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
module PushShared
|
||||||
|
def shared_exec(argv, m)
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
if !vm.id
|
||||||
|
vm.ui.info("Not created. Cannot push snapshot state.")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
vm.env.lock("machine-snapshot-stack") do
|
||||||
|
m.call(vm)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit with 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
|
||||||
|
def push(machine)
|
||||||
|
snapshot_name = "push_#{Time.now.to_i}_#{rand(10000)}"
|
||||||
|
|
||||||
|
# Save the snapshot. This will raise an exception if it fails.
|
||||||
|
machine.action(:snapshot_save, snapshot_name: snapshot_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pop(machine)
|
||||||
|
# By reverse sorting, we should be able to find the first
|
||||||
|
# pushed snapshot.
|
||||||
|
name = nil
|
||||||
|
snapshots = machine.provider.capability(:snapshot_list)
|
||||||
|
snapshots.sort.reverse.each do |snapshot|
|
||||||
|
if snapshot =~ /^push_\d+_\d+$/
|
||||||
|
name = snapshot
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If no snapshot was found, we never pushed
|
||||||
|
if !name
|
||||||
|
machine.ui.info(I18n.t("vagrant.commands.snapshot.no_push_snapshot"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Restore the snapshot and tell the provider to delete it as well.
|
||||||
|
machine.action(
|
||||||
|
:snapshot_restore,
|
||||||
|
snapshot_name: name,
|
||||||
|
snapshot_delete: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,35 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Restore < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot restore [options] [vm-name] <name>"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Restore a snapshot taken previously with snapshot save."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
name = argv.pop
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
vm.action(:snapshot_restore, snapshot_name: name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,89 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Root < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"manages snapshots: saving, restoring, etc."
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(argv, env)
|
||||||
|
super
|
||||||
|
|
||||||
|
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||||
|
|
||||||
|
@subcommands = Vagrant::Registry.new
|
||||||
|
@subcommands.register(:save) do
|
||||||
|
require_relative "save"
|
||||||
|
Save
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:restore) do
|
||||||
|
require_relative "restore"
|
||||||
|
Restore
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:delete) do
|
||||||
|
require_relative "delete"
|
||||||
|
Delete
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:list) do
|
||||||
|
require_relative "list"
|
||||||
|
List
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:push) do
|
||||||
|
require_relative "push"
|
||||||
|
Push
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:pop) do
|
||||||
|
require_relative "pop"
|
||||||
|
Pop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
if @main_args.include?("-h") || @main_args.include?("--help")
|
||||||
|
# Print the help for all the commands.
|
||||||
|
return help
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we reached this far then we must have a subcommand. If not,
|
||||||
|
# then we also just print the help and exit.
|
||||||
|
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||||
|
return help if !command_class || !@sub_command
|
||||||
|
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
||||||
|
|
||||||
|
# Initialize and execute the command class
|
||||||
|
command_class.new(@sub_args, @env).execute
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prints the help out for this command
|
||||||
|
def help
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: vagrant snapshot <subcommand> [<args>]"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Available subcommands:"
|
||||||
|
|
||||||
|
# Add the available subcommands as separators in order to print them
|
||||||
|
# out as well.
|
||||||
|
keys = []
|
||||||
|
@subcommands.each { |key, value| keys << key.to_s }
|
||||||
|
|
||||||
|
keys.sort.each do |key|
|
||||||
|
opts.separator " #{key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For help on any individual subcommand run `vagrant snapshot <subcommand> -h`"
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.info(opts.help, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Save < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot save [options] [vm-name] <name>"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Take a snapshot of the current state of the machine. The snapshot"
|
||||||
|
o.separator "can be restored via `vagrant snapshot restore` at any point in the"
|
||||||
|
o.separator "future to get back to this exact machine state."
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Snapshots are useful for experimenting in a machine and being able"
|
||||||
|
o.separator "to rollback quickly."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
name = argv.pop
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
vm.action(:snapshot_save, snapshot_name: name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,15 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "snapshot command"
|
||||||
|
description "The `snapshot` command gives you a way to manage snapshots."
|
||||||
|
|
||||||
|
command("snapshot") do
|
||||||
|
require_relative "command/root"
|
||||||
|
Command::Root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
require 'optparse'
|
require 'optparse'
|
||||||
|
require 'set'
|
||||||
|
|
||||||
require "vagrant"
|
require "vagrant"
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ module VagrantPlugins
|
||||||
def execute
|
def execute
|
||||||
options = {}
|
options = {}
|
||||||
options[:destroy_on_error] = true
|
options[:destroy_on_error] = true
|
||||||
|
options[:install_provider] = true
|
||||||
options[:parallel] = true
|
options[:parallel] = true
|
||||||
options[:provision_ignore_sentinel] = false
|
options[:provision_ignore_sentinel] = false
|
||||||
|
|
||||||
|
@ -41,6 +43,11 @@ module VagrantPlugins
|
||||||
"Back the machine with a specific provider") do |provider|
|
"Back the machine with a specific provider") do |provider|
|
||||||
options[:provider] = provider
|
options[:provider] = provider
|
||||||
end
|
end
|
||||||
|
|
||||||
|
o.on("--[no-]install-provider",
|
||||||
|
"If possible, install the provider if it isn't installed") do |p|
|
||||||
|
options[:install_provider] = p
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parse the options
|
# Parse the options
|
||||||
|
@ -48,14 +55,12 @@ 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...")
|
||||||
|
|
||||||
# Build up the batch job of what we'll do
|
# Get the names of the machines we want to bring up
|
||||||
machines = []
|
|
||||||
@env.batch(options[:parallel]) do |batch|
|
|
||||||
names = argv
|
names = argv
|
||||||
if names.empty?
|
if names.empty?
|
||||||
autostart = false
|
autostart = false
|
||||||
|
@ -70,7 +75,17 @@ module VagrantPlugins
|
||||||
names = nil if autostart && names.empty?
|
names = nil if autostart && names.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Build up the batch job of what we'll do
|
||||||
|
machines = []
|
||||||
if names
|
if names
|
||||||
|
# If we're installing providers, then do that. We don't
|
||||||
|
# parallelize this step because it is likely the same provider
|
||||||
|
# anyways.
|
||||||
|
if options[:install_provider]
|
||||||
|
install_providers(names, provider: options[:provider])
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.batch(options[:parallel]) do |batch|
|
||||||
with_target_vms(names, provider: options[:provider]) do |machine|
|
with_target_vms(names, provider: options[:provider]) do |machine|
|
||||||
@env.ui.info(I18n.t(
|
@env.ui.info(I18n.t(
|
||||||
"vagrant.commands.up.upping",
|
"vagrant.commands.up.upping",
|
||||||
|
@ -106,6 +121,64 @@ module VagrantPlugins
|
||||||
# Success, exit status 0
|
# Success, exit status 0
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def install_providers(names, provider: nil)
|
||||||
|
# First create a set of all the providers we need to check for.
|
||||||
|
# Most likely this will be a set of one.
|
||||||
|
providers = Set.new
|
||||||
|
names.each do |name|
|
||||||
|
# Check if we have this machine in the index
|
||||||
|
entry = @env.machine_index.get(name.to_s)
|
||||||
|
|
||||||
|
# Get the provider for this machine. This logic isn't completely
|
||||||
|
# straightforward. If we have a forced provider, we always use
|
||||||
|
# that no matter what. If we have an entry in the index (meaning
|
||||||
|
# the machine may be created), we use that provider no matter
|
||||||
|
# what since that will be used by the core. If we have none, then
|
||||||
|
# we ask the Vagrant env what the default provider would be and use
|
||||||
|
# that.
|
||||||
|
#
|
||||||
|
# Note that this logic is a bit redundant if we have "provider"
|
||||||
|
# set but I think its probably cleaner to put this logic in one
|
||||||
|
# place.
|
||||||
|
p = provider
|
||||||
|
p = entry.provider.to_sym if !p && entry
|
||||||
|
p = @env.default_provider(
|
||||||
|
machine: name.to_sym, check_usable: false) if !p
|
||||||
|
|
||||||
|
# Add it to the set
|
||||||
|
providers.add(p)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Go through and determine if we can install the providers
|
||||||
|
providers.delete_if do |name|
|
||||||
|
!@env.can_install_provider?(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Install the providers if we have to
|
||||||
|
providers.each do |name|
|
||||||
|
# Find the provider. Ignore if we can't find it, this error
|
||||||
|
# will pop up later in the process.
|
||||||
|
parts = Vagrant.plugin("2").manager.providers[name]
|
||||||
|
next if !parts
|
||||||
|
|
||||||
|
# If the provider is already installed, then our work here is done
|
||||||
|
cls = parts[0]
|
||||||
|
next if cls.installed?
|
||||||
|
|
||||||
|
# Some human-friendly output
|
||||||
|
ui = Vagrant::UI::Prefixed.new(@env.ui, "")
|
||||||
|
ui.output(I18n.t(
|
||||||
|
"vagrant.installing_provider",
|
||||||
|
provider: name.to_s))
|
||||||
|
ui.detail(I18n.t("vagrant.installing_provider_detail"))
|
||||||
|
|
||||||
|
# Install the provider
|
||||||
|
@env.install_provider(name)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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,7 +28,19 @@ 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)
|
||||||
|
if options[:provision_types].nil?
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
provisioner_names = Set.new
|
||||||
|
with_target_vms(argv) do |machine|
|
||||||
|
machine.config.vm.provisioners.map(&:name).each do |name|
|
||||||
|
provisioner_names.add(name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (provisioner_names & options[:provision_types]).empty?
|
||||||
(options[:provision_types] || []).each do |type|
|
(options[:provision_types] || []).each do |type|
|
||||||
klass = Vagrant.plugin("2").manager.provisioners[type]
|
klass = Vagrant.plugin("2").manager.provisioners[type]
|
||||||
if !klass
|
if !klass
|
||||||
|
@ -38,3 +52,4 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -30,7 +30,12 @@ module VagrantPlugins
|
||||||
# Wait for winrm_info to be ready
|
# Wait for winrm_info to be ready
|
||||||
winrm_info = nil
|
winrm_info = nil
|
||||||
while true
|
while true
|
||||||
|
winrm_info = nil
|
||||||
|
begin
|
||||||
winrm_info = Helper.winrm_info(@machine)
|
winrm_info = Helper.winrm_info(@machine)
|
||||||
|
rescue Errors::WinRMNotReady
|
||||||
|
@logger.debug("WinRM not ready yet; retrying until boot_timeout is reached.")
|
||||||
|
end
|
||||||
break if winrm_info
|
break if winrm_info
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
end
|
end
|
||||||
|
@ -38,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
|
||||||
|
@ -131,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
|
||||||
|
@ -188,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
|
||||||
|
@ -203,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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 > $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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
end
|
|
||||||
end
|
|
||||||
File.delete(tmpints)
|
|
||||||
|
|
||||||
networks.each do |network|
|
# Should map interface to service { "en1" => "Thunderbolt Ethernet" }
|
||||||
service_name = devlist[network[:interface]][:service]
|
interface_map[interface] = service
|
||||||
if network[:type].to_sym == :static
|
end
|
||||||
command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}"
|
end
|
||||||
elsif network[:type].to_sym == :dhcp
|
File.delete(tmp_ints)
|
||||||
command = "networksetup -setdhcp \"#{service_name}\""
|
|
||||||
|
mac_service_map = {}
|
||||||
|
macs = ::IO.read(tmp_hw)
|
||||||
|
macs.split(/\n\n/m).each do |i|
|
||||||
|
if i.match(/Hardware/) && i.match(/Ethernet/)
|
||||||
|
# Ethernet, should be 3 lines,
|
||||||
|
# Hardware Port: Thunderbolt 1
|
||||||
|
# Device: en1
|
||||||
|
# Ethernet Address: a1:b2:c3:d4:e5:f6
|
||||||
|
|
||||||
|
# multiline, should match "en1", "00:c1:00:a1:b2:c3"
|
||||||
|
devicearry = i.match(/Device: (.+)\nEthernet Address: (.+)/m)
|
||||||
|
interface = devicearry[1]
|
||||||
|
naked_mac = devicearry[2].gsub(':','').upcase
|
||||||
|
|
||||||
|
# Skip hardware ports without MAC (bridges, bluetooth, etc.)
|
||||||
|
next if naked_mac == "N/A"
|
||||||
|
|
||||||
|
if !interface_map[interface]
|
||||||
|
@@logger.warn("Could not find network service for interface #{interface}")
|
||||||
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
machine.communicate.sudo(command)
|
# Should map MAC to service, { "00C100A1B2C3" => "Thunderbolt Ethernet" }
|
||||||
end
|
mac_service_map[naked_mac] = interface_map[interface]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
File.delete(tmp_hw)
|
||||||
|
|
||||||
|
mac_service_map
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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")
|
||||||
|
|
|
@ -17,7 +17,10 @@ module VagrantPlugins
|
||||||
virtual = false
|
virtual = false
|
||||||
interface_names = Array.new
|
interface_names = Array.new
|
||||||
interface_names_by_slot = Array.new
|
interface_names_by_slot = Array.new
|
||||||
machine.communicate.sudo("/usr/sbin/biosdevname; echo $?") do |_, result|
|
machine.communicate.sudo("/usr/sbin/biosdevname &>/dev/null; echo $?") do |_, result|
|
||||||
|
# The above command returns:
|
||||||
|
# - '4' if /usr/sbin/biosdevname detects it is running in a virtual machine
|
||||||
|
# - '127' if /usr/sbin/biosdevname doesn't exist
|
||||||
virtual = true if ['4', '127'].include? result.chomp
|
virtual = true if ['4', '127'].include? result.chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -106,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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -25,16 +25,13 @@ module VagrantPlugins
|
||||||
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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module GuestPld
|
||||||
|
module Cap
|
||||||
|
class Flavor
|
||||||
|
def self.flavor(machine)
|
||||||
|
return :pld
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
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")
|
machine.communicate.sudo("yum -y install nfs-utils nfs-utils-lib")
|
||||||
|
end
|
||||||
restart_nfs(machine)
|
restart_nfs(machine)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ 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|
|
||||||
|
if VagrantPlugins::GuestRedHat::Plugin.dnf?(machine)
|
||||||
|
comm.sudo("dnf -y install rsync")
|
||||||
|
else
|
||||||
comm.sudo("yum -y install rsync")
|
comm.sudo("yum -y install rsync")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -11,3 +14,4 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue