Merge tag 'tags/v1.9.1' into patch-guest-esxi
This commit is contained in:
commit
e3e7484e16
|
@ -4,18 +4,14 @@ sudo: false
|
|||
|
||||
cache: bundler
|
||||
|
||||
before_install:
|
||||
- gem uninstall bundler -aIxq --force
|
||||
- gem uninstall -Ixq --force -i /home/travis/.rvm/gems/ruby-2.2.3@global bundler
|
||||
- gem install bundler -v '1.12.5'
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- bsdtar
|
||||
|
||||
rvm:
|
||||
- 2.2.3
|
||||
- 2.2.5
|
||||
- 2.3.3
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
|
76
CHANGELOG.md
76
CHANGELOG.md
|
@ -1,7 +1,81 @@
|
|||
## Next Version (Unreleased)
|
||||
## 1.9.1 (December 7, 2016)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- core: Disable Vagrantfile loading when running plugin commands [GH-8066]
|
||||
- guests/redhat: Detect and restart NetworkManager service if in use [GH-8052, GH-7994]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- core: Detect load failures within install solution sets and retry [GH-8068]
|
||||
- core: Prevent interactive shell on plugin uninstall [GH-8086, GH-8087]
|
||||
- core: Remove bundler usage from Util::Env [GH-8090, GH-8094]
|
||||
- guests/linux: Prevent stderr output on init version check for synced folders [GH-8051]
|
||||
|
||||
## 1.9.0 (November 28, 2016)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- commands/box: Add `prune` subcommand for removing outdated boxes [GH-7978]
|
||||
- core: Remove Bundler integration for handling internal plugins [GH-7793, GH-8000, GH-8011, GH-8031]
|
||||
- providers/hyperv: Add support for Hyper-V binary configuration format
|
||||
[GH-7854, GH-7706, GH-6102]
|
||||
- provisioners/shell: Support MD5/SHA1 checksum validation of remote scripts [GH-7985, GH-6323]
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- commands/plugin: Retain name sorted output when listing plugins [GH-8028]
|
||||
- communicator/ssh: Support custom environment variable export template
|
||||
[GH-7976, GH-6747]
|
||||
- provisioners/ansible(both): Add `config_file` option to point the location of an
|
||||
`ansible.cfg` file via ANSIBLE_CONFIG environment variable [GH-7195, GH-7918]
|
||||
- synced_folders: Support custom naming and disable auto-mount [GH-7980, GH-6836]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- guests/linux: Do not match interfaces with special characters when sorting [GH-7989, GH-7988]
|
||||
- provisioner/salt: Fix Hash construction for constant [GH-7986, GH-7981]
|
||||
|
||||
## 1.8.7 (November 4, 2016)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- guests/linux: Place ethernet devices at start of network devices list [GH-7848]
|
||||
- guests/linux: Provide more consistent guest detection [GH-7887, GH-7827]
|
||||
- guests/openbsd: Validate guest rsync installation success [GH-7929, GH-7898]
|
||||
- guests/redhat: Include Virtuozzo Linux 7 within flavor identification [GH-7818]
|
||||
- guests/windows: Allow vagrant to start Windows Nano without provisioning [GH-7831]
|
||||
- provisioners/ansible_local: Change the Ansible binary detection mechanism [GH-7536]
|
||||
- provisioners/ansible(both): Add the `playbook_command` option [GH-7881]
|
||||
- provisioners/puppet: Support custom environment variables [GH-7931, GH-7252, GH-2270]
|
||||
- util/safe_exec: Use subprocess for safe_exec on Windows [GH-7802]
|
||||
- util/subprocess: Allow closing STDIN [GH-7778]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- communicators/winrm: Prevent connection leakage [GH-7712]
|
||||
- core: Prevent duplicate provider priorities [GH-7756]
|
||||
- core: Allow Numeric type for box version [GH-7874, GH-6960]
|
||||
- core: Provide friendly error when user environment is too large [GH-7889, GH-7857]
|
||||
- guests: Remove `set -e` usage for better shell compatibility [GH-7921, GH-7739]
|
||||
- guests/linux: Fix incorrectly configured private network [GH-7844, GH-7848]
|
||||
- guests/linux: Properly order network interfaces
|
||||
[GH-7866, GH-7876, GH-7858, GH-7876]
|
||||
- guests/linux: Only emit upstart event if initctl is available [GH-7813]
|
||||
- guests/netbsd: Fix rsync installation [GH-7922, GH-7901]
|
||||
- guests/photon: Fix networking setup [GH-7808, GH-7873]
|
||||
- guests/redhat: Properly configure network and restart service [GH-7751]
|
||||
- guests/redhat: Prevent NetworkManager from managing devices on initial start [GH-7926]
|
||||
- hosts/linux: Fix race condition in writing /etc/exports file for NFS configuration
|
||||
[GH-7947, GH-7938] - Thanks to Aron Griffis (@agriffis) for identifying this issue
|
||||
- plugins/rsync: Escape exclude paths [GH-7928, GH-7910]
|
||||
- providers/docker: Remove --interactive flag when pty is true [GH-7688]
|
||||
- provisioners/ansible_local: Use enquoted path for file/directory existence checks
|
||||
- provisioners/salt: Synchronize configuration defaults with documentation [GH-7907, GH-6624]
|
||||
- pushes/atlas: Fix atlas push on Windows platform [GH-6938, GH-7802]
|
||||
|
||||
## 1.8.6 (September 27, 2016)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Add detection for DragonFly BSD [GH-7701]
|
||||
|
|
13
README.md
13
README.md
|
@ -2,7 +2,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
|
||||
* [![Gitter chat](https://badges.gitter.im/mitchellh/vagrant.png)](https://gitter.im/mitchellh/vagrant)
|
||||
* Mailing list: [Google Groups](https://groups.google.com/group/vagrant-up)
|
||||
|
||||
Vagrant is a tool for building and distributing development environments.
|
||||
|
@ -45,11 +45,7 @@ To learn how to build a fully functional development environment, follow the
|
|||
## Installing the Gem from Git
|
||||
|
||||
If you want the bleeding edge version of Vagrant, we try to keep master pretty stable
|
||||
and you're welcome to give it a shot. The following is an example showing how to do this:
|
||||
|
||||
rake install
|
||||
|
||||
Ruby 2.0 is needed.
|
||||
and you're welcome to give it a shot. Please review the installation page [here](https://www.vagrantup.com/docs/installation/source.html).
|
||||
|
||||
## Contributing to Vagrant
|
||||
|
||||
|
@ -66,11 +62,6 @@ like so:
|
|||
|
||||
bundle exec vagrant help
|
||||
|
||||
**NOTE:** By default running Vagrant via `bundle` will disable plugins.
|
||||
This is necessary because Vagrant creates its own private Bundler context
|
||||
(it does not respect your Gemfile), because it uses Bundler to manage plugin
|
||||
dependencies.
|
||||
|
||||
### Acceptance Tests
|
||||
|
||||
Vagrant also comes with an acceptance test suite that does black-box
|
||||
|
|
73
bin/vagrant
73
bin/vagrant
|
@ -8,6 +8,11 @@ Signal.trap("INT") { abort }
|
|||
# Split arguments by "--" if its there, we'll recombine them later
|
||||
argv = ARGV.dup
|
||||
argv_extra = []
|
||||
|
||||
# These will be the options that are passed to initialze the Vagrant
|
||||
# environment.
|
||||
opts = {}
|
||||
|
||||
if idx = argv.index("--")
|
||||
argv_extra = argv.slice(idx+1, argv.length-2)
|
||||
argv = argv.slice(0, idx)
|
||||
|
@ -20,43 +25,26 @@ if argv.include?("-v") || argv.include?("--version")
|
|||
exit 0
|
||||
end
|
||||
|
||||
# This is kind of hacky, and I'd love to find a better way to do this, but
|
||||
# if we're accessing the plugin interface, we want to NOT load plugins
|
||||
# for this run, because they can actually interfere with the function
|
||||
# of the plugin interface.
|
||||
# Disable plugin loading for commands where plugins are not required. This will
|
||||
# also disable loading of the Vagrantfile if it available as the environment
|
||||
# is not required for these commands
|
||||
argv.each_index do |i|
|
||||
arg = argv[i]
|
||||
|
||||
if !arg.start_with?("-")
|
||||
if arg == "plugin"
|
||||
ENV["VAGRANT_NO_PLUGINS"] = "1"
|
||||
ENV["VAGRANT_VAGRANTFILE"] = "plugin_command_#{Time.now.to_i}"
|
||||
if ["plugin", "help"].include?(arg) || (arg == "box" && argv[i+1] == "list")
|
||||
opts[:vagrantfile_name] = ""
|
||||
ENV['VAGRANT_NO_PLUGINS'] = "1"
|
||||
end
|
||||
|
||||
if arg == "help"
|
||||
ENV["VAGRANT_VAGRANTFILE"] = "plugin_command_#{Time.now.to_i}"
|
||||
end
|
||||
|
||||
if arg == "box" && argv[i+1] == "list"
|
||||
ENV["VAGRANT_VAGRANTFILE"] = "plugin_command_#{Time.now.to_i}"
|
||||
if arg == "plugin" && argv[i+1] != "list"
|
||||
ENV['VAGRANT_DISABLE_PLUGIN_INIT'] = "1"
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# First, make sure that we're executing using the proper Bundler context
|
||||
# with our plugins. If we're not, then load that and reload Vagrant.
|
||||
if !ENV["VAGRANT_INTERNAL_BUNDLERIZED"]
|
||||
require "rbconfig"
|
||||
ruby_path = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"])
|
||||
Kernel.exec(
|
||||
ruby_path,
|
||||
File.expand_path("../../lib/vagrant/pre-rubygems.rb", __FILE__),
|
||||
*ARGV)
|
||||
raise "Fatal error: this line should never be reached"
|
||||
end
|
||||
|
||||
# Set logging level to `debug`. This is done before loading 'vagrant', as it
|
||||
# sets up the logging system.
|
||||
if argv.include?("--debug")
|
||||
|
@ -64,37 +52,6 @@ if argv.include?("--debug")
|
|||
ENV["VAGRANT_LOG"] = "debug"
|
||||
end
|
||||
|
||||
# Setup our dependencies by initializing Bundler. If we're using plugins,
|
||||
# then also initialize the paths to the plugins.
|
||||
require "bundler"
|
||||
begin
|
||||
$vagrant_bundler_runtime = Bundler.setup(:default, :plugins)
|
||||
rescue Bundler::GemNotFound
|
||||
$stderr.puts "Bundler, the underlying system used to manage Vagrant plugins,"
|
||||
$stderr.puts "is reporting that a plugin or its dependency can't be found."
|
||||
$stderr.puts "This is usually caused by manual tampering with the 'plugins.json'"
|
||||
$stderr.puts "file in the Vagrant home directory. To fix this error, please"
|
||||
$stderr.puts "remove that file and reinstall all your plugins using `vagrant"
|
||||
$stderr.puts "plugin install`."
|
||||
rescue Bundler::VersionConflict => e
|
||||
$stderr.puts "Vagrant experienced a version conflict with some installed plugins!"
|
||||
$stderr.puts "This usually happens if you recently upgraded Vagrant. As part of the"
|
||||
$stderr.puts "upgrade process, some existing plugins are no longer compatible with"
|
||||
$stderr.puts "this version of Vagrant. The recommended way to fix this is to remove"
|
||||
$stderr.puts "your existing plugins and reinstall them one-by-one. To remove all"
|
||||
$stderr.puts "plugins:"
|
||||
$stderr.puts ""
|
||||
$stderr.puts " rm -r ~/.vagrant.d/plugins.json ~/.vagrant.d/gems"
|
||||
$stderr.puts ""
|
||||
$stderr.puts "Note if you have an alternate VAGRANT_HOME environmental variable"
|
||||
$stderr.puts "set, the folders above will be in that directory rather than your"
|
||||
$stderr.puts "user's home directory."
|
||||
$stderr.puts ""
|
||||
$stderr.puts "The error message is shown below:\n\n"
|
||||
$stderr.puts e.message
|
||||
exit 1
|
||||
end
|
||||
|
||||
# Stdout/stderr should not buffer output
|
||||
$stdout.sync = true
|
||||
$stderr.sync = true
|
||||
|
@ -114,10 +71,6 @@ begin
|
|||
logger = Log4r::Logger.new("vagrant::bin::vagrant")
|
||||
logger.info("`vagrant` invoked: #{ARGV.inspect}")
|
||||
|
||||
# These will be the options that are passed to initialze the Vagrant
|
||||
# environment.
|
||||
opts = {}
|
||||
|
||||
# Disable color in a few cases:
|
||||
#
|
||||
# * --no-color is anywhere in our arguments
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
require "vagrant/shared_helpers"
|
||||
|
||||
if Vagrant.plugins_enabled? && !defined?(Bundler)
|
||||
puts "It appears that Vagrant was not properly loaded. Specifically,"
|
||||
puts "the bundler context Vagrant requires was not setup. Please execute"
|
||||
puts "vagrant using only the `vagrant` executable."
|
||||
abort
|
||||
end
|
||||
|
||||
require 'rubygems'
|
||||
require 'log4r'
|
||||
|
||||
|
@ -72,11 +65,6 @@ global_logger.info("RubyGems version: #{Gem::VERSION}")
|
|||
ENV.each do |k, v|
|
||||
global_logger.info("#{k}=#{v.inspect}") if k =~ /^VAGRANT_/
|
||||
end
|
||||
global_logger.info("Plugins:")
|
||||
Bundler.definition.specs_for([:plugins]).each do |spec|
|
||||
global_logger.info(" - #{spec.name} = #{spec.version}")
|
||||
end
|
||||
|
||||
|
||||
# We need these components always so instead of an autoload we
|
||||
# just require them explicitly here.
|
||||
|
@ -254,6 +242,35 @@ if I18n.config.respond_to?(:enforce_available_locales=)
|
|||
I18n.config.enforce_available_locales = true
|
||||
end
|
||||
|
||||
# Setup the plugin manager and load any defined plugins
|
||||
require_relative "vagrant/plugin/manager"
|
||||
plugins = Vagrant::Plugin::Manager.instance.installed_plugins
|
||||
|
||||
global_logger.info("Plugins:")
|
||||
plugins.each do |plugin_name, plugin_info|
|
||||
installed_version = plugin_info["installed_gem_version"]
|
||||
version_constraint = plugin_info["gem_version"]
|
||||
installed_version = 'undefined' if installed_version.to_s.empty?
|
||||
version_constraint = '> 0' if version_constraint.to_s.empty?
|
||||
global_logger.info(
|
||||
" - #{plugin_name} = [installed: " \
|
||||
"#{installed_version} constraint: " \
|
||||
"#{version_constraint}]"
|
||||
)
|
||||
end
|
||||
|
||||
if Vagrant.plugins_init?
|
||||
begin
|
||||
Vagrant::Bundler.instance.init!(plugins)
|
||||
rescue Exception => e
|
||||
global_logger.error("Plugin initialization error - #{e.class}: #{e}")
|
||||
e.backtrace.each do |backtrace_line|
|
||||
global_logger.debug(backtrace_line)
|
||||
end
|
||||
raise Vagrant::Errors::PluginInitError, message: e.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# A lambda that knows how to load plugins from a single directory.
|
||||
plugin_load_proc = lambda do |directory|
|
||||
# We only care about directories
|
||||
|
@ -288,8 +305,40 @@ end
|
|||
if Vagrant.plugins_enabled?
|
||||
begin
|
||||
global_logger.info("Loading plugins!")
|
||||
$vagrant_bundler_runtime.require(:plugins)
|
||||
plugins.each do |plugin_name, plugin_info|
|
||||
if plugin_info["require"].to_s.empty?
|
||||
begin
|
||||
global_logger.debug("Loading plugin `#{plugin_name}` with default require: `#{plugin_name}`")
|
||||
require plugin_name
|
||||
rescue LoadError, Gem::LoadError => load_error
|
||||
if plugin_name.include?("-")
|
||||
begin
|
||||
plugin_slash = plugin_name.gsub("-", "/")
|
||||
global_logger.debug("Failed to load plugin `#{plugin_name}` with default require.")
|
||||
global_logger.debug("Loading plugin `#{plugin_name}` with slash require: `#{plugin_slash}`")
|
||||
require plugin_slash
|
||||
rescue LoadError, Gem::LoadError
|
||||
raise load_error
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
global_logger.debug("Loading plugin `#{plugin_name}` with custom require: `#{plugin_info["require"]}`")
|
||||
require plugin_info["require"]
|
||||
end
|
||||
global_logger.debug("Successfully loaded plugin `#{plugin_name}`.")
|
||||
end
|
||||
if defined?(::Bundler)
|
||||
global_logger.debug("Bundler detected in use. Loading `:plugins` group.")
|
||||
::Bundler.require(:plugins)
|
||||
end
|
||||
rescue Exception => e
|
||||
global_logger.error("Plugin loading error: #{e.class} - #{e}")
|
||||
e.backtrace.each do |backtrace_line|
|
||||
global_logger.debug(backtrace_line)
|
||||
end
|
||||
raise Vagrant::Errors::PluginLoadError, message: e.to_s
|
||||
end
|
||||
else
|
||||
global_logger.debug("Plugin loading is currently disabled.")
|
||||
end
|
||||
|
|
|
@ -4,7 +4,9 @@ require "set"
|
|||
require "tempfile"
|
||||
require "fileutils"
|
||||
|
||||
require "bundler"
|
||||
require "rubygems/package"
|
||||
require "rubygems/uninstaller"
|
||||
require "rubygems/name_tuple"
|
||||
|
||||
require_relative "shared_helpers"
|
||||
require_relative "version"
|
||||
|
@ -15,83 +17,77 @@ module Vagrant
|
|||
# Bundler as a way to properly resolve all dependencies of Vagrant and
|
||||
# all Vagrant-installed plugins.
|
||||
class Bundler
|
||||
|
||||
HASHICORP_GEMSTORE = 'https://gems.hashicorp.com'.freeze
|
||||
|
||||
def self.instance
|
||||
@bundler ||= self.new
|
||||
end
|
||||
|
||||
attr_reader :plugin_gem_path
|
||||
|
||||
def initialize
|
||||
@enabled = true if ENV["VAGRANT_INSTALLER_ENV"] ||
|
||||
ENV["VAGRANT_FORCE_BUNDLER"]
|
||||
@enabled = !::Bundler::SharedHelpers.in_bundle? if !@enabled
|
||||
@monitor = Monitor.new
|
||||
|
||||
@gem_home = ENV["GEM_HOME"]
|
||||
@gem_path = ENV["GEM_PATH"]
|
||||
|
||||
# Set the Bundler UI to be a silent UI. We have to add the
|
||||
# `silence` method to it because Bundler UI doesn't have it.
|
||||
::Bundler.ui =
|
||||
if ::Bundler::UI.const_defined? :Silent
|
||||
# bundler >= 1.6.0, we use our custom UI
|
||||
BundlerUI.new
|
||||
else
|
||||
# bundler < 1.6.0
|
||||
::Bundler::UI.new
|
||||
end
|
||||
if !::Bundler.ui.respond_to?(:silence)
|
||||
ui = ::Bundler.ui
|
||||
def ui.silence(*args)
|
||||
yield
|
||||
end
|
||||
end
|
||||
@plugin_gem_path = Vagrant.user_data_path.join("gems", RUBY_VERSION).freeze
|
||||
@logger = Log4r::Logger.new("vagrant::bundler")
|
||||
end
|
||||
|
||||
# Initializes Bundler and the various gem paths so that we can begin
|
||||
# loading gems. This must only be called once.
|
||||
def init!(plugins)
|
||||
# If we're not enabled, then we don't do anything.
|
||||
return if !@enabled
|
||||
def init!(plugins, repair=false)
|
||||
# Add HashiCorp RubyGems source
|
||||
Gem.sources << HASHICORP_GEMSTORE
|
||||
|
||||
bundle_path = Vagrant.user_data_path.join("gems")
|
||||
|
||||
# Setup the "local" Bundler configuration. We need to set BUNDLE_PATH
|
||||
# because the existence of this actually suppresses `sudo`.
|
||||
@appconfigpath = Dir.mktmpdir("vagrant-bundle-app-config")
|
||||
File.open(File.join(@appconfigpath, "config"), "w+") do |f|
|
||||
f.write("BUNDLE_PATH: \"#{bundle_path}\"")
|
||||
# Generate dependencies for all registered plugins
|
||||
plugin_deps = plugins.map do |name, info|
|
||||
Gem::Dependency.new(name, info['gem_version'].to_s.empty? ? '> 0' : info['gem_version'])
|
||||
end
|
||||
|
||||
# Setup the Bundler configuration
|
||||
@configfile = tempfile("vagrant-configfile")
|
||||
@configfile.close
|
||||
@logger.debug("Current generated plugin dependency list: #{plugin_deps}")
|
||||
|
||||
# Build up the Gemfile for our Bundler context. We make sure to
|
||||
# lock Vagrant to our current Vagrant version. In addition to that,
|
||||
# we add all our plugin dependencies.
|
||||
@gemfile = build_gemfile(plugins)
|
||||
# Load dependencies into a request set for resolution
|
||||
request_set = Gem::RequestSet.new(*plugin_deps)
|
||||
# Never allow dependencies to be remotely satisfied during init
|
||||
request_set.remote = false
|
||||
|
||||
Util::SafeEnv.change_env do |env|
|
||||
# Set the environmental variables for Bundler
|
||||
env["BUNDLE_APP_CONFIG"] = @appconfigpath
|
||||
env["BUNDLE_CONFIG"] = @configfile.path
|
||||
env["BUNDLE_GEMFILE"] = @gemfile.path
|
||||
env["BUNDLE_RETRY"] = "3"
|
||||
env["GEM_PATH"] =
|
||||
"#{bundle_path}#{::File::PATH_SEPARATOR}#{@gem_path}"
|
||||
repair_result = nil
|
||||
begin
|
||||
# Compose set for resolution
|
||||
composed_set = generate_vagrant_set
|
||||
# Resolve the request set to ensure proper activation order
|
||||
solution = request_set.resolve(composed_set)
|
||||
rescue Gem::UnsatisfiableDependencyError => failure
|
||||
if repair
|
||||
raise failure if @init_retried
|
||||
@logger.debug("Resolution failed but attempting to repair. Failure: #{failure}")
|
||||
install(plugins)
|
||||
@init_retried = true
|
||||
retry
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
Gem.clear_paths
|
||||
# Activate the gems
|
||||
activate_solution(solution)
|
||||
|
||||
full_vagrant_spec_list = Gem::Specification.find_all{true} +
|
||||
solution.map(&:full_spec)
|
||||
|
||||
if(defined?(::Bundler))
|
||||
@logger.debug("Updating Bundler with full specification list")
|
||||
::Bundler.rubygems.replace_entrypoints(full_vagrant_spec_list)
|
||||
end
|
||||
|
||||
Gem.post_reset do
|
||||
Gem::Specification.all = full_vagrant_spec_list
|
||||
end
|
||||
|
||||
Gem::Specification.reset
|
||||
end
|
||||
|
||||
# Removes any temporary files created by init
|
||||
def deinit
|
||||
# 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
|
||||
# no-op
|
||||
end
|
||||
|
||||
# Installs the list of plugins.
|
||||
|
@ -106,35 +102,17 @@ module Vagrant
|
|||
#
|
||||
# @param [String] path Path to a local gem file.
|
||||
# @return [Gem::Specification]
|
||||
def install_local(path)
|
||||
# We have to do this load here because this file can be loaded
|
||||
# before RubyGems is actually loaded.
|
||||
require "rubygems/dependency_installer"
|
||||
begin
|
||||
require "rubygems/format"
|
||||
rescue LoadError
|
||||
# rubygems 2.x
|
||||
end
|
||||
|
||||
# If we're installing from a gem file, determine the name
|
||||
# based on the spec in the file.
|
||||
pkg = if defined?(Gem::Format)
|
||||
# RubyGems 1.x
|
||||
Gem::Format.from_file_by_path(path)
|
||||
else
|
||||
# RubyGems 2.x
|
||||
Gem::Package.new(path)
|
||||
end
|
||||
|
||||
# Install the gem manually. If the gem exists locally, then
|
||||
# Bundler shouldn't attempt to get it remotely.
|
||||
with_isolated_gem do
|
||||
installer = Gem::DependencyInstaller.new(
|
||||
document: [], prerelease: false)
|
||||
installer.install(path, "= #{pkg.spec.version}")
|
||||
end
|
||||
|
||||
pkg.spec
|
||||
def install_local(path, opts={})
|
||||
plugin_source = Gem::Source::SpecificFile.new(path)
|
||||
plugin_info = {
|
||||
plugin_source.spec.name => {
|
||||
"local_source" => plugin_source,
|
||||
"sources" => opts.fetch(:sources, Gem.sources.map(&:to_s))
|
||||
}
|
||||
}
|
||||
@logger.debug("Installing local plugin - #{plugin_info}")
|
||||
internal_install(plugin_info, {})
|
||||
plugin_source.spec
|
||||
end
|
||||
|
||||
# Update updates the given plugins, or every plugin if none is given.
|
||||
|
@ -144,277 +122,319 @@ module Vagrant
|
|||
# empty or nil, all plugins will be updated.
|
||||
def update(plugins, specific)
|
||||
specific ||= []
|
||||
update = true
|
||||
update = { gems: specific } if !specific.empty?
|
||||
update = {gems: specific.empty? ? true : specific}
|
||||
internal_install(plugins, update)
|
||||
end
|
||||
|
||||
# Clean removes any unused gems.
|
||||
def clean(plugins)
|
||||
gemfile = build_gemfile(plugins)
|
||||
lockfile = "#{gemfile.path}.lock"
|
||||
definition = ::Bundler::Definition.build(gemfile, lockfile, nil)
|
||||
root = File.dirname(gemfile.path)
|
||||
@logger.debug("Cleaning Vagrant plugins of stale gems.")
|
||||
# Generate dependencies for all registered plugins
|
||||
plugin_deps = plugins.map do |name, info|
|
||||
gem_version = info['installed_gem_version']
|
||||
gem_version = info['gem_version'] if gem_version.to_s.empty?
|
||||
gem_version = "> 0" if gem_version.to_s.empty?
|
||||
Gem::Dependency.new(name, gem_version)
|
||||
end
|
||||
|
||||
with_isolated_gem do
|
||||
runtime = ::Bundler::Runtime.new(root, definition)
|
||||
runtime.clean
|
||||
@logger.debug("Current plugin dependency list: #{plugin_deps}")
|
||||
|
||||
# Load dependencies into a request set for resolution
|
||||
request_set = Gem::RequestSet.new(*plugin_deps)
|
||||
# Never allow dependencies to be remotely satisfied during cleaning
|
||||
request_set.remote = false
|
||||
|
||||
# Sets that we can resolve our dependencies from. Note that we only
|
||||
# resolve from the current set as all required deps are activated during
|
||||
# init.
|
||||
current_set = generate_vagrant_set
|
||||
|
||||
# Collect all plugin specifications
|
||||
plugin_specs = Dir.glob(plugin_gem_path.join('specifications/*.gemspec').to_s).map do |spec_path|
|
||||
Gem::Specification.load(spec_path)
|
||||
end
|
||||
|
||||
@logger.debug("Generating current plugin state solution set.")
|
||||
|
||||
# Resolve the request set to ensure proper activation order
|
||||
solution = request_set.resolve(current_set)
|
||||
solution_specs = solution.map(&:full_spec)
|
||||
solution_full_names = solution_specs.map(&:full_name)
|
||||
|
||||
# Find all specs installed to plugins directory that are not
|
||||
# found within the solution set
|
||||
plugin_specs.delete_if do |spec|
|
||||
solution_full_names.include?(spec.full_name)
|
||||
end
|
||||
|
||||
@logger.debug("Specifications to be removed - #{plugin_specs.map(&:full_name)}")
|
||||
|
||||
# Now delete all unused specs
|
||||
plugin_specs.each do |spec|
|
||||
@logger.debug("Uninstalling gem - #{spec.full_name}")
|
||||
Gem::Uninstaller.new(spec.name,
|
||||
version: spec.version,
|
||||
install_dir: plugin_gem_path,
|
||||
all: true,
|
||||
executables: true,
|
||||
force: true,
|
||||
ignore: true,
|
||||
).uninstall_gem(spec)
|
||||
end
|
||||
|
||||
solution.find_all do |spec|
|
||||
plugins.keys.include?(spec.name)
|
||||
end
|
||||
end
|
||||
|
||||
# During the duration of the yielded block, Bundler loud output
|
||||
# is enabled.
|
||||
def verbose
|
||||
@monitor.synchronize do
|
||||
begin
|
||||
old_ui = ::Bundler.ui
|
||||
require 'bundler/vendored_thor'
|
||||
::Bundler.ui = ::Bundler::UI::Shell.new
|
||||
yield
|
||||
ensure
|
||||
::Bundler.ui = old_ui
|
||||
end
|
||||
if block_given?
|
||||
initial_state = @verbose
|
||||
@verbose = true
|
||||
yield
|
||||
@verbose = initial_state
|
||||
else
|
||||
@verbose = true
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Builds a valid Gemfile for use with Bundler given the list of
|
||||
# plugins.
|
||||
#
|
||||
# @return [Tempfile]
|
||||
def build_gemfile(plugins)
|
||||
sources = plugins.values.map { |p| p["sources"] }.flatten.compact.uniq
|
||||
def internal_install(plugins, update, **extra)
|
||||
# Only allow defined Gem sources
|
||||
Gem.sources.clear
|
||||
|
||||
f = tempfile("vagrant-gemfile")
|
||||
f.tap do |gemfile|
|
||||
sources.each do |source|
|
||||
next if source == ""
|
||||
gemfile.puts(%Q[source "#{source}"])
|
||||
update = {} if !update.is_a?(Hash)
|
||||
skips = []
|
||||
installer_set = Gem::Resolver::InstallerSet.new(:both)
|
||||
|
||||
# Generate all required plugin deps
|
||||
plugin_deps = plugins.map do |name, info|
|
||||
if update[:gems] == true || (update[:gems].respond_to?(:include?) && update[:gems].include?(name))
|
||||
gem_version = '> 0'
|
||||
skips << name
|
||||
else
|
||||
gem_version = info['gem_version'].to_s.empty? ? '> 0' : info['gem_version']
|
||||
end
|
||||
if plugin_source = info.delete("local_source")
|
||||
installer_set.add_local(plugin_source.spec.name, plugin_source.spec, plugin_source)
|
||||
end
|
||||
Array(info["sources"]).each do |source|
|
||||
if !Gem.sources.include?(source)
|
||||
@logger.debug("Adding RubyGems source for plugin install: #{source}")
|
||||
Gem.sources << source
|
||||
end
|
||||
end
|
||||
Gem::Dependency.new(name, gem_version)
|
||||
end
|
||||
|
||||
gemfile.puts(%Q[gem "vagrant", "= #{VERSION}"])
|
||||
@logger.debug("Dependency list for installation: #{plugin_deps}")
|
||||
|
||||
gemfile.puts("group :plugins do")
|
||||
plugins.each do |name, plugin|
|
||||
version = plugin["gem_version"]
|
||||
version = nil if version == ""
|
||||
# Create the request set for the new plugins
|
||||
request_set = Gem::RequestSet.new(*plugin_deps)
|
||||
|
||||
opts = {}
|
||||
if plugin["require"] && plugin["require"] != ""
|
||||
opts[:require] = plugin["require"]
|
||||
installer_set = Gem::Resolver.compose_sets(
|
||||
installer_set,
|
||||
generate_builtin_set,
|
||||
generate_plugin_set(skips)
|
||||
)
|
||||
|
||||
@logger.debug("Generating solution set for installation.")
|
||||
|
||||
# Generate the required solution set for new plugins
|
||||
solution = request_set.resolve(installer_set)
|
||||
activate_solution(solution)
|
||||
|
||||
@logger.debug("Installing required gems.")
|
||||
|
||||
# Install all remote gems into plugin path. Set the installer to ignore dependencies
|
||||
# as we know the dependencies are satisfied and it will attempt to validate a gem's
|
||||
# dependencies are satisified by gems in the install directory (which will likely not
|
||||
# be true)
|
||||
result = request_set.install_into(plugin_gem_path.to_s, true, ignore_dependencies: true)
|
||||
result = result.map(&:full_spec)
|
||||
result
|
||||
end
|
||||
|
||||
# Generate the composite resolver set totally all of vagrant (builtin + plugin set)
|
||||
def generate_vagrant_set
|
||||
Gem::Resolver.compose_sets(generate_builtin_set, generate_plugin_set)
|
||||
end
|
||||
|
||||
# @return [Array<[Gem::Specification, String]>] spec and directory pairs
|
||||
def vagrant_internal_specs
|
||||
list = {}
|
||||
directories = [Gem::Specification.default_specifications_dir]
|
||||
Gem::Specification.find_all{true}.each do |spec|
|
||||
list[spec.full_name] = spec
|
||||
end
|
||||
if(!defined?(::Bundler))
|
||||
directories += Gem::Specification.dirs.find_all do |path|
|
||||
!path.start_with?(Gem.user_dir)
|
||||
end
|
||||
end
|
||||
Gem::Specification.each_spec(directories) do |spec|
|
||||
if !list[spec.full_name]
|
||||
list[spec.full_name] = spec
|
||||
end
|
||||
end
|
||||
list.values
|
||||
end
|
||||
|
||||
# Generate the builtin resolver set
|
||||
def generate_builtin_set
|
||||
builtin_set = BuiltinSet.new
|
||||
@logger.debug("Generating new builtin set instance.")
|
||||
vagrant_internal_specs.each do |spec|
|
||||
builtin_set.add_builtin_spec(spec)
|
||||
end
|
||||
builtin_set
|
||||
end
|
||||
|
||||
# Generate the plugin resolver set. Optionally provide specification names (short or
|
||||
# full) that should be ignored
|
||||
def generate_plugin_set(skip=[])
|
||||
plugin_set = PluginSet.new
|
||||
@logger.debug("Generating new plugin set instance. Skip gems - #{skip}")
|
||||
Dir.glob(plugin_gem_path.join('specifications/*.gemspec').to_s).each do |spec_path|
|
||||
spec = Gem::Specification.load(spec_path)
|
||||
desired_spec_path = File.join(spec.gem_dir, "#{spec.name}.gemspec")
|
||||
# Vendor set requires the spec to be within the gem directory. Some gems will package their
|
||||
# spec file, and that's not what we want to load.
|
||||
if !File.exist?(desired_spec_path) || !FileUtils.cmp(spec.spec_file, desired_spec_path)
|
||||
File.write(desired_spec_path, spec.to_ruby)
|
||||
end
|
||||
next if skip.include?(spec.name) || skip.include?(spec.full_name)
|
||||
plugin_set.add_vendor_gem(spec.name, spec.gem_dir)
|
||||
end
|
||||
plugin_set
|
||||
end
|
||||
|
||||
# Activate a given solution
|
||||
def activate_solution(solution)
|
||||
retried = false
|
||||
begin
|
||||
@logger.debug("Activating solution set: #{solution.map(&:full_name)}")
|
||||
solution.each do |activation_request|
|
||||
unless activation_request.full_spec.activated?
|
||||
@logger.debug("Activating gem #{activation_request.full_spec.full_name}")
|
||||
activation_request.full_spec.activate
|
||||
if(defined?(::Bundler))
|
||||
@logger.debug("Marking gem #{activation_request.full_spec.full_name} loaded within Bundler.")
|
||||
::Bundler.rubygems.mark_loaded activation_request.full_spec
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Gem::LoadError => e
|
||||
# Depending on the version of Ruby, the ordering of the solution set
|
||||
# will be either 0..n (molinillo) or n..0 (pre-molinillo). Instead of
|
||||
# attempting to determine what's in use, or if it has some how changed
|
||||
# again, just reverse order on failure and attempt again.
|
||||
if retried
|
||||
@logger.error("Failed to load solution set - #{e.class}: #{e}")
|
||||
matcher = e.message.match(/Could not find '(?<gem_name>[^']+)'/)
|
||||
if matcher && !matcher["gem_name"].empty?
|
||||
desired_activation_request = solution.detect do |request|
|
||||
request.name == matcher["gem_name"]
|
||||
end
|
||||
if desired_activation_request && !desired_activation_request.full_spec.activated?
|
||||
activation_request = desired_activation_request
|
||||
@logger.warn("Found misordered activation request for #{desired_activation_request.full_name}. Moving to solution HEAD.")
|
||||
solution.delete(desired_activation_request)
|
||||
solution.unshift(desired_activation_request)
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
gemfile.puts(%Q[gem "#{name}", #{version.inspect}, #{opts.inspect}])
|
||||
raise
|
||||
else
|
||||
@logger.debug("Failed to load solution set. Retrying with reverse order.")
|
||||
retried = true
|
||||
solution.reverse!
|
||||
retry
|
||||
end
|
||||
gemfile.puts("end")
|
||||
gemfile.close
|
||||
end
|
||||
end
|
||||
|
||||
# This installs a set of plugins and optionally updates those gems.
|
||||
#
|
||||
# @param [Hash] plugins
|
||||
# @param [Hash, Boolean] update If true, updates all plugins, otherwise
|
||||
# can be a hash of options. See Bundler.definition.
|
||||
# @return [Array<Gem::Specification>]
|
||||
def internal_install(plugins, update, **extra)
|
||||
gemfile = build_gemfile(plugins)
|
||||
lockfile = "#{gemfile.path}.lock"
|
||||
definition = ::Bundler::Definition.build(gemfile, lockfile, update)
|
||||
root = File.dirname(gemfile.path)
|
||||
opts = {}
|
||||
opts["local"] = true if extra[:local]
|
||||
|
||||
with_isolated_gem do
|
||||
::Bundler::Installer.install(root, definition, opts)
|
||||
end
|
||||
|
||||
# TODO(mitchellh): clean gems here... for some reason when I put
|
||||
# it in on install, we get a GemNotFound exception. Gotta investigate.
|
||||
|
||||
definition.specs
|
||||
rescue ::Bundler::VersionConflict => e
|
||||
raise Errors::PluginInstallVersionConflict,
|
||||
conflicts: e.to_s.gsub("Bundler", "Vagrant")
|
||||
rescue ::Bundler::BundlerError => e
|
||||
if !::Bundler.ui.is_a?(BundlerUI)
|
||||
raise
|
||||
end
|
||||
|
||||
# Add the warn/error level output from Bundler if we have any
|
||||
message = "#{e.message}"
|
||||
if ::Bundler.ui.output != ""
|
||||
message += "\n\n#{::Bundler.ui.output}"
|
||||
end
|
||||
|
||||
raise ::Bundler::BundlerError, message
|
||||
end
|
||||
|
||||
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"] = 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
|
||||
ENV["GEM_HOME"] = Vagrant.user_data_path.join("gems").to_s
|
||||
|
||||
# Clear paths so that it reads the new GEM_HOME setting
|
||||
Gem.paths = ENV
|
||||
|
||||
# Reset the all specs override that Bundler does
|
||||
old_all = Gem::Specification._all
|
||||
|
||||
# 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
|
||||
begin
|
||||
old_config = Gem.configuration
|
||||
rescue Psych::SyntaxError
|
||||
# Just ignore this. This means that the ".gemrc" file has
|
||||
# an invalid syntax and can't be loaded. We don't care, because
|
||||
# when we set Gem.configuration to nil later, it'll force a reload
|
||||
# if it is needed.
|
||||
end
|
||||
Gem.configuration = NilGemConfig.new
|
||||
|
||||
# Use a silent UI so that we have no output
|
||||
Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) do
|
||||
return yield
|
||||
end
|
||||
ensure
|
||||
tmp_gemfile.unlink rescue nil
|
||||
|
||||
ENV["BUNDLE_GEMFILE"] = old_gemfile
|
||||
ENV["GEM_HOME"] = @gem_home
|
||||
ENV["RUBYOPT"] = old_rubyopt
|
||||
|
||||
Gem.configuration = old_config
|
||||
Gem.paths = ENV
|
||||
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
|
||||
# This is a custom Gem::Resolver::Set for use with vagrant "system" gems. It
|
||||
# allows the installed set of gems to be used for providing a solution while
|
||||
# enforcing strict constraints. This ensures that plugins cannot "upgrade"
|
||||
# gems that are builtin to vagrant itself.
|
||||
class BuiltinSet < Gem::Resolver::Set
|
||||
def initialize
|
||||
# We _can not_ `super` here because that can really mess up
|
||||
# some other configuration state. We need to just set everything
|
||||
# directly.
|
||||
super
|
||||
@remote = false
|
||||
@specs = []
|
||||
end
|
||||
|
||||
@api_keys = {}
|
||||
@args = []
|
||||
@backtrace = false
|
||||
@bulk_threshold = 1000
|
||||
@hash = {}
|
||||
@update_sources = true
|
||||
@verbose = true
|
||||
def add_builtin_spec(spec)
|
||||
@specs.push(spec).uniq!
|
||||
end
|
||||
|
||||
def find_all(req)
|
||||
@specs.select do |spec|
|
||||
req.match?(spec)
|
||||
end.map do |spec|
|
||||
Gem::Resolver::InstalledSpecification.new(self, spec)
|
||||
end
|
||||
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
|
||||
# This is a custom Gem::Resolver::Set for use with Vagrant plugins. It is
|
||||
# a modified Gem::Resolver::VendorSet that supports multiple versions of
|
||||
# a specific gem
|
||||
class PluginSet < Gem::Resolver::VendorSet
|
||||
##
|
||||
# Adds a specification to the set with the given +name+ which has been
|
||||
# unpacked into the given +directory+.
|
||||
def add_vendor_gem(name, directory)
|
||||
gemspec = File.join(directory, "#{name}.gemspec")
|
||||
spec = Gem::Specification.load(gemspec)
|
||||
if !spec
|
||||
raise Gem::GemNotFoundException,
|
||||
"unable to find #{gemspec} for gem #{name}"
|
||||
end
|
||||
|
||||
spec.full_gem_path = File.expand_path(directory)
|
||||
|
||||
@specs[spec.name] ||= []
|
||||
@specs[spec.name] << spec
|
||||
@directories[spec] = directory
|
||||
|
||||
spec
|
||||
end
|
||||
end
|
||||
|
||||
if ::Bundler::UI.const_defined? :Silent
|
||||
class BundlerUI < ::Bundler::UI::Silent
|
||||
attr_reader :output
|
||||
|
||||
def initialize
|
||||
@output = ""
|
||||
##
|
||||
# Returns an Array of VendorSpecification objects matching the
|
||||
# DependencyRequest +req+.
|
||||
def find_all(req)
|
||||
@specs.values.flatten.select do |spec|
|
||||
req.match?(spec)
|
||||
end.map do |spec|
|
||||
source = Gem::Source::Vendor.new(@directories[spec])
|
||||
Gem::Resolver::VendorSpecification.new(self, spec, source)
|
||||
end
|
||||
end
|
||||
|
||||
def info(message, newline = nil)
|
||||
end
|
||||
|
||||
def confirm(message, newline = nil)
|
||||
end
|
||||
|
||||
def warn(message, newline = nil)
|
||||
@output += message
|
||||
@output += "\n" if newline
|
||||
end
|
||||
|
||||
def error(message, newline = nil)
|
||||
@output += message
|
||||
@output += "\n" if newline
|
||||
end
|
||||
|
||||
def debug(message, newline = nil)
|
||||
end
|
||||
|
||||
def debug?
|
||||
false
|
||||
end
|
||||
|
||||
def quiet?
|
||||
false
|
||||
end
|
||||
|
||||
def ask(message)
|
||||
end
|
||||
|
||||
def level=(name)
|
||||
end
|
||||
|
||||
def level(name = nil)
|
||||
"info"
|
||||
end
|
||||
|
||||
def trace(message, newline = nil)
|
||||
end
|
||||
|
||||
def silence
|
||||
yield
|
||||
end
|
||||
##
|
||||
# Loads a spec with the given +name+. +version+, +platform+ and +source+ are
|
||||
# ignored.
|
||||
def load_spec (name, version, platform, source)
|
||||
version = Gem::Version.new(version) if !version.is_a?(Gem::Version)
|
||||
@specs.fetch(name, []).detect{|s| s.name == name && s.version = version}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Patch for Ruby 2.2 and Bundler to behave properly when uninstalling plugins
|
||||
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
|
||||
if defined?(::Bundler) && !::Bundler::SpecSet.instance_methods.include?(:delete)
|
||||
class Gem::Specification
|
||||
def self.remove_spec(spec)
|
||||
Gem::Specification.reset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -338,7 +338,7 @@ module Vagrant
|
|||
# a priority to each in the order they exist so that we try these first.
|
||||
config = {}
|
||||
root_config.vm.__providers.reverse.each_with_index do |key, idx|
|
||||
config[key] = idx
|
||||
config[key] = idx + 1
|
||||
end
|
||||
|
||||
# Determine the max priority so that we can add the config priority
|
||||
|
|
|
@ -340,6 +340,10 @@ module Vagrant
|
|||
error_key(:downloader_interrupted)
|
||||
end
|
||||
|
||||
class DownloaderChecksumError < VagrantError
|
||||
error_key(:downloader_checksum_error)
|
||||
end
|
||||
|
||||
class EnvInval < VagrantError
|
||||
error_key(:env_inval)
|
||||
end
|
||||
|
@ -456,6 +460,10 @@ module Vagrant
|
|||
error_key(:nfs_bad_exports)
|
||||
end
|
||||
|
||||
class NFSExportsFailed < VagrantError
|
||||
error_key(:nfs_exports_failed)
|
||||
end
|
||||
|
||||
class NFSCantReadExports < VagrantError
|
||||
error_key(:nfs_cant_read_exports)
|
||||
end
|
||||
|
@ -580,6 +588,10 @@ module Vagrant
|
|||
error_key(:plugin_uninstall_system)
|
||||
end
|
||||
|
||||
class PluginInitError < VagrantError
|
||||
error_key(:plugin_init_error)
|
||||
end
|
||||
|
||||
class PushesNotDefined < VagrantError
|
||||
error_key(:pushes_not_defined)
|
||||
end
|
||||
|
@ -608,6 +620,10 @@ module Vagrant
|
|||
error_key(:rsync_not_installed_in_guest)
|
||||
end
|
||||
|
||||
class RSyncGuestInstallError < VagrantError
|
||||
error_key(:rsync_guest_install_error)
|
||||
end
|
||||
|
||||
class SCPPermissionDenied < VagrantError
|
||||
error_key(:scp_permission_denied)
|
||||
end
|
||||
|
|
|
@ -44,10 +44,9 @@ module Vagrant
|
|||
local = false
|
||||
if name =~ /\.gem$/
|
||||
# If this is a gem file, then we install that gem locally.
|
||||
local_spec = Vagrant::Bundler.instance.install_local(name)
|
||||
local_spec = Vagrant::Bundler.instance.install_local(name, opts)
|
||||
name = local_spec.name
|
||||
opts[:version] = local_spec.version.to_s
|
||||
local = true
|
||||
end
|
||||
|
||||
plugins = installed_plugins
|
||||
|
@ -57,33 +56,41 @@ module Vagrant
|
|||
"sources" => opts[:sources],
|
||||
}
|
||||
|
||||
result = nil
|
||||
install_lambda = lambda do
|
||||
Vagrant::Bundler.instance.install(plugins, local).each do |spec|
|
||||
next if spec.name != name
|
||||
next if result && result.version >= spec.version
|
||||
result = spec
|
||||
if local_spec.nil?
|
||||
result = nil
|
||||
install_lambda = lambda do
|
||||
Vagrant::Bundler.instance.install(plugins, local).each do |spec|
|
||||
next if spec.name != name
|
||||
next if result && result.version >= spec.version
|
||||
result = spec
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if opts[:verbose]
|
||||
Vagrant::Bundler.instance.verbose(&install_lambda)
|
||||
if opts[:verbose]
|
||||
Vagrant::Bundler.instance.verbose(&install_lambda)
|
||||
else
|
||||
install_lambda.call
|
||||
end
|
||||
else
|
||||
install_lambda.call
|
||||
result = local_spec
|
||||
end
|
||||
|
||||
# Add the plugin to the state file
|
||||
@user_file.add_plugin(
|
||||
result.name,
|
||||
version: opts[:version],
|
||||
require: opts[:require],
|
||||
sources: opts[:sources],
|
||||
installed_gem_version: result.version.to_s
|
||||
)
|
||||
|
||||
# After install clean plugin gems to remove any cruft. This is useful
|
||||
# for removing outdated dependencies or other versions of an installed
|
||||
# plugin if the plugin is upgraded/downgraded
|
||||
Vagrant::Bundler.instance.clean(installed_plugins)
|
||||
result
|
||||
rescue ::Bundler::GemNotFound
|
||||
rescue Gem::GemNotFoundException
|
||||
raise Errors::PluginGemNotFound, name: name
|
||||
rescue ::Bundler::BundlerError => e
|
||||
rescue Gem::Exception => e
|
||||
raise Errors::BundlerError, message: e.to_s
|
||||
end
|
||||
|
||||
|
@ -102,14 +109,30 @@ module Vagrant
|
|||
|
||||
# Clean the environment, removing any old plugins
|
||||
Vagrant::Bundler.instance.clean(installed_plugins)
|
||||
rescue ::Bundler::BundlerError => e
|
||||
rescue Gem::Exception => e
|
||||
raise Errors::BundlerError, message: e.to_s
|
||||
end
|
||||
|
||||
# Updates all or a specific set of plugins.
|
||||
def update_plugins(specific)
|
||||
Vagrant::Bundler.instance.update(installed_plugins, specific)
|
||||
rescue ::Bundler::BundlerError => e
|
||||
result = Vagrant::Bundler.instance.update(installed_plugins, specific)
|
||||
installed_plugins.each do |name, info|
|
||||
matching_spec = result.detect{|s| s.name == name}
|
||||
info = Hash[
|
||||
info.map do |key, value|
|
||||
[key.to_sym, value]
|
||||
end
|
||||
]
|
||||
if matching_spec
|
||||
@user_file.add_plugin(name, **info.merge(
|
||||
version: "> 0",
|
||||
installed_gem_version: matching_spec.version.to_s
|
||||
))
|
||||
end
|
||||
end
|
||||
Vagrant::Bundler.instance.clean(installed_plugins)
|
||||
result
|
||||
rescue Gem::Exception => e
|
||||
raise Errors::BundlerError, message: e.to_s
|
||||
end
|
||||
|
||||
|
@ -123,8 +146,14 @@ module Vagrant
|
|||
system[k] = v.merge("system" => true)
|
||||
end
|
||||
end
|
||||
plugin_list = system.merge(@user_file.installed_plugins)
|
||||
|
||||
system.merge(@user_file.installed_plugins)
|
||||
# Sort plugins by name
|
||||
Hash[
|
||||
plugin_list.map{|plugin_name, plugin_info|
|
||||
[plugin_name, plugin_info]
|
||||
}.sort_by(&:first)
|
||||
]
|
||||
end
|
||||
|
||||
# This returns the list of plugins that are installed as
|
||||
|
|
|
@ -31,11 +31,12 @@ module Vagrant
|
|||
# @param [String] name The name of the plugin
|
||||
def add_plugin(name, **opts)
|
||||
@data["installed"][name] = {
|
||||
"ruby_version" => RUBY_VERSION,
|
||||
"vagrant_version" => Vagrant::VERSION,
|
||||
"gem_version" => opts[:version] || "",
|
||||
"require" => opts[:require] || "",
|
||||
"sources" => opts[:sources] || [],
|
||||
"ruby_version" => RUBY_VERSION,
|
||||
"vagrant_version" => Vagrant::VERSION,
|
||||
"gem_version" => opts[:version] || "",
|
||||
"require" => opts[:require] || "",
|
||||
"sources" => opts[:sources] || [],
|
||||
"installed_gem_version" => opts[:installed_gem_version]
|
||||
}
|
||||
|
||||
save!
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
# This file is to be loaded _before_ any RubyGems are loaded. This file
|
||||
# initializes the Bundler context so that Vagrant and its associated plugins
|
||||
# can load properly, and then execs out into Vagrant again.
|
||||
|
||||
require_relative "shared_helpers"
|
||||
|
||||
if defined?(Bundler)
|
||||
require "bundler/shared_helpers"
|
||||
if Bundler::SharedHelpers.in_bundle? && !Vagrant.very_quiet?
|
||||
puts "Vagrant appears to be running in a Bundler environment. Your "
|
||||
puts "existing Gemfile will be used. Vagrant will not auto-load any plugins"
|
||||
puts "installed with `vagrant plugin`. Vagrant will autoload any plugins in"
|
||||
puts "the 'plugins' group in your Gemfile. You can force Vagrant to take over"
|
||||
puts "with VAGRANT_FORCE_BUNDLER."
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
require_relative "bundler"
|
||||
require_relative "plugin/manager"
|
||||
|
||||
plugins = Vagrant::Plugin::Manager.instance.installed_plugins
|
||||
Vagrant::Bundler.instance.init!(plugins)
|
||||
|
||||
ENV["VAGRANT_INTERNAL_BUNDLERIZED"] = "1"
|
||||
|
||||
# If the VAGRANT_EXECUTABLE env is set, then we use that to point to a
|
||||
# Ruby file to directly execute. Otherwise, we just depend on PATH lookup.
|
||||
# This minor optimization can save hundreds of milliseconds on Windows.
|
||||
if ENV["VAGRANT_EXECUTABLE"]
|
||||
Kernel.exec("ruby", ENV["VAGRANT_EXECUTABLE"], *ARGV)
|
||||
else
|
||||
Kernel.exec("vagrant", *ARGV)
|
||||
end
|
|
@ -38,11 +38,18 @@ module Vagrant
|
|||
ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"]
|
||||
end
|
||||
|
||||
# Should the plugin system be initialized
|
||||
#
|
||||
# @return [Boolean]
|
||||
def self.plugins_init?
|
||||
!ENV['VAGRANT_DISABLE_PLUGIN_INIT']
|
||||
end
|
||||
|
||||
# This returns whether or not 3rd party plugins should and can be loaded.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def self.plugins_enabled?
|
||||
!ENV["VAGRANT_NO_PLUGINS"] && $vagrant_bundler_runtime
|
||||
!ENV["VAGRANT_NO_PLUGINS"]
|
||||
end
|
||||
|
||||
# Whether or not super quiet mode is enabled. This is ill-advised.
|
||||
|
|
|
@ -9,6 +9,7 @@ module Vagrant
|
|||
autoload :SafeExec, 'vagrant/util/safe_exec'
|
||||
autoload :StackedProcRunner, 'vagrant/util/stacked_proc_runner'
|
||||
autoload :TemplateRenderer, 'vagrant/util/template_renderer'
|
||||
autoload :StringBlockEditor, 'vagrant/util/string_block_editor'
|
||||
autoload :Subprocess, 'vagrant/util/subprocess'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
require "uri"
|
||||
|
||||
require "log4r"
|
||||
|
||||
require "digest/md5"
|
||||
require "digest/sha1"
|
||||
require "vagrant/util/busy"
|
||||
require "vagrant/util/platform"
|
||||
require "vagrant/util/subprocess"
|
||||
|
@ -18,6 +19,12 @@ module Vagrant
|
|||
# Vagrant/1.7.4 (+https://www.vagrantup.com; ruby2.1.0)
|
||||
USER_AGENT = "Vagrant/#{VERSION} (+https://www.vagrantup.com; #{RUBY_ENGINE}#{RUBY_VERSION})".freeze
|
||||
|
||||
# Supported file checksum
|
||||
CHECKSUM_MAP = {
|
||||
:md5 => Digest::MD5,
|
||||
:sha1 => Digest::SHA1
|
||||
}.freeze
|
||||
|
||||
attr_reader :source
|
||||
attr_reader :destination
|
||||
|
||||
|
@ -52,6 +59,10 @@ module Vagrant
|
|||
@ui = options[:ui]
|
||||
@client_cert = options[:client_cert]
|
||||
@location_trusted = options[:location_trusted]
|
||||
@checksums = {
|
||||
:md5 => options[:md5],
|
||||
:sha1 => options[:sha1]
|
||||
}
|
||||
end
|
||||
|
||||
# This executes the actual download, downloading the source file
|
||||
|
@ -161,6 +172,8 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
validate_download!(@source, @destination, @checksums)
|
||||
|
||||
# Everything succeeded
|
||||
true
|
||||
end
|
||||
|
@ -178,6 +191,46 @@ module Vagrant
|
|||
|
||||
protected
|
||||
|
||||
# Apply any checksum validations based on provided
|
||||
# options content
|
||||
#
|
||||
# @param source [String] Source of file
|
||||
# @param path [String, Pathname] local file path
|
||||
# @param checksums [Hash] User provided options
|
||||
# @option checksums [String] :md5 Compare MD5 checksum
|
||||
# @option checksums [String] :sha1 Compare SHA1 checksum
|
||||
# @return [Boolean]
|
||||
def validate_download!(source, path, checksums)
|
||||
CHECKSUM_MAP.each do |type, klass|
|
||||
if checksums[type]
|
||||
result = checksum_file(klass, path)
|
||||
@logger.debug("Validating checksum (#{type}) for #{source}. " \
|
||||
"expected: #{checksums[type]} actual: #{result}")
|
||||
if checksums[type] != result
|
||||
raise Errors::DownloaderChecksumError.new(
|
||||
source: source,
|
||||
path: path,
|
||||
type: type,
|
||||
expected_checksum: checksums[type],
|
||||
actual_checksum: result
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Generate checksum on given file
|
||||
#
|
||||
# @param digest_class [Class] Digest class to use for generating checksum
|
||||
# @param path [String, Pathname] Path to file
|
||||
# @return [String] hexdigest result
|
||||
def checksum_file(digest_class, path)
|
||||
digester = digest_class.new
|
||||
digester.file(path)
|
||||
digester.hexdigest
|
||||
end
|
||||
|
||||
def execute_curl(options, subprocess_options, &data_proc)
|
||||
options = options.dup
|
||||
options << subprocess_options
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
require "bundler"
|
||||
|
||||
module Vagrant
|
||||
module Util
|
||||
class Env
|
||||
def self.with_original_env
|
||||
original_env = ENV.to_hash
|
||||
ENV.replace(::Bundler::ORIGINAL_ENV) if defined?(::Bundler::ORIGINAL_ENV)
|
||||
if defined?(::Bundler) && defined?(::Bundler::ORIGINAL_ENV)
|
||||
ENV.replace(::Bundler::ORIGINAL_ENV)
|
||||
end
|
||||
ENV.update(Vagrant.original_env)
|
||||
yield
|
||||
ensure
|
||||
|
@ -37,7 +37,9 @@ module Vagrant
|
|||
# the block to execute with the cleaned environment
|
||||
def self.with_clean_env
|
||||
with_original_env do
|
||||
ENV["MANPATH"] = ENV["BUNDLE_ORIG_MANPATH"]
|
||||
if ENV["BUNDLE_ORIG_MANPATH"]
|
||||
ENV["MANPATH"] = ENV["BUNDLE_ORIG_MANPATH"]
|
||||
end
|
||||
ENV.delete_if { |k,_| k[0,7] == "BUNDLE_" }
|
||||
if ENV.has_key? "RUBYOPT"
|
||||
ENV["RUBYOPT"] = ENV["RUBYOPT"].sub("-rbundler/setup", "")
|
||||
|
|
|
@ -7,6 +7,9 @@ module Vagrant
|
|||
# thread. In that case, `safe_exec` automatically falls back to
|
||||
# forking.
|
||||
class SafeExec
|
||||
|
||||
@@logger = Log4r::Logger.new("vagrant::util::safe_exec")
|
||||
|
||||
def self.exec(command, *args)
|
||||
# Create a list of things to rescue from. Since this is OS
|
||||
# specific, we need to do some defined? checks here to make
|
||||
|
@ -18,10 +21,27 @@ module Vagrant
|
|||
|
||||
fork_instead = false
|
||||
begin
|
||||
pid = nil
|
||||
pid = fork if fork_instead
|
||||
Kernel.exec(command, *args) if pid.nil?
|
||||
Process.wait(pid) if pid
|
||||
if fork_instead
|
||||
if Vagrant::Util::Platform.windows?
|
||||
@@logger.debug("Using subprocess because windows platform")
|
||||
args = args.dup << {notify: [:stdout, :stderr]}
|
||||
result = Vagrant::Util::Subprocess.execute(command, *args) do |type, data|
|
||||
case type
|
||||
when :stdout
|
||||
@@logger.info(data, new_line: false)
|
||||
when :stderr
|
||||
@@logger.info(data, new_line: false)
|
||||
end
|
||||
end
|
||||
Kernel.exit(result.exit_code)
|
||||
else
|
||||
pid = fork
|
||||
Kernel.exec(command, *args)
|
||||
Process.wait(pid)
|
||||
end
|
||||
else
|
||||
Kernel.exec(command, *args)
|
||||
end
|
||||
rescue *rescue_from
|
||||
# We retried already, raise the issue and be done
|
||||
raise if fork_instead
|
||||
|
|
|
@ -144,10 +144,11 @@ module Vagrant
|
|||
# Record the start time for timeout purposes
|
||||
start_time = Time.now.to_i
|
||||
|
||||
open_readers = [stdout, stderr]
|
||||
open_writers = notify_stdin ? [process.io.stdin] : []
|
||||
@logger.debug("Selecting on IO")
|
||||
while true
|
||||
writers = notify_stdin ? [process.io.stdin] : []
|
||||
results = ::IO.select([stdout, stderr], writers, nil, 0.1)
|
||||
results = ::IO.select(open_readers, open_writers, nil, 0.1)
|
||||
results ||= []
|
||||
readers = results[0]
|
||||
writers = results[1]
|
||||
|
@ -178,8 +179,14 @@ module Vagrant
|
|||
break if process.exited?
|
||||
|
||||
# Check the writers to see if they're ready, and notify any listeners
|
||||
if writers && !writers.empty?
|
||||
yield :stdin, process.io.stdin if block_given?
|
||||
if writers && !writers.empty? && block_given?
|
||||
yield :stdin, process.io.stdin
|
||||
|
||||
# if the callback closed stdin, we should remove it, because
|
||||
# IO.select() will throw if called with a closed io.
|
||||
if process.io.stdin.closed?
|
||||
open_writers = []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -290,7 +297,9 @@ module Vagrant
|
|||
def jailbreak(env = {})
|
||||
return if ENV.key?("VAGRANT_SKIP_SUBPROCESS_JAILBREAK")
|
||||
|
||||
env.replace(::Bundler::ORIGINAL_ENV) if defined?(::Bundler::ORIGINAL_ENV)
|
||||
if defined?(::Bundler) && defined?(::Bundler::ORIGINAL_ENV)
|
||||
env.replace(::Bundler::ORIGINAL_ENV)
|
||||
end
|
||||
env.merge!(Vagrant.original_env)
|
||||
|
||||
# Bundler does this, so I guess we should as well, since I think it
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
require 'optparse'
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandBox
|
||||
module Command
|
||||
class Prune < Vagrant.plugin("2", :command)
|
||||
def execute
|
||||
options = {}
|
||||
options[:force] = false
|
||||
options[:dry_run] = false
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant box prune [options]"
|
||||
o.separator ""
|
||||
o.separator "Options:"
|
||||
o.separator ""
|
||||
|
||||
o.on("-p PROVIDER", "--provider PROVIDER", String, "The specific provider type for the boxes to destroy.") do |p|
|
||||
options[:provider] = p
|
||||
end
|
||||
|
||||
o.on("-n", "--dry-run", "Only print the boxes that would be removed.") do |f|
|
||||
options[:dry_run] = f
|
||||
end
|
||||
|
||||
o.on("--name NAME", String, "The specific box name to check for outdated versions.") do |name|
|
||||
options[:name] = name
|
||||
end
|
||||
|
||||
o.on("-f", "--force", "Destroy without confirmation even when box is in use.") do |f|
|
||||
options[:force] = f
|
||||
end
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
|
||||
boxes = @env.boxes.all.sort
|
||||
if boxes.empty?
|
||||
return @env.ui.warn(I18n.t("vagrant.commands.box.no_installed_boxes"), prefix: false)
|
||||
end
|
||||
|
||||
delete_oldest_boxes(boxes, options[:provider], options[:force], options[:name], options[:dry_run])
|
||||
|
||||
# Success, exit status 0
|
||||
0
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def delete_oldest_boxes(boxes, only_provider, skip_confirm, only_name, dry_run)
|
||||
# Find the longest box name
|
||||
longest_box = boxes.max_by { |x| x[0].length }
|
||||
longest_box_length = longest_box[0].length
|
||||
|
||||
# Hash map to keep track of newest versions
|
||||
newest_boxes = Hash.new
|
||||
|
||||
# First find the newest version for every installed box
|
||||
boxes.each do |name, version, provider|
|
||||
next if only_provider and only_provider != provider.to_s
|
||||
next if only_name and only_name != name
|
||||
|
||||
# Nested to make sure it works for boxes with different providers
|
||||
if newest_boxes.has_key?(name)
|
||||
if newest_boxes[name].has_key?(provider)
|
||||
saved = Gem::Version.new(newest_boxes[name][provider])
|
||||
current = Gem::Version.new(version)
|
||||
if current > saved
|
||||
newest_boxes[name][provider] = version
|
||||
end
|
||||
else
|
||||
newest_boxes[name][provider] = version
|
||||
end
|
||||
else
|
||||
newest_boxes[name] = Hash.new
|
||||
newest_boxes[name][provider] = version
|
||||
end
|
||||
end
|
||||
|
||||
@env.ui.info("The following boxes will be kept...");
|
||||
newest_boxes.each do |name, providers|
|
||||
providers.each do |provider, version|
|
||||
@env.ui.info("#{name.ljust(longest_box_length)} (#{provider}, #{version})")
|
||||
|
||||
@env.ui.machine("box-name", name)
|
||||
@env.ui.machine("box-provider", provider)
|
||||
@env.ui.machine("box-version", version)
|
||||
end
|
||||
end
|
||||
|
||||
@env.ui.info("", prefix: false)
|
||||
@env.ui.info("Checking for older boxes...");
|
||||
|
||||
# Track if we removed anything so the user can be informed
|
||||
removed_any_box = false
|
||||
boxes.each do |name, version, provider|
|
||||
next if !newest_boxes.has_key?(name) or !newest_boxes[name].has_key?(provider)
|
||||
|
||||
current = Gem::Version.new(version)
|
||||
saved = Gem::Version.new(newest_boxes[name][provider])
|
||||
if current < saved
|
||||
removed_any_box = true
|
||||
|
||||
# Use the remove box action
|
||||
if dry_run
|
||||
@env.ui.info("Would remove #{name} #{provider} #{version}")
|
||||
else
|
||||
@env.action_runner.run(Vagrant::Action.action_box_remove, {
|
||||
box_name: name,
|
||||
box_provider: provider,
|
||||
box_version: version,
|
||||
force_confirm_box_remove: skip_confirm,
|
||||
box_remove_all_versions: false,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if !removed_any_box
|
||||
@env.ui.info("No old versions of boxes to remove...");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -34,6 +34,11 @@ module VagrantPlugins
|
|||
Remove
|
||||
end
|
||||
|
||||
@subcommands.register(:prune) do
|
||||
require_relative "prune"
|
||||
Prune
|
||||
end
|
||||
|
||||
@subcommands.register(:repackage) do
|
||||
require File.expand_path("../repackage", __FILE__)
|
||||
Repackage
|
||||
|
|
|
@ -6,6 +6,12 @@ module VagrantPlugins
|
|||
module CommandPlugin
|
||||
module Action
|
||||
# This middleware sequence will install a plugin.
|
||||
def self.action_expunge
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use ExpungePlugins
|
||||
end
|
||||
end
|
||||
|
||||
def self.action_install
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use InstallGem
|
||||
|
@ -27,6 +33,13 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
# This middleware sequence will repair installed plugins.
|
||||
def self.action_repair
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use RepairPlugins
|
||||
end
|
||||
end
|
||||
|
||||
# This middleware sequence will uninstall a plugin.
|
||||
def self.action_uninstall
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
|
@ -44,10 +57,12 @@ module VagrantPlugins
|
|||
|
||||
# The autoload farm
|
||||
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
||||
autoload :ExpungePlugins, action_root.join("expunge_plugins")
|
||||
autoload :InstallGem, action_root.join("install_gem")
|
||||
autoload :LicensePlugin, action_root.join("license_plugin")
|
||||
autoload :ListPlugins, action_root.join("list_plugins")
|
||||
autoload :PluginExistsCheck, action_root.join("plugin_exists_check")
|
||||
autoload :RepairPlugins, action_root.join("repair_plugins")
|
||||
autoload :UninstallPlugin, action_root.join("uninstall_plugin")
|
||||
autoload :UpdateGems, action_root.join("update_gems")
|
||||
end
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
require "vagrant/plugin/manager"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Action
|
||||
# This middleware removes user installed plugins by
|
||||
# removing:
|
||||
# * ~/.vagrant.d/plugins.json
|
||||
# * ~/.vagrant.d/gems
|
||||
# Usage should be restricted to when a repair is
|
||||
# unsuccessful and the only reasonable option remaining
|
||||
# is to re-install all plugins
|
||||
class ExpungePlugins
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if !env[:force]
|
||||
result = env[:ui].ask(
|
||||
I18n.t("vagrant.commands.plugin.expunge_confirm") +
|
||||
" [Y/N]:"
|
||||
)
|
||||
if result.to_s.downcase.strip != 'y'
|
||||
abort_action = true
|
||||
end
|
||||
end
|
||||
|
||||
if !abort_action
|
||||
plugins_json = File.join(env[:home_path], "plugins.json")
|
||||
plugins_gems = env[:gems_path]
|
||||
|
||||
if File.exist?(plugins_json)
|
||||
FileUtils.rm(plugins_json)
|
||||
end
|
||||
|
||||
if File.directory?(plugins_gems)
|
||||
FileUtils.rm_rf(plugins_gems)
|
||||
end
|
||||
|
||||
env[:ui].info(I18n.t("vagrant.commands.plugin.expunge_complete"))
|
||||
|
||||
@app.call(env)
|
||||
else
|
||||
env[:ui].info(I18n.t("vagrant.commands.plugin.expunge_aborted"))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,7 +18,11 @@ module VagrantPlugins
|
|||
def call(env)
|
||||
manager = Vagrant::Plugin::Manager.instance
|
||||
plugins = manager.installed_plugins
|
||||
specs = manager.installed_specs
|
||||
specs = Hash[
|
||||
manager.installed_specs.map do |spec|
|
||||
[spec.name, spec]
|
||||
end
|
||||
]
|
||||
|
||||
# Output!
|
||||
if specs.empty?
|
||||
|
@ -26,9 +30,10 @@ module VagrantPlugins
|
|||
return @app.call(env)
|
||||
end
|
||||
|
||||
specs.each do |spec|
|
||||
# Grab the plugin.
|
||||
plugin = plugins[spec.name]
|
||||
plugins.each do |plugin_name, plugin|
|
||||
|
||||
spec = specs[plugin_name]
|
||||
next if spec.nil?
|
||||
|
||||
system = ""
|
||||
system = ", system" if plugin && plugin["system"]
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
require "vagrant/plugin/manager"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Action
|
||||
# This middleware attempts to repair installed plugins.
|
||||
#
|
||||
# In general, if plugins are failing to properly load the
|
||||
# core issue will likely be one of two issues:
|
||||
# 1. manual modifications within ~/.vagrant.d/
|
||||
# 2. vagrant upgrade
|
||||
# Running an install on configured plugin set will most
|
||||
# likely fix these issues, which is all this action does.
|
||||
class RepairPlugins
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::plugins::plugincommand::repair")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env[:ui].info(I18n.t("vagrant.commands.plugin.repairing"))
|
||||
plugins = Vagrant::Plugin::Manager.instance.installed_plugins
|
||||
begin
|
||||
Vagrant::Bundler.instance.init!(plugins, :repair)
|
||||
env[:ui].info(I18n.t("vagrant.commands.plugin.repair_complete"))
|
||||
rescue Exception => e
|
||||
@logger.error("Failed to repair user installed plugins: #{e.class} - #{e}")
|
||||
e.backtrace.each do |backtrace_line|
|
||||
@logger.debug(backtrace_line)
|
||||
end
|
||||
env[:ui].error(I18n.t("vagrant.commands.plugin.repair_failed", message: e.message))
|
||||
end
|
||||
# Continue
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -19,17 +19,15 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
manager = Vagrant::Plugin::Manager.instance
|
||||
installed_specs = manager.installed_specs
|
||||
installed_plugins = manager.installed_plugins
|
||||
new_specs = manager.update_plugins(names)
|
||||
updated_plugins = manager.installed_plugins
|
||||
|
||||
updated = {}
|
||||
installed_specs.each do |ispec|
|
||||
new_specs.each do |uspec|
|
||||
next if uspec.name != ispec.name
|
||||
next if ispec.version >= uspec.version
|
||||
next if updated[uspec.name] && updated[uspec.name].version >= uspec.version
|
||||
|
||||
updated[uspec.name] = uspec
|
||||
installed_plugins.each do |name, info|
|
||||
update = updated_plugins[name]
|
||||
if update && update["installed_gem_version"] != info["installed_gem_version"]
|
||||
updated[name] = update["installed_gem_version"]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -37,9 +35,9 @@ module VagrantPlugins
|
|||
env[:ui].success(I18n.t("vagrant.commands.plugin.up_to_date"))
|
||||
end
|
||||
|
||||
updated.values.each do |spec|
|
||||
updated.each do |name, version|
|
||||
env[:ui].success(I18n.t("vagrant.commands.plugin.updated",
|
||||
name: spec.name, version: spec.version.to_s))
|
||||
name: name, version: version.to_s))
|
||||
end
|
||||
|
||||
# Continue
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
require 'optparse'
|
||||
|
||||
require_relative "base"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Command
|
||||
class Expunge < Base
|
||||
def execute
|
||||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant plugin expunge [-h]"
|
||||
|
||||
o.on("--force", "Do not prompt for confirmation") do |force|
|
||||
options[:force] = force
|
||||
end
|
||||
|
||||
o.on("--reinstall", "Reinstall current plugins after expunge") do |reinstall|
|
||||
options[:reinstall] = reinstall
|
||||
end
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp if argv.length > 0
|
||||
|
||||
plugins = Vagrant::Plugin::Manager.instance.installed_plugins
|
||||
|
||||
if !options[:reinstall] && !options[:force] && !plugins.empty?
|
||||
result = @env.ui.ask(
|
||||
I18n.t("vagrant.commands.plugin.expunge_request_reinstall") +
|
||||
" [Y/N]:"
|
||||
)
|
||||
options[:reinstall] = result.to_s.downcase.strip == "y"
|
||||
end
|
||||
|
||||
# Remove all installed user plugins
|
||||
action(Action.action_expunge, options)
|
||||
|
||||
if options[:reinstall]
|
||||
@env.ui.info(I18n.t("vagrant.commands.plugin.expunge_reinstall"))
|
||||
plugins.each do |plugin_name, plugin_info|
|
||||
next if plugin_info["system"] # system plugins do not require re-install
|
||||
# Rebuild information hash to use symbols
|
||||
plugin_info = Hash[
|
||||
plugin_info.map do |key, value|
|
||||
["plugin_#{key}".to_sym, value]
|
||||
end
|
||||
]
|
||||
action(
|
||||
Action.action_install,
|
||||
plugin_info.merge(
|
||||
plugin_name: plugin_name
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Success, exit status 0
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -13,15 +13,6 @@ module VagrantPlugins
|
|||
options[:entry_point] = entry_point
|
||||
end
|
||||
|
||||
# @deprecated
|
||||
o.on("--plugin-prerelease",
|
||||
"Allow prerelease versions of this plugin.") do |plugin_prerelease|
|
||||
puts "--plugin-prelease is deprecated and will be removed in the next"
|
||||
puts "version of Vagrant. It has no effect now. Use the '--plugin-version'"
|
||||
puts "flag to get a specific pre-release version."
|
||||
puts
|
||||
end
|
||||
|
||||
o.on("--plugin-clean-sources",
|
||||
"Remove all plugin sources defined so far (including defaults)") do |clean|
|
||||
options[:plugin_sources] = [] if clean
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
require 'optparse'
|
||||
|
||||
require_relative "base"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPlugin
|
||||
module Command
|
||||
class Repair < Base
|
||||
def execute
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant plugin repair [-h]"
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp if argv.length > 0
|
||||
|
||||
# Attempt to repair installed plugins
|
||||
action(Action.action_repair)
|
||||
|
||||
# Success, exit status 0
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,6 +14,11 @@ module VagrantPlugins
|
|||
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||
|
||||
@subcommands = Vagrant::Registry.new
|
||||
@subcommands.register(:expunge) do
|
||||
require_relative "expunge"
|
||||
Expunge
|
||||
end
|
||||
|
||||
@subcommands.register(:install) do
|
||||
require_relative "install"
|
||||
Install
|
||||
|
@ -29,6 +34,11 @@ module VagrantPlugins
|
|||
List
|
||||
end
|
||||
|
||||
@subcommands.register(:repair) do
|
||||
require_relative "repair"
|
||||
Repair
|
||||
end
|
||||
|
||||
@subcommands.register(:update) do
|
||||
require_relative "update"
|
||||
Update
|
||||
|
|
|
@ -540,7 +540,7 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
# Set the terminal
|
||||
ch2.send_data "export TERM=vt100\n"
|
||||
ch2.send_data generate_environment_export("TERM", "vt100")
|
||||
|
||||
# Set SSH_AUTH_SOCK if we are in sudo and forwarding agent.
|
||||
# This is to work around often misconfigured boxes where
|
||||
|
@ -563,7 +563,7 @@ module VagrantPlugins
|
|||
@logger.warn("No SSH_AUTH_SOCK found despite forward_agent being set.")
|
||||
else
|
||||
@logger.info("Setting SSH_AUTH_SOCK remotely: #{auth_socket}")
|
||||
ch2.send_data "export SSH_AUTH_SOCK=#{auth_socket}\n"
|
||||
ch2.send_data generate_environment_export("SSH_AUTH_SOCK", auth_socket)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -572,9 +572,9 @@ module VagrantPlugins
|
|||
# without the cruft added from pty mode.
|
||||
if pty
|
||||
data = "stty raw -echo\n"
|
||||
data += "export PS1=\n"
|
||||
data += "export PS2=\n"
|
||||
data += "export PROMPT_COMMAND=\n"
|
||||
data += generate_environment_export("PS1", "")
|
||||
data += generate_environment_export("PS2", "")
|
||||
data += generate_environment_export("PROMPT_COMMAND", "")
|
||||
data += "printf #{PTY_DELIM_START}\n"
|
||||
data += "#{command}\n"
|
||||
data += "exitcode=$?\n"
|
||||
|
@ -670,6 +670,11 @@ module VagrantPlugins
|
|||
source_path = Vagrant.source_root.join("keys", "vagrant")
|
||||
return File.read(path).chomp == source_path.read.chomp
|
||||
end
|
||||
|
||||
def generate_environment_export(env_key, env_value)
|
||||
template = @machine.config.ssh.export_command_template
|
||||
template.sub("%ENV_KEY%", env_key).sub("%ENV_VALUE%", env_value) + "\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -104,7 +104,7 @@ module VagrantPlugins
|
|||
@logger.info("Checking whether WinRM is ready...")
|
||||
|
||||
result = Timeout.timeout(@machine.config.winrm.timeout) do
|
||||
shell(true).powershell("hostname")
|
||||
shell(true).cmd("hostname")
|
||||
end
|
||||
|
||||
@logger.info("WinRM is ready!")
|
||||
|
|
|
@ -56,11 +56,15 @@ module VagrantPlugins
|
|||
def powershell(command, &block)
|
||||
# Ensure an exit code
|
||||
command += "\r\nif ($?) { exit 0 } else { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }"
|
||||
execute_with_rescue(executor.method("run_powershell_script"), command, &block)
|
||||
session.create_executor do |executor|
|
||||
execute_with_rescue(executor.method("run_powershell_script"), command, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def cmd(command, &block)
|
||||
execute_with_rescue(executor.method("run_cmd"), command, &block)
|
||||
session.create_executor do |executor|
|
||||
execute_with_rescue(executor.method("run_cmd"), command, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def wql(query, &block)
|
||||
|
@ -172,10 +176,6 @@ module VagrantPlugins
|
|||
@session ||= new_session
|
||||
end
|
||||
|
||||
def executor
|
||||
@executor ||= session.create_executor
|
||||
end
|
||||
|
||||
def endpoint
|
||||
case @config.transport.to_sym
|
||||
when :ssl
|
||||
|
|
|
@ -8,18 +8,16 @@ module VagrantPlugins
|
|||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, "")
|
||||
set -e
|
||||
# Remove comments and blank lines from /etc/hosts
|
||||
sed -i'' -e 's/#.*$//' -e '/^$/d' /etc/hosts
|
||||
|
||||
# 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 || {
|
||||
test $? -eq 0 && (grep -w '#{name}' /etc/hosts || {
|
||||
sed -i'' '1i 127.0.0.1\\t#{name}\\t#{basename}' /etc/hosts
|
||||
}
|
||||
})
|
||||
EOH
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,10 +12,9 @@ module VagrantPlugins
|
|||
|
||||
def self.configure_networks(machine, networks)
|
||||
comm = machine.communicate
|
||||
commands = []
|
||||
|
||||
commands = ["set -e"]
|
||||
interfaces = machine.guest.capability(:network_interfaces)
|
||||
|
||||
networks.each.with_index do |network, i|
|
||||
network[:device] = interfaces[network[:interface]]
|
||||
|
||||
|
@ -42,15 +41,15 @@ module VagrantPlugins
|
|||
|
||||
commands << <<-EOH.gsub(/^ {14}/, '')
|
||||
# Configure #{network[:device]}
|
||||
mv '#{remote_path}' '/etc/netctl/#{network[:device]}'
|
||||
ip link set '#{network[:device]}' down
|
||||
netctl restart '#{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"))
|
||||
comm.sudo(commands.join(" && \n"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,8 +15,7 @@ module VagrantPlugins
|
|||
# https://bbs.archlinux.org/viewtopic.php?id=193410
|
||||
#
|
||||
comm.sudo <<-EOH.gsub(/^ {12}/, "")
|
||||
set -e
|
||||
systemctl enable rpcbind
|
||||
systemctl enable rpcbind &&
|
||||
systemctl start rpcbind
|
||||
EOH
|
||||
end
|
||||
|
@ -24,8 +23,7 @@ module VagrantPlugins
|
|||
def self.nfs_client_install(machine)
|
||||
comm = machine.communicate
|
||||
comm.sudo <<-EOH.gsub(/^ {12}/, "")
|
||||
set -e
|
||||
pacman --noconfirm -Syy
|
||||
pacman --noconfirm -Syy &&
|
||||
pacman --noconfirm -S nfs-utils ntp
|
||||
EOH
|
||||
end
|
||||
|
|
|
@ -5,9 +5,9 @@ module VagrantPlugins
|
|||
def self.rsync_install(machine)
|
||||
comm = machine.communicate
|
||||
comm.sudo <<-EOH.gsub(/^ {12}/, '')
|
||||
set -e
|
||||
pacman -Sy --noconfirm
|
||||
pacman -S --noconfirm rsync
|
||||
exit $?
|
||||
EOH
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,18 +8,16 @@ module VagrantPlugins
|
|||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, "")
|
||||
set -e
|
||||
# Remove comments and blank lines from /etc/hosts
|
||||
sed -i'' -e 's/#.*$//' -e '/^$/d' /etc/hosts
|
||||
|
||||
# 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 || {
|
||||
test $? -eq 0 && (grep -w '#{name}' /etc/hosts || {
|
||||
sed -i'' '1i 127.0.0.1\\t#{name}\\t#{basename}' /etc/hosts
|
||||
}
|
||||
})
|
||||
EOH
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,10 +11,8 @@ module VagrantPlugins
|
|||
def self.mount_nfs_folder(machine, ip, folders)
|
||||
comm = machine.communicate
|
||||
|
||||
# Mount each folder separately so we can retry.
|
||||
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])
|
||||
|
@ -29,14 +27,14 @@ module VagrantPlugins
|
|||
mount_opts = mount_opts.join(",")
|
||||
|
||||
# Make the directory on the guest.
|
||||
commands << "mkdir -p #{guest_path}"
|
||||
machine.communicate.sudo("mkdir -p #{guest_path}")
|
||||
|
||||
# Perform the mount operation.
|
||||
commands << "/sbin/mount -t nfs -o '#{mount_opts}' #{ip}:#{host_path} #{guest_path}"
|
||||
command = "/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"),
|
||||
machine.communicate.sudo(command,
|
||||
error_class: Vagrant::Errors::NFSMountFailed,
|
||||
shell: "sh",
|
||||
)
|
||||
|
|
|
@ -22,14 +22,13 @@ module VagrantPlugins
|
|||
# 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
|
||||
|
||||
chmod 0700 ~/.ssh &&
|
||||
cat '#{remote_path}' >> ~/.ssh/authorized_keys &&
|
||||
chmod 0600 ~/.ssh/authorized_keys
|
||||
result=$?
|
||||
rm -f '#{remote_path}'
|
||||
exit $result
|
||||
EOH
|
||||
end
|
||||
|
||||
|
@ -49,15 +48,16 @@ module VagrantPlugins
|
|||
# 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
|
||||
|
||||
result=0
|
||||
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
|
||||
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
|
||||
result=$?
|
||||
fi
|
||||
|
||||
rm -f '#{remote_path}'
|
||||
exit $result
|
||||
EOH
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,16 +8,17 @@ module VagrantPlugins
|
|||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, '')
|
||||
set -e
|
||||
|
||||
# LocalHostName should not contain dots - it is used by Bonjour and
|
||||
# visible through file sharing services.
|
||||
comm.sudo <<-EOH.gsub(/^ */, '')
|
||||
# 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}'
|
||||
scutil --set ComputerName '#{name}' &&
|
||||
scutil --set HostName '#{name}' &&
|
||||
scutil --set LocalHostName '#{basename}'
|
||||
result=$?
|
||||
if [ $result -ne 0 ]; then
|
||||
exit $result
|
||||
fi
|
||||
|
||||
hostname '#{name}'
|
||||
|
||||
|
@ -27,8 +28,8 @@ module VagrantPlugins
|
|||
|
||||
# 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
|
||||
echo -e '127.0.0.1\\t#{name}\\t#{basename}' | cat - /etc/hosts > /tmp/tmp-hosts &&
|
||||
mv /tmp/tmp-hosts /etc/hosts
|
||||
}
|
||||
EOH
|
||||
end
|
||||
|
|
|
@ -8,9 +8,6 @@ module VagrantPlugins
|
|||
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
|
||||
|
||||
# Set the hostname
|
||||
echo '#{basename}' > /etc/hostname
|
||||
hostname -F /etc/hostname
|
||||
|
|
|
@ -11,7 +11,7 @@ module VagrantPlugins
|
|||
def self.configure_networks(machine, networks)
|
||||
comm = machine.communicate
|
||||
|
||||
commands = ["set -e"]
|
||||
commands = []
|
||||
entries = []
|
||||
interfaces = machine.guest.capability(:network_interfaces)
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ module VagrantPlugins
|
|||
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
|
||||
exit $?
|
||||
EOH
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,6 @@ module VagrantPlugins
|
|||
def self.rsync_install(machine)
|
||||
comm = machine.communicate
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, '')
|
||||
set -e
|
||||
apt-get -yqq update
|
||||
apt-get -yqq install rsync
|
||||
EOH
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
require "vagrant"
|
||||
require_relative '../linux/guest'
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestDebian
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /etc/issue | grep 'Debian'")
|
||||
end
|
||||
class Guest < VagrantPlugins::GuestLinux::Guest
|
||||
# Name used for guest detection
|
||||
GUEST_DETECTION_NAME = "debian".freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,8 +8,6 @@ module VagrantPlugins
|
|||
if !comm.test("hostname -f | grep '^#{name}$'", sudo: false)
|
||||
basename = name.split(".", 2)[0]
|
||||
comm.sudo <<-EOH.gsub(/^ {14}/, "")
|
||||
set -e
|
||||
|
||||
# Set the hostname
|
||||
hostname '#{basename}'
|
||||
echo "hostname=#{basename}" > /etc/conf.d/hostname
|
||||
|
@ -20,8 +18,8 @@ module VagrantPlugins
|
|||
|
||||
# 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
|
||||
echo -e '127.0.0.1\\t#{name}\\t#{basename}' | cat - /etc/hosts > /tmp/tmp-hosts &&
|
||||
mv /tmp/tmp-hosts /etc/hosts
|
||||
}
|
||||
EOH
|
||||
end
|
||||
|
|
|
@ -94,7 +94,7 @@ SCRIPT
|
|||
|
||||
# Emit an upstart event if we can
|
||||
machine.communicate.sudo <<-SCRIPT
|
||||
if command -v /sbin/init && /sbin/init --version | grep upstart; then
|
||||
if command -v /sbin/init && /sbin/init 2>/dev/null --version | grep upstart; then
|
||||
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT='#{expanded_guest_path}'
|
||||
fi
|
||||
SCRIPT
|
||||
|
|
|
@ -89,7 +89,7 @@ module VagrantPlugins
|
|||
|
||||
# Emit an upstart event if we can
|
||||
machine.communicate.sudo <<-EOH.gsub(/^ {12}/, "")
|
||||
if command -v /sbin/init && /sbin/init --version | grep upstart; then
|
||||
if command -v /sbin/init && /sbin/init 2>/dev/null --version | grep upstart; then
|
||||
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guest_path}
|
||||
fi
|
||||
EOH
|
||||
|
|
|
@ -2,6 +2,11 @@ module VagrantPlugins
|
|||
module GuestLinux
|
||||
module Cap
|
||||
class NetworkInterfaces
|
||||
# Valid ethernet device prefix values.
|
||||
# eth - classic prefix
|
||||
# en - predictable interface names prefix
|
||||
POSSIBLE_ETHERNET_PREFIXES = ["eth".freeze, "en".freeze].freeze
|
||||
|
||||
@@logger = Log4r::Logger.new("vagrant::guest::linux::network_interfaces")
|
||||
|
||||
# Get network interfaces as a list. The result will be something like:
|
||||
|
@ -18,6 +23,9 @@ module VagrantPlugins
|
|||
@@logger.debug("Unsorted list: #{ifaces.inspect}")
|
||||
# Break out integers from strings and sort the arrays to provide
|
||||
# a natural sort for the interface names
|
||||
# NOTE: Devices named with a hex value suffix will _not_ be sorted
|
||||
# as expected. This is generally seen with veth* devices, and proper ordering
|
||||
# is currently not required
|
||||
ifaces = ifaces.map do |iface|
|
||||
iface.scan(/(.+?)(\d+)/).flatten.map do |iface_part|
|
||||
if iface_part.to_i.to_s == iface_part
|
||||
|
@ -26,8 +34,32 @@ module VagrantPlugins
|
|||
iface_part
|
||||
end
|
||||
end
|
||||
end.sort.map(&:join)
|
||||
end
|
||||
ifaces = ifaces.sort do |lhs, rhs|
|
||||
result = 0
|
||||
slice_length = [rhs.size, lhs.size].min
|
||||
slice_length.times do |idx|
|
||||
if(lhs[idx].is_a?(rhs[idx].class))
|
||||
result = lhs[idx] <=> rhs[idx]
|
||||
elsif(lhs[idx].is_a?(String))
|
||||
result = 1
|
||||
else
|
||||
result = -1
|
||||
end
|
||||
break if result != 0
|
||||
end
|
||||
result
|
||||
end.map(&:join)
|
||||
@@logger.debug("Sorted list: #{ifaces.inspect}")
|
||||
# Extract ethernet devices and place at start of list
|
||||
resorted_ifaces = []
|
||||
resorted_ifaces += ifaces.find_all do |iface|
|
||||
POSSIBLE_ETHERNET_PREFIXES.any?{|prefix| iface.start_with?(prefix)} &&
|
||||
iface.match(/^[a-zA-Z0-9]+$/)
|
||||
end
|
||||
resorted_ifaces += ifaces - resorted_ifaces
|
||||
ifaces = resorted_ifaces
|
||||
@@logger.debug("Ethernet preferred sorted list: #{ifaces.inspect}")
|
||||
ifaces
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,10 +13,8 @@ module VagrantPlugins
|
|||
def self.mount_nfs_folder(machine, ip, folders)
|
||||
comm = machine.communicate
|
||||
|
||||
# Mount each folder separately so we can retry.
|
||||
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])
|
||||
|
@ -30,22 +28,24 @@ module VagrantPlugins
|
|||
end
|
||||
mount_opts = mount_opts.join(",")
|
||||
|
||||
# Make the directory on the guest.
|
||||
commands << "mkdir -p #{guest_path}"
|
||||
machine.communicate.sudo("mkdir -p #{guest_path}")
|
||||
|
||||
# Perform the mount operation.
|
||||
commands << "mount -o #{mount_opts} #{ip}:#{host_path} #{guest_path}"
|
||||
|
||||
# Emit a mount event
|
||||
commands << <<-EOH.gsub(/^ {14}/, '')
|
||||
if command -v /sbin/init && /sbin/init --version | grep upstart; then
|
||||
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guest_path}
|
||||
# Perform the mount operation and emit mount event if applicable
|
||||
command = <<-EOH.gsub(/^ */, '')
|
||||
mount -o #{mount_opts} #{ip}:#{host_path} #{guest_path}
|
||||
result=$?
|
||||
if test $result -eq 0; then
|
||||
if test -x /sbin/initctl && command -v /sbin/init && /sbin/init 2>/dev/null --version | grep upstart; then
|
||||
/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guest_path}
|
||||
fi
|
||||
else
|
||||
exit $result
|
||||
fi
|
||||
EOH
|
||||
|
||||
# Run the command, raising a specific error.
|
||||
retryable(on: Vagrant::Errors::NFSMountFailed, tries: 3, sleep: 5) do
|
||||
machine.communicate.sudo(commands.join("\n"),
|
||||
machine.communicate.sudo(command,
|
||||
error_class: Vagrant::Errors::NFSMountFailed,
|
||||
)
|
||||
end
|
||||
|
|
|
@ -21,15 +21,13 @@ module VagrantPlugins
|
|||
|
||||
# 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
|
||||
|
||||
comm.execute <<-EOH.gsub(/^ */, "")
|
||||
mkdir -p ~/.ssh
|
||||
chmod 0700 ~/.ssh
|
||||
cat '#{remote_path}' >> ~/.ssh/authorized_keys
|
||||
chmod 0600 ~/.ssh/authorized_keys
|
||||
|
||||
cat '#{remote_path}' >> ~/.ssh/authorized_keys && chmod 0600 ~/.ssh/authorized_keys
|
||||
result=$?
|
||||
rm -f '#{remote_path}'
|
||||
exit $result
|
||||
EOH
|
||||
end
|
||||
|
||||
|
@ -48,16 +46,14 @@ module VagrantPlugins
|
|||
|
||||
# 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
|
||||
|
||||
comm.execute <<-EOH.sub(/^ */, "")
|
||||
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
|
||||
mv ~/.ssh/authorized_keys.tmp ~/.ssh/authorized_keys && chmod 0600 ~/.ssh/authorized_keys
|
||||
result=$?
|
||||
fi
|
||||
|
||||
rm -f '#{remote_path}'
|
||||
exit $result
|
||||
EOH
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,22 @@
|
|||
module VagrantPlugins
|
||||
module GuestLinux
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
# Name used for guest detection
|
||||
GUEST_DETECTION_NAME = "linux".freeze
|
||||
|
||||
def detect?(machine)
|
||||
machine.communicate.test("uname -s | grep 'Linux'")
|
||||
machine.communicate.test <<-EOH.gsub(/^ */, '')
|
||||
if test -r /etc/os-release; then
|
||||
source /etc/os-release && test x#{self.class.const_get(:GUEST_DETECTION_NAME)} = x$ID && exit
|
||||
fi
|
||||
if test -x /usr/bin/lsb_release; then
|
||||
/usr/bin/lsb_release -i 2>/dev/null | grep -qi #{self.class.const_get(:GUEST_DETECTION_NAME)} && exit
|
||||
fi
|
||||
if test -r /etc/issue; then
|
||||
cat /etc/issue | grep -qi #{self.class.const_get(:GUEST_DETECTION_NAME)} && exit
|
||||
fi
|
||||
exit 1
|
||||
EOH
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
require_relative '../linux/guest'
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestMint
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /etc/issue | grep 'Linux Mint'")
|
||||
end
|
||||
class Guest < VagrantPlugins::GuestLinux::Guest
|
||||
# Name used for guest detection
|
||||
GUEST_DETECTION_NAME = "Linux Mint".freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,9 +5,8 @@ module VagrantPlugins
|
|||
def self.change_host_name(machine, name)
|
||||
if !machine.communicate.test("hostname -s | grep '^#{name}$'")
|
||||
machine.communicate.sudo(<<CMDS, {shell: "sh"})
|
||||
set -e
|
||||
sed -e 's/^hostname=.*$/hostname=#{name}/' /etc/rc.conf > /tmp/rc.conf.vagrant_changehostname_#{name}
|
||||
mv /tmp/rc.conf.vagrant_changehostname_#{name} /etc/rc.conf
|
||||
sed -e 's/^hostname=.*$/hostname=#{name}/' /etc/rc.conf > /tmp/rc.conf.vagrant_changehostname_#{name} &&
|
||||
mv /tmp/rc.conf.vagrant_changehostname_#{name} /etc/rc.conf &&
|
||||
hostname #{name}
|
||||
CMDS
|
||||
end
|
||||
|
|
|
@ -8,9 +8,11 @@ module VagrantPlugins
|
|||
|
||||
def self.rsync_install(machine)
|
||||
machine.communicate.sudo(
|
||||
'PKG_PATH="http://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/' \
|
||||
'`uname -m`/`uname -r | cut -d. -f1-2`/All" ' \
|
||||
'pkg_add rsync')
|
||||
'PATH=$PATH:/usr/sbin '\
|
||||
'PKG_PATH="http://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/' \
|
||||
'`uname -m`/`uname -r | cut -d. -f1-2`/All" ' \
|
||||
'pkg_add rsync'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,10 +7,21 @@ module VagrantPlugins
|
|||
extend VagrantPlugins::SyncedFolderRSync::DefaultUnixCap
|
||||
|
||||
def self.rsync_install(machine)
|
||||
machine.communicate.sudo(
|
||||
'PKG_PATH="http://ftp.openbsd.org/pub/OpenBSD/' \
|
||||
install_output = {:stderr => '', :stdout => ''}
|
||||
command = 'PKG_PATH="http://ftp.openbsd.org/pub/OpenBSD/' \
|
||||
'`uname -r`/packages/`arch -s`/" ' \
|
||||
'pkg_add -I rsync--')
|
||||
'pkg_add -I rsync--'
|
||||
machine.communicate.sudo(command) do |type, data|
|
||||
install_output[type] << data if install_output.key?(type)
|
||||
end
|
||||
# pkg_add returns 0 even if package was not found, so
|
||||
# validate package is actually installed
|
||||
machine.communicate.sudo('pkg_info -cA | grep inst:rsync-[[:digit:]]',
|
||||
error_class: Vagrant::Errors::RSyncNotInstalledInGuest,
|
||||
command: command,
|
||||
stderr: install_output[:stderr],
|
||||
stdout: install_output[:stdout]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ module VagrantPlugins
|
|||
device = interfaces[network[:interface]]
|
||||
command = "ifconfig #{device}"
|
||||
command << " #{network[:ip]}" if network[:ip]
|
||||
command << " netmast #{network[:netmask]}" if network[:netmask]
|
||||
command << " netmask #{network[:netmask]}" if network[:netmask]
|
||||
commands << command
|
||||
end
|
||||
|
||||
|
|
|
@ -31,8 +31,12 @@ module VagrantPlugins
|
|||
sed -i'' '1i 127.0.0.1\\t#{name}\\t#{basename}' /etc/hosts
|
||||
}
|
||||
|
||||
# Restart network
|
||||
service network restart
|
||||
# Restart network (through NetworkManager if running)
|
||||
if service NetworkManager status 2>&1 | grep -q running; then
|
||||
service NetworkManager restart
|
||||
else
|
||||
service network restart
|
||||
fi
|
||||
EOH
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,16 +40,23 @@ module VagrantPlugins
|
|||
# Down the interface before munging the config file. This might
|
||||
# fail if the interface is not actually set up yet so ignore
|
||||
# errors.
|
||||
/sbin/ifdown '#{network[:device]}' || true
|
||||
|
||||
/sbin/ifdown '#{network[:device]}'
|
||||
# Move new config into place
|
||||
mv '#{remote_path}' '#{final_path}'
|
||||
|
||||
# Bring the interface up
|
||||
ARPCHECK=no /sbin/ifup '#{network[:device]}'
|
||||
mv -f '#{remote_path}' '#{final_path}'
|
||||
# attempt to force network manager to reload configurations
|
||||
nmcli c reload || true
|
||||
EOH
|
||||
end
|
||||
|
||||
commands << <<-EOH.gsub(/^ {12}/, '')
|
||||
# Restart network (through NetworkManager if running)
|
||||
if service NetworkManager status 2>&1 | grep -q running; then
|
||||
service NetworkManager restart
|
||||
else
|
||||
service network restart
|
||||
fi
|
||||
EOH
|
||||
|
||||
comm.sudo(commands.join("\n"))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
# Detect various flavors we care about
|
||||
if output =~ /(CentOS|Red Hat Enterprise|Scientific|Cloud)\s*Linux( .+)? release 7/i
|
||||
if output =~ /(CentOS|Red Hat Enterprise|Scientific|Cloud|Virtuozzo)\s*Linux( .+)? release 7/i
|
||||
return :rhel_7
|
||||
else
|
||||
return :rhel
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
require "vagrant"
|
||||
require_relative '../linux/guest'
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestTinyCore
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
machine.communicate.test("cat /etc/issue | grep 'Core Linux'")
|
||||
end
|
||||
class Guest < VagrantPlugins::GuestLinux::Guest
|
||||
# Name used for guest detection
|
||||
GUEST_DETECTION_NAME = "Core Linux".freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,24 +1,10 @@
|
|||
require_relative '../linux/guest'
|
||||
|
||||
module VagrantPlugins
|
||||
module GuestUbuntu
|
||||
class Guest < Vagrant.plugin("2", :guest)
|
||||
def detect?(machine)
|
||||
# This command detects if we are running on Ubuntu. /etc/os-release is
|
||||
# available on modern Ubuntu versions, but does not exist on 14.04 and
|
||||
# previous versions, so we fall back to lsb_release.
|
||||
#
|
||||
# GH-7524
|
||||
# GH-7625
|
||||
#
|
||||
machine.communicate.test <<-EOH.gsub(/^ {10}/, "")
|
||||
if test -r /etc/os-release; then
|
||||
source /etc/os-release && test xubuntu = x$ID
|
||||
elif test -x /usr/bin/lsb_release; then
|
||||
/usr/bin/lsb_release -i 2>/dev/null | grep -q Ubuntu
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
EOH
|
||||
end
|
||||
class Guest < VagrantPlugins::GuestLinux::Guest
|
||||
# Name used for guest detection
|
||||
GUEST_DETECTION_NAME = "ubuntu".freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,8 @@ module VagrantPlugins
|
|||
module HostLinux
|
||||
module Cap
|
||||
class NFS
|
||||
|
||||
NFS_EXPORTS_PATH = "/etc/exports".freeze
|
||||
extend Vagrant::Util::Retryable
|
||||
|
||||
def self.nfs_apply_command(env)
|
||||
|
@ -36,16 +38,9 @@ module VagrantPlugins
|
|||
ui.info I18n.t("vagrant.hosts.linux.nfs_export")
|
||||
sleep 0.5
|
||||
|
||||
nfs_cleanup(id)
|
||||
|
||||
# Only use "sudo" if we can't write to /etc/exports directly
|
||||
sudo_command = ""
|
||||
sudo_command = "sudo " if !File.writable?("/etc/exports")
|
||||
|
||||
output.split("\n").each do |line|
|
||||
line = Vagrant::Util::ShellQuote.escape(line, "'")
|
||||
system(%Q[echo '#{line}' | #{sudo_command}tee -a /etc/exports >/dev/null])
|
||||
end
|
||||
nfs_cleanup("#{Process.uid} #{id}")
|
||||
output = "#{nfs_exports_content}\n#{output}"
|
||||
nfs_write_exports(output)
|
||||
|
||||
if nfs_running?(nfs_check_command)
|
||||
system("sudo #{nfs_apply_command}")
|
||||
|
@ -62,48 +57,111 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def self.nfs_prune(environment, ui, valid_ids)
|
||||
return if !File.exist?("/etc/exports")
|
||||
return if !File.exist?(NFS_EXPORTS_PATH)
|
||||
|
||||
logger = Log4r::Logger.new("vagrant::hosts::linux")
|
||||
logger.info("Pruning invalid NFS entries...")
|
||||
|
||||
output = false
|
||||
user = Process.uid
|
||||
|
||||
File.read("/etc/exports").lines.each do |line|
|
||||
if id = line[/^# VAGRANT-BEGIN:( #{user})? ([\.\/A-Za-z0-9\-_:]+?)$/, 2]
|
||||
if valid_ids.include?(id)
|
||||
logger.debug("Valid ID: #{id}")
|
||||
else
|
||||
if !output
|
||||
# We want to warn the user but we only want to output once
|
||||
ui.info I18n.t("vagrant.hosts.linux.nfs_prune")
|
||||
output = true
|
||||
end
|
||||
# Create editor instance for removing invalid IDs
|
||||
editor = Vagrant::Util::StringBlockEditor.new(nfs_exports_content)
|
||||
|
||||
logger.info("Invalid ID, pruning: #{id}")
|
||||
nfs_cleanup(id)
|
||||
end
|
||||
end
|
||||
# Build composite IDs with UID information and discover invalid entries
|
||||
composite_ids = valid_ids.map do |v_id|
|
||||
"#{user} #{v_id}"
|
||||
end
|
||||
remove_ids = editor.keys - composite_ids
|
||||
|
||||
logger.debug("Known valid NFS export IDs: #{valid_ids}")
|
||||
logger.debug("Composite valid NFS export IDs with user: #{composite_ids}")
|
||||
logger.debug("NFS export IDs to be removed: #{remove_ids}")
|
||||
if !remove_ids.empty?
|
||||
ui.info I18n.t("vagrant.hosts.linux.nfs_prune")
|
||||
nfs_cleanup(remove_ids)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.nfs_cleanup(id)
|
||||
return if !File.exist?("/etc/exports")
|
||||
def self.nfs_cleanup(remove_ids)
|
||||
return if !File.exist?(NFS_EXPORTS_PATH)
|
||||
|
||||
user = Regexp.escape(Process.uid.to_s)
|
||||
id = Regexp.escape(id.to_s)
|
||||
editor = Vagrant::Util::StringBlockEditor.new(nfs_exports_content)
|
||||
remove_ids = Array(remove_ids)
|
||||
|
||||
# Only use "sudo" if we can't write to /etc/exports directly
|
||||
sudo_command = ""
|
||||
sudo_command = "sudo " if !File.writable?("/etc/exports")
|
||||
# Remove all invalid ID entries
|
||||
remove_ids.each do |r_id|
|
||||
editor.delete(r_id)
|
||||
end
|
||||
nfs_write_exports(editor.value)
|
||||
end
|
||||
|
||||
# Use sed to just strip out the block of code which was inserted
|
||||
# by Vagrant
|
||||
tmp = ENV["TMPDIR"] || ENV["TMP"] || "/tmp"
|
||||
system("cp /etc/exports '#{tmp}' && #{sudo_command}sed -r -e '\\\x01^# VAGRANT-BEGIN:( #{user})? #{id}\x01,\\\x01^# VAGRANT-END:( #{user})? #{id}\x01 d' -ibak '#{tmp}/exports' ; #{sudo_command}cp '#{tmp}/exports' /etc/exports")
|
||||
def self.nfs_write_exports(new_exports_content)
|
||||
if(nfs_exports_content != new_exports_content.strip)
|
||||
begin
|
||||
# Write contents out to temporary file
|
||||
new_exports_file = Tempfile.create('vagrant')
|
||||
new_exports_file.puts(new_exports_content)
|
||||
new_exports_file.close
|
||||
new_exports_path = new_exports_file.path
|
||||
|
||||
# Only use "sudo" if we can't write to /etc/exports directly
|
||||
sudo_command = ""
|
||||
sudo_command = "sudo " if !File.writable?(NFS_EXPORTS_PATH)
|
||||
|
||||
# Ensure new file mode and uid/gid match existing file to replace
|
||||
existing_stat = File.stat(NFS_EXPORTS_PATH)
|
||||
new_stat = File.stat(new_exports_path)
|
||||
if existing_stat.mode != new_stat.mode
|
||||
File.chmod(existing_stat.mode, new_exports_path)
|
||||
end
|
||||
if existing_stat.uid != new_stat.uid || existing_stat.gid != new_stat.gid
|
||||
chown_cmd = "#{sudo_command}chown #{existing_stat.uid}:#{existing_stat.gid} #{new_exports_path}"
|
||||
result = Vagrant::Util::Subprocess.execute(*Shellwords.split(chown_cmd))
|
||||
if result.exit_code != 0
|
||||
raise Vagrant::Errors::NFSExportsFailed,
|
||||
command: chown_cmd,
|
||||
stderr: result.stderr,
|
||||
stdout: result.stdout
|
||||
end
|
||||
end
|
||||
# Always force move the file to prevent overwrite prompting
|
||||
mv_cmd = "#{sudo_command}mv -f #{new_exports_path} #{NFS_EXPORTS_PATH}"
|
||||
result = Vagrant::Util::Subprocess.execute(*Shellwords.split(mv_cmd))
|
||||
if result.exit_code != 0
|
||||
raise Vagrant::Errors::NFSExportsFailed,
|
||||
command: mv_cmd,
|
||||
stderr: result.stderr,
|
||||
stdout: result.stdout
|
||||
end
|
||||
ensure
|
||||
if File.exist?(new_exports_path)
|
||||
File.unlink(new_exports_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.nfs_exports_content
|
||||
if(File.exist?(NFS_EXPORTS_PATH))
|
||||
if(File.readable?(NFS_EXPORTS_PATH))
|
||||
File.read(NFS_EXPORTS_PATH)
|
||||
else
|
||||
cmd = "sudo cat #{NFS_EXPORTS_PATH}"
|
||||
result = Vagrant::Util::Subprocess.execute(*Shellwords.split(cmd))
|
||||
if result.exit_code != 0
|
||||
raise Vagrant::Errors::NFSExportsFailed,
|
||||
command: cmd,
|
||||
stderr: result.stderr,
|
||||
stdout: result.stdout
|
||||
else
|
||||
result.stdout
|
||||
end
|
||||
end
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def self.nfs_opts_setup(folders)
|
||||
|
|
|
@ -15,24 +15,25 @@ module VagrantPlugins
|
|||
attr_accessor :ssh_command
|
||||
attr_accessor :pty
|
||||
attr_accessor :sudo_command
|
||||
attr_accessor :export_command_template
|
||||
|
||||
attr_reader :default
|
||||
|
||||
def initialize
|
||||
super
|
||||
|
||||
@forward_agent = UNSET_VALUE
|
||||
@forward_x11 = UNSET_VALUE
|
||||
@forward_env = UNSET_VALUE
|
||||
@guest_port = UNSET_VALUE
|
||||
@keep_alive = UNSET_VALUE
|
||||
@proxy_command = UNSET_VALUE
|
||||
@ssh_command = UNSET_VALUE
|
||||
@pty = UNSET_VALUE
|
||||
@shell = UNSET_VALUE
|
||||
@sudo_command = UNSET_VALUE
|
||||
|
||||
@default = SSHConnectConfig.new
|
||||
@forward_agent = UNSET_VALUE
|
||||
@forward_x11 = UNSET_VALUE
|
||||
@forward_env = UNSET_VALUE
|
||||
@guest_port = UNSET_VALUE
|
||||
@keep_alive = UNSET_VALUE
|
||||
@proxy_command = UNSET_VALUE
|
||||
@ssh_command = UNSET_VALUE
|
||||
@pty = UNSET_VALUE
|
||||
@shell = UNSET_VALUE
|
||||
@sudo_command = UNSET_VALUE
|
||||
@export_command_template = UNSET_VALUE
|
||||
@default = SSHConnectConfig.new
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
|
@ -55,6 +56,10 @@ module VagrantPlugins
|
|||
@pty = false if @pty == UNSET_VALUE
|
||||
@shell = "bash -l" if @shell == UNSET_VALUE
|
||||
|
||||
if @export_command_template == UNSET_VALUE
|
||||
@export_command_template = 'export %ENV_KEY%="%ENV_VALUE%"'
|
||||
end
|
||||
|
||||
if @sudo_command == UNSET_VALUE
|
||||
@sudo_command = "sudo -E -H %c"
|
||||
end
|
||||
|
|
|
@ -207,7 +207,19 @@ module VagrantPlugins
|
|||
hostpath = hostpath.to_s.gsub("\\", "/")
|
||||
end
|
||||
|
||||
if guestpath.is_a?(Hash)
|
||||
options = guestpath
|
||||
guestpath = nil
|
||||
end
|
||||
|
||||
options ||= {}
|
||||
|
||||
if options.has_key?(:name)
|
||||
synced_folder_name = options.delete(:name)
|
||||
else
|
||||
synced_folder_name = guestpath
|
||||
end
|
||||
|
||||
options[:guestpath] = guestpath.to_s.gsub(/\/$/, '')
|
||||
options[:hostpath] = hostpath
|
||||
options[:disabled] = false if !options.key?(:disabled)
|
||||
|
@ -217,7 +229,7 @@ module VagrantPlugins
|
|||
# Make sure the type is a symbol
|
||||
options[:type] = options[:type].to_sym if options[:type]
|
||||
|
||||
@__synced_folders[options[:guestpath]] = options
|
||||
@__synced_folders[synced_folder_name] = options
|
||||
end
|
||||
|
||||
# Define a way to access the machine via a network. This exposes a
|
||||
|
@ -581,7 +593,7 @@ module VagrantPlugins
|
|||
@hostname && @hostname !~ /^[a-z0-9][-.a-z0-9]*$/i
|
||||
|
||||
if @box_version
|
||||
@box_version.split(",").each do |v|
|
||||
@box_version.to_s.split(",").each do |v|
|
||||
begin
|
||||
Gem::Requirement.new(v.strip)
|
||||
rescue Gem::Requirement::BadRequirementError
|
||||
|
@ -626,7 +638,7 @@ module VagrantPlugins
|
|||
# If the shared folder is disabled then don't worry about validating it
|
||||
next if options[:disabled]
|
||||
|
||||
guestpath = Pathname.new(options[:guestpath])
|
||||
guestpath = Pathname.new(options[:guestpath]) if options[:guestpath]
|
||||
hostpath = Pathname.new(options[:hostpath]).expand_path(machine.env.root_path)
|
||||
|
||||
if guestpath.to_s != ""
|
||||
|
|
|
@ -48,7 +48,7 @@ module VagrantPlugins
|
|||
run_cmd += volumes.map { |v| ['-v', v.to_s] }
|
||||
run_cmd += %W(--privileged) if params[:privileged]
|
||||
run_cmd += %W(-h #{params[:hostname]}) if params[:hostname]
|
||||
run_cmd << "-i" << "-t" if params[:pty]
|
||||
run_cmd << "-t" if params[:pty]
|
||||
run_cmd << "--rm=true" if params[:rm]
|
||||
run_cmd += params[:extra_args] if params[:extra_args]
|
||||
run_cmd += [image, cmd]
|
||||
|
|
|
@ -7,7 +7,7 @@ module VagrantPlugins
|
|||
module Action
|
||||
class Import
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::hyperv::import")
|
||||
end
|
||||
|
||||
|
@ -35,13 +35,28 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
config_path = nil
|
||||
config_type = nil
|
||||
vm_dir.each_child do |f|
|
||||
if f.extname.downcase == ".xml"
|
||||
if f.extname.downcase == '.xml'
|
||||
config_path = f
|
||||
config_type = 'xml'
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
# Only check for .vmcx if there is no XML found to not
|
||||
# risk breaking older vagrant boxes that added an XML
|
||||
# file manually
|
||||
if config_type == nil
|
||||
vm_dir.each_child do |f|
|
||||
if f.extname.downcase == '.vmcx'
|
||||
config_path = f
|
||||
config_type = 'vmcx'
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
image_path = nil
|
||||
image_ext = nil
|
||||
image_filename = nil
|
||||
|
@ -49,7 +64,7 @@ module VagrantPlugins
|
|||
if %w{.vhd .vhdx}.include?(f.extname.downcase)
|
||||
image_path = f
|
||||
image_ext = f.extname.downcase
|
||||
image_filename = File.basename(f,image_ext)
|
||||
image_filename = File.basename(f, image_ext)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -100,19 +115,27 @@ module VagrantPlugins
|
|||
|
||||
env[:ui].detail("Cloning virtual hard drive...")
|
||||
source_path = image_path.to_s
|
||||
dest_path = env[:machine].data_dir.join("#{image_filename}#{image_ext}").to_s
|
||||
if differencing_disk
|
||||
env[:machine].provider.driver.execute("clone_vhd.ps1", {Source: source_path, Destination: dest_path})
|
||||
else
|
||||
FileUtils.cp(source_path, dest_path)
|
||||
dest_path = env[:machine].data_dir.join("Virtual Hard Disks").join("#{image_filename}#{image_ext}").to_s
|
||||
|
||||
# Still hard copy the disk of old XML configurations
|
||||
if config_type == 'xml'
|
||||
if differencing_disk
|
||||
env[:machine].provider.driver.execute("clone_vhd.ps1", {Source: source_path, Destination: dest_path})
|
||||
else
|
||||
FileUtils.mkdir_p(env[:machine].data_dir.join("Virtual Hard Disks"))
|
||||
FileUtils.cp(source_path, dest_path)
|
||||
end
|
||||
end
|
||||
image_path = dest_path
|
||||
|
||||
# We have to normalize the paths to be Windows paths since
|
||||
# we're executing PowerShell.
|
||||
options = {
|
||||
vm_xml_config: config_path.to_s.gsub("/", "\\"),
|
||||
image_path: image_path.to_s.gsub("/", "\\")
|
||||
vm_config_file: config_path.to_s.gsub("/", "\\"),
|
||||
vm_config_type: config_type,
|
||||
source_path: source_path.to_s,
|
||||
dest_path: dest_path,
|
||||
data_path: env[:machine].data_dir.to_s.gsub("/", "\\")
|
||||
}
|
||||
options[:switchname] = switch if switch
|
||||
options[:memory] = memory if memory
|
||||
|
@ -121,6 +144,7 @@ module VagrantPlugins
|
|||
options[:vmname] = vmname if vmname
|
||||
options[:auto_start_action] = auto_start_action if auto_start_action
|
||||
options[:auto_stop_action] = auto_stop_action if auto_stop_action
|
||||
options[:differencing_disk] = differencing_disk if differencing_disk
|
||||
|
||||
env[:ui].detail("Creating and registering the VM...")
|
||||
server = env[:machine].provider.driver.import(options)
|
||||
|
|
|
@ -74,7 +74,15 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def import(options)
|
||||
execute('import_vm.ps1', options)
|
||||
config_type = options.delete(:vm_config_type)
|
||||
if config_type === "vmcx"
|
||||
execute('import_vm_vmcx.ps1', options)
|
||||
else
|
||||
options.delete(:data_path)
|
||||
options.delete(:source_path)
|
||||
options.delete(:differencing_disk)
|
||||
execute('import_vm_xml.ps1', options)
|
||||
end
|
||||
end
|
||||
|
||||
def net_set_vlan(vlan_id)
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
Param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$vm_config_file,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$source_path,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$dest_path,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$data_path,
|
||||
|
||||
[string]$switchname=$null,
|
||||
[string]$memory=$null,
|
||||
[string]$maxmemory=$null,
|
||||
[string]$cpus=$null,
|
||||
[string]$vmname=$null,
|
||||
[string]$auto_start_action=$null,
|
||||
[string]$auto_stop_action=$null,
|
||||
[string]$differencing_disk=$null
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
|
||||
$VmProperties = @{
|
||||
Path = $vm_config_file
|
||||
SnapshotFilePath = Join-Path $data_path 'Snapshots'
|
||||
VhdDestinationPath = Join-Path $data_path 'Virtual Hard Disks'
|
||||
VirtualMachinePath = $data_path
|
||||
}
|
||||
|
||||
$vmConfig = (Compare-VM -Copy -GenerateNewID @VmProperties)
|
||||
|
||||
$generation = $vmConfig.VM.Generation
|
||||
|
||||
if (!$vmname) {
|
||||
# Get the name of the vm
|
||||
$vm_name = $vmconfig.VM.VMName
|
||||
} else {
|
||||
$vm_name = $vmname
|
||||
}
|
||||
|
||||
if (!$cpus) {
|
||||
# Get the processorcount of the VM
|
||||
$processors = (Get-VMProcessor -VM $vmConfig.VM).Count
|
||||
}else {
|
||||
$processors = $cpus
|
||||
}
|
||||
|
||||
function GetUniqueName($name) {
|
||||
Get-VM | ForEach-Object -Process {
|
||||
if ($name -eq $_.Name) {
|
||||
$name = $name + "_1"
|
||||
}
|
||||
}
|
||||
return $name
|
||||
}
|
||||
|
||||
do {
|
||||
$name = $vm_name
|
||||
$vm_name = GetUniqueName $name
|
||||
} while ($vm_name -ne $name)
|
||||
|
||||
if (!$memory) {
|
||||
$configMemory = Get-VMMemory -VM $vmConfig.VM
|
||||
$dynamicmemory = $configMemory.DynamicMemoryEnabled
|
||||
|
||||
$MemoryMaximumBytes = ($configMemory.Maximum)
|
||||
$MemoryStartupBytes = ($configMemory.Startup)
|
||||
$MemoryMinimumBytes = ($configMemory.Minimum)
|
||||
} else {
|
||||
if (!$maxmemory){
|
||||
$dynamicmemory = $False
|
||||
$MemoryMaximumBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryStartupBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryMinimumBytes = ($memory -as [int]) * 1MB
|
||||
} else {
|
||||
$dynamicmemory = $True
|
||||
$MemoryMaximumBytes = ($maxmemory -as [int]) * 1MB
|
||||
$MemoryStartupBytes = ($memory -as [int]) * 1MB
|
||||
$MemoryMinimumBytes = ($memory -as [int]) * 1MB
|
||||
}
|
||||
}
|
||||
|
||||
if (!$switchname) {
|
||||
$switchname = (Get-VMNetworkAdapter -VM $vmConfig.VM).SwitchName
|
||||
}
|
||||
|
||||
$vmNetworkAdapter = Get-VMNetworkAdapter -VM $vmConfig.VM
|
||||
Connect-VMNetworkAdapter -VMNetworkAdapter $vmNetworkAdapter -SwitchName $switchname
|
||||
Set-VM -VM $vmConfig.VM -NewVMName $vm_name
|
||||
Set-VM -VM $vmConfig.VM -ErrorAction "Stop"
|
||||
Set-VM -VM $vmConfig.VM -ProcessorCount $processors
|
||||
|
||||
if ($dynamicmemory) {
|
||||
Set-VM -VM $vmConfig.VM -DynamicMemory
|
||||
Set-VM -VM $vmConfig.VM -MemoryMinimumBytes $MemoryMinimumBytes -MemoryMaximumBytes $MemoryMaximumBytes -MemoryStartupBytes $MemoryStartupBytes
|
||||
} else {
|
||||
Set-VM -VM $vmConfig.VM -StaticMemory
|
||||
Set-VM -VM $vmConfig.VM -MemoryStartupBytes $MemoryStartupBytes
|
||||
}
|
||||
|
||||
if ($notes) {
|
||||
Set-VM -VM $vmConfig.VM -Notes $notes
|
||||
}
|
||||
|
||||
if ($auto_start_action) {
|
||||
Set-VM -VM $vmConfig.VM -AutomaticStartAction $auto_start_action
|
||||
}
|
||||
|
||||
if ($auto_stop_action) {
|
||||
Set-VM -VM $vmConfig.VM -AutomaticStartAction $auto_stop_action
|
||||
}
|
||||
|
||||
# Only set EFI secure boot for Gen 2 machines, not gen 1
|
||||
if ($generation -ne 1) {
|
||||
Set-VMFirmware -VM $vmConfig.VM -EnableSecureBoot (Get-VMFirmware -VM $vmConfig.VM).SecureBoot
|
||||
}
|
||||
|
||||
$report = Compare-VM -CompatibilityReport $vmConfig
|
||||
|
||||
# Stop if there are incompatibilities
|
||||
if($report.Incompatibilities.Length -gt 0){
|
||||
Write-Error-Message $(ConvertTo-Json $($report.Incompatibilities | Select -ExpandProperty Message))
|
||||
exit 0
|
||||
}
|
||||
|
||||
if($differencing_disk){
|
||||
# Get all controller on the VM, first scsi, then IDE if it is a Gen 1 device
|
||||
$controllers = Get-VMScsiController -VM $vmConfig.VM
|
||||
if($generation -eq 1){
|
||||
$controllers = @($controllers) + @(Get-VMIdeController -VM $vmConfig.VM)
|
||||
}
|
||||
|
||||
foreach($controller in $controllers){
|
||||
foreach($drive in $controller.Drives){
|
||||
if([System.IO.Path]::GetFileName($drive.Path) -eq [System.IO.Path]::GetFileName($source_path)){
|
||||
# Remove the old disk and replace it with a differencing version
|
||||
$path = $drive.Path
|
||||
Remove-VMHardDiskDrive $drive
|
||||
New-VHD -Path $dest_path -ParentPath $source_path -ErrorAction Stop
|
||||
Add-VMHardDiskDrive -VM $vmConfig.VM -Path $dest_path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Import-VM -CompatibilityReport $vmConfig
|
||||
|
||||
$vm_id = (Get-VM $vm_name).id.guid
|
||||
$resultHash = @{
|
||||
name = $vm_name
|
||||
id = $vm_id
|
||||
}
|
||||
|
||||
$result = ConvertTo-Json $resultHash
|
||||
Write-Output-Message $result
|
|
@ -1,8 +1,8 @@
|
|||
Param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$vm_xml_config,
|
||||
[string]$vm_config_file,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$image_path,
|
||||
[string]$dest_path,
|
||||
|
||||
[string]$switchname=$null,
|
||||
[string]$memory=$null,
|
||||
|
@ -17,7 +17,7 @@ Param(
|
|||
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||
|
||||
[xml]$vmconfig = Get-Content -Path $vm_xml_config
|
||||
[xml]$vmconfig = Get-Content -Path $vm_config_file
|
||||
|
||||
$generation = [int]($vmconfig.configuration.properties.subtype.'#text')+1
|
||||
|
||||
|
@ -190,7 +190,7 @@ foreach ($controller in $controllers) {
|
|||
|
||||
$addDriveParam = @{
|
||||
ControllerNumber = $rx.Match($controller.node.name).value
|
||||
Path = $image_path
|
||||
Path = $dest_path
|
||||
}
|
||||
|
||||
if ($drive.pool_id."#text") {
|
|
@ -4,16 +4,19 @@ module VagrantPlugins
|
|||
class Base < Vagrant.plugin("2", :config)
|
||||
|
||||
GALAXY_COMMAND_DEFAULT = "ansible-galaxy install --role-file=%{role_file} --roles-path=%{roles_path} --force".freeze
|
||||
PLAYBOOK_COMMAND_DEFAULT = "ansible-playbook".freeze
|
||||
|
||||
attr_accessor :config_file
|
||||
attr_accessor :extra_vars
|
||||
attr_accessor :galaxy_role_file
|
||||
attr_accessor :galaxy_roles_path
|
||||
attr_accessor :galaxy_command
|
||||
attr_accessor :host_vars
|
||||
attr_accessor :groups
|
||||
attr_accessor :host_vars
|
||||
attr_accessor :inventory_path
|
||||
attr_accessor :limit
|
||||
attr_accessor :playbook
|
||||
attr_accessor :playbook_command
|
||||
attr_accessor :raw_arguments
|
||||
attr_accessor :skip_tags
|
||||
attr_accessor :start_at_task
|
||||
|
@ -24,15 +27,17 @@ module VagrantPlugins
|
|||
attr_accessor :verbose
|
||||
|
||||
def initialize
|
||||
@config_file = UNSET_VALUE
|
||||
@extra_vars = UNSET_VALUE
|
||||
@galaxy_role_file = UNSET_VALUE
|
||||
@galaxy_roles_path = UNSET_VALUE
|
||||
@galaxy_command = UNSET_VALUE
|
||||
@host_vars = UNSET_VALUE
|
||||
@groups = UNSET_VALUE
|
||||
@host_vars = UNSET_VALUE
|
||||
@inventory_path = UNSET_VALUE
|
||||
@limit = UNSET_VALUE
|
||||
@playbook = UNSET_VALUE
|
||||
@playbook_command = UNSET_VALUE
|
||||
@raw_arguments = UNSET_VALUE
|
||||
@skip_tags = UNSET_VALUE
|
||||
@start_at_task = UNSET_VALUE
|
||||
|
@ -44,23 +49,25 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def finalize!
|
||||
@extra_vars = nil if @extra_vars == UNSET_VALUE
|
||||
@galaxy_role_file = nil if @galaxy_role_file == UNSET_VALUE
|
||||
@galaxy_roles_path = nil if @galaxy_roles_path == UNSET_VALUE
|
||||
@galaxy_command = GALAXY_COMMAND_DEFAULT if @galaxy_command == UNSET_VALUE
|
||||
@host_vars = {} if @host_vars == UNSET_VALUE
|
||||
@groups = {} if @groups == UNSET_VALUE
|
||||
@inventory_path = nil if @inventory_path == UNSET_VALUE
|
||||
@limit = nil if @limit == UNSET_VALUE
|
||||
@playbook = nil if @playbook == UNSET_VALUE
|
||||
@raw_arguments = nil if @raw_arguments == UNSET_VALUE
|
||||
@skip_tags = nil if @skip_tags == UNSET_VALUE
|
||||
@start_at_task = nil if @start_at_task == UNSET_VALUE
|
||||
@sudo = false if @sudo != true
|
||||
@sudo_user = nil if @sudo_user == UNSET_VALUE
|
||||
@tags = nil if @tags == UNSET_VALUE
|
||||
@vault_password_file = nil if @vault_password_file == UNSET_VALUE
|
||||
@verbose = false if @verbose == UNSET_VALUE
|
||||
@config_file = nil if @config_file == UNSET_VALUE
|
||||
@extra_vars = nil if @extra_vars == UNSET_VALUE
|
||||
@galaxy_role_file = nil if @galaxy_role_file == UNSET_VALUE
|
||||
@galaxy_roles_path = nil if @galaxy_roles_path == UNSET_VALUE
|
||||
@galaxy_command = GALAXY_COMMAND_DEFAULT if @galaxy_command == UNSET_VALUE
|
||||
@groups = {} if @groups == UNSET_VALUE
|
||||
@host_vars = {} if @host_vars == UNSET_VALUE
|
||||
@inventory_path = nil if @inventory_path == UNSET_VALUE
|
||||
@limit = nil if @limit == UNSET_VALUE
|
||||
@playbook = nil if @playbook == UNSET_VALUE
|
||||
@playbook_command = PLAYBOOK_COMMAND_DEFAULT if @playbook_command == UNSET_VALUE
|
||||
@raw_arguments = nil if @raw_arguments == UNSET_VALUE
|
||||
@skip_tags = nil if @skip_tags == UNSET_VALUE
|
||||
@start_at_task = nil if @start_at_task == UNSET_VALUE
|
||||
@sudo = false if @sudo != true
|
||||
@sudo_user = nil if @sudo_user == UNSET_VALUE
|
||||
@tags = nil if @tags == UNSET_VALUE
|
||||
@vault_password_file = nil if @vault_password_file == UNSET_VALUE
|
||||
@verbose = false if @verbose == UNSET_VALUE
|
||||
end
|
||||
|
||||
# Just like the normal configuration "validate" method except that
|
||||
|
|
|
@ -26,25 +26,44 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def check_files_existence
|
||||
check_path_is_a_file config.playbook, :playbook
|
||||
check_path_is_a_file(config.playbook, :playbook)
|
||||
|
||||
check_path_exists config.inventory_path, :inventory_path if config.inventory_path
|
||||
check_path_is_a_file config.extra_vars[1..-1], :extra_vars if has_an_extra_vars_file_argument
|
||||
check_path_is_a_file config.galaxy_role_file, :galaxy_role_file if config.galaxy_role_file
|
||||
check_path_is_a_file config.vault_password_file, :vault_password if config.vault_password_file
|
||||
check_path_exists(config.inventory_path, :inventory_path) if config.inventory_path
|
||||
check_path_is_a_file(config.config_file, :config_file) if config.config_file
|
||||
check_path_is_a_file(config.extra_vars[1..-1], :extra_vars) if has_an_extra_vars_file_argument
|
||||
check_path_is_a_file(config.galaxy_role_file, :galaxy_role_file) if config.galaxy_role_file
|
||||
check_path_is_a_file(config.vault_password_file, :vault_password_file) if config.vault_password_file
|
||||
end
|
||||
|
||||
def get_environment_variables_for_shell_execution
|
||||
shell_env_vars = []
|
||||
@environment_variables.each_pair do |k, v|
|
||||
if k =~ /ANSIBLE_SSH_ARGS|ANSIBLE_ROLES_PATH|ANSIBLE_CONFIG/
|
||||
shell_env_vars << "#{k}='#{v}'"
|
||||
else
|
||||
shell_env_vars << "#{k}=#{v}"
|
||||
end
|
||||
end
|
||||
shell_env_vars
|
||||
end
|
||||
|
||||
def ansible_galaxy_command_for_shell_execution
|
||||
command_values = {
|
||||
role_file: "'#{get_galaxy_role_file}'",
|
||||
roles_path: "'#{get_galaxy_roles_path}'"
|
||||
}
|
||||
|
||||
shell_command = get_environment_variables_for_shell_execution
|
||||
|
||||
shell_command << config.galaxy_command % command_values
|
||||
|
||||
shell_command.flatten.join(' ')
|
||||
end
|
||||
|
||||
def ansible_playbook_command_for_shell_execution
|
||||
shell_command = []
|
||||
@environment_variables.each_pair do |k, v|
|
||||
if k =~ /ANSIBLE_SSH_ARGS|ANSIBLE_ROLES_PATH/
|
||||
shell_command << "#{k}='#{v}'"
|
||||
else
|
||||
shell_command << "#{k}=#{v}"
|
||||
end
|
||||
end
|
||||
shell_command = get_environment_variables_for_shell_execution
|
||||
|
||||
shell_command << "ansible-playbook"
|
||||
shell_command << config.playbook_command
|
||||
|
||||
shell_args = []
|
||||
@command_arguments.each do |arg|
|
||||
|
@ -102,6 +121,12 @@ module VagrantPlugins
|
|||
# Use ANSIBLE_ROLES_PATH to tell ansible-playbook where to look for roles
|
||||
# (there is no equivalent command line argument in ansible-playbook)
|
||||
@environment_variables["ANSIBLE_ROLES_PATH"] = get_galaxy_roles_path if config.galaxy_roles_path
|
||||
|
||||
prepare_ansible_config_environment_variable
|
||||
end
|
||||
|
||||
def prepare_ansible_config_environment_variable
|
||||
@environment_variables["ANSIBLE_CONFIG"] = config.config_file if config.config_file
|
||||
end
|
||||
|
||||
# Auto-generate "safe" inventory file based on Vagrantfile,
|
||||
|
|
|
@ -52,9 +52,9 @@ module VagrantPlugins
|
|||
@machine.guest.capability(:ansible_install, config.install_mode, config.version)
|
||||
end
|
||||
|
||||
# Check that ansible binaries are well installed on the guest,
|
||||
# Check that Ansible Playbook command is available on the guest
|
||||
@machine.communicate.execute(
|
||||
"ansible-galaxy info --help && ansible-playbook --help",
|
||||
"test -x \"$(command -v #{config.playbook_command})\"",
|
||||
error_class: Ansible::Errors::AnsibleNotFoundOnGuest,
|
||||
error_key: :ansible_not_found_on_guest
|
||||
)
|
||||
|
@ -72,14 +72,9 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def execute_ansible_galaxy_on_guest
|
||||
command_values = {
|
||||
role_file: "'#{get_galaxy_role_file}'",
|
||||
roles_path: "'#{get_galaxy_roles_path}'"
|
||||
}
|
||||
prepare_ansible_config_environment_variable
|
||||
|
||||
remote_command = config.galaxy_command % command_values
|
||||
|
||||
execute_ansible_command_on_guest "galaxy", remote_command
|
||||
execute_ansible_command_on_guest "galaxy", ansible_galaxy_command_for_shell_execution
|
||||
end
|
||||
|
||||
def execute_ansible_playbook_on_guest
|
||||
|
@ -156,7 +151,7 @@ module VagrantPlugins
|
|||
# and error if it doesn't exist.
|
||||
|
||||
remote_path = Helpers::expand_path_in_unix_style(path, config.provisioning_path)
|
||||
command = "test #{test_args} #{remote_path}"
|
||||
command = "test #{test_args} '#{remote_path}'"
|
||||
|
||||
@machine.communicate.execute(
|
||||
command,
|
||||
|
|
|
@ -20,6 +20,7 @@ module VagrantPlugins
|
|||
|
||||
check_files_existence
|
||||
warn_for_unsupported_platform
|
||||
|
||||
execute_ansible_galaxy_from_host if config.galaxy_role_file
|
||||
execute_ansible_playbook_from_host
|
||||
end
|
||||
|
@ -88,6 +89,8 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def execute_ansible_galaxy_from_host
|
||||
prepare_ansible_config_environment_variable
|
||||
|
||||
command_values = {
|
||||
role_file: get_galaxy_role_file,
|
||||
roles_path: get_galaxy_roles_path
|
||||
|
@ -97,23 +100,23 @@ module VagrantPlugins
|
|||
|
||||
command = str_command.split(VAGRANT_ARG_SEPARATOR)
|
||||
command << {
|
||||
env: @environment_variables,
|
||||
# Write stdout and stderr data, since it's the regular Ansible output
|
||||
notify: [:stdout, :stderr],
|
||||
workdir: @machine.env.root_path.to_s
|
||||
}
|
||||
|
||||
# FIXME: role_file and roles_path arguments should be quoted in the console output
|
||||
ui_running_ansible_command "galaxy", str_command.gsub(VAGRANT_ARG_SEPARATOR, ' ')
|
||||
ui_running_ansible_command "galaxy", ansible_galaxy_command_for_shell_execution
|
||||
|
||||
execute_command_from_host command
|
||||
end
|
||||
|
||||
def execute_ansible_playbook_from_host
|
||||
prepare_command_arguments
|
||||
prepare_environment_variables
|
||||
prepare_command_arguments
|
||||
|
||||
# Assemble the full ansible-playbook command
|
||||
command = %w(ansible-playbook) << @command_arguments
|
||||
command = [config.playbook_command] << @command_arguments
|
||||
|
||||
# Add the raw arguments at the end, to give them the highest precedence
|
||||
command << config.raw_arguments if config.raw_arguments
|
||||
|
@ -234,6 +237,7 @@ module VagrantPlugins
|
|||
proxy_cmd += " exec nc %h %p 2>/dev/null"
|
||||
|
||||
ssh_options << "-o ProxyCommand='#{ proxy_cmd }'"
|
||||
# TODO ssh_options << "-o ProxyCommand=\"#{ proxy_cmd }\""
|
||||
end
|
||||
|
||||
# Use an SSH ProxyCommand when corresponding Vagrant setting is defined
|
||||
|
|
|
@ -64,16 +64,6 @@ module VagrantPlugins
|
|||
# @return [String]
|
||||
attr_accessor :installer_download_path
|
||||
|
||||
# @deprecated
|
||||
def prerelease=(value)
|
||||
STDOUT.puts <<-EOH
|
||||
[DEPRECATED] The configuration `chef.prerelease' has been deprecated. Please use
|
||||
`chef.channel' instead. The default value for channel is "stable", which
|
||||
includes the latest published versions of the Chef Client. You can choose to use
|
||||
prerelease versions by setting the channel to "current".
|
||||
EOH
|
||||
end
|
||||
|
||||
def initialize
|
||||
super
|
||||
|
||||
|
|
|
@ -5,15 +5,6 @@ module VagrantPlugins
|
|||
class Config < Vagrant.plugin("2", :config)
|
||||
attr_reader :images
|
||||
|
||||
def version=(value)
|
||||
STDOUT.puts <<-EOH
|
||||
[DEPRECATED] The configuration `docker.version' has been deprecated. Docker no
|
||||
longer allows you to specify the version of Docker you want installed and will
|
||||
automatically choose the best version for your guest. Please remove this option
|
||||
from your Vagrantfile.
|
||||
EOH
|
||||
end
|
||||
|
||||
def initialize
|
||||
@images = Set.new
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ module VagrantPlugins
|
|||
attr_accessor :manifests_path
|
||||
attr_accessor :environment
|
||||
attr_accessor :environment_path
|
||||
attr_accessor :environment_variables
|
||||
attr_accessor :module_path
|
||||
attr_accessor :options
|
||||
attr_accessor :synced_folder_type
|
||||
|
@ -23,18 +24,19 @@ module VagrantPlugins
|
|||
def initialize
|
||||
super
|
||||
|
||||
@binary_path = UNSET_VALUE
|
||||
@hiera_config_path = UNSET_VALUE
|
||||
@manifest_file = UNSET_VALUE
|
||||
@manifests_path = UNSET_VALUE
|
||||
@environment = UNSET_VALUE
|
||||
@environment_path = UNSET_VALUE
|
||||
@module_path = UNSET_VALUE
|
||||
@options = []
|
||||
@facter = {}
|
||||
@synced_folder_type = UNSET_VALUE
|
||||
@temp_dir = UNSET_VALUE
|
||||
@working_directory = UNSET_VALUE
|
||||
@binary_path = UNSET_VALUE
|
||||
@hiera_config_path = UNSET_VALUE
|
||||
@manifest_file = UNSET_VALUE
|
||||
@manifests_path = UNSET_VALUE
|
||||
@environment = UNSET_VALUE
|
||||
@environment_path = UNSET_VALUE
|
||||
@environment_variables = UNSET_VALUE
|
||||
@module_path = UNSET_VALUE
|
||||
@options = []
|
||||
@facter = {}
|
||||
@synced_folder_type = UNSET_VALUE
|
||||
@temp_dir = UNSET_VALUE
|
||||
@working_directory = UNSET_VALUE
|
||||
end
|
||||
|
||||
def nfs=(value)
|
||||
|
@ -87,6 +89,10 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
if @environment_variables == UNSET_VALUE
|
||||
@environment_variables = {}
|
||||
end
|
||||
|
||||
@binary_path = nil if @binary_path == UNSET_VALUE
|
||||
@module_path = nil if @module_path == UNSET_VALUE
|
||||
@synced_folder_type = nil if @synced_folder_type == UNSET_VALUE
|
||||
|
|
|
@ -207,7 +207,7 @@ module VagrantPlugins
|
|||
options = options.join(" ")
|
||||
|
||||
# Build up the custom facts if we have any
|
||||
facter = ""
|
||||
facter = nil
|
||||
if !config.facter.empty?
|
||||
facts = []
|
||||
config.facter.each do |key, value|
|
||||
|
@ -219,7 +219,7 @@ module VagrantPlugins
|
|||
facts.map! { |v| "$env:#{v};" }
|
||||
end
|
||||
|
||||
facter = "#{facts.join(" ")} "
|
||||
facter = facts.join(" ")
|
||||
end
|
||||
|
||||
puppet_bin = "puppet"
|
||||
|
@ -227,7 +227,28 @@ module VagrantPlugins
|
|||
puppet_bin = File.join(@config.binary_path, puppet_bin)
|
||||
end
|
||||
|
||||
command = "#{facter} #{puppet_bin} apply #{options}"
|
||||
env_vars = nil
|
||||
if !config.environment_variables.nil? && !config.environment_variables.empty?
|
||||
env_vars = config.environment_variables.map do |env_key, env_value|
|
||||
"#{env_key}=\"#{env_value}\""
|
||||
end
|
||||
|
||||
if windows?
|
||||
env_vars.map! do |env_var_string|
|
||||
"$env:#{env_var_string}"
|
||||
end
|
||||
end
|
||||
|
||||
env_vars = env_vars.join(" ")
|
||||
end
|
||||
|
||||
command = [
|
||||
env_vars,
|
||||
facter,
|
||||
puppet_bin,
|
||||
"apply",
|
||||
options
|
||||
].compact.map(&:to_s).join(" ")
|
||||
if config.working_directory
|
||||
if windows?
|
||||
command = "cd #{config.working_directory}; if ($?) \{ #{command} \}"
|
||||
|
|
|
@ -4,11 +4,6 @@ require "vagrant/util/deep_merge"
|
|||
module VagrantPlugins
|
||||
module Salt
|
||||
class Config < Vagrant.plugin("2", :config)
|
||||
## @deprecated
|
||||
def config_dir=(value)
|
||||
puts "salt config_dir is deprecated and will be removed in Vagrant 1.9"
|
||||
end
|
||||
|
||||
## salty-vagrant options
|
||||
attr_accessor :minion_config
|
||||
attr_accessor :minion_key
|
||||
|
@ -74,12 +69,6 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def finalize!
|
||||
@minion_config = nil if @minion_config == UNSET_VALUE
|
||||
@minion_key = nil if @minion_key == UNSET_VALUE
|
||||
@minion_pub = nil if @minion_pub == UNSET_VALUE
|
||||
@master_config = nil if @master_config == UNSET_VALUE
|
||||
@master_key = nil if @master_key == UNSET_VALUE
|
||||
@master_pub = nil if @master_pub == UNSET_VALUE
|
||||
@grains_config = nil if @grains_config == UNSET_VALUE
|
||||
@run_highstate = nil if @run_highstate == UNSET_VALUE
|
||||
@run_overstate = nil if @run_overstate == UNSET_VALUE
|
||||
|
@ -102,6 +91,15 @@ module VagrantPlugins
|
|||
@version = nil if @version == UNSET_VALUE
|
||||
@run_service = nil if @run_service == UNSET_VALUE
|
||||
@master_id = nil if @master_id == UNSET_VALUE
|
||||
|
||||
# NOTE: Optimistic defaults are set in the provisioner. UNSET_VALUEs
|
||||
# are converted there to allow proper detection of unset values.
|
||||
# @minion_config = nil if @minion_config == UNSET_VALUE
|
||||
# @minion_key = nil if @minion_key == UNSET_VALUE
|
||||
# @minion_pub = nil if @minion_pub == UNSET_VALUE
|
||||
# @master_config = nil if @master_config == UNSET_VALUE
|
||||
# @master_key = nil if @master_key == UNSET_VALUE
|
||||
# @master_pub = nil if @master_pub == UNSET_VALUE
|
||||
end
|
||||
|
||||
def pillar(data)
|
||||
|
@ -111,14 +109,14 @@ module VagrantPlugins
|
|||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
if @minion_config
|
||||
if @minion_config && @minion_config != UNSET_VALUE
|
||||
expanded = Pathname.new(@minion_config).expand_path(machine.env.root_path)
|
||||
if !expanded.file?
|
||||
errors << I18n.t("vagrant.provisioners.salt.minion_config_nonexist", missing_config_file: expanded)
|
||||
end
|
||||
end
|
||||
|
||||
if @master_config
|
||||
if @master_config && @master_config != UNSET_VALUE
|
||||
expanded = Pathname.new(@master_config).expand_path(machine.env.root_path)
|
||||
if !expanded.file?
|
||||
errors << I18n.t("vagrant.provisioners.salt.master_config_nonexist", missing_config_file: expanded)
|
||||
|
|
|
@ -3,7 +3,20 @@ require 'json'
|
|||
module VagrantPlugins
|
||||
module Salt
|
||||
class Provisioner < Vagrant.plugin("2", :provisioner)
|
||||
|
||||
# Default path values to set within configuration only
|
||||
# if configuration value is unset and local path exists
|
||||
OPTIMISTIC_PATH_DEFAULTS = Hash[*[
|
||||
"minion_config", "salt/minion",
|
||||
"minion_key", "salt/key/minion.key",
|
||||
"minion_pub", "salt/key/minion.pub",
|
||||
"master_config", "salt/master",
|
||||
"master_key", "salt/key/master.key",
|
||||
"master_pub", "salt/key/master.pub"
|
||||
].map(&:freeze)].freeze
|
||||
|
||||
def provision
|
||||
set_default_configs
|
||||
upload_configs
|
||||
upload_keys
|
||||
run_bootstrap_script
|
||||
|
@ -238,19 +251,19 @@ module VagrantPlugins
|
|||
bootstrap_path = get_bootstrap
|
||||
if @machine.config.vm.communicator == :winrm
|
||||
if @config.version
|
||||
options += " -version %s" % @config.version
|
||||
options += " -version %s" % @config.version
|
||||
end
|
||||
if @config.run_service
|
||||
@machine.env.ui.info "Salt minion will be stopped after installing."
|
||||
options += " -runservice %s" % @config.run_service
|
||||
options += " -runservice %s" % @config.run_service
|
||||
end
|
||||
if @config.minion_id
|
||||
@machine.env.ui.info "Setting minion to @config.minion_id."
|
||||
options += " -minion %s" % @config.minion_id
|
||||
options += " -minion %s" % @config.minion_id
|
||||
end
|
||||
if @config.master_id
|
||||
@machine.env.ui.info "Setting master to @config.master_id."
|
||||
options += " -master %s" % @config.master_id
|
||||
options += " -master %s" % @config.master_id
|
||||
end
|
||||
bootstrap_destination = File.join(config_dir, "bootstrap_salt.ps1")
|
||||
else
|
||||
|
@ -390,6 +403,16 @@ module VagrantPlugins
|
|||
@machine.communicate.sudo(cmd, &log_output)
|
||||
end
|
||||
end
|
||||
|
||||
# Sets optimistic default values into config
|
||||
def set_default_configs
|
||||
OPTIMISTIC_PATH_DEFAULTS.each do |config_key, config_default|
|
||||
if config.send(config_key) == Config::UNSET_VALUE
|
||||
config_value = File.exist?(expanded_path(config_default)) ? config_default : nil
|
||||
config.send("#{config_key}=", config_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,8 @@ module VagrantPlugins
|
|||
class Config < Vagrant.plugin("2", :config)
|
||||
attr_accessor :inline
|
||||
attr_accessor :path
|
||||
attr_accessor :md5
|
||||
attr_accessor :sha1
|
||||
attr_accessor :env
|
||||
attr_accessor :upload_path
|
||||
attr_accessor :args
|
||||
|
@ -19,6 +21,8 @@ module VagrantPlugins
|
|||
@args = UNSET_VALUE
|
||||
@inline = UNSET_VALUE
|
||||
@path = UNSET_VALUE
|
||||
@md5 = UNSET_VALUE
|
||||
@sha1 = UNSET_VALUE
|
||||
@env = UNSET_VALUE
|
||||
@upload_path = UNSET_VALUE
|
||||
@privileged = UNSET_VALUE
|
||||
|
@ -33,6 +37,8 @@ module VagrantPlugins
|
|||
@args = nil if @args == UNSET_VALUE
|
||||
@inline = nil if @inline == UNSET_VALUE
|
||||
@path = nil if @path == UNSET_VALUE
|
||||
@md5 = nil if @md5 == UNSET_VALUE
|
||||
@sha1 = nil if @sha1 == UNSET_VALUE
|
||||
@env = {} if @env == UNSET_VALUE
|
||||
@upload_path = "/tmp/vagrant-shell" if @upload_path == UNSET_VALUE
|
||||
@privileged = true if @privileged == UNSET_VALUE
|
||||
|
|
|
@ -177,7 +177,12 @@ module VagrantPlugins
|
|||
download_path.delete if download_path.file?
|
||||
|
||||
begin
|
||||
Vagrant::Util::Downloader.new(config.path, download_path).download!
|
||||
Vagrant::Util::Downloader.new(
|
||||
config.path,
|
||||
download_path,
|
||||
md5: config.md5,
|
||||
sha1: config.sha1
|
||||
).download!
|
||||
ext = File.extname(config.path)
|
||||
script = download_path.read
|
||||
ensure
|
||||
|
|
|
@ -32,7 +32,7 @@ module VagrantPlugins
|
|||
exclude_base = Pathname.new(opts[:guestpath])
|
||||
exclusions = Array(opts[:exclude]).map do |ex_path|
|
||||
ex_path = ex_path.slice(1, ex_path.size) if ex_path.start_with?(File::SEPARATOR)
|
||||
"-path #{exclude_base.join(ex_path)} -prune"
|
||||
"-path #{Shellwords.escape(exclude_base.join(ex_path))} -prune"
|
||||
end.join(" -o ") + " -o "
|
||||
end
|
||||
"find #{guest_path} #{exclusions}" \
|
||||
|
|
|
@ -734,6 +734,14 @@ en:
|
|||
downloader_interrupted: |-
|
||||
The download was interrupted by an external signal. It did not
|
||||
complete.
|
||||
downloader_checksum_error: |-
|
||||
The calculated checksum of the requested file does not match the expected
|
||||
checksum!
|
||||
|
||||
File source: %{source}
|
||||
Checsum type: %{type}
|
||||
Expected checksum: %{expected_checksum}
|
||||
Calculated checksum: %{actual_checksum}
|
||||
env_inval: |-
|
||||
Vagrant received an "EINVAL" error while attempting to set some
|
||||
environment variables. This is usually caused by the total size of your
|
||||
|
@ -877,6 +885,14 @@ en:
|
|||
the issues below and execute "vagrant reload":
|
||||
|
||||
%{output}
|
||||
nfs_exports_failed: |-
|
||||
Vagrant failed to install an updated NFS exports file. This may be
|
||||
due to overly restrictive permissions on your NFS exports file. Please
|
||||
validate them and try again.
|
||||
|
||||
command: %{command}
|
||||
stdout: %{stdout}
|
||||
stderr: %{stderr}
|
||||
nfs_cant_read_exports: |-
|
||||
Vagrant can't read your current NFS exports! The exports file should be
|
||||
readable by any user. This is usually caused by invalid permissions
|
||||
|
@ -966,6 +982,20 @@ en:
|
|||
by contacting a plugin author to see if they can address the conflict.
|
||||
|
||||
%{conflicts}
|
||||
plugin_init_error: |-
|
||||
The plugins failed to initialize correctly. This may be due to manual
|
||||
modifications made within the Vagrant home directory. Vagrant can
|
||||
attempt to automatically correct this issue by running:
|
||||
|
||||
vagrant plugin repair
|
||||
|
||||
If Vagrant was recently updated, this error may be due to incompatible
|
||||
versions of dependencies. To fix this problem please remove and re-install
|
||||
all plugins. Vagrant can attempt to do this automatically by running:
|
||||
|
||||
vagrant plugin expunge --reinstall
|
||||
|
||||
Error message given during initialization: %{message}
|
||||
plugin_load_error: |-
|
||||
The plugins failed to load properly. The error message given is
|
||||
shown below.
|
||||
|
@ -1065,6 +1095,15 @@ en:
|
|||
Guest path: %{guestpath}
|
||||
Command: %{command}
|
||||
Error: %{stderr}
|
||||
rsync_guest_install_error: |-
|
||||
Installation of rsync into the guest has failed! The stdout
|
||||
and stderr are shown below. Please read the error output, resolve
|
||||
it and try again. If the problem persists, please install rsync
|
||||
manually within the guest.
|
||||
|
||||
Command: %{command}
|
||||
Stdout: %{stdout}
|
||||
Stderr: %{stderr}
|
||||
rsync_not_found: |-
|
||||
"rsync" could not be found on your PATH. Make sure that rsync
|
||||
is properly installed on your system and available on the PATH.
|
||||
|
@ -1559,6 +1598,24 @@ en:
|
|||
the comments in the Vagrantfile as well as documentation on
|
||||
`vagrantup.com` for more information on using Vagrant.
|
||||
plugin:
|
||||
expunge_confirm: |-
|
||||
|
||||
This command permanently deletes all currently installed user plugins. It
|
||||
should only be used when a repair command is unable to properly fix the
|
||||
system.
|
||||
|
||||
Continue?
|
||||
expunge_request_reinstall: |-
|
||||
Would you like Vagrant to attempt to reinstall current plugins?
|
||||
expunge_complete: |-
|
||||
|
||||
All user installed plugins have been removed from this Vagrant environment!
|
||||
expunge_reinstall: |-
|
||||
|
||||
Vagrant will now attempt to reinstall user plugins that were removed.
|
||||
expunge_aborted: |-
|
||||
|
||||
Vagrant expunge has been declined. Skipping removal of plugins.
|
||||
installed_license: |-
|
||||
The license for '%{name}' was successfully installed!
|
||||
installing_license: |-
|
||||
|
@ -1584,6 +1641,20 @@ en:
|
|||
post_install: |-
|
||||
Post install message from the '%{name}' plugin:
|
||||
|
||||
%{message}
|
||||
repairing: |-
|
||||
Repairing currently installed plugins. This may take a few minutes...
|
||||
repair_complete: |-
|
||||
Installed plugins successfully repaired!
|
||||
repair_failed: |-
|
||||
Failed to automatically repair installed Vagrant plugins. To fix this
|
||||
problem remove all user installed plugins and reinstall. Vagrant can
|
||||
do this for you automatically by running the following command:
|
||||
|
||||
vagrant plugin expunge --reinstall
|
||||
|
||||
Failure message received during repair:
|
||||
|
||||
%{message}
|
||||
snapshot:
|
||||
not_supported: |-
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
require File.expand_path("../../../../../base", __FILE__)
|
||||
|
||||
require Vagrant.source_root.join("plugins/commands/box/command/prune")
|
||||
|
||||
describe VagrantPlugins::CommandBox::Command::Prune do
|
||||
include_context "unit"
|
||||
include_context "command plugin helpers"
|
||||
|
||||
let(:entry_klass) { Vagrant::MachineIndex::Entry }
|
||||
|
||||
let(:iso_env) do
|
||||
# We have to create a Vagrantfile so there is a root path
|
||||
isolated_environment.tap do |env|
|
||||
env.vagrantfile("")
|
||||
end
|
||||
end
|
||||
|
||||
let(:iso_vagrant_env) { iso_env.create_vagrant_env }
|
||||
|
||||
let(:argv) { [] }
|
||||
|
||||
# Seems this way of providing a box version triggers box in use.
|
||||
def new_entry(name, box_name, box_provider, version)
|
||||
entry_klass.new.tap do |e|
|
||||
e.name = name
|
||||
e.vagrantfile_path = "/bar"
|
||||
e.extra_data["box"] = {
|
||||
"name" => box_name,
|
||||
"provider" => box_provider,
|
||||
"version" => version,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
subject { described_class.new(argv, iso_vagrant_env) }
|
||||
|
||||
describe "execute" do
|
||||
context "with no args" do
|
||||
it "removes the old version and keeps the current one" do
|
||||
|
||||
# Let's put some things in the index
|
||||
iso_env.box3("foobox", "1.0", :virtualbox);
|
||||
iso_env.box3("foobox", "1.1", :virtualbox);
|
||||
iso_env.box3("barbox", "1.0", :vmware);
|
||||
iso_env.box3("barbox", "1.1", :vmware);
|
||||
|
||||
iso_vagrant_env.machine_index.set(new_entry("foo", "foobox", "virtualbox", 1))
|
||||
|
||||
output = ""
|
||||
allow(iso_vagrant_env.ui).to receive(:info) do |data|
|
||||
output << data
|
||||
end
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(4)
|
||||
expect(subject.execute).to eq(0)
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(2)
|
||||
|
||||
expect(output).to include("barbox (vmware, 1.1)")
|
||||
expect(output).to include("Removing box 'barbox' (v1.0) with provider 'vmware'...")
|
||||
expect(output).to include("foobox (virtualbox, 1.1)")
|
||||
expect(output).to include("Removing box 'foobox' (v1.0) with provider 'virtualbox'...")
|
||||
end
|
||||
|
||||
it "removes nothing" do
|
||||
# Let's put some things in the index
|
||||
iso_env.box3("foobox", "1.0", :virtualbox);
|
||||
iso_env.box3("barbox", "1.0", :vmware);
|
||||
|
||||
iso_vagrant_env.machine_index.set(new_entry("foo", "foobox", "virtualbox", 1))
|
||||
|
||||
output = ""
|
||||
allow(iso_vagrant_env.ui).to receive(:info) do |data|
|
||||
output << data
|
||||
end
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(2)
|
||||
expect(subject.execute).to eq(0)
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(2)
|
||||
|
||||
expect(output).to include("No old versions of boxes to remove...")
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context "with --provider" do
|
||||
let(:argv) { ["--provider", "virtualbox"] }
|
||||
|
||||
it "removes the old versions of the specified provider" do
|
||||
|
||||
# Let's put some things in the index
|
||||
iso_env.box3("foobox", "1.0", :virtualbox);
|
||||
iso_env.box3("foobox", "1.1", :virtualbox);
|
||||
iso_env.box3("barbox", "1.0", :vmware);
|
||||
iso_env.box3("barbox", "1.1", :vmware);
|
||||
|
||||
iso_vagrant_env.machine_index.set(new_entry("foo", "foobox", "virtualbox", 1))
|
||||
|
||||
output = ""
|
||||
allow(iso_vagrant_env.ui).to receive(:info) do |data|
|
||||
output << "\n" + data
|
||||
end
|
||||
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(4)
|
||||
expect(subject.execute).to eq(0)
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(3)
|
||||
|
||||
expect(output).to include("foobox (virtualbox, 1.1)")
|
||||
expect(output).to include("Removing box 'foobox' (v1.0) with provider 'virtualbox'...")
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context "with --dry-run" do
|
||||
let(:argv) { ["--dry-run"] }
|
||||
|
||||
it "removes the old versions of the specified provider" do
|
||||
|
||||
# Let's put some things in the index
|
||||
iso_env.box3("foobox", "1.0", :virtualbox);
|
||||
iso_env.box3("foobox", "1.1", :virtualbox);
|
||||
|
||||
iso_vagrant_env.machine_index.set(new_entry("foo", "foobox", "virtualbox", 1))
|
||||
|
||||
output = ""
|
||||
allow(iso_vagrant_env.ui).to receive(:info) do |data|
|
||||
output << "\n" + data
|
||||
end
|
||||
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(2)
|
||||
expect(subject.execute).to eq(0)
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(2)
|
||||
|
||||
|
||||
expect(output).to include("foobox (virtualbox, 1.1)")
|
||||
expect(output).to include("Would remove foobox virtualbox 1.0")
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context "with --name" do
|
||||
let(:argv) { ["--name", "barbox"] }
|
||||
|
||||
it "removes the old versions of the specified provider" do
|
||||
|
||||
# Let's put some things in the index
|
||||
iso_env.box3("foobox", "1.0", :virtualbox);
|
||||
iso_env.box3("foobox", "1.1", :virtualbox);
|
||||
iso_env.box3("barbox", "1.0", :vmware);
|
||||
iso_env.box3("barbox", "1.1", :vmware);
|
||||
|
||||
iso_vagrant_env.machine_index.set(new_entry("foo", "foobox", "virtualbox", 1))
|
||||
|
||||
output = ""
|
||||
allow(iso_vagrant_env.ui).to receive(:info) do |data|
|
||||
output << "\n" + data
|
||||
end
|
||||
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(4)
|
||||
expect(subject.execute).to eq(0)
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(3)
|
||||
|
||||
expect(output).to include("barbox (vmware, 1.1)")
|
||||
expect(output).to include("Removing box 'barbox' (v1.0) with provider 'vmware'...")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context "with --name and --provider" do
|
||||
let(:argv) { ["--name", "foobox", "--provider", "virtualbox"] }
|
||||
|
||||
it "removed the old versions of that name and provider only" do
|
||||
# Let's put some things in the index
|
||||
iso_env.box3("foobox", "1.0", :virtualbox);
|
||||
iso_env.box3("foobox", "1.1", :virtualbox);
|
||||
iso_env.box3("foobox", "1.0", :vmware);
|
||||
iso_env.box3("foobox", "1.1", :vmware);
|
||||
iso_env.box3("barbox", "1.0", :vmware);
|
||||
iso_env.box3("barbox", "1.1", :vmware);
|
||||
|
||||
iso_vagrant_env.machine_index.set(new_entry("foo", "foobox", "virtualbox", 1))
|
||||
|
||||
output = ""
|
||||
allow(iso_vagrant_env.ui).to receive(:info) do |data|
|
||||
output << "\n" + data
|
||||
end
|
||||
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(6)
|
||||
expect(subject.execute).to eq(0)
|
||||
expect(iso_vagrant_env.boxes.all.count).to eq(5)
|
||||
|
||||
expect(output).to include("Removing box 'foobox' (v1.0) with provider 'virtualbox'...")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,64 @@
|
|||
require File.expand_path("../../../../../base", __FILE__)
|
||||
|
||||
describe VagrantPlugins::CommandPlugin::Action::ExpungePlugins do
|
||||
let(:app) { lambda { |env| } }
|
||||
let(:home_path){ '/fake/file/path/.vagrant.d' }
|
||||
let(:gems_path){ "#{home_path}/gems" }
|
||||
let(:force){ true }
|
||||
let(:env) {{
|
||||
ui: Vagrant::UI::Silent.new,
|
||||
home_path: home_path,
|
||||
gems_path: gems_path,
|
||||
force: force
|
||||
}}
|
||||
|
||||
let(:manager) { double("manager") }
|
||||
|
||||
let(:expect_to_receive) do
|
||||
lambda do
|
||||
allow(File).to receive(:exist?).with(File.join(home_path, 'plugins.json')).and_return(true)
|
||||
allow(File).to receive(:directory?).with(gems_path).and_return(true)
|
||||
expect(FileUtils).to receive(:rm).with(File.join(home_path, 'plugins.json'))
|
||||
expect(FileUtils).to receive(:rm_rf).with(gems_path)
|
||||
expect(app).to receive(:call).with(env).once
|
||||
end
|
||||
end
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
before do
|
||||
Vagrant::Plugin::Manager.stub(instance: manager)
|
||||
end
|
||||
|
||||
describe "#call" do
|
||||
before do
|
||||
instance_exec(&expect_to_receive)
|
||||
end
|
||||
|
||||
it "should delete all plugins" do
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
describe "when force is false" do
|
||||
let(:force){ false }
|
||||
|
||||
it "should prompt user before deleting all plugins" do
|
||||
expect(env[:ui]).to receive(:ask).and_return("Y\n")
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
describe "when user declines prompt" do
|
||||
let(:expect_to_receive) do
|
||||
lambda do
|
||||
expect(app).not_to receive(:call)
|
||||
end
|
||||
end
|
||||
|
||||
it "should not delete all plugins" do
|
||||
expect(env[:ui]).to receive(:ask).and_return("N\n")
|
||||
subject.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,12 +18,14 @@ describe VagrantPlugins::CommandPlugin::Action::UpdateGems do
|
|||
describe "#call" do
|
||||
it "should update all plugins if none are specified" do
|
||||
expect(manager).to receive(:update_plugins).with([]).once.and_return([])
|
||||
expect(manager).to receive(:installed_plugins).twice.and_return({})
|
||||
expect(app).to receive(:call).with(env).once
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
it "should update specified plugins" do
|
||||
expect(manager).to receive(:update_plugins).with(["foo"]).once.and_return([])
|
||||
expect(manager).to receive(:installed_plugins).twice.and_return({})
|
||||
expect(app).to receive(:call).with(env).once
|
||||
|
||||
env[:plugin_name] = ["foo"]
|
||||
|
|
|
@ -5,6 +5,8 @@ require Vagrant.source_root.join("plugins/communicators/ssh/communicator")
|
|||
describe VagrantPlugins::CommunicatorSSH::Communicator do
|
||||
include_context "unit"
|
||||
|
||||
let(:export_command_template){ 'export %ENV_KEY%="%ENV_VALUE%"' }
|
||||
|
||||
# SSH configuration information mock
|
||||
let(:ssh) do
|
||||
double("ssh",
|
||||
|
@ -15,6 +17,7 @@ describe VagrantPlugins::CommunicatorSSH::Communicator do
|
|||
pty: false,
|
||||
keep_alive: false,
|
||||
insert_key: false,
|
||||
export_command_template: export_command_template,
|
||||
shell: 'bash -l'
|
||||
)
|
||||
end
|
||||
|
@ -509,4 +512,18 @@ describe VagrantPlugins::CommunicatorSSH::Communicator do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".generate_environment_export" do
|
||||
it "should generate bourne shell compatible export" do
|
||||
communicator.send(:generate_environment_export, "TEST", "value").should eq("export TEST=\"value\"\n")
|
||||
end
|
||||
|
||||
context "with custom template defined" do
|
||||
let(:export_command_template){ "setenv %ENV_KEY% %ENV_VALUE%" }
|
||||
|
||||
it "should generate custom export based on template" do
|
||||
communicator.send(:generate_environment_export, "TEST", "value").should eq("setenv TEST value\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -45,7 +45,7 @@ describe VagrantPlugins::CommunicatorWinRM::Communicator do
|
|||
port: '22',
|
||||
})
|
||||
# Makes ready? return true
|
||||
allow(shell).to receive(:powershell).with("hostname").and_return({ exitcode: 0 })
|
||||
allow(shell).to receive(:cmd).with("hostname").and_return({ exitcode: 0 })
|
||||
end
|
||||
|
||||
it "retries ssh_info until ready" do
|
||||
|
@ -57,22 +57,22 @@ describe VagrantPlugins::CommunicatorWinRM::Communicator do
|
|||
|
||||
describe ".ready?" do
|
||||
it "returns true if hostname command executes without error" do
|
||||
expect(shell).to receive(:powershell).with("hostname").and_return({ exitcode: 0 })
|
||||
expect(shell).to receive(:cmd).with("hostname").and_return({ exitcode: 0 })
|
||||
expect(subject.ready?).to be_true
|
||||
end
|
||||
|
||||
it "returns false if hostname command fails with a transient error" do
|
||||
expect(shell).to receive(:powershell).with("hostname").and_raise(VagrantPlugins::CommunicatorWinRM::Errors::TransientError)
|
||||
expect(shell).to receive(:cmd).with("hostname").and_raise(VagrantPlugins::CommunicatorWinRM::Errors::TransientError)
|
||||
expect(subject.ready?).to be_false
|
||||
end
|
||||
|
||||
it "raises an error if hostname command fails with an unknown error" do
|
||||
expect(shell).to receive(:powershell).with("hostname").and_raise(Vagrant::Errors::VagrantError)
|
||||
expect(shell).to receive(:cmd).with("hostname").and_raise(Vagrant::Errors::VagrantError)
|
||||
expect { subject.ready? }.to raise_error(Vagrant::Errors::VagrantError)
|
||||
end
|
||||
|
||||
it "raises timeout error when hostname command takes longer then winrm timeout" do
|
||||
expect(shell).to receive(:powershell).with("hostname") do
|
||||
expect(shell).to receive(:cmd).with("hostname") do
|
||||
sleep 2 # winrm.timeout = 1
|
||||
end
|
||||
expect { subject.ready? }.to raise_error(Timeout::Error)
|
||||
|
|
|
@ -6,7 +6,7 @@ require Vagrant.source_root.join("plugins/communicators/winrm/config")
|
|||
describe VagrantPlugins::CommunicatorWinRM::WinRMShell do
|
||||
include_context "unit"
|
||||
|
||||
let(:session) { double("winrm_session", create_executor: executor) }
|
||||
let(:session) { double("winrm_session") }
|
||||
let(:executor) { double("command_executor") }
|
||||
let(:port) { config.transport == :ssl ? 5986 : 5985 }
|
||||
let(:config) {
|
||||
|
@ -22,6 +22,8 @@ describe VagrantPlugins::CommunicatorWinRM::WinRMShell do
|
|||
end
|
||||
}
|
||||
|
||||
before { allow(session).to receive(:create_executor).and_yield(executor) }
|
||||
|
||||
subject do
|
||||
described_class.new('localhost', port, config).tap do |comm|
|
||||
allow(comm).to receive(:new_session).and_return(session)
|
||||
|
|
|
@ -31,10 +31,9 @@ describe "VagrantPlugins::GuestBSD::Cap::NFS" do
|
|||
}
|
||||
cap.mount_nfs_folder(machine, ip, folders)
|
||||
|
||||
expect(comm.received_commands[0]).to match(/set -e/)
|
||||
expect(comm.received_commands[0]).to match(/mkdir -p \/guest/)
|
||||
expect(comm.received_commands[0]).to match(/mount -t nfs/)
|
||||
expect(comm.received_commands[0]).to match(/1.2.3.4:\/host \/guest/)
|
||||
expect(comm.received_commands[1]).to match(/mount -t nfs/)
|
||||
expect(comm.received_commands[1]).to match(/1.2.3.4:\/host \/guest/)
|
||||
end
|
||||
|
||||
it "mounts with options" do
|
||||
|
@ -49,7 +48,7 @@ describe "VagrantPlugins::GuestBSD::Cap::NFS" do
|
|||
}
|
||||
cap.mount_nfs_folder(machine, ip, folders)
|
||||
|
||||
expect(comm.received_commands[0]).to match(/mount -t nfs -o 'nfsv2,mntudp,banana'/)
|
||||
expect(comm.received_commands[1]).to match(/mount -t nfs -o 'nfsv2,mntudp,banana'/)
|
||||
end
|
||||
|
||||
it "escapes host and guest paths" do
|
||||
|
@ -61,8 +60,8 @@ describe "VagrantPlugins::GuestBSD::Cap::NFS" do
|
|||
}
|
||||
cap.mount_nfs_folder(machine, ip, folders)
|
||||
|
||||
expect(comm.received_commands[0]).to match(/host\\\'s/)
|
||||
expect(comm.received_commands[0]).to match(/guest\\\ with\\\ spaces/)
|
||||
expect(comm.received_commands[1]).to match(/host\\\'s/)
|
||||
expect(comm.received_commands[1]).to match(/guest\\\ with\\\ spaces/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -43,7 +43,7 @@ describe "VagrantPlugins::GuestLinux::Cap::MountNFS" do
|
|||
cap.mount_nfs_folder(machine, ip, folders)
|
||||
|
||||
expect(comm.received_commands[0]).to match(/mkdir -p #{guestpath}/)
|
||||
expect(comm.received_commands[0]).to match(/1.2.3.4:#{hostpath} #{guestpath}/)
|
||||
expect(comm.received_commands[1]).to match(/1.2.3.4:#{hostpath} #{guestpath}/)
|
||||
end
|
||||
|
||||
it "mounts with options" do
|
||||
|
@ -58,7 +58,7 @@ describe "VagrantPlugins::GuestLinux::Cap::MountNFS" do
|
|||
}
|
||||
cap.mount_nfs_folder(machine, ip, folders)
|
||||
|
||||
expect(comm.received_commands[0]).to match(/mount -o vers=2,udp/)
|
||||
expect(comm.received_commands[1]).to match(/mount -o vers=2,udp/)
|
||||
end
|
||||
|
||||
it "emits an event" do
|
||||
|
@ -71,7 +71,7 @@ describe "VagrantPlugins::GuestLinux::Cap::MountNFS" do
|
|||
}
|
||||
cap.mount_nfs_folder(machine, ip, folders)
|
||||
|
||||
expect(comm.received_commands[0]).to include(
|
||||
expect(comm.received_commands[1]).to include(
|
||||
"/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{guestpath}")
|
||||
end
|
||||
|
||||
|
@ -84,8 +84,8 @@ describe "VagrantPlugins::GuestLinux::Cap::MountNFS" do
|
|||
}
|
||||
cap.mount_nfs_folder(machine, ip, folders)
|
||||
|
||||
expect(comm.received_commands[0]).to match(/host\\\'s/)
|
||||
expect(comm.received_commands[0]).to match(/guest\\\ with\\\ spaces/)
|
||||
expect(comm.received_commands[1]).to match(/host\\\'s/)
|
||||
expect(comm.received_commands[1]).to match(/guest\\\ with\\\ spaces/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -44,5 +44,41 @@ describe "VagrantPlugins::GuestLinux::Cap::NetworkInterfaces" do
|
|||
result = cap.network_interfaces(machine)
|
||||
expect(result).to eq(["enp0s3", "enp0s5", "enp0s8", "enp0s10", "enp1s3"])
|
||||
end
|
||||
|
||||
it "sorts ethernet devices discovered with classic naming first in list" do
|
||||
expect(comm).to receive(:sudo).and_yield(:stdout, "eth1\neth2\ndocker0\nbridge0\neth0")
|
||||
result = cap.network_interfaces(machine)
|
||||
expect(result).to eq(["eth0", "eth1", "eth2", "bridge0", "docker0"])
|
||||
end
|
||||
|
||||
it "sorts ethernet devices discovered with predictable network interfaces naming first in list" do
|
||||
expect(comm).to receive(:sudo).and_yield(:stdout, "enp0s8\ndocker0\nenp0s3\nbridge0\nenp0s5")
|
||||
result = cap.network_interfaces(machine)
|
||||
expect(result).to eq(["enp0s3", "enp0s5", "enp0s8", "bridge0", "docker0"])
|
||||
end
|
||||
|
||||
it "sorts ethernet devices discovered with predictable network interfaces naming first in list with less" do
|
||||
expect(comm).to receive(:sudo).and_yield(:stdout, "enp0s3\nenp0s8\ndocker0")
|
||||
result = cap.network_interfaces(machine)
|
||||
expect(result).to eq(["enp0s3", "enp0s8", "docker0"])
|
||||
end
|
||||
|
||||
it "does not include ethernet devices aliases within prefix device listing" do
|
||||
expect(comm).to receive(:sudo).and_yield(:stdout, "eth1\neth2\ndocker0\nbridge0\neth0\ndocker1\neth0:0")
|
||||
result = cap.network_interfaces(machine)
|
||||
expect(result).to eq(["eth0", "eth1", "eth2", "bridge0", "docker0", "docker1", "eth0:0"])
|
||||
end
|
||||
|
||||
it "does not include ethernet devices aliases within prefix device listing with dot separators" do
|
||||
expect(comm).to receive(:sudo).and_yield(:stdout, "eth1\neth2\ndocker0\nbridge0\neth0\ndocker1\neth0.1@eth0")
|
||||
result = cap.network_interfaces(machine)
|
||||
expect(result).to eq(["eth0", "eth1", "eth2", "bridge0", "docker0", "docker1", "eth0.1@eth0"])
|
||||
end
|
||||
|
||||
it "properly sorts non-consistent device name formats" do
|
||||
expect(comm).to receive(:sudo).and_yield(:stdout, "eth0\neth1\ndocker0\nveth437f7f9\nveth06b3e44\nveth8bb7081")
|
||||
result = cap.network_interfaces(machine)
|
||||
expect(result).to eq(["eth0", "eth1", "docker0", "veth8bb7081", "veth437f7f9", "veth06b3e44"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -70,15 +70,27 @@ describe "VagrantPlugins::GuestLinux::Cap::Rsync" do
|
|||
end
|
||||
|
||||
context "with excludes provided" do
|
||||
let(:excludes){ ["tmp", "state/*"] }
|
||||
let(:excludes){ ["tmp", "state/*", "path/with a/space"] }
|
||||
|
||||
it "ignores files that are excluded" do
|
||||
comm.expect_command(
|
||||
"find #{guest_directory} -path #{File.join(guest_directory, excludes.first)} -prune -o " \
|
||||
"-path #{File.join(guest_directory, excludes.last)} -prune -o '!' -type l -a '(' ! -user " \
|
||||
"#{owner} -or ! -group #{group} ')' -exec chown #{owner}:#{group} '{}' +"
|
||||
)
|
||||
# comm.expect_command(
|
||||
# "find #{guest_directory} -path #{Shellwords.escape(File.join(guest_directory, excludes.first))} -prune -o " \
|
||||
# "-path #{Shellwords.escape(File.join(guest_directory, excludes.last))} -prune -o '!' " \
|
||||
# "-path -type l -a '(' ! -user " \
|
||||
# "#{owner} -or ! -group #{group} ')' -exec chown #{owner}:#{group} '{}' +"
|
||||
# )
|
||||
cap.rsync_post(machine, options)
|
||||
excludes.each do |ex_path|
|
||||
expect(comm.received_commands.first).to include("-path #{Shellwords.escape(File.join(guest_directory, ex_path))} -prune")
|
||||
end
|
||||
end
|
||||
|
||||
it "properly escapes excluded directories" do
|
||||
cap.rsync_post(machine, options)
|
||||
exclude_with_space = excludes.detect{|ex| ex.include?(' ')}
|
||||
escaped_exclude_with_space = Shellwords.escape(exclude_with_space)
|
||||
expect(comm.received_commands.first).not_to include(exclude_with_space)
|
||||
expect(comm.received_commands.first).to include(escaped_exclude_with_space)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
require_relative "../../../../base"
|
||||
|
||||
describe "VagrantPlugins::GuestOpenBSD::Cap::RSync" do
|
||||
let(:caps) do
|
||||
VagrantPlugins::GuestOpenBSD::Plugin
|
||||
.components
|
||||
.guest_capabilities[:openbsd]
|
||||
end
|
||||
|
||||
let(:machine) { double("machine") }
|
||||
let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
|
||||
|
||||
before do
|
||||
allow(machine).to receive(:communicate).and_return(comm)
|
||||
end
|
||||
|
||||
after do
|
||||
comm.verify_expectations!
|
||||
end
|
||||
|
||||
describe ".rsync_install" do
|
||||
let(:cap) { caps.get(:rsync_install) }
|
||||
|
||||
describe "successful installation" do
|
||||
it "installs rsync" do
|
||||
cap.rsync_install(machine)
|
||||
expect(comm.received_commands[0]).to match(/pkg_add -I rsync/)
|
||||
expect(comm.received_commands[1]).to match(/pkg_info/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "failure installation" do
|
||||
before do
|
||||
expect(comm).to receive(:execute).and_raise(Vagrant::Errors::RSyncNotInstalledInGuest, {command: '', output: ''})
|
||||
end
|
||||
|
||||
it "raises custom exception" do
|
||||
expect{ cap.rsync_install(machine) }.to raise_error(Vagrant::Errors::RSyncNotInstalledInGuest)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".rsync_installed" do
|
||||
let(:cap) { caps.get(:rsync_installed) }
|
||||
|
||||
it "checks if rsync is installed" do
|
||||
comm.expect_command("which rsync")
|
||||
cap.rsync_installed(machine)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".rsync_command" do
|
||||
let(:cap) { caps.get(:rsync_command) }
|
||||
|
||||
it "defaults to 'sudo rsync'" do
|
||||
expect(cap.rsync_command(machine)).to eq("sudo rsync")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -45,7 +45,7 @@ describe "VagrantPlugins::GuestPhoton::Cap:ConfigureNetworks" do
|
|||
it "creates and starts the networks" do
|
||||
cap.configure_networks(machine, [network_1, network_2])
|
||||
expect(comm.received_commands[1]).to match(/ifconfig eth1/)
|
||||
expect(comm.received_commands[1]).to match(/ifconfig eth2 33.33.33.10 netmast 255.255.0.0/)
|
||||
expect(comm.received_commands[1]).to match(/ifconfig eth2 33.33.33.10 netmask 255.255.0.0/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,9 +56,10 @@ describe "VagrantPlugins::GuestRedHat::Cap::ConfigureNetworks" do
|
|||
|
||||
cap.configure_networks(machine, [network_1, network_2])
|
||||
expect(comm.received_commands[0]).to match(/\/sbin\/ifdown 'eth1'/)
|
||||
expect(comm.received_commands[0]).to match(/\/sbin\/ifup 'eth1'/)
|
||||
expect(comm.received_commands[0]).to match(/ifcfg-eth1/)
|
||||
expect(comm.received_commands[0]).to match(/\/sbin\/ifdown 'eth2'/)
|
||||
expect(comm.received_commands[0]).to match(/\/sbin\/ifup 'eth2'/)
|
||||
expect(comm.received_commands[0]).to match(/ifcfg-eth2/)
|
||||
expect(comm.received_commands[0]).to match(/nmcli c reload/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
require_relative "../../../../base"
|
||||
require_relative "../../../../../../plugins/hosts/linux/cap/nfs"
|
||||
require_relative "../../../../../../lib/vagrant/util"
|
||||
|
||||
describe VagrantPlugins::HostLinux::Cap::NFS do
|
||||
|
||||
include_context "unit"
|
||||
|
||||
let(:caps) do
|
||||
VagrantPlugins::HostLinux::Plugin
|
||||
.components
|
||||
.host_capabilities[:linux]
|
||||
end
|
||||
|
||||
let(:tmp_exports_path) do
|
||||
@tmp_exports ||= temporary_file
|
||||
end
|
||||
let(:exports_path){ VagrantPlugins::HostLinux::Cap::NFS::NFS_EXPORTS_PATH }
|
||||
let(:env){ double(:env) }
|
||||
let(:ui){ double(:ui) }
|
||||
let(:host){ double(:host) }
|
||||
|
||||
before do
|
||||
@original_exports_path = VagrantPlugins::HostLinux::Cap::NFS::NFS_EXPORTS_PATH
|
||||
VagrantPlugins::HostLinux::Cap::NFS.send(:remove_const, :NFS_EXPORTS_PATH)
|
||||
VagrantPlugins::HostLinux::Cap::NFS.const_set(:NFS_EXPORTS_PATH, tmp_exports_path.to_s)
|
||||
end
|
||||
|
||||
after do
|
||||
VagrantPlugins::HostLinux::Cap::NFS.send(:remove_const, :NFS_EXPORTS_PATH)
|
||||
VagrantPlugins::HostLinux::Cap::NFS.const_set(:NFS_EXPORTS_PATH, @original_exports_path)
|
||||
File.unlink(tmp_exports_path.to_s) if File.exist?(tmp_exports_path.to_s)
|
||||
@tmp_exports = nil
|
||||
end
|
||||
|
||||
describe ".nfs_export" do
|
||||
|
||||
let(:cap){ caps.get(:nfs_export) }
|
||||
|
||||
before do
|
||||
allow(env).to receive(:host).and_return(host)
|
||||
allow(host).to receive(:capability).with(:nfs_apply_command).and_return("/bin/true")
|
||||
allow(host).to receive(:capability).with(:nfs_check_command).and_return("/bin/true")
|
||||
allow(host).to receive(:capability).with(:nfs_start_command).and_return("/bin/true")
|
||||
allow(ui).to receive(:info)
|
||||
allow(cap).to receive(:system).with("sudo /bin/true").and_return(true)
|
||||
allow(cap).to receive(:system).with("/bin/true").and_return(true)
|
||||
end
|
||||
|
||||
it "should export new entries" do
|
||||
cap.nfs_export(env, ui, SecureRandom.uuid, ["127.0.0.1"], "tmp" => {:hostpath => "/tmp"})
|
||||
exports_content = File.read(exports_path)
|
||||
expect(exports_content).to match(/\/tmp.*127\.0\.0\.1/)
|
||||
end
|
||||
|
||||
it "should not remove existing entries" do
|
||||
File.write(exports_path, "/custom/directory hostname1(rw,sync,no_subtree_check)")
|
||||
cap.nfs_export(env, ui, SecureRandom.uuid, ["127.0.0.1"], "tmp" => {:hostpath => "/tmp"})
|
||||
exports_content = File.read(exports_path)
|
||||
expect(exports_content).to match(/\/tmp.*127\.0\.0\.1/)
|
||||
expect(exports_content).to match(/\/custom\/directory.*hostname1/)
|
||||
end
|
||||
|
||||
it "should remove entries no longer valid" do
|
||||
valid_id = SecureRandom.uuid
|
||||
other_id = SecureRandom.uuid
|
||||
content =<<-EOH
|
||||
# VAGRANT-BEGIN: #{Process.uid} #{other_id}
|
||||
"/tmp" 127.0.0.1(rw,no_subtree_check,all_squash,anonuid=,anongid=,fsid=)
|
||||
# VAGRANT-END: #{Process.uid} #{other_id}
|
||||
# VAGRANT-BEGIN: #{Process.uid} #{valid_id}
|
||||
"/var" 127.0.0.1(rw,no_subtree_check,all_squash,anonuid=,anongid=,fsid=)
|
||||
# VAGRANT-END: #{Process.uid} #{valid_id}
|
||||
EOH
|
||||
File.write(exports_path, content)
|
||||
cap.nfs_export(env, ui, valid_id, ["127.0.0.1"], "home" => {:hostpath => "/home"})
|
||||
exports_content = File.read(exports_path)
|
||||
expect(exports_content).to include("/home")
|
||||
expect(exports_content).to include("/tmp")
|
||||
expect(exports_content).not_to include("/var")
|
||||
end
|
||||
end
|
||||
|
||||
describe ".nfs_prune" do
|
||||
|
||||
let(:cap){ caps.get(:nfs_prune) }
|
||||
|
||||
before do
|
||||
allow(ui).to receive(:info)
|
||||
end
|
||||
|
||||
it "should remove entries no longer valid" do
|
||||
invalid_id = SecureRandom.uuid
|
||||
valid_id = SecureRandom.uuid
|
||||
content =<<-EOH
|
||||
# VAGRANT-BEGIN: #{Process.uid} #{invalid_id}
|
||||
"/tmp" 127.0.0.1(rw,no_subtree_check,all_squash,anonuid=,anongid=,fsid=)
|
||||
# VAGRANT-END: #{Process.uid} #{invalid_id}
|
||||
# VAGRANT-BEGIN: #{Process.uid} #{valid_id}
|
||||
"/var" 127.0.0.1(rw,no_subtree_check,all_squash,anonuid=,anongid=,fsid=)
|
||||
# VAGRANT-END: #{Process.uid} #{valid_id}
|
||||
EOH
|
||||
File.write(exports_path, content)
|
||||
cap.nfs_prune(env, ui, [valid_id])
|
||||
exports_content = File.read(exports_path)
|
||||
expect(exports_content).to include(valid_id)
|
||||
expect(exports_content).not_to include(invalid_id)
|
||||
expect(exports_content).to include("/var")
|
||||
expect(exports_content).not_to include("/tmp")
|
||||
end
|
||||
end
|
||||
|
||||
describe ".nfs_write_exports" do
|
||||
|
||||
before do
|
||||
File.write(tmp_exports_path, "original content")
|
||||
end
|
||||
|
||||
it "should write updated contents to file" do
|
||||
described_class.nfs_write_exports("new content")
|
||||
exports_content = File.read(exports_path)
|
||||
expect(exports_content).to include("new content")
|
||||
expect(exports_content).not_to include("original content")
|
||||
end
|
||||
|
||||
it "should only update contents if different" do
|
||||
original_stat = File.stat(exports_path)
|
||||
described_class.nfs_write_exports("original content")
|
||||
updated_stat = File.stat(exports_path)
|
||||
expect(original_stat).to eq(updated_stat)
|
||||
end
|
||||
|
||||
it "should retain existing file permissions" do
|
||||
File.chmod(0600, exports_path)
|
||||
original_stat = File.stat(exports_path)
|
||||
described_class.nfs_write_exports("original content")
|
||||
updated_stat = File.stat(exports_path)
|
||||
expect(original_stat.mode).to eq(updated_stat.mode)
|
||||
end
|
||||
|
||||
it "should raise exception when failing to move new exports file" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).and_return(
|
||||
Vagrant::Util::Subprocess::Result.new(1, "Failed to move file", "")
|
||||
)
|
||||
expect{ described_class.nfs_write_exports("new content") }.to raise_error(Vagrant::Errors::NFSExportsFailed)
|
||||
end
|
||||
|
||||
it "should retain existing file owner and group IDs" do
|
||||
pending("investigate using a simulated FS to test")
|
||||
end
|
||||
|
||||
it "should raise custom exception when chown fails" do
|
||||
pending("investigate using a simulated FS to test")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -133,6 +133,14 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
|
|||
|
||||
assert_valid
|
||||
end
|
||||
|
||||
["1", 1, "1.0", 1.0].each do |valid|
|
||||
it "is valid: #{valid}" do
|
||||
subject.box_version = valid
|
||||
subject.finalize!
|
||||
assert_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#communicator" do
|
||||
|
@ -526,6 +534,21 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
|
|||
subject.finalize!
|
||||
assert_valid
|
||||
end
|
||||
|
||||
it "allows providing custom name via options" do
|
||||
subject.synced_folder(".", "/vagrant", name: "my-vagrant-folder")
|
||||
sf = subject.synced_folders
|
||||
expect(sf).to have_key("my-vagrant-folder")
|
||||
expect(sf["my-vagrant-folder"][:guestpath]).to eq("/vagrant")
|
||||
expect(sf["my-vagrant-folder"][:hostpath]).to eq(".")
|
||||
end
|
||||
|
||||
it "allows providing custom name without guest path" do
|
||||
subject.synced_folder(".", name: "my-vagrant-folder")
|
||||
sf = subject.synced_folders
|
||||
expect(sf).to have_key("my-vagrant-folder")
|
||||
expect(sf["my-vagrant-folder"][:hostpath]).to eq(".")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#usable_port_range" do
|
||||
|
|
|
@ -16,7 +16,8 @@ describe VagrantPlugins::Ansible::Config::Guest do
|
|||
let(:existing_file) { "this/path/is/a/stub" }
|
||||
|
||||
it "supports a list of options" do
|
||||
supported_options = %w( extra_vars
|
||||
supported_options = %w( config_file
|
||||
extra_vars
|
||||
galaxy_command
|
||||
galaxy_role_file
|
||||
galaxy_roles_path
|
||||
|
@ -27,6 +28,7 @@ describe VagrantPlugins::Ansible::Config::Guest do
|
|||
inventory_path
|
||||
limit
|
||||
playbook
|
||||
playbook_command
|
||||
provisioning_path
|
||||
raw_arguments
|
||||
skip_tags
|
||||
|
|
|
@ -15,6 +15,7 @@ describe VagrantPlugins::Ansible::Config::Host, :skip_windows => true do
|
|||
it "supports a list of options" do
|
||||
supported_options = %w( ask_sudo_pass
|
||||
ask_vault_pass
|
||||
config_file
|
||||
extra_vars
|
||||
force_remote_user
|
||||
galaxy_command
|
||||
|
@ -26,6 +27,7 @@ describe VagrantPlugins::Ansible::Config::Host, :skip_windows => true do
|
|||
inventory_path
|
||||
limit
|
||||
playbook
|
||||
playbook_command
|
||||
raw_arguments
|
||||
raw_ssh_args
|
||||
skip_tags
|
||||
|
@ -63,7 +65,7 @@ describe VagrantPlugins::Ansible::Config::Host, :skip_windows => true do
|
|||
it_behaves_like "any VagrantConfigProvisioner strict boolean attribute", :ask_sudo_pass, false
|
||||
end
|
||||
describe "ask_vault_pass option" do
|
||||
it_behaves_like "any VagrantConfigProvisioner strict boolean attribute", :ask_sudo_pass, false
|
||||
it_behaves_like "any VagrantConfigProvisioner strict boolean attribute", :ask_vault_pass, false
|
||||
end
|
||||
|
||||
describe "#validate" do
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue