Merge remote-tracking branch 'mitchellh/master'
This commit is contained in:
commit
7177739c01
|
@ -37,5 +37,5 @@ The following guidelines for contribution should be followed if you want to subm
|
|||
|
||||
# Additional Resources
|
||||
|
||||
* [General GitHub documentation](http://help.github.com/)
|
||||
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
|
||||
* [General GitHub documentation](https://help.github.com/)
|
||||
* [GitHub pull request documentation](https://help.github.com/send-pull-requests/)
|
|
@ -0,0 +1,45 @@
|
|||
Please note that the Vagrant issue tracker is reserved for bug reports and
|
||||
enhancements. For general usage questions, please use the Vagrant mailing list:
|
||||
https://groups.google.com/forum/#!forum/vagrant-up. Thank you!
|
||||
|
||||
### Vagrant version
|
||||
Run `vagrant -v` to show the version. If you are not running the latest version
|
||||
of Vagrant, please upgrade before submitting an issue.
|
||||
|
||||
### Host operating system
|
||||
This is the operating system that you run locally.
|
||||
|
||||
### Guest operating system
|
||||
This is the operating system you run in the virtual machine.
|
||||
|
||||
### Vagrantfile
|
||||
```ruby
|
||||
# Copy-paste your Vagrantfile here
|
||||
```
|
||||
|
||||
Please note, if you are using Homestead or a different Vagrantfile format, we
|
||||
may be unable to assist with your issue. Try to reproduce the issue using a
|
||||
vanilla Vagrantfile first.
|
||||
|
||||
### Debug output
|
||||
Provide a link to a GitHub Gist containing the complete debug output:
|
||||
https://www.vagrantup.com/docs/other/debugging.html. The debug output should
|
||||
be very long. Do NOT paste the debug output in the issue, just paste the
|
||||
link to the Gist.
|
||||
|
||||
### Expected behavior
|
||||
What should have happened?
|
||||
|
||||
### Actual behavior
|
||||
What actually happened?
|
||||
|
||||
### Steps to reproduce
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### References
|
||||
Are there any other GitHub issues (open or closed) that should be linked here?
|
||||
For example:
|
||||
- GH-1234
|
||||
- ...
|
|
@ -9,8 +9,8 @@
|
|||
acceptance_config.yml
|
||||
boxes/*
|
||||
/.vagrant
|
||||
/website/docs/.vagrant
|
||||
/website/www/.vagrant
|
||||
/website/.vagrant
|
||||
/website/build
|
||||
/vagrant-spec.config.rb
|
||||
|
||||
# Bundler/Rubygems
|
||||
|
@ -21,6 +21,7 @@ tags
|
|||
/Gemfile.lock
|
||||
test/tmp/
|
||||
vendor/
|
||||
/exec
|
||||
|
||||
# Documentation
|
||||
_site/*
|
||||
|
@ -43,14 +44,3 @@ doc/
|
|||
.ruby-gemset
|
||||
.ruby-version
|
||||
.rvmrc
|
||||
|
||||
# Website: docs
|
||||
website/docs/.sass-cache
|
||||
website/docs/build
|
||||
website/docs/Rakefile
|
||||
|
||||
# Website: www
|
||||
website/www/.sass-cache
|
||||
website/www/build
|
||||
website/www/Rakefile
|
||||
exec/
|
||||
|
|
|
@ -4,13 +4,16 @@ sudo: false
|
|||
|
||||
cache: bundler
|
||||
|
||||
before_install:
|
||||
- gem install bundler -v '1.12.5'
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- bsdtar
|
||||
|
||||
rvm:
|
||||
- 2.0.0
|
||||
- 2.2.3
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
|
233
CHANGELOG.md
233
CHANGELOG.md
|
@ -1,9 +1,228 @@
|
|||
## Next Version (unreleased)
|
||||
## Next Version (Unreleased)
|
||||
|
||||
FEATURES:
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- provisioners/ansible_local: Fix error in `playbook` existence check when
|
||||
running on a Windows host [GH-6740]
|
||||
- hosts/arch: Detect NFS server by service name on arch [GH-7630, GH-7629]
|
||||
- guests/linux: Fix SSH key permissions [GH-7610, GH-7611]
|
||||
- guests/ubuntu: Fix detection on older guests [GH-7632, GH-7524, GH-7625]
|
||||
|
||||
|
||||
## 1.8.5 (July 18, 2016)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- core: Provide a way to globally disable box update checks with the
|
||||
environment variable `VAGRANT_BOX_UPDATE_CHECK_DISABLE`. Setting this
|
||||
to any non-empty value will instruct Vagrant to not look for box updates
|
||||
when running `vagrant up`. Setting this environment variable has no
|
||||
effect on the `vagrant box` commands.
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- guests/arch: Support installing synced folder clients [GH-7519]
|
||||
- guests/darwin: Allow ipv6 static networks [GH-7491]
|
||||
- providers/virtualbox: Add support for 5.1 [GH-7574]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- core: Bump listen gem and Ruby version to improve rsync performance
|
||||
[GH-7453, GH-7441]
|
||||
- core: Check process stdout when detecting if a hyperv admin
|
||||
[GH-7465, GH-7467]
|
||||
- core: Ensure removal of temporary directory when box download fails
|
||||
[GH-7496, GH-7499]
|
||||
- core: Fix regression for installing plugins from path [GH-7505, GH-7493]
|
||||
- core: Skip checking conflicts on disabled ports [GH-7587]
|
||||
- core: Idempotent write-out for state file [GH-7550]
|
||||
- core/guests: Create common BSD guest for shared logic
|
||||
- core/guests: Ignore empty output from `/sbin/ip`
|
||||
[GH-7539, GH-7537, GH-7533, GH-7605]
|
||||
- synced_folders/nfs: Shellescape rsync paths
|
||||
[GH-7540, GH-7605]
|
||||
- synced_folders/nfs: Ensure retries take place [GH-6360, GH-7605]
|
||||
- synced_folders/rsync: Shellescape rsync paths
|
||||
[GH-7580, GH-6690, GH-7579, GH-7605]
|
||||
- synced_folders/rsync: Translate Windows paths
|
||||
[GH-7012, GH-6702, GH-6568, GH-7046]
|
||||
- guests/bsd: Consolidate core logic for mounting NFS folders
|
||||
[GH-7480, GH-7474, GH-7466]
|
||||
- guests/bsd: Consolidate core logic for public key management [GH-7481]
|
||||
- guests/bsd: Consolidate core logic for halting [GH-7484]
|
||||
- guests/centos: Use `ip` instead of `ifconfig` to detect network interfaces
|
||||
[GH-7460]
|
||||
- guests/debian: Ensure newline when inserting public key [GH-7456]
|
||||
- guests/linux: Ensure NFS retries during mounting [GH-7492]
|
||||
- guests/redhat: Use `/sbin/ip` to list and configure networks for
|
||||
compatability with older versions of CentOS [GH-7482]
|
||||
- guests/redhat: Ensure newline when inserting public key [GH-7598, GH-7605]
|
||||
- guests/ubuntu: Use /etc/os-release to detech [GH-7524]
|
||||
- guests/ubuntu: Use short hostname [GH-7488, GH-7605]
|
||||
- providers/hyperv: Fix version check and catch statement [GH-7447, GH-7487]
|
||||
|
||||
## 1.8.4 (June 13, 2016)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- core: Fix bundler plugin issue and version constraint [GH-7418, GH-7415]
|
||||
- providers/virtualbox: Use 8 network interfaces (due to Windows limitation)
|
||||
[GH-7417, GH-7419]
|
||||
- provisioners/ansible(both): Honor "galaxy_roles_path" option when running
|
||||
ansible-playbook [GH-7269, GH-7420]
|
||||
- provisioners/ansible_local: Add quotes around "ansible-galaxy" arguments
|
||||
[GH-7420]
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- guests/redhat: Add CloudLinux detection [GH-7428, GH-7427]
|
||||
|
||||
## 1.8.3 (June 10, 2016)
|
||||
|
||||
BREAKING CHANGES:
|
||||
|
||||
- The `winrm` communicator now shares the same upload behavior as the `ssh`
|
||||
communicator. This change should have no impact to most vagrant operations
|
||||
but may break behavior when uploading directories to an existing
|
||||
destination target. The `file` provisioner should be the only builtin
|
||||
provisioner affected by this change. When uploading a directory and the
|
||||
destination directory exists on the endpoint, the source base directory
|
||||
will be created below the destination directory on the endpoint and the
|
||||
source directory contents will be unzipped to that location. Prior to this
|
||||
release, the contents of the source directory would be unzipped to an
|
||||
existing destination directory without creating the source base directory.
|
||||
This new behavior is more consistent with SCP and other well known shell copy commands.
|
||||
- The Chef provisioner's `channel` default value has changed from "current" to
|
||||
"stable". The "current" channel includes nightly releases and should be
|
||||
opt-in only. Note that users wishing to download the Chef Development Kit
|
||||
will need to opt into the "current" channel until Chef Software promotes
|
||||
into the "stable" channel.
|
||||
- The Arch Linux host capability for NFS removed support for rc.d in favor or
|
||||
systemd which has been present since 2012. Please see GH-7181 for more
|
||||
information.
|
||||
|
||||
FEATURES:
|
||||
|
||||
- provider/docker: Allow non-linux users to opt-out of the host VM to run
|
||||
Docker containers by setting `config.force_host_vm = false` in the
|
||||
Vagrantfile. This is especially useful for customers who wish to use
|
||||
the beta builds for Mac and Windows, dlite, or a custom provider.
|
||||
[GH-7277, GH-7298, 8c11b53]
|
||||
- provider/docker: New command: `docker-exec` allows attaching to an
|
||||
already-running container.
|
||||
[GH-7377, GH-6566, GH-5193, GH-4904, GH-4057, GH-4179, GH-4903]
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- core/downloader: increase box resume download limit to 24h
|
||||
[GH-7352, GH-7272]
|
||||
- core/package: run validations prior to packaging [GH-7353, GH-7351]
|
||||
- core/action: make `start` ("vagrant up") run provisioners [GH-4467, GH-4421]
|
||||
- commands/all: Make it clear that machine IDs can be specified
|
||||
[GH-7356, GH-7228]
|
||||
- commands/init: Add support for specifying the box version [GH-7363, GH-5004]
|
||||
- commands/login: Print a warning with both the environment variable and
|
||||
local login token are present [GH-7206, GH-7219]
|
||||
- communicators/winrm: Upgrade to latest WinRM gems [GH-6922]
|
||||
- provisioners/ansible_local: Allow to install Ansible from pip,
|
||||
with version selection capability [GH-6654, GH-7167]
|
||||
- provisioners/ansible_local: Use `provisioning_path` as working directory
|
||||
for `ansible-galaxy` execution
|
||||
- provisioners/ansible(both provisioners): Add basic config
|
||||
validators/converters on `raw_arguments` and `raw_ssh_args` options
|
||||
[GH-7103]
|
||||
- provisioners/chef: Add the ability to install on SUSE [GH-6806]
|
||||
- provisioners/chef: Support legacy solo mode [GH-7327]
|
||||
- provisioners/docker: Restart container if newer image is available
|
||||
[GH-7358, GH-6620]
|
||||
- hosts/arch: Remove sysvinit and assume systemd [GH-7181]
|
||||
- hosts/linux: Do not use a pager with systemctl commands [GH-7270]
|
||||
- hosts/darwin: Add `extra_args` support for RDP [GH-5523, GH-6602]
|
||||
- hosts/windows: Use SafeExec to capture history in Powershell [GH-6749]
|
||||
- guests/amazon: Add detection [GH-7395, GH-7254]
|
||||
- guests/freebsd: Add quotes around hostname [GH-6867]
|
||||
- guests/fedora: Add support for ipv6 static networks [GH-7275, GH-7276]
|
||||
- guests/tinycore: Add support for shared folders [GH-6977, GH-6968]
|
||||
- guests/trisquel: Add initial support [GH-6842, GH-6843]
|
||||
- guests/windows: Add support for automatic login (no password prompting)
|
||||
[GH-5670]
|
||||
- core: Add `--no-delete` and provisioning flags to snapshot restore/pop
|
||||
[GH-6879]
|
||||
- providers/docker: Allow TCP and UDP ports on the same number [GH-7365,
|
||||
GH-5527]
|
||||
- providers/hyperv: Add support for differencing disk [GH-7090]
|
||||
- providers/hyperv: Add support for snapshots [GH-7110]
|
||||
- providers/hyperv: Reinstate compatibility with PS 4 [GH-7108]
|
||||
- providers/virtualbox: Add linked clone support for Virtualbox 1.4 [GH-7050]
|
||||
- synced_folders/nfs: Read static and dynamic IPs [GH-7290, GH-7289]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- core: Bump nokogiri version to fix windows bug [GH-6766, GH-6848]
|
||||
- core: Revert a change made to the output of the identify file [GH-6962,
|
||||
GH-6929, GH-6589]
|
||||
- core: Fix login command behind a proxy [GH-6898, GH-6899]
|
||||
- core: Fix support for regular expressions on multi-machine `up`
|
||||
[GH-6908, GH-6909]
|
||||
- core: Allow boxes to use pre-release versions [GH-6892, GH-6893]
|
||||
- core: Rescue `Errno:ENOTCONN` waiting for port to be open [GH-7182, GH-7184]
|
||||
- core: Properly authenticate metadata box URLs [GH-6776, GH-7158]
|
||||
- core: Do not run provisioners if already run on resume [GH-7059, GH-6787]
|
||||
- core: Implement better tracking of tempfiles and tmpdirs to identify file
|
||||
leaks [GH-7355]
|
||||
- core: Allow SSH forwarding on Windows [GH-7287, GH-7202]
|
||||
- core: Allow customizing `keys_only` SSH option [GH-7360, GH-4275]
|
||||
- core: Allow customizing `paranoid` SSH option [GH-7360, GH-4275]
|
||||
- command/box_update: Do not update the same box twice [GH-6042, GH-7379]
|
||||
- command/init: Remove unnecessary `sudo` from generated Vagrantfile
|
||||
[GH-7369, GH-7295]
|
||||
- docs & core: Be consistent about the "2" in the Vagrantfile version
|
||||
[GH-6961, GH-6963]
|
||||
- guests/all: Refactor guest capabilities to run in a single command -
|
||||
**please see GH-7393 for the complete list of changes!**
|
||||
- guests/arch: Restart network after configuration [GH-7120, GH-7119]
|
||||
- guests/debian: Do not return an error if ifdown fails [GH-7159,
|
||||
GH-7155, GH-6871]
|
||||
- guests/freebsd: Use `pkg` to install rsync [GH-6760]
|
||||
- guests/freebsd: Use `netif` to configure networks [GH-5852, GH-7093]
|
||||
- guests/coreos: Detect all interface names [GH-6608, GH-6610]
|
||||
- providers/hyperv: Only specify Hyper-V if the parameter is support
|
||||
[GH-7101, GH-7098]
|
||||
- providers/virtualbox: Set maximum network adapters to 36 [GH-7293, GH-7286]
|
||||
- providers/virtualbox: Do not fail when master VM from linked clone is
|
||||
missing [GH-7126, GH-6742]
|
||||
- providers/virtualbox: Use scoped overrides in preparring NFS
|
||||
[GH-7387, GH-7386]
|
||||
- provisioners/ansible: Fix a race condition in the concurrent generations of
|
||||
the ansible inventory file, while running `vagrant up --parallel`
|
||||
[GH-6526, GH-7190]
|
||||
- provisioners/ansible_local: Don't quote the Ansible arguments defined in the
|
||||
`raw_arguments` option [GH-7103]
|
||||
- provisioners/ansible_local: Format json `extra_vars` with double quotes
|
||||
[GH-6726, GH-7103]
|
||||
- provisioners/ansible_local: Fix errors in absolute paths to playbook or
|
||||
galaxy resources when running on a Windows host [GH-6740, GH-6757]
|
||||
- provisioners/ansible_local: Change the way to verify `ansible-galaxy`
|
||||
presence, to avoid a non-zero status code with Ansible 2.0 [GH-6793]
|
||||
- provisioners/ansible(both provisioners): The Ansible configuration files
|
||||
detection is only executed by the `provision` action [GH-6763, GH-6984]
|
||||
- provisioners/chef: Do not use double sudo when installing
|
||||
[GGH-6805, GH-6804]
|
||||
- provisioners/chef: Change the default channel to "stable" (previously it
|
||||
was "current") [GH-7001, GH-6979]
|
||||
- provisioners/chef: Default node_name to hostname if present
|
||||
[GH-7063, GH-7153]
|
||||
- provisioners/docker: Fix -no-trunc command option [GH-7085]
|
||||
- provisioners/docker: Allow provisioning when container name is specified
|
||||
[GH-7074, GH-7086]
|
||||
- provisioners/puppet: Use `where.exe` to locate puppet binary
|
||||
[GH-6912, GH-6876]
|
||||
- provisioners/salt: Move masterless config to apply to all platforms
|
||||
[GH-7207, Gh-6924, GH-6915]
|
||||
- pushes/ftp: Create parent directories when uploading [GH-7154, GH-6316]
|
||||
- synced_folders/smb: Do not interpolate configuration file [GH-6906]
|
||||
|
||||
## 1.8.1 (December 21, 2015)
|
||||
|
||||
|
@ -15,6 +234,8 @@ BUG FIXES:
|
|||
UNC paths [GH-6598]
|
||||
- core: Fix a crash in parsing the config in some cases with network
|
||||
configurations [GH-6730]
|
||||
- core: Clean up temporarily files created by bundler
|
||||
[GH-7354, GH-6301, GH-3469, GH-6231]
|
||||
- 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]
|
||||
|
@ -597,7 +818,7 @@ BUG FIXES:
|
|||
- commands/package: base package won't crash with exception [GH-4017]
|
||||
- commands/rsync-auto: Destroyed machines won't raise exceptions. [GH-4031]
|
||||
- commands/ssh: Extra args are passed through to Docker container. [GH-4378]
|
||||
- communicators/ssh: Nicer error if remote unexpectedly disconects. [GH-4038]
|
||||
- communicators/ssh: Nicer error if remote unexpectedly disconnects. [GH-4038]
|
||||
- communicators/ssh: Clean error when max sessions is hit. [GH-4044]
|
||||
- communicators/ssh: Fix many issues around PTY-enabled output parsing.
|
||||
[GH-4408]
|
||||
|
@ -1306,7 +1527,7 @@ IMPROVEMENTS:
|
|||
certs from a custom CA. [GH-2337]
|
||||
- commands/box/add: Can now specify a client cert when downloading a
|
||||
box. [GH-1889]
|
||||
- commands/init: Add `--output` option for specifing output path, or
|
||||
- commands/init: Add `--output` option for specifying output path, or
|
||||
"-" for stdin. [GH-1364]
|
||||
- commands/provision: Add `--no-parallel` option to disable provider
|
||||
parallelization if the provider supports it. [GH-2404]
|
||||
|
@ -2845,7 +3066,7 @@ compatibility.
|
|||
in a saved state. [GH-123]
|
||||
- Added `config.chef.recipe_url` which allows you to specify a URL to
|
||||
a gzipped tar file for chef solo to download cookbooks. See the
|
||||
[chef-solo docs](http://wiki.opscode.com/display/chef/Chef+Solo#ChefSolo-RunningfromaURL) for more information.
|
||||
[chef-solo docs](https://docs.chef.io/chef_solo.html) for more information.
|
||||
[GH-121]
|
||||
- Added `vagrant box repackage` which repackages boxes which have
|
||||
been added. This is useful in case you want to redistribute a base
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Website: [https://www.vagrantup.com/](https://www.vagrantup.com/)
|
||||
* Source: [https://github.com/mitchellh/vagrant](https://github.com/mitchellh/vagrant)
|
||||
* IRC: `#vagrant` on Freenode
|
||||
* Mailing list: [Google Groups](http://groups.google.com/group/vagrant-up)
|
||||
* Mailing list: [Google Groups](https://groups.google.com/group/vagrant-up)
|
||||
|
||||
Vagrant is a tool for building and distributing development environments.
|
||||
|
||||
|
@ -21,12 +21,12 @@ between Windows, Mac OS X, and Linux.
|
|||
For the quick-start, we'll bring up a development machine on
|
||||
[VirtualBox](https://www.virtualbox.org/) because it is free and works
|
||||
on all major platforms. Vagrant can, however, work with almost any
|
||||
system such as [OpenStack] (https://www.openstack.org/), [VMware] (http://www.vmware.com/), [Docker] (https://docs.docker.com/), etc.
|
||||
system such as [OpenStack] (https://www.openstack.org/), [VMware] (https://www.vmware.com/), [Docker] (https://docs.docker.com/), etc.
|
||||
|
||||
First, make sure your development machine has
|
||||
[VirtualBox](https://www.virtualbox.org/)
|
||||
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](https://www.vagrantup.com/downloads.html).
|
||||
|
||||
To build your first virtual environment:
|
||||
|
||||
|
@ -40,7 +40,7 @@ the box doesn't already exist on your system.
|
|||
## Getting Started Guide
|
||||
|
||||
To learn how to build a fully functional development environment, follow the
|
||||
[getting started guide](http://docs.vagrantup.com/v2/getting-started/index.html).
|
||||
[getting started guide](https://www.vagrantup.com/docs/getting-started/index.html).
|
||||
|
||||
## Installing the Gem from Git
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
# Releasing Vagrant
|
||||
|
||||
This documents how to release Vagrant. Various steps in this document will
|
||||
require privileged access to private systems, so this document is only
|
||||
targetted at Vagrant core members who have the ability to cut a release.
|
||||
|
||||
1. Update `version.txt` to the version you want to release.
|
||||
|
||||
1. Update `CHANGELOG.md` to have a header with the release version and date.
|
||||
|
||||
1. Commit those changes and also tag the release with the version:
|
||||
|
||||
```
|
||||
$ git tag vX.Y.Z
|
||||
$ git push --tags
|
||||
```
|
||||
|
||||
1. Trigger an installer creation run within the HashiCorp Bamboo installation.
|
||||
This will take around 45 minutes.
|
||||
|
||||
1. Download all the resulting artifacts into the `pkg/dist` folder relative to
|
||||
the Vagrant repository on your local machine.
|
||||
|
||||
1. Run `./scripts/sign.sh` with the version that is being created. This must be
|
||||
run from the Vagrant repo root. This will GPG sign and checksum the files.
|
||||
|
||||
1. Run the following command to upload the binaries to the releases site:
|
||||
|
||||
```
|
||||
$ hc-releases upload pkg/dist
|
||||
```
|
||||
|
||||
1. Publish the new index files to the releases site:
|
||||
|
||||
```
|
||||
$ hc-releases publish
|
||||
```
|
||||
|
||||
1. Update `website/config.rb` to point to the latest version, commit, and push.
|
||||
|
||||
1. Tell HashiBot to deploy in ``#deploys`
|
||||
|
||||
```
|
||||
hashibot deploy vagrant
|
||||
```
|
||||
|
||||
1. Update `version.txt` to append `.dev` and add a new blank entry in the
|
||||
CHANGELOG, commit, and push.
|
||||
|
||||
1. Update [Checkpoint](https://checkpoint.hashicorp.com/control) with the new
|
||||
version.
|
|
@ -139,7 +139,7 @@ begin
|
|||
end
|
||||
|
||||
# Also allow users to force colors.
|
||||
if argv.include?("--color")
|
||||
if argv.include?("--color") || ENV["VAGRANT_FORCE_COLOR"]
|
||||
argv.delete("--color")
|
||||
opts[:ui_class] = Vagrant::UI::Colored
|
||||
end
|
||||
|
|
|
@ -53,7 +53,7 @@ __vagrantinvestigate() {
|
|||
_vagrant() {
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
commands="box connect destroy docker-logs docker-run global-status halt help init list-commands login package plugin provision push rdp reload resume rsync rsync-auto share ssh ssh-config status suspend up version"
|
||||
commands="box connect destroy docker-exec docker-logs docker-run global-status halt help init list-commands login package plugin provision push rdp reload resume rsync rsync-auto share snapshot ssh ssh-config status suspend up version"
|
||||
|
||||
if [ $COMP_CWORD == 1 ]
|
||||
then
|
||||
|
@ -104,6 +104,11 @@ _vagrant() {
|
|||
COMPREPLY=($(compgen -W "${commands}" -- ${cur}))
|
||||
return 0
|
||||
;;
|
||||
"snapshot")
|
||||
snapshot_commands="delete list pop push restore save"
|
||||
COMPREPLY=($(compgen -W "${snapshot_commands}" -- ${cur}))
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 --no-pager nfs-server.service
|
||||
Cmnd_Alias VAGRANT_NFSD_START = /usr/bin/systemctl start nfs-server.service
|
||||
Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar
|
||||
Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /*/exports
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Insecure Keypair
|
||||
|
||||
These keys are the "insecure" public/private keypair we offer to
|
||||
[base box creators](http://docs.vagrantup.com/v2/boxes/base.html) for use in their base boxes so that
|
||||
[base box creators](https://www.vagrantup.com/docs/boxes/base.html) for use in their base boxes so that
|
||||
vagrant installations can automatically SSH into the boxes.
|
||||
|
||||
If you're working with a team or company or with a custom box and
|
||||
|
|
|
@ -18,6 +18,10 @@ module Vagrant
|
|||
# to NOT be metadata.
|
||||
METADATA_SIZE_LIMIT = 20971520
|
||||
|
||||
# This is the amount of time to "resume" downloads if a partial box
|
||||
# file already exists.
|
||||
RESUME_DELAY = 24 * 60 * 60
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::action::builtin::box_add")
|
||||
|
@ -30,7 +34,7 @@ module Vagrant
|
|||
u = u.gsub("\\", "/")
|
||||
if Util::Platform.windows? && u =~ /^[a-z]:/i
|
||||
# On Windows, we need to be careful about drive letters
|
||||
u = "file://#{URI.escape(u)}"
|
||||
u = "file:///#{URI.escape(u)}"
|
||||
end
|
||||
|
||||
if u =~ /^[a-z0-9]+:.*$/i && !u.start_with?("file://")
|
||||
|
@ -253,7 +257,7 @@ module Vagrant
|
|||
end
|
||||
|
||||
provider_url = metadata_provider.url
|
||||
if url != authenticated_url
|
||||
if provider_url != authenticated_url
|
||||
# Authenticate the provider URL since we're using auth
|
||||
hook_env = env[:hook].call(:authenticate_box_url, box_urls: [provider_url])
|
||||
authed_urls = hook_env[:box_urls]
|
||||
|
@ -261,7 +265,7 @@ module Vagrant
|
|||
raise "Bad box authentication hook, did not generate proper results."
|
||||
end
|
||||
provider_url = authed_urls[0]
|
||||
end
|
||||
end
|
||||
|
||||
box_add(
|
||||
[[provider_url, metadata_provider.url]],
|
||||
|
@ -393,7 +397,7 @@ module Vagrant
|
|||
if env[:box_clean]
|
||||
@logger.info("Cleaning existing temp box file.")
|
||||
delete = true
|
||||
elsif temp_path.mtime.to_i < (Time.now.to_i - 6 * 60 * 60)
|
||||
elsif temp_path.mtime.to_i < (Time.now.to_i - RESUME_DELAY)
|
||||
@logger.info("Existing temp file is too old. Removing.")
|
||||
delete = true
|
||||
end
|
||||
|
@ -468,6 +472,8 @@ module Vagrant
|
|||
if uri.scheme == "file"
|
||||
url = uri.path
|
||||
url ||= uri.opaque
|
||||
#7570 Strip leading slash left in front of drive letter by uri.path
|
||||
Util::Platform.windows? && url.gsub!(/^\/([a-zA-Z]:)/, '\1')
|
||||
|
||||
begin
|
||||
File.open(url, "r") do |f|
|
||||
|
|
|
@ -93,6 +93,11 @@ module Vagrant
|
|||
guest_port = options[:guest]
|
||||
host_port = options[:host]
|
||||
|
||||
if options[:disabled]
|
||||
@logger.debug("Skipping disabled port #{host_port}.")
|
||||
next
|
||||
end
|
||||
|
||||
if options[:protocol] && options[:protocol] != "tcp"
|
||||
@logger.debug("Skipping #{host_port} because UDP protocol.")
|
||||
next
|
||||
|
|
|
@ -3,6 +3,7 @@ require "pathname"
|
|||
|
||||
require 'vagrant/util/safe_chdir'
|
||||
require 'vagrant/util/subprocess'
|
||||
require 'vagrant/util/presence'
|
||||
|
||||
module Vagrant
|
||||
module Action
|
||||
|
@ -20,25 +21,63 @@ module Vagrant
|
|||
class Package
|
||||
include Util
|
||||
|
||||
# Perform sanity validations that the provided output filepath is sane.
|
||||
# In particular, this function validates:
|
||||
#
|
||||
# - The output path is a regular file (not a directory or symlink)
|
||||
# - No file currently exists at the given path
|
||||
# - A directory of package files was actually provided (internal)
|
||||
#
|
||||
# @param [String] output path to the output file
|
||||
# @param [String] directory path to a directory containing the files
|
||||
def self.validate!(output, directory)
|
||||
filename = File.basename(output.to_s)
|
||||
output = fullpath(output)
|
||||
|
||||
if File.directory?(output)
|
||||
raise Vagrant::Errors::PackageOutputDirectory
|
||||
end
|
||||
|
||||
if File.exist?(output)
|
||||
raise Vagrant::Errors::PackageOutputExists, filename: filename
|
||||
end
|
||||
|
||||
if !Vagrant::Util::Presence.present?(directory) || !File.directory?(directory)
|
||||
raise Vagrant::Errors::PackageRequiresDirectory
|
||||
end
|
||||
end
|
||||
|
||||
# Calculate the full path of the given path, relative to the current
|
||||
# working directory (where the command was run).
|
||||
#
|
||||
# @param [String] output the relative path
|
||||
def self.fullpath(output)
|
||||
File.expand_path(output, Dir.pwd)
|
||||
end
|
||||
|
||||
# The path to the final output file.
|
||||
# @return [String]
|
||||
attr_reader :fullpath
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
|
||||
env["package.files"] ||= {}
|
||||
env["package.output"] ||= "package.box"
|
||||
|
||||
@fullpath = self.class.fullpath(env["package.output"])
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
file_name = File.basename(@env["package.output"].to_s)
|
||||
|
||||
raise Errors::PackageOutputDirectory if File.directory?(tar_path)
|
||||
raise Errors::PackageOutputExists, file_name:file_name if File.exist?(tar_path)
|
||||
raise Errors::PackageRequiresDirectory if !env["package.directory"] ||
|
||||
!File.directory?(env["package.directory"])
|
||||
self.class.validate!(env["package.output"], env["package.directory"])
|
||||
|
||||
raise Errors::PackageOutputDirectory if File.directory?(fullpath)
|
||||
|
||||
@app.call(env)
|
||||
|
||||
@env[:ui].info I18n.t("vagrant.actions.general.package.compressing", tar_path: tar_path)
|
||||
@env[:ui].info I18n.t("vagrant.actions.general.package.compressing", fullpath: fullpath)
|
||||
copy_include_files
|
||||
setup_private_key
|
||||
compress
|
||||
|
@ -54,7 +93,7 @@ module Vagrant
|
|||
end
|
||||
|
||||
# Cleanup any packaged files if the packaging failed at some point.
|
||||
File.delete(tar_path) if File.exist?(tar_path)
|
||||
File.delete(fullpath) if File.exist?(fullpath)
|
||||
end
|
||||
|
||||
# This method copies the include files (passed in via command line)
|
||||
|
@ -88,7 +127,7 @@ module Vagrant
|
|||
def compress
|
||||
# Get the output path. We have to do this up here so that the
|
||||
# pwd returns the proper thing.
|
||||
output_path = tar_path.to_s
|
||||
output_path = fullpath.to_s
|
||||
|
||||
# Switch into that directory and package everything up
|
||||
Util::SafeChdir.safe_chdir(@env["package.directory"]) do
|
||||
|
@ -147,11 +186,6 @@ module Vagrant
|
|||
f.puts %Q[end]
|
||||
end
|
||||
end
|
||||
|
||||
# Path to the final box output file
|
||||
def tar_path
|
||||
File.expand_path(@env["package.output"], FileUtils.pwd)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -118,7 +118,7 @@ module Vagrant
|
|||
# @param [Hash] download_options Options to pass to the downloader.
|
||||
# @return [BoxMetadata]
|
||||
def load_metadata(**download_options)
|
||||
tf = Tempfile.new("vagrant")
|
||||
tf = Tempfile.new("vagrant-load-metadata")
|
||||
tf.close
|
||||
|
||||
url = @metadata_url
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require "digest/sha1"
|
||||
require "fileutils"
|
||||
require "monitor"
|
||||
require "tmpdir"
|
||||
|
||||
|
@ -276,17 +277,16 @@ module Vagrant
|
|||
next if versiondir.basename.to_s.start_with?(".")
|
||||
|
||||
version = versiondir.basename.to_s
|
||||
Gem::Version.new(version)
|
||||
end.compact
|
||||
|
||||
# Traverse through versions with the latest version first
|
||||
versions.sort.reverse.each do |v|
|
||||
if !requirements.all? { |r| r.satisfied_by?(v) }
|
||||
if !requirements.all? { |r| r.satisfied_by?(Gem::Version.new(v)) }
|
||||
# Unsatisfied version requirements
|
||||
next
|
||||
end
|
||||
|
||||
versiondir = box_directory.join(v.to_s)
|
||||
versiondir = box_directory.join(v)
|
||||
providers.each do |provider|
|
||||
provider_dir = versiondir.join(provider.to_s)
|
||||
next if !provider_dir.directory?
|
||||
|
@ -303,7 +303,7 @@ module Vagrant
|
|||
end
|
||||
|
||||
return Box.new(
|
||||
name, provider, v.to_s, provider_dir,
|
||||
name, provider, v, provider_dir,
|
||||
metadata_url: metadata_url,
|
||||
)
|
||||
end
|
||||
|
@ -448,7 +448,7 @@ module Vagrant
|
|||
|
||||
yield dir
|
||||
ensure
|
||||
dir.rmtree if dir.exist?
|
||||
FileUtils.rm_rf(dir.to_s)
|
||||
end
|
||||
|
||||
# Checks if a box with a given name exists.
|
||||
|
|
|
@ -2,6 +2,7 @@ require "monitor"
|
|||
require "pathname"
|
||||
require "set"
|
||||
require "tempfile"
|
||||
require "fileutils"
|
||||
|
||||
require "bundler"
|
||||
|
||||
|
@ -55,13 +56,13 @@ module Vagrant
|
|||
|
||||
# Setup the "local" Bundler configuration. We need to set BUNDLE_PATH
|
||||
# because the existence of this actually suppresses `sudo`.
|
||||
@appconfigpath = Dir.mktmpdir
|
||||
@appconfigpath = Dir.mktmpdir("vagrant-bundle-app-config")
|
||||
File.open(File.join(@appconfigpath, "config"), "w+") do |f|
|
||||
f.write("BUNDLE_PATH: \"#{bundle_path}\"")
|
||||
end
|
||||
|
||||
# Setup the Bundler configuration
|
||||
@configfile = File.open(Tempfile.new("vagrant").path + "1", "w+")
|
||||
@configfile = tempfile("vagrant-configfile")
|
||||
@configfile.close
|
||||
|
||||
# Build up the Gemfile for our Bundler context. We make sure to
|
||||
|
@ -84,9 +85,13 @@ module Vagrant
|
|||
|
||||
# Removes any temporary files created by init
|
||||
def deinit
|
||||
File.unlink(ENV["BUNDLE_APP_CONFIG"]) rescue nil
|
||||
File.unlink(ENV["BUNDLE_CONFIG"]) rescue nil
|
||||
File.unlink(ENV["GEMFILE"]) rescue nil
|
||||
# If we weren't enabled, then we don't do anything.
|
||||
return if !@enabled
|
||||
|
||||
FileUtils.rm_rf(ENV["BUNDLE_APP_CONFIG"]) rescue nil
|
||||
FileUtils.rm_f(ENV["BUNDLE_CONFIG"]) rescue nil
|
||||
FileUtils.rm_f(ENV["BUNDLE_GEMFILE"]) rescue nil
|
||||
FileUtils.rm_f(ENV["BUNDLE_GEMFILE"]+".lock") rescue nil
|
||||
end
|
||||
|
||||
# Installs the list of plugins.
|
||||
|
@ -181,7 +186,7 @@ module Vagrant
|
|||
def build_gemfile(plugins)
|
||||
sources = plugins.values.map { |p| p["sources"] }.flatten.compact.uniq
|
||||
|
||||
f = File.open(Tempfile.new("vagrant").path + "2", "w+")
|
||||
f = tempfile("vagrant-gemfile")
|
||||
f.tap do |gemfile|
|
||||
sources.each do |source|
|
||||
next if source == ""
|
||||
|
@ -203,7 +208,6 @@ module Vagrant
|
|||
gemfile.puts(%Q[gem "#{name}", #{version.inspect}, #{opts.inspect}])
|
||||
end
|
||||
gemfile.puts("end")
|
||||
|
||||
gemfile.close
|
||||
end
|
||||
end
|
||||
|
@ -250,11 +254,14 @@ module Vagrant
|
|||
def with_isolated_gem
|
||||
raise Errors::BundlerDisabled if !@enabled
|
||||
|
||||
tmp_gemfile = tempfile("vagrant-gemfile")
|
||||
tmp_gemfile.close
|
||||
|
||||
# Remove bundler settings so that Bundler isn't loaded when building
|
||||
# native extensions because it causes all sorts of problems.
|
||||
old_rubyopt = ENV["RUBYOPT"]
|
||||
old_gemfile = ENV["BUNDLE_GEMFILE"]
|
||||
ENV["BUNDLE_GEMFILE"] = Tempfile.new("vagrant-gemfile").path
|
||||
ENV["BUNDLE_GEMFILE"] = tmp_gemfile.path
|
||||
ENV["RUBYOPT"] = (ENV["RUBYOPT"] || "").gsub(/-rbundler\/setup\s*/, "")
|
||||
|
||||
# Set the GEM_HOME so gems are installed only to our local gem dir
|
||||
|
@ -265,7 +272,10 @@ module Vagrant
|
|||
|
||||
# Reset the all specs override that Bundler does
|
||||
old_all = Gem::Specification._all
|
||||
Gem::Specification.all = nil
|
||||
|
||||
# WARNING: Seriously don't touch this without reading the comment attached
|
||||
# to the monkey-patch at the bottom of this file.
|
||||
Gem::Specification.vagrant_reset!
|
||||
|
||||
# /etc/gemrc and so on.
|
||||
old_config = nil
|
||||
|
@ -284,6 +294,8 @@ module Vagrant
|
|||
return yield
|
||||
end
|
||||
ensure
|
||||
tmp_gemfile.unlink rescue nil
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] = old_gemfile
|
||||
ENV["GEM_HOME"] = @gem_home
|
||||
ENV["RUBYOPT"] = old_rubyopt
|
||||
|
@ -293,6 +305,17 @@ module Vagrant
|
|||
Gem::Specification.all = old_all
|
||||
end
|
||||
|
||||
# This method returns a proper "tempfile" on disk. Ruby's Tempfile class
|
||||
# would work really great for this, except GC can come along and remove
|
||||
# the file before we are done with it. This is because we "close" the file,
|
||||
# but we might be shelling out to a subprocess.
|
||||
#
|
||||
# @return [File]
|
||||
def tempfile(name)
|
||||
path = Dir::Tmpname.create(name) {}
|
||||
return File.open(path, "w+")
|
||||
end
|
||||
|
||||
# This is pretty hacky but it is a custom implementation of
|
||||
# Gem::ConfigFile so that we don't load any gemrc files.
|
||||
class NilGemConfig < Gem::ConfigFile
|
||||
|
@ -311,6 +334,36 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
# This monkey patches Gem::Specification from RubyGems to add a new method,
|
||||
# `vagrant_reset!`. For some background, Vagrant needs to set the value
|
||||
# of these variables to nil to force new specs to be loaded. Previously,
|
||||
# this was accomplished by setting Gem::Specification.specs = nil. However,
|
||||
# newer versions of Rubygems try to map across that nil using a group_by
|
||||
# clause, breaking things.
|
||||
#
|
||||
# This generally never affected Vagrant users who were using the official
|
||||
# Vagrant installers because we lock to an older version of Rubygems that
|
||||
# does not have this issue. The users of the official debian packages,
|
||||
# however, experienced this issue because they float on Rubygems.
|
||||
#
|
||||
# In GH-7073, a number of Debian users reported this issue, but it was not
|
||||
# reproducible in the official installer for reasons described above. Commit
|
||||
# ba77d4b switched to using Gem::Specification.reset, but this actually
|
||||
# broke the ability to install gems locally (GH-7493) because it resets
|
||||
# the complete local cache, which is already built.
|
||||
#
|
||||
# The only solution that works with both new and old versions of Rubygems
|
||||
# is to provide our own function for JUST resetting all the stubs. Both
|
||||
# @@all and @@stubs must be set to a falsey value, so some of the
|
||||
# originally-suggested solutions of using an empty array do not work. Only
|
||||
# setting these values to nil (without clearing the cache), allows Vagrant
|
||||
# to install and manage plugins.
|
||||
class Gem::Specification < Gem::BasicSpecification
|
||||
def self.vagrant_reset!
|
||||
@@all = @@stubs = nil
|
||||
end
|
||||
end
|
||||
|
||||
if ::Bundler::UI.const_defined? :Silent
|
||||
class BundlerUI < ::Bundler::UI::Silent
|
||||
attr_reader :output
|
||||
|
|
|
@ -324,10 +324,6 @@ module Vagrant
|
|||
error_key(:darwin_mount_failed)
|
||||
end
|
||||
|
||||
class DarwinNFSMountFailed < VagrantError
|
||||
error_key(:darwin_nfs_mount_failed)
|
||||
end
|
||||
|
||||
class DestroyRequiresForce < VagrantError
|
||||
error_key(:destroy_requires_force)
|
||||
end
|
||||
|
@ -404,10 +400,6 @@ module Vagrant
|
|||
error_key(:linux_mount_failed)
|
||||
end
|
||||
|
||||
class LinuxNFSMountFailed < VagrantError
|
||||
error_key(:linux_nfs_mount_failed)
|
||||
end
|
||||
|
||||
class LinuxRDPClientNotFound < VagrantError
|
||||
error_key(:linux_rdp_client_not_found)
|
||||
end
|
||||
|
@ -456,6 +448,10 @@ module Vagrant
|
|||
error_key(:not_found, "vagrant.actions.vm.host_only_network")
|
||||
end
|
||||
|
||||
class NetworkTypeNotSupported < VagrantError
|
||||
error_key(:network_type_not_supported)
|
||||
end
|
||||
|
||||
class NFSBadExports < VagrantError
|
||||
error_key(:nfs_bad_exports)
|
||||
end
|
||||
|
@ -464,6 +460,10 @@ module Vagrant
|
|||
error_key(:nfs_cant_read_exports)
|
||||
end
|
||||
|
||||
class NFSMountFailed < VagrantError
|
||||
error_key(:nfs_mount_failed)
|
||||
end
|
||||
|
||||
class NFSNoGuestIP < VagrantError
|
||||
error_key(:nfs_no_guest_ip)
|
||||
end
|
||||
|
@ -780,6 +780,14 @@ module Vagrant
|
|||
error_key(:virtualbox_no_name)
|
||||
end
|
||||
|
||||
class VirtualBoxMountFailed < VagrantError
|
||||
error_key(:virtualbox_mount_failed)
|
||||
end
|
||||
|
||||
class VirtualBoxMountNotSupportedBSD < VagrantError
|
||||
error_key(:virtualbox_mount_not_supported_bsd)
|
||||
end
|
||||
|
||||
class VirtualBoxNameExists < VagrantError
|
||||
error_key(:virtualbox_name_exists)
|
||||
end
|
||||
|
|
|
@ -109,6 +109,7 @@ module Vagrant
|
|||
@provider_options = provider_options
|
||||
@ui = Vagrant::UI::Prefixed.new(@env.ui, @name)
|
||||
@ui_mutex = Mutex.new
|
||||
@state_mutex = Mutex.new
|
||||
|
||||
# Read the ID, which is usually in local storage
|
||||
@id = nil
|
||||
|
@ -434,6 +435,8 @@ module Vagrant
|
|||
info[:host] ||= @config.ssh.default.host
|
||||
info[:port] ||= @config.ssh.default.port
|
||||
info[:private_key_path] ||= @config.ssh.default.private_key_path
|
||||
info[:keys_only] ||= @config.ssh.default.keys_only
|
||||
info[:paranoid] ||= @config.ssh.default.paranoid
|
||||
info[:username] ||= @config.ssh.default.username
|
||||
|
||||
# We set overrides if they are set. These take precedence over
|
||||
|
@ -505,11 +508,17 @@ module Vagrant
|
|||
# master index.
|
||||
uuid = index_uuid
|
||||
if uuid
|
||||
entry = @env.machine_index.get(uuid)
|
||||
if entry
|
||||
entry.state = result.short_description
|
||||
@env.machine_index.set(entry)
|
||||
@env.machine_index.release(entry)
|
||||
# active_machines provides access to query this info on each machine
|
||||
# from a different thread, ensure multiple machines do not access
|
||||
# the locked entry simultaneously as this triggers a locked machine
|
||||
# exception.
|
||||
@state_mutex.synchronize do
|
||||
entry = @env.machine_index.get(uuid)
|
||||
if entry
|
||||
entry.state = result.short_description
|
||||
@env.machine_index.set(entry)
|
||||
@env.machine_index.release(entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
require "json"
|
||||
require "fileutils"
|
||||
require "tempfile"
|
||||
|
||||
module Vagrant
|
||||
module Plugin
|
||||
|
@ -91,8 +93,13 @@ module Vagrant
|
|||
|
||||
# This saves the state back into the state file.
|
||||
def save!
|
||||
@path.open("w+") do |f|
|
||||
Tempfile.open(@path.basename.to_s, @path.dirname.to_s) do |f|
|
||||
f.binmode
|
||||
f.write(JSON.dump(@data))
|
||||
f.fsync
|
||||
f.chmod(0644)
|
||||
f.close
|
||||
FileUtils.mv(f.path, @path)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ module Vagrant
|
|||
end
|
||||
|
||||
def clear_line
|
||||
# See: http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
# See: https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
reset = "\r\033[K"
|
||||
|
||||
info(reset, new_line: false)
|
||||
|
|
|
@ -30,7 +30,7 @@ module Vagrant
|
|||
return true
|
||||
end
|
||||
rescue Timeout::Error, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, \
|
||||
Errno::ENETUNREACH, Errno::EACCES
|
||||
Errno::ENETUNREACH, Errno::EACCES, Errno::ENOTCONN
|
||||
# Any of the above exceptions signal that the port is closed.
|
||||
return false
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'rbconfig'
|
||||
require 'shellwords'
|
||||
require 'tmpdir'
|
||||
require "rbconfig"
|
||||
require "shellwords"
|
||||
require "tmpdir"
|
||||
|
||||
require "vagrant/util/subprocess"
|
||||
|
||||
|
@ -10,17 +10,21 @@ module Vagrant
|
|||
class Platform
|
||||
class << self
|
||||
def cygwin?
|
||||
# Installer detects Cygwin
|
||||
return true if ENV["VAGRANT_DETECTED_OS"] &&
|
||||
ENV["VAGRANT_DETECTED_OS"].downcase.include?("cygwin")
|
||||
return @_cygwin if defined?(@_cygwin)
|
||||
@_cygwin = -> {
|
||||
# Installer detects Cygwin
|
||||
return true if ENV["VAGRANT_DETECTED_OS"] &&
|
||||
ENV["VAGRANT_DETECTED_OS"].downcase.include?("cygwin")
|
||||
|
||||
# Ruby running in Cygwin
|
||||
return true if 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")
|
||||
# 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")
|
||||
}.call
|
||||
return @_cygwin
|
||||
end
|
||||
|
||||
[:darwin, :bsd, :freebsd, :linux, :solaris].each do |type|
|
||||
|
@ -30,11 +34,9 @@ module Vagrant
|
|||
end
|
||||
|
||||
def windows?
|
||||
%W[mingw mswin].each do |text|
|
||||
return true if platform.include?(text)
|
||||
end
|
||||
|
||||
false
|
||||
return @_windows if defined?(@_windows)
|
||||
@_windows = %w[mingw mswin].any? { |t| platform.include?(t) }
|
||||
return @_windows
|
||||
end
|
||||
|
||||
# Checks if the user running Vagrant on Windows has administrative
|
||||
|
@ -42,23 +44,28 @@ module Vagrant
|
|||
#
|
||||
# @return [Boolean]
|
||||
def windows_admin?
|
||||
return @_windows_admin if defined?(@_windows_admin)
|
||||
|
||||
# We lazily-load this because it is only available on Windows
|
||||
require 'win32/registry'
|
||||
require "win32/registry"
|
||||
|
||||
# Verify that we have administrative privileges. The odd method of
|
||||
# detecting this is based on this StackOverflow question:
|
||||
#
|
||||
# http://stackoverflow.com/questions/560366/
|
||||
# https://stackoverflow.com/questions/560366/
|
||||
# detect-if-running-with-administrator-privileges-under-windows-xp
|
||||
begin
|
||||
Win32::Registry::HKEY_USERS.open("S-1-5-19") {}
|
||||
rescue Win32::Registry::Error
|
||||
return false
|
||||
end
|
||||
@_windows_admin = -> {
|
||||
begin
|
||||
Win32::Registry::HKEY_USERS.open("S-1-5-19") {}
|
||||
|
||||
# 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?
|
||||
# The above doesn't seem to be 100% bullet proof. See GH-5616.
|
||||
return (`reg query HKU\\S-1-5-19 2>&1` =~ /ERROR/).nil?
|
||||
rescue Win32::Registry::Error
|
||||
return false
|
||||
end
|
||||
}.call
|
||||
|
||||
return @_windows_admin
|
||||
end
|
||||
|
||||
# Checks if the user running Vagrant on Windows is a member of the
|
||||
|
@ -70,14 +77,17 @@ module Vagrant
|
|||
#
|
||||
# @return [Boolean]
|
||||
def windows_hyperv_admin?
|
||||
return @_windows_hyperv_admin if defined?(@_windows_hyperv_admin)
|
||||
@_windows_hyperv_admin = -> {
|
||||
begin
|
||||
username = ENV["USERNAME"]
|
||||
process = Subprocess.execute("net", "localgroup", "Hyper-V Administrators")
|
||||
output = process.stdout.chomp
|
||||
return output.include?(username)
|
||||
return process.stdout.include?(username)
|
||||
rescue Errors::CommandUnavailableWindows
|
||||
return false
|
||||
end
|
||||
}.call
|
||||
return @_windows_hyperv_admin
|
||||
end
|
||||
|
||||
# This takes any path and converts it from a Windows path to a
|
||||
|
@ -125,16 +135,18 @@ module Vagrant
|
|||
# directory runs a different filesystem than the root directory.
|
||||
# However, this works in many cases.
|
||||
def fs_case_sensitive?
|
||||
Dir.mktmpdir("vagrant") do |tmp_dir|
|
||||
tmp_file = File.join(tmp_dir, "FILE")
|
||||
return @_fs_case_sensitive if defined?(@_fs_case_sensitive)
|
||||
@_fs_case_sensitive = Dir.mktmpdir("vagrant-fs-case-sensitive") do |dir|
|
||||
tmp_file = File.join(dir, "FILE")
|
||||
File.open(tmp_file, "w") do |f|
|
||||
f.write("foo")
|
||||
end
|
||||
|
||||
# The filesystem is case sensitive if the lowercased version
|
||||
# of the filename is NOT reported as existing.
|
||||
!File.file?(File.join(tmp_dir, "file"))
|
||||
!File.file?(File.join(dir, "file"))
|
||||
end
|
||||
return @_fs_case_sensitive
|
||||
end
|
||||
|
||||
# This expands the path and ensures proper casing of each part
|
||||
|
@ -197,18 +209,31 @@ module Vagrant
|
|||
# Returns a boolean noting whether the terminal supports color.
|
||||
# output.
|
||||
def terminal_supports_colors?
|
||||
if windows?
|
||||
return true if ENV.key?("ANSICON")
|
||||
return true if cygwin?
|
||||
return true if ENV["TERM"] == "cygwin"
|
||||
return false
|
||||
end
|
||||
return @_terminal_supports_colors if defined?(@_terminal_supports_colors)
|
||||
@_terminal_supports_colors = -> {
|
||||
if windows?
|
||||
return true if ENV.key?("ANSICON")
|
||||
return true if cygwin?
|
||||
return true if ENV["TERM"] == "cygwin"
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
return true
|
||||
}.call
|
||||
return @_terminal_supports_colors
|
||||
end
|
||||
|
||||
def platform
|
||||
RbConfig::CONFIG["host_os"].downcase
|
||||
return @_platform if defined?(@_platform)
|
||||
@_platform = RbConfig::CONFIG["host_os"].downcase
|
||||
return @_platform
|
||||
end
|
||||
|
||||
# @private
|
||||
# Reset the cached values for platform. This is not considered a public
|
||||
# API and should only be used for testing.
|
||||
def reset!
|
||||
instance_variables.each(&method(:remove_instance_variable))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ module VagrantPlugins
|
|||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
||||
o.on("-f", "--force", "Destroy without confirmation.") do |f|
|
||||
o.on("-f", "--force", "Remove without confirmation.") do |f|
|
||||
options[:force] = f
|
||||
end
|
||||
|
||||
|
|
|
@ -86,6 +86,8 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def update_vms(argv, provider, download_options)
|
||||
machines = {}
|
||||
|
||||
with_target_vms(argv, provider: provider) do |machine|
|
||||
if !machine.config.vm.box
|
||||
machine.ui.output(I18n.t(
|
||||
|
@ -100,6 +102,14 @@ module VagrantPlugins
|
|||
next
|
||||
end
|
||||
|
||||
name = machine.box.name
|
||||
provider = machine.box.provider
|
||||
version = machine.config.vm.box_version || machine.box.version
|
||||
|
||||
machines["#{name}_#{provider}_#{version}"] = machine
|
||||
end
|
||||
|
||||
machines.each do |_, machine|
|
||||
box = machine.box
|
||||
version = machine.config.vm.box_version
|
||||
# Get download options from machine configuration if not specified
|
||||
|
|
|
@ -10,7 +10,7 @@ module VagrantPlugins
|
|||
options[:force] = false
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant destroy [options] [name]"
|
||||
o.banner = "Usage: vagrant destroy [options] [name|id]"
|
||||
o.separator ""
|
||||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
|
|
@ -12,7 +12,7 @@ module VagrantPlugins
|
|||
options[:force] = false
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant halt [options] [name]"
|
||||
o.banner = "Usage: vagrant halt [options] [name|id]"
|
||||
o.separator ""
|
||||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
|
|
@ -22,6 +22,10 @@ module VagrantPlugins
|
|||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
||||
o.on("--box-version VERSION", "Version of the box to add") do |f|
|
||||
options[:box_version] = f
|
||||
end
|
||||
|
||||
o.on("-f", "--force", "Overwrite existing Vagrantfile") do |f|
|
||||
options[:force] = f
|
||||
end
|
||||
|
@ -54,8 +58,10 @@ module VagrantPlugins
|
|||
|
||||
template_path = ::Vagrant.source_root.join(template)
|
||||
contents = Vagrant::Util::TemplateRenderer.render(template_path,
|
||||
box_name: argv[0] || "base",
|
||||
box_url: argv[1])
|
||||
box_name: argv[0] || "base",
|
||||
box_url: argv[1],
|
||||
box_version: options[:box_version],
|
||||
)
|
||||
|
||||
if save_path
|
||||
# Write out the contents
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
require "rest_client"
|
||||
require "vagrant/util/downloader"
|
||||
require "vagrant/util/presence"
|
||||
|
||||
module VagrantPlugins
|
||||
module LoginCommand
|
||||
class Client
|
||||
include Vagrant::Util::Presence
|
||||
|
||||
# Initializes a login client with the given Vagrant::Environment.
|
||||
#
|
||||
# @param [Vagrant::Environment] env
|
||||
|
@ -50,6 +53,7 @@ module VagrantPlugins
|
|||
proxy = nil
|
||||
proxy ||= ENV["HTTPS_PROXY"] || ENV["https_proxy"]
|
||||
proxy ||= ENV["HTTP_PROXY"] || ENV["http_proxy"]
|
||||
RestClient.proxy = proxy
|
||||
|
||||
response = RestClient::Request.execute(
|
||||
method: :post,
|
||||
|
@ -87,7 +91,21 @@ module VagrantPlugins
|
|||
#
|
||||
# @return [String]
|
||||
def token
|
||||
if ENV["ATLAS_TOKEN"] && !ENV["ATLAS_TOKEN"].empty?
|
||||
if present?(ENV["ATLAS_TOKEN"]) && token_path.exist?
|
||||
@env.ui.warn <<-EOH.strip
|
||||
Vagrant detected both the ATLAS_TOKEN environment variable and a Vagrant login
|
||||
token are present on this system. The ATLAS_TOKEN environment variable takes
|
||||
precedence over the locally stored token. To remove this error, either unset
|
||||
the ATLAS_TOKEN environment variable or remove the login token stored on disk:
|
||||
|
||||
~/.vagrant.d/data/vagrant_login_token
|
||||
|
||||
In general, the ATLAS_TOKEN is more preferred because it is respected by all
|
||||
HashiCorp products.
|
||||
EOH
|
||||
end
|
||||
|
||||
if present?(ENV["ATLAS_TOKEN"])
|
||||
@logger.debug("Using authentication token from environment variable")
|
||||
return ENV["ATLAS_TOKEN"]
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ module VagrantPlugins
|
|||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant package [options] [name]"
|
||||
o.banner = "Usage: vagrant package [options] [name|id]"
|
||||
o.separator ""
|
||||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
|
|
@ -5,7 +5,7 @@ module VagrantPlugins
|
|||
def build_install_opts(o, options)
|
||||
options[:plugin_sources] = [
|
||||
"https://rubygems.org",
|
||||
"http://gems.hashicorp.com",
|
||||
"https://gems.hashicorp.com",
|
||||
]
|
||||
|
||||
o.on("--entry-point NAME", String,
|
||||
|
|
|
@ -43,7 +43,7 @@ module VagrantPlugins
|
|||
# Clear the sources so that installation uses custom sources
|
||||
old_sources = Gem.sources
|
||||
Gem.sources = Gem.default_sources
|
||||
Gem.sources << "http://gems.hashicorp.com"
|
||||
Gem.sources << "https://gems.hashicorp.com"
|
||||
|
||||
# Use a silent UI so that we have no output
|
||||
Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) do
|
||||
|
|
|
@ -15,7 +15,7 @@ module VagrantPlugins
|
|||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant port [options] [name]"
|
||||
o.banner = "Usage: vagrant port [options] [name|id]"
|
||||
o.separator ""
|
||||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
|
|
@ -11,7 +11,7 @@ module VagrantPlugins
|
|||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant rdp [options] [name] [-- extra args]"
|
||||
o.banner = "Usage: vagrant rdp [options] [name|id] [-- extra args]"
|
||||
end
|
||||
|
||||
# Parse out the extra args to send to the RDP client, which
|
||||
|
|
|
@ -1,24 +1,38 @@
|
|||
require 'optparse'
|
||||
|
||||
require Vagrant.source_root.join("plugins/commands/up/start_mixins")
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandResume
|
||||
class Command < Vagrant.plugin("2", :command)
|
||||
# We assume that the `up` plugin exists and that we'll have access
|
||||
# to this.
|
||||
include VagrantPlugins::CommandUp::StartMixins
|
||||
|
||||
def self.synopsis
|
||||
"resume a suspended vagrant machine"
|
||||
end
|
||||
|
||||
def execute
|
||||
options = {}
|
||||
options[:provision_ignore_sentinel] = false
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant resume [vm-name]"
|
||||
o.separator ""
|
||||
build_start_options(o, options)
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
|
||||
# Validate the provisioners
|
||||
validate_provisioner_flags!(options, argv)
|
||||
|
||||
@logger.debug("'resume' each target VM...")
|
||||
with_target_vms(argv) do |machine|
|
||||
machine.action(:resume)
|
||||
machine.action(:resume, options)
|
||||
end
|
||||
|
||||
# Success, exit status 0
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
require 'json'
|
||||
require 'optparse'
|
||||
|
||||
require 'vagrant'
|
||||
|
||||
require Vagrant.source_root.join("plugins/commands/up/start_mixins")
|
||||
|
||||
require_relative "push_shared"
|
||||
|
||||
module VagrantPlugins
|
||||
|
@ -8,19 +12,30 @@ module VagrantPlugins
|
|||
module Command
|
||||
class Pop < Vagrant.plugin("2", :command)
|
||||
include PushShared
|
||||
include VagrantPlugins::CommandUp::StartMixins
|
||||
|
||||
def execute
|
||||
options = {}
|
||||
options[:snapshot_delete] = true
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant snapshot pop [options] [vm-name]"
|
||||
o.separator ""
|
||||
build_start_options(o, options)
|
||||
o.separator "Restore state that was pushed with `vagrant snapshot push`."
|
||||
|
||||
o.on("--no-delete", "Don't delete the snapshot after the restore") do
|
||||
options[:snapshot_delete] = false
|
||||
end
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
|
||||
return shared_exec(argv, method(:pop))
|
||||
# Validate the provisioners
|
||||
validate_provisioner_flags!(options, argv)
|
||||
|
||||
return shared_exec(argv, method(:pop), options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ module VagrantPlugins
|
|||
module CommandSnapshot
|
||||
module Command
|
||||
module PushShared
|
||||
def shared_exec(argv, m)
|
||||
def shared_exec(argv, m, opts={})
|
||||
with_target_vms(argv) do |vm|
|
||||
if !vm.id
|
||||
vm.ui.info("Not created. Cannot push snapshot state.")
|
||||
|
@ -12,7 +12,7 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
vm.env.lock("machine-snapshot-stack") do
|
||||
m.call(vm)
|
||||
m.call(vm, opts)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -20,14 +20,14 @@ module VagrantPlugins
|
|||
0
|
||||
end
|
||||
|
||||
def push(machine)
|
||||
def push(machine, opts={})
|
||||
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)
|
||||
def pop(machine, opts={})
|
||||
# By reverse sorting, we should be able to find the first
|
||||
# pushed snapshot.
|
||||
name = nil
|
||||
|
@ -45,11 +45,9 @@ module VagrantPlugins
|
|||
return
|
||||
end
|
||||
|
||||
# Restore the snapshot and tell the provider to delete it as well.
|
||||
machine.action(
|
||||
:snapshot_restore,
|
||||
snapshot_name: name,
|
||||
snapshot_delete: true)
|
||||
# Restore the snapshot and tell the provider to delete it, if required
|
||||
opts[:snapshot_name] = name
|
||||
machine.action(:snapshot_restore, opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
require 'optparse'
|
||||
|
||||
require 'vagrant'
|
||||
|
||||
require Vagrant.source_root.join("plugins/commands/up/start_mixins")
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandSnapshot
|
||||
module Command
|
||||
class Restore < Vagrant.plugin("2", :command)
|
||||
|
||||
include VagrantPlugins::CommandUp::StartMixins
|
||||
|
||||
def execute
|
||||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant snapshot restore [options] [vm-name] <name>"
|
||||
o.separator ""
|
||||
build_start_options(o, options)
|
||||
o.separator "Restore a snapshot taken previously with snapshot save."
|
||||
end
|
||||
|
||||
|
@ -21,9 +29,14 @@ module VagrantPlugins
|
|||
help: opts.help.chomp
|
||||
end
|
||||
|
||||
# Validate the provisioners
|
||||
validate_provisioner_flags!(options, argv)
|
||||
|
||||
name = argv.pop
|
||||
options[:snapshot_name] = name
|
||||
|
||||
with_target_vms(argv) do |vm|
|
||||
vm.action(:snapshot_restore, snapshot_name: name)
|
||||
vm.action(:snapshot_restore, options)
|
||||
end
|
||||
|
||||
# Success, exit status 0
|
||||
|
|
|
@ -11,7 +11,7 @@ module VagrantPlugins
|
|||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant ssh [options] [name] [-- extra ssh args]"
|
||||
o.banner = "Usage: vagrant ssh [options] [name|id] [-- extra ssh args]"
|
||||
o.separator ""
|
||||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
@ -55,6 +55,7 @@ module VagrantPlugins
|
|||
exit_status = env[:ssh_run_exit_status] || 0
|
||||
return exit_status
|
||||
else
|
||||
Vagrant::Bundler.instance.deinit
|
||||
@logger.debug("Invoking `ssh` action on machine")
|
||||
vm.action(:ssh, ssh_opts: ssh_opts)
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ module VagrantPlugins
|
|||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant ssh-config [options] [name]"
|
||||
o.banner = "Usage: vagrant ssh-config [options] [name|id]"
|
||||
o.separator ""
|
||||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
|
|
@ -9,7 +9,7 @@ module VagrantPlugins
|
|||
|
||||
def execute
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant status [name]"
|
||||
o.banner = "Usage: vagrant status [name|id]"
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
|
|
|
@ -9,7 +9,7 @@ module VagrantPlugins
|
|||
|
||||
def execute
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant suspend [name]"
|
||||
o.banner = "Usage: vagrant suspend [name|id]"
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
|
|
|
@ -22,7 +22,7 @@ module VagrantPlugins
|
|||
options[:provision_ignore_sentinel] = false
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant up [options] [name]"
|
||||
o.banner = "Usage: vagrant up [options] [name|id]"
|
||||
o.separator ""
|
||||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
@ -128,9 +128,9 @@ module VagrantPlugins
|
|||
# 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|
|
||||
with_target_vms(names) do |machine|
|
||||
# Check if we have this machine in the index
|
||||
entry = @env.machine_index.get(name.to_s)
|
||||
entry = @env.machine_index.get(machine.name.to_s)
|
||||
|
||||
# Get the provider for this machine. This logic isn't completely
|
||||
# straightforward. If we have a forced provider, we always use
|
||||
|
@ -146,7 +146,7 @@ module VagrantPlugins
|
|||
p = provider
|
||||
p = entry.provider.to_sym if !p && entry
|
||||
p = @env.default_provider(
|
||||
machine: name.to_sym, check_usable: false) if !p
|
||||
machine: machine.name.to_sym, check_usable: false) if !p
|
||||
|
||||
# Add it to the set
|
||||
providers.add(p)
|
||||
|
|
|
@ -335,8 +335,8 @@ module VagrantPlugins
|
|||
forward_agent: ssh_info[:forward_agent],
|
||||
send_env: ssh_info[:forward_env],
|
||||
keys: ssh_info[:private_key_path],
|
||||
keys_only: true,
|
||||
paranoid: false,
|
||||
keys_only: ssh_info[:keys_only],
|
||||
paranoid: ssh_info[:paranoid],
|
||||
password: ssh_info[:password],
|
||||
port: ssh_info[:port],
|
||||
timeout: 15,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "timeout"
|
||||
|
||||
require "log4r"
|
||||
require "tempfile"
|
||||
require "timeout"
|
||||
|
||||
require_relative "helper"
|
||||
require_relative "shell"
|
||||
|
@ -10,6 +10,8 @@ module VagrantPlugins
|
|||
module CommunicatorWinRM
|
||||
# Provides communication channel for Vagrant commands via WinRM.
|
||||
class Communicator < Vagrant.plugin("2", :communicator)
|
||||
include Vagrant::Util
|
||||
|
||||
def self.match?(machine)
|
||||
# This is useless, and will likely be removed in the future (this
|
||||
# whole method).
|
||||
|
@ -142,6 +144,7 @@ module VagrantPlugins
|
|||
|
||||
opts[:good_exit] = Array(opts[:good_exit])
|
||||
command = wrap_in_scheduled_task(command, opts[:interactive]) if opts[:elevated]
|
||||
@logger.debug("#{opts[:shell]} executing:\n#{command}")
|
||||
output = shell.send(opts[:shell], command, &block)
|
||||
execution_output(output, opts)
|
||||
end
|
||||
|
@ -201,15 +204,12 @@ module VagrantPlugins
|
|||
interactive: interactive,
|
||||
})
|
||||
guest_script_path = "c:/tmp/vagrant-elevated-shell.ps1"
|
||||
file = Tempfile.new(["vagrant-elevated-shell", "ps1"])
|
||||
begin
|
||||
file.write(script)
|
||||
file.fsync
|
||||
file.close
|
||||
upload(file.path, guest_script_path)
|
||||
ensure
|
||||
file.close
|
||||
file.unlink
|
||||
Tempfile.open(["vagrant-elevated-shell", "ps1"]) do |f|
|
||||
f.binmode
|
||||
f.write(script)
|
||||
f.fsync
|
||||
f.close
|
||||
upload(f.path, guest_script_path)
|
||||
end
|
||||
|
||||
# Convert to double byte unicode string then base64 encode
|
||||
|
|
|
@ -12,6 +12,7 @@ module VagrantPlugins
|
|||
attr_accessor :transport
|
||||
attr_accessor :ssl_peer_verification
|
||||
attr_accessor :execution_time_limit
|
||||
attr_accessor :basic_auth_only
|
||||
|
||||
def initialize
|
||||
@username = UNSET_VALUE
|
||||
|
@ -25,12 +26,13 @@ module VagrantPlugins
|
|||
@transport = UNSET_VALUE
|
||||
@ssl_peer_verification = UNSET_VALUE
|
||||
@execution_time_limit = UNSET_VALUE
|
||||
@basic_auth_only = UNSET_VALUE
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@username = "vagrant" if @username == UNSET_VALUE
|
||||
@password = "vagrant" if @password == UNSET_VALUE
|
||||
@transport = :plaintext if @transport == UNSET_VALUE
|
||||
@transport = :negotiate if @transport == UNSET_VALUE
|
||||
@host = nil if @host == UNSET_VALUE
|
||||
is_ssl = @transport == :ssl
|
||||
@port = (is_ssl ? 5986 : 5985) if @port == UNSET_VALUE
|
||||
|
@ -40,6 +42,7 @@ module VagrantPlugins
|
|||
@timeout = 1800 if @timeout == UNSET_VALUE
|
||||
@ssl_peer_verification = true if @ssl_peer_verification == UNSET_VALUE
|
||||
@execution_time_limit = "PT2H" if @execution_time_limit == UNSET_VALUE
|
||||
@basic_auth_only = false if @basic_auth_only == UNSET_VALUE
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
|
@ -56,6 +59,9 @@ module VagrantPlugins
|
|||
unless @ssl_peer_verification == true || @ssl_peer_verification == false
|
||||
errors << "winrm.ssl_peer_verification must be a boolean."
|
||||
end
|
||||
unless @basic_auth_only == true || @basic_auth_only == false
|
||||
errors << "winrm.basic_auth_only must be a boolean."
|
||||
end
|
||||
|
||||
{ "WinRM" => errors }
|
||||
end
|
||||
|
|
|
@ -54,20 +54,21 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def powershell(command, &block)
|
||||
# Suppress the progress stream from leaking to stderr
|
||||
command = "$ProgressPreference='SilentlyContinue';\r\n" + command
|
||||
command << "\r\n"
|
||||
# Ensure an exit code
|
||||
command << "if ($?) { exit 0 } else { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }"
|
||||
execute_shell(command, :powershell, &block)
|
||||
command += "\r\nif ($?) { exit 0 } else { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }"
|
||||
execute_with_rescue(executor.method("run_powershell_script"), command, &block)
|
||||
end
|
||||
|
||||
def cmd(command, &block)
|
||||
execute_shell(command, :cmd, &block)
|
||||
execute_with_rescue(executor.method("run_cmd"), command, &block)
|
||||
end
|
||||
|
||||
def wql(query, &block)
|
||||
execute_shell(query, :wql, &block)
|
||||
retryable(tries: @config.max_tries, on: @@exceptions_to_retry_on, sleep: @config.retry_delay) do
|
||||
handle_output(session.method("run_wql"), query, &block)
|
||||
end
|
||||
rescue => e
|
||||
raise_winrm_exception(e, "run_wql", query)
|
||||
end
|
||||
|
||||
def upload(from, to)
|
||||
|
@ -82,42 +83,35 @@ module VagrantPlugins
|
|||
|
||||
protected
|
||||
|
||||
def execute_shell(command, shell=:powershell, &block)
|
||||
raise Errors::WinRMInvalidShell, shell: shell unless [:powershell, :cmd, :wql].include?(shell)
|
||||
|
||||
begin
|
||||
execute_shell_with_retry(command, shell, &block)
|
||||
rescue => e
|
||||
raise_winrm_exception(e, shell, command)
|
||||
end
|
||||
def execute_with_rescue(method, command, &block)
|
||||
handle_output(method, command, &block)
|
||||
rescue => e
|
||||
raise_winrm_exception(e, method.name, command)
|
||||
end
|
||||
|
||||
def execute_shell_with_retry(command, shell, &block)
|
||||
retryable(tries: @config.max_tries, on: @@exceptions_to_retry_on, sleep: @config.retry_delay) do
|
||||
@logger.debug("#{shell} executing:\n#{command}")
|
||||
output = session.send(shell, command) do |out, err|
|
||||
block.call(:stdout, out) if block_given? && out
|
||||
block.call(:stderr, err) if block_given? && err
|
||||
end
|
||||
def handle_output(execute_method, command, &block)
|
||||
output = execute_method.call(command) do |out, err|
|
||||
block.call(:stdout, out) if block_given? && out
|
||||
block.call(:stderr, err) if block_given? && err
|
||||
end
|
||||
|
||||
@logger.debug("Output: #{output.inspect}")
|
||||
@logger.debug("Output: #{output.inspect}")
|
||||
|
||||
# Verify that we didn't get a parser error, and if so we should
|
||||
# set the exit code to 1. Parse errors return exit code 0 so we
|
||||
# need to do this.
|
||||
if output[:exitcode] == 0
|
||||
(output[:data] || []).each do |data|
|
||||
next if !data[:stderr]
|
||||
if data[:stderr].include?("ParserError")
|
||||
@logger.warn("Detected ParserError, setting exit code to 1")
|
||||
output[:exitcode] = 1
|
||||
break
|
||||
end
|
||||
# Verify that we didn't get a parser error, and if so we should
|
||||
# set the exit code to 1. Parse errors return exit code 0 so we
|
||||
# need to do this.
|
||||
if output[:exitcode] == 0
|
||||
(output[:data] || []).each do |data|
|
||||
next if !data[:stderr]
|
||||
if data[:stderr].include?("ParserError")
|
||||
@logger.warn("Detected ParserError, setting exit code to 1")
|
||||
output[:exitcode] = 1
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
def raise_winrm_exception(exception, shell = nil, command = nil)
|
||||
|
@ -170,7 +164,7 @@ module VagrantPlugins
|
|||
|
||||
client = ::WinRM::WinRMWebService.new(endpoint, @config.transport.to_sym, endpoint_options)
|
||||
client.set_timeout(@config.timeout)
|
||||
client.toggle_nori_type_casting(:off) #we don't want coersion of types
|
||||
client.logger = @logger
|
||||
client
|
||||
end
|
||||
|
||||
|
@ -178,11 +172,15 @@ module VagrantPlugins
|
|||
@session ||= new_session
|
||||
end
|
||||
|
||||
def executor
|
||||
@executor ||= session.create_executor
|
||||
end
|
||||
|
||||
def endpoint
|
||||
case @config.transport.to_sym
|
||||
when :ssl
|
||||
"https://#{@host}:#{@port}/wsman"
|
||||
when :plaintext
|
||||
when :plaintext, :negotiate
|
||||
"http://#{@host}:#{@port}/wsman"
|
||||
else
|
||||
raise Errors::WinRMInvalidTransport, transport: @config.transport
|
||||
|
@ -194,8 +192,10 @@ module VagrantPlugins
|
|||
pass: @password,
|
||||
host: @host,
|
||||
port: @port,
|
||||
basic_auth_only: true,
|
||||
no_ssl_peer_verification: !@config.ssl_peer_verification }
|
||||
basic_auth_only: @config.basic_auth_only,
|
||||
no_ssl_peer_verification: !@config.ssl_peer_verification,
|
||||
retry_delay: @config.retry_delay,
|
||||
retry_limit: @config.max_tries }
|
||||
end
|
||||
end #WinShell class
|
||||
end
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
module VagrantPlugins
|
||||
module GuestAmazon
|
||||
module Cap
|
||||
class Flavor
|
||||
def self.flavor(machine)
|
||||
# Amazon AMI is a frankenstien RHEL, mainly based on 6
|
||||
# Maybe in the future if they incoporate RHEL 7 elements
|
||||
# this should be extended to read /etc/os-release or similar
|
||||
return :rhel
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
module VagrantPlugins
|
||||
module GuestAmazon
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("grep 'Amazon Linux AMI' /etc/os-release")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestAmazon
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "Amazon Linux guest"
|
||||
description "Amazon linux guest support."
|
||||
|
||||
guest(:amazon, :redhat) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability(:amazon, :flavor) do
|
||||
require_relative "cap/flavor"
|
||||
Cap::Flavor
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,12 +3,24 @@ module VagrantPlugins
|
|||
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("hostnamectl set-hostname #{name}")
|
||||
comm.sudo("sed -i 's@^\\(127[.]0[.]0[.]1[[:space:]]\\+\\)@\\1#{name} @' /etc/hosts")
|
||||
end
|
||||
comm = machine.communicate
|
||||
|
||||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, "")
|
||||
set -e
|
||||
|
||||
# Set hostname
|
||||
hostnamectl set-hostname '#{basename}'
|
||||
|
||||
# Remove comments and blank lines from /etc/hosts
|
||||
sed -i'' -e 's/#.*$//' -e '/^$/d' /etc/hosts
|
||||
|
||||
# Prepend ourselves to /etc/hosts
|
||||
grep -w '#{name}' /etc/hosts || {
|
||||
sed -i'' '1i 127.0.0.1\\t#{name}\\t#{basename}' /etc/hosts
|
||||
}
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
require "ipaddr"
|
||||
require "socket"
|
||||
require "tempfile"
|
||||
|
||||
require "vagrant/util/template_renderer"
|
||||
require_relative "../../../../lib/vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestArch
|
||||
|
@ -10,25 +11,46 @@ module VagrantPlugins
|
|||
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
|
||||
comm = machine.communicate
|
||||
|
||||
networks.each do |network|
|
||||
commands = ["set -e"]
|
||||
interfaces = machine.guest.capability(:network_interfaces)
|
||||
|
||||
networks.each.with_index do |network, i|
|
||||
network[:device] = interfaces[network[:interface]]
|
||||
|
||||
entry = TemplateRenderer.render("guests/arch/network_#{network[:type]}", options: network)
|
||||
# Arch expects netmasks to be in the "24" or "64", but users may
|
||||
# specify IPV4 netmasks like "255.255.255.0". This magic converts
|
||||
# the netmask to the proper value.
|
||||
if network[:netmask] && network[:netmask].to_s.include?(".")
|
||||
network[:netmask] = (32-Math.log2((IPAddr.new(network[:netmask], Socket::AF_INET).to_i^0xffffffff)+1)).to_i
|
||||
end
|
||||
|
||||
temp = Tempfile.new("vagrant")
|
||||
temp.binmode
|
||||
temp.write(entry)
|
||||
temp.close
|
||||
entry = TemplateRenderer.render("guests/arch/network_#{network[:type]}",
|
||||
options: network,
|
||||
)
|
||||
|
||||
machine.communicate.upload(temp.path, "/tmp/vagrant_network")
|
||||
machine.communicate.sudo("mv /tmp/vagrant_network /etc/netctl/#{network[:device]}")
|
||||
machine.communicate.sudo("ip link set #{network[:device]} down && netctl start #{network[:device]} && netctl enable #{network[:device]}")
|
||||
remote_path = "/tmp/vagrant-network-#{network[:device]}-#{Time.now.to_i}-#{i}"
|
||||
|
||||
Tempfile.open("vagrant-arch-configure-networks") do |f|
|
||||
f.binmode
|
||||
f.write(entry)
|
||||
f.fsync
|
||||
f.close
|
||||
comm.upload(f.path, remote_path)
|
||||
end
|
||||
|
||||
commands << <<-EOH.gsub(/^ {14}/, '')
|
||||
# Configure #{network[:device]}
|
||||
mv '#{remote_path}' '/etc/netctl/#{network[:device]}'
|
||||
ip link set '#{network[:device]}' down
|
||||
netctl restart '#{network[:device]}'
|
||||
netctl enable '#{network[:device]}'
|
||||
EOH
|
||||
end
|
||||
|
||||
# Run all the network modification commands in one communicator call.
|
||||
comm.sudo(commands.join("\n"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
module VagrantPlugins
|
||||
module GuestArch
|
||||
module Cap
|
||||
class NFS
|
||||
def self.nfs_client_installed(machine)
|
||||
machine.communicate.test("pacman -Q nfs-utils")
|
||||
end
|
||||
|
||||
def self.nfs_pre(machine)
|
||||
comm = machine.communicate
|
||||
|
||||
# There is a bug in NFS where the rpcbind functionality is not started
|
||||
# and it's not a dependency of nfs-utils. Read more here:
|
||||
#
|
||||
# https://bbs.archlinux.org/viewtopic.php?id=193410
|
||||
#
|
||||
comm.sudo <<-EOH.gsub(/^ {12}/, "")
|
||||
set -e
|
||||
systemctl enable rpcbind
|
||||
systemctl start rpcbind
|
||||
EOH
|
||||
end
|
||||
|
||||
def self.nfs_client_install(machine)
|
||||
comm = machine.communicate
|
||||
comm.sudo <<-EOH.gsub(/^ {12}/, "")
|
||||
set -e
|
||||
pacman --noconfirm -Syy
|
||||
pacman --noconfirm -S nfs-utils ntp
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
module VagrantPlugins
|
||||
module GuestArch
|
||||
module Cap
|
||||
class RSync
|
||||
def self.rsync_install(machine)
|
||||
comm = machine.communicate
|
||||
comm.sudo <<-EOH.gsub(/^ {12}/, '')
|
||||
set -e
|
||||
pacman -Sy --noconfirm
|
||||
pacman -S --noconfirm rsync
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
module VagrantPlugins
|
||||
module GuestArch
|
||||
module Cap
|
||||
class SMB
|
||||
def self.smb_install(machine)
|
||||
comm = machine.communicate
|
||||
if !comm.test("test -f /usr/bin/mount.cifs")
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, '')
|
||||
pacman -Sy --noconfirm
|
||||
pacman -S --noconfirm cifs-utils
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,20 +6,45 @@ module VagrantPlugins
|
|||
name "Arch guest"
|
||||
description "Arch guest support."
|
||||
|
||||
guest("arch", "linux") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
guest(:arch, :linux) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("arch", "change_host_name") do
|
||||
guest_capability(:arch, :change_host_name) do
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
|
||||
guest_capability("arch", "configure_networks") do
|
||||
guest_capability(:arch, :configure_networks) do
|
||||
require_relative "cap/configure_networks"
|
||||
Cap::ConfigureNetworks
|
||||
end
|
||||
|
||||
guest_capability(:arch, :nfs_client_install) do
|
||||
require_relative "cap/nfs"
|
||||
Cap::NFS
|
||||
end
|
||||
|
||||
guest_capability(:arch, :nfs_client_installed) do
|
||||
require_relative "cap/nfs"
|
||||
Cap::NFS
|
||||
end
|
||||
|
||||
guest_capability(:arch, :nfs_pre) do
|
||||
require_relative "cap/nfs"
|
||||
Cap::NFS
|
||||
end
|
||||
|
||||
guest_capability(:arch, :rsync_install) do
|
||||
require_relative "cap/rsync"
|
||||
Cap::RSync
|
||||
end
|
||||
|
||||
guest_capability(:arch, :smb_install) do
|
||||
require_relative "cap/smb"
|
||||
Cap::SMB
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,25 @@ module VagrantPlugins
|
|||
module Cap
|
||||
class ChangeHostName
|
||||
def self.change_host_name(machine, name)
|
||||
machine.communicate.sudo("hostnamectl set-hostname #{name}")
|
||||
comm = machine.communicate
|
||||
|
||||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, "")
|
||||
set -e
|
||||
|
||||
# Set hostname
|
||||
hostnamectl set-hostname '#{basename}'
|
||||
|
||||
# Remove comments and blank lines from /etc/hosts
|
||||
sed -i'' -e 's/#.*$//' -e '/^$/d' /etc/hosts
|
||||
|
||||
# Prepend ourselves to /etc/hosts
|
||||
grep -w '#{name}' /etc/hosts || {
|
||||
sed -i'' '1i 127.0.0.1\\t#{name}\\t#{basename}' /etc/hosts
|
||||
}
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'vagrant'
|
||||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestAtomic
|
||||
|
@ -6,17 +6,17 @@ module VagrantPlugins
|
|||
name "Atomic Host guest"
|
||||
description "Atomic Host guest support."
|
||||
|
||||
guest("atomic", "fedora") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
guest(:atomic, :fedora) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("atomic", "change_host_name") do
|
||||
guest_capability(:atomic, :change_host_name) do
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
|
||||
guest_capability("atomic", "docker_daemon_running") do
|
||||
guest_capability(:atomic, :docker_daemon_running) do
|
||||
require_relative "cap/docker"
|
||||
Cap::Docker
|
||||
end
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
module VagrantPlugins
|
||||
module GuestOpenBSD
|
||||
module GuestBSD
|
||||
module Cap
|
||||
class Halt
|
||||
def self.halt(machine)
|
||||
begin
|
||||
machine.communicate.sudo("shutdown -p -h now")
|
||||
machine.communicate.sudo("/sbin/shutdown -p now", shell: "sh")
|
||||
rescue IOError
|
||||
# Do nothing, because it probably means the machine shut down
|
||||
# and SSH connection was lost.
|
|
@ -0,0 +1,49 @@
|
|||
require "shellwords"
|
||||
require "vagrant/util/retryable"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestBSD
|
||||
module Cap
|
||||
class NFS
|
||||
extend Vagrant::Util::Retryable
|
||||
|
||||
# Mount the given NFS folder.
|
||||
def self.mount_nfs_folder(machine, ip, folders)
|
||||
comm = machine.communicate
|
||||
|
||||
folders.each do |name, opts|
|
||||
# Mount each folder separately so we can retry.
|
||||
commands = ["set -e"]
|
||||
|
||||
# Shellescape the paths in case they do not have special characters.
|
||||
guest_path = Shellwords.escape(opts[:guestpath])
|
||||
host_path = Shellwords.escape(opts[:hostpath])
|
||||
|
||||
# Build the list of mount options.
|
||||
mount_opts = []
|
||||
mount_opts << "nfsv#{opts[:nfs_version]}" if opts[:nfs_version]
|
||||
mount_opts << "mntudp" if opts[:nfs_udp]
|
||||
if opts[:mount_options]
|
||||
mount_opts = mount_opts + opts[:mount_options].dup
|
||||
end
|
||||
mount_opts = mount_opts.join(",")
|
||||
|
||||
# Make the directory on the guest.
|
||||
commands << "mkdir -p #{guest_path}"
|
||||
|
||||
# Perform the mount operation.
|
||||
commands << "/sbin/mount -t nfs -o '#{mount_opts}' #{ip}:#{host_path} #{guest_path}"
|
||||
|
||||
# Run the command, raising a specific error.
|
||||
retryable(on: Vagrant::Errors::NFSMountFailed, tries: 3, sleep: 5) do
|
||||
machine.communicate.sudo(commands.join("\n"),
|
||||
error_class: Vagrant::Errors::NFSMountFailed,
|
||||
shell: "sh",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,66 @@
|
|||
require "tempfile"
|
||||
|
||||
require "vagrant/util/shell_quote"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestBSD
|
||||
module Cap
|
||||
class PublicKey
|
||||
def self.insert_public_key(machine, contents)
|
||||
comm = machine.communicate
|
||||
contents = contents.strip << "\n"
|
||||
|
||||
remote_path = "/tmp/vagrant-insert-pubkey-#{Time.now.to_i}"
|
||||
Tempfile.open("vagrant-bsd-insert-public-key") do |f|
|
||||
f.binmode
|
||||
f.write(contents)
|
||||
f.fsync
|
||||
f.close
|
||||
comm.upload(f.path, remote_path)
|
||||
end
|
||||
|
||||
# Use execute (not sudo) because we want to execute this as the SSH
|
||||
# user (which is "vagrant" by default).
|
||||
comm.execute <<-EOH.gsub(/^ {12}/, "")
|
||||
set -e
|
||||
|
||||
mkdir -p ~/.ssh
|
||||
chmod 0700 ~/.ssh
|
||||
cat '#{remote_path}' >> ~/.ssh/authorized_keys
|
||||
chmod 0600 ~/.ssh/authorized_keys
|
||||
|
||||
rm -f '#{remote_path}'
|
||||
EOH
|
||||
end
|
||||
|
||||
def self.remove_public_key(machine, contents)
|
||||
comm = machine.communicate
|
||||
contents = contents.strip << "\n"
|
||||
|
||||
remote_path = "/tmp/vagrant-remove-pubkey-#{Time.now.to_i}"
|
||||
Tempfile.open("vagrant-bsd-remove-public-key") do |f|
|
||||
f.binmode
|
||||
f.write(contents)
|
||||
f.fsync
|
||||
f.close
|
||||
comm.upload(f.path, remote_path)
|
||||
end
|
||||
|
||||
# Use execute (not sudo) because we want to execute this as the SSH
|
||||
# user (which is "vagrant" by default).
|
||||
comm.execute <<-EOH.sub(/^ {12}/, "")
|
||||
set -e
|
||||
|
||||
if test -f ~/.ssh/authorized_keys; then
|
||||
grep -v -x -f '#{remote_path}' ~/.ssh/authorized_keys > ~/.ssh/authorized_keys.tmp
|
||||
mv ~/.ssh/authorized_keys.tmp ~/.ssh/authorized_keys
|
||||
chmod 0600 ~/.ssh/authorized_keys
|
||||
fi
|
||||
|
||||
rm -f '#{remote_path}'
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
module VagrantPlugins
|
||||
module GuestBSD
|
||||
module Cap
|
||||
class VirtualBox
|
||||
# BSD-based guests do not currently support VirtualBox synced folders.
|
||||
# Instead of raising an error about a missing capability, this defines
|
||||
# the capability and then provides a more detailed error message,
|
||||
# linking to sources on the Internet where the problem is
|
||||
# better-described.
|
||||
def self.mount_virtualbox_shared_folder(machine, name, guestpath, options)
|
||||
raise Vagrant::Errors::VirtualBoxMountNotSupportedBSD
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
module VagrantPlugins
|
||||
module GuestBSD
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("uname -s | grep -i 'Darwin|BSD'")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestBSD
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "BSD-based guest"
|
||||
description "BSD-based guest support."
|
||||
|
||||
guest(:bsd) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability(:bsd, :halt) do
|
||||
require_relative "cap/halt"
|
||||
Cap::Halt
|
||||
end
|
||||
|
||||
guest_capability(:bsd, :insert_public_key) do
|
||||
require_relative "cap/public_key"
|
||||
Cap::PublicKey
|
||||
end
|
||||
|
||||
guest_capability(:bsd, :mount_nfs_folder) do
|
||||
require_relative "cap/nfs"
|
||||
Cap::NFS
|
||||
end
|
||||
|
||||
guest_capability(:bsd, :mount_virtualbox_shared_folder) do
|
||||
require_relative "cap/virtualbox"
|
||||
Cap::VirtualBox
|
||||
end
|
||||
|
||||
guest_capability(:bsd, :remove_public_key) do
|
||||
require_relative "cap/public_key"
|
||||
Cap::PublicKey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,10 +3,16 @@ module VagrantPlugins
|
|||
module Cap
|
||||
class ChangeHostName
|
||||
def self.change_host_name(machine, name)
|
||||
machine.communicate.tap do |comm|
|
||||
if !comm.test("sudo hostname --fqdn | grep '#{name}'")
|
||||
comm.sudo("hostname #{name.split('.')[0]}")
|
||||
end
|
||||
comm = machine.communicate
|
||||
|
||||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
comm.sudo("hostname '#{basename}'")
|
||||
|
||||
# Note that when working with CoreOS, we explicitly do not add the
|
||||
# entry to /etc/hosts because this file does not exist on CoreOS.
|
||||
# We could create it, but the recommended approach on CoreOS is to
|
||||
# use Fleet to manage /etc/hosts files.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "tempfile"
|
||||
|
||||
require "vagrant/util/template_renderer"
|
||||
require_relative "../../../../lib/vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestCoreOS
|
||||
|
@ -10,64 +10,76 @@ module VagrantPlugins
|
|||
|
||||
def self.configure_networks(machine, networks)
|
||||
machine.communicate.tap do |comm|
|
||||
# Disable default etcd
|
||||
comm.sudo("systemctl stop etcd")
|
||||
|
||||
# Read network interface names
|
||||
interfaces = []
|
||||
comm.sudo("ifconfig | grep 'enp0\\|ens' | cut -f1 -d:") do |_, result|
|
||||
comm.sudo("ifconfig | grep '(e[n,t][h,s,p][[:digit:]]([a-z][[:digit:]])?' | cut -f1 -d:") do |_, result|
|
||||
interfaces = result.split("\n")
|
||||
end
|
||||
|
||||
# Configure interfaces
|
||||
# FIXME: fix matching of interfaces with IP adresses
|
||||
networks.each do |network|
|
||||
comm.sudo("ifconfig #{interfaces[network[:interface].to_i]} #{network[:ip]} netmask #{network[:netmask]}")
|
||||
end
|
||||
|
||||
primary_machine_config = machine.env.active_machines.first
|
||||
primary_machine = machine.env.machine(*primary_machine_config, true)
|
||||
|
||||
get_ip = lambda do |machine|
|
||||
ip = nil
|
||||
machine.config.vm.networks.each do |type, opts|
|
||||
if type == :private_network && opts[:ip]
|
||||
ip = opts[:ip]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
ip
|
||||
end
|
||||
|
||||
primary_machine_ip = get_ip.(primary_machine)
|
||||
current_ip = get_ip.(machine)
|
||||
primary_machine_ip = get_ip(primary_machine)
|
||||
current_ip = get_ip(machine)
|
||||
if current_ip == primary_machine_ip
|
||||
entry = TemplateRenderer.render("guests/coreos/etcd.service", options: {
|
||||
my_ip: current_ip
|
||||
})
|
||||
my_ip: current_ip,
|
||||
})
|
||||
else
|
||||
connection_string = "#{primary_machine_ip}:7001"
|
||||
entry = TemplateRenderer.render("guests/coreos/etcd.service", options: {
|
||||
connection_string: connection_string,
|
||||
my_ip: current_ip
|
||||
my_ip: current_ip,
|
||||
})
|
||||
end
|
||||
|
||||
Tempfile.open("vagrant") do |temp|
|
||||
temp.binmode
|
||||
temp.write(entry)
|
||||
temp.close
|
||||
comm.upload(temp.path, "/tmp/etcd-cluster.service")
|
||||
Tempfile.open("vagrant-coreos-configure-networks") do |f|
|
||||
f.binmode
|
||||
f.write(entry)
|
||||
f.fsync
|
||||
f.close
|
||||
comm.upload(f.path, "/tmp/etcd-cluster.service")
|
||||
end
|
||||
|
||||
comm.sudo("mv /tmp/etcd-cluster.service /media/state/units/")
|
||||
comm.sudo("systemctl restart local-enable.service")
|
||||
# Build a list of commands
|
||||
commands = []
|
||||
|
||||
# Restart default etcd
|
||||
comm.sudo("systemctl start etcd")
|
||||
# Stop default systemd
|
||||
commands << "systemctl stop etcd"
|
||||
|
||||
# Configure interfaces
|
||||
# FIXME: fix matching of interfaces with IP adresses
|
||||
networks.each do |network|
|
||||
iface = interfaces[network[:interface].to_i]
|
||||
commands << "ifconfig #{iface} #{network[:ip]} netmask #{network[:netmask]}".squeeze(" ")
|
||||
end
|
||||
|
||||
commands << <<-EOH.gsub(/^ {14}/, '')
|
||||
mv /tmp/etcd-cluster.service /media/state/units/
|
||||
systemctl restart local-enable.service
|
||||
|
||||
# Restart default etcd
|
||||
systemctl start etcd
|
||||
EOH
|
||||
|
||||
# Run all network configuration commands in one communicator session.
|
||||
comm.sudo(commands.join("\n"))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.get_ip(machine)
|
||||
ip = nil
|
||||
machine.config.vm.networks.each do |type, opts|
|
||||
if type == :private_network && opts[:ip]
|
||||
ip = opts[:ip]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
ip
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestCoreOS
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
|
|
|
@ -6,22 +6,22 @@ module VagrantPlugins
|
|||
name "CoreOS guest"
|
||||
description "CoreOS guest support."
|
||||
|
||||
guest("coreos", "linux") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
guest(:coreos, :linux) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("coreos", "change_host_name") do
|
||||
guest_capability(:coreos, :change_host_name) do
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
|
||||
guest_capability("coreos", "configure_networks") do
|
||||
guest_capability(:coreos, :configure_networks) do
|
||||
require_relative "cap/configure_networks"
|
||||
Cap::ConfigureNetworks
|
||||
end
|
||||
|
||||
guest_capability("coreos", "docker_daemon_running") do
|
||||
guest_capability(:coreos, :docker_daemon_running) do
|
||||
require_relative "cap/docker"
|
||||
Cap::Docker
|
||||
end
|
||||
|
|
|
@ -3,13 +3,34 @@ module VagrantPlugins
|
|||
module Cap
|
||||
class ChangeHostName
|
||||
def self.change_host_name(machine, name)
|
||||
if !machine.communicate.test("hostname -f | grep '^#{name}$' || hostname -s | grep '^#{name}$'")
|
||||
machine.communicate.sudo("scutil --set ComputerName #{name}")
|
||||
machine.communicate.sudo("scutil --set HostName #{name}")
|
||||
# LocalHostName shouldn't contain dots.
|
||||
# It is used by Bonjour and visible through file sharing services.
|
||||
machine.communicate.sudo("scutil --set LocalHostName #{name.gsub(/\.+/, '')}")
|
||||
machine.communicate.sudo("hostname #{name}")
|
||||
comm = machine.communicate
|
||||
|
||||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, '')
|
||||
set -e
|
||||
|
||||
# Set hostname
|
||||
scutil --set ComputerName '#{name}'
|
||||
scutil --set HostName '#{name}'
|
||||
|
||||
# LocalHostName should not contain dots - it is used by Bonjour and
|
||||
# visible through file sharing services.
|
||||
scutil --set LocalHostName '#{basename}'
|
||||
|
||||
hostname '#{name}'
|
||||
|
||||
# Remove comments and blank lines from /etc/hosts
|
||||
sed -i'' -e 's/#.*$//' /etc/hosts
|
||||
sed -i'' -e '/^$/d' /etc/hosts
|
||||
|
||||
# Prepend ourselves to /etc/hosts - sed on bsd is sad
|
||||
grep -w '#{name}' /etc/hosts || {
|
||||
echo -e '127.0.0.1\\t#{name}\\t#{basename}' | cat - /etc/hosts > /tmp/tmp-hosts
|
||||
mv /tmp/tmp-hosts /etc/hosts
|
||||
}
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,16 +3,16 @@ module VagrantPlugins
|
|||
module Cap
|
||||
module ChooseAddressableIPAddr
|
||||
def self.choose_addressable_ip_addr(machine, possible)
|
||||
machine.communicate.tap do |comm|
|
||||
possible.each do |ip|
|
||||
command = "ping -c1 -t1 #{ip}"
|
||||
if comm.test(command)
|
||||
return ip
|
||||
end
|
||||
comm = machine.communicate
|
||||
|
||||
possible.each do |ip|
|
||||
if comm.test("ping -c1 -t1 #{ip}")
|
||||
return ip
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
# If we got this far, there are no addressable IPs
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,12 +35,19 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
network_type = network[:type].to_sym
|
||||
if network_type == :static
|
||||
command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}"
|
||||
elsif network_type == :dhcp
|
||||
case network_type.to_sym
|
||||
when :static
|
||||
command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]} #{network[:router]}"
|
||||
when :static6
|
||||
command = "networksetup -setv6manual \"#{service_name}\" #{network[:ip]} #{network[:netmask]} #{network[:router]}"
|
||||
when :dhcp
|
||||
command = "networksetup -setdhcp \"#{service_name}\""
|
||||
when :dhcp6
|
||||
# This is not actually possible yet in Vagrant, but when we do
|
||||
# enable IPv6 across the board, Darwin will already have support.
|
||||
command = "networksetup -setv6automatic \"#{service_name}\""
|
||||
else
|
||||
raise "#{network_type} network type is not supported, try static or dhcp"
|
||||
raise Vagrant::Errors::NetworkTypeNotSupported, type: network_type
|
||||
end
|
||||
|
||||
machine.communicate.sudo(command)
|
||||
|
@ -65,7 +72,7 @@ module VagrantPlugins
|
|||
ints = ::IO.read(tmp_ints)
|
||||
ints.split(/\n\n/m).each do |i|
|
||||
if i.match(/Hardware/) && i.match(/Ethernet/)
|
||||
# Ethernet, should be 2 lines,
|
||||
# Ethernet, should be 2 lines,
|
||||
# (3) Thunderbolt Ethernet
|
||||
# (Hardware Port: Thunderbolt Ethernet, Device: en1)
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@ module VagrantPlugins
|
|||
class Halt
|
||||
def self.halt(machine)
|
||||
begin
|
||||
machine.communicate.sudo("shutdown -h now")
|
||||
# Darwin does not support the `-p` option like the rest of the
|
||||
# BSD-based guests, so it needs its own cap.
|
||||
machine.communicate.sudo("/sbin/shutdown -h now")
|
||||
rescue IOError
|
||||
# Do nothing because SSH connection closed and it probably
|
||||
# means the VM just shut down really fast.
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
require "vagrant/util/shell_quote"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDarwin
|
||||
module Cap
|
||||
class InsertPublicKey
|
||||
def self.insert_public_key(machine, contents)
|
||||
contents = contents.chomp
|
||||
contents = Vagrant::Util::ShellQuote.escape(contents, "'")
|
||||
|
||||
machine.communicate.tap do |comm|
|
||||
comm.execute("mkdir -p ~/.ssh")
|
||||
comm.execute("chmod 0700 ~/.ssh")
|
||||
comm.execute("printf '#{contents}\\n' >> ~/.ssh/authorized_keys")
|
||||
comm.execute("chmod 0600 ~/.ssh/authorized_keys")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,37 +0,0 @@
|
|||
require "vagrant/util/retryable"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDarwin
|
||||
module Cap
|
||||
class MountNFSFolder
|
||||
extend Vagrant::Util::Retryable
|
||||
def self.mount_nfs_folder(machine, ip, folders)
|
||||
folders.each do |name, opts|
|
||||
# Expand the guest path so we can handle things like "~/vagrant"
|
||||
expanded_guest_path = machine.guest.capability(
|
||||
:shell_expand_guest_path, opts[:guestpath])
|
||||
|
||||
# Create the folder
|
||||
machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
|
||||
|
||||
# Figure out any options
|
||||
mount_opts = ["vers=#{opts[:nfs_version]}"]
|
||||
mount_opts << "udp" if opts[:nfs_udp]
|
||||
if opts[:mount_options]
|
||||
mount_opts = opts[:mount_options].dup
|
||||
end
|
||||
|
||||
mount_command = "mount -t nfs " +
|
||||
"-o '#{mount_opts.join(",")}' " +
|
||||
"'#{ip}:#{opts[:hostpath]}' '#{expanded_guest_path}'"
|
||||
retryable(on: Vagrant::Errors::DarwinNFSMountFailed, tries: 10, sleep: 5) do
|
||||
machine.communicate.sudo(
|
||||
mount_command,
|
||||
error_class: Vagrant::Errors::DarwinNFSMountFailed)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
require "vagrant/util/shell_quote"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDarwin
|
||||
module Cap
|
||||
class RemovePublicKey
|
||||
def self.remove_public_key(machine, contents)
|
||||
contents = contents.chomp
|
||||
contents = Vagrant::Util::ShellQuote.escape(contents, "'")
|
||||
|
||||
machine.communicate.tap do |comm|
|
||||
if comm.test("test -f ~/.ssh/authorized_keys")
|
||||
comm.execute(
|
||||
"sed -i '' '/^.*#{contents}.*$/d' ~/.ssh/authorized_keys")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,3 +1,5 @@
|
|||
require "shellwords"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDarwin
|
||||
module Cap
|
||||
|
@ -11,9 +13,8 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def self.rsync_pre(machine, opts)
|
||||
machine.communicate.tap do |comm|
|
||||
comm.sudo("mkdir -p '#{opts[:guestpath]}'")
|
||||
end
|
||||
guest_path = Shellwords.escape(opts[:guestpath])
|
||||
machine.communicate.sudo("mkdir -p #{guest_path}")
|
||||
end
|
||||
|
||||
def self.rsync_post(machine, opts)
|
||||
|
@ -21,8 +22,10 @@ module VagrantPlugins
|
|||
return
|
||||
end
|
||||
|
||||
guest_path = Shellwords.escape(opts[:guestpath])
|
||||
|
||||
machine.communicate.sudo(
|
||||
"find '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
|
||||
"find #{guest_path} '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
|
||||
"xargs -0 chown #{opts[:owner]}:#{opts[:group]}")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'vagrant/util/template_renderer'
|
||||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDarwin
|
||||
|
|
|
@ -6,82 +6,67 @@ module VagrantPlugins
|
|||
name "Darwin guest"
|
||||
description "Darwin guest support."
|
||||
|
||||
guest("darwin") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
guest(:darwin, :bsd) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("darwin", "change_host_name") do
|
||||
guest_capability(:darwin, :change_host_name) do
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
|
||||
guest_capability("darwin", "choose_addressable_ip_addr") do
|
||||
guest_capability(:darwin, :choose_addressable_ip_addr) do
|
||||
require_relative "cap/choose_addressable_ip_addr"
|
||||
Cap::ChooseAddressableIPAddr
|
||||
end
|
||||
|
||||
guest_capability("darwin", "configure_networks") do
|
||||
guest_capability(:darwin, :configure_networks) do
|
||||
require_relative "cap/configure_networks"
|
||||
Cap::ConfigureNetworks
|
||||
end
|
||||
|
||||
guest_capability("darwin", "halt") do
|
||||
guest_capability(:darwin, :halt) do
|
||||
require_relative "cap/halt"
|
||||
Cap::Halt
|
||||
end
|
||||
|
||||
guest_capability("darwin", "insert_public_key") do
|
||||
require_relative "cap/insert_public_key"
|
||||
Cap::InsertPublicKey
|
||||
end
|
||||
|
||||
guest_capability("darwin", "mount_nfs_folder") do
|
||||
require_relative "cap/mount_nfs_folder"
|
||||
Cap::MountNFSFolder
|
||||
end
|
||||
|
||||
guest_capability("darwin", "mount_smb_shared_folder") do
|
||||
guest_capability(:darwin, :mount_smb_shared_folder) do
|
||||
require_relative "cap/mount_smb_shared_folder"
|
||||
Cap::MountSMBSharedFolder
|
||||
end
|
||||
|
||||
guest_capability("darwin", "mount_vmware_shared_folder") do
|
||||
guest_capability(:darwin, :mount_vmware_shared_folder) do
|
||||
require_relative "cap/mount_vmware_shared_folder"
|
||||
Cap::MountVmwareSharedFolder
|
||||
end
|
||||
|
||||
guest_capability("darwin", "remove_public_key") do
|
||||
require_relative "cap/remove_public_key"
|
||||
Cap::RemovePublicKey
|
||||
end
|
||||
|
||||
guest_capability("darwin", "rsync_installed") do
|
||||
guest_capability(:darwin, :rsync_installed) do
|
||||
require_relative "cap/rsync"
|
||||
Cap::RSync
|
||||
end
|
||||
|
||||
guest_capability("darwin", "rsync_command") do
|
||||
guest_capability(:darwin, :rsync_command) do
|
||||
require_relative "cap/rsync"
|
||||
Cap::RSync
|
||||
end
|
||||
|
||||
guest_capability("darwin", "rsync_post") do
|
||||
guest_capability(:darwin, :rsync_post) do
|
||||
require_relative "cap/rsync"
|
||||
Cap::RSync
|
||||
end
|
||||
|
||||
guest_capability("darwin", "rsync_pre") do
|
||||
guest_capability(:darwin, :rsync_pre) do
|
||||
require_relative "cap/rsync"
|
||||
Cap::RSync
|
||||
end
|
||||
|
||||
guest_capability("darwin", "shell_expand_guest_path") do
|
||||
guest_capability(:darwin, :shell_expand_guest_path) do
|
||||
require_relative "cap/shell_expand_guest_path"
|
||||
Cap::ShellExpandGuestPath
|
||||
end
|
||||
|
||||
guest_capability("darwin", "verify_vmware_hgfs") do
|
||||
guest_capability(:darwin, :verify_vmware_hgfs) do
|
||||
require_relative "cap/verify_vmware_hgfs"
|
||||
Cap::VerifyVmwareHgfs
|
||||
end
|
||||
|
|
|
@ -3,91 +3,43 @@ module VagrantPlugins
|
|||
module Cap
|
||||
class ChangeHostName
|
||||
def self.change_host_name(machine, name)
|
||||
new(machine, name).change!
|
||||
end
|
||||
comm = machine.communicate
|
||||
|
||||
attr_reader :machine, :new_hostname
|
||||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, '')
|
||||
# Ensure exit on command error
|
||||
set -e
|
||||
|
||||
def initialize(machine, new_hostname)
|
||||
@machine = machine
|
||||
@new_hostname = new_hostname
|
||||
end
|
||||
# Set the hostname
|
||||
echo '#{basename}' > /etc/hostname
|
||||
hostname -F /etc/hostname
|
||||
|
||||
def change!
|
||||
return unless should_change?
|
||||
if command -v hostnamectl; then
|
||||
hostnamectl set-hostname '#{basename}'
|
||||
fi
|
||||
|
||||
update_etc_hostname
|
||||
update_etc_hosts
|
||||
refresh_hostname_service
|
||||
update_mailname
|
||||
renew_dhcp
|
||||
end
|
||||
# Remove comments and blank lines from /etc/hosts
|
||||
sed -i'' -e 's/#.*$//' -e '/^$/d' /etc/hosts
|
||||
|
||||
def should_change?
|
||||
new_hostname != current_hostname
|
||||
end
|
||||
# Prepend ourselves to /etc/hosts
|
||||
grep -w '#{name}' /etc/hosts || {
|
||||
sed -i'' '1i 127.0.0.1\\t#{name}\\t#{basename}' /etc/hosts
|
||||
}
|
||||
|
||||
def current_hostname
|
||||
@current_hostname ||= get_current_hostname
|
||||
end
|
||||
# Update mailname
|
||||
echo '#{name}' > /etc/mailname
|
||||
|
||||
def get_current_hostname
|
||||
hostname = ""
|
||||
sudo "hostname -f" do |type, data|
|
||||
hostname = data.chomp if type == :stdout && hostname.empty?
|
||||
# Restart hostname services
|
||||
if test -f /etc/init.d/hostname; then
|
||||
/etc/init.d/hostname start || true
|
||||
fi
|
||||
|
||||
if test -f /etc/init.d/hostname.sh; then
|
||||
/etc/init.d/hostname.sh start || true
|
||||
fi
|
||||
EOH
|
||||
end
|
||||
|
||||
hostname
|
||||
end
|
||||
|
||||
def update_etc_hostname
|
||||
sudo("echo '#{short_hostname}' > /etc/hostname")
|
||||
end
|
||||
|
||||
# /etc/hosts should resemble:
|
||||
# 127.0.0.1 localhost
|
||||
# 127.0.1.1 host.fqdn.com host.fqdn host
|
||||
def update_etc_hosts
|
||||
if test("grep '#{current_hostname}' /etc/hosts")
|
||||
# Current hostname entry is in /etc/hosts
|
||||
ip_address = '([0-9]{1,3}\.){3}[0-9]{1,3}'
|
||||
search = "^(#{ip_address})\\s+#{Regexp.escape(current_hostname)}(\\s.*)?$"
|
||||
replace = "\\1 #{fqdn} #{short_hostname}"
|
||||
expression = ['s', search, replace, 'g'].join('@')
|
||||
|
||||
sudo("sed -ri '#{expression}' /etc/hosts")
|
||||
else
|
||||
# Current hostname entry isn't in /etc/hosts, just append it
|
||||
sudo("echo '127.0.1.1 #{fqdn} #{short_hostname}' >>/etc/hosts")
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_hostname_service
|
||||
sudo("hostname -F /etc/hostname")
|
||||
end
|
||||
|
||||
def update_mailname
|
||||
sudo("hostname --fqdn > /etc/mailname")
|
||||
end
|
||||
|
||||
def renew_dhcp
|
||||
sudo("ifdown -a; ifup -a; ifup eth0")
|
||||
end
|
||||
|
||||
def fqdn
|
||||
new_hostname
|
||||
end
|
||||
|
||||
def short_hostname
|
||||
new_hostname.split('.').first
|
||||
end
|
||||
|
||||
def sudo(cmd, &block)
|
||||
machine.communicate.sudo(cmd, &block)
|
||||
end
|
||||
|
||||
def test(cmd)
|
||||
machine.communicate.test(cmd)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
require 'set'
|
||||
require 'tempfile'
|
||||
require "tempfile"
|
||||
|
||||
require "vagrant/util/template_renderer"
|
||||
require_relative "../../../../lib/vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDebian
|
||||
|
@ -10,50 +9,62 @@ module VagrantPlugins
|
|||
include Vagrant::Util
|
||||
|
||||
def self.configure_networks(machine, networks)
|
||||
machine.communicate.tap do |comm|
|
||||
# First, remove any previous network modifications
|
||||
# from the interface file.
|
||||
comm.sudo("sed -e '/^#VAGRANT-BEGIN/,$ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces.pre")
|
||||
comm.sudo("sed -ne '/^#VAGRANT-END/,$ p' /etc/network/interfaces | tac | sed -e '/^#VAGRANT-END/,$ d' | tac > /tmp/vagrant-network-interfaces.post")
|
||||
comm = machine.communicate
|
||||
|
||||
# Accumulate the configurations to add to the interfaces file as
|
||||
# well as what interfaces we're actually configuring since we use that
|
||||
# later.
|
||||
interfaces = Set.new
|
||||
entries = []
|
||||
networks.each do |network|
|
||||
interfaces.add(network[:interface])
|
||||
entry = TemplateRenderer.render("guests/debian/network_#{network[:type]}",
|
||||
options: network)
|
||||
commands = ["set -e"]
|
||||
entries = []
|
||||
interfaces = machine.guest.capability(:network_interfaces)
|
||||
|
||||
entries << entry
|
||||
end
|
||||
networks.each do |network|
|
||||
network[:device] = interfaces[network[:interface]]
|
||||
|
||||
# Perform the careful dance necessary to reconfigure
|
||||
# the network interfaces
|
||||
temp = Tempfile.new("vagrant")
|
||||
temp.binmode
|
||||
temp.write(entries.join("\n"))
|
||||
temp.close
|
||||
|
||||
comm.upload(temp.path, "/tmp/vagrant-network-entry")
|
||||
|
||||
# Bring down all the interfaces we're reconfiguring. By bringing down
|
||||
# each specifically, we avoid reconfiguring eth0 (the NAT interface) so
|
||||
# SSH never dies.
|
||||
interfaces.each do |interface|
|
||||
comm.sudo("/sbin/ifdown eth#{interface} 2> /dev/null")
|
||||
comm.sudo("/sbin/ip addr flush dev eth#{interface} 2> /dev/null")
|
||||
end
|
||||
|
||||
comm.sudo('cat /tmp/vagrant-network-interfaces.pre /tmp/vagrant-network-entry /tmp/vagrant-network-interfaces.post > /etc/network/interfaces')
|
||||
comm.sudo('rm -f /tmp/vagrant-network-interfaces.pre /tmp/vagrant-network-entry /tmp/vagrant-network-interfaces.post')
|
||||
|
||||
# Bring back up each network interface, reconfigured
|
||||
interfaces.each do |interface|
|
||||
comm.sudo("/sbin/ifup eth#{interface}")
|
||||
end
|
||||
entry = TemplateRenderer.render("guests/debian/network_#{network[:type]}",
|
||||
options: network,
|
||||
)
|
||||
entries << entry
|
||||
end
|
||||
|
||||
Tempfile.open("vagrant-debian-configure-networks") do |f|
|
||||
f.binmode
|
||||
f.write(entries.join("\n"))
|
||||
f.fsync
|
||||
f.close
|
||||
comm.upload(f.path, "/tmp/vagrant-network-entry")
|
||||
end
|
||||
|
||||
networks.each do |network|
|
||||
# Ubuntu 16.04+ returns an error when downing an interface that
|
||||
# does not exist. The `|| true` preserves the behavior that older
|
||||
# Ubuntu versions exhibit and Vagrant expects (GH-7155)
|
||||
commands << "/sbin/ifdown '#{network[:device]}' || true"
|
||||
commands << "/sbin/ip addr flush dev '#{network[:device]}'"
|
||||
end
|
||||
|
||||
# Reconfigure /etc/network/interfaces.
|
||||
commands << <<-EOH.gsub(/^ {12}/, "")
|
||||
# Remove any previous network modifications from the interfaces file
|
||||
sed -e '/^#VAGRANT-BEGIN/,$ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces.pre
|
||||
sed -ne '/^#VAGRANT-END/,$ p' /etc/network/interfaces | tac | sed -e '/^#VAGRANT-END/,$ d' | tac > /tmp/vagrant-network-interfaces.post
|
||||
|
||||
cat \\
|
||||
/tmp/vagrant-network-interfaces.pre \\
|
||||
/tmp/vagrant-network-entry \\
|
||||
/tmp/vagrant-network-interfaces.post \\
|
||||
> /etc/network/interfaces
|
||||
|
||||
rm -f /tmp/vagrant-network-interfaces.pre
|
||||
rm -f /tmp/vagrant-network-entry
|
||||
rm -f /tmp/vagrant-network-interfaces.post
|
||||
EOH
|
||||
|
||||
# Bring back up each network interface, reconfigured.
|
||||
networks.each do |network|
|
||||
commands << "/sbin/ifup '#{network[:device]}'"
|
||||
end
|
||||
|
||||
# Run all the commands in one session to prevent partial configuration
|
||||
# due to a severed network.
|
||||
comm.sudo(commands.join("\n"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
module VagrantPlugins
|
||||
module GuestDebian
|
||||
module Cap
|
||||
class NFS
|
||||
def self.nfs_client_install(machine)
|
||||
comm = machine.communicate
|
||||
comm.sudo <<-EOH.gsub(/^ {12}/, '')
|
||||
set -e
|
||||
apt-get -yqq update
|
||||
apt-get -yqq install nfs-common portmap
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
module VagrantPlugins
|
||||
module GuestDebian
|
||||
module Cap
|
||||
class NFSClient
|
||||
def self.nfs_client_install(machine)
|
||||
machine.communicate.tap do |comm|
|
||||
comm.sudo("apt-get -y update")
|
||||
comm.sudo("apt-get -y install nfs-common portmap")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,10 +3,12 @@ module VagrantPlugins
|
|||
module Cap
|
||||
class RSync
|
||||
def self.rsync_install(machine)
|
||||
machine.communicate.tap do |comm|
|
||||
comm.sudo("apt-get -y update")
|
||||
comm.sudo("apt-get -y install rsync")
|
||||
end
|
||||
comm = machine.communicate
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, '')
|
||||
set -e
|
||||
apt-get -yqq update
|
||||
apt-get -yqq install rsync
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,13 +3,12 @@ module VagrantPlugins
|
|||
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
|
||||
comm = machine.communicate
|
||||
if !comm.test("test -f /sbin/mount.cifs")
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, '')
|
||||
apt-get -yqq update
|
||||
apt-get -yqq install cifs-utils
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDebian
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
|
|
|
@ -6,32 +6,32 @@ module VagrantPlugins
|
|||
name "Debian guest"
|
||||
description "Debian guest support."
|
||||
|
||||
guest("debian", "linux") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
guest(:debian, :linux) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("debian", "configure_networks") do
|
||||
guest_capability(:debian, :configure_networks) do
|
||||
require_relative "cap/configure_networks"
|
||||
Cap::ConfigureNetworks
|
||||
end
|
||||
|
||||
guest_capability("debian", "change_host_name") do
|
||||
guest_capability(:debian, :change_host_name) do
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
|
||||
guest_capability("debian", "nfs_client_install") do
|
||||
require_relative "cap/nfs_client"
|
||||
Cap::NFSClient
|
||||
guest_capability(:debian, :nfs_client_install) do
|
||||
require_relative "cap/nfs"
|
||||
Cap::NFS
|
||||
end
|
||||
|
||||
guest_capability("debian", "rsync_install") do
|
||||
guest_capability(:debian, :rsync_install) do
|
||||
require_relative "cap/rsync"
|
||||
Cap::RSync
|
||||
end
|
||||
|
||||
guest_capability("debian", "smb_install") do
|
||||
guest_capability(:debian, :smb_install) do
|
||||
require_relative "cap/smb"
|
||||
Cap::SMB
|
||||
end
|
||||
|
|
|
@ -13,9 +13,9 @@ module VagrantPlugins
|
|||
comm.execute("localcli storage nfs remove -v #{volume}")
|
||||
end
|
||||
mount_command = "localcli storage nfs add -H #{ip} -s '#{opts[:hostpath]}' -v '#{volume}'"
|
||||
retryable(on: Vagrant::Errors::LinuxNFSMountFailed, tries: 5, sleep: 2) do
|
||||
retryable(on: Vagrant::Errors::NFSMountFailed, tries: 5, sleep: 2) do
|
||||
comm.execute(mount_command,
|
||||
error_class: Vagrant::Errors::LinuxNFSMountFailed)
|
||||
error_class: Vagrant::Errors::NFSMountFailed)
|
||||
end
|
||||
|
||||
# symlink vmfs volume to :guestpath
|
||||
|
|
|
@ -6,27 +6,27 @@ module VagrantPlugins
|
|||
name "ESXi guest."
|
||||
description "ESXi guest support."
|
||||
|
||||
guest("esxi") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
guest(:esxi) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("esxi", "change_host_name") do
|
||||
guest_capability(:esxi, :change_host_name) do
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
|
||||
guest_capability("esxi", "configure_networks") do
|
||||
guest_capability(:esxi, :configure_networks) do
|
||||
require_relative "cap/configure_networks"
|
||||
Cap::ConfigureNetworks
|
||||
end
|
||||
|
||||
guest_capability("esxi", "mount_nfs_folder") do
|
||||
guest_capability(:esxi, :mount_nfs_folder) do
|
||||
require_relative "cap/mount_nfs_folder"
|
||||
Cap::MountNFSFolder
|
||||
end
|
||||
|
||||
guest_capability("esxi", "halt") do
|
||||
guest_capability(:esxi, :halt) do
|
||||
require_relative "cap/halt"
|
||||
Cap::Halt
|
||||
end
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
module VagrantPlugins
|
||||
module GuestFedora
|
||||
module Cap
|
||||
class ChangeHostName
|
||||
def self.change_host_name(machine, name)
|
||||
new(machine, name).change!
|
||||
end
|
||||
|
||||
attr_reader :machine, :new_hostname
|
||||
|
||||
def initialize(machine, new_hostname)
|
||||
@machine = machine
|
||||
@new_hostname = new_hostname
|
||||
end
|
||||
|
||||
def change!
|
||||
return unless should_change?
|
||||
|
||||
update_etc_hostname
|
||||
update_etc_hosts
|
||||
refresh_hostname_service
|
||||
end
|
||||
|
||||
def should_change?
|
||||
new_hostname != current_hostname
|
||||
end
|
||||
|
||||
def current_hostname
|
||||
@current_hostname ||= get_current_hostname
|
||||
end
|
||||
|
||||
def get_current_hostname
|
||||
hostname = ""
|
||||
sudo "hostname -f" do |type, data|
|
||||
hostname = data.chomp if type == :stdout && hostname.empty?
|
||||
end
|
||||
|
||||
hostname
|
||||
end
|
||||
|
||||
def update_etc_hostname
|
||||
sudo("echo '#{short_hostname}' > /etc/hostname")
|
||||
end
|
||||
|
||||
# /etc/hosts should resemble:
|
||||
# 127.0.0.1 localhost
|
||||
# 127.0.1.1 host.fqdn.com host.fqdn host
|
||||
def update_etc_hosts
|
||||
ip_address = '([0-9]{1,3}\.){3}[0-9]{1,3}'
|
||||
search = "^(#{ip_address})\\s+#{Regexp.escape(current_hostname)}(\\s.*)?$"
|
||||
replace = "\\1 #{fqdn} #{short_hostname} \\3"
|
||||
expression = ['s', search, replace, 'g'].join('@')
|
||||
|
||||
sudo("sed -ri '#{expression}' /etc/hosts")
|
||||
end
|
||||
|
||||
def refresh_hostname_service
|
||||
sudo("hostname -F /etc/hostname")
|
||||
end
|
||||
|
||||
def fqdn
|
||||
new_hostname
|
||||
end
|
||||
|
||||
def short_hostname
|
||||
new_hostname.split('.').first
|
||||
end
|
||||
|
||||
def sudo(cmd, &block)
|
||||
machine.communicate.sudo(cmd, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,134 +0,0 @@
|
|||
require "set"
|
||||
require "tempfile"
|
||||
|
||||
require "vagrant/util/retryable"
|
||||
require "vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestFedora
|
||||
module Cap
|
||||
class ConfigureNetworks
|
||||
extend Vagrant::Util::Retryable
|
||||
include Vagrant::Util
|
||||
|
||||
def self.configure_networks(machine, networks)
|
||||
network_scripts_dir = machine.guest.capability("network_scripts_dir")
|
||||
|
||||
virtual = false
|
||||
interface_names = Array.new
|
||||
interface_names_by_slot = Array.new
|
||||
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
|
||||
end
|
||||
|
||||
if virtual
|
||||
machine.communicate.sudo("ls /sys/class/net | egrep -v lo\\|docker") do |_, result|
|
||||
interface_names = result.split("\n")
|
||||
end
|
||||
|
||||
interface_names_by_slot = networks.map do |network|
|
||||
"#{interface_names[network[:interface]]}"
|
||||
end
|
||||
else
|
||||
machine.communicate.sudo("/usr/sbin/biosdevname -d | grep Kernel | cut -f2 -d: | sed -e 's/ //;'") do |_, result|
|
||||
interface_names = result.split("\n")
|
||||
end
|
||||
|
||||
interface_name_pairs = Array.new
|
||||
interface_names.each do |interface_name|
|
||||
machine.communicate.sudo("/usr/sbin/biosdevname --policy=all_ethN -i #{interface_name}") do |_, result|
|
||||
interface_name_pairs.push([interface_name, result.gsub("\n", "")])
|
||||
end
|
||||
end
|
||||
|
||||
setting_interface_names = networks.map do |network|
|
||||
"eth#{network[:interface]}"
|
||||
end
|
||||
|
||||
interface_names_by_slot = interface_names.dup
|
||||
interface_name_pairs.each do |interface_name, previous_interface_name|
|
||||
if setting_interface_names.index(previous_interface_name) == nil
|
||||
interface_names_by_slot.delete(interface_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Read interface MAC addresses for later matching
|
||||
mac_addresses = Array.new(interface_names.length)
|
||||
interface_names.each_with_index do |ifname, index|
|
||||
machine.communicate.sudo("cat /sys/class/net/#{ifname}/address") do |_, result|
|
||||
mac_addresses[index] = result.strip
|
||||
end
|
||||
end
|
||||
|
||||
# Accumulate the configurations to add to the interfaces file as well
|
||||
# as what interfaces we're actually configuring since we use that later.
|
||||
interfaces = Set.new
|
||||
networks.each do |network|
|
||||
interface = nil
|
||||
if network[:mac_address]
|
||||
found_idx = mac_addresses.find_index(network[:mac_address])
|
||||
# Ignore network if requested MAC address could not be found
|
||||
next if found_idx.nil?
|
||||
interface = interface_names[found_idx]
|
||||
else
|
||||
ifname_by_slot = interface_names_by_slot[network[:interface]-1]
|
||||
# Don't overwrite if interface was already matched via MAC address
|
||||
next if interfaces.include?(ifname_by_slot)
|
||||
interface = ifname_by_slot
|
||||
end
|
||||
|
||||
interfaces.add(interface)
|
||||
network[:device] = interface
|
||||
|
||||
# Remove any previous vagrant configuration in this network
|
||||
# interface's configuration files.
|
||||
machine.communicate.sudo("touch #{network_scripts_dir}/ifcfg-#{interface}")
|
||||
machine.communicate.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' #{network_scripts_dir}/ifcfg-#{interface} > /tmp/vagrant-ifcfg-#{interface}")
|
||||
machine.communicate.sudo("cat /tmp/vagrant-ifcfg-#{interface} > #{network_scripts_dir}/ifcfg-#{interface}")
|
||||
machine.communicate.sudo("rm -f /tmp/vagrant-ifcfg-#{interface}")
|
||||
|
||||
# Render and upload the network entry file to a deterministic
|
||||
# temporary location.
|
||||
entry = TemplateRenderer.render("guests/fedora/network_#{network[:type]}",
|
||||
options: network)
|
||||
|
||||
temp = Tempfile.new("vagrant")
|
||||
temp.binmode
|
||||
temp.write(entry)
|
||||
temp.close
|
||||
|
||||
machine.communicate.upload(temp.path, "/tmp/vagrant-network-entry_#{interface}")
|
||||
end
|
||||
|
||||
# Bring down all the interfaces we're reconfiguring. By bringing down
|
||||
# each specifically, we avoid reconfiguring p7p (the NAT interface) so
|
||||
# SSH never dies.
|
||||
interfaces.each do |interface|
|
||||
retryable(on: Vagrant::Errors::VagrantError, tries: 3, sleep: 2) do
|
||||
machine.communicate.sudo(<<-SCRIPT, error_check: true)
|
||||
cat /tmp/vagrant-network-entry_#{interface} >> #{network_scripts_dir}/ifcfg-#{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
|
|
@ -14,7 +14,7 @@ module VagrantPlugins
|
|||
if version.nil?
|
||||
return :fedora
|
||||
else
|
||||
return "fedora_#{version}".to_sym
|
||||
return :"fedora_#{version}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
module VagrantPlugins
|
||||
module GuestFedora
|
||||
module Cap
|
||||
class NetworkScriptsDir
|
||||
# The path to the directory with the network configuration scripts.
|
||||
# This is pulled out into its own directory since there are other
|
||||
# operating systems (SUSE) which behave similarly but with a different
|
||||
# path to the network scripts.
|
||||
def self.network_scripts_dir(machine)
|
||||
"/etc/sysconfig/network-scripts"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,27 +6,12 @@ module VagrantPlugins
|
|||
name "Fedora guest"
|
||||
description "Fedora guest support."
|
||||
|
||||
guest("fedora", "redhat") do
|
||||
require File.expand_path("../guest", __FILE__)
|
||||
guest(:fedora, :redhat) do
|
||||
require_relative "guest"
|
||||
Guest
|
||||
end
|
||||
|
||||
guest_capability("fedora", "change_host_name") do
|
||||
require_relative "cap/change_host_name"
|
||||
Cap::ChangeHostName
|
||||
end
|
||||
|
||||
guest_capability("fedora", "configure_networks") do
|
||||
require_relative "cap/configure_networks"
|
||||
Cap::ConfigureNetworks
|
||||
end
|
||||
|
||||
guest_capability("fedora", "network_scripts_dir") do
|
||||
require_relative "cap/network_scripts_dir"
|
||||
Cap::NetworkScriptsDir
|
||||
end
|
||||
|
||||
guest_capability("fedora", "flavor") do
|
||||
guest_capability(:fedora, :flavor) do
|
||||
require_relative "cap/flavor"
|
||||
Cap::Flavor
|
||||
end
|
||||
|
|
|
@ -3,9 +3,26 @@ module VagrantPlugins
|
|||
module Cap
|
||||
class ChangeHostName
|
||||
def self.change_host_name(machine, name)
|
||||
if !machine.communicate.test("hostname -f | grep '^#{name}$' || hostname -s | grep '^#{name}$'", {shell: "sh"})
|
||||
machine.communicate.sudo("sed -i '' 's/^hostname=.*$/hostname=#{name}/' /etc/rc.conf", {shell: "sh"})
|
||||
machine.communicate.sudo("hostname #{name}", {shell: "sh"})
|
||||
comm = machine.communicate
|
||||
|
||||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false, shell: "sh")
|
||||
basename = name.split(".", 2)[0]
|
||||
command = <<-EOH.gsub(/^ {14}/, '')
|
||||
# Set the hostname
|
||||
hostname '#{name}'
|
||||
sed -i '' 's/^hostname=.*$/hostname=\"#{name}\"/' /etc/rc.conf
|
||||
|
||||
# Remove comments and blank lines from /etc/hosts
|
||||
sed -i'' -e 's/#.*$//' /etc/hosts
|
||||
sed -i'' -e '/^$/d' /etc/hosts
|
||||
|
||||
# Prepend ourselves to /etc/hosts
|
||||
grep -w '#{name}' /etc/hosts || {
|
||||
echo -e '127.0.0.1\\t#{name}\\t#{basename}' | cat - /etc/hosts > /tmp/tmp-hosts
|
||||
mv /tmp/tmp-hosts /etc/hosts
|
||||
}
|
||||
EOH
|
||||
comm.sudo(command, shell: "sh")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "tempfile"
|
||||
|
||||
require "vagrant/util/template_renderer"
|
||||
require_relative "../../../../lib/vagrant/util/template_renderer"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestFreeBSD
|
||||
|
@ -9,42 +9,57 @@ module VagrantPlugins
|
|||
include Vagrant::Util
|
||||
|
||||
def self.configure_networks(machine, networks)
|
||||
options = { shell: "sh" }
|
||||
comm = machine.communicate
|
||||
|
||||
commands = []
|
||||
interfaces = []
|
||||
|
||||
# Remove any previous network additions to the configuration file.
|
||||
machine.communicate.sudo("sed -i '' -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/rc.conf", {shell: "sh"})
|
||||
commands << "sed -i'' -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/rc.conf"
|
||||
|
||||
networks.each do |network|
|
||||
# Determine the interface prefix...
|
||||
command = "ifconfig -a | grep -o ^[0-9a-z]*"
|
||||
result = ""
|
||||
ifname = ""
|
||||
machine.communicate.execute(command) do |type, data|
|
||||
result << data if type == :stdout
|
||||
if result.split(/\n/).any?{|i| i.match(/vtnet*/)}
|
||||
ifname = "vtnet#{network[:interface]}"
|
||||
else
|
||||
ifname = "em#{network[:interface]}"
|
||||
end
|
||||
end
|
||||
|
||||
entry = TemplateRenderer.render("guests/freebsd/network_#{network[:type]}",
|
||||
options: network, ifname: ifname)
|
||||
|
||||
# Write the entry to a temporary location
|
||||
temp = Tempfile.new("vagrant")
|
||||
temp.binmode
|
||||
temp.write(entry)
|
||||
temp.close
|
||||
|
||||
machine.communicate.upload(temp.path, "/tmp/vagrant-network-entry")
|
||||
machine.communicate.sudo("su -m root -c 'cat /tmp/vagrant-network-entry >> /etc/rc.conf'", {shell: "sh"})
|
||||
machine.communicate.sudo("rm -f /tmp/vagrant-network-entry", {shell: "sh"})
|
||||
|
||||
if network[:type].to_sym == :static
|
||||
machine.communicate.sudo("ifconfig #{ifname} inet #{network[:ip]} netmask #{network[:netmask]}", {shell: "sh"})
|
||||
elsif network[:type].to_sym == :dhcp
|
||||
machine.communicate.sudo("dhclient #{ifname}", {shell: "sh"})
|
||||
end
|
||||
comm.sudo("ifconfig -a | grep -o ^[0-9a-z]* | grep -v '^lo'", options) do |_, stdout|
|
||||
interfaces = stdout.split("\n")
|
||||
end
|
||||
|
||||
networks.each.with_index do |network, i|
|
||||
network[:device] = interfaces[network[:interface]]
|
||||
|
||||
entry = TemplateRenderer.render("guests/freebsd/network_#{network[:type]}",
|
||||
options: network,
|
||||
)
|
||||
|
||||
remote_path = "/tmp/vagrant-network-#{network[:device]}-#{Time.now.to_i}-#{i}"
|
||||
|
||||
Tempfile.open("vagrant-freebsd-configure-networks") do |f|
|
||||
f.binmode
|
||||
f.write(entry)
|
||||
f.fsync
|
||||
f.close
|
||||
comm.upload(f.path, remote_path)
|
||||
end
|
||||
|
||||
commands << <<-EOH.gsub(/^ {14}/, '')
|
||||
cat '#{remote_path}' >> /etc/rc.conf
|
||||
rm -f '#{remote_path}'
|
||||
EOH
|
||||
|
||||
# If the network is DHCP, then we have to start the dhclient, unless
|
||||
# it is already running. See GH-5852 for more information
|
||||
if network[:type].to_sym == :dhcp
|
||||
file = "/var/run/dhclient.#{network[:device]}.pid"
|
||||
commands << <<-EOH.gsub(/^ {16}/, '')
|
||||
if ! test -f '#{file}' || ! kill -0 $(cat '#{file}'); then
|
||||
dhclient '#{network[:device]}'
|
||||
fi
|
||||
EOH
|
||||
end
|
||||
|
||||
# For some reason, this returns status 1... every time
|
||||
commands << "/etc/rc.d/netif restart '#{network[:device]}' || true"
|
||||
end
|
||||
|
||||
comm.sudo(commands.join("\n"), options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
module VagrantPlugins
|
||||
module GuestFreeBSD
|
||||
module Cap
|
||||
class Halt
|
||||
def self.halt(machine)
|
||||
begin
|
||||
machine.communicate.sudo("shutdown -p now", {shell: "sh"})
|
||||
rescue IOError
|
||||
# Do nothing because SSH connection closed and it probably
|
||||
# means the VM just shut down really fast.
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
require "vagrant/util/shell_quote"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestFreeBSD
|
||||
module Cap
|
||||
class InsertPublicKey
|
||||
def self.insert_public_key(machine, contents)
|
||||
contents = Vagrant::Util::ShellQuote.escape(contents, "'")
|
||||
contents = contents.gsub("\n", "\\n")
|
||||
|
||||
machine.communicate.tap do |comm|
|
||||
comm.execute("mkdir -p ~/.ssh", shell: "sh")
|
||||
comm.execute("chmod 0700 ~/.ssh", shell: "sh")
|
||||
comm.execute("printf '#{contents}' >> ~/.ssh/authorized_keys", shell: "sh")
|
||||
comm.execute("chmod 0600 ~/.ssh/authorized_keys", shell: "sh")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
module VagrantPlugins
|
||||
module GuestFreeBSD
|
||||
module Cap
|
||||
class MountNFSFolder
|
||||
def self.mount_nfs_folder(machine, ip, folders)
|
||||
folders.each do |name, opts|
|
||||
if opts[:nfs_version]
|
||||
nfs_version_mount_option="-o nfsv#{opts[:nfs_version]}"
|
||||
end
|
||||
|
||||
machine.communicate.sudo("mkdir -p #{opts[:guestpath]}", {shell: "sh"})
|
||||
|
||||
machine.communicate.sudo(
|
||||
"mount -t nfs #{nfs_version_mount_option} " +
|
||||
"'#{ip}:#{opts[:hostpath]}' '#{opts[:guestpath]}'", {shell: "sh"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
require "vagrant/util/shell_quote"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestFreeBSD
|
||||
module Cap
|
||||
class RemovePublicKey
|
||||
def self.remove_public_key(machine, contents)
|
||||
contents = contents.chomp
|
||||
contents = Vagrant::Util::ShellQuote.escape(contents, "'")
|
||||
|
||||
machine.communicate.tap do |comm|
|
||||
if comm.test("test -f ~/.ssh/authorized_keys")
|
||||
comm.execute(
|
||||
"sed -i .bak '/^.*#{contents}.*$/d' ~/.ssh/authorized_keys")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,19 +1,11 @@
|
|||
require "shellwords"
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestFreeBSD
|
||||
module Cap
|
||||
class RSync
|
||||
def self.rsync_install(machine)
|
||||
version = nil
|
||||
machine.communicate.execute("uname -r") do |type, result|
|
||||
version = result.split('.')[0].to_i if type == :stdout
|
||||
end
|
||||
|
||||
pkg_cmd = "pkg_add -r"
|
||||
if version && version >= 10
|
||||
pkg_cmd = "pkg install -y"
|
||||
end
|
||||
|
||||
machine.communicate.sudo("#{pkg_cmd} rsync")
|
||||
machine.communicate.sudo("pkg install -y rsync")
|
||||
end
|
||||
|
||||
def self.rsync_installed(machine)
|
||||
|
@ -25,9 +17,8 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def self.rsync_pre(machine, opts)
|
||||
machine.communicate.tap do |comm|
|
||||
comm.sudo("mkdir -p '#{opts[:guestpath]}'")
|
||||
end
|
||||
guest_path = Shellwords.escape(opts[:guestpath])
|
||||
machine.communicate.sudo("mkdir -p #{guest_path}")
|
||||
end
|
||||
|
||||
def self.rsync_post(machine, opts)
|
||||
|
@ -35,8 +26,10 @@ module VagrantPlugins
|
|||
return
|
||||
end
|
||||
|
||||
guest_path = Shellwords.escape(opts[:guestpath])
|
||||
|
||||
machine.communicate.sudo(
|
||||
"find '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
|
||||
"find #{guest_path} '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
|
||||
"xargs -0 -r chown #{opts[:owner]}:#{opts[:group]}")
|
||||
end
|
||||
end
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue