From 5a7e00c5b1deffa3329c43c9c22186cd6d49991e Mon Sep 17 00:00:00 2001
From: Ray Ruvinskiy
Date: Sun, 7 Sep 2014 23:45:32 -0400
Subject: [PATCH 001/484] Add HTTPS download options to `box update` and `box
outdated`
Vagrant::Box.load_metadata did not provide a way to specify the HTTPS
download options that could be specified when downloading boxes
(ca cert, ca path, client cert, insecure). As a result, while it was
possible to add a box whose metadata file needed to be downloaded with one of
those options specified, it was impossible to check for updates. The following
changes have been made to address the situation:
1. Create a DownloadMixins module to provide the --insecure, --cacert, --capth,
and --cert command line options to all of `vagrant box add`,
`vagrant box update`, and `vagrant box outdated`.
2. Extend `Vagrant::Box.has_update?` and `Vagrant::Box.load_metadata` to accept
said download options.
3. Extend `box outdated` and `box update` commands to pass download options
down.
4. Extend `Vagrant::Builtin::Action::BoxCheckOutdated` to honour download
options.
5. Options specified on the command line take precedence over options specified
in the machine configuration, if any.
6. Fix bug in `vagrant box add` where client cert was being passed down using
the wrong environment key.
7. Unit test coverage in update_test and box_check_outdated_test.
Resolves #4420
---
.../action/builtin/box_check_outdated.rb | 12 +-
lib/vagrant/box.rb | 9 +-
plugins/commands/box/command/add.rb | 23 +--
.../commands/box/command/download_mixins.rb | 29 +++
plugins/commands/box/command/outdated.rb | 15 +-
plugins/commands/box/command/update.rb | 35 +++-
.../commands/box/command/update_test.rb | 184 ++++++++++++++----
.../action/builtin/box_check_outdated_test.rb | 37 +++-
8 files changed, 275 insertions(+), 69 deletions(-)
create mode 100644 plugins/commands/box/command/download_mixins.rb
diff --git a/lib/vagrant/action/builtin/box_check_outdated.rb b/lib/vagrant/action/builtin/box_check_outdated.rb
index cee8c6877..d39afd272 100644
--- a/lib/vagrant/action/builtin/box_check_outdated.rb
+++ b/lib/vagrant/action/builtin/box_check_outdated.rb
@@ -37,13 +37,23 @@ module Vagrant
end
constraints = machine.config.vm.box_version
+ # Have download options specified in the environment override
+ # options specified for the machine.
+ download_options = {
+ ca_cert: env[:ca_cert] || machine.config.vm.box_download_ca_cert,
+ ca_path: env[:ca_path] || machine.config.vm.box_download_ca_path,
+ client_cert: env[:client_cert] ||
+ machine.config.vm.box_download_client_cert,
+ insecure: !env[:insecure].nil? ?
+ env[:insecure] : machine.config.vm.box_download_insecure
+ }
env[:ui].output(I18n.t(
"vagrant.box_outdated_checking_with_refresh",
name: box.name))
update = nil
begin
- update = box.has_update?(constraints)
+ update = box.has_update?(constraints, download_options: download_options)
rescue Errors::BoxMetadataDownloadError => e
env[:ui].warn(I18n.t(
"vagrant.box_outdated_metadata_download_error",
diff --git a/lib/vagrant/box.rb b/lib/vagrant/box.rb
index 537c94e2a..045b22fd3 100644
--- a/lib/vagrant/box.rb
+++ b/lib/vagrant/box.rb
@@ -115,8 +115,9 @@ module Vagrant
# Loads the metadata URL and returns the latest metadata associated
# with this box.
#
+ # @param [Hash] download_options Options to pass to the downloader.
# @return [BoxMetadata]
- def load_metadata
+ def load_metadata(**download_options)
tf = Tempfile.new("vagrant")
tf.close
@@ -127,7 +128,7 @@ module Vagrant
url = "file:#{url}"
end
- opts = { headers: ["Accept: application/json"] }
+ opts = { headers: ["Accept: application/json"] }.merge(download_options)
Util::Downloader.new(url, tf.path, **opts).download!
BoxMetadata.new(File.open(tf.path, "r"))
rescue Errors::DownloaderError => e
@@ -148,7 +149,7 @@ module Vagrant
# satisfy. If nil, the version constrain defaults to being a
# larger version than this box.
# @return [Array]
- def has_update?(version=nil)
+ def has_update?(version=nil, download_options: {})
if !@metadata_url
raise Errors::BoxUpdateNoMetadata, name: @name
end
@@ -156,7 +157,7 @@ module Vagrant
version += ", " if version
version ||= ""
version += "> #{@version}"
- md = self.load_metadata
+ md = self.load_metadata(download_options)
newer = md.version(version, provider: @provider)
return nil if !newer
diff --git a/plugins/commands/box/command/add.rb b/plugins/commands/box/command/add.rb
index 0356ee298..e9d429433 100644
--- a/plugins/commands/box/command/add.rb
+++ b/plugins/commands/box/command/add.rb
@@ -1,9 +1,13 @@
require 'optparse'
+require_relative 'download_mixins'
+
module VagrantPlugins
module CommandBox
module Command
class Add < Vagrant.plugin("2", :command)
+ include DownloadMixins
+
def execute
options = {}
@@ -21,22 +25,7 @@ module VagrantPlugins
options[:force] = f
end
- o.on("--insecure", "Do not validate SSL certificates") do |i|
- options[:insecure] = i
- end
-
- o.on("--cacert FILE", String, "CA certificate for SSL download") do |c|
- options[:ca_cert] = c
- end
-
- o.on("--capath DIR", String, "CA certificate directory for SSL download") do |c|
- options[:ca_path] = c
- end
-
- o.on("--cert FILE", String,
- "A client SSL cert, if needed") do |c|
- options[:client_cert] = c
- end
+ build_download_options(o, options)
o.on("--provider PROVIDER", String, "Provider the box should satisfy") do |p|
options[:provider] = p
@@ -93,7 +82,7 @@ module VagrantPlugins
box_force: options[:force],
box_download_ca_cert: options[:ca_cert],
box_download_ca_path: options[:ca_path],
- box_download_client_cert: options[:client_cert],
+ box_client_cert: options[:client_cert],
box_download_insecure: options[:insecure],
ui: Vagrant::UI::Prefixed.new(@env.ui, "box"),
})
diff --git a/plugins/commands/box/command/download_mixins.rb b/plugins/commands/box/command/download_mixins.rb
new file mode 100644
index 000000000..eda31b6bf
--- /dev/null
+++ b/plugins/commands/box/command/download_mixins.rb
@@ -0,0 +1,29 @@
+module VagrantPlugins
+ module CommandBox
+ module DownloadMixins
+ # This adds common download command line flags to the given
+ # OptionParser, storing the result in the `options` dictionary.
+ #
+ # @param [OptionParser] parser
+ # @param [Hash] options
+ def build_download_options(parser, options)
+ # Add the options
+ parser.on("--insecure", "Do not validate SSL certificates") do |i|
+ options[:insecure] = i
+ end
+
+ parser.on("--cacert FILE", String, "CA certificate for SSL download") do |c|
+ options[:ca_cert] = c
+ end
+
+ parser.on("--capath DIR", String, "CA certificate directory for SSL download") do |c|
+ options[:ca_path] = c
+ end
+
+ parser.on("--cert FILE", String, "A client SSL cert, if needed") do |c|
+ options[:client_cert] = c
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/box/command/outdated.rb b/plugins/commands/box/command/outdated.rb
index a686fa496..cde932e1a 100644
--- a/plugins/commands/box/command/outdated.rb
+++ b/plugins/commands/box/command/outdated.rb
@@ -1,11 +1,16 @@
require 'optparse'
+require_relative 'download_mixins'
+
module VagrantPlugins
module CommandBox
module Command
class Outdated < Vagrant.plugin("2", :command)
+ include DownloadMixins
+
def execute
options = {}
+ download_options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant box outdated [options]"
@@ -20,6 +25,8 @@ module VagrantPlugins
o.on("--global", "Check all boxes installed") do |g|
options[:global] = g
end
+
+ build_download_options(o, download_options)
end
argv = parse_options(opts)
@@ -27,7 +34,7 @@ module VagrantPlugins
# If we're checking the boxes globally, then do that.
if options[:global]
- outdated_global
+ outdated_global(download_options)
return 0
end
@@ -37,11 +44,11 @@ module VagrantPlugins
box_outdated_refresh: true,
box_outdated_success_ui: true,
machine: machine,
- })
+ }.merge(download_options))
end
end
- def outdated_global
+ def outdated_global(download_options)
boxes = {}
@env.boxes.all.reverse.each do |name, version, provider|
next if boxes[name]
@@ -58,7 +65,7 @@ module VagrantPlugins
md = nil
begin
- md = box.load_metadata
+ md = box.load_metadata(download_options)
rescue Vagrant::Errors::DownloaderError => e
@env.ui.error(I18n.t(
"vagrant.box_outdated_metadata_error",
diff --git a/plugins/commands/box/command/update.rb b/plugins/commands/box/command/update.rb
index 5633b0aaf..67d07bcc0 100644
--- a/plugins/commands/box/command/update.rb
+++ b/plugins/commands/box/command/update.rb
@@ -1,11 +1,16 @@
require 'optparse'
+require_relative 'download_mixins'
+
module VagrantPlugins
module CommandBox
module Command
class Update < Vagrant.plugin("2", :command)
+ include DownloadMixins
+
def execute
options = {}
+ download_options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant box update [options]"
@@ -27,21 +32,23 @@ module VagrantPlugins
o.on("--provider PROVIDER", String, "Update box with specific provider") do |p|
options[:provider] = p.to_sym
end
+
+ build_download_options(o, download_options)
end
argv = parse_options(opts)
return if !argv
if options[:box]
- update_specific(options[:box], options[:provider])
+ update_specific(options[:box], options[:provider], download_options)
else
- update_vms(argv, options[:provider])
+ update_vms(argv, options[:provider], download_options)
end
0
end
- def update_specific(name, provider)
+ def update_specific(name, provider, download_options)
boxes = {}
@env.boxes.all.each do |n, v, p|
boxes[n] ||= {}
@@ -74,11 +81,11 @@ module VagrantPlugins
to_update.each do |n, p, v|
box = @env.boxes.find(n, p, v)
- box_update(box, "> #{v}", @env.ui)
+ box_update(box, "> #{v}", @env.ui, download_options)
end
end
- def update_vms(argv, provider)
+ def update_vms(argv, provider, download_options)
with_target_vms(argv, provider: provider) do |machine|
if !machine.config.vm.box
machine.ui.output(I18n.t(
@@ -95,17 +102,25 @@ module VagrantPlugins
box = machine.box
version = machine.config.vm.box_version
- box_update(box, version, machine.ui)
+ # Get download options from machine configuration if not specified
+ # on the command line.
+ download_options[:ca_cert] ||= machine.config.vm.box_download_ca_cert
+ download_options[:ca_path] ||= machine.config.vm.box_download_ca_path
+ download_options[:client_cert] ||= machine.config.vm.box_download_client_cert
+ if download_options[:insecure].nil?
+ download_options[:insecure] = machine.config.vm.box_download_insecure
+ end
+ box_update(box, version, machine.ui, download_options)
end
end
- def box_update(box, version, ui)
+ def box_update(box, version, ui, download_options)
ui.output(I18n.t("vagrant.box_update_checking", name: box.name))
ui.detail("Latest installed version: #{box.version}")
ui.detail("Version constraints: #{version}")
ui.detail("Provider: #{box.provider}")
- update = box.has_update?(version)
+ update = box.has_update?(version, download_options: download_options)
if !update
ui.success(I18n.t(
"vagrant.box_up_to_date_single",
@@ -124,6 +139,10 @@ module VagrantPlugins
box_provider: update[2].name,
box_version: update[1].version,
ui: ui,
+ box_client_cert: download_options[:client_cert],
+ box_download_ca_cert: download_options[:ca_cert],
+ box_download_ca_path: download_options[:ca_path],
+ box_download_insecure: download_options[:insecure]
})
end
end
diff --git a/test/unit/plugins/commands/box/command/update_test.rb b/test/unit/plugins/commands/box/command/update_test.rb
index 4477d0aa5..067d0dd35 100644
--- a/test/unit/plugins/commands/box/command/update_test.rb
+++ b/test/unit/plugins/commands/box/command/update_test.rb
@@ -19,6 +19,11 @@ describe VagrantPlugins::CommandBox::Command::Update do
let(:action_runner) { double("action_runner") }
let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
+ let(:download_options) { ["--insecure",
+ "--cacert", "foo",
+ "--capath", "bar",
+ "--cert", "baz"] }
+
subject { described_class.new(argv, iso_env) }
before do
@@ -86,6 +91,10 @@ describe VagrantPlugins::CommandBox::Command::Update do
expect(opts[:box_url]).to eq(metadata_url.to_s)
expect(opts[:box_provider]).to eq("virtualbox")
expect(opts[:box_version]).to eq("1.1")
+ expect(opts[:box_download_ca_path]).to be_nil
+ expect(opts[:box_download_ca_cert]).to be_nil
+ expect(opts[:box_client_cert]).to be_nil
+ expect(opts[:box_download_insecure]).to be_nil
end
opts
@@ -158,6 +167,50 @@ describe VagrantPlugins::CommandBox::Command::Update do
end
end
+ context "download options are specified" do
+ let(:argv) { ["--box", "foo" ].concat(download_options) }
+
+ it "passes down download options" do
+ metadata_url.open("w") do |f|
+ f.write(<<-RAW)
+ {
+ "name": "foo",
+ "versions": [
+ {
+ "version": "1.0"
+ },
+ {
+ "version": "1.1",
+ "providers": [
+ {
+ "name": "virtualbox",
+ "url": "bar"
+ }
+ ]
+ }
+ ]
+ }
+ RAW
+ end
+
+ action_called = false
+ allow(action_runner).to receive(:run) do |action, opts|
+ if opts[:box_provider]
+ action_called = true
+ expect(opts[:box_download_ca_cert]).to eq("foo")
+ expect(opts[:box_download_ca_path]).to eq("bar")
+ expect(opts[:box_client_cert]).to eq("baz")
+ expect(opts[:box_download_insecure]).to be_true
+ end
+
+ opts
+ end
+
+ subject.execute
+ expect(action_called).to be_true
+ end
+ end
+
context "with a box that doesn't exist" do
let(:argv) { ["--box", "nope"] }
@@ -192,7 +245,10 @@ describe VagrantPlugins::CommandBox::Command::Update do
it "doesn't update boxes if they're up-to-date" do
machine.stub(box: box)
expect(box).to receive(:has_update?).
- with(machine.config.vm.box_version).
+ with(machine.config.vm.box_version,
+ {download_options:
+ {ca_cert: nil, ca_path: nil, client_cert: nil,
+ insecure: false}}).
and_return(nil)
expect(action_runner).to receive(:run).never
@@ -200,41 +256,101 @@ describe VagrantPlugins::CommandBox::Command::Update do
subject.execute
end
- it "updates boxes if they have an update" do
- md = Vagrant::BoxMetadata.new(StringIO.new(<<-RAW))
- {
- "name": "foo",
- "versions": [
- {
- "version": "1.0"
- },
- {
- "version": "1.1",
- "providers": [
- {
- "name": "virtualbox",
- "url": "bar"
- }
- ]
- }
- ]
- }
- RAW
-
- machine.stub(box: box)
- expect(box).to receive(:has_update?).
- with(machine.config.vm.box_version).
- and_return([md, md.version("1.1"), md.version("1.1").provider("virtualbox")])
-
- expect(action_runner).to receive(:run).with { |action, opts|
- expect(opts[:box_url]).to eq(box.metadata_url)
- expect(opts[:box_provider]).to eq("virtualbox")
- expect(opts[:box_version]).to eq("1.1")
- expect(opts[:ui]).to equal(machine.ui)
- true
+ context "boxes have an update" do
+ let(:md) {
+ md = Vagrant::BoxMetadata.new(StringIO.new(<<-RAW))
+ {
+ "name": "foo",
+ "versions": [
+ {
+ "version": "1.0"
+ },
+ {
+ "version": "1.1",
+ "providers": [
+ {
+ "name": "virtualbox",
+ "url": "bar"
+ }
+ ]
+ }
+ ]
+ }
+ RAW
}
- subject.execute
+ before { machine.stub(box: box) }
+
+ it "updates boxes" do
+ expect(box).to receive(:has_update?).
+ with(machine.config.vm.box_version,
+ {download_options:
+ {ca_cert: nil, ca_path: nil, client_cert: nil,
+ insecure: false}}).
+ and_return([md, md.version("1.1"), md.version("1.1").provider("virtualbox")])
+
+ expect(action_runner).to receive(:run).with { |action, opts|
+ expect(opts[:box_url]).to eq(box.metadata_url)
+ expect(opts[:box_provider]).to eq("virtualbox")
+ expect(opts[:box_version]).to eq("1.1")
+ expect(opts[:ui]).to equal(machine.ui)
+ true
+ }
+
+ subject.execute
+ end
+
+ context "machine has download options" do
+ before do
+ machine.config.vm.box_download_ca_cert = "oof"
+ machine.config.vm.box_download_ca_path = "rab"
+ machine.config.vm.box_download_client_cert = "zab"
+ machine.config.vm.box_download_insecure = false
+ end
+
+ it "uses download options from machine" do
+ expect(box).to receive(:has_update?).
+ with(machine.config.vm.box_version,
+ {download_options:
+ {ca_cert: "oof", ca_path: "rab", client_cert: "zab",
+ insecure: false}}).
+ and_return([md, md.version("1.1"), md.version("1.1").provider("virtualbox")])
+
+ expect(action_runner).to receive(:run).with { |action, opts|
+ expect(opts[:box_download_ca_cert]).to eq("oof")
+ expect(opts[:box_download_ca_path]).to eq("rab")
+ expect(opts[:box_client_cert]).to eq("zab")
+ expect(opts[:box_download_insecure]).to be_false
+ true
+ }
+
+ subject.execute
+ end
+
+ context "download options are specified on the command line" do
+ let(:argv) { download_options }
+
+ it "overrides download options from machine with options from CLI" do
+ expect(box).to receive(:has_update?).
+ with(machine.config.vm.box_version,
+ {download_options:
+ {ca_cert: "foo", ca_path: "bar", client_cert: "baz",
+ insecure: true}}).
+ and_return([md, md.version("1.1"),
+ md.version("1.1").provider("virtualbox")])
+
+ expect(action_runner).to receive(:run).with { |action, opts|
+ expect(opts[:box_download_ca_cert]).to eq("foo")
+ expect(opts[:box_download_ca_path]).to eq("bar")
+ expect(opts[:box_client_cert]).to eq("baz")
+ expect(opts[:box_download_insecure]).to be_true
+ true
+ }
+
+ subject.execute
+ end
+ end
+ end
end
end
end
diff --git a/test/unit/vagrant/action/builtin/box_check_outdated_test.rb b/test/unit/vagrant/action/builtin/box_check_outdated_test.rb
index bcb313d1c..0bb175c59 100644
--- a/test/unit/vagrant/action/builtin/box_check_outdated_test.rb
+++ b/test/unit/vagrant/action/builtin/box_check_outdated_test.rb
@@ -117,7 +117,9 @@ describe Vagrant::Action::Builtin::BoxCheckOutdated do
}
RAW
- expect(box).to receive(:has_update?).with(machine.config.vm.box_version).
+ expect(box).to receive(:has_update?).with(machine.config.vm.box_version,
+ {download_options:
+ {ca_cert: nil, ca_path: nil, client_cert: nil, insecure: false}}).
and_return([md, md.version("1.1"), md.version("1.1").provider("virtualbox")])
expect(app).to receive(:call).with(env).once
@@ -180,5 +182,38 @@ describe Vagrant::Action::Builtin::BoxCheckOutdated do
expect { subject.call(env) }.to_not raise_error
end
+
+ context "when machine download options are specified" do
+ before do
+ machine.config.vm.box_download_ca_cert = "foo"
+ machine.config.vm.box_download_ca_path = "bar"
+ machine.config.vm.box_download_client_cert = "baz"
+ machine.config.vm.box_download_insecure = true
+ end
+
+ it "uses download options from machine" do
+ expect(box).to receive(:has_update?).with(machine.config.vm.box_version,
+ {download_options:
+ {ca_cert: "foo", ca_path: "bar", client_cert: "baz", insecure: true}})
+
+ expect(app).to receive(:call).with(env).once
+
+ subject.call(env)
+ end
+
+ it "overrides download options from machine with options from env" do
+ expect(box).to receive(:has_update?).with(machine.config.vm.box_version,
+ {download_options:
+ {ca_cert: "oof", ca_path: "rab", client_cert: "zab", insecure: false}})
+
+ env[:ca_cert] = "oof"
+ env[:ca_path] = "rab"
+ env[:client_cert] = "zab"
+ env[:insecure] = false
+ expect(app).to receive(:call).with(env).once
+
+ subject.call(env)
+ end
+ end
end
end
From c20624bfdc71e1d9bbc85ca8bfbbbac0fd0bf2c1 Mon Sep 17 00:00:00 2001
From: mpoeter
Date: Tue, 9 Sep 2014 19:17:04 +0200
Subject: [PATCH 002/484] Add support for linked clones for VirtualBox.
---
lib/vagrant/errors.rb | 8 +++
plugins/providers/virtualbox/action.rb | 10 ++-
.../virtualbox/action/create_clone.rb | 51 +++++++++++++++
.../virtualbox/action/import_master.rb | 62 +++++++++++++++++++
plugins/providers/virtualbox/config.rb | 10 +++
plugins/providers/virtualbox/driver/meta.rb | 2 +
.../virtualbox/driver/version_4_3.rb | 25 ++++++--
templates/locales/en.yml | 8 +++
8 files changed, 171 insertions(+), 5 deletions(-)
create mode 100644 plugins/providers/virtualbox/action/create_clone.rb
create mode 100644 plugins/providers/virtualbox/action/import_master.rb
diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb
index 8995f6505..b4a609aa1 100644
--- a/lib/vagrant/errors.rb
+++ b/lib/vagrant/errors.rb
@@ -740,6 +740,14 @@ module Vagrant
error_key(:boot_timeout)
end
+ class VMCloneFailure < VagrantError
+ error_key(:failure, "vagrant.actions.vm.clone")
+ end
+
+ class VMCreateMasterFailure < VagrantError
+ error_key(:failure, "vagrant.actions.vm.clone.create_master")
+ end
+
class VMCustomizationFailed < VagrantError
error_key(:failure, "vagrant.actions.vm.customize")
end
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 668cbe0ef..b0051ce3d 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -12,6 +12,7 @@ module VagrantPlugins
autoload :CleanMachineFolder, File.expand_path("../action/clean_machine_folder", __FILE__)
autoload :ClearForwardedPorts, File.expand_path("../action/clear_forwarded_ports", __FILE__)
autoload :ClearNetworkInterfaces, File.expand_path("../action/clear_network_interfaces", __FILE__)
+ autoload :CreateClone, File.expand_path("../action/create_clone", __FILE__)
autoload :Created, File.expand_path("../action/created", __FILE__)
autoload :Customize, File.expand_path("../action/customize", __FILE__)
autoload :Destroy, File.expand_path("../action/destroy", __FILE__)
@@ -21,6 +22,7 @@ module VagrantPlugins
autoload :ForcedHalt, File.expand_path("../action/forced_halt", __FILE__)
autoload :ForwardPorts, File.expand_path("../action/forward_ports", __FILE__)
autoload :Import, File.expand_path("../action/import", __FILE__)
+ autoload :ImportMaster, File.expand_path("../action/import_master", __FILE__)
autoload :IsPaused, File.expand_path("../action/is_paused", __FILE__)
autoload :IsRunning, File.expand_path("../action/is_running", __FILE__)
autoload :IsSaved, File.expand_path("../action/is_saved", __FILE__)
@@ -313,7 +315,13 @@ module VagrantPlugins
if !env[:result]
b2.use CheckAccessible
b2.use Customize, "pre-import"
- b2.use Import
+
+ if env[:machine].provider_config.use_linked_clone
+ b2.use ImportMaster
+ b2.use CreateClone
+ else
+ b2.use Import
+ end
b2.use MatchMACAddress
end
end
diff --git a/plugins/providers/virtualbox/action/create_clone.rb b/plugins/providers/virtualbox/action/create_clone.rb
new file mode 100644
index 000000000..e26b5721f
--- /dev/null
+++ b/plugins/providers/virtualbox/action/create_clone.rb
@@ -0,0 +1,51 @@
+require "log4r"
+#require "lockfile"
+
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ class CreateClone
+ def initialize(app, env)
+ @app = app
+ @logger = Log4r::Logger.new("vagrant::action::vm::clone")
+ end
+
+ def call(env)
+ @logger.info("Creating linked clone from master '#{env[:master_id]}'")
+
+ env[:ui].info I18n.t("vagrant.actions.vm.clone.creating", name: env[:machine].box.name)
+ env[:machine].id = env[:machine].provider.driver.clonevm(env[:master_id], env[:machine].box.name, "base") do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ # Clear the line one last time since the progress meter doesn't disappear immediately.
+ env[:ui].clear_line
+
+ # Flag as erroneous and return if clone failed
+ raise Vagrant::Errors::VMCloneFailure if !env[:machine].id
+
+ # Continue
+ @app.call(env)
+ end
+
+ def recover(env)
+ if env[:machine].state.id != :not_created
+ return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
+
+ # If we're not supposed to destroy on error then just return
+ return if !env[:destroy_on_error]
+
+ # Interrupted, destroy the VM. We note that we don't want to
+ # validate the configuration here, and we don't want to confirm
+ # we want to destroy.
+ destroy_env = env.clone
+ destroy_env[:config_validate] = false
+ destroy_env[:force_confirm_destroy] = true
+ env[:action_runner].run(Action.action_destroy, destroy_env)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/virtualbox/action/import_master.rb b/plugins/providers/virtualbox/action/import_master.rb
new file mode 100644
index 000000000..090b769c4
--- /dev/null
+++ b/plugins/providers/virtualbox/action/import_master.rb
@@ -0,0 +1,62 @@
+require "log4r"
+#require "lockfile"
+
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ class ImportMaster
+ def initialize(app, env)
+ @app = app
+ @logger = Log4r::Logger.new("vagrant::action::vm::create_master")
+ end
+
+ def call(env)
+ master_id_file = env[:machine].box.directory.join("master_id")
+
+ env[:master_id] = master_id_file.read.chomp if master_id_file.file?
+ if env[:master_id] && env[:machine].provider.driver.vm_exists?(env[:master_id])
+ # Master VM already exists -> nothing to do - continue.
+ @app.call(env)
+ end
+
+ env[:ui].info I18n.t("vagrant.actions.vm.clone.importing", name: env[:machine].box.name)
+
+ #TODO - prevent concurrent creation of master vms for the same box.
+
+ # Import the virtual machine
+ ovf_file = env[:machine].box.directory.join("box.ovf").to_s
+ env[:master_id] = env[:machine].provider.driver.import(ovf_file) do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ # Clear the line one last time since the progress meter doesn't disappear immediately.
+ env[:ui].clear_line
+
+ # Flag as erroneous and return if import failed
+ raise Vagrant::Errors::VMImportFailure if !env[:master_id]
+
+ @logger.info("Imported box #{env[:machine].box.name} as master vm with id #{env[:master_id]}")
+
+ @logger.info("Creating base snapshot for master VM.")
+ env[:machine].provider.driver.create_snapshot(env[:master_id], "base")do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ @logger.debug("Writing id of master VM '#{env[:master_id]}' to #{master_id_file}")
+ master_id_file.open("w+") do |f|
+ f.write(env[:master_id])
+ end
+
+ # If we got interrupted, then the import could have been
+ # interrupted and its not a big deal. Just return out.
+ return if env[:interrupted]
+
+ # Import completed successfully. Continue the chain
+ @app.call(env)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/virtualbox/config.rb b/plugins/providers/virtualbox/config.rb
index aed1c692c..7a0e08d08 100644
--- a/plugins/providers/virtualbox/config.rb
+++ b/plugins/providers/virtualbox/config.rb
@@ -32,6 +32,12 @@ module VagrantPlugins
# @return [Boolean]
attr_accessor :gui
+ # If set to `true`, then a linked clone is created from a master
+ # VM generated from the specified box.
+ #
+ # @return [Boolean]
+ attr_accessor :use_linked_clone
+
# This should be set to the name of the machine in the VirtualBox
# GUI.
#
@@ -59,6 +65,7 @@ module VagrantPlugins
@name = UNSET_VALUE
@network_adapters = {}
@gui = UNSET_VALUE
+ @use_linked_clone = UNSET_VALUE
# We require that network adapter 1 is a NAT device.
network_adapter(1, :nat)
@@ -136,6 +143,9 @@ module VagrantPlugins
# Default is to not show a GUI
@gui = false if @gui == UNSET_VALUE
+ # Do not create linked clone by default
+ @use_linked_clone = false if @use_linked_clone == UNSET_VALUE
+
# The default name is just nothing, and we default it
@name = nil if @name == UNSET_VALUE
end
diff --git a/plugins/providers/virtualbox/driver/meta.rb b/plugins/providers/virtualbox/driver/meta.rb
index 1da74d5d3..5f0700c32 100644
--- a/plugins/providers/virtualbox/driver/meta.rb
+++ b/plugins/providers/virtualbox/driver/meta.rb
@@ -79,8 +79,10 @@ module VagrantPlugins
def_delegators :@driver, :clear_forwarded_ports,
:clear_shared_folders,
+ :clonevm,
:create_dhcp_server,
:create_host_only_network,
+ :create_snapshot,
:delete,
:delete_unused_host_only_networks,
:discard_saved_state,
diff --git a/plugins/providers/virtualbox/driver/version_4_3.rb b/plugins/providers/virtualbox/driver/version_4_3.rb
index cc700c0fa..76ccdcd6a 100644
--- a/plugins/providers/virtualbox/driver/version_4_3.rb
+++ b/plugins/providers/virtualbox/driver/version_4_3.rb
@@ -34,6 +34,15 @@ module VagrantPlugins
end
end
+ def clonevm(master_id, box_name, snapshot_name)
+ @logger.debug("Creating linked clone from master vm with id #{master_id} from snapshot '#{snapshot_name}'")
+
+ machine_name = "#{box_name}_#{snapshot_name}_clone_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
+ execute("clonevm", master_id, "--snapshot", snapshot_name, "--options", "link", "--register", "--name", machine_name)
+
+ return get_machine_id machine_name
+ end
+
def create_dhcp_server(network, options)
execute("dhcpserver", "add", "--ifname", network,
"--ip", options[:dhcp_ip],
@@ -62,6 +71,10 @@ module VagrantPlugins
}
end
+ def create_snapshot(machine_id, snapshot_name)
+ execute("snapshot", machine_id, "take", snapshot_name)
+ end
+
def delete
execute("unregistervm", @uuid, "--delete")
end
@@ -156,6 +169,13 @@ module VagrantPlugins
execute("modifyvm", @uuid, *args) if !args.empty?
end
+ def get_machine_id(machine_name)
+ output = execute("list", "vms", retryable: true)
+ match = /^"#{Regexp.escape(machine_name)}" \{(.+?)\}$/.match(output)
+ return match[1].to_s if match
+ nil
+ end
+
def halt
execute("controlvm", @uuid, "poweroff")
end
@@ -231,10 +251,7 @@ module VagrantPlugins
end
end
- output = execute("list", "vms", retryable: true)
- match = /^"#{Regexp.escape(specified_name)}" \{(.+?)\}$/.match(output)
- return match[1].to_s if match
- nil
+ return get_machine_id specified_name
end
def max_network_adapters
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 4be7a92e7..4cbf5a0a3 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1482,6 +1482,14 @@ en:
deleting: Clearing any previously set network interfaces...
clear_shared_folders:
deleting: Cleaning previously set shared folders...
+ clone:
+ importing: Importing box '%{name}' as master vm...
+ creating: Creating linked clone...
+ failure: Creation of the linked clone failed.
+
+ create_master:
+ failure: |-
+ Failed to create lock-file for master VM creation for box %{box}.
customize:
failure: |-
A customization command failed:
From 14b84a4a76dc3bc3e7693b2388b37072370169b6 Mon Sep 17 00:00:00 2001
From: Rob Kinyon
Date: Tue, 28 Oct 2014 21:53:41 -0400
Subject: [PATCH 003/484] Added a --plugin-clean-sources parameter that will
allow for only those sources that are defined by the user to be used.
---
.gitignore | 4 ++++
lib/vagrant/bundler.rb | 5 -----
plugins/commands/plugin/command/mixin_install_opts.rb | 11 ++++++++++-
3 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/.gitignore b/.gitignore
index 47b95a67e..8fe665031 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,10 @@
# OS-specific
.DS_Store
+# Editor swapfiles
+.*.sw?
+*~
+
# Vagrant stuff
acceptance_config.yml
boxes/*
diff --git a/lib/vagrant/bundler.rb b/lib/vagrant/bundler.rb
index 05867da15..e12b89174 100644
--- a/lib/vagrant/bundler.rb
+++ b/lib/vagrant/bundler.rb
@@ -178,11 +178,6 @@ module Vagrant
f = File.open(Tempfile.new("vagrant").path + "2", "w+")
f.tap do |gemfile|
- if !sources.include?("http://rubygems.org")
- gemfile.puts(%Q[source "https://rubygems.org"])
- end
-
- gemfile.puts(%Q[source "http://gems.hashicorp.com"])
sources.each do |source|
next if source == ""
gemfile.puts(%Q[source "#{source}"])
diff --git a/plugins/commands/plugin/command/mixin_install_opts.rb b/plugins/commands/plugin/command/mixin_install_opts.rb
index 0b1b0973a..ffee55cde 100644
--- a/plugins/commands/plugin/command/mixin_install_opts.rb
+++ b/plugins/commands/plugin/command/mixin_install_opts.rb
@@ -3,6 +3,11 @@ module VagrantPlugins
module Command
module MixinInstallOpts
def build_install_opts(o, options)
+ options[:plugin_sources] = [
+ "https://rubygems.org",
+ "http://gems.hashicorp.com",
+ ]
+
o.on("--entry-point NAME", String,
"The name of the entry point file for loading the plugin.") do |entry_point|
options[:entry_point] = entry_point
@@ -17,9 +22,13 @@ module VagrantPlugins
puts
end
+ o.on("--plugin-clean-sources", String,
+ "Remove all plugin sources defined so far (including defaults)") do
+ options[:plugin_sources] = []
+ end
+
o.on("--plugin-source PLUGIN_SOURCE", String,
"Add a RubyGems repository source") do |plugin_source|
- options[:plugin_sources] ||= []
options[:plugin_sources] << plugin_source
end
From c3151c0b8829582873dfb355f0ca5a2edcb75208 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=B6ter?=
Date: Wed, 3 Jun 2015 13:27:03 +0200
Subject: [PATCH 004/484] Ignore failure when trying to delete lock file.
Deleting the lock file can fail when another process is currently trying to acquire it (-> race condition).
It is safe to ignore this error since the other process will eventually acquire the lock and again try to delete the lock file.
---
lib/vagrant/environment.rb | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index 571ae75ab..455921485 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -484,7 +484,11 @@ module Vagrant
if name != "dotlock"
lock("dotlock", retry: true) do
f.close
- File.delete(lock_path)
+ begin
+ File.delete(lock_path)
+ rescue
+ @logger.debug("Failed to delete lock file #{lock_path} - some other thread might be trying to acquire it -> ignoring this error")
+ end
end
end
From 9d63ca4dd237947756ea59b447013e78313f4c3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=B6ter?=
Date: Wed, 3 Jun 2015 13:31:43 +0200
Subject: [PATCH 005/484] Acquire lock to prevent concurrent creation of master
VM for the same box.
---
.../virtualbox/action/import_master.rb | 68 ++++++++++---------
1 file changed, 36 insertions(+), 32 deletions(-)
diff --git a/plugins/providers/virtualbox/action/import_master.rb b/plugins/providers/virtualbox/action/import_master.rb
index 090b769c4..cba6216fd 100644
--- a/plugins/providers/virtualbox/action/import_master.rb
+++ b/plugins/providers/virtualbox/action/import_master.rb
@@ -12,46 +12,50 @@ module VagrantPlugins
def call(env)
master_id_file = env[:machine].box.directory.join("master_id")
-
- env[:master_id] = master_id_file.read.chomp if master_id_file.file?
- if env[:master_id] && env[:machine].provider.driver.vm_exists?(env[:master_id])
- # Master VM already exists -> nothing to do - continue.
- @app.call(env)
- end
- env[:ui].info I18n.t("vagrant.actions.vm.clone.importing", name: env[:machine].box.name)
+ env[:machine].env.lock(env[:machine].box.name, retry: true) do
+ env[:master_id] = master_id_file.read.chomp if master_id_file.file?
+ if env[:master_id] && env[:machine].provider.driver.vm_exists?(env[:master_id])
+ # Master VM already exists -> nothing to do - continue.
+ @logger.info("Master VM for '#{env[:machine].box.name}' already exists (id=#{env[:master_id]}) - skipping import step.")
+ return @app.call(env)
+ end
- #TODO - prevent concurrent creation of master vms for the same box.
-
- # Import the virtual machine
- ovf_file = env[:machine].box.directory.join("box.ovf").to_s
- env[:master_id] = env[:machine].provider.driver.import(ovf_file) do |progress|
+ env[:ui].info I18n.t("vagrant.actions.vm.clone.importing", name: env[:machine].box.name)
+
+ # Import the virtual machine
+ ovf_file = env[:machine].box.directory.join("box.ovf").to_s
+ env[:master_id] = env[:machine].provider.driver.import(ovf_file) do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ # Clear the line one last time since the progress meter doesn't disappear immediately.
env[:ui].clear_line
- env[:ui].report_progress(progress, 100, false)
- end
-
- # Clear the line one last time since the progress meter doesn't disappear immediately.
- env[:ui].clear_line
+
+ # Flag as erroneous and return if import failed
+ raise Vagrant::Errors::VMImportFailure if !env[:master_id]
- # Flag as erroneous and return if import failed
- raise Vagrant::Errors::VMImportFailure if !env[:master_id]
-
- @logger.info("Imported box #{env[:machine].box.name} as master vm with id #{env[:master_id]}")
-
- @logger.info("Creating base snapshot for master VM.")
- env[:machine].provider.driver.create_snapshot(env[:master_id], "base")do |progress|
- env[:ui].clear_line
- env[:ui].report_progress(progress, 100, false)
- end
+ @logger.info("Imported box #{env[:machine].box.name} as master vm with id #{env[:master_id]}")
- @logger.debug("Writing id of master VM '#{env[:master_id]}' to #{master_id_file}")
- master_id_file.open("w+") do |f|
- f.write(env[:master_id])
- end
+ @logger.info("Creating base snapshot for master VM.")
+ env[:machine].provider.driver.create_snapshot(env[:master_id], "base") do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ @logger.debug("Writing id of master VM '#{env[:master_id]}' to #{master_id_file}")
+ master_id_file.open("w+") do |f|
+ f.write(env[:master_id])
+ end
+ end
# If we got interrupted, then the import could have been
# interrupted and its not a big deal. Just return out.
- return if env[:interrupted]
+ if env[:interrupted]
+ @logger.info("Import of master VM was interrupted -> exiting.")
+ return
+ end
# Import completed successfully. Continue the chain
@app.call(env)
From c60a020096e576243e703517511d886fd461a925 Mon Sep 17 00:00:00 2001
From: Matt Wrock
Date: Wed, 27 Aug 2014 12:17:30 -0700
Subject: [PATCH 006/484] adds a ps command to vagrant that drops the user into
a remote powershell shell
---
plugins/commands/ps/command.rb | 116 ++++++++++++++++++
plugins/commands/ps/errors.rb | 18 +++
plugins/commands/ps/plugin.rb | 31 +++++
.../commands/ps/scripts/enable_psremoting.ps1 | 60 +++++++++
.../ps/scripts/reset_trustedhosts.ps1 | 12 ++
plugins/hosts/windows/cap/ps.rb | 50 ++++++++
plugins/hosts/windows/plugin.rb | 5 +
templates/locales/command_ps.yml | 16 +++
8 files changed, 308 insertions(+)
create mode 100644 plugins/commands/ps/command.rb
create mode 100644 plugins/commands/ps/errors.rb
create mode 100644 plugins/commands/ps/plugin.rb
create mode 100644 plugins/commands/ps/scripts/enable_psremoting.ps1
create mode 100644 plugins/commands/ps/scripts/reset_trustedhosts.ps1
create mode 100644 plugins/hosts/windows/cap/ps.rb
create mode 100644 templates/locales/command_ps.yml
diff --git a/plugins/commands/ps/command.rb b/plugins/commands/ps/command.rb
new file mode 100644
index 000000000..33eeec253
--- /dev/null
+++ b/plugins/commands/ps/command.rb
@@ -0,0 +1,116 @@
+require "optparse"
+
+require_relative "../../communicators/winrm/helper"
+
+module VagrantPlugins
+ module CommandPS
+ class Command < Vagrant.plugin("2", :command)
+ def self.synopsis
+ "connects to machine via powershell remoting"
+ end
+
+ def execute
+ options = {}
+
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant ps [-- extra ps args]"
+
+ o.separator ""
+ o.separator "Options:"
+ o.separator ""
+
+ o.on("-c", "--command COMMAND", "Execute a powershell command directly") do |c|
+ options[:command] = c
+ end
+ end
+
+ # Parse out the extra args to send to the ps session, which
+ # is everything after the "--"
+ split_index = @argv.index("--")
+ if split_index
+ options[:extra_args] = @argv.drop(split_index + 1)
+ @argv = @argv.take(split_index)
+ end
+
+ # Parse the options and return if we don't have any target.
+ argv = parse_options(opts)
+ return if !argv
+
+ # Check if the host even supports ps remoting
+ raise Errors::HostUnsupported if !@env.host.capability?(:ps_client)
+
+ # Execute ps session if we can
+ with_target_vms(argv, single_target: true) do |machine|
+ if !machine.communicate.ready?
+ raise Vagrant::Errors::VMNotCreatedError
+ end
+
+ if machine.config.vm.communicator != :winrm #|| !machine.provider.capability?(:winrm_info)
+ raise VagrantPlugins::CommunicatorWinRM::Errors::WinRMNotReady
+ end
+
+ if !options[:command].nil?
+ out_code = machine.communicate.execute options[:command]
+ if out_code == 0
+ machine.ui.detail("Command: #{options[:command]} executed succesfully with output code #{out_code}.")
+ end
+ break
+ end
+
+ ps_info = VagrantPlugins::CommunicatorWinRM::Helper.winrm_info(machine)
+ ps_info[:username] = machine.config.winrm.username
+ ps_info[:password] = machine.config.winrm.password
+ # Extra arguments if we have any
+ ps_info[:extra_args] = options[:extra_args]
+
+ result = ready_ps_remoting_for machine, ps_info
+
+ machine.ui.detail(
+ "Creating powershell session to #{ps_info[:host]}:#{ps_info[:port]}")
+ machine.ui.detail("Username: #{ps_info[:username]}")
+
+ begin
+ @env.host.capability(:ps_client, ps_info)
+ ensure
+ if !result["PreviousTrustedHosts"].nil?
+ reset_ps_remoting_for machine, ps_info
+ end
+ end
+ end
+ end
+
+ def ready_ps_remoting_for(machine, ps_info)
+ machine.ui.output(I18n.t("vagrant_ps.detecting"))
+ script_path = File.expand_path("../scripts/enable_psremoting.ps1", __FILE__)
+ args = []
+ args << "-hostname" << ps_info[:host]
+ args << "-port" << ps_info[:port].to_s
+ args << "-username" << ps_info[:username]
+ args << "-password" << ps_info[:password]
+ result = Vagrant::Util::PowerShell.execute(script_path, *args)
+ if result.exit_code != 0
+ raise Errors::PowershellError,
+ script: script_path,
+ stderr: result.stderr
+ end
+
+ result_output = JSON.parse(result.stdout)
+ raise Errors::PSRemotingUndetected if !result_output["Success"]
+ result_output
+ end
+
+ def reset_ps_remoting_for(machine, ps_info)
+ machine.ui.output(I18n.t("vagrant_ps.reseting"))
+ script_path = File.expand_path("../scripts/reset_trustedhosts.ps1", __FILE__)
+ args = []
+ args << "-hostname" << ps_info[:host]
+ result = Vagrant::Util::PowerShell.execute(script_path, *args)
+ if result.exit_code != 0
+ raise Errors::PowershellError,
+ script: script_path,
+ stderr: result.stderr
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/ps/errors.rb b/plugins/commands/ps/errors.rb
new file mode 100644
index 000000000..c614fb87a
--- /dev/null
+++ b/plugins/commands/ps/errors.rb
@@ -0,0 +1,18 @@
+module VagrantPlugins
+ module CommandPS
+ module Errors
+ # A convenient superclass for all our errors.
+ class PSError < Vagrant::Errors::VagrantError
+ error_namespace("vagrant_ps.errors")
+ end
+
+ class HostUnsupported < PSError
+ error_key(:host_unsupported)
+ end
+
+ class PSRemotingUndetected < PSError
+ error_key(:ps_remoting_undetected)
+ end
+ end
+ end
+end
diff --git a/plugins/commands/ps/plugin.rb b/plugins/commands/ps/plugin.rb
new file mode 100644
index 000000000..56b84b3c5
--- /dev/null
+++ b/plugins/commands/ps/plugin.rb
@@ -0,0 +1,31 @@
+require "vagrant"
+
+module VagrantPlugins
+ module CommandPS
+ autoload :Errors, File.expand_path("../errors", __FILE__)
+
+ class Plugin < Vagrant.plugin("2")
+ name "ps command"
+ description <<-DESC
+ The ps command opens a remote powershell session to the
+ machine if it supports powershell remoting.
+ DESC
+
+ command("ps") do
+ require File.expand_path("../command", __FILE__)
+ init!
+ Command
+ end
+
+ protected
+
+ def self.init!
+ return if defined?(@_init)
+ I18n.load_path << File.expand_path(
+ "templates/locales/command_ps.yml", Vagrant.source_root)
+ I18n.reload!
+ @_init = true
+ end
+ end
+ end
+end
diff --git a/plugins/commands/ps/scripts/enable_psremoting.ps1 b/plugins/commands/ps/scripts/enable_psremoting.ps1
new file mode 100644
index 000000000..4d7ded704
--- /dev/null
+++ b/plugins/commands/ps/scripts/enable_psremoting.ps1
@@ -0,0 +1,60 @@
+Param(
+ [string]$hostname,
+ [string]$port,
+ [string]$username,
+ [string]$password
+)
+# If we are in this script, we know basic winrm is working
+# If the user is not using a domain acount and chances are
+# they are not, PS Remoting will not work if the guest is not
+# listed in the trusted hosts.
+
+$encrypted_password = ConvertTo-SecureString $password -asplaintext -force
+$creds = New-Object System.Management.Automation.PSCredential (
+ "$hostname\\$username", $encrypted_password)
+
+$result = @{
+ Success = $false
+ PreviousTrustedHosts = $null
+}
+try {
+ invoke-command -computername $hostname `
+ -Credential $creds `
+ -Port $port `
+ -ScriptBlock {} `
+ -ErrorAction Stop
+ $result.Success = $true
+} catch{}
+
+if(!$result.Success) {
+ $newHosts = @()
+ $result.PreviousTrustedHosts=(
+ Get-Item "wsman:\localhost\client\trustedhosts").Value
+ $hostArray=$result.PreviousTrustedHosts.Split(",").Trim()
+ if($hostArray -contains "*") {
+ $result.PreviousTrustedHosts = $null
+ }
+ elseif(!($hostArray -contains $hostname)) {
+ $strNewHosts = $hostname
+ if($result.PreviousTrustedHosts.Length -gt 0){
+ $strNewHosts = $result.PreviousTrustedHosts + "," + $strNewHosts
+ }
+ Set-Item -Path "wsman:\localhost\client\trustedhosts" `
+ -Value $strNewHosts -Force
+
+ try {
+ invoke-command -computername $hostname `
+ -Credential $creds `
+ -Port $port `
+ -ScriptBlock {} `
+ -ErrorAction Stop
+ $result.Success = $true
+ } catch{
+ Set-Item -Path "wsman:\localhost\client\trustedhosts" `
+ -Value $result.PreviousTrustedHosts -Force
+ $result.PreviousTrustedHosts = $null
+ }
+ }
+}
+
+Write-Output $(ConvertTo-Json $result)
diff --git a/plugins/commands/ps/scripts/reset_trustedhosts.ps1 b/plugins/commands/ps/scripts/reset_trustedhosts.ps1
new file mode 100644
index 000000000..5865a4e77
--- /dev/null
+++ b/plugins/commands/ps/scripts/reset_trustedhosts.ps1
@@ -0,0 +1,12 @@
+Param(
+ [string]$hostname
+)
+
+$trustedHosts = (
+ Get-Item "wsman:\localhost\client\trustedhosts").Value.Replace(
+ $hostname, '')
+$trustedHosts = $trustedHosts.Replace(",,","")
+if($trustedHosts.EndsWith(",")){
+ $trustedHosts = $trustedHosts.Substring(0,$trustedHosts.length-1)
+}
+Set-Item "wsman:\localhost\client\trustedhosts" -Value $trustedHosts -Force
\ No newline at end of file
diff --git a/plugins/hosts/windows/cap/ps.rb b/plugins/hosts/windows/cap/ps.rb
new file mode 100644
index 000000000..939235915
--- /dev/null
+++ b/plugins/hosts/windows/cap/ps.rb
@@ -0,0 +1,50 @@
+require "pathname"
+require "tmpdir"
+
+require "vagrant/util/subprocess"
+
+module VagrantPlugins
+ module HostWindows
+ module Cap
+ class PS
+ def self.ps_client(env, ps_info)
+ logger = Log4r::Logger.new("vagrant::hosts::windows")
+
+ command = <<-EOS
+ $plain_password = "#{ps_info[:password]}"
+ $username = "#{ps_info[:username]}"
+ $port = "#{ps_info[:port]}"
+ $hostname = "#{ps_info[:host]}"
+ $password = ConvertTo-SecureString $plain_password -asplaintext -force
+ $creds = New-Object System.Management.Automation.PSCredential ("$hostname\\$username", $password)
+ function prompt { kill $PID }
+ Enter-PSSession -ComputerName $hostname -Credential $creds -Port $port
+ EOS
+
+ logger.debug("Starting remote powershell with command:\n#{command}")
+ command = command.chars.to_a.join("\x00").chomp
+ command << "\x00" unless command[-1].eql? "\x00"
+ if(defined?(command.encode))
+ command = command.encode('ASCII-8BIT')
+ command = Base64.strict_encode64(command)
+ else
+ command = Base64.encode64(command).chomp
+ end
+
+ args = ["-NoProfile"]
+ args << "-ExecutionPolicy"
+ args << "Bypass"
+ args << "-NoExit"
+ args << "-EncodedCommand"
+ args << command
+ if ps_info[:extra_args]
+ args << ps_info[:extra_args]
+ end
+
+ # Launch it
+ Vagrant::Util::Subprocess.execute("powershell", *args)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/hosts/windows/plugin.rb b/plugins/hosts/windows/plugin.rb
index fe3b28923..97e8ad134 100644
--- a/plugins/hosts/windows/plugin.rb
+++ b/plugins/hosts/windows/plugin.rb
@@ -20,6 +20,11 @@ module VagrantPlugins
require_relative "cap/rdp"
Cap::RDP
end
+
+ host_capability("windows", "ps_client") do
+ require_relative "cap/ps"
+ Cap::PS
+ end
end
end
end
diff --git a/templates/locales/command_ps.yml b/templates/locales/command_ps.yml
new file mode 100644
index 000000000..e30e5246c
--- /dev/null
+++ b/templates/locales/command_ps.yml
@@ -0,0 +1,16 @@
+en:
+ vagrant_ps:
+ detecting: |-
+ Detecting if a remote powershell connection can be made with the guest...
+ reseting: |-
+ Reseting WinRM TrustedHosts to their original value.
+
+ errors:
+ host_unsupported: |-
+ Your host does not support powershell. A remote powershell connection
+ can only be made from a windows host.
+
+ ps_remoting_undetected: |-
+ Unable to establish a remote powershell connection with the guest.
+ Check if the firewall rules on the guest allow connections to the
+ windows remote management service.
From 1cd10330933fce64608ce2d47bbb72ad0756533f Mon Sep 17 00:00:00 2001
From: Matt Wrock
Date: Fri, 5 Jun 2015 00:11:06 -0700
Subject: [PATCH 007/484] fixes from @sethvargo comments.
---
plugins/commands/ps/command.rb | 10 +++++-----
plugins/commands/ps/plugin.rb | 7 +++----
plugins/communicators/winrm/shell.rb | 2 +-
templates/locales/command_ps.yml | 8 ++++----
4 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/plugins/commands/ps/command.rb b/plugins/commands/ps/command.rb
index 33eeec253..3bcc41ba8 100644
--- a/plugins/commands/ps/command.rb
+++ b/plugins/commands/ps/command.rb
@@ -45,16 +45,16 @@ module VagrantPlugins
raise Vagrant::Errors::VMNotCreatedError
end
- if machine.config.vm.communicator != :winrm #|| !machine.provider.capability?(:winrm_info)
+ if machine.config.vm.communicator != :winrm
raise VagrantPlugins::CommunicatorWinRM::Errors::WinRMNotReady
end
if !options[:command].nil?
- out_code = machine.communicate.execute options[:command]
+ out_code = machine.communicate.execute(options[:command])
if out_code == 0
machine.ui.detail("Command: #{options[:command]} executed succesfully with output code #{out_code}.")
end
- break
+ next
end
ps_info = VagrantPlugins::CommunicatorWinRM::Helper.winrm_info(machine)
@@ -63,7 +63,7 @@ module VagrantPlugins
# Extra arguments if we have any
ps_info[:extra_args] = options[:extra_args]
- result = ready_ps_remoting_for machine, ps_info
+ result = ready_ps_remoting_for(machine, ps_info)
machine.ui.detail(
"Creating powershell session to #{ps_info[:host]}:#{ps_info[:port]}")
@@ -73,7 +73,7 @@ module VagrantPlugins
@env.host.capability(:ps_client, ps_info)
ensure
if !result["PreviousTrustedHosts"].nil?
- reset_ps_remoting_for machine, ps_info
+ reset_ps_remoting_for(machine, ps_info)
end
end
end
diff --git a/plugins/commands/ps/plugin.rb b/plugins/commands/ps/plugin.rb
index 56b84b3c5..847b82c47 100644
--- a/plugins/commands/ps/plugin.rb
+++ b/plugins/commands/ps/plugin.rb
@@ -7,12 +7,12 @@ module VagrantPlugins
class Plugin < Vagrant.plugin("2")
name "ps command"
description <<-DESC
- The ps command opens a remote powershell session to the
+ The ps command opens a remote PowerShell session to the
machine if it supports powershell remoting.
DESC
command("ps") do
- require File.expand_path("../command", __FILE__)
+ require_relative "../command"
init!
Command
end
@@ -21,8 +21,7 @@ module VagrantPlugins
def self.init!
return if defined?(@_init)
- I18n.load_path << File.expand_path(
- "templates/locales/command_ps.yml", Vagrant.source_root)
+ I18n.load_path << File.expand_path("templates/locales/command_ps.yml", Vagrant.source_root)
I18n.reload!
@_init = true
end
diff --git a/plugins/communicators/winrm/shell.rb b/plugins/communicators/winrm/shell.rb
index d9d5f28ce..784660b5e 100644
--- a/plugins/communicators/winrm/shell.rb
+++ b/plugins/communicators/winrm/shell.rb
@@ -9,7 +9,7 @@ Vagrant::Util::SilenceWarnings.silence! do
require "winrm"
end
-require "winrm-fs/file_manager"
+require "winrm-fs"
module VagrantPlugins
module CommunicatorWinRM
diff --git a/templates/locales/command_ps.yml b/templates/locales/command_ps.yml
index e30e5246c..51bf666cc 100644
--- a/templates/locales/command_ps.yml
+++ b/templates/locales/command_ps.yml
@@ -1,16 +1,16 @@
en:
vagrant_ps:
detecting: |-
- Detecting if a remote powershell connection can be made with the guest...
+ Detecting if a remote PowerShell connection can be made with the guest...
reseting: |-
Reseting WinRM TrustedHosts to their original value.
errors:
host_unsupported: |-
- Your host does not support powershell. A remote powershell connection
+ Your host does not support PowerShell. A remote PowerShell connection
can only be made from a windows host.
ps_remoting_undetected: |-
- Unable to establish a remote powershell connection with the guest.
+ Unable to establish a remote PowerShell connection with the guest.
Check if the firewall rules on the guest allow connections to the
- windows remote management service.
+ Windows remote management service.
From 47e57a7cd941c1a2f24e287ab175b9728d5e042b Mon Sep 17 00:00:00 2001
From: Matt Wrock
Date: Fri, 5 Jun 2015 04:17:56 -0700
Subject: [PATCH 008/484] fix relative path
---
plugins/commands/ps/plugin.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/commands/ps/plugin.rb b/plugins/commands/ps/plugin.rb
index 847b82c47..b108658bc 100644
--- a/plugins/commands/ps/plugin.rb
+++ b/plugins/commands/ps/plugin.rb
@@ -12,7 +12,7 @@ module VagrantPlugins
DESC
command("ps") do
- require_relative "../command"
+ require_relative "command"
init!
Command
end
From cf6d4ef5a1943ec656695440d452b160aa74f676 Mon Sep 17 00:00:00 2001
From: Matt Wrock
Date: Fri, 5 Jun 2015 04:18:23 -0700
Subject: [PATCH 009/484] clean up command encoding
---
plugins/hosts/windows/cap/ps.rb | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/plugins/hosts/windows/cap/ps.rb b/plugins/hosts/windows/cap/ps.rb
index 939235915..9960f689e 100644
--- a/plugins/hosts/windows/cap/ps.rb
+++ b/plugins/hosts/windows/cap/ps.rb
@@ -22,21 +22,13 @@ module VagrantPlugins
EOS
logger.debug("Starting remote powershell with command:\n#{command}")
- command = command.chars.to_a.join("\x00").chomp
- command << "\x00" unless command[-1].eql? "\x00"
- if(defined?(command.encode))
- command = command.encode('ASCII-8BIT')
- command = Base64.strict_encode64(command)
- else
- command = Base64.encode64(command).chomp
- end
args = ["-NoProfile"]
args << "-ExecutionPolicy"
args << "Bypass"
args << "-NoExit"
args << "-EncodedCommand"
- args << command
+ args << ::WinRM::PowershellScript.new(command).encoded
if ps_info[:extra_args]
args << ps_info[:extra_args]
end
From 740877065a8fc0b777cc7aa51b4fb074307affbd Mon Sep 17 00:00:00 2001
From: Matt Wrock
Date: Fri, 5 Jun 2015 05:03:29 -0700
Subject: [PATCH 010/484] marshall back command output when passing a command
to ps
---
plugins/commands/ps/command.rb | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/plugins/commands/ps/command.rb b/plugins/commands/ps/command.rb
index 3bcc41ba8..ee021d0ed 100644
--- a/plugins/commands/ps/command.rb
+++ b/plugins/commands/ps/command.rb
@@ -50,9 +50,11 @@ module VagrantPlugins
end
if !options[:command].nil?
- out_code = machine.communicate.execute(options[:command])
+ out_code = machine.communicate.execute(options[:command].dup) do |type,data|
+ machine.ui.detail(data) if type == :stdout
+ end
if out_code == 0
- machine.ui.detail("Command: #{options[:command]} executed succesfully with output code #{out_code}.")
+ machine.ui.success("Command: #{options[:command]} executed succesfully with output code #{out_code}.")
end
next
end
From e6daf2f17279c7ec1452cec1123ad13dccf52890 Mon Sep 17 00:00:00 2001
From: Matt Wrock
Date: Fri, 5 Jun 2015 22:24:05 -0700
Subject: [PATCH 011/484] fix pscommand error messaging
---
plugins/commands/ps/command.rb | 4 ++--
plugins/commands/ps/errors.rb | 10 +++++++---
templates/locales/command_ps.yml | 13 ++++++++++++-
3 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/plugins/commands/ps/command.rb b/plugins/commands/ps/command.rb
index ee021d0ed..63963491a 100644
--- a/plugins/commands/ps/command.rb
+++ b/plugins/commands/ps/command.rb
@@ -91,7 +91,7 @@ module VagrantPlugins
args << "-password" << ps_info[:password]
result = Vagrant::Util::PowerShell.execute(script_path, *args)
if result.exit_code != 0
- raise Errors::PowershellError,
+ raise Errors::PowerShellError,
script: script_path,
stderr: result.stderr
end
@@ -108,7 +108,7 @@ module VagrantPlugins
args << "-hostname" << ps_info[:host]
result = Vagrant::Util::PowerShell.execute(script_path, *args)
if result.exit_code != 0
- raise Errors::PowershellError,
+ raise Errors::PowerShellError,
script: script_path,
stderr: result.stderr
end
diff --git a/plugins/commands/ps/errors.rb b/plugins/commands/ps/errors.rb
index c614fb87a..4be70551a 100644
--- a/plugins/commands/ps/errors.rb
+++ b/plugins/commands/ps/errors.rb
@@ -2,17 +2,21 @@ module VagrantPlugins
module CommandPS
module Errors
# A convenient superclass for all our errors.
- class PSError < Vagrant::Errors::VagrantError
+ class PSCommandError < Vagrant::Errors::VagrantError
error_namespace("vagrant_ps.errors")
end
- class HostUnsupported < PSError
+ class HostUnsupported < PSCommandError
error_key(:host_unsupported)
end
- class PSRemotingUndetected < PSError
+ class PSRemotingUndetected < PSCommandError
error_key(:ps_remoting_undetected)
end
+
+ class PowerShellError < PSCommandError
+ error_key(:powershell_error)
+ end
end
end
end
diff --git a/templates/locales/command_ps.yml b/templates/locales/command_ps.yml
index 51bf666cc..179aae842 100644
--- a/templates/locales/command_ps.yml
+++ b/templates/locales/command_ps.yml
@@ -3,7 +3,7 @@ en:
detecting: |-
Detecting if a remote PowerShell connection can be made with the guest...
reseting: |-
- Reseting WinRM TrustedHosts to their original value.
+ Resetting WinRM TrustedHosts to their original value.
errors:
host_unsupported: |-
@@ -14,3 +14,14 @@ en:
Unable to establish a remote PowerShell connection with the guest.
Check if the firewall rules on the guest allow connections to the
Windows remote management service.
+
+ powershell_error: |-
+ An error occurred while executing a PowerShell script. This error
+ is shown below. Please read the error message and see if this is
+ a configuration error with your system. If it is not, then please
+ report a bug.
+
+ Script: %{script}
+ Error:
+
+ %{stderr}
From 2717f5605ae4372c93a3eb768242a4355c37f1de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=B6ter?=
Date: Mon, 8 Jun 2015 18:03:03 +0200
Subject: [PATCH 012/484] Document use_linked_clone property for VirtualBox
provider.
---
.../v2/virtualbox/configuration.html.md | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/website/docs/source/v2/virtualbox/configuration.html.md b/website/docs/source/v2/virtualbox/configuration.html.md
index 22cb2a6c5..c9ee51540 100644
--- a/website/docs/source/v2/virtualbox/configuration.html.md
+++ b/website/docs/source/v2/virtualbox/configuration.html.md
@@ -36,6 +36,30 @@ config.vm.provider "virtualbox" do |v|
end
```
+## Linked Clones
+
+By default new machines are created by importing the base box. For large
+boxes this produces a large overhead in terms of time (the import operation)
+and space (the new machine contains a copy of the base box's image).
+Using linked clones can drastically reduce this overhead.
+
+Linked clones are based on a master VM, which is generated by importing the
+base box only once the first time it is required. For the linked clones only
+differencing disk images are created where the parent disk image belongs to
+the master VM.
+
+```ruby
+config.vm.provider "virtualbox" do |v|
+ v.use_linked_clone = true
+end
+```
+
+
+ Note: the generated master VMs are currently not removed
+ automatically by Vagrant. This has to be done manually. However, a master
+ VM can only be remove when there are no linked clones connected to it.
+
+
## VBoxManage Customizations
[VBoxManage](http://www.virtualbox.org/manual/ch08.html) is a utility that can
From dbcb513075a6117b867f4d2933f4715cbbd187aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=B6ter?=
Date: Thu, 16 Jul 2015 13:23:57 +0200
Subject: [PATCH 013/484] Fix typo.
---
website/docs/source/v2/virtualbox/configuration.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/virtualbox/configuration.html.md b/website/docs/source/v2/virtualbox/configuration.html.md
index c9ee51540..5c908ab68 100644
--- a/website/docs/source/v2/virtualbox/configuration.html.md
+++ b/website/docs/source/v2/virtualbox/configuration.html.md
@@ -57,7 +57,7 @@ end
Note: the generated master VMs are currently not removed
automatically by Vagrant. This has to be done manually. However, a master
- VM can only be remove when there are no linked clones connected to it.
+ VM can only be removed when there are no linked clones connected to it.
## VBoxManage Customizations
From 772f276ee3a1cb6ea62b851bb41f45b49a168587 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=B6ter?=
Date: Thu, 16 Jul 2015 13:27:24 +0200
Subject: [PATCH 014/484] Port support for linked clones to VirtualBox 5.0
driver.
---
.../virtualbox/driver/version_5_0.rb | 25 ++++++++++++++++---
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index d7d3b58df..e2aeb35a1 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -34,6 +34,15 @@ module VagrantPlugins
end
end
+ def clonevm(master_id, box_name, snapshot_name)
+ @logger.debug("Creating linked clone from master vm with id #{master_id} from snapshot '#{snapshot_name}'")
+
+ machine_name = "#{box_name}_#{snapshot_name}_clone_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
+ execute("clonevm", master_id, "--snapshot", snapshot_name, "--options", "link", "--register", "--name", machine_name)
+
+ return get_machine_id machine_name
+ end
+
def create_dhcp_server(network, options)
execute("dhcpserver", "add", "--ifname", network,
"--ip", options[:dhcp_ip],
@@ -62,6 +71,10 @@ module VagrantPlugins
}
end
+ def create_snapshot(machine_id, snapshot_name)
+ execute("snapshot", machine_id, "take", snapshot_name)
+ end
+
def delete
execute("unregistervm", @uuid, "--delete")
end
@@ -156,6 +169,13 @@ module VagrantPlugins
execute("modifyvm", @uuid, *args) if !args.empty?
end
+ def get_machine_id(machine_name)
+ output = execute("list", "vms", retryable: true)
+ match = /^"#{Regexp.escape(machine_name)}" \{(.+?)\}$/.match(output)
+ return match[1].to_s if match
+ nil
+ end
+
def halt
execute("controlvm", @uuid, "poweroff")
end
@@ -231,10 +251,7 @@ module VagrantPlugins
end
end
- output = execute("list", "vms", retryable: true)
- match = /^"#{Regexp.escape(specified_name)}" \{(.+?)\}$/.match(output)
- return match[1].to_s if match
- nil
+ return get_machine_id specified_name
end
def max_network_adapters
From 209556c3cdd426cbcca51a186e0b10be52aa7dd7 Mon Sep 17 00:00:00 2001
From: Jon Burgess
Date: Fri, 17 Jul 2015 14:26:13 +1000
Subject: [PATCH 015/484] Allow provisioner instance names to be specified for
`up` and `reload` commands and option `--provision-with`
Ref: https://github.com/mitchellh/vagrant/issues/5139
---
plugins/commands/reload/command.rb | 2 +-
plugins/commands/up/command.rb | 2 +-
plugins/commands/up/start_mixins.rb | 23 ++++++++++++++++-------
3 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/plugins/commands/reload/command.rb b/plugins/commands/reload/command.rb
index 33a6f8e5e..1d43d13b7 100644
--- a/plugins/commands/reload/command.rb
+++ b/plugins/commands/reload/command.rb
@@ -30,7 +30,7 @@ module VagrantPlugins
return if !argv
# Validate the provisioners
- validate_provisioner_flags!(options)
+ validate_provisioner_flags!(options, argv)
@logger.debug("'reload' each target VM...")
machines = []
diff --git a/plugins/commands/up/command.rb b/plugins/commands/up/command.rb
index 826bea0ae..e340dad96 100644
--- a/plugins/commands/up/command.rb
+++ b/plugins/commands/up/command.rb
@@ -48,7 +48,7 @@ module VagrantPlugins
return if !argv
# Validate the provisioners
- validate_provisioner_flags!(options)
+ validate_provisioner_flags!(options, argv)
# Go over each VM and bring it up
@logger.debug("'Up' each target VM...")
diff --git a/plugins/commands/up/start_mixins.rb b/plugins/commands/up/start_mixins.rb
index 548d889ca..8be96c68a 100644
--- a/plugins/commands/up/start_mixins.rb
+++ b/plugins/commands/up/start_mixins.rb
@@ -26,13 +26,22 @@ module VagrantPlugins
# This validates the provisioner flags and raises an exception
# if there are invalid ones.
- def validate_provisioner_flags!(options)
- (options[:provision_types] || []).each do |type|
- klass = Vagrant.plugin("2").manager.provisioners[type]
- if !klass
- raise Vagrant::Errors::ProvisionerFlagInvalid,
- name: type.to_s
- end
+ def validate_provisioner_flags!(options, argv)
+ provisioner_instance_names = []
+ with_target_vms(argv) do |machine|
+ provisioner_instance_names << machine.config.vm.provisioners.map(&:name)
+ end
+
+ provisioner_instance_names.flatten!.uniq!
+
+ if (provisioner_instance_names & options[:provision_types]).empty?
+ (options[:provision_types] || []).each do |type|
+ klass = Vagrant.plugin("2").manager.provisioners[type]
+ if !klass
+ raise Vagrant::Errors::ProvisionerFlagInvalid,
+ name: type.to_s
+ end
+ end
end
end
end
From d2b0df0a7d3f63eaeca81585edb81f9d9be7f83f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Denis=20Br=C3=A6khus?=
Date: Fri, 17 Jul 2015 21:44:58 +0200
Subject: [PATCH 016/484] Specify time and don't do -h -H which is not really a
valid usage.
---
plugins/guests/debian8/cap/halt.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/guests/debian8/cap/halt.rb b/plugins/guests/debian8/cap/halt.rb
index 932281347..b2e5a141b 100644
--- a/plugins/guests/debian8/cap/halt.rb
+++ b/plugins/guests/debian8/cap/halt.rb
@@ -4,7 +4,7 @@ module VagrantPlugins
class Halt
def self.halt(machine)
begin
- machine.communicate.sudo("shutdown -h -H")
+ machine.communicate.sudo("shutdown -h now")
rescue IOError
# Do nothing, because it probably means the machine shut down
# and SSH connection was lost.
From f349a58a1e32ba68deedeca57eae1b67a8266ec3 Mon Sep 17 00:00:00 2001
From: Mattias Appelgren
Date: Sat, 18 Jul 2015 13:54:58 +0200
Subject: [PATCH 017/484] provisioners/puppet: Fix Puppet environment default
manifest
Also parse the puppet variables $codedir and $environment when
resolving a manifest path from environment.conf
---
plugins/provisioners/puppet/provisioner/puppet.rb | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/plugins/provisioners/puppet/provisioner/puppet.rb b/plugins/provisioners/puppet/provisioner/puppet.rb
index f1987dbd5..d1e124e85 100644
--- a/plugins/provisioners/puppet/provisioner/puppet.rb
+++ b/plugins/provisioners/puppet/provisioner/puppet.rb
@@ -62,12 +62,16 @@ module VagrantPlugins
# Parse out the environment manifest path since puppet apply doesnt do that for us.
environment_conf = File.join(environments_guest_path, @config.environment, "environment.conf")
if @machine.communicate.test("test -e #{environment_conf}", sudo: true)
- conf = @machine.communicate.sudo("cat #{environment_conf}") do | type, data|
+ @machine.communicate.sudo("cat #{environment_conf}") do | type, data|
if type == :stdout
data.each_line do |line|
if line =~ /^\s*manifest\s+=\s+([^\s]+)/
@manifest_file = $1
- @manifest_file.gsub! '$basemodulepath:', "#{environments_guest_path}/#{@config.environment}/"
+ @manifest_file.gsub! "$codedir", File.dirname(environments_guest_path)
+ @manifest_file.gsub! "$environment", @config.environment
+ if !@manifest_file.start_with? "/"
+ @manifest_file = File.join(environments_guest_path, @config.environment, @manifest_file)
+ end
@logger.debug("Using manifest from environment.conf: #{@manifest_file}")
end
end
@@ -85,7 +89,7 @@ module VagrantPlugins
# In environment mode we still need to specify a manifest file, if its not, use the one from env config if specified.
if !@manifest_file
- @manifest_file = "#{environments_guest_path}/#{@config.environment}/manifests/site.pp"
+ @manifest_file = "#{environments_guest_path}/#{@config.environment}/manifests"
parse_environment_metadata
end
# Check that the shared folders are properly shared
From 27b948f53ccd3e5743fc223f2e70617ecf663c83 Mon Sep 17 00:00:00 2001
From: Mattias Appelgren
Date: Sat, 18 Jul 2015 14:20:57 +0200
Subject: [PATCH 018/484] website/docs: Add more information regarding Puppet
environments
---
.../docs/source/v2/provisioning/puppet_apply.html.md | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/website/docs/source/v2/provisioning/puppet_apply.html.md b/website/docs/source/v2/provisioning/puppet_apply.html.md
index 89fe90195..b8f0a5f02 100644
--- a/website/docs/source/v2/provisioning/puppet_apply.html.md
+++ b/website/docs/source/v2/provisioning/puppet_apply.html.md
@@ -140,8 +140,9 @@ that the path is located in the "vm" at "/path/to/manifests".
## Environments
-If you are using Puppet 4 or higher, you can also specify the name of the
-Puppet environment and the path on the local disk to the environment files:
+If you are using Puppet 4 or higher, you can proivision using
+[Puppet Environments](https://docs.puppetlabs.com/puppet/latest/reference/environments.html) by specifying the name of the environment and the path on the
+local disk to the environment files:
```ruby
Vagrant.configure("2") do |config|
@@ -152,6 +153,13 @@ Vagrant.configure("2") do |config|
end
```
+The default manifest is the environment's `manifests` directory.
+If the environment has an `environment.conf` the manifest path is parsed
+from there. Relative paths are assumed to be relative to the directory of
+the environment. If the manifest setting in `environment.conf` use
+the Puppet variables `$codedir` or `$environment` they are resoled to
+the parent directory of `environment_path` and `environment` respectively.
+
## Modules
Vagrant also supports provisioning with [Puppet modules](http://docs.puppetlabs.com/guides/modules.html).
From 19b7bbc369b1d6dd27491a3e8da78e3e93466daa Mon Sep 17 00:00:00 2001
From: Pat O'Shea
Date: Sat, 18 Jul 2015 08:39:00 -0600
Subject: [PATCH 019/484] Corrected masterless example
The basic Vagrantfile file example for a masterless setup doesn't set the masterless value. That property defaults to false. https://github.com/mitchellh/vagrant/blob/master/plugins/provisioners/salt/provisioner.rb
---
website/docs/source/v2/provisioning/salt.html.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/website/docs/source/v2/provisioning/salt.html.md b/website/docs/source/v2/provisioning/salt.html.md
index 8169ec28e..1799a09dd 100644
--- a/website/docs/source/v2/provisioning/salt.html.md
+++ b/website/docs/source/v2/provisioning/salt.html.md
@@ -30,7 +30,8 @@ on a single minion, without a master:
## Use all the defaults:
config.vm.provision :salt do |salt|
-
+
+ salt.masterless = true
salt.minion_config = "salt/minion"
salt.run_highstate = true
From d34bc38bf39ce9a045dcc4c96c8f2693ef1280a3 Mon Sep 17 00:00:00 2001
From: Pat O'Shea
Date: Sat, 18 Jul 2015 20:53:46 -0600
Subject: [PATCH 020/484] Updated salt-minion and call ext on windows guest
Salt-minion and salt-call are batch files on a windows guest, not executables.
---
plugins/provisioners/salt/provisioner.rb | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb
index d74c4fa11..b5f65f1ae 100644
--- a/plugins/provisioners/salt/provisioner.rb
+++ b/plugins/provisioners/salt/provisioner.rb
@@ -35,8 +35,8 @@ module VagrantPlugins
desired_binaries = []
if !@config.no_minion
if @machine.config.vm.communicator == :winrm
- desired_binaries.push('C:\\salt\\salt-minion.exe')
- desired_binaries.push('C:\\salt\\salt-call.exe')
+ desired_binaries.push('C:\\salt\\salt-minion.bat')
+ desired_binaries.push('C:\\salt\\salt-call.bat')
else
desired_binaries.push('salt-minion')
desired_binaries.push('salt-call')
@@ -361,8 +361,8 @@ module VagrantPlugins
else
if @machine.config.vm.communicator == :winrm
opts = { elevated: true }
- @machine.communicate.execute("C:\\salt\\salt-call.exe saltutil.sync_all", opts)
- @machine.communicate.execute("C:\\salt\\salt-call.exe state.highstate --retcode-passthrough #{get_loglevel}#{get_colorize}#{get_pillar}", opts) do |type, data|
+ @machine.communicate.execute("C:\\salt\\salt-call.bat saltutil.sync_all", opts)
+ @machine.communicate.execute("C:\\salt\\salt-call.bat state.highstate --retcode-passthrough #{get_loglevel}#{get_colorize}#{get_pillar}", opts) do |type, data|
if @config.verbose
@machine.env.ui.info(data.rstrip)
end
From 562ed26533a072b4a255ba7d9fe31b1260c367e6 Mon Sep 17 00:00:00 2001
From: Ievgen Prokhorenko
Date: Sun, 19 Jul 2015 16:38:52 +0300
Subject: [PATCH 021/484] Fix #3570 'Box data left in ~/.vagrant.d/boxes after
removal'
---
lib/vagrant/action/builtin/box_remove.rb | 1 +
lib/vagrant/box_collection.rb | 28 ++++++++++++++++---
.../vagrant/action/builtin/box_remove_test.rb | 26 +++++++++++++++++
3 files changed, 51 insertions(+), 4 deletions(-)
diff --git a/lib/vagrant/action/builtin/box_remove.rb b/lib/vagrant/action/builtin/box_remove.rb
index 1d0cea7fd..4c242aa97 100644
--- a/lib/vagrant/action/builtin/box_remove.rb
+++ b/lib/vagrant/action/builtin/box_remove.rb
@@ -106,6 +106,7 @@ module Vagrant
provider: box.provider,
version: box.version))
box.destroy!
+ env[:box_collection].clean_up(box)
# Passes on the removed box to the rest of the middleware chain
env[:box_removed] = box
diff --git a/lib/vagrant/box_collection.rb b/lib/vagrant/box_collection.rb
index a7599f7c2..17c2f3927 100644
--- a/lib/vagrant/box_collection.rb
+++ b/lib/vagrant/box_collection.rb
@@ -13,6 +13,8 @@ module Vagrant
# boxes.
class BoxCollection
TEMP_PREFIX = "vagrant-box-add-temp-"
+ VAGRANT_SLASH = "-VAGRANTSLASH-"
+ VAGRANT_COLON = "-VAGRANTCOLON-"
# The directory where the boxes in this collection are stored.
#
@@ -346,6 +348,19 @@ module Vagrant
end
end
+ # Removes the whole directory of a given box if there are no
+ # other versions nor providers of the box exist.
+ def clean_up(box)
+ return false if exists?(box.name)
+
+ box_directory = box.name
+ .gsub('/', VAGRANT_SLASH)
+ .gsub(':', VAGRANT_COLON)
+
+ path = File.join(directory, box_directory)
+ FileUtils.rm_r(path)
+ end
+
protected
# Returns the directory name for the box of the given name.
@@ -354,16 +369,16 @@ module Vagrant
# @return [String]
def dir_name(name)
name = name.dup
- name.gsub!(":", "-VAGRANTCOLON-") if Util::Platform.windows?
- name.gsub!("/", "-VAGRANTSLASH-")
+ name.gsub!(":", VAGRANT_COLON) if Util::Platform.windows?
+ name.gsub!("/", VAGRANT_SLASH)
name
end
# Returns the directory name for the box cleaned up
def undir_name(name)
name = name.dup
- name.gsub!("-VAGRANTCOLON-", ":")
- name.gsub!("-VAGRANTSLASH-", "/")
+ name.gsub!(VAGRANT_COLON, ":")
+ name.gsub!(VAGRANT_SLASH, "/")
name
end
@@ -440,5 +455,10 @@ module Vagrant
ensure
dir.rmtree if dir.exist?
end
+
+ # Checks if a box with a given name exists.
+ def exists?(box_name)
+ all.any? { |box| box.first.eql?(box_name) }
+ end
end
end
diff --git a/test/unit/vagrant/action/builtin/box_remove_test.rb b/test/unit/vagrant/action/builtin/box_remove_test.rb
index 9de3e467b..016fec243 100644
--- a/test/unit/vagrant/action/builtin/box_remove_test.rb
+++ b/test/unit/vagrant/action/builtin/box_remove_test.rb
@@ -30,6 +30,8 @@ describe Vagrant::Action::Builtin::BoxRemove do
expect(box_collection).to receive(:find).with(
"foo", :virtualbox, "1.0").and_return(box)
+ expect(box_collection).to receive(:clean_up).with(box)
+ .and_return(true)
expect(box).to receive(:destroy!).once
expect(app).to receive(:call).with(env).once
@@ -50,6 +52,8 @@ describe Vagrant::Action::Builtin::BoxRemove do
expect(box_collection).to receive(:find).with(
"foo", :virtualbox, "1.0").and_return(box)
+ expect(box_collection).to receive(:clean_up).with(box)
+ .and_return(false)
expect(box).to receive(:destroy!).once
expect(app).to receive(:call).with(env).once
@@ -70,6 +74,8 @@ describe Vagrant::Action::Builtin::BoxRemove do
expect(box_collection).to receive(:find).with(
"foo", :virtualbox, "1.0").and_return(box)
+ expect(box_collection).to receive(:clean_up).with(box)
+ .and_return(false)
expect(box).to receive(:destroy!).once
expect(app).to receive(:call).with(env).once
@@ -78,6 +84,22 @@ describe Vagrant::Action::Builtin::BoxRemove do
expect(env[:box_removed]).to equal(box)
end
+ it "deletes the whole directory of the box if it's the last box on the system" do
+ box_collection.stub(
+ all: [
+ ["foo", "1.0", :virtualbox],
+ ])
+
+ env[:box_name] = "foo"
+
+ expect(box_collection).to receive(:find).with(
+ "foo", :virtualbox, "1.0").and_return(box)
+ expect(box_collection).to receive(:clean_up).with(box)
+ .and_return(true)
+
+ subject.call(env)
+ end
+
context "checking if a box is in use" do
def new_entry(name, provider, version, valid=true)
Vagrant::MachineIndex::Entry.new.tap do |entry|
@@ -110,6 +132,8 @@ describe Vagrant::Action::Builtin::BoxRemove do
expect(box_collection).to receive(:find).with(
"foo", :virtualbox, "1.0").and_return(box)
expect(box).to receive(:destroy!).once
+ expect(box_collection).to receive(:clean_up).with(box)
+ .and_return(true)
subject.call(env)
end
@@ -123,6 +147,8 @@ describe Vagrant::Action::Builtin::BoxRemove do
expect(box_collection).to receive(:find).with(
"foo", :virtualbox, "1.0").and_return(box)
+ expect(box_collection).to receive(:clean_up).with(box)
+ .and_return(true)
expect(box).to receive(:destroy!).once
subject.call(env)
From e4cdb473bd1a7ad666ddc9f398c661f62a9cfb2c Mon Sep 17 00:00:00 2001
From: Brian Dwyer
Date: Tue, 28 Jul 2015 12:41:51 -0400
Subject: [PATCH 022/484] Bring back `nodes_path` support for the Chef Zero
provisioner
---
plugins/provisioners/chef/config/chef_zero.rb | 7 +++++++
plugins/provisioners/chef/provisioner/chef_solo.rb | 2 ++
plugins/provisioners/chef/provisioner/chef_zero.rb | 1 +
templates/provisioners/chef_zero/zero.erb | 4 ++--
4 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/plugins/provisioners/chef/config/chef_zero.rb b/plugins/provisioners/chef/config/chef_zero.rb
index d28de3dc9..9b1daf1a5 100644
--- a/plugins/provisioners/chef/config/chef_zero.rb
+++ b/plugins/provisioners/chef/config/chef_zero.rb
@@ -17,6 +17,10 @@ module VagrantPlugins
# @return [String]
attr_accessor :environments_path
+ # The path where nodes are stored on disk.
+ # @return [String]
+ attr_accessor :nodes_path
+
# The path where roles are stored on disk.
# @return [String]
attr_accessor :roles_path
@@ -31,6 +35,7 @@ module VagrantPlugins
@cookbooks_path = UNSET_VALUE
@data_bags_path = UNSET_VALUE
@environments_path = UNSET_VALUE
+ @nodes_path = UNSET_VALUE
@roles_path = UNSET_VALUE
@synced_folder_type = UNSET_VALUE
end
@@ -47,6 +52,7 @@ module VagrantPlugins
end
@data_bags_path = [] if @data_bags_path == UNSET_VALUE
+ @nodes_path = [] if @nodes_path == UNSET_VALUE
@roles_path = [] if @roles_path == UNSET_VALUE
@environments_path = [] if @environments_path == UNSET_VALUE
@environments_path = [@environments_path].flatten
@@ -54,6 +60,7 @@ module VagrantPlugins
# Make sure the path is an array.
@cookbooks_path = prepare_folders_config(@cookbooks_path)
@data_bags_path = prepare_folders_config(@data_bags_path)
+ @nodes_path = prepare_folders_config(@nodes_path)
@roles_path = prepare_folders_config(@roles_path)
@environments_path = prepare_folders_config(@environments_path)
diff --git a/plugins/provisioners/chef/provisioner/chef_solo.rb b/plugins/provisioners/chef/provisioner/chef_solo.rb
index f3b52f178..14ee5747c 100644
--- a/plugins/provisioners/chef/provisioner/chef_solo.rb
+++ b/plugins/provisioners/chef/provisioner/chef_solo.rb
@@ -33,12 +33,14 @@ module VagrantPlugins
@role_folders = expanded_folders(@config.roles_path, "roles")
@data_bags_folders = expanded_folders(@config.data_bags_path, "data_bags")
@environments_folders = expanded_folders(@config.environments_path, "environments")
+ @node_folders = expanded_folders(@config.nodes_path, "nodes")
existing = synced_folders(@machine, cached: true)
share_folders(root_config, "csc", @cookbook_folders, existing)
share_folders(root_config, "csr", @role_folders, existing)
share_folders(root_config, "csdb", @data_bags_folders, existing)
share_folders(root_config, "cse", @environments_folders, existing)
+ share_folders(root_config, "csn", @node_folders, existing)
end
def provision
diff --git a/plugins/provisioners/chef/provisioner/chef_zero.rb b/plugins/provisioners/chef/provisioner/chef_zero.rb
index 48078a09f..70fff6854 100644
--- a/plugins/provisioners/chef/provisioner/chef_zero.rb
+++ b/plugins/provisioners/chef/provisioner/chef_zero.rb
@@ -44,6 +44,7 @@ module VagrantPlugins
local_mode: true,
enable_reporting: false,
cookbooks_path: guest_paths(@cookbook_folders),
+ nodes_path: guest_paths(@node_folders),
roles_path: guest_paths(@role_folders),
data_bags_path: guest_paths(@data_bags_folders).first,
environments_path: guest_paths(@environments_folders).first,
diff --git a/templates/provisioners/chef_zero/zero.erb b/templates/provisioners/chef_zero/zero.erb
index 29de30d23..8c4b76407 100644
--- a/templates/provisioners/chef_zero/zero.erb
+++ b/templates/provisioners/chef_zero/zero.erb
@@ -31,8 +31,8 @@ environment "<%= environment %>"
chef_zero.enabled true
local_mode true
<% end -%>
-<% if node_path -%>
-node_path <%= node_path.inspect %>
+<% if nodes_path -%>
+node_path <%= nodes_path.inspect %>
<% end -%>
<% if formatter %>
From 15ec95328ad962ee4326e3cdcaca376af7cea8e0 Mon Sep 17 00:00:00 2001
From: Brian Dwyer
Date: Tue, 28 Jul 2015 13:24:39 -0400
Subject: [PATCH 023/484] Update test
---
.../plugins/provisioners/chef/config/chef_zero_test.rb | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/test/unit/plugins/provisioners/chef/config/chef_zero_test.rb b/test/unit/plugins/provisioners/chef/config/chef_zero_test.rb
index 2f9cd82aa..9a1f98cd6 100644
--- a/test/unit/plugins/provisioners/chef/config/chef_zero_test.rb
+++ b/test/unit/plugins/provisioners/chef/config/chef_zero_test.rb
@@ -50,6 +50,14 @@ describe VagrantPlugins::Chef::Config::ChefZero do
end
end
+ describe "#nodes_path" do
+ it "defaults to an empty array" do
+ subject.finalize!
+ expect(subject.nodes_path).to be_a(Array)
+ expect(subject.nodes_path).to be_empty
+ end
+ end
+
describe "#synced_folder_type" do
it "defaults to nil" do
subject.finalize!
From 01f0dccbdc3f26842ed74a018f7cf828e9e19234 Mon Sep 17 00:00:00 2001
From: Brian Dwyer
Date: Tue, 28 Jul 2015 13:25:25 -0400
Subject: [PATCH 024/484] Update documentation for Chef Zero `nodes_path`
---
website/docs/source/v2/provisioning/chef_zero.html.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/website/docs/source/v2/provisioning/chef_zero.html.md b/website/docs/source/v2/provisioning/chef_zero.html.md
index 4f35f362a..bd2527fc9 100644
--- a/website/docs/source/v2/provisioning/chef_zero.html.md
+++ b/website/docs/source/v2/provisioning/chef_zero.html.md
@@ -41,6 +41,9 @@ available below this section.
* `environments_path` (string) - A path where environment definitions are
located. By default, no environments folder is set.
+* `nodes_path` (string or array) - A list of paths where node objects (in JSON format) are stored. By default, no
+ nodes path is set.
+
* `environment` (string) - The environment you want the Chef run to be
a part of. This requires Chef 11.6.0 or later, and that `environments_path`
is set.
From 3f29be0de2e64498fa7b6d4bfcbe6414e1a5604b Mon Sep 17 00:00:00 2001
From: Ben Hines
Date: Tue, 28 Jul 2015 11:16:20 -0700
Subject: [PATCH 025/484] Fix string parse error in the environment path
missing error message.
---
plugins/provisioners/puppet/config/puppet.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/provisioners/puppet/config/puppet.rb b/plugins/provisioners/puppet/config/puppet.rb
index 9910c6e05..0761294ca 100644
--- a/plugins/provisioners/puppet/config/puppet.rb
+++ b/plugins/provisioners/puppet/config/puppet.rb
@@ -143,7 +143,7 @@ module VagrantPlugins
if !expanded_environment_file.file? && !expanded_environment_file.directory?
errors << I18n.t("vagrant.provisioners.puppet.environment_missing",
environment: environment.to_s,
- environment_path: expanded_path.to_s)
+ environmentpath: expanded_path.to_s)
end
end
end
From f13220cd748d67430f4236eefff9dfa69ef68237 Mon Sep 17 00:00:00 2001
From: Casey Lang
Date: Fri, 31 Jul 2015 14:10:57 -0400
Subject: [PATCH 026/484] Clarify config.ssh.insert_key docs
Modified the description of `config.ssh.insert_key` a bit to improve readability.
---
website/docs/source/v2/vagrantfile/ssh_settings.html.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/website/docs/source/v2/vagrantfile/ssh_settings.html.md b/website/docs/source/v2/vagrantfile/ssh_settings.html.md
index b07835b75..cadeca060 100644
--- a/website/docs/source/v2/vagrantfile/ssh_settings.html.md
+++ b/website/docs/source/v2/vagrantfile/ssh_settings.html.md
@@ -68,12 +68,12 @@ is enabled. Defaults to false.
`config.ssh.insert_key` - If `true`, Vagrant will automatically insert
-an keypair to use for SSH, replacing the default Vagrant's insecure key
+a keypair to use for SSH, replacing Vagrant's default insecure key
inside the machine if detected. By default, this is true.
This only has an effect if you don't already use private keys for
authentication or if you are relying on the default insecure key.
-If you don't have to take care about security in your project and want to
+If you don't have to care about security in your project and want to
keep using the default insecure key, set this to `false`.
From ea7b277f411da996fd911fe24e1219fe13800ff0 Mon Sep 17 00:00:00 2001
From: John Syrinek
Date: Fri, 31 Jul 2015 16:05:55 -0500
Subject: [PATCH 027/484] Prevent fatal error caused by attempting to upload
minion config to privileged directory
---
plugins/provisioners/salt/config.rb | 18 ------------------
plugins/provisioners/salt/provisioner.rb | 5 -----
2 files changed, 23 deletions(-)
diff --git a/plugins/provisioners/salt/config.rb b/plugins/provisioners/salt/config.rb
index 9c564179e..38aaec8de 100644
--- a/plugins/provisioners/salt/config.rb
+++ b/plugins/provisioners/salt/config.rb
@@ -20,7 +20,6 @@ module VagrantPlugins
attr_accessor :bootstrap_script
attr_accessor :verbose
attr_accessor :seed_master
- attr_accessor :config_dir
attr_reader :pillar_data
attr_accessor :colorize
attr_accessor :log_level
@@ -65,7 +64,6 @@ module VagrantPlugins
@install_command = UNSET_VALUE
@no_minion = UNSET_VALUE
@bootstrap_options = UNSET_VALUE
- @config_dir = UNSET_VALUE
@masterless = UNSET_VALUE
@minion_id = UNSET_VALUE
@version = UNSET_VALUE
@@ -98,7 +96,6 @@ module VagrantPlugins
@install_command = nil if @install_command == UNSET_VALUE
@no_minion = nil if @no_minion == UNSET_VALUE
@bootstrap_options = nil if @bootstrap_options == UNSET_VALUE
- @config_dir = nil if @config_dir == UNSET_VALUE
@masterless = false if @masterless == UNSET_VALUE
@minion_id = nil if @minion_id == UNSET_VALUE
@version = nil if @version == UNSET_VALUE
@@ -111,17 +108,6 @@ module VagrantPlugins
@pillar_data = Vagrant::Util::DeepMerge.deep_merge(@pillar_data, data)
end
- def default_config_dir(machine)
- guest_type = machine.config.vm.guest || :linux
-
- # FIXME: there should be a way to do that a bit smarter
- if guest_type == :windows
- return "C:\\salt\\conf"
- else
- return "/etc/salt"
- end
- end
-
def validate(machine)
errors = _detected_errors
if @minion_config
@@ -161,10 +147,6 @@ module VagrantPlugins
errors << I18n.t("vagrant.provisioners.salt.must_accept_keys")
end
- if @config_dir.nil?
- @config_dir = default_config_dir(machine)
- end
-
return {"salt provisioner" => errors}
end
end
diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb
index d74c4fa11..5b217da4b 100644
--- a/plugins/provisioners/salt/provisioner.rb
+++ b/plugins/provisioners/salt/provisioner.rb
@@ -342,11 +342,6 @@ module VagrantPlugins
end
def call_highstate
- if @config.minion_config
- @machine.env.ui.info "Copying salt minion config to #{@config.config_dir}"
- @machine.communicate.upload(expanded_path(@config.minion_config).to_s, @config.config_dir + "/minion")
- end
-
if @config.masterless
call_masterless
elsif @config.run_highstate
From 587c88e65ae294c4f2939937c2079c545efd17cb Mon Sep 17 00:00:00 2001
From: Mike Averto
Date: Sun, 9 Aug 2015 12:44:49 -0400
Subject: [PATCH 028/484] Fix Win 10 Enterprise Vagrant Error
This fixes error for Win 10 Enterprise:
An error occurred while executing a PowerShell script. This error
is shown below. Please read the error message and see if this is
a configuration error with your system. If it is not, then please
report a bug.
Script: get_vm_status.ps1
Error:
C:\HashiCorp\Vagrant\embedded\gems\gems\vagrant-1.7.4\plugins\providers\hyperv\scripts\get_vm_status.ps1 : Unable to
find type [Microsoft.HyperV.PowerShell.VirtualizationOperationFailedException].
At line:1 char:1
+ &('C:\HashiCorp\Vagrant\embedded\gems\gems\vagrant-1.7.4\plugins\prov ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Microsoft.Hyper...FailedException:TypeName) [get_vm_status.ps1], Ru
ntimeException
+ FullyQualifiedErrorId : TypeNotFound,get_vm_status.ps1
---
plugins/providers/hyperv/scripts/get_vm_status.ps1 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/providers/hyperv/scripts/get_vm_status.ps1 b/plugins/providers/hyperv/scripts/get_vm_status.ps1
index 739560190..5c1e1aa73 100644
--- a/plugins/providers/hyperv/scripts/get_vm_status.ps1
+++ b/plugins/providers/hyperv/scripts/get_vm_status.ps1
@@ -12,7 +12,7 @@ try {
$VM = Get-VM -Id $VmId -ErrorAction "Stop"
$State = $VM.state
$Status = $VM.status
-} catch [Microsoft.HyperV.PowerShell.VirtualizationOperationFailedException] {
+} catch [Microsoft.HyperV.PowerShell.VirtualizationException] {
$State = "not_created"
$Status = $State
}
From 2a2f0a4751a7ea40f7db9941904291746d9729ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=B6ter?=
Date: Wed, 12 Aug 2015 14:25:54 +0200
Subject: [PATCH 029/484] Use hash of machine name for lock file to avoid
problems with invalid characters for file names.
---
plugins/providers/virtualbox/action/import_master.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/providers/virtualbox/action/import_master.rb b/plugins/providers/virtualbox/action/import_master.rb
index cba6216fd..61b0064eb 100644
--- a/plugins/providers/virtualbox/action/import_master.rb
+++ b/plugins/providers/virtualbox/action/import_master.rb
@@ -13,7 +13,7 @@ module VagrantPlugins
def call(env)
master_id_file = env[:machine].box.directory.join("master_id")
- env[:machine].env.lock(env[:machine].box.name, retry: true) do
+ env[:machine].env.lock(Digest::MD5.hexdigest(env[:machine].box.name), retry: true) do
env[:master_id] = master_id_file.read.chomp if master_id_file.file?
if env[:master_id] && env[:machine].provider.driver.vm_exists?(env[:master_id])
# Master VM already exists -> nothing to do - continue.
From 6f59c8bb548c70053c23c80ca7fb62429fa99496 Mon Sep 17 00:00:00 2001
From: Victor Costan
Date: Sat, 15 Aug 2015 06:19:51 -0400
Subject: [PATCH 030/484] The docs typo'd the nic_type parameter
The parameter name in the VirtualBox provider source is nic_type, not nictype.
The typo is probably caused by the fact that the parameter maps to nictype args in the VirtualBox CLI.
---
website/docs/source/v2/virtualbox/networking.html.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/website/docs/source/v2/virtualbox/networking.html.md b/website/docs/source/v2/virtualbox/networking.html.md
index 55e7d4c4c..5811373de 100644
--- a/website/docs/source/v2/virtualbox/networking.html.md
+++ b/website/docs/source/v2/virtualbox/networking.html.md
@@ -36,8 +36,8 @@ end
## VirtualBox NIC Type
-You can specify a specific nictype for the created network interface
-by using the `nictype` parameter. This isn't prefixed by `virtualbox__`
+You can specify a specific NIC type for the created network interface
+by using the `nic_type` parameter. This isn't prefixed by `virtualbox__`
for legacy reasons, but is VirtualBox-specific.
This is an advanced option and should only be used if you know what
@@ -48,6 +48,6 @@ Example:
```ruby
Vagrant.configure("2") do |config|
config.vm.network "private_network", ip: "192.168.50.4",
- nictype: "virtio"
+ nic_type: "virtio"
end
```
From 4425d91d863b3b36347ebc53550b13d8e6e5bc37 Mon Sep 17 00:00:00 2001
From: Victor Costan
Date: Sat, 15 Aug 2015 06:53:01 -0400
Subject: [PATCH 031/484] Don't warn about an .1 IP for DHCP networks
When the network's type is :dhcp, the :ip option is used to derive the DHCP server configuration, and it doesn't actually indicate the IP that will be received by the VM(s).
---
plugins/kernel_v2/config/vm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/kernel_v2/config/vm.rb b/plugins/kernel_v2/config/vm.rb
index 2de1b343f..5f2486179 100644
--- a/plugins/kernel_v2/config/vm.rb
+++ b/plugins/kernel_v2/config/vm.rb
@@ -688,7 +688,7 @@ module VagrantPlugins
end
end
- if options[:ip] && options[:ip].end_with?(".1")
+ if options[:ip] && options[:ip].end_with?(".1") && options[:type].to_sym != :dhcp
machine.ui.warn(I18n.t(
"vagrant.config.vm.network_ip_ends_in_one"))
end
From 0f8a88f4975a68c13057d7bcb6b55d04081a0766 Mon Sep 17 00:00:00 2001
From: Justin Campbell
Date: Mon, 17 Aug 2015 11:22:24 -0400
Subject: [PATCH 032/484] website/www: Fix logos/copyright alignment
Before:
![](http://cl.ly/image/2g2h0v1Z371r/Screen%20Shot%202015-08-17%20at%2011.22.48%20AM.png)
After:
![](http://cl.ly/image/0s1e2a272o2q/Screen%20Shot%202015-08-17%20at%2011.21.31%20AM.png)
---
website/www/source/layouts/layout.erb | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/website/www/source/layouts/layout.erb b/website/www/source/layouts/layout.erb
index 4e6736743..a510d31bf 100644
--- a/website/www/source/layouts/layout.erb
+++ b/website/www/source/layouts/layout.erb
@@ -78,9 +78,11 @@
-
- Copyright © <%= Time.now.year %> HashiCorp
-
+
+
+ Copyright © <%= Time.now.year %> HashiCorp
+
+
From c58c9a1ffccd576c6c08fb2edc721258808b9d6d Mon Sep 17 00:00:00 2001
From: Justin Campbell
Date: Mon, 17 Aug 2015 11:29:46 -0400
Subject: [PATCH 033/484] website/www: Add Atlas box search to nav
---
website/www/source/layouts/layout.erb | 1 +
1 file changed, 1 insertion(+)
diff --git a/website/www/source/layouts/layout.erb b/website/www/source/layouts/layout.erb
index 4e6736743..cbf2b8c88 100644
--- a/website/www/source/layouts/layout.erb
+++ b/website/www/source/layouts/layout.erb
@@ -41,6 +41,7 @@
- VMware Integration
- Downloads
+ - Boxes
- Documentation
- Blog
- About
From b897fd73651e263fc2b0fd364b7d6aba2f8f905d Mon Sep 17 00:00:00 2001
From: Lonnie VanZandt
Date: Tue, 18 Aug 2015 10:56:13 -0600
Subject: [PATCH 034/484] Scrub Guest Paths for Windows Rsync leaving Dirty
Paths for Winrm Mkdir
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Windows offers no out-of-the-box rsync utility. By far, the most
commonly used external utilities for Windows rsync are built with the
GNU Cygwin libraries. The cost for this convenience is that rsync on
Windows has to be provided paths that begin “/cygdrive/c” rather than
“c:/“ like other Windows-API utilities. Compounding the situation,
rsync doesn’t create paths/to/sub/targets and so the vagrant plugin
code, when performing an rsync, is responsible for creating
intermediate directories in guest paths if there are any. Furthermore,
the mkdir utility in Windows is not another Cygwin utility like rsync
but the routine mkdir of Windows command.com. Therefore, while rsync
needs the /cygwin paths, mkdir uses the Windows paths. Later, the
chef_solo.rp provisioner running within the guest will expect to find
Windows-style paths in its solo.rb configuration file. Due to all this,
vagrant has to keep track of both the original, possibly dirty Windows
guest path and the cygwin-scrubbed guest path.
---
plugins/guests/windows/cap/rsync.rb | 9 +++++++++
plugins/guests/windows/plugin.rb | 5 +++++
plugins/synced_folders/rsync/helper.rb | 5 +++++
3 files changed, 19 insertions(+)
diff --git a/plugins/guests/windows/cap/rsync.rb b/plugins/guests/windows/cap/rsync.rb
index e391b92db..aa9f1bcdf 100644
--- a/plugins/guests/windows/cap/rsync.rb
+++ b/plugins/guests/windows/cap/rsync.rb
@@ -2,8 +2,17 @@ module VagrantPlugins
module GuestWindows
module Cap
class RSync
+ def self.rsync_scrub_guestpath( machine, opts )
+ # Windows guests most often use cygwin-dependent rsync utilities
+ # that expect "/cygdrive/c" instead of "c:" as the path prefix
+ # some vagrant code may pass guest paths with drive-lettered paths here
+ opts[:guestpath].gsub( /^([a-zA-Z]):/, '/cygdrive/\1' )
+ end
+
def self.rsync_pre(machine, opts)
machine.communicate.tap do |comm|
+ # rsync does not construct any gaps in the path to the target directory
+ # make sure that all subdirectories are created
comm.execute("mkdir '#{opts[:guestpath]}'")
end
end
diff --git a/plugins/guests/windows/plugin.rb b/plugins/guests/windows/plugin.rb
index 47ca67e3f..d22dc2743 100644
--- a/plugins/guests/windows/plugin.rb
+++ b/plugins/guests/windows/plugin.rb
@@ -64,6 +64,11 @@ module VagrantPlugins
Cap::MountSharedFolder
end
+ guest_capability(:windows, :rsync_scrub_guestpath) do
+ require_relative "cap/rsync"
+ Cap::RSync
+ end
+
guest_capability(:windows, :rsync_pre) do
require_relative "cap/rsync"
Cap::RSync
diff --git a/plugins/synced_folders/rsync/helper.rb b/plugins/synced_folders/rsync/helper.rb
index 594410436..e155d61f7 100644
--- a/plugins/synced_folders/rsync/helper.rb
+++ b/plugins/synced_folders/rsync/helper.rb
@@ -38,6 +38,11 @@ module VagrantPlugins
hostpath = File.expand_path(hostpath, machine.env.root_path)
hostpath = Vagrant::Util::Platform.fs_real_path(hostpath).to_s
+ # if the guest has a guest path scrubber capability, use it
+ if machine.guest.capability?(:rsync_scrub_guestpath)
+ guestpath = machine.guest.capability(:rsync_scrub_guestpath, opts)
+ end
+
if Vagrant::Util::Platform.windows?
# rsync for Windows expects cygwin style paths, always.
hostpath = Vagrant::Util::Platform.cygwin_path(hostpath)
From d11ff3237066a3c65de32ae4e058122a6c958819 Mon Sep 17 00:00:00 2001
From: Chris Bednarski
Date: Wed, 19 Aug 2015 11:21:43 -0700
Subject: [PATCH 035/484] Change docs for checkpoint environment variable to
reflect the not-vagrant-specific version CHECKPOINT_DISABLE
---
website/docs/source/v2/other/environmental-variables.html.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/website/docs/source/v2/other/environmental-variables.html.md b/website/docs/source/v2/other/environmental-variables.html.md
index 41ecdd252..7ed73f4fd 100644
--- a/website/docs/source/v2/other/environmental-variables.html.md
+++ b/website/docs/source/v2/other/environmental-variables.html.md
@@ -17,12 +17,12 @@ when launching Vagrant from the official installer, you can specify the
`VAGRANT_DEBUG_LAUNCHER` environment variable to output debugging information
about the launch process.
-## VAGRANT\_CHECKPOINT\_DISABLE
+## CHECKPOINT\_DISABLE
Vagrant does occasional network calls to check whether the version of Vagrant
that is running locally is up to date. We understand that software making remote
calls over the internet for any reason can be undesirable. To surpress these
-calls, set the environment variable `VAGRANT_CHECKPOINT_DISABLE` to any
+calls, set the environment variable `CHECKPOINT_DISABLE` to any
non-empty value.
## VAGRANT\_CWD
From e7ca6acbfe6bea66ca1b7f8ebbfd6d96ff6557f5 Mon Sep 17 00:00:00 2001
From: Chris Bednarski
Date: Thu, 20 Aug 2015 14:34:23 -0700
Subject: [PATCH 036/484] Revert heading change and add note about
CHECKPOINT_DISABLE
---
.../docs/source/v2/other/environmental-variables.html.md | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/website/docs/source/v2/other/environmental-variables.html.md b/website/docs/source/v2/other/environmental-variables.html.md
index 7ed73f4fd..866b4369a 100644
--- a/website/docs/source/v2/other/environmental-variables.html.md
+++ b/website/docs/source/v2/other/environmental-variables.html.md
@@ -17,14 +17,17 @@ when launching Vagrant from the official installer, you can specify the
`VAGRANT_DEBUG_LAUNCHER` environment variable to output debugging information
about the launch process.
-## CHECKPOINT\_DISABLE
+## VAGRANT\_CHECKPOINT\_DISABLE
Vagrant does occasional network calls to check whether the version of Vagrant
that is running locally is up to date. We understand that software making remote
calls over the internet for any reason can be undesirable. To surpress these
-calls, set the environment variable `CHECKPOINT_DISABLE` to any
+calls, set the environment variable `VAGRANT_CHECKPOINT_DISABLE` to any
non-empty value.
+If you use other HashiCorp tools like Packer and would prefer to configure this
+setting only once, you can set `CHECKPOINT_DISABLE` instead.
+
## VAGRANT\_CWD
`VAGRANT_CWD` can be set to change the working directory of Vagrant. By
From f71b27ff27b3061c3206ce48762ee4a79f56005d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?=
Date: Fri, 21 Aug 2015 12:49:36 +0300
Subject: [PATCH 037/484] fix network detection on pld-linux
pld linux uses redhat as base, but lacks :flavour
this will add it
---
plugins/guests/pld/cap/flavor.rb | 11 +++++++++++
plugins/guests/pld/plugin.rb | 5 +++++
2 files changed, 16 insertions(+)
create mode 100644 plugins/guests/pld/cap/flavor.rb
diff --git a/plugins/guests/pld/cap/flavor.rb b/plugins/guests/pld/cap/flavor.rb
new file mode 100644
index 000000000..5ade9d18c
--- /dev/null
+++ b/plugins/guests/pld/cap/flavor.rb
@@ -0,0 +1,11 @@
+module VagrantPlugins
+ module GuestPld
+ module Cap
+ class Flavor
+ def self.flavor(machine)
+ return :pld
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/pld/plugin.rb b/plugins/guests/pld/plugin.rb
index ef7939fad..697599c81 100644
--- a/plugins/guests/pld/plugin.rb
+++ b/plugins/guests/pld/plugin.rb
@@ -20,6 +20,11 @@ module VagrantPlugins
require_relative "cap/network_scripts_dir"
Cap::NetworkScriptsDir
end
+
+ guest_capability("pld", "flavor") do
+ require_relative "cap/flavor"
+ Cap::Flavor
+ end
end
end
end
From af0f267b5089098ded8c2c3e6b8495cbeb8cbcdd Mon Sep 17 00:00:00 2001
From: Arlo Louis O'Keeffe
Date: Wed, 26 Aug 2015 00:15:03 +0200
Subject: [PATCH 038/484] Check if Schedule.Service com object is available
---
.../communicators/winrm/scripts/elevated_shell.ps1.erb | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
index 17767e436..77529aa76 100644
--- a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
+++ b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
@@ -1,5 +1,13 @@
param([String]$username, [String]$password, [String]$encoded_command)
+$schedule = $null
+Try {
+ $schedule = New-Object -ComObject "Schedule.Service"
+} Catch [System.Management.Automation.PSArgumentException] {
+ powershell.exe -EncodedCommand $encoded_command
+ exit $LASTEXITCODE
+}
+
$task_name = "WinRM_Elevated_Shell"
$out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell.log"
@@ -50,7 +58,6 @@ $arguments = "/c powershell.exe -EncodedCommand $encoded_command > $out_file
$task_xml = $task_xml.Replace("{arguments}", $arguments)
$task_xml = $task_xml.Replace("{username}", $username)
-$schedule = New-Object -ComObject "Schedule.Service"
$schedule.Connect()
$task = $schedule.NewTask($null)
$task.XmlText = $task_xml
From be90f6b1da85b6dd9e52617f344004cf8253718e Mon Sep 17 00:00:00 2001
From: Dusty Mabe
Date: Thu, 27 Aug 2015 16:44:17 -0400
Subject: [PATCH 039/484] Fix Fedora /etc/hosts bug
Update so that localhost entries don't get deleted when the hostname
gets added to the 127.0.0.1 line. Closes #6202
---
plugins/guests/fedora/cap/change_host_name.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/guests/fedora/cap/change_host_name.rb b/plugins/guests/fedora/cap/change_host_name.rb
index 2a93b9de6..f0c95eec6 100644
--- a/plugins/guests/fedora/cap/change_host_name.rb
+++ b/plugins/guests/fedora/cap/change_host_name.rb
@@ -48,7 +48,7 @@ module VagrantPlugins
def update_etc_hosts
ip_address = '([0-9]{1,3}\.){3}[0-9]{1,3}'
search = "^(#{ip_address})\\s+#{Regexp.escape(current_hostname)}(\\s.*)?$"
- replace = "\\1 #{fqdn} #{short_hostname}"
+ replace = "\\1 #{fqdn} #{short_hostname} \\3"
expression = ['s', search, replace, 'g'].join('@')
sudo("sed -ri '#{expression}' /etc/hosts")
@@ -72,4 +72,4 @@ module VagrantPlugins
end
end
end
-end
\ No newline at end of file
+end
From 18d229ca829536c115e351489f88891376232620 Mon Sep 17 00:00:00 2001
From: Jeremy Roberts
Date: Sun, 30 Aug 2015 13:09:25 -0400
Subject: [PATCH 040/484] Added execution_time_limit for WinRM.
Adds a configurable value for WinRm and the elevated permission shell ExecutionTimeLimit.
Please see mitchellh/vagrant#5506
Ex: config.winrm.execution_time_limit = "P1D"
---
plugins/communicators/winrm/communicator.rb | 3 ++-
plugins/communicators/winrm/config.rb | 4 ++++
plugins/communicators/winrm/scripts/elevated_shell.ps1.erb | 5 +++--
plugins/communicators/winrm/shell.rb | 2 ++
4 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/plugins/communicators/winrm/communicator.rb b/plugins/communicators/winrm/communicator.rb
index fdb3fe615..38fda78f9 100644
--- a/plugins/communicators/winrm/communicator.rb
+++ b/plugins/communicators/winrm/communicator.rb
@@ -210,7 +210,8 @@ module VagrantPlugins
"powershell -executionpolicy bypass -file \"#{guest_script_path}\" " +
"-username \"#{shell.username}\" -password \"#{shell.password}\" " +
- "-encoded_command \"#{wrapped_encoded_command}\""
+ "-encoded_command \"#{wrapped_encoded_command}\" " +
+ "-execution_time_limit \"#{shell.execution_time_limit}\""
end
# Handles the raw WinRM shell result and converts it to a
diff --git a/plugins/communicators/winrm/config.rb b/plugins/communicators/winrm/config.rb
index 79901d503..3387ca142 100644
--- a/plugins/communicators/winrm/config.rb
+++ b/plugins/communicators/winrm/config.rb
@@ -11,6 +11,7 @@ module VagrantPlugins
attr_accessor :timeout
attr_accessor :transport
attr_accessor :ssl_peer_verification
+ attr_accessor :execution_time_limit
def initialize
@username = UNSET_VALUE
@@ -23,6 +24,7 @@ module VagrantPlugins
@timeout = UNSET_VALUE
@transport = UNSET_VALUE
@ssl_peer_verification = UNSET_VALUE
+ @execution_time_limit = UNSET_VALUE
end
def finalize!
@@ -37,6 +39,7 @@ module VagrantPlugins
@retry_delay = 2 if @retry_delay == UNSET_VALUE
@timeout = 1800 if @timeout == UNSET_VALUE
@ssl_peer_verification = true if @ssl_peer_verification == UNSET_VALUE
+ @execution_time_limit = "PT2H" if @execution_time_limit == UNSET_VALUE
end
def validate(machine)
@@ -49,6 +52,7 @@ module VagrantPlugins
errors << "winrm.max_tries cannot be nil." if @max_tries.nil?
errors << "winrm.retry_delay cannot be nil." if @max_tries.nil?
errors << "winrm.timeout cannot be nil." if @timeout.nil?
+ errors << "winrm.execution_time_limit cannot be nil." if @execution_time_limit.nil?
unless @ssl_peer_verification == true || @ssl_peer_verification == false
errors << "winrm.ssl_peer_verification must be a boolean."
end
diff --git a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
index 17767e436..66bc94043 100644
--- a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
+++ b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
@@ -1,4 +1,4 @@
-param([String]$username, [String]$password, [String]$encoded_command)
+param([String]$username, [String]$password, [String]$encoded_command, [String]$execution_time_limit)
$task_name = "WinRM_Elevated_Shell"
$out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell.log"
@@ -33,7 +33,7 @@ $task_xml = @'
false
false
false
- PT2H
+ {execution_time_limit}
4
@@ -49,6 +49,7 @@ $arguments = "/c powershell.exe -EncodedCommand $encoded_command > $out_file
$task_xml = $task_xml.Replace("{arguments}", $arguments)
$task_xml = $task_xml.Replace("{username}", $username)
+$task_xml = $task_xml.Replace("{execution_time_limit}", $execution_time_limit)
$schedule = New-Object -ComObject "Schedule.Service"
$schedule.Connect()
diff --git a/plugins/communicators/winrm/shell.rb b/plugins/communicators/winrm/shell.rb
index 9b0f4e302..967565046 100644
--- a/plugins/communicators/winrm/shell.rb
+++ b/plugins/communicators/winrm/shell.rb
@@ -37,6 +37,7 @@ module VagrantPlugins
attr_reader :port
attr_reader :username
attr_reader :password
+ attr_reader :execution_time_limit
attr_reader :config
def initialize(host, port, config)
@@ -47,6 +48,7 @@ module VagrantPlugins
@port = port
@username = config.username
@password = config.password
+ @execution_time_limit = config.execution_time_limit
@config = config
end
From 44154c92a90e32b5b5189ece0d12f086198bdd77 Mon Sep 17 00:00:00 2001
From: Jeremy Roberts
Date: Sun, 30 Aug 2015 21:08:39 -0400
Subject: [PATCH 041/484] Fixing WinRM communicator unit test.
---
test/unit/plugins/communicators/winrm/communicator_test.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/unit/plugins/communicators/winrm/communicator_test.rb b/test/unit/plugins/communicators/winrm/communicator_test.rb
index ceea0985d..42588a511 100644
--- a/test/unit/plugins/communicators/winrm/communicator_test.rb
+++ b/test/unit/plugins/communicators/winrm/communicator_test.rb
@@ -20,6 +20,7 @@ describe VagrantPlugins::CommunicatorWinRM::Communicator do
before do
allow(shell).to receive(:username).and_return('vagrant')
allow(shell).to receive(:password).and_return('password')
+ allow(shell).to receive(:execution_time_limit).and_return('PT2H')
end
describe ".ready?" do
@@ -56,7 +57,7 @@ describe VagrantPlugins::CommunicatorWinRM::Communicator do
expect(shell).to receive(:upload).with(kind_of(String), "c:/tmp/vagrant-elevated-shell.ps1")
expect(shell).to receive(:powershell) do |cmd|
expect(cmd).to eq("powershell -executionpolicy bypass -file \"c:/tmp/vagrant-elevated-shell.ps1\" " +
- "-username \"vagrant\" -password \"password\" -encoded_command \"ZABpAHIAOwAgAGUAeABpAHQAIAAkAEwAQQBTAFQARQBYAEkAVABDAE8ARABFAA==\"")
+ "-username \"vagrant\" -password \"password\" -encoded_command \"ZABpAHIAOwAgAGUAeABpAHQAIAAkAEwAQQBTAFQARQBYAEkAVABDAE8ARABFAA==\" -execution_time_limit \"PT2H\"")
end.and_return({ exitcode: 0 })
expect(subject.execute("dir", { elevated: true })).to eq(0)
end
From c844a9c4fd587c78b8ada9c2ac521712aa99f0f2 Mon Sep 17 00:00:00 2001
From: Jeremy Roberts
Date: Mon, 31 Aug 2015 11:27:08 -0400
Subject: [PATCH 042/484] Adding WinRM execution_time_limit to log.
---
plugins/communicators/winrm/communicator.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/plugins/communicators/winrm/communicator.rb b/plugins/communicators/winrm/communicator.rb
index 38fda78f9..6a11d985c 100644
--- a/plugins/communicators/winrm/communicator.rb
+++ b/plugins/communicators/winrm/communicator.rb
@@ -38,6 +38,7 @@ module VagrantPlugins
# Got it! Let the user know what we're connecting to.
@machine.ui.detail("WinRM address: #{shell.host}:#{shell.port}")
@machine.ui.detail("WinRM username: #{shell.username}")
+ @machine.ui.detail("WinRM execution_time_limit: #{shell.execution_time_limit}")
@machine.ui.detail("WinRM transport: #{shell.config.transport}")
last_message = nil
From c7186236f1ae30b6f4824b5aa2c56574c2fd7e5c Mon Sep 17 00:00:00 2001
From: Jeff Goldschrafe
Date: Mon, 31 Aug 2015 16:50:58 -0400
Subject: [PATCH 043/484] Better Ubuntu systemd detection
Check the running process at PID 1 to determine which init system is currently in use.
---
plugins/guests/ubuntu/cap/change_host_name.rb | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/plugins/guests/ubuntu/cap/change_host_name.rb b/plugins/guests/ubuntu/cap/change_host_name.rb
index 706d4850a..df68a010a 100644
--- a/plugins/guests/ubuntu/cap/change_host_name.rb
+++ b/plugins/guests/ubuntu/cap/change_host_name.rb
@@ -7,7 +7,7 @@ module VagrantPlugins
end
def update_etc_hostname
- return super unless vivid?
+ return super unless systemd?
sudo("hostnamectl set-hostname '#{short_hostname}'")
end
@@ -15,7 +15,7 @@ module VagrantPlugins
if hardy?
# hostname.sh returns 1, so use `true` to get a 0 exitcode
sudo("/etc/init.d/hostname.sh start; true")
- elsif vivid?
+ elsif systemd?
# Service runs via hostnamectl
else
sudo("service hostname start")
@@ -26,19 +26,25 @@ module VagrantPlugins
os_version("hardy")
end
- def vivid?
- os_version("vivid")
- end
-
def renew_dhcp
sudo("ifdown -a; ifup -a; ifup -a --allow=hotplug")
end
private
+ def init_package
+ machine.communicate.execute('cat /proc/1/comm') do |type, data|
+ return data.chomp if type == :stdout
+ end
+ end
+
def os_version(name)
machine.communicate.test("[ `lsb_release -c -s` = #{name} ]")
end
+
+ def systemd?
+ init_package == 'systemd'
+ end
end
end
end
From 1e84cc4d6aa5eff2f27fc2e13663aa9734336a4f Mon Sep 17 00:00:00 2001
From: Paul Hinze
Date: Wed, 2 Sep 2015 16:36:23 -0500
Subject: [PATCH 044/484] communicators/winrm: respect boot_timeout when
fetching winrm_info
We gained a ton of improvemnts to WinRM error handling in
https://github.com/mitchellh/vagrant/pull/4943, but we also got one bug.
The new code raises an exception when `winrm_info` does not return right
away. This was preventing us from catching the retry/timout logic that's
meant to wait until boot_timeout for the WinRM communicator to be ready.
This restores the proper behavior by rescuing the WinRMNotReady
exception and continuing to retry until the surrounding timeout fires.
---
plugins/communicators/winrm/communicator.rb | 7 +++-
.../communicators/winrm/communicator_test.rb | 38 +++++++++++++++++--
2 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/plugins/communicators/winrm/communicator.rb b/plugins/communicators/winrm/communicator.rb
index fdb3fe615..b14b28efa 100644
--- a/plugins/communicators/winrm/communicator.rb
+++ b/plugins/communicators/winrm/communicator.rb
@@ -30,7 +30,12 @@ module VagrantPlugins
# Wait for winrm_info to be ready
winrm_info = nil
while true
- winrm_info = Helper.winrm_info(@machine)
+ winrm_info = nil
+ begin
+ winrm_info = Helper.winrm_info(@machine)
+ rescue Errors::WinRMNotReady
+ @logger.debug("WinRM not ready yet; retrying until boot_timeout is reached.")
+ end
break if winrm_info
sleep 0.5
end
diff --git a/test/unit/plugins/communicators/winrm/communicator_test.rb b/test/unit/plugins/communicators/winrm/communicator_test.rb
index ceea0985d..e98f646b3 100644
--- a/test/unit/plugins/communicators/winrm/communicator_test.rb
+++ b/test/unit/plugins/communicators/winrm/communicator_test.rb
@@ -5,10 +5,11 @@ require Vagrant.source_root.join("plugins/communicators/winrm/communicator")
describe VagrantPlugins::CommunicatorWinRM::Communicator do
include_context "unit"
- let(:winrm) { double("winrm", timeout: 1) }
+ let(:winrm) { double("winrm", timeout: 1, host: nil, port: 5986, guest_port: 5986) }
let(:config) { double("config", winrm: winrm) }
- let(:machine) { double("machine", config: config) }
-
+ let(:provider) { double("provider") }
+ let(:ui) { double("ui") }
+ let(:machine) { double("machine", config: config, provider: provider, ui: ui) }
let(:shell) { double("shell") }
subject do
@@ -22,6 +23,37 @@ describe VagrantPlugins::CommunicatorWinRM::Communicator do
allow(shell).to receive(:password).and_return('password')
end
+ describe ".wait_for_ready" do
+ context "with no winrm_info capability and no static config (default scenario)" do
+ before do
+ # No default providers support this capability
+ allow(provider).to receive(:capability?).with(:winrm_info).and_return(false)
+
+ # Get us through the detail prints
+ allow(ui).to receive(:detail)
+ allow(shell).to receive(:host)
+ allow(shell).to receive(:port)
+ allow(shell).to receive(:username)
+ allow(shell).to receive(:config) { double("config", transport: nil)}
+ end
+
+ context "when ssh_info requires a multiple tries before it is ready" do
+ before do
+ allow(machine).to receive(:ssh_info).and_return(nil, {
+ host: '10.1.2.3',
+ port: '22',
+ })
+ # Makes ready? return true
+ allow(shell).to receive(:powershell).with("hostname").and_return({ exitcode: 0 })
+ end
+
+ it "retries ssh_info until ready" do
+ expect(subject.wait_for_ready(2)).to eq(true)
+ end
+ end
+ end
+ end
+
describe ".ready?" do
it "returns true if hostname command executes without error" do
expect(shell).to receive(:powershell).with("hostname").and_return({ exitcode: 0 })
From 4b32744424ee3c0307ee9a24ad9bba330e9ad5ed Mon Sep 17 00:00:00 2001
From: Jeff Kwan
Date: Thu, 3 Sep 2015 16:54:41 -0400
Subject: [PATCH 045/484] Use a .NET API call instead of a Win8+ cmdlet
The root cause is that Windows 7 doesn't have Get-NetIPAddress (
see:
https://stackoverflow.com/questions/19529442/gather-ip-address-information
)
but the change was to try and solve the bug that the VPN IP
addresses
aren't visible detailed
here:
https://support.microsoft.com/en-us/kb/2549091
Resolved using the
2nd solution
from
http://serverfault.com/questions/145259/powershell-win32-networkadapterconfiguration-not-seeing-ppp-adapter
---
.../synced_folders/smb/scripts/host_info.ps1 | 32 ++++++++++++-------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/plugins/synced_folders/smb/scripts/host_info.ps1 b/plugins/synced_folders/smb/scripts/host_info.ps1
index 0e089932e..c4f13aada 100644
--- a/plugins/synced_folders/smb/scripts/host_info.ps1
+++ b/plugins/synced_folders/smb/scripts/host_info.ps1
@@ -1,11 +1,21 @@
-$ErrorAction = "Stop"
-
-$net = Get-NetIPAddress | Where-Object {
- ($_.IPAddress -ne "127.0.0.1") -and ($_.IPAddress -ne "::1")
-} | Sort-Object $_.AddressFamily
-
-$result = @{
- ip_addresses = $net.IPAddress
-}
-
-Write-Output $(ConvertTo-Json $result)
+$ErrorAction = "Stop"
+
+# Find all of the NICsq
+$nics = [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces()
+
+# Save the IP addresses somewhere
+$nic_ip_addresses = @()
+
+foreach ($nic in $nics) {
+ $nic_ip_addresses += $nic.GetIPProperties().UnicastAddresses | Where-Object {
+ ($_.Address.IPAddressToString -ne "127.0.0.1") -and ($_.Address.IPAddressToString -ne "::1")
+ } | Select -ExpandProperty Address
+}
+
+$nic_ip_addresses = $nic_ip_addresses | Sort-Object $_.AddressFamily
+
+$result = @{
+ ip_addresses = $nic_ip_addresses.IPAddressToString
+}
+
+Write-Output $(ConvertTo-Json $result)
From 1911586832132f93669d2db58a2add78b70e432b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?=
Date: Thu, 10 Sep 2015 10:05:14 +0200
Subject: [PATCH 046/484] Better NFS status check command for SUSE
---
plugins/hosts/suse/cap/nfs.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/hosts/suse/cap/nfs.rb b/plugins/hosts/suse/cap/nfs.rb
index 42bde6bb2..789c6cb47 100644
--- a/plugins/hosts/suse/cap/nfs.rb
+++ b/plugins/hosts/suse/cap/nfs.rb
@@ -7,7 +7,7 @@ module VagrantPlugins
end
def self.nfs_check_command(env)
- "pidof nfsd > /dev/null"
+ "/sbin/service nfsserver status"
end
def self.nfs_start_command(env)
From 33b4d6a63d9275ce9b3156883cac32551a79038d Mon Sep 17 00:00:00 2001
From: Philip Wigg
Date: Fri, 11 Sep 2015 20:06:21 +0100
Subject: [PATCH 047/484] Fix verify_binary for Puppet for Windows guests.
---
plugins/provisioners/puppet/provisioner/puppet.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/provisioners/puppet/provisioner/puppet.rb b/plugins/provisioners/puppet/provisioner/puppet.rb
index f1987dbd5..6cd8716aa 100644
--- a/plugins/provisioners/puppet/provisioner/puppet.rb
+++ b/plugins/provisioners/puppet/provisioner/puppet.rb
@@ -150,7 +150,7 @@ module VagrantPlugins
# This is very platform dependent.
test_cmd = "sh -c 'command -v #{binary}'"
if windows?
- test_cmd = "which #{binary}"
+ test_cmd = "where #{binary}"
if @config.binary_path
test_cmd = "where \"#{@config.binary_path}:#{binary}\""
end
From acde6e1b16674f3d63f6d2e94e43ce57c95641fa Mon Sep 17 00:00:00 2001
From: Rickard von Essen
Date: Sun, 20 Sep 2015 09:30:49 +0200
Subject: [PATCH 048/484] Use dnf on Fedora guests instead of yum if available.
Fixes #6286 now properly installs Docker on Fedora guests.
Fixes #6287 use dnf if available.
---
plugins/guests/redhat/cap/nfs_client.rb | 6 +++-
plugins/guests/redhat/cap/rsync.rb | 6 +++-
plugins/guests/redhat/plugin.rb | 4 +++
.../cfengine/cap/redhat/cfengine_install.rb | 12 ++++++-
.../chef/cap/redhat/chef_install.rb | 12 ++++++-
.../docker/cap/fedora/docker_install.rb | 31 +++++++++++++++++++
plugins/provisioners/docker/plugin.rb | 5 +++
7 files changed, 72 insertions(+), 4 deletions(-)
create mode 100644 plugins/provisioners/docker/cap/fedora/docker_install.rb
diff --git a/plugins/guests/redhat/cap/nfs_client.rb b/plugins/guests/redhat/cap/nfs_client.rb
index ef88e9900..78e2d5bca 100644
--- a/plugins/guests/redhat/cap/nfs_client.rb
+++ b/plugins/guests/redhat/cap/nfs_client.rb
@@ -3,7 +3,11 @@ module VagrantPlugins
module Cap
class NFSClient
def self.nfs_client_install(machine)
- machine.communicate.sudo("yum -y install nfs-utils nfs-utils-lib")
+ if VagrantPlugins::GuestRedHat::Plugin.dnf?(machine)
+ machine.communicate.sudo("dnf -y install nfs-utils nfs-utils-lib")
+ else
+ machine.communicate.sudo("yum -y install nfs-utils nfs-utils-lib")
+ end
restart_nfs(machine)
end
diff --git a/plugins/guests/redhat/cap/rsync.rb b/plugins/guests/redhat/cap/rsync.rb
index 9a1cfeeac..8eace63f0 100644
--- a/plugins/guests/redhat/cap/rsync.rb
+++ b/plugins/guests/redhat/cap/rsync.rb
@@ -4,7 +4,11 @@ module VagrantPlugins
class RSync
def self.rsync_install(machine)
machine.communicate.tap do |comm|
- comm.sudo("yum -y install rsync")
+ if VagrantPlugins::GuestRedHat::Plugin.dnf?(machine)
+ comm.sudo("dnf -y install rsync")
+ else
+ comm.sudo("yum -y install rsync")
+ end
end
end
end
diff --git a/plugins/guests/redhat/plugin.rb b/plugins/guests/redhat/plugin.rb
index 96e641bcb..0a97febee 100644
--- a/plugins/guests/redhat/plugin.rb
+++ b/plugins/guests/redhat/plugin.rb
@@ -45,6 +45,10 @@ module VagrantPlugins
require_relative "cap/rsync"
Cap::RSync
end
+
+ def self.dnf?(machine)
+ machine.communicate.test("/usr/bin/which -s dnf")
+ end
end
end
end
diff --git a/plugins/provisioners/cfengine/cap/redhat/cfengine_install.rb b/plugins/provisioners/cfengine/cap/redhat/cfengine_install.rb
index 828b336d6..f22979388 100644
--- a/plugins/provisioners/cfengine/cap/redhat/cfengine_install.rb
+++ b/plugins/provisioners/cfengine/cap/redhat/cfengine_install.rb
@@ -14,9 +14,19 @@ module VagrantPlugins
logger.info("Installing CFEngine Community Yum Repository GPG KEY from #{config.repo_gpg_key_url}")
comm.sudo("GPGFILE=$(mktemp) && wget -O $GPGFILE #{config.repo_gpg_key_url} && rpm --import $GPGFILE; rm -f $GPGFILE")
- comm.sudo("yum -y install #{config.package_name}")
+ if dnf?(machine)
+ comm.sudo("dnf -y install #{config.package_name}")
+ else
+ comm.sudo("yum -y install #{config.package_name}")
+ end
end
end
+
+ protected
+
+ def self.dnf?(machine)
+ machine.communicate.test("/usr/bin/which -s dnf")
+ end
end
end
end
diff --git a/plugins/provisioners/chef/cap/redhat/chef_install.rb b/plugins/provisioners/chef/cap/redhat/chef_install.rb
index c6aff7bad..7d376e7d0 100644
--- a/plugins/provisioners/chef/cap/redhat/chef_install.rb
+++ b/plugins/provisioners/chef/cap/redhat/chef_install.rb
@@ -6,11 +6,21 @@ module VagrantPlugins
module Redhat
module ChefInstall
def self.chef_install(machine, version, prerelease, download_path)
- machine.communicate.sudo("yum install -y -q curl")
+ if dnf?(machine)
+ machine.communicate.sudo("dnf install -y -q curl")
+ else
+ machine.communicate.sudo("yum install -y -q curl")
+ end
command = Omnibus.build_command(version, prerelease, download_path)
machine.communicate.sudo(command)
end
+
+ protected
+
+ def self.dnf?(machine)
+ machine.communicate.test("/usr/bin/which -s dnf")
+ end
end
end
end
diff --git a/plugins/provisioners/docker/cap/fedora/docker_install.rb b/plugins/provisioners/docker/cap/fedora/docker_install.rb
new file mode 100644
index 000000000..16377f410
--- /dev/null
+++ b/plugins/provisioners/docker/cap/fedora/docker_install.rb
@@ -0,0 +1,31 @@
+module VagrantPlugins
+ module DockerProvisioner
+ module Cap
+ module Fedora
+ module DockerInstall
+ def self.docker_install(machine, version)
+ if version != :latest
+ machine.ui.warn(I18n.t("vagrant.docker_install_with_version_not_supported"))
+ end
+
+ machine.communicate.tap do |comm|
+ if dnf?(machine)
+ comm.sudo("dnf -y install docker")
+ else
+ comm.sudo("yum -y install docker")
+ end
+ comm.sudo("systemctl start docker.service")
+ comm.sudo("systemctl enable docker.service")
+ end
+ end
+
+ protected
+
+ def self.dnf?(machine)
+ machine.communicate.test("/usr/bin/which -s dnf")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/provisioners/docker/plugin.rb b/plugins/provisioners/docker/plugin.rb
index b606729ac..b39422cd0 100644
--- a/plugins/provisioners/docker/plugin.rb
+++ b/plugins/provisioners/docker/plugin.rb
@@ -24,6 +24,11 @@ module VagrantPlugins
Cap::Debian::DockerStartService
end
+ guest_capability("fedora", "docker_install") do
+ require_relative "cap/fedora/docker_install"
+ Cap::Fedora::DockerInstall
+ end
+
guest_capability("redhat", "docker_install") do
require_relative "cap/redhat/docker_install"
Cap::Redhat::DockerInstall
From f3215f0ae62376bb9168d8868b9d5a1a7d6ad781 Mon Sep 17 00:00:00 2001
From: J Lynn
Date: Wed, 23 Sep 2015 13:29:11 +1000
Subject: [PATCH 049/484] copied documentation from docs to website for
use_dhcp_assigned_default_route in order to complete documentation
---
.../docs/source/v2/networking/public_network.html.md | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/website/docs/source/v2/networking/public_network.html.md b/website/docs/source/v2/networking/public_network.html.md
index e52cbaf58..913f6164e 100644
--- a/website/docs/source/v2/networking/public_network.html.md
+++ b/website/docs/source/v2/networking/public_network.html.md
@@ -51,6 +51,17 @@ When DHCP is used, the IP can be determined by using `vagrant ssh` to
SSH into the machine and using the appropriate command line tool to find
the IP, such as `ifconfig`.
+### Using the DHCP Assigned Default Route
+
+Some cases require the DHCP assigned default route to be untouched. In these cases one
+my specify the :use_dhcp_assigned_default_route option. As an example:
+
+```ruby
+Vagrant.configure("2") do |config|
+ config.vm.network "public_network", use_dhcp_assigned_default_route: true
+end
+```
+
## Static IP
Depending on your setup, you may wish to manually set the IP of your
From f22bfcb8def85d5f4ba4634f6b7d1a81dc082aa2 Mon Sep 17 00:00:00 2001
From: J Lynn
Date: Wed, 23 Sep 2015 13:58:01 +1000
Subject: [PATCH 050/484] resolve formatting issues
---
website/docs/source/v2/networking/public_network.html.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/website/docs/source/v2/networking/public_network.html.md b/website/docs/source/v2/networking/public_network.html.md
index 913f6164e..91b2443b7 100644
--- a/website/docs/source/v2/networking/public_network.html.md
+++ b/website/docs/source/v2/networking/public_network.html.md
@@ -54,11 +54,12 @@ the IP, such as `ifconfig`.
### Using the DHCP Assigned Default Route
Some cases require the DHCP assigned default route to be untouched. In these cases one
-my specify the :use_dhcp_assigned_default_route option. As an example:
+may specify the `use_dhcp_assigned_default_route` option. As an example:
```ruby
Vagrant.configure("2") do |config|
- config.vm.network "public_network", use_dhcp_assigned_default_route: true
+ config.vm.network "public_network",
+ use_dhcp_assigned_default_route: true
end
```
From ed1c219a07180bb525d2eaa915625656bdefc888 Mon Sep 17 00:00:00 2001
From: Trey Briggs
Date: Tue, 22 Sep 2015 23:26:02 -0500
Subject: [PATCH 051/484] version is a Symbol, convert to String before concat.
---
plugins/provisioners/chef/cap/windows/chef_installed.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/provisioners/chef/cap/windows/chef_installed.rb b/plugins/provisioners/chef/cap/windows/chef_installed.rb
index c95ea8498..6ab3bd4b7 100644
--- a/plugins/provisioners/chef/cap/windows/chef_installed.rb
+++ b/plugins/provisioners/chef/cap/windows/chef_installed.rb
@@ -7,7 +7,7 @@ module VagrantPlugins
# @return [true, false]
def self.chef_installed(machine, version)
if version != :latest
- command = 'if ((&knife --version) -Match "Chef: "' + version + '"){ exit 0 } else { exit 1 }'
+ command = 'if ((&knife --version) -Match "Chef: "' + version.to_s + '"){ exit 0 } else { exit 1 }'
else
command = 'if ((&knife --version) -Match "Chef: *"){ exit 0 } else { exit 1 }'
end
From a5b6e23e201f57dcd2ef66373046ca4be921b349 Mon Sep 17 00:00:00 2001
From: Trey Briggs
Date: Tue, 22 Sep 2015 23:28:14 -0500
Subject: [PATCH 052/484] Removed extra quote in powershell command.
---
plugins/provisioners/chef/cap/windows/chef_installed.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/provisioners/chef/cap/windows/chef_installed.rb b/plugins/provisioners/chef/cap/windows/chef_installed.rb
index 6ab3bd4b7..b08794833 100644
--- a/plugins/provisioners/chef/cap/windows/chef_installed.rb
+++ b/plugins/provisioners/chef/cap/windows/chef_installed.rb
@@ -7,7 +7,7 @@ module VagrantPlugins
# @return [true, false]
def self.chef_installed(machine, version)
if version != :latest
- command = 'if ((&knife --version) -Match "Chef: "' + version.to_s + '"){ exit 0 } else { exit 1 }'
+ command = 'if ((&knife --version) -Match "Chef: ' + version.to_s + '"){ exit 0 } else { exit 1 }'
else
command = 'if ((&knife --version) -Match "Chef: *"){ exit 0 } else { exit 1 }'
end
From e0dad41b0c04de7a35b4fbf44b23eea1b41d1e4e Mon Sep 17 00:00:00 2001
From: Maarten De Wispelaere
Date: Thu, 24 Sep 2015 12:18:59 +0200
Subject: [PATCH 053/484] FIX: no exception for debian 8 needed, shutdown -h -H
doesn't work ; use normal shutdown -h now
---
plugins/guests/debian8/cap/halt.rb | 16 ----------------
plugins/guests/debian8/guest.rb | 9 ---------
plugins/guests/debian8/plugin.rb | 21 ---------------------
3 files changed, 46 deletions(-)
delete mode 100644 plugins/guests/debian8/cap/halt.rb
delete mode 100644 plugins/guests/debian8/guest.rb
delete mode 100644 plugins/guests/debian8/plugin.rb
diff --git a/plugins/guests/debian8/cap/halt.rb b/plugins/guests/debian8/cap/halt.rb
deleted file mode 100644
index 932281347..000000000
--- a/plugins/guests/debian8/cap/halt.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-module VagrantPlugins
- module GuestDebian8
- module Cap
- class Halt
- def self.halt(machine)
- begin
- machine.communicate.sudo("shutdown -h -H")
- rescue IOError
- # Do nothing, because it probably means the machine shut down
- # and SSH connection was lost.
- end
- end
- end
- end
- end
-end
diff --git a/plugins/guests/debian8/guest.rb b/plugins/guests/debian8/guest.rb
deleted file mode 100644
index ec95e9e85..000000000
--- a/plugins/guests/debian8/guest.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module VagrantPlugins
- module GuestDebian8
- class Guest < Vagrant.plugin("2", :guest)
- def detect?(machine)
- machine.communicate.test("cat /etc/issue | grep 'Debian' | grep '8'")
- end
- end
- end
-end
diff --git a/plugins/guests/debian8/plugin.rb b/plugins/guests/debian8/plugin.rb
deleted file mode 100644
index 1f566f5fa..000000000
--- a/plugins/guests/debian8/plugin.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require "vagrant"
-
-module VagrantPlugins
- module GuestDebian8
- class Plugin < Vagrant.plugin("2")
- name "Debian Jessie guest"
- description "Debian Jessie guest support."
-
- guest("debian8", "debian") do
- require File.expand_path("../guest", __FILE__)
- Guest
- end
-
- guest_capability("debian8", "halt") do
- require_relative "cap/halt"
- Cap::Halt
- end
-
- end
- end
-end
From 599feb5d0e179a2c0647109f238627a73016d014 Mon Sep 17 00:00:00 2001
From: Sam Handler
Date: Thu, 24 Sep 2015 16:41:40 -0700
Subject: [PATCH 054/484] Add Makefile to `website/docs`
---
website/docs/Makefile | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 website/docs/Makefile
diff --git a/website/docs/Makefile b/website/docs/Makefile
new file mode 100644
index 000000000..63bb4cab1
--- /dev/null
+++ b/website/docs/Makefile
@@ -0,0 +1,10 @@
+all: build
+
+init:
+ bundle
+
+dev: init
+ bundle exec middleman server
+
+build: init
+ bundle exec middleman build
\ No newline at end of file
From b4bd0c925eeb4a4674d67de7f5f47436c9e04569 Mon Sep 17 00:00:00 2001
From: Sam Handler
Date: Thu, 24 Sep 2015 16:42:27 -0700
Subject: [PATCH 055/484] Point website/docs README to Makefile and /v2 url
---
website/docs/README.md | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/website/docs/README.md b/website/docs/README.md
index ca4c038fe..e9ac25640 100644
--- a/website/docs/README.md
+++ b/website/docs/README.md
@@ -14,13 +14,7 @@ requests like any normal GitHub project, and we'll merge it in.
## Running the Site Locally
-Running the site locally is simple. Clone this repo and run the following
-commands:
+Running the site locally is simple. Clone this repo and run `make dev`.
-```
-$ bundle
-$ bundle exec middleman server
-```
-
-Then open up `localhost:4567`. Note that some URLs you may need to append
+Then open up `localhost:4567/v2`. Note that some URLs you may need to append
".html" to make them work (in the navigation and such).
From 73314cfcbef8ca659cf8aadcce75fcecb0c5f1c2 Mon Sep 17 00:00:00 2001
From: Sam Handler
Date: Thu, 24 Sep 2015 16:44:08 -0700
Subject: [PATCH 056/484] Add 'Edit this page' link to website/docs footer
---
website/docs/source/layouts/layout.erb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/website/docs/source/layouts/layout.erb b/website/docs/source/layouts/layout.erb
index 4fedc3627..38a735de3 100644
--- a/website/docs/source/layouts/layout.erb
+++ b/website/docs/source/layouts/layout.erb
@@ -324,6 +324,8 @@
- Documentation
- About
- Support
+ <% github_link = 'https://github.com/mitchellh/vagrant/blob/master/' + current_page.source_file.match(/website.*/)[0] %>
+ - Edit this page
- Download
From ab590f7740628cb7cf22550d22faa16452e8a2b8 Mon Sep 17 00:00:00 2001
From: Sam Handler
Date: Thu, 24 Sep 2015 16:44:54 -0700
Subject: [PATCH 057/484] Add Makefile to `website/www`
---
website/www/Makefile | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 website/www/Makefile
diff --git a/website/www/Makefile b/website/www/Makefile
new file mode 100644
index 000000000..63bb4cab1
--- /dev/null
+++ b/website/www/Makefile
@@ -0,0 +1,10 @@
+all: build
+
+init:
+ bundle
+
+dev: init
+ bundle exec middleman server
+
+build: init
+ bundle exec middleman build
\ No newline at end of file
From 33d602ba84a805be2e88b0ee71ef984026cb45e6 Mon Sep 17 00:00:00 2001
From: Sam Handler
Date: Thu, 24 Sep 2015 16:45:43 -0700
Subject: [PATCH 058/484] Point `website/www` README to Makefile
---
website/www/README.md | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/website/www/README.md b/website/www/README.md
index 814da3877..3645fa52c 100644
--- a/website/www/README.md
+++ b/website/www/README.md
@@ -14,13 +14,7 @@ requests like any normal GitHub project, and we'll merge it in.
## Running the Site Locally
-Running the site locally is simple. Clone this repo and run the following
-commands:
-
-```
-$ bundle
-$ bundle exec middleman server
-```
+Running the site locally is simple. Clone this repo and run `make dev`.
Then open up `localhost:4567`. Note that some URLs you may need to append
".html" to make them work (in the navigation and such).
From 094d8b89efc14a9c47c9dcd7833692e791f04025 Mon Sep 17 00:00:00 2001
From: Sam Handler
Date: Thu, 24 Sep 2015 16:47:14 -0700
Subject: [PATCH 059/484] Add 'Edit this page' link to website/www footer
---
website/www/source/layouts/layout.erb | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/website/www/source/layouts/layout.erb b/website/www/source/layouts/layout.erb
index 4e6736743..2daba176d 100644
--- a/website/www/source/layouts/layout.erb
+++ b/website/www/source/layouts/layout.erb
@@ -59,6 +59,10 @@
- Documentation
- About
- Support
+ <% if current_page.url != "/" %>
+ <% github_link = 'https://github.com/mitchellh/vagrant/blob/master/' + current_page.source_file.match(/website.*/)[0] %>
+ - Edit this page
+ <% end %>
- Download
From 6b033f2d65b3f347f813969fb032ef5ac3f62d4b Mon Sep 17 00:00:00 2001
From: Daniel Hahler
Date: Fri, 25 Sep 2015 15:14:12 +0200
Subject: [PATCH 060/484] doc: mention "directory" in the file provisioner
reference
---
.../docs/source/v2/provisioning/file.html.md | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/website/docs/source/v2/provisioning/file.html.md b/website/docs/source/v2/provisioning/file.html.md
index ca65c8bb9..0fab619ce 100644
--- a/website/docs/source/v2/provisioning/file.html.md
+++ b/website/docs/source/v2/provisioning/file.html.md
@@ -7,8 +7,8 @@ sidebar_current: "provisioning-file"
**Provisioner name: `"file"`**
-The file provisioner allows you to upload a file from the host machine to
-the guest machine.
+The file provisioner allows you to upload a file or directory from the host
+machine to the guest machine.
File provisioning is a simple way to, for example, replicate your local
~/.gitconfig to the vagrant user's home directory on the guest machine so
@@ -21,19 +21,20 @@ new VM.
config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"
end
-Note that, unlike with synced folders, files that are uploaded will not
-be kept in sync. Continuing with the example above, if you make further
-changes to your local ~/.gitconfig, they will not be immediately reflected
-in the copy you uploaded to the guest machine.
+Note that, unlike with synced folders, files or directories that are uploaded
+will not be kept in sync. Continuing with the example above, if you make
+further changes to your local ~/.gitconfig, they will not be immediately
+reflected in the copy you uploaded to the guest machine.
## Options
The file provisioner takes only two options, both of which are required:
-* `source` (string) - Is the local path of the file to be uploaded.
+* `source` (string) - Is the local path of the file or directory to be
+ uploaded.
* `destination` (string) - Is the remote path on the guest machine where
- the file will be uploaded to. The file is uploaded as the SSH user over
- SCP, so this location must be writable to that user. The SSH user can be
+ the source will be uploaded to. The file/folder is uploaded as the SSH user
+ over SCP, so this location must be writable to that user. The SSH user can be
determined by running `vagrant ssh-config`, and defaults to "vagrant".
From fd593a85b7034229e2428e2caa1a38355f0057e8 Mon Sep 17 00:00:00 2001
From: Brian Dwyer
Date: Sun, 27 Sep 2015 23:23:28 -0400
Subject: [PATCH 061/484] Add `nodes_path` support for the Chef-Solo
provisioner
---
plugins/provisioners/chef/config/chef_solo.rb | 7 +++++++
plugins/provisioners/chef/provisioner/chef_solo.rb | 2 ++
templates/provisioners/chef_solo/solo.erb | 4 ++--
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/plugins/provisioners/chef/config/chef_solo.rb b/plugins/provisioners/chef/config/chef_solo.rb
index ee4a2ac2e..a9630a7b8 100644
--- a/plugins/provisioners/chef/config/chef_solo.rb
+++ b/plugins/provisioners/chef/config/chef_solo.rb
@@ -17,6 +17,10 @@ module VagrantPlugins
# @return [String]
attr_accessor :environments_path
+ # The path where nodes are stored on disk.
+ # @return [String]
+ attr_accessor :nodes_path
+
# A URL download a remote recipe from. Note: you should use chef-apply
# instead.
#
@@ -39,6 +43,7 @@ module VagrantPlugins
@cookbooks_path = UNSET_VALUE
@data_bags_path = UNSET_VALUE
@environments_path = UNSET_VALUE
+ @nodes_path = UNSET_VALUE
@recipe_url = UNSET_VALUE
@roles_path = UNSET_VALUE
@synced_folder_type = UNSET_VALUE
@@ -86,6 +91,7 @@ module VagrantPlugins
end
@data_bags_path = [] if @data_bags_path == UNSET_VALUE
+ @nodes_path = [] if @nodes_path == UNSET_VALUE
@roles_path = [] if @roles_path == UNSET_VALUE
@environments_path = [] if @environments_path == UNSET_VALUE
@environments_path = [@environments_path].flatten
@@ -93,6 +99,7 @@ module VagrantPlugins
# Make sure the path is an array.
@cookbooks_path = prepare_folders_config(@cookbooks_path)
@data_bags_path = prepare_folders_config(@data_bags_path)
+ @nodes_path = prepare_folders_config(@nodes_path)
@roles_path = prepare_folders_config(@roles_path)
@environments_path = prepare_folders_config(@environments_path)
end
diff --git a/plugins/provisioners/chef/provisioner/chef_solo.rb b/plugins/provisioners/chef/provisioner/chef_solo.rb
index 14ee5747c..1fc29da6e 100644
--- a/plugins/provisioners/chef/provisioner/chef_solo.rb
+++ b/plugins/provisioners/chef/provisioner/chef_solo.rb
@@ -19,6 +19,7 @@ module VagrantPlugins
attr_reader :environments_folders
attr_reader :cookbook_folders
+ attr_reader :node_folders
attr_reader :role_folders
attr_reader :data_bags_folders
@@ -160,6 +161,7 @@ module VagrantPlugins
{
cookbooks_path: guest_paths(@cookbook_folders),
recipe_url: @config.recipe_url,
+ nodes_path: guest_paths(@node_folders),
roles_path: guest_paths(@role_folders),
data_bags_path: guest_paths(@data_bags_folders).first,
environments_path: guest_paths(@environments_folders).first
diff --git a/templates/provisioners/chef_solo/solo.erb b/templates/provisioners/chef_solo/solo.erb
index 25d3346b7..a3b01ed3b 100644
--- a/templates/provisioners/chef_solo/solo.erb
+++ b/templates/provisioners/chef_solo/solo.erb
@@ -31,8 +31,8 @@ environment "<%= environment %>"
<% if local_mode -%>
local_mode true
<% end -%>
-<% if node_path -%>
-node_path <%= node_path.inspect %>
+<% if nodes_path -%>
+node_path <%= nodes_path.inspect %>
<% end -%>
http_proxy <%= http_proxy.inspect %>
From c23610d70379f03ac27ba281356def7108aca868 Mon Sep 17 00:00:00 2001
From: Brian Dwyer
Date: Sun, 27 Sep 2015 23:24:01 -0400
Subject: [PATCH 062/484] Update test
---
.../plugins/provisioners/chef/config/chef_solo_test.rb | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/test/unit/plugins/provisioners/chef/config/chef_solo_test.rb b/test/unit/plugins/provisioners/chef/config/chef_solo_test.rb
index d6a2a03af..2c699cbd2 100644
--- a/test/unit/plugins/provisioners/chef/config/chef_solo_test.rb
+++ b/test/unit/plugins/provisioners/chef/config/chef_solo_test.rb
@@ -57,6 +57,14 @@ describe VagrantPlugins::Chef::Config::ChefSolo do
end
end
+ describe "#nodes_path" do
+ it "defaults to an empty array" do
+ subject.finalize!
+ expect(subject.nodes_path).to be_a(Array)
+ expect(subject.nodes_path).to be_empty
+ end
+ end
+
describe "#synced_folder_type" do
it "defaults to nil" do
subject.finalize!
From 8fb2e0b4a54f38a93c133928c630101aa55a7e3c Mon Sep 17 00:00:00 2001
From: Brian Dwyer
Date: Sun, 27 Sep 2015 23:24:40 -0400
Subject: [PATCH 063/484] Update documentation for Chef Solo `nodes_path`
---
website/docs/source/v2/provisioning/chef_solo.html.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/website/docs/source/v2/provisioning/chef_solo.html.md b/website/docs/source/v2/provisioning/chef_solo.html.md
index a7841b90e..a43232bed 100644
--- a/website/docs/source/v2/provisioning/chef_solo.html.md
+++ b/website/docs/source/v2/provisioning/chef_solo.html.md
@@ -42,6 +42,9 @@ available below this section.
* `environments_path` (string) - A path where environment definitions are
located. By default, no environments folder is set.
+* `nodes_path` (string or array) - A list of paths where node objects (in JSON format) are stored. By default, no
+ nodes path is set.
+
* `environment` (string) - The environment you want the Chef run to be
a part of. This requires Chef 11.6.0 or later, and that `environments_path`
is set.
From cfd4270cdb36833e5a4d322641c68b7a53cacc58 Mon Sep 17 00:00:00 2001
From: Maarten De Wispelaere
Date: Mon, 28 Sep 2015 09:08:20 +0200
Subject: [PATCH 064/484] FIX bug introduced in #6315
---
plugins/guests/debian/guest.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/guests/debian/guest.rb b/plugins/guests/debian/guest.rb
index be08b3605..a7f3d65de 100644
--- a/plugins/guests/debian/guest.rb
+++ b/plugins/guests/debian/guest.rb
@@ -2,7 +2,7 @@ module VagrantPlugins
module GuestDebian
class Guest < Vagrant.plugin("2", :guest)
def detect?(machine)
- machine.communicate.test("cat /etc/issue | grep 'Debian' | grep -v '8'")
+ machine.communicate.test("cat /etc/issue | grep 'Debian'")
end
end
end
From 702e8d6324a9485f2d1e6c46c9cee5aa8316405d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?=
Date: Thu, 10 Sep 2015 10:05:41 +0200
Subject: [PATCH 065/484] Add a sudoers script for SUSE
---
contrib/sudoers/linux-suse | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 contrib/sudoers/linux-suse
diff --git a/contrib/sudoers/linux-suse b/contrib/sudoers/linux-suse
new file mode 100644
index 000000000..30658af3f
--- /dev/null
+++ b/contrib/sudoers/linux-suse
@@ -0,0 +1,7 @@
+Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
+Cmnd_Alias VAGRANT_NFSD_CHECK = /sbin/service nfsserver status
+Cmnd_Alias VAGRANT_NFSD_START = /sbin/service nfsserver start
+Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar
+Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -r -e * d -ibak /*/exports
+Cmnd_Alias VAGRANT_EXPORTS_REMOVE_2 = /usr/bin/cp /*/exports /etc/exports
+%vagrant ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE, VAGRANT_EXPORTS_REMOVE_2
From 04fb0d99f6fd3e878938ec31174843fa3ea8d812 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?=
Date: Mon, 28 Sep 2015 09:17:40 +0200
Subject: [PATCH 066/484] Fix sudoers files after change to cleanup command
PR #5773 modified the cleanup command so that the
example sudoers scripts no longer match.
---
contrib/sudoers/linux-fedora | 5 +++--
contrib/sudoers/linux-ubuntu | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/contrib/sudoers/linux-fedora b/contrib/sudoers/linux-fedora
index f2d64b66d..5bec89189 100644
--- a/contrib/sudoers/linux-fedora
+++ b/contrib/sudoers/linux-fedora
@@ -2,5 +2,6 @@ Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
Cmnd_Alias VAGRANT_NFSD_CHECK = /usr/bin/systemctl status nfs-server.service
Cmnd_Alias VAGRANT_NFSD_START = /usr/bin/systemctl start nfs-server.service
Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar
-Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /etc/exports
-%vagrant ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE
+Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /*/exports
+Cmnd_Alias VAGRANT_EXPORTS_REMOVE_2 = /bin/cp /*/exports /etc/exports
+%vagrant ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE, VAGRANT_EXPORTS_REMOVE_2
diff --git a/contrib/sudoers/linux-ubuntu b/contrib/sudoers/linux-ubuntu
index c4e786cf3..4e2cd8bde 100644
--- a/contrib/sudoers/linux-ubuntu
+++ b/contrib/sudoers/linux-ubuntu
@@ -4,5 +4,6 @@ Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
Cmnd_Alias VAGRANT_NFSD_CHECK = /etc/init.d/nfs-kernel-server status
Cmnd_Alias VAGRANT_NFSD_START = /etc/init.d/nfs-kernel-server start
Cmnd_Alias VAGRANT_NFSD_APPLY = /usr/sbin/exportfs -ar
-Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /etc/exports
-%sudo ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE
+Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /bin/sed -r -e * d -ibak /*/exports
+Cmnd_Alias VAGRANT_EXPORTS_REMOVE_2 = /bin/cp /*/exports /etc/exports
+%sudo ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD_CHECK, VAGRANT_NFSD_START, VAGRANT_NFSD_APPLY, VAGRANT_EXPORTS_REMOVE, VAGRANT_EXPORTS_REMOVE_2
From ec0b0fb7f9e12bcff1c246668268084ebd308bb6 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 30 Sep 2015 17:23:25 -0700
Subject: [PATCH 067/484] providers/virtualbox: IPv6 host only networks
---
lib/vagrant/util/network_ip.rb | 11 +++
.../providers/virtualbox/action/network.rb | 72 ++++++++++++-------
.../virtualbox/driver/version_4_3.rb | 24 +++++--
.../virtualbox/driver/version_5_0.rb | 4 ++
templates/guests/debian/network_static6.erb | 10 +++
test/unit/vagrant/util/network_ip_test.rb | 12 ++++
6 files changed, 103 insertions(+), 30 deletions(-)
create mode 100644 templates/guests/debian/network_static6.erb
diff --git a/lib/vagrant/util/network_ip.rb b/lib/vagrant/util/network_ip.rb
index fca98f8b4..5f22f69d4 100644
--- a/lib/vagrant/util/network_ip.rb
+++ b/lib/vagrant/util/network_ip.rb
@@ -1,10 +1,21 @@
+require "ipaddr"
+
module Vagrant
module Util
module NetworkIP
# Returns the network address of the given IP and subnet.
#
+ # If the IP address is an IPv6 address, subnet should be a prefix
+ # length such as "64".
+ #
# @return [String]
def network_address(ip, subnet)
+ # If this is an IPv6 address, then just mask it
+ if subnet.to_s =~ /^\d+$/
+ ip = IPAddr.new(ip)
+ return ip.mask(subnet.to_i).to_s
+ end
+
ip = ip_parts(ip)
netmask = ip_parts(subnet)
diff --git a/plugins/providers/virtualbox/action/network.rb b/plugins/providers/virtualbox/action/network.rb
index 3697cdfef..881fcdf51 100644
--- a/plugins/providers/virtualbox/action/network.rb
+++ b/plugins/providers/virtualbox/action/network.rb
@@ -1,3 +1,4 @@
+require "ipaddr"
require "set"
require "log4r"
@@ -248,7 +249,6 @@ module VagrantPlugins
auto_config: true,
mac: nil,
nic_type: nil,
- netmask: "255.255.255.0",
type: :static
}.merge(options)
@@ -258,31 +258,45 @@ module VagrantPlugins
# Default IP is in the 20-bit private network block for DHCP based networks
options[:ip] = "172.28.128.1" if options[:type] == :dhcp && !options[:ip]
- # Calculate our network address for the given IP/netmask
- netaddr = network_address(options[:ip], options[:netmask])
+ ip = IPAddr.new(options[:ip])
+ if !ip.ipv6?
+ options[:netmask] ||= "255.255.255.0"
- # Verify that a host-only network subnet would not collide
- # with a bridged networking interface.
- #
- # If the subnets overlap in any way then the host only network
- # will not work because the routing tables will force the
- # traffic onto the real interface rather than the VirtualBox
- # interface.
- @env[:machine].provider.driver.read_bridged_interfaces.each do |interface|
- that_netaddr = network_address(interface[:ip], interface[:netmask])
- raise Vagrant::Errors::NetworkCollision if \
- netaddr == that_netaddr && interface[:status] != "Down"
+ # Calculate our network address for the given IP/netmask
+ netaddr = network_address(options[:ip], options[:netmask])
+
+ # Verify that a host-only network subnet would not collide
+ # with a bridged networking interface.
+ #
+ # If the subnets overlap in any way then the host only network
+ # will not work because the routing tables will force the
+ # traffic onto the real interface rather than the VirtualBox
+ # interface.
+ @env[:machine].provider.driver.read_bridged_interfaces.each do |interface|
+ that_netaddr = network_address(interface[:ip], interface[:netmask])
+ raise Vagrant::Errors::NetworkCollision if \
+ netaddr == that_netaddr && interface[:status] != "Down"
+ end
+
+ # Split the IP address into its components
+ ip_parts = netaddr.split(".").map { |i| i.to_i }
+
+ # Calculate the adapter IP, which we assume is the IP ".1" at
+ # the end usually.
+ adapter_ip = ip_parts.dup
+ adapter_ip[3] += 1
+ options[:adapter_ip] ||= adapter_ip.join(".")
+ else
+ # Default subnet prefix length
+ options[:netmask] ||= 64
+
+ # IPv6 we just mask the address and use that as the adapter
+ options[:adapter_ip] ||= ip.mask(options[:netmask].to_i).to_s
+
+ # Append a 6 to the end of the type
+ options[:type] = "#{options[:type]}6".to_sym
end
- # Split the IP address into its components
- ip_parts = netaddr.split(".").map { |i| i.to_i }
-
- # Calculate the adapter IP, which we assume is the IP ".1" at
- # the end usually.
- adapter_ip = ip_parts.dup
- adapter_ip[3] += 1
- options[:adapter_ip] ||= adapter_ip.join(".")
-
dhcp_options = {}
if options[:type] == :dhcp
# Calculate the DHCP server IP, which is the network address
@@ -456,8 +470,16 @@ module VagrantPlugins
@env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
return interface if config[:name] && config[:name] == interface[:name]
- return interface if this_netaddr == \
- network_address(interface[:ip], interface[:netmask])
+
+ if interface[:ip] != ""
+ return interface if this_netaddr == \
+ network_address(interface[:ip], interface[:netmask])
+ end
+
+ if interface[:ipv6] != ""
+ return interface if this_netaddr == \
+ network_address(interface[:ipv6], interface[:ipv6_prefix])
+ end
end
nil
diff --git a/plugins/providers/virtualbox/driver/version_4_3.rb b/plugins/providers/virtualbox/driver/version_4_3.rb
index b421e7911..ed4b7aa9e 100644
--- a/plugins/providers/virtualbox/driver/version_4_3.rb
+++ b/plugins/providers/virtualbox/driver/version_4_3.rb
@@ -1,3 +1,4 @@
+require 'ipaddr'
require 'log4r'
require "vagrant/util/platform"
@@ -46,12 +47,21 @@ module VagrantPlugins
def create_host_only_network(options)
# Create the interface
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
- name = $1.to_s
+ name = $1.to_s
- # Configure it
- execute("hostonlyif", "ipconfig", name,
- "--ip", options[:adapter_ip],
- "--netmask", options[:netmask])
+ # Get the IP so we can determine v4 vs v6
+ ip = IPAddr.new(options[:adapter_ip])
+
+ # Configure
+ if ip.ipv4?
+ execute("hostonlyif", "ipconfig", name,
+ "--ip", options[:adapter_ip],
+ "--netmask", options[:netmask])
+ elsif ip.ipv6?
+ execute("hostonlyif", "ipconfig", name,
+ "--ipv6", options[:adapter_ip],
+ "--netmasklengthv6", options[:netmask])
+ end
# Return the details
return {
@@ -366,6 +376,10 @@ module VagrantPlugins
info[:ip] = $1.to_s
elsif line =~ /^NetworkMask:\s+(.+?)$/
info[:netmask] = $1.to_s
+ elsif line =~ /^IPV6Address:\s+(.+?)$/
+ info[:ipv6] = $1.to_s.strip
+ elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
+ info[:ipv6_prefix] = $1.to_s.strip
elsif line =~ /^Status:\s+(.+?)$/
info[:status] = $1.to_s
end
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index 102d838bc..c8d659e11 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -366,6 +366,10 @@ module VagrantPlugins
info[:ip] = $1.to_s
elsif line =~ /^NetworkMask:\s+(.+?)$/
info[:netmask] = $1.to_s
+ elsif line =~ /^IPV6Address:\s+(.+?)$/
+ info[:ipv6] = $1.to_s
+ elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
+ info[:ipv6_prefix] = $1.to_s
elsif line =~ /^Status:\s+(.+?)$/
info[:status] = $1.to_s
end
diff --git a/templates/guests/debian/network_static6.erb b/templates/guests/debian/network_static6.erb
new file mode 100644
index 000000000..7b9e8a694
--- /dev/null
+++ b/templates/guests/debian/network_static6.erb
@@ -0,0 +1,10 @@
+#VAGRANT-BEGIN
+# The contents below are automatically generated by Vagrant. Do not modify.
+auto eth<%= options[:interface] %>
+iface eth<%= options[:interface] %> inet6 static
+ address <%= options[:ip] %>
+ netmask <%= options[:netmask] %>
+<% if options[:gateway] %>
+ gateway <%= options[:gateway] %>
+<% end %>
+#VAGRANT-END
diff --git a/test/unit/vagrant/util/network_ip_test.rb b/test/unit/vagrant/util/network_ip_test.rb
index a4ff8944c..9d0d09b12 100644
--- a/test/unit/vagrant/util/network_ip_test.rb
+++ b/test/unit/vagrant/util/network_ip_test.rb
@@ -13,5 +13,17 @@ describe Vagrant::Util::NetworkIP do
it "calculates it properly" do
expect(klass.network_address("192.168.2.234", "255.255.255.0")).to eq("192.168.2.0")
end
+
+ it "calculates it properly with integer submask" do
+ expect(klass.network_address("192.168.2.234", "24")).to eq("192.168.2.0")
+ end
+
+ it "calculates it properly for IPv6" do
+ expect(klass.network_address("fde4:8dba:82e1::c4", "64")).to eq("fde4:8dba:82e1::")
+ end
+
+ it "calculates it properly for IPv6" do
+ expect(klass.network_address("fde4:8dba:82e1::c4", 64)).to eq("fde4:8dba:82e1::")
+ end
end
end
From 0d50f454ea17ee05aeabe7dd33ff3bd85d75c000 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 30 Sep 2015 17:29:23 -0700
Subject: [PATCH 068/484] providers/virtualbox: VB5 support
---
.../virtualbox/driver/version_4_3.rb | 2 +-
.../virtualbox/driver/version_5_0.rb | 23 +++++++++++++------
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/plugins/providers/virtualbox/driver/version_4_3.rb b/plugins/providers/virtualbox/driver/version_4_3.rb
index ed4b7aa9e..b3d29c6c8 100644
--- a/plugins/providers/virtualbox/driver/version_4_3.rb
+++ b/plugins/providers/virtualbox/driver/version_4_3.rb
@@ -60,7 +60,7 @@ module VagrantPlugins
elsif ip.ipv6?
execute("hostonlyif", "ipconfig", name,
"--ipv6", options[:adapter_ip],
- "--netmasklengthv6", options[:netmask])
+ "--netmasklengthv6", options[:netmask].to_s)
end
# Return the details
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index c8d659e11..a9aad8442 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -46,12 +46,21 @@ module VagrantPlugins
def create_host_only_network(options)
# Create the interface
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
- name = $1.to_s
+ name = $1.to_s
- # Configure it
- execute("hostonlyif", "ipconfig", name,
- "--ip", options[:adapter_ip],
- "--netmask", options[:netmask])
+ # Get the IP so we can determine v4 vs v6
+ ip = IPAddr.new(options[:adapter_ip])
+
+ # Configure
+ if ip.ipv4?
+ execute("hostonlyif", "ipconfig", name,
+ "--ip", options[:adapter_ip],
+ "--netmask", options[:netmask])
+ elsif ip.ipv6?
+ execute("hostonlyif", "ipconfig", name,
+ "--ipv6", options[:adapter_ip],
+ "--netmasklengthv6", options[:netmask].to_s)
+ end
# Return the details
return {
@@ -367,9 +376,9 @@ module VagrantPlugins
elsif line =~ /^NetworkMask:\s+(.+?)$/
info[:netmask] = $1.to_s
elsif line =~ /^IPV6Address:\s+(.+?)$/
- info[:ipv6] = $1.to_s
+ info[:ipv6] = $1.to_s.strip
elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
- info[:ipv6_prefix] = $1.to_s
+ info[:ipv6_prefix] = $1.to_s.strip
elsif line =~ /^Status:\s+(.+?)$/
info[:status] = $1.to_s
end
From 061a91d09b5c7ad3401c4c48a48d071512cfd0e7 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 30 Sep 2015 18:19:37 -0700
Subject: [PATCH 069/484] providers/virtualbox: workaround IPv6 routing bug in
VB
VirtualBox has a bug where the IPv6 route is lost on every other
configuration of a host-only network. This is also triggered when a VM
is booted.
To fix this, we test the route-ability of all IPv6 networks, and
reconfigure if necessary. This is very fast but we still only do this if
we have any IPv6 networks.
---
plugins/providers/virtualbox/action.rb | 2 +
.../virtualbox/action/network_fix_ipv6.rb | 64 +++++++++++++++++++
plugins/providers/virtualbox/driver/base.rb | 8 +++
plugins/providers/virtualbox/driver/meta.rb | 1 +
.../virtualbox/driver/version_4_3.rb | 5 ++
.../virtualbox/driver/version_5_0.rb | 5 ++
6 files changed, 85 insertions(+)
create mode 100644 plugins/providers/virtualbox/action/network_fix_ipv6.rb
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 83eb3aec9..0d8fc8e38 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -30,6 +30,7 @@ module VagrantPlugins
autoload :MessageNotRunning, File.expand_path("../action/message_not_running", __FILE__)
autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__)
autoload :Network, File.expand_path("../action/network", __FILE__)
+ autoload :NetworkFixIPv6, File.expand_path("../action/network_fix_ipv6", __FILE__)
autoload :Package, File.expand_path("../action/package", __FILE__)
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
autoload :PrepareNFSSettings, File.expand_path("../action/prepare_nfs_settings", __FILE__)
@@ -63,6 +64,7 @@ module VagrantPlugins
b.use PrepareNFSSettings
b.use ClearNetworkInterfaces
b.use Network
+ b.use NetworkFixIPv6
b.use ForwardPorts
b.use SetHostname
b.use SaneDefaults
diff --git a/plugins/providers/virtualbox/action/network_fix_ipv6.rb b/plugins/providers/virtualbox/action/network_fix_ipv6.rb
new file mode 100644
index 000000000..eb4ca48ef
--- /dev/null
+++ b/plugins/providers/virtualbox/action/network_fix_ipv6.rb
@@ -0,0 +1,64 @@
+require "ipaddr"
+require "socket"
+
+require "log4r"
+
+require "vagrant/util/scoped_hash_override"
+
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ # This middleware works around a bug in VirtualBox where booting
+ # a VM with an IPv6 host-only network will someties lose the
+ # route to that machine.
+ class NetworkFixIPv6
+ include Vagrant::Util::ScopedHashOverride
+
+ def initialize(app, env)
+ @logger = Log4r::Logger.new("vagrant::plugins::virtualbox::network")
+ @app = app
+ end
+
+ def call(env)
+ @env = env
+
+ # Determine if we have an IPv6 network
+ has_v6 = false
+ env[:machine].config.vm.networks.each do |type, options|
+ next if type != :private_network
+ options = scoped_hash_override(options, :virtualbox)
+ next if options[:ip] == ""
+ if IPAddr.new(options[:ip]).ipv6?
+ has_v6 = true
+ break
+ end
+ end
+
+ # Call up
+ @app.call(env)
+
+ # If we have no IPv6, forget it
+ return if !has_v6
+
+ # We do, so fix them if we must
+ env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
+ # Ignore interfaces without an IPv6 address
+ next if interface[:ipv6] == ""
+
+ # Make the test IP. This is just the highest value IP
+ ip = IPAddr.new(interface[:ipv6])
+ ip |= IPAddr.new(":#{":FFFF" * (interface[:ipv6_prefix].to_i / 16)}")
+
+ @logger.info("testing IPv6: #{ip}")
+ begin
+ UDPSocket.new(Socket::AF_INET6).connect(ip.to_s, 80)
+ rescue Errno::EHOSTUNREACH
+ @logger.info("IPv6 host unreachable. Fixing: #{ip}")
+ env[:machine].provider.driver.reconfig_host_only(interface)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/virtualbox/driver/base.rb b/plugins/providers/virtualbox/driver/base.rb
index 112e97d5b..768bd9cef 100644
--- a/plugins/providers/virtualbox/driver/base.rb
+++ b/plugins/providers/virtualbox/driver/base.rb
@@ -263,6 +263,14 @@ module VagrantPlugins
def read_vms
end
+ # Reconfigure the hostonly network given by interface (the result
+ # of read_host_only_networks). This is a sad function that only
+ # exists to work around VirtualBox bugs.
+ #
+ # @return nil
+ def reconfig_host_only(interface)
+ end
+
# Removes the DHCP server identified by the provided network name.
#
# @param [String] network_name The the full network name associated
diff --git a/plugins/providers/virtualbox/driver/meta.rb b/plugins/providers/virtualbox/driver/meta.rb
index 10bef3f8f..242372452 100644
--- a/plugins/providers/virtualbox/driver/meta.rb
+++ b/plugins/providers/virtualbox/driver/meta.rb
@@ -109,6 +109,7 @@ module VagrantPlugins
:read_state,
:read_used_ports,
:read_vms,
+ :reconfig_host_only,
:remove_dhcp_server,
:resume,
:set_mac_address,
diff --git a/plugins/providers/virtualbox/driver/version_4_3.rb b/plugins/providers/virtualbox/driver/version_4_3.rb
index b3d29c6c8..3b08d43cd 100644
--- a/plugins/providers/virtualbox/driver/version_4_3.rb
+++ b/plugins/providers/virtualbox/driver/version_4_3.rb
@@ -72,6 +72,11 @@ module VagrantPlugins
}
end
+ def reconfig_host_only(interface)
+ execute("hostonlyif", "ipconfig", interface[:name],
+ "--ipv6", interface[:ipv6])
+ end
+
def delete
execute("unregistervm", @uuid, "--delete")
end
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index a9aad8442..c58bae3c0 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -488,6 +488,11 @@ module VagrantPlugins
results
end
+ def reconfig_host_only(interface)
+ execute("hostonlyif", "ipconfig", interface[:name],
+ "--ipv6", interface[:ipv6])
+ end
+
def remove_dhcp_server(network_name)
execute("dhcpserver", "remove", "--netname", network_name)
end
From 7e18a92bd94ce2fe20b97b27cf6504e6a795b7cd Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 1 Oct 2015 08:45:44 -0400
Subject: [PATCH 070/484] test: fix tests
---
.../support/shared/virtualbox_driver_version_4_x_examples.rb | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/test/unit/plugins/providers/virtualbox/support/shared/virtualbox_driver_version_4_x_examples.rb b/test/unit/plugins/providers/virtualbox/support/shared/virtualbox_driver_version_4_x_examples.rb
index 88f199a82..a56a45311 100644
--- a/test/unit/plugins/providers/virtualbox/support/shared/virtualbox_driver_version_4_x_examples.rb
+++ b/test/unit/plugins/providers/virtualbox/support/shared/virtualbox_driver_version_4_x_examples.rb
@@ -159,6 +159,7 @@ shared_examples "a version 4.x virtualbox driver" do |options|
name: 'vboxnet0',
ip: '172.28.128.1',
netmask: '255.255.255.0',
+ ipv6_prefix: '0',
status: 'Up',
}])
end
@@ -196,8 +197,8 @@ shared_examples "a version 4.x virtualbox driver" do |options|
it "returns a list with one entry for each interface" do
expect(subject.read_host_only_interfaces).to eq([
- {name: 'vboxnet0', ip: '172.28.128.1', netmask: '255.255.255.0', status: 'Up'},
- {name: 'vboxnet1', ip: '10.0.0.1', netmask: '255.255.255.0', status: 'Up'},
+ {name: 'vboxnet0', ip: '172.28.128.1', netmask: '255.255.255.0', ipv6_prefix: "0", status: 'Up'},
+ {name: 'vboxnet1', ip: '10.0.0.1', netmask: '255.255.255.0', ipv6_prefix: "0", status: 'Up'},
])
end
end
From 199a58fdd902cdb7e9f7d9707d5b1f36358682aa Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 1 Oct 2015 08:47:25 -0400
Subject: [PATCH 071/484] test: test IPv6
---
.../virtualbox_driver_version_4_x_examples.rb | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/test/unit/plugins/providers/virtualbox/support/shared/virtualbox_driver_version_4_x_examples.rb b/test/unit/plugins/providers/virtualbox/support/shared/virtualbox_driver_version_4_x_examples.rb
index a56a45311..85dee3cb1 100644
--- a/test/unit/plugins/providers/virtualbox/support/shared/virtualbox_driver_version_4_x_examples.rb
+++ b/test/unit/plugins/providers/virtualbox/support/shared/virtualbox_driver_version_4_x_examples.rb
@@ -202,6 +202,35 @@ shared_examples "a version 4.x virtualbox driver" do |options|
])
end
end
+
+ context "with an IPv6 host-only interface" do
+ let(:output) {
+ <<-OUTPUT.gsub(/^ */, '')
+ Name: vboxnet1
+ GUID: 786f6276-656e-4174-8000-0a0027000001
+ DHCP: Disabled
+ IPAddress: 192.168.57.1
+ NetworkMask: 255.255.255.0
+ IPV6Address: fde4:8dba:82e1::
+ IPV6NetworkMaskPrefixLength: 64
+ HardwareAddress: 0a:00:27:00:00:01
+ MediumType: Ethernet
+ Status: Up
+ VBoxNetworkName: HostInterfaceNetworking-vboxnet1
+ OUTPUT
+ }
+
+ it "returns a list with one entry describing that interface" do
+ expect(subject.read_host_only_interfaces).to eq([{
+ name: 'vboxnet1',
+ ip: '192.168.57.1',
+ netmask: '255.255.255.0',
+ ipv6: 'fde4:8dba:82e1::',
+ ipv6_prefix: '64',
+ status: 'Up',
+ }])
+ end
+ end
end
describe "remove_dhcp_server" do
From 05fbb4ced2e717e0255da2bf04f30a408aac5cf8 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 1 Oct 2015 08:50:47 -0400
Subject: [PATCH 072/484] providers/virtualbox: more support
---
.../virtualbox/driver/version_4_0.rb | 26 ++++++++++++++---
.../virtualbox/driver/version_4_1.rb | 26 ++++++++++++++---
.../virtualbox/driver/version_4_2.rb | 28 +++++++++++++++----
3 files changed, 67 insertions(+), 13 deletions(-)
diff --git a/plugins/providers/virtualbox/driver/version_4_0.rb b/plugins/providers/virtualbox/driver/version_4_0.rb
index 53361bbbb..66e9a37be 100644
--- a/plugins/providers/virtualbox/driver/version_4_0.rb
+++ b/plugins/providers/virtualbox/driver/version_4_0.rb
@@ -48,10 +48,19 @@ module VagrantPlugins
interface = execute("hostonlyif", "create")
name = interface[/^Interface '(.+?)' was successfully created$/, 1]
- # Configure it
- execute("hostonlyif", "ipconfig", name,
- "--ip", options[:adapter_ip],
- "--netmask", options[:netmask])
+ # Get the IP so we can determine v4 vs v6
+ ip = IPAddr.new(options[:adapter_ip])
+
+ # Configure
+ if ip.ipv4?
+ execute("hostonlyif", "ipconfig", name,
+ "--ip", options[:adapter_ip],
+ "--netmask", options[:netmask])
+ elsif ip.ipv6?
+ execute("hostonlyif", "ipconfig", name,
+ "--ipv6", options[:adapter_ip],
+ "--netmasklengthv6", options[:netmask].to_s)
+ end
# Return the details
return {
@@ -320,6 +329,10 @@ module VagrantPlugins
info[:ip] = ip
elsif netmask = line[/^NetworkMask:\s+(.+?)$/, 1]
info[:netmask] = netmask
+ elsif line =~ /^IPV6Address:\s+(.+?)$/
+ info[:ipv6] = $1.to_s.strip
+ elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
+ info[:ipv6_prefix] = $1.to_s.strip
elsif status = line[/^Status:\s+(.+?)$/, 1]
info[:status] = status
end
@@ -429,6 +442,11 @@ module VagrantPlugins
results
end
+ def reconfig_host_only(interface)
+ execute("hostonlyif", "ipconfig", interface[:name],
+ "--ipv6", interface[:ipv6])
+ end
+
def remove_dhcp_server(network_name)
execute("dhcpserver", "remove", "--netname", network_name)
end
diff --git a/plugins/providers/virtualbox/driver/version_4_1.rb b/plugins/providers/virtualbox/driver/version_4_1.rb
index ae1830019..8830297ba 100644
--- a/plugins/providers/virtualbox/driver/version_4_1.rb
+++ b/plugins/providers/virtualbox/driver/version_4_1.rb
@@ -48,10 +48,19 @@ module VagrantPlugins
interface = execute("hostonlyif", "create")
name = interface[/^Interface '(.+?)' was successfully created$/, 1]
- # Configure it
- execute("hostonlyif", "ipconfig", name,
- "--ip", options[:adapter_ip],
- "--netmask", options[:netmask])
+ # Get the IP so we can determine v4 vs v6
+ ip = IPAddr.new(options[:adapter_ip])
+
+ # Configure
+ if ip.ipv4?
+ execute("hostonlyif", "ipconfig", name,
+ "--ip", options[:adapter_ip],
+ "--netmask", options[:netmask])
+ elsif ip.ipv6?
+ execute("hostonlyif", "ipconfig", name,
+ "--ipv6", options[:adapter_ip],
+ "--netmasklengthv6", options[:netmask].to_s)
+ end
# Return the details
return {
@@ -325,6 +334,10 @@ module VagrantPlugins
info[:ip] = ip
elsif netmask = line[/^NetworkMask:\s+(.+?)$/, 1]
info[:netmask] = netmask
+ elsif line =~ /^IPV6Address:\s+(.+?)$/
+ info[:ipv6] = $1.to_s.strip
+ elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
+ info[:ipv6_prefix] = $1.to_s.strip
elsif status = line[/^Status:\s+(.+?)$/, 1]
info[:status] = status
end
@@ -434,6 +447,11 @@ module VagrantPlugins
results
end
+ def reconfig_host_only(interface)
+ execute("hostonlyif", "ipconfig", interface[:name],
+ "--ipv6", interface[:ipv6])
+ end
+
def remove_dhcp_server(network_name)
execute("dhcpserver", "remove", "--netname", network_name)
end
diff --git a/plugins/providers/virtualbox/driver/version_4_2.rb b/plugins/providers/virtualbox/driver/version_4_2.rb
index dc7da430a..0f1f79698 100644
--- a/plugins/providers/virtualbox/driver/version_4_2.rb
+++ b/plugins/providers/virtualbox/driver/version_4_2.rb
@@ -46,12 +46,21 @@ module VagrantPlugins
def create_host_only_network(options)
# Create the interface
execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/
- name = $1.to_s
+ name = $1.to_s
- # Configure it
- execute("hostonlyif", "ipconfig", name,
- "--ip", options[:adapter_ip],
- "--netmask", options[:netmask])
+ # Get the IP so we can determine v4 vs v6
+ ip = IPAddr.new(options[:adapter_ip])
+
+ # Configure
+ if ip.ipv4?
+ execute("hostonlyif", "ipconfig", name,
+ "--ip", options[:adapter_ip],
+ "--netmask", options[:netmask])
+ elsif ip.ipv6?
+ execute("hostonlyif", "ipconfig", name,
+ "--ipv6", options[:adapter_ip],
+ "--netmasklengthv6", options[:netmask].to_s)
+ end
# Return the details
return {
@@ -356,6 +365,10 @@ module VagrantPlugins
info[:ip] = $1.to_s
elsif line =~ /^NetworkMask:\s+(.+?)$/
info[:netmask] = $1.to_s
+ elsif line =~ /^IPV6Address:\s+(.+?)$/
+ info[:ipv6] = $1.to_s.strip
+ elsif line =~ /^IPV6NetworkMaskPrefixLength:\s+(.+?)$/
+ info[:ipv6_prefix] = $1.to_s.strip
elsif line =~ /^Status:\s+(.+?)$/
info[:status] = $1.to_s
end
@@ -465,6 +478,11 @@ module VagrantPlugins
results
end
+ def reconfig_host_only(interface)
+ execute("hostonlyif", "ipconfig", interface[:name],
+ "--ipv6", interface[:ipv6])
+ end
+
def remove_dhcp_server(network_name)
execute("dhcpserver", "remove", "--netname", network_name)
end
From 2b732a96c7b2d675cdc33f80c6e6cc8b82786e71 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 1 Oct 2015 08:55:03 -0400
Subject: [PATCH 073/484] website/docs: IPv6
---
.../v2/networking/private_network.html.md | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/website/docs/source/v2/networking/private_network.html.md b/website/docs/source/v2/networking/private_network.html.md
index 345547f05..e11c7b3c7 100644
--- a/website/docs/source/v2/networking/private_network.html.md
+++ b/website/docs/source/v2/networking/private_network.html.md
@@ -74,6 +74,35 @@ reachable.
+## IPv6
+
+You can specify a static IP via IPv6. DHCP for IPv6 is not supported.
+To use IPv6, just specify an IPv6 address as the IP:
+
+```ruby
+Vagrant.configure("2") do |config|
+ config.vm.network "private_network", ip: "fde4:8dba:82e1::c4"
+end
+```
+
+This will assign that IP to the machine. The entire `/64` subnet will
+be reserved. Please make sure to use the reserved local addresses approved
+for IPv6.
+
+You can also modify the prefix length by changing the `netmask` option
+(defaults to 64):
+
+```ruby
+Vagrant.configure("2") do |config|
+ config.vm.network "private_network",
+ ip: "fde4:8dba:82e1::c4",
+ netmask: "96"
+end
+```
+
+IPv6 supports for private networks was added in Vagrant 1.7.5 and may
+not work with every provider.
+
## Disable Auto-Configuration
If you want to manually configure the network interface yourself, you
From 2299715b4135d199e2335cca43db69f33f1e2532 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 1 Oct 2015 17:01:27 -0400
Subject: [PATCH 074/484] providers/virtualbox: code review comments
---
plugins/providers/virtualbox/action/network.rb | 6 ++++--
plugins/providers/virtualbox/driver/version_5_0.rb | 2 ++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/plugins/providers/virtualbox/action/network.rb b/plugins/providers/virtualbox/action/network.rb
index 881fcdf51..cf5ca3b47 100644
--- a/plugins/providers/virtualbox/action/network.rb
+++ b/plugins/providers/virtualbox/action/network.rb
@@ -259,7 +259,7 @@ module VagrantPlugins
options[:ip] = "172.28.128.1" if options[:type] == :dhcp && !options[:ip]
ip = IPAddr.new(options[:ip])
- if !ip.ipv6?
+ if ip.ipv4?
options[:netmask] ||= "255.255.255.0"
# Calculate our network address for the given IP/netmask
@@ -286,7 +286,7 @@ module VagrantPlugins
adapter_ip = ip_parts.dup
adapter_ip[3] += 1
options[:adapter_ip] ||= adapter_ip.join(".")
- else
+ elsif ip.ipv6?
# Default subnet prefix length
options[:netmask] ||= 64
@@ -295,6 +295,8 @@ module VagrantPlugins
# Append a 6 to the end of the type
options[:type] = "#{options[:type]}6".to_sym
+ else
+ raise "BUG: Unknown IP type: #{ip.inspect}"
end
dhcp_options = {}
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index c58bae3c0..3c84ad3c7 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -60,6 +60,8 @@ module VagrantPlugins
execute("hostonlyif", "ipconfig", name,
"--ipv6", options[:adapter_ip],
"--netmasklengthv6", options[:netmask].to_s)
+ else
+ raise "BUG: Unknown IP type: #{ip.inspect}"
end
# Return the details
From a152045f81e3433c76640cae449a359de2c311bb Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 1 Oct 2015 17:06:56 -0400
Subject: [PATCH 075/484] update CHANGELOG
---
CHANGELOG.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e3567eb1c..7166a1b3f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,9 @@
FEATURES:
+ - **IPv6 Private Networks**: Private networking now supports IPv6. This
+ only works with VirtualBox and VMware at this point. [GH-6342]
+
IMPROVEMENTS:
BUG FIXES:
From 0556b3b040a75c3d698a5e0917722e7d83b5b001 Mon Sep 17 00:00:00 2001
From: ctammes
Date: Tue, 6 Oct 2015 14:02:45 +0200
Subject: [PATCH 076/484] Update push.rb
https://github.com/mitchellh/vagrant/issues/5570
When uploading from Windows to Linux, the Windows filepath was added to the Linux path.
---
plugins/pushes/ftp/push.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/pushes/ftp/push.rb b/plugins/pushes/ftp/push.rb
index 7a69c4f02..755304ee6 100644
--- a/plugins/pushes/ftp/push.rb
+++ b/plugins/pushes/ftp/push.rb
@@ -19,7 +19,7 @@ module VagrantPlugins
# wait and close the (S)FTP connection as well
files = Hash[*all_files.flat_map do |file|
relative_path = relative_path_for(file, config.dir)
- destination = File.expand_path(File.join(config.destination, relative_path))
+ destination = File.join(config.destination, relative_path)
file = File.expand_path(file, env.root_path)
[file, destination]
end]
From 2c936b2e3722a84ca703e335e8cb2f19c09d670f Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 6 Oct 2015 14:11:41 -0400
Subject: [PATCH 077/484] providers/virtualbox: tidying up the linked clone
feature
---
lib/vagrant/environment.rb | 4 +-
plugins/providers/virtualbox/action.rb | 7 +-
.../virtualbox/action/create_clone.rb | 9 +-
plugins/providers/virtualbox/action/import.rb | 5 +-
.../virtualbox/action/import_master.rb | 88 +++++++++++--------
plugins/providers/virtualbox/config.rb | 8 +-
templates/locales/en.yml | 9 +-
7 files changed, 75 insertions(+), 55 deletions(-)
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index d4b8db1fd..c3dabd676 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -529,7 +529,9 @@ module Vagrant
begin
File.delete(lock_path)
rescue
- @logger.debug("Failed to delete lock file #{lock_path} - some other thread might be trying to acquire it -> ignoring this error")
+ @logger.error(
+ "Failed to delete lock file #{lock_path} - some other thread " +
+ "might be trying to acquire it. ignoring this error")
end
end
end
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 635907827..088221ed1 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -327,13 +327,14 @@ module VagrantPlugins
if !env[:result]
b2.use CheckAccessible
b2.use Customize, "pre-import"
-
- if env[:machine].provider_config.use_linked_clone
+
+ if env[:machine].provider_config.linked_clone
b2.use ImportMaster
b2.use CreateClone
else
b2.use Import
- end
+ end
+
b2.use MatchMACAddress
end
end
diff --git a/plugins/providers/virtualbox/action/create_clone.rb b/plugins/providers/virtualbox/action/create_clone.rb
index e26b5721f..9cc8f7ed5 100644
--- a/plugins/providers/virtualbox/action/create_clone.rb
+++ b/plugins/providers/virtualbox/action/create_clone.rb
@@ -1,5 +1,4 @@
require "log4r"
-#require "lockfile"
module VagrantPlugins
module ProviderVirtualBox
@@ -12,14 +11,16 @@ module VagrantPlugins
def call(env)
@logger.info("Creating linked clone from master '#{env[:master_id]}'")
-
+
env[:ui].info I18n.t("vagrant.actions.vm.clone.creating", name: env[:machine].box.name)
- env[:machine].id = env[:machine].provider.driver.clonevm(env[:master_id], env[:machine].box.name, "base") do |progress|
+ env[:machine].id = env[:machine].provider.driver.clonevm(
+ env[:master_id], env[:machine].box.name, "base") do |progress|
env[:ui].clear_line
env[:ui].report_progress(progress, 100, false)
end
- # Clear the line one last time since the progress meter doesn't disappear immediately.
+ # Clear the line one last time since the progress meter doesn't
+ # disappear immediately.
env[:ui].clear_line
# Flag as erroneous and return if clone failed
diff --git a/plugins/providers/virtualbox/action/import.rb b/plugins/providers/virtualbox/action/import.rb
index 6648faefc..238f88e00 100644
--- a/plugins/providers/virtualbox/action/import.rb
+++ b/plugins/providers/virtualbox/action/import.rb
@@ -12,11 +12,14 @@ module VagrantPlugins
# Import the virtual machine
ovf_file = env[:machine].box.directory.join("box.ovf").to_s
- env[:machine].id = env[:machine].provider.driver.import(ovf_file) do |progress|
+ id = env[:machine].provider.driver.import(ovf_file) do |progress|
env[:ui].clear_line
env[:ui].report_progress(progress, 100, false)
end
+ # Set the machine ID
+ env[:machine].id = id if !env[:skip_machine]
+
# Clear the line one last time since the progress meter doesn't disappear
# immediately.
env[:ui].clear_line
diff --git a/plugins/providers/virtualbox/action/import_master.rb b/plugins/providers/virtualbox/action/import_master.rb
index 61b0064eb..9b088b2a1 100644
--- a/plugins/providers/virtualbox/action/import_master.rb
+++ b/plugins/providers/virtualbox/action/import_master.rb
@@ -1,5 +1,6 @@
require "log4r"
-#require "lockfile"
+
+require "digest/md5"
module VagrantPlugins
module ProviderVirtualBox
@@ -11,45 +12,14 @@ module VagrantPlugins
end
def call(env)
- master_id_file = env[:machine].box.directory.join("master_id")
-
- env[:machine].env.lock(Digest::MD5.hexdigest(env[:machine].box.name), retry: true) do
- env[:master_id] = master_id_file.read.chomp if master_id_file.file?
- if env[:master_id] && env[:machine].provider.driver.vm_exists?(env[:master_id])
- # Master VM already exists -> nothing to do - continue.
- @logger.info("Master VM for '#{env[:machine].box.name}' already exists (id=#{env[:master_id]}) - skipping import step.")
- return @app.call(env)
- end
-
- env[:ui].info I18n.t("vagrant.actions.vm.clone.importing", name: env[:machine].box.name)
-
- # Import the virtual machine
- ovf_file = env[:machine].box.directory.join("box.ovf").to_s
- env[:master_id] = env[:machine].provider.driver.import(ovf_file) do |progress|
- env[:ui].clear_line
- env[:ui].report_progress(progress, 100, false)
- end
-
- # Clear the line one last time since the progress meter doesn't disappear immediately.
- env[:ui].clear_line
-
- # Flag as erroneous and return if import failed
- raise Vagrant::Errors::VMImportFailure if !env[:master_id]
+ # Do the import while locked so that nobody else imports
+ # a master at the same time. This is a no-op if we already
+ # have a master that exists.
+ lock_key = Digest::MD5.hexdigest(env[:machine].box.name)
+ env[:machine].env.lock(lock_key, retry: true) do
+ import_master(env)
+ end
- @logger.info("Imported box #{env[:machine].box.name} as master vm with id #{env[:master_id]}")
-
- @logger.info("Creating base snapshot for master VM.")
- env[:machine].provider.driver.create_snapshot(env[:master_id], "base") do |progress|
- env[:ui].clear_line
- env[:ui].report_progress(progress, 100, false)
- end
-
- @logger.debug("Writing id of master VM '#{env[:master_id]}' to #{master_id_file}")
- master_id_file.open("w+") do |f|
- f.write(env[:master_id])
- end
- end
-
# If we got interrupted, then the import could have been
# interrupted and its not a big deal. Just return out.
if env[:interrupted]
@@ -60,6 +30,46 @@ module VagrantPlugins
# Import completed successfully. Continue the chain
@app.call(env)
end
+
+ protected
+
+ def import_master(env)
+ master_id_file = env[:machine].box.directory.join("master_id")
+
+ # Read the master ID if we have it in the file.
+ env[:master_id] = master_id_file.read.chomp if master_id_file.file?
+
+ # If we have the ID and the VM exists already, then we
+ # have nothing to do. Success!
+ if env[:master_id] && env[:machine].provider.driver.vm_exists?(env[:master_id])
+ @logger.info(
+ "Master VM for '#{env[:machine].box.name}' already exists " +
+ " (id=#{env[:master_id]}) - skipping import step.")
+ return
+ end
+
+ env[:ui].info(I18n.t("vagrant.actions.vm.clone.setup_master"))
+ env[:ui].detail("\n"+I18n.t("vagrant.actions.vm.clone.setup_master_detail"))
+
+ # Import the virtual machine
+ import_env = env[:action_runner].run(Import, skip_machine: true)
+ env[:master_id] = import_env[:machine_id]
+
+ @logger.info(
+ "Imported box #{env[:machine].box.name} as master vm " +
+ "with id #{env[:master_id]}")
+
+ @logger.info("Creating base snapshot for master VM.")
+ env[:machine].provider.driver.create_snapshot(env[:master_id], "base") do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ @logger.debug("Writing id of master VM '#{env[:master_id]}' to #{master_id_file}")
+ master_id_file.open("w+") do |f|
+ f.write(env[:master_id])
+ end
+ end
end
end
end
diff --git a/plugins/providers/virtualbox/config.rb b/plugins/providers/virtualbox/config.rb
index 55b8356aa..12b882b01 100644
--- a/plugins/providers/virtualbox/config.rb
+++ b/plugins/providers/virtualbox/config.rb
@@ -36,8 +36,8 @@ module VagrantPlugins
# VM generated from the specified box.
#
# @return [Boolean]
- attr_accessor :use_linked_clone
-
+ attr_accessor :linked_clone
+
# This should be set to the name of the machine in the VirtualBox
# GUI.
#
@@ -65,7 +65,7 @@ module VagrantPlugins
@name = UNSET_VALUE
@network_adapters = {}
@gui = UNSET_VALUE
- @use_linked_clone = UNSET_VALUE
+ @linked_clone = UNSET_VALUE
# We require that network adapter 1 is a NAT device.
network_adapter(1, :nat)
@@ -144,7 +144,7 @@ module VagrantPlugins
@gui = false if @gui == UNSET_VALUE
# Do not create linked clone by default
- @use_linked_clone = false if @use_linked_clone == UNSET_VALUE
+ @linked_clone = false if @linked_clone == UNSET_VALUE
# The default name is just nothing, and we default it
@name = nil if @name == UNSET_VALUE
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index d0f311fd0..171cd60ba 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1619,10 +1619,13 @@ en:
clear_shared_folders:
deleting: Cleaning previously set shared folders...
clone:
- importing: Importing box '%{name}' as master vm...
- creating: Creating linked clone...
+ setup_master: Preparing master VM for linked clones...
+ setup_master_detail: |-
+ This is a one time operation. Once the master VM is prepared,
+ it will be used as a base for linked clones, making the creation
+ of new VMs take milliseconds on a modern system.
+ creating: Creating linked clone...
failure: Creation of the linked clone failed.
-
create_master:
failure: |-
Failed to create lock-file for master VM creation for box %{box}.
From 3b3de6e2e510227e47a0b1bf46cba10c553a2152 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 6 Oct 2015 14:24:43 -0400
Subject: [PATCH 078/484] support Bundler 1.10.6
---
vagrant.gemspec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vagrant.gemspec b/vagrant.gemspec
index 3e0aea4e3..b0f0638e3 100644
--- a/vagrant.gemspec
+++ b/vagrant.gemspec
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = ">= 1.3.6"
s.rubyforge_project = "vagrant"
- s.add_dependency "bundler", ">= 1.5.2", "<= 1.10.5"
+ s.add_dependency "bundler", ">= 1.5.2", "<= 1.10.6"
s.add_dependency "childprocess", "~> 0.5.0"
s.add_dependency "erubis", "~> 2.7.0"
s.add_dependency "i18n", ">= 0.6.0", "<= 0.8.0"
From 0586412f9dc0bcfa2b4a6b996a386be29e6a30d4 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 6 Oct 2015 16:22:48 -0400
Subject: [PATCH 079/484] providers/virtualbox: fix some crashing bugs
---
plugins/providers/virtualbox/action/import.rb | 5 +++--
plugins/providers/virtualbox/action/import_master.rb | 4 ++--
plugins/providers/virtualbox/driver/version_5_0.rb | 10 +++++-----
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/plugins/providers/virtualbox/action/import.rb b/plugins/providers/virtualbox/action/import.rb
index 238f88e00..92e004f01 100644
--- a/plugins/providers/virtualbox/action/import.rb
+++ b/plugins/providers/virtualbox/action/import.rb
@@ -18,6 +18,7 @@ module VagrantPlugins
end
# Set the machine ID
+ env[:machine_id] = id
env[:machine].id = id if !env[:skip_machine]
# Clear the line one last time since the progress meter doesn't disappear
@@ -29,14 +30,14 @@ module VagrantPlugins
return if env[:interrupted]
# Flag as erroneous and return if import failed
- raise Vagrant::Errors::VMImportFailure if !env[:machine].id
+ raise Vagrant::Errors::VMImportFailure if !id
# Import completed successfully. Continue the chain
@app.call(env)
end
def recover(env)
- if env[:machine].state.id != :not_created
+ if env[:machine] && env[:machine].state.id != :not_created
return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
# If we're not supposed to destroy on error then just return
diff --git a/plugins/providers/virtualbox/action/import_master.rb b/plugins/providers/virtualbox/action/import_master.rb
index 9b088b2a1..5b9ae7790 100644
--- a/plugins/providers/virtualbox/action/import_master.rb
+++ b/plugins/providers/virtualbox/action/import_master.rb
@@ -49,10 +49,10 @@ module VagrantPlugins
end
env[:ui].info(I18n.t("vagrant.actions.vm.clone.setup_master"))
- env[:ui].detail("\n"+I18n.t("vagrant.actions.vm.clone.setup_master_detail"))
+ env[:ui].detail(I18n.t("vagrant.actions.vm.clone.setup_master_detail"))
# Import the virtual machine
- import_env = env[:action_runner].run(Import, skip_machine: true)
+ import_env = env[:action_runner].run(Import, env.dup.merge(skip_machine: true))
env[:master_id] = import_env[:machine_id]
@logger.info(
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index 4bb839c1c..df833bb3f 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -36,13 +36,13 @@ module VagrantPlugins
def clonevm(master_id, box_name, snapshot_name)
@logger.debug("Creating linked clone from master vm with id #{master_id} from snapshot '#{snapshot_name}'")
-
+
machine_name = "#{box_name}_#{snapshot_name}_clone_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
execute("clonevm", master_id, "--snapshot", snapshot_name, "--options", "link", "--register", "--name", machine_name)
-
+
return get_machine_id machine_name
end
-
+
def create_dhcp_server(network, options)
execute("dhcpserver", "add", "--ifname", network,
"--ip", options[:dhcp_ip],
@@ -85,7 +85,7 @@ module VagrantPlugins
def create_snapshot(machine_id, snapshot_name)
execute("snapshot", machine_id, "take", snapshot_name)
end
-
+
def delete
execute("unregistervm", @uuid, "--delete")
end
@@ -186,7 +186,7 @@ module VagrantPlugins
return match[1].to_s if match
nil
end
-
+
def halt
execute("controlvm", @uuid, "poweroff")
end
From 169cacd710805b23e880302dd41156765b00c61d Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Tue, 6 Oct 2015 16:24:02 -0400
Subject: [PATCH 080/484] update CHANGELOG
---
CHANGELOG.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7166a1b3f..8840cc522 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@ FEATURES:
- **IPv6 Private Networks**: Private networking now supports IPv6. This
only works with VirtualBox and VMware at this point. [GH-6342]
+ - **Linked Clones**: VirtualBox and VMware providers now support
+ linked clones for very fast (millisecond) imports on up. [GH-4484]
IMPROVEMENTS:
From 07e38f1bb3e890fa373fda3e106f08e69c7194a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Guillermo=20Bonveh=C3=AD?=
Date: Wed, 7 Oct 2015 01:17:07 -0300
Subject: [PATCH 081/484] Fix Slackware Host detection and nfsd checks
Slackware's version file is /etc/slackware-version not
/etc/slackware-release.
pidof is not on PATH by default (not running as root) so call it using
full path
---
plugins/hosts/slackware/cap/nfs.rb | 2 +-
plugins/hosts/slackware/host.rb | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/hosts/slackware/cap/nfs.rb b/plugins/hosts/slackware/cap/nfs.rb
index e7f21a094..84413236d 100644
--- a/plugins/hosts/slackware/cap/nfs.rb
+++ b/plugins/hosts/slackware/cap/nfs.rb
@@ -3,7 +3,7 @@ module VagrantPlugins
module Cap
class NFS
def self.nfs_check_command(env)
- "pidof nfsd >/dev/null"
+ "/sbin/pidof nfsd >/dev/null"
end
def self.nfs_start_command(env)
diff --git a/plugins/hosts/slackware/host.rb b/plugins/hosts/slackware/host.rb
index 2afaff8f3..ec3503ac0 100644
--- a/plugins/hosts/slackware/host.rb
+++ b/plugins/hosts/slackware/host.rb
@@ -4,7 +4,7 @@ module VagrantPlugins
module HostSlackware
class Host < Vagrant.plugin("2", :host)
def detect?(env)
- return File.exists?("/etc/slackware-release") ||
+ return File.exists?("/etc/slackware-version") ||
!Dir.glob("/usr/lib/setup/Plamo-*").empty?
end
end
From a99ebcb3ceeead60397d5632b19b61917eb6cc22 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 7 Oct 2015 15:52:37 -0400
Subject: [PATCH 082/484] commands/snapshot
---
plugins/commands/snapshot/command/delete.rb | 35 +++++++++
plugins/commands/snapshot/command/list.rb | 30 ++++++++
plugins/commands/snapshot/command/restore.rb | 35 +++++++++
plugins/commands/snapshot/command/root.rb | 79 ++++++++++++++++++++
plugins/commands/snapshot/command/save.rb | 40 ++++++++++
plugins/commands/snapshot/plugin.rb | 15 ++++
6 files changed, 234 insertions(+)
create mode 100644 plugins/commands/snapshot/command/delete.rb
create mode 100644 plugins/commands/snapshot/command/list.rb
create mode 100644 plugins/commands/snapshot/command/restore.rb
create mode 100644 plugins/commands/snapshot/command/root.rb
create mode 100644 plugins/commands/snapshot/command/save.rb
create mode 100644 plugins/commands/snapshot/plugin.rb
diff --git a/plugins/commands/snapshot/command/delete.rb b/plugins/commands/snapshot/command/delete.rb
new file mode 100644
index 000000000..0d5118847
--- /dev/null
+++ b/plugins/commands/snapshot/command/delete.rb
@@ -0,0 +1,35 @@
+require 'optparse'
+
+module VagrantPlugins
+ module CommandSnapshot
+ module Command
+ class Delete < Vagrant.plugin("2", :command)
+ def execute
+ options = {}
+
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant snapshot delete [options] [vm-name] "
+ o.separator ""
+ o.separator "Delete a snapshot taken previously with snapshot save."
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+ if argv.empty? || argv.length > 2
+ raise Vagrant::Errors::CLIInvalidUsage,
+ help: opts.help.chomp
+ end
+
+ name = argv.pop
+ with_target_vms(argv) do |vm|
+ vm.action(:snapshot_delete, snapshot_name: name)
+ end
+
+ # Success, exit status 0
+ 0
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/command/list.rb b/plugins/commands/snapshot/command/list.rb
new file mode 100644
index 000000000..af91e76f5
--- /dev/null
+++ b/plugins/commands/snapshot/command/list.rb
@@ -0,0 +1,30 @@
+require 'optparse'
+
+module VagrantPlugins
+ module CommandSnapshot
+ module Command
+ class List < Vagrant.plugin("2", :command)
+ def execute
+ options = {}
+
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant snapshot list [options] [vm-name]"
+ o.separator ""
+ o.separator "List all snapshots taken for a machine."
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+
+ with_target_vms(argv) do |vm|
+ vm.action(:snapshot_list)
+ end
+
+ # Success, exit status 0
+ 0
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/command/restore.rb b/plugins/commands/snapshot/command/restore.rb
new file mode 100644
index 000000000..930a811f4
--- /dev/null
+++ b/plugins/commands/snapshot/command/restore.rb
@@ -0,0 +1,35 @@
+require 'optparse'
+
+module VagrantPlugins
+ module CommandSnapshot
+ module Command
+ class Restore < Vagrant.plugin("2", :command)
+ def execute
+ options = {}
+
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant snapshot restore [options] [vm-name] "
+ o.separator ""
+ o.separator "Restore a snapshot taken previously with snapshot save."
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+ if argv.empty? || argv.length > 2
+ raise Vagrant::Errors::CLIInvalidUsage,
+ help: opts.help.chomp
+ end
+
+ name = argv.pop
+ with_target_vms(argv) do |vm|
+ vm.action(:snapshot_restore, snapshot_name: name)
+ end
+
+ # Success, exit status 0
+ 0
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/command/root.rb b/plugins/commands/snapshot/command/root.rb
new file mode 100644
index 000000000..03bcebb80
--- /dev/null
+++ b/plugins/commands/snapshot/command/root.rb
@@ -0,0 +1,79 @@
+require 'optparse'
+
+module VagrantPlugins
+ module CommandSnapshot
+ module Command
+ class Root < Vagrant.plugin("2", :command)
+ def self.synopsis
+ "manages snapshots: saving, restoring, etc."
+ end
+
+ def initialize(argv, env)
+ super
+
+ @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
+
+ @subcommands = Vagrant::Registry.new
+ @subcommands.register(:save) do
+ require File.expand_path("../save", __FILE__)
+ Save
+ end
+
+ @subcommands.register(:restore) do
+ require File.expand_path("../restore", __FILE__)
+ Restore
+ end
+
+ @subcommands.register(:delete) do
+ require File.expand_path("../delete", __FILE__)
+ Delete
+ end
+
+ @subcommands.register(:list) do
+ require File.expand_path("../list", __FILE__)
+ List
+ end
+ end
+
+ def execute
+ if @main_args.include?("-h") || @main_args.include?("--help")
+ # Print the help for all the commands.
+ return help
+ end
+
+ # If we reached this far then we must have a subcommand. If not,
+ # then we also just print the help and exit.
+ command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
+ return help if !command_class || !@sub_command
+ @logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
+
+ # Initialize and execute the command class
+ command_class.new(@sub_args, @env).execute
+ end
+
+ # Prints the help out for this command
+ def help
+ opts = OptionParser.new do |opts|
+ opts.banner = "Usage: vagrant snapshot []"
+ opts.separator ""
+ opts.separator "Available subcommands:"
+
+ # Add the available subcommands as separators in order to print them
+ # out as well.
+ keys = []
+ @subcommands.each { |key, value| keys << key.to_s }
+
+ keys.sort.each do |key|
+ opts.separator " #{key}"
+ end
+
+ opts.separator ""
+ opts.separator "For help on any individual subcommand run `vagrant snapshot -h`"
+ end
+
+ @env.ui.info(opts.help, prefix: false)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/command/save.rb b/plugins/commands/snapshot/command/save.rb
new file mode 100644
index 000000000..496891eac
--- /dev/null
+++ b/plugins/commands/snapshot/command/save.rb
@@ -0,0 +1,40 @@
+require 'optparse'
+
+module VagrantPlugins
+ module CommandSnapshot
+ module Command
+ class Save < Vagrant.plugin("2", :command)
+ def execute
+ options = {}
+
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant snapshot save [options] [vm-name] "
+ o.separator ""
+ o.separator "Take a snapshot of the current state of the machine. The snapshot"
+ o.separator "can be restored via `vagrant snapshot restore` at any point in the"
+ o.separator "future to get back to this exact machine state."
+ o.separator ""
+ o.separator "Snapshots are useful for experimenting in a machine and being able"
+ o.separator "to rollback quickly."
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+ if argv.empty? || argv.length > 2
+ raise Vagrant::Errors::CLIInvalidUsage,
+ help: opts.help.chomp
+ end
+
+ name = argv.pop
+ with_target_vms(argv) do |vm|
+ vm.action(:snapshot_save, snapshot_name: name)
+ end
+
+ # Success, exit status 0
+ 0
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/plugin.rb b/plugins/commands/snapshot/plugin.rb
new file mode 100644
index 000000000..e83be5bca
--- /dev/null
+++ b/plugins/commands/snapshot/plugin.rb
@@ -0,0 +1,15 @@
+require "vagrant"
+
+module VagrantPlugins
+ module CommandSnapshot
+ class Plugin < Vagrant.plugin("2")
+ name "snapshot command"
+ description "The `snapshot` command gives you a way to manage snapshots."
+
+ command("snapshot") do
+ require File.expand_path("../command/root", __FILE__)
+ Command::Root
+ end
+ end
+ end
+end
From d0e8ecfc73e9604d60c3d15aa1aae4bf34f79cdb Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 7 Oct 2015 16:16:24 -0400
Subject: [PATCH 083/484] providers/virtualbox: snapshot save/delete
---
plugins/providers/virtualbox/action.rb | 29 +++++++++++++++++++
.../virtualbox/action/snapshot_delete.rb | 25 ++++++++++++++++
.../virtualbox/action/snapshot_save.rb | 25 ++++++++++++++++
plugins/providers/virtualbox/driver/meta.rb | 2 ++
.../virtualbox/driver/version_5_0.rb | 8 +++++
templates/locales/en.yml | 11 +++++++
6 files changed, 100 insertions(+)
create mode 100644 plugins/providers/virtualbox/action/snapshot_delete.rb
create mode 100644 plugins/providers/virtualbox/action/snapshot_save.rb
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 088221ed1..96cd2373d 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -42,6 +42,8 @@ module VagrantPlugins
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
autoload :SetName, File.expand_path("../action/set_name", __FILE__)
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
+ autoload :SnapshotDelete, File.expand_path("../action/snapshot_delete", __FILE__)
+ autoload :SnapshotSave, File.expand_path("../action/snapshot_save", __FILE__)
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
# Include the built-in modules so that we can use them as top-level
@@ -222,6 +224,33 @@ module VagrantPlugins
end
end
+ def self.action_snapshot_delete
+ Vagrant::Action::Builder.new.tap do |b|
+ b.use CheckVirtualbox
+ b.use Call, Created do |env, b2|
+ if env[:result]
+ b2.use SnapshotDelete
+ else
+ b2.use MessageNotCreated
+ end
+ end
+ end
+ end
+
+ # This is the action that is primarily responsible for saving a snapshot
+ def self.action_snapshot_save
+ Vagrant::Action::Builder.new.tap do |b|
+ b.use CheckVirtualbox
+ b.use Call, Created do |env, b2|
+ if env[:result]
+ b2.use SnapshotSave
+ else
+ b2.use MessageNotCreated
+ end
+ end
+ end
+ end
+
# This is the action that will exec into an SSH shell.
def self.action_ssh
Vagrant::Action::Builder.new.tap do |b|
diff --git a/plugins/providers/virtualbox/action/snapshot_delete.rb b/plugins/providers/virtualbox/action/snapshot_delete.rb
new file mode 100644
index 000000000..2efc8eae2
--- /dev/null
+++ b/plugins/providers/virtualbox/action/snapshot_delete.rb
@@ -0,0 +1,25 @@
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ class SnapshotDelete
+ def initialize(app, env)
+ @app = app
+ end
+
+ def call(env)
+ env[:ui].info(I18n.t(
+ "vagrant.actions.vm.snapshot.deleting",
+ name: env[:snapshot_name]))
+ env[:machine].provider.driver.delete_snapshot(
+ env[:machine].id, env[:snapshot_name])
+
+ env[:ui].success(I18n.t(
+ "vagrant.actions.vm.snapshot.deleted",
+ name: env[:snapshot_name]))
+
+ @app.call(env)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/virtualbox/action/snapshot_save.rb b/plugins/providers/virtualbox/action/snapshot_save.rb
new file mode 100644
index 000000000..98b720763
--- /dev/null
+++ b/plugins/providers/virtualbox/action/snapshot_save.rb
@@ -0,0 +1,25 @@
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ class SnapshotSave
+ def initialize(app, env)
+ @app = app
+ end
+
+ def call(env)
+ env[:ui].info(I18n.t(
+ "vagrant.actions.vm.snapshot.saving",
+ name: env[:snapshot_name]))
+ env[:machine].provider.driver.create_snapshot(
+ env[:machine].id, env[:snapshot_name])
+
+ env[:ui].success(I18n.t(
+ "vagrant.actions.vm.snapshot.saved",
+ name: env[:snapshot_name]))
+
+ @app.call(env)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/virtualbox/driver/meta.rb b/plugins/providers/virtualbox/driver/meta.rb
index df52f0849..a4246ba78 100644
--- a/plugins/providers/virtualbox/driver/meta.rb
+++ b/plugins/providers/virtualbox/driver/meta.rb
@@ -89,6 +89,7 @@ module VagrantPlugins
:create_host_only_network,
:create_snapshot,
:delete,
+ :delete_snapshot,
:delete_unused_host_only_networks,
:discard_saved_state,
:enable_adapters,
@@ -113,6 +114,7 @@ module VagrantPlugins
:read_vms,
:reconfig_host_only,
:remove_dhcp_server,
+ :restore_snapshot,
:resume,
:set_mac_address,
:set_name,
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index df833bb3f..b7e186538 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -86,6 +86,14 @@ module VagrantPlugins
execute("snapshot", machine_id, "take", snapshot_name)
end
+ def delete_snapshot(machine_id, snapshot_name)
+ execute("snapshot", machine_id, "delete", snapshot_name)
+ end
+
+ def restore_snapshot(machine_id, snapshot_name)
+ execute("snapshot", machine_id, "restore", snapshot_name)
+ end
+
def delete
execute("unregistervm", @uuid, "--delete")
end
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 171cd60ba..7db1260ae 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1765,6 +1765,17 @@ en:
set_name:
setting_name: |-
Setting the name of the VM: %{name}
+ snapshot:
+ deleting: |-
+ Deleting the snapshot '%{name}'...
+ deleted: |-
+ Snapshot deleted!
+ saving: |-
+ Snapshotting the machine as '%{name}'...
+ saved: |-
+ Snapshot saved! You can restore the snapshot at any time by
+ using `vagrant snapshot restore`. You can delete it using
+ `vagrant snapshot delete`.
suspend:
suspending: Saving VM state and suspending execution...
From c635352b898b42c4ff7ede683dc527a3dfa5d395 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 7 Oct 2015 16:41:58 -0400
Subject: [PATCH 084/484] providers/virtualbox: list snapshots, progress for
delete
---
plugins/providers/virtualbox/action.rb | 15 +++++++
.../virtualbox/action/snapshot_delete.rb | 9 +++-
.../virtualbox/action/snapshot_list.rb | 22 ++++++++++
.../virtualbox/action/snapshot_restore.rb | 21 ++++++++++
plugins/providers/virtualbox/driver/meta.rb | 1 +
.../virtualbox/driver/version_5_0.rb | 41 ++++++++++++++++++-
6 files changed, 107 insertions(+), 2 deletions(-)
create mode 100644 plugins/providers/virtualbox/action/snapshot_list.rb
create mode 100644 plugins/providers/virtualbox/action/snapshot_restore.rb
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 96cd2373d..d355b8a69 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -43,6 +43,8 @@ module VagrantPlugins
autoload :SetName, File.expand_path("../action/set_name", __FILE__)
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
autoload :SnapshotDelete, File.expand_path("../action/snapshot_delete", __FILE__)
+ autoload :SnapshotList, File.expand_path("../action/snapshot_list", __FILE__)
+ autoload :SnapshotRestore, File.expand_path("../action/snapshot_restore", __FILE__)
autoload :SnapshotSave, File.expand_path("../action/snapshot_save", __FILE__)
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
@@ -237,6 +239,19 @@ module VagrantPlugins
end
end
+ def self.action_snapshot_list
+ Vagrant::Action::Builder.new.tap do |b|
+ b.use CheckVirtualbox
+ b.use Call, Created do |env, b2|
+ if env[:result]
+ b2.use SnapshotList
+ else
+ b2.use MessageNotCreated
+ end
+ end
+ end
+ end
+
# This is the action that is primarily responsible for saving a snapshot
def self.action_snapshot_save
Vagrant::Action::Builder.new.tap do |b|
diff --git a/plugins/providers/virtualbox/action/snapshot_delete.rb b/plugins/providers/virtualbox/action/snapshot_delete.rb
index 2efc8eae2..1d8cecc73 100644
--- a/plugins/providers/virtualbox/action/snapshot_delete.rb
+++ b/plugins/providers/virtualbox/action/snapshot_delete.rb
@@ -11,7 +11,14 @@ module VagrantPlugins
"vagrant.actions.vm.snapshot.deleting",
name: env[:snapshot_name]))
env[:machine].provider.driver.delete_snapshot(
- env[:machine].id, env[:snapshot_name])
+ env[:machine].id, env[:snapshot_name]) do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ # Clear the line one last time since the progress meter doesn't disappear
+ # immediately.
+ env[:ui].clear_line
env[:ui].success(I18n.t(
"vagrant.actions.vm.snapshot.deleted",
diff --git a/plugins/providers/virtualbox/action/snapshot_list.rb b/plugins/providers/virtualbox/action/snapshot_list.rb
new file mode 100644
index 000000000..e909c5e87
--- /dev/null
+++ b/plugins/providers/virtualbox/action/snapshot_list.rb
@@ -0,0 +1,22 @@
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ class SnapshotList
+ def initialize(app, env)
+ @app = app
+ end
+
+ def call(env)
+ snapshots = env[:machine].provider.driver.list_snapshots(
+ env[:machine].id)
+
+ snapshots.each do |snapshot|
+ env[:machine].ui.output(snapshot, prefix: false)
+ end
+
+ @app.call(env)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/virtualbox/action/snapshot_restore.rb b/plugins/providers/virtualbox/action/snapshot_restore.rb
new file mode 100644
index 000000000..c05480261
--- /dev/null
+++ b/plugins/providers/virtualbox/action/snapshot_restore.rb
@@ -0,0 +1,21 @@
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ class SnapshotRestore
+ def initialize(app, env)
+ @app = app
+ end
+
+ def call(env)
+ env[:ui].info(I18n.t(
+ "vagrant.actions.vm.snapshot.restoring",
+ name: env[:snapshot_name]))
+ env[:machine].provider.driver.restore_snapshot(
+ env[:machine].id, env[:snapshot_name])
+
+ @app.call(env)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/providers/virtualbox/driver/meta.rb b/plugins/providers/virtualbox/driver/meta.rb
index a4246ba78..136ab196a 100644
--- a/plugins/providers/virtualbox/driver/meta.rb
+++ b/plugins/providers/virtualbox/driver/meta.rb
@@ -98,6 +98,7 @@ module VagrantPlugins
:forward_ports,
:halt,
:import,
+ :list_snapshots,
:read_forwarded_ports,
:read_bridged_interfaces,
:read_dhcp_servers,
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index b7e186538..2a0f3ea3d 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -87,7 +87,46 @@ module VagrantPlugins
end
def delete_snapshot(machine_id, snapshot_name)
- execute("snapshot", machine_id, "delete", snapshot_name)
+ # Start with 0%
+ last = 0
+ total = ""
+ yield 0 if block_given?
+
+ # Snapshot and report the % progress
+ execute("snapshot", machine_id, "delete", snapshot_name) do |type, data|
+ if type == :stderr
+ # Append the data so we can see the full view
+ total << data.gsub("\r", "")
+
+ # Break up the lines. We can't get the progress until we see an "OK"
+ lines = total.split("\n")
+
+ # The progress of the import will be in the last line. Do a greedy
+ # regular expression to find what we're looking for.
+ match = /.+(\d{2})%/.match(lines.last)
+ if match
+ current = match[1].to_i
+ if current > last
+ last = current
+ yield current if block_given?
+ end
+ end
+ end
+ end
+ end
+
+ def list_snapshots(machine_id)
+ result = []
+ output = execute(
+ "snapshot", machine_id, "list", "--machinereadable",
+ retryable: true)
+ output.split("\n").each do |line|
+ if line =~ /^SnapshotName.*?="(.+?)"$/i
+ result << $1.to_s
+ end
+ end
+
+ result.sort
end
def restore_snapshot(machine_id, snapshot_name)
From 8c0e38b3978acdc18ac2dc3223d219c242db33b1 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 7 Oct 2015 16:48:29 -0400
Subject: [PATCH 085/484] providers/virtualbox: snapshot restore
---
plugins/providers/virtualbox/action.rb | 19 ++++++++++++++
.../virtualbox/action/snapshot_restore.rb | 9 ++++++-
.../virtualbox/driver/version_5_0.rb | 26 ++++++++++++++++++-
templates/locales/en.yml | 2 ++
4 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index d355b8a69..d8b4d7ea1 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -252,6 +252,25 @@ module VagrantPlugins
end
end
+ # This is the action that is primarily responsible for saving a snapshot
+ def self.action_snapshot_restore
+ Vagrant::Action::Builder.new.tap do |b|
+ b.use CheckVirtualbox
+ b.use Call, Created do |env, b2|
+ if !env[:result]
+ b2.use MessageNotCreated
+ next
+ end
+
+ b2.use CheckAccessible
+ b2.use EnvSet, force_halt: true
+ b2.use action_halt
+ b2.use SnapshotRestore
+ b2.use action_start
+ end
+ end
+ end
+
# This is the action that is primarily responsible for saving a snapshot
def self.action_snapshot_save
Vagrant::Action::Builder.new.tap do |b|
diff --git a/plugins/providers/virtualbox/action/snapshot_restore.rb b/plugins/providers/virtualbox/action/snapshot_restore.rb
index c05480261..f655471c1 100644
--- a/plugins/providers/virtualbox/action/snapshot_restore.rb
+++ b/plugins/providers/virtualbox/action/snapshot_restore.rb
@@ -11,7 +11,14 @@ module VagrantPlugins
"vagrant.actions.vm.snapshot.restoring",
name: env[:snapshot_name]))
env[:machine].provider.driver.restore_snapshot(
- env[:machine].id, env[:snapshot_name])
+ env[:machine].id, env[:snapshot_name]) do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ # Clear the line one last time since the progress meter doesn't disappear
+ # immediately.
+ env[:ui].clear_line
@app.call(env)
end
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index 2a0f3ea3d..9f1c14359 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -130,7 +130,31 @@ module VagrantPlugins
end
def restore_snapshot(machine_id, snapshot_name)
- execute("snapshot", machine_id, "restore", snapshot_name)
+ # Start with 0%
+ last = 0
+ total = ""
+ yield 0 if block_given?
+
+ execute("snapshot", machine_id, "restore", snapshot_name) do |type, data|
+ if type == :stderr
+ # Append the data so we can see the full view
+ total << data.gsub("\r", "")
+
+ # Break up the lines. We can't get the progress until we see an "OK"
+ lines = total.split("\n")
+
+ # The progress of the import will be in the last line. Do a greedy
+ # regular expression to find what we're looking for.
+ match = /.+(\d{2})%/.match(lines.last)
+ if match
+ current = match[1].to_i
+ if current > last
+ last = current
+ yield current if block_given?
+ end
+ end
+ end
+ end
end
def delete
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 7db1260ae..f6d9e8cbc 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1770,6 +1770,8 @@ en:
Deleting the snapshot '%{name}'...
deleted: |-
Snapshot deleted!
+ restoring: |-
+ Restoring the snapshot '%{name}'...
saving: |-
Snapshotting the machine as '%{name}'...
saved: |-
From 00894b5a2791afce6ac5132c08d2a7d463519c8c Mon Sep 17 00:00:00 2001
From: caleblloyd
Date: Wed, 7 Oct 2015 20:25:09 -0400
Subject: [PATCH 086/484] hyper-v boot device by generation fixes #6372
---
.../providers/hyperv/scripts/import_vm.ps1 | 26 +++++++++++++------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/plugins/providers/hyperv/scripts/import_vm.ps1 b/plugins/providers/hyperv/scripts/import_vm.ps1
index 3e8664eb2..a994c1cfb 100644
--- a/plugins/providers/hyperv/scripts/import_vm.ps1
+++ b/plugins/providers/hyperv/scripts/import_vm.ps1
@@ -81,14 +81,24 @@ if (!$switchname) {
$switchname = (Select-Xml -xml $vmconfig -XPath "//AltSwitchName").node."#text"
}
-# Determine boot device
-Switch ((Select-Xml -xml $vmconfig -XPath "//boot").node.device0."#text") {
- "Floppy" { $bootdevice = "floppy" }
- "HardDrive" { $bootdevice = "IDE" }
- "Optical" { $bootdevice = "CD" }
- "Network" { $bootdevice = "LegacyNetworkAdapter" }
- "Default" { $bootdevice = "IDE" }
-} #switch
+if ($generation -eq 1) {
+ # Determine boot device
+ Switch ((Select-Xml -xml $vmconfig -XPath "//boot").node.device0."#text") {
+ "Floppy" { $bootdevice = "Floppy" }
+ "HardDrive" { $bootdevice = "IDE" }
+ "Optical" { $bootdevice = "CD" }
+ "Network" { $bootdevice = "LegacyNetworkAdapter" }
+ "Default" { $bootdevice = "IDE" }
+ } #switch
+} else {
+ # Determine boot device
+ Switch ((Select-Xml -xml $vmconfig -XPath "//boot").node.device0."#text") {
+ "HardDrive" { $bootdevice = "VHD" }
+ "Optical" { $bootdevice = "CD" }
+ "Network" { $bootdevice = "NetworkAdapter" }
+ "Default" { $bootdevice = "VHD" }
+ } #switch
+}
# Determine secure boot options
$secure_boot_enabled = (Select-Xml -xml $vmconfig -XPath "//secure_boot_enabled").Node."#text"
From c36b682e40e46f0e1e48f7d1cc2a24c2eed616a1 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 7 Oct 2015 22:22:55 -0400
Subject: [PATCH 087/484] providers/virtualbox: fix error if no snapshots
---
plugins/providers/virtualbox/action/snapshot_list.rb | 5 +++++
plugins/providers/virtualbox/driver/base.rb | 3 ++-
plugins/providers/virtualbox/driver/version_5_0.rb | 6 +++++-
templates/locales/en.yml | 7 +++++++
4 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/plugins/providers/virtualbox/action/snapshot_list.rb b/plugins/providers/virtualbox/action/snapshot_list.rb
index e909c5e87..27c1e3d12 100644
--- a/plugins/providers/virtualbox/action/snapshot_list.rb
+++ b/plugins/providers/virtualbox/action/snapshot_list.rb
@@ -14,6 +14,11 @@ module VagrantPlugins
env[:machine].ui.output(snapshot, prefix: false)
end
+ if snapshots.empty?
+ env[:machine].ui.output(I18n.t("vagrant.actions.vm.snapshot.list_none"))
+ env[:machine].ui.detail(I18n.t("vagrant.actions.vm.snapshot.list_none_detail"))
+ end
+
@app.call(env)
end
end
diff --git a/plugins/providers/virtualbox/driver/base.rb b/plugins/providers/virtualbox/driver/base.rb
index 768bd9cef..8dc0ba994 100644
--- a/plugins/providers/virtualbox/driver/base.rb
+++ b/plugins/providers/virtualbox/driver/base.rb
@@ -386,7 +386,8 @@ module VagrantPlugins
if errored
raise Vagrant::Errors::VBoxManageError,
command: command.inspect,
- stderr: r.stderr
+ stderr: r.stderr,
+ stdout: r.stdout
end
end
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index 9f1c14359..9762eda42 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -116,10 +116,11 @@ module VagrantPlugins
end
def list_snapshots(machine_id)
- result = []
output = execute(
"snapshot", machine_id, "list", "--machinereadable",
retryable: true)
+
+ result = []
output.split("\n").each do |line|
if line =~ /^SnapshotName.*?="(.+?)"$/i
result << $1.to_s
@@ -127,6 +128,9 @@ module VagrantPlugins
end
result.sort
+ rescue Vagrant::Errors::VBoxManageError => e
+ return [] if e.extra_data[:stdout].include?("does not have")
+ raise
end
def restore_snapshot(machine_id, snapshot_name)
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index f6d9e8cbc..5d4e4d912 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1770,6 +1770,13 @@ en:
Deleting the snapshot '%{name}'...
deleted: |-
Snapshot deleted!
+ list_none: |-
+ No snapshots have been taken yet!
+ list_none_detail: |-
+ You can take a snapshot using `vagrant snapshot save`. Note that
+ not all providers support this yet. Once a snapshot is taken, you
+ can list them using this command, and use commands such as
+ `vagrant snapshot restore` to go back to a certain snapshot.
restoring: |-
Restoring the snapshot '%{name}'...
saving: |-
From ed4df21c85813eeec76c4c1d3e4bcd097bbe912f Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 7 Oct 2015 22:52:27 -0400
Subject: [PATCH 088/484] commands/snapshot: push and pop
---
lib/vagrant/action.rb | 1 +
lib/vagrant/action/builtin/is_env_set.rb | 23 +++++++
plugins/commands/snapshot/command/pop.rb | 28 ++++++++
plugins/commands/snapshot/command/push.rb | 33 ++++++++++
.../commands/snapshot/command/push_shared.rb | 65 +++++++++++++++++++
plugins/commands/snapshot/command/root.rb | 10 +++
plugins/providers/virtualbox/action.rb | 7 ++
7 files changed, 167 insertions(+)
create mode 100644 lib/vagrant/action/builtin/is_env_set.rb
create mode 100644 plugins/commands/snapshot/command/pop.rb
create mode 100644 plugins/commands/snapshot/command/push.rb
create mode 100644 plugins/commands/snapshot/command/push_shared.rb
diff --git a/lib/vagrant/action.rb b/lib/vagrant/action.rb
index fcf8d916d..db4875dbb 100644
--- a/lib/vagrant/action.rb
+++ b/lib/vagrant/action.rb
@@ -20,6 +20,7 @@ module Vagrant
autoload :HandleBox, "vagrant/action/builtin/handle_box"
autoload :HandleBoxUrl, "vagrant/action/builtin/handle_box_url"
autoload :HandleForwardedPortCollisions, "vagrant/action/builtin/handle_forwarded_port_collisions"
+ autoload :IsEnvSet, "vagrant/action/builtin/is_env_set"
autoload :IsState, "vagrant/action/builtin/is_state"
autoload :Lock, "vagrant/action/builtin/lock"
autoload :Message, "vagrant/action/builtin/message"
diff --git a/lib/vagrant/action/builtin/is_env_set.rb b/lib/vagrant/action/builtin/is_env_set.rb
new file mode 100644
index 000000000..d08ed9632
--- /dev/null
+++ b/lib/vagrant/action/builtin/is_env_set.rb
@@ -0,0 +1,23 @@
+module Vagrant
+ module Action
+ module Builtin
+ # This middleware is meant to be used with Call and can check if
+ # a variable in env is set.
+ class IsEnvSet
+ def initialize(app, env, key, **opts)
+ @app = app
+ @logger = Log4r::Logger.new("vagrant::action::builtin::is_env_set")
+ @key = key
+ @invert = !!opts[:invert]
+ end
+
+ def call(env)
+ @logger.debug("Checking if env is set: '#{@key}'")
+ env[:result] = !!env[@key]
+ @logger.debug(" - Result: #{env[:result].inspect}")
+ @app.call(env)
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/command/pop.rb b/plugins/commands/snapshot/command/pop.rb
new file mode 100644
index 000000000..2c3499f43
--- /dev/null
+++ b/plugins/commands/snapshot/command/pop.rb
@@ -0,0 +1,28 @@
+require 'json'
+require 'optparse'
+
+require_relative "push_shared"
+
+module VagrantPlugins
+ module CommandSnapshot
+ module Command
+ class Pop < Vagrant.plugin("2", :command)
+ include PushShared
+
+ def execute
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant snapshot pop [options] [vm-name]"
+ o.separator ""
+ o.separator "Restore state that was pushed with `vagrant snapshot push`."
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+
+ return shared_exec(argv, method(:pop))
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/command/push.rb b/plugins/commands/snapshot/command/push.rb
new file mode 100644
index 000000000..c1168bcf2
--- /dev/null
+++ b/plugins/commands/snapshot/command/push.rb
@@ -0,0 +1,33 @@
+require 'json'
+require 'optparse'
+
+require_relative "push_shared"
+
+module VagrantPlugins
+ module CommandSnapshot
+ module Command
+ class Push < Vagrant.plugin("2", :command)
+ include PushShared
+
+ def execute
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant snapshot push [options] [vm-name]"
+ o.separator ""
+ o.separator "Take a snapshot of the current state of the machine and 'push'"
+ o.separator "it onto the stack of states. You can use `vagrant snapshot pop`"
+ o.separator "to restore back to this state at any time."
+ o.separator ""
+ o.separator "If you use `vagrant snapshot save` or restore at any point after"
+ o.separator "a push, pop will still bring you back to this pushed state."
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+
+ return shared_exec(argv, method(:push))
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/command/push_shared.rb b/plugins/commands/snapshot/command/push_shared.rb
new file mode 100644
index 000000000..880f8bcf5
--- /dev/null
+++ b/plugins/commands/snapshot/command/push_shared.rb
@@ -0,0 +1,65 @@
+require 'json'
+
+module VagrantPlugins
+ module CommandSnapshot
+ module Command
+ module PushShared
+ def shared_exec(argv, m)
+ with_target_vms(argv) do |vm|
+ if !vm.id
+ vm.ui.info("Not created. Cannot push snapshot state.")
+ next
+ end
+
+ vm.env.lock("machine-snapshot-stack") do
+ m.call(vm)
+ end
+ end
+
+ 0
+ end
+
+ def push(machine)
+ snapshot_name = "push_#{Time.now.to_i}_#{rand(10000)}"
+
+ # Save the snapshot. This will raise an exception if it fails.
+ machine.action(:snapshot_save, snapshot_name: snapshot_name)
+
+ # Success! Write the resulting stack out
+ modify_snapshot_stack(machine) do |stack|
+ stack << snapshot_name
+ end
+ end
+
+ def pop(machine)
+ modify_snapshot_stack(machine) do |stack|
+ name = stack.pop
+
+ # Restore the snapshot and tell the provider to delete it as well.
+ machine.action(
+ :snapshot_restore,
+ snapshot_name: name,
+ snapshot_delete: true)
+ end
+ end
+
+ protected
+
+ def modify_snapshot_stack(machine)
+ # Get the stack
+ snapshot_stack = []
+ snapshot_file = machine.data_dir.join("snapshot_stack")
+ snapshot_stack = JSON.parse(snapshot_file.read) if snapshot_file.file?
+
+ # Yield it so it can be modified
+ yield snapshot_stack
+
+ # Write it out
+ snapshot_file.open("w+") do |f|
+ f.write(JSON.dump(snapshot_stack))
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/commands/snapshot/command/root.rb b/plugins/commands/snapshot/command/root.rb
index 03bcebb80..2ed460fa4 100644
--- a/plugins/commands/snapshot/command/root.rb
+++ b/plugins/commands/snapshot/command/root.rb
@@ -33,6 +33,16 @@ module VagrantPlugins
require File.expand_path("../list", __FILE__)
List
end
+
+ @subcommands.register(:push) do
+ require File.expand_path("../push", __FILE__)
+ Push
+ end
+
+ @subcommands.register(:pop) do
+ require File.expand_path("../pop", __FILE__)
+ Pop
+ end
end
def execute
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index d8b4d7ea1..12773736d 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -266,6 +266,13 @@ module VagrantPlugins
b2.use EnvSet, force_halt: true
b2.use action_halt
b2.use SnapshotRestore
+
+ b2.use Call, IsEnvSet, :snapshot_delete do |env2, b3|
+ if env2[:result]
+ b3.use action_snapshot_delete
+ end
+ end
+
b2.use action_start
end
end
From cc8cdafdc32f4b6e627421e4c06fda1e009f5886 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 7 Oct 2015 22:54:27 -0400
Subject: [PATCH 089/484] test: test for IsEnvSet
---
.../vagrant/action/builtin/is_env_set_test.rb | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 test/unit/vagrant/action/builtin/is_env_set_test.rb
diff --git a/test/unit/vagrant/action/builtin/is_env_set_test.rb b/test/unit/vagrant/action/builtin/is_env_set_test.rb
new file mode 100644
index 000000000..56eafa956
--- /dev/null
+++ b/test/unit/vagrant/action/builtin/is_env_set_test.rb
@@ -0,0 +1,31 @@
+require "pathname"
+require "tmpdir"
+
+require File.expand_path("../../../../base", __FILE__)
+
+describe Vagrant::Action::Builtin::IsEnvSet do
+ let(:app) { lambda { |env| } }
+ let(:env) { { } }
+
+ describe "#call" do
+ it "sets result to true if it is set" do
+ env[:bar] = true
+
+ subject = described_class.new(app, env, :bar)
+
+ expect(app).to receive(:call).with(env)
+
+ subject.call(env)
+ expect(env[:result]).to be_true
+ end
+
+ it "sets result to false if it isn't set" do
+ subject = described_class.new(app, env, :bar)
+
+ expect(app).to receive(:call).with(env)
+
+ subject.call(env)
+ expect(env[:result]).to be_false
+ end
+ end
+end
From 94b675581379a062d6555adfa6ac82b87ec9084b Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Wed, 7 Oct 2015 23:03:13 -0400
Subject: [PATCH 090/484] website/docs: update docs for snapshotting
---
website/docs/source/layouts/layout.erb | 1 +
website/docs/source/v2/cli/snapshot.html.md | 79 +++++++++++++++++++++
2 files changed, 80 insertions(+)
create mode 100644 website/docs/source/v2/cli/snapshot.html.md
diff --git a/website/docs/source/layouts/layout.erb b/website/docs/source/layouts/layout.erb
index 4fedc3627..259577d79 100644
--- a/website/docs/source/layouts/layout.erb
+++ b/website/docs/source/layouts/layout.erb
@@ -108,6 +108,7 @@
>reload
>resume
>share
+ >snapshot
>ssh
>ssh-config
>status
diff --git a/website/docs/source/v2/cli/snapshot.html.md b/website/docs/source/v2/cli/snapshot.html.md
new file mode 100644
index 000000000..42a2dfc68
--- /dev/null
+++ b/website/docs/source/v2/cli/snapshot.html.md
@@ -0,0 +1,79 @@
+---
+page_title: "vagrant snapshot - Command-Line Interface"
+sidebar_current: "cli-snapshot"
+---
+
+# Snapshot
+
+**Command: `vagrant snapshot`**
+
+This is the command used to manage snapshots with the guest machine.
+Snapshots record a point-in-time state of a guest machine. You can then
+quickly restore to this environment. This lets you experiment and try things
+and quickly restore back to a previous state.
+
+Snapshotting is not supported by every provider. If it isn't supported,
+Vagrant will give you an error message.
+
+The main functionality of this command is exposed via even more subcommands:
+
+* `push`
+* `pop`
+* `save`
+* `restore`
+* `list`
+* `delete`
+
+# Snapshot Push
+
+**Command: `vagrant snapshot push`**
+
+This takes a snapshot and pushes it onto the snapshot stack.
+
+This is a shorthand for `vagrant snapshot save` where you don't need
+to specify a name. When you call the inverse `vagrant snapshot pop`, it will
+restore the pushed state.
+
+~> **Warning:** If you are using `push` and `pop`, avoid using `save`
+ and `restore` which are unsafe to mix.
+
+# Snapshot Pop
+
+**Command: `vagrant snapshot pop`**
+
+This command is the inverse of `vagrant snapshot push`: it will restore
+the pushed state.
+
+# Snapshot Save
+
+**Command: `vagrant snapshot save NAME`**
+
+This command saves a new named snapshot. If this command is used, the
+`push` and `pop` subcommands cannot be safely used.
+
+# Snapshot Restore
+
+**Command: `vagrant snapshot restore NAME`**
+
+This command restores the named snapshot.
+
+# Snapshot List
+
+**Command: `vagrant snapshot list`**
+
+This command will list all the snapshots taken.
+
+# Snapshot Delete
+
+**Command: `vagrant snapshot delete NAME`**
+
+This command will delete the named snapshot.
+
+Some providers require all "child" snapshots to be deleted first. Vagrant
+itself doesn't track what these children are. If this is the case (such
+as with VirtualBox), then you must be sure to delete the snapshots in the
+reverse order they were taken.
+
+This command is typically _much faster_ if the machine is halted prior to
+snapshotting. If this isn't an option, or isn't ideal, then the deletion
+can also be done online with most providers.
From 7480b65e9dff0cbb1ada8f8fe4d7086882b23e28 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 08:46:36 -0400
Subject: [PATCH 091/484] providers/virtualbox: use caps for snapshot list
---
plugins/commands/snapshot/command/list.rb | 23 +++++++++++++---
plugins/providers/virtualbox/action.rb | 14 ----------
.../virtualbox/action/snapshot_list.rb | 27 -------------------
plugins/providers/virtualbox/cap.rb | 7 +++++
plugins/providers/virtualbox/plugin.rb | 5 ++++
templates/locales/en.yml | 7 +++++
6 files changed, 39 insertions(+), 44 deletions(-)
delete mode 100644 plugins/providers/virtualbox/action/snapshot_list.rb
diff --git a/plugins/commands/snapshot/command/list.rb b/plugins/commands/snapshot/command/list.rb
index af91e76f5..d0c433b94 100644
--- a/plugins/commands/snapshot/command/list.rb
+++ b/plugins/commands/snapshot/command/list.rb
@@ -5,8 +5,6 @@ module VagrantPlugins
module Command
class List < Vagrant.plugin("2", :command)
def execute
- options = {}
-
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant snapshot list [options] [vm-name]"
o.separator ""
@@ -18,7 +16,26 @@ module VagrantPlugins
return if !argv
with_target_vms(argv) do |vm|
- vm.action(:snapshot_list)
+ if !vm.id
+ vm.ui.info(I18n.t("vagrant.commands.common.vm_not_created"))
+ next
+ end
+
+ if !vm.provider.capability?(:snapshot_list)
+ vm.ui.info(I18n.t("vagrant.commands.snapshot.not_supported"))
+ next
+ end
+
+ snapshots = vm.provider.capability(:snapshot_list)
+ if snapshots.empty?
+ vm.ui.output(I18n.t("vagrant.actions.vm.snapshot.list_none"))
+ vm.ui.detail(I18n.t("vagrant.actions.vm.snapshot.list_none_detail"))
+ next
+ end
+
+ snapshots.each do |snapshot|
+ vm.ui.output(snapshot, prefix: false)
+ end
end
# Success, exit status 0
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 12773736d..9c4d68c72 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -43,7 +43,6 @@ module VagrantPlugins
autoload :SetName, File.expand_path("../action/set_name", __FILE__)
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
autoload :SnapshotDelete, File.expand_path("../action/snapshot_delete", __FILE__)
- autoload :SnapshotList, File.expand_path("../action/snapshot_list", __FILE__)
autoload :SnapshotRestore, File.expand_path("../action/snapshot_restore", __FILE__)
autoload :SnapshotSave, File.expand_path("../action/snapshot_save", __FILE__)
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
@@ -239,19 +238,6 @@ module VagrantPlugins
end
end
- def self.action_snapshot_list
- Vagrant::Action::Builder.new.tap do |b|
- b.use CheckVirtualbox
- b.use Call, Created do |env, b2|
- if env[:result]
- b2.use SnapshotList
- else
- b2.use MessageNotCreated
- end
- end
- end
- end
-
# This is the action that is primarily responsible for saving a snapshot
def self.action_snapshot_restore
Vagrant::Action::Builder.new.tap do |b|
diff --git a/plugins/providers/virtualbox/action/snapshot_list.rb b/plugins/providers/virtualbox/action/snapshot_list.rb
deleted file mode 100644
index 27c1e3d12..000000000
--- a/plugins/providers/virtualbox/action/snapshot_list.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-module VagrantPlugins
- module ProviderVirtualBox
- module Action
- class SnapshotList
- def initialize(app, env)
- @app = app
- end
-
- def call(env)
- snapshots = env[:machine].provider.driver.list_snapshots(
- env[:machine].id)
-
- snapshots.each do |snapshot|
- env[:machine].ui.output(snapshot, prefix: false)
- end
-
- if snapshots.empty?
- env[:machine].ui.output(I18n.t("vagrant.actions.vm.snapshot.list_none"))
- env[:machine].ui.detail(I18n.t("vagrant.actions.vm.snapshot.list_none_detail"))
- end
-
- @app.call(env)
- end
- end
- end
- end
-end
diff --git a/plugins/providers/virtualbox/cap.rb b/plugins/providers/virtualbox/cap.rb
index e459c97bf..77f8ee1ad 100644
--- a/plugins/providers/virtualbox/cap.rb
+++ b/plugins/providers/virtualbox/cap.rb
@@ -22,6 +22,13 @@ module VagrantPlugins
def self.nic_mac_addresses(machine)
machine.provider.driver.read_mac_addresses
end
+
+ # Returns a list of the snapshots that are taken on this machine.
+ #
+ # @return [Array] Snapshot Name
+ def self.snapshot_list(machine)
+ machine.provider.driver.list_snapshots(machine.id)
+ end
end
end
end
diff --git a/plugins/providers/virtualbox/plugin.rb b/plugins/providers/virtualbox/plugin.rb
index 18e33d4bb..84f86ba51 100644
--- a/plugins/providers/virtualbox/plugin.rb
+++ b/plugins/providers/virtualbox/plugin.rb
@@ -33,6 +33,11 @@ module VagrantPlugins
require_relative "cap"
Cap
end
+
+ provider_capability(:virtualbox, :snapshot_list) do
+ require_relative "cap"
+ Cap
+ end
end
autoload :Action, File.expand_path("../action", __FILE__)
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 5d4e4d912..c57f78688 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1501,6 +1501,13 @@ en:
Post install message from the '%{name}' plugin:
%{message}
+ snapshot: |-
+ not_supported: |-
+ This provider doesn't support snapshots.
+
+ This may be intentional or this may be a bug. If this provider
+ should support snapshots, then please report this as a bug to the
+ maintainer of the provider.
status:
aborted: |-
The VM is in an aborted state. This means that it was abruptly
From 0abc17eaed7755f9ebc2c3cabd3de8a73c843064 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 08:55:13 -0400
Subject: [PATCH 092/484] commands/snapshot: push now uses caps to be more
resilient
---
.../commands/snapshot/command/push_shared.rb | 47 ++++++++-----------
templates/locales/en.yml | 6 ++-
2 files changed, 24 insertions(+), 29 deletions(-)
diff --git a/plugins/commands/snapshot/command/push_shared.rb b/plugins/commands/snapshot/command/push_shared.rb
index 880f8bcf5..bbaba8dbc 100644
--- a/plugins/commands/snapshot/command/push_shared.rb
+++ b/plugins/commands/snapshot/command/push_shared.rb
@@ -24,40 +24,31 @@ module VagrantPlugins
# Save the snapshot. This will raise an exception if it fails.
machine.action(:snapshot_save, snapshot_name: snapshot_name)
-
- # Success! Write the resulting stack out
- modify_snapshot_stack(machine) do |stack|
- stack << snapshot_name
- end
end
def pop(machine)
- modify_snapshot_stack(machine) do |stack|
- name = stack.pop
-
- # Restore the snapshot and tell the provider to delete it as well.
- machine.action(
- :snapshot_restore,
- snapshot_name: name,
- snapshot_delete: true)
+ # By reverse sorting, we should be able to find the first
+ # pushed snapshot.
+ name = nil
+ snapshots = machine.provider.capability(:snapshot_list)
+ snapshots.sort.reverse.each do |snapshot|
+ if snapshot =~ /^push_\d+_\d+$/
+ name = snapshot
+ break
+ end
end
- end
- protected
-
- def modify_snapshot_stack(machine)
- # Get the stack
- snapshot_stack = []
- snapshot_file = machine.data_dir.join("snapshot_stack")
- snapshot_stack = JSON.parse(snapshot_file.read) if snapshot_file.file?
-
- # Yield it so it can be modified
- yield snapshot_stack
-
- # Write it out
- snapshot_file.open("w+") do |f|
- f.write(JSON.dump(snapshot_stack))
+ # If no snapshot was found, we never pushed
+ if !name
+ machine.ui.info(I18n.t("vagrant.commands.snapshot.no_push_snapshot"))
+ return
end
+
+ # Restore the snapshot and tell the provider to delete it as well.
+ machine.action(
+ :snapshot_restore,
+ snapshot_name: name,
+ snapshot_delete: true)
end
end
end
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index c57f78688..929962453 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1501,13 +1501,17 @@ en:
Post install message from the '%{name}' plugin:
%{message}
- snapshot: |-
+ snapshot:
not_supported: |-
This provider doesn't support snapshots.
This may be intentional or this may be a bug. If this provider
should support snapshots, then please report this as a bug to the
maintainer of the provider.
+ no_push_snapshot: |-
+ No pushed snapshot found!
+
+ Use `vagrant snapshot push` to push a snapshot to restore to.
status:
aborted: |-
The VM is in an aborted state. This means that it was abruptly
From 6e187aaefbbe7b22938960d2c7cf29458409ecef Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 08:57:21 -0400
Subject: [PATCH 093/484] providers/virtualbox: v4.2 and 4.3 support
---
.../virtualbox/driver/version_4_2.rb | 79 +++++++++++++++++++
.../virtualbox/driver/version_4_3.rb | 75 ++++++++++++++++++
2 files changed, 154 insertions(+)
diff --git a/plugins/providers/virtualbox/driver/version_4_2.rb b/plugins/providers/virtualbox/driver/version_4_2.rb
index 0f1f79698..b3f33f110 100644
--- a/plugins/providers/virtualbox/driver/version_4_2.rb
+++ b/plugins/providers/virtualbox/driver/version_4_2.rb
@@ -608,6 +608,85 @@ module VagrantPlugins
execute("showvminfo", uuid)
return true
end
+
+ def create_snapshot(machine_id, snapshot_name)
+ execute("snapshot", machine_id, "take", snapshot_name)
+ end
+
+ def delete_snapshot(machine_id, snapshot_name)
+ # Start with 0%
+ last = 0
+ total = ""
+ yield 0 if block_given?
+
+ # Snapshot and report the % progress
+ execute("snapshot", machine_id, "delete", snapshot_name) do |type, data|
+ if type == :stderr
+ # Append the data so we can see the full view
+ total << data.gsub("\r", "")
+
+ # Break up the lines. We can't get the progress until we see an "OK"
+ lines = total.split("\n")
+
+ # The progress of the import will be in the last line. Do a greedy
+ # regular expression to find what we're looking for.
+ match = /.+(\d{2})%/.match(lines.last)
+ if match
+ current = match[1].to_i
+ if current > last
+ last = current
+ yield current if block_given?
+ end
+ end
+ end
+ end
+ end
+
+ def list_snapshots(machine_id)
+ output = execute(
+ "snapshot", machine_id, "list", "--machinereadable",
+ retryable: true)
+
+ result = []
+ output.split("\n").each do |line|
+ if line =~ /^SnapshotName.*?="(.+?)"$/i
+ result << $1.to_s
+ end
+ end
+
+ result.sort
+ rescue Vagrant::Errors::VBoxManageError => e
+ return [] if e.extra_data[:stdout].include?("does not have")
+ raise
+ end
+
+ def restore_snapshot(machine_id, snapshot_name)
+ # Start with 0%
+ last = 0
+ total = ""
+ yield 0 if block_given?
+
+ execute("snapshot", machine_id, "restore", snapshot_name) do |type, data|
+ if type == :stderr
+ # Append the data so we can see the full view
+ total << data.gsub("\r", "")
+
+ # Break up the lines. We can't get the progress until we see an "OK"
+ lines = total.split("\n")
+
+ # The progress of the import will be in the last line. Do a greedy
+ # regular expression to find what we're looking for.
+ match = /.+(\d{2})%/.match(lines.last)
+ if match
+ current = match[1].to_i
+ if current > last
+ last = current
+ yield current if block_given?
+ end
+ end
+ end
+ end
+ end
end
end
end
diff --git a/plugins/providers/virtualbox/driver/version_4_3.rb b/plugins/providers/virtualbox/driver/version_4_3.rb
index bc2c87478..b51eec37a 100644
--- a/plugins/providers/virtualbox/driver/version_4_3.rb
+++ b/plugins/providers/virtualbox/driver/version_4_3.rb
@@ -90,6 +90,81 @@ module VagrantPlugins
execute("snapshot", machine_id, "take", snapshot_name)
end
+ def delete_snapshot(machine_id, snapshot_name)
+ # Start with 0%
+ last = 0
+ total = ""
+ yield 0 if block_given?
+
+ # Snapshot and report the % progress
+ execute("snapshot", machine_id, "delete", snapshot_name) do |type, data|
+ if type == :stderr
+ # Append the data so we can see the full view
+ total << data.gsub("\r", "")
+
+ # Break up the lines. We can't get the progress until we see an "OK"
+ lines = total.split("\n")
+
+ # The progress of the import will be in the last line. Do a greedy
+ # regular expression to find what we're looking for.
+ match = /.+(\d{2})%/.match(lines.last)
+ if match
+ current = match[1].to_i
+ if current > last
+ last = current
+ yield current if block_given?
+ end
+ end
+ end
+ end
+ end
+
+ def list_snapshots(machine_id)
+ output = execute(
+ "snapshot", machine_id, "list", "--machinereadable",
+ retryable: true)
+
+ result = []
+ output.split("\n").each do |line|
+ if line =~ /^SnapshotName.*?="(.+?)"$/i
+ result << $1.to_s
+ end
+ end
+
+ result.sort
+ rescue Vagrant::Errors::VBoxManageError => e
+ return [] if e.extra_data[:stdout].include?("does not have")
+ raise
+ end
+
+ def restore_snapshot(machine_id, snapshot_name)
+ # Start with 0%
+ last = 0
+ total = ""
+ yield 0 if block_given?
+
+ execute("snapshot", machine_id, "restore", snapshot_name) do |type, data|
+ if type == :stderr
+ # Append the data so we can see the full view
+ total << data.gsub("\r", "")
+
+ # Break up the lines. We can't get the progress until we see an "OK"
+ lines = total.split("\n")
+
+ # The progress of the import will be in the last line. Do a greedy
+ # regular expression to find what we're looking for.
+ match = /.+(\d{2})%/.match(lines.last)
+ if match
+ current = match[1].to_i
+ if current > last
+ last = current
+ yield current if block_given?
+ end
+ end
+ end
+ end
+ end
+
def delete
execute("unregistervm", @uuid, "--delete")
end
From 31ae00cfc39a485835e9b4a32843bb7901d67dec Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 09:10:55 -0400
Subject: [PATCH 094/484] test: more tests for snapshots
---
.../commands/snapshot/command/pop_test.rb | 52 +++++++++++++++++++
.../commands/snapshot/command/push_test.rb | 46 ++++++++++++++++
2 files changed, 98 insertions(+)
create mode 100644 test/unit/plugins/commands/snapshot/command/pop_test.rb
create mode 100644 test/unit/plugins/commands/snapshot/command/push_test.rb
diff --git a/test/unit/plugins/commands/snapshot/command/pop_test.rb b/test/unit/plugins/commands/snapshot/command/pop_test.rb
new file mode 100644
index 000000000..66687868f
--- /dev/null
+++ b/test/unit/plugins/commands/snapshot/command/pop_test.rb
@@ -0,0 +1,52 @@
+require File.expand_path("../../../../../base", __FILE__)
+
+require Vagrant.source_root.join("plugins/commands/snapshot/command/pop")
+
+describe VagrantPlugins::CommandSnapshot::Command::Pop do
+ include_context "unit"
+
+ let(:iso_env) do
+ # We have to create a Vagrantfile so there is a root path
+ env = isolated_environment
+ env.vagrantfile("")
+ env.create_vagrant_env
+ end
+
+ let(:guest) { double("guest") }
+ let(:host) { double("host") }
+ let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
+
+ let(:argv) { [] }
+
+ subject { described_class.new(argv, iso_env) }
+
+ before do
+ allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
+ end
+
+ describe "execute" do
+ it "calls snapshot_restore with the last pushed snapshot" do
+ machine.id = "foo"
+
+ allow(machine.provider).to receive(:capability).
+ with(:snapshot_list).and_return(["push_2_0", "push_1_0"])
+
+ expect(machine).to receive(:action) do |name, opts|
+ expect(name).to eq(:snapshot_restore)
+ expect(opts[:snapshot_name]).to eq("push_2_0")
+ end
+
+ expect(subject.execute).to eq(0)
+ end
+
+ it "isn't an error if no matching snapshot" do
+ machine.id = "foo"
+
+ allow(machine.provider).to receive(:capability).
+ with(:snapshot_list).and_return(["foo"])
+
+ expect(machine).to_not receive(:action)
+ expect(subject.execute).to eq(0)
+ end
+ end
+end
diff --git a/test/unit/plugins/commands/snapshot/command/push_test.rb b/test/unit/plugins/commands/snapshot/command/push_test.rb
new file mode 100644
index 000000000..3da907cfa
--- /dev/null
+++ b/test/unit/plugins/commands/snapshot/command/push_test.rb
@@ -0,0 +1,46 @@
+require File.expand_path("../../../../../base", __FILE__)
+
+require Vagrant.source_root.join("plugins/commands/snapshot/command/push")
+
+describe VagrantPlugins::CommandSnapshot::Command::Push do
+ include_context "unit"
+
+ let(:iso_env) do
+ # We have to create a Vagrantfile so there is a root path
+ env = isolated_environment
+ env.vagrantfile("")
+ env.create_vagrant_env
+ end
+
+ let(:guest) { double("guest") }
+ let(:host) { double("host") }
+ let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
+
+ let(:argv) { [] }
+
+ subject { described_class.new(argv, iso_env) }
+
+ before do
+ allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
+ end
+
+ describe "execute" do
+ it "calls snapshot_save with a random snapshot name" do
+ machine.id = "foo"
+
+ expect(machine).to receive(:action) do |name, opts|
+ expect(name).to eq(:snapshot_save)
+ expect(opts[:snapshot_name]).to match(/^push_/)
+ end
+
+ expect(subject.execute).to eq(0)
+ end
+
+ it "doesn't snapshot a non-existent machine" do
+ machine.id = nil
+
+ expect(machine).to_not receive(:action)
+ expect(subject.execute).to eq(0)
+ end
+ end
+end
From 99d29f17fa88b46e91bce85723ba0a305f4a05e2 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 10:35:36 -0400
Subject: [PATCH 095/484] commands/cap
---
plugins/commands/cap/command.rb | 68 +++++++++++++++++++
plugins/commands/cap/plugin.rb | 17 +++++
.../unit/plugins/commands/cap/command_test.rb | 51 ++++++++++++++
3 files changed, 136 insertions(+)
create mode 100644 plugins/commands/cap/command.rb
create mode 100644 plugins/commands/cap/plugin.rb
create mode 100644 test/unit/plugins/commands/cap/command_test.rb
diff --git a/plugins/commands/cap/command.rb b/plugins/commands/cap/command.rb
new file mode 100644
index 000000000..0c2d04e86
--- /dev/null
+++ b/plugins/commands/cap/command.rb
@@ -0,0 +1,68 @@
+require 'optparse'
+
+module VagrantPlugins
+ module CommandCap
+ class Command < Vagrant.plugin("2", :command)
+ def self.synopsis
+ "checks and executes capability"
+ end
+
+ def execute
+ options = {}
+ options[:check] = false
+
+ opts = OptionParser.new do |o|
+ o.banner = "Usage: vagrant cap [options] TYPE NAME [args]"
+ o.separator ""
+ o.separator "Options:"
+ o.separator ""
+
+ o.on("--check", "Only checks for a capability, does not execute") do |f|
+ options[:check] = f
+ end
+ end
+
+ # Parse the options
+ argv = parse_options(opts)
+ return if !argv
+ if argv.length < 2
+ raise Vagrant::Errors::CLIInvalidUsage,
+ help: opts.help.chomp
+ end
+
+ type = argv.shift.to_sym
+ name = argv.shift.to_sym
+
+ # Get the proper capability host to check
+ cap_host = nil
+ if type == :host
+ cap_host = @env.host
+ else
+ with_target_vms([]) do |vm|
+ cap_host = case type
+ when :provider
+ vm.provider
+ when :guest
+ vm.guest
+ else
+ raise Vagrant::Errors::CLIInvalidUsage,
+ help: opts.help.chomp
+ end
+ end
+ end
+
+ # If we're just checking, then just return exit codes
+ if options[:check]
+ return 0 if cap_host.capability?(name)
+ return 1
+ end
+
+ # Otherwise, call it
+ cap_host.capability(name, *argv)
+
+ # Success, exit status 0
+ 0
+ end
+ end
+ end
+end
diff --git a/plugins/commands/cap/plugin.rb b/plugins/commands/cap/plugin.rb
new file mode 100644
index 000000000..dd8ffbb23
--- /dev/null
+++ b/plugins/commands/cap/plugin.rb
@@ -0,0 +1,17 @@
+require "vagrant"
+
+module VagrantPlugins
+ module CommandCap
+ class Plugin < Vagrant.plugin("2")
+ name "cap command"
+ description <<-DESC
+ The `cap` command checks and executes arbitrary capabilities.
+ DESC
+
+ command("cap", primary: false) do
+ require File.expand_path("../command", __FILE__)
+ Command
+ end
+ end
+ end
+end
diff --git a/test/unit/plugins/commands/cap/command_test.rb b/test/unit/plugins/commands/cap/command_test.rb
new file mode 100644
index 000000000..9e3394fec
--- /dev/null
+++ b/test/unit/plugins/commands/cap/command_test.rb
@@ -0,0 +1,51 @@
+require File.expand_path("../../../../base", __FILE__)
+
+require Vagrant.source_root.join("plugins/commands/cap/command")
+
+describe VagrantPlugins::CommandCap::Command do
+ include_context "unit"
+
+ let(:iso_env) do
+ # We have to create a Vagrantfile so there is a root path
+ env = isolated_environment
+ env.vagrantfile("")
+ env.create_vagrant_env
+ end
+
+ let(:guest) { double("guest") }
+ let(:host) { double("host") }
+ let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
+
+ let(:argv) { [] }
+
+ subject { described_class.new(argv, iso_env) }
+
+ before do
+ allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
+ end
+
+ describe "execute" do
+ context "--check provider foo (exists)" do
+ let(:argv) { ["--check", "provider", "foo"] }
+ let(:cap) { Class.new }
+
+ before do
+ register_plugin do |p|
+ p.provider_capability(:dummy, :foo) { cap }
+ end
+ end
+
+ it "exits with 0 if it exists" do
+ expect(subject.execute).to eq(0)
+ end
+ end
+
+ context "--check provider foo (doesn't exists)" do
+ let(:argv) { ["--check", "provider", "foo"] }
+
+ it "exits with 1" do
+ expect(subject.execute).to eq(1)
+ end
+ end
+ end
+end
From 0b2d60ac399527d896b6c21c99f6fde133cff62e Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 10:36:44 -0400
Subject: [PATCH 096/484] commands/cap: better help
---
plugins/commands/cap/command.rb | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/plugins/commands/cap/command.rb b/plugins/commands/cap/command.rb
index 0c2d04e86..43a80cfb5 100644
--- a/plugins/commands/cap/command.rb
+++ b/plugins/commands/cap/command.rb
@@ -14,6 +14,13 @@ module VagrantPlugins
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant cap [options] TYPE NAME [args]"
o.separator ""
+ o.separator "This is an advanced command. If you don't know what this"
+ o.separator "does and you aren't explicitly trying to use it, you probably"
+ o.separator "don't want to use this."
+ o.separator ""
+ o.separator "This command checks or executes arbitrary capabilities that"
+ o.separator "Vagrant has for hosts, guests, and providers."
+ o.separator ""
o.separator "Options:"
o.separator ""
From 9e371277a9138e40908e1347750412946d4a345c Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 10:38:18 -0400
Subject: [PATCH 097/484] core: IsEnvSet remove invert opt
---
lib/vagrant/action/builtin/is_env_set.rb | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/vagrant/action/builtin/is_env_set.rb b/lib/vagrant/action/builtin/is_env_set.rb
index d08ed9632..269a6479c 100644
--- a/lib/vagrant/action/builtin/is_env_set.rb
+++ b/lib/vagrant/action/builtin/is_env_set.rb
@@ -8,7 +8,6 @@ module Vagrant
@app = app
@logger = Log4r::Logger.new("vagrant::action::builtin::is_env_set")
@key = key
- @invert = !!opts[:invert]
end
def call(env)
From 0a52e0629859cd310b0773ab88de2e3f008c420b Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 10:40:46 -0400
Subject: [PATCH 098/484] commands/snapshot: use require relative
---
plugins/commands/snapshot/command/push_shared.rb | 1 +
plugins/commands/snapshot/command/root.rb | 12 ++++++------
plugins/commands/snapshot/plugin.rb | 2 +-
3 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/plugins/commands/snapshot/command/push_shared.rb b/plugins/commands/snapshot/command/push_shared.rb
index bbaba8dbc..a82779ee5 100644
--- a/plugins/commands/snapshot/command/push_shared.rb
+++ b/plugins/commands/snapshot/command/push_shared.rb
@@ -16,6 +16,7 @@ module VagrantPlugins
end
end
+ # Success, exit with 0
0
end
diff --git a/plugins/commands/snapshot/command/root.rb b/plugins/commands/snapshot/command/root.rb
index 2ed460fa4..4ced72277 100644
--- a/plugins/commands/snapshot/command/root.rb
+++ b/plugins/commands/snapshot/command/root.rb
@@ -15,32 +15,32 @@ module VagrantPlugins
@subcommands = Vagrant::Registry.new
@subcommands.register(:save) do
- require File.expand_path("../save", __FILE__)
+ require_relative "save"
Save
end
@subcommands.register(:restore) do
- require File.expand_path("../restore", __FILE__)
+ require_relative "restore"
Restore
end
@subcommands.register(:delete) do
- require File.expand_path("../delete", __FILE__)
+ require_relative "delete"
Delete
end
@subcommands.register(:list) do
- require File.expand_path("../list", __FILE__)
+ require_relative "list"
List
end
@subcommands.register(:push) do
- require File.expand_path("../push", __FILE__)
+ require_relative "push"
Push
end
@subcommands.register(:pop) do
- require File.expand_path("../pop", __FILE__)
+ require_relative "pop"
Pop
end
end
diff --git a/plugins/commands/snapshot/plugin.rb b/plugins/commands/snapshot/plugin.rb
index e83be5bca..5b2af81df 100644
--- a/plugins/commands/snapshot/plugin.rb
+++ b/plugins/commands/snapshot/plugin.rb
@@ -7,7 +7,7 @@ module VagrantPlugins
description "The `snapshot` command gives you a way to manage snapshots."
command("snapshot") do
- require File.expand_path("../command/root", __FILE__)
+ require_relative "command/root"
Command::Root
end
end
From 50638b2e55a2323fed9cb487b90c1a5819e95c9c Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 10:42:10 -0400
Subject: [PATCH 099/484] commands/cap: require_relative
---
plugins/commands/cap/plugin.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/commands/cap/plugin.rb b/plugins/commands/cap/plugin.rb
index dd8ffbb23..21199c9a9 100644
--- a/plugins/commands/cap/plugin.rb
+++ b/plugins/commands/cap/plugin.rb
@@ -9,7 +9,7 @@ module VagrantPlugins
DESC
command("cap", primary: false) do
- require File.expand_path("../command", __FILE__)
+ require_relative "command"
Command
end
end
From 6c55fef21d421b592e8be1acd61eaa25da2dda80 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 10:53:07 -0400
Subject: [PATCH 100/484] update CHANGELOG
---
CHANGELOG.md | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8840cc522..c794b3ce0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,10 +2,12 @@
FEATURES:
- - **IPv6 Private Networks**: Private networking now supports IPv6. This
- only works with VirtualBox and VMware at this point. [GH-6342]
- **Linked Clones**: VirtualBox and VMware providers now support
linked clones for very fast (millisecond) imports on up. [GH-4484]
+ - **Snapshots**: The `vagrant snapshot` command can be used to checkpoint
+ and restore point-in-time snapshots.
+ - **IPv6 Private Networks**: Private networking now supports IPv6. This
+ only works with VirtualBox and VMware at this point. [GH-6342]
IMPROVEMENTS:
From e45ba11e14c01090c4ad9e3e059fbcfe983b7487 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 11:14:32 -0400
Subject: [PATCH 101/484] up version for dev
---
version.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/version.txt b/version.txt
index 10c088013..31b38cacd 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.7.4
+1.8.0.dev
From 44d484e2e09bcb4ea6d266c78f09fd5ee0e74bf6 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 11:58:47 -0400
Subject: [PATCH 102/484] providers/virtualbox: ability to customize linked
clone snapshot
---
.../providers/virtualbox/action/create_clone.rb | 13 +++++++++++--
.../providers/virtualbox/action/import_master.rb | 14 ++++++++++----
plugins/providers/virtualbox/config.rb | 10 ++++++++++
3 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/plugins/providers/virtualbox/action/create_clone.rb b/plugins/providers/virtualbox/action/create_clone.rb
index 9cc8f7ed5..a76e23794 100644
--- a/plugins/providers/virtualbox/action/create_clone.rb
+++ b/plugins/providers/virtualbox/action/create_clone.rb
@@ -12,9 +12,18 @@ module VagrantPlugins
def call(env)
@logger.info("Creating linked clone from master '#{env[:master_id]}'")
- env[:ui].info I18n.t("vagrant.actions.vm.clone.creating", name: env[:machine].box.name)
+ # Get the snapshot to base the linked clone on. This defaults
+ # to "base" which is automatically setup with linked clones.
+ snapshot = "base"
+ if env[:machine].provider_config.linked_clone_snapshot
+ snapshot = env[:machine].provider_config.linked_clone_snapshot
+ end
+
+ # Do the actual clone
+ env[:ui].info I18n.t(
+ "vagrant.actions.vm.clone.creating", name: env[:machine].box.name)
env[:machine].id = env[:machine].provider.driver.clonevm(
- env[:master_id], env[:machine].box.name, "base") do |progress|
+ env[:master_id], env[:machine].box.name, snapshot) do |progress|
env[:ui].clear_line
env[:ui].report_progress(progress, 100, false)
end
diff --git a/plugins/providers/virtualbox/action/import_master.rb b/plugins/providers/virtualbox/action/import_master.rb
index 5b9ae7790..985a346ba 100644
--- a/plugins/providers/virtualbox/action/import_master.rb
+++ b/plugins/providers/virtualbox/action/import_master.rb
@@ -59,10 +59,16 @@ module VagrantPlugins
"Imported box #{env[:machine].box.name} as master vm " +
"with id #{env[:master_id]}")
- @logger.info("Creating base snapshot for master VM.")
- env[:machine].provider.driver.create_snapshot(env[:master_id], "base") do |progress|
- env[:ui].clear_line
- env[:ui].report_progress(progress, 100, false)
+ if !env[:machine].provider_config.linked_clone_snapshot
+ snapshots = env[:machine].provider.driver.list_snapshots(env[:master_id])
+ if !snapshots.include?("base")
+ @logger.info("Creating base snapshot for master VM.")
+ env[:machine].provider.driver.create_snapshot(
+ env[:master_id], "base") do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+ end
end
@logger.debug("Writing id of master VM '#{env[:master_id]}' to #{master_id_file}")
diff --git a/plugins/providers/virtualbox/config.rb b/plugins/providers/virtualbox/config.rb
index 12b882b01..d549606ec 100644
--- a/plugins/providers/virtualbox/config.rb
+++ b/plugins/providers/virtualbox/config.rb
@@ -38,6 +38,14 @@ module VagrantPlugins
# @return [Boolean]
attr_accessor :linked_clone
+ # The snapshot to base the linked clone from. If this isn't set
+ # a snapshot will be made with the name of "base" which will be used.
+ #
+ # If this is set, then the snapshot must already exist.
+ #
+ # @return [String]
+ attr_accessor :linked_clone_snapshot
+
# This should be set to the name of the machine in the VirtualBox
# GUI.
#
@@ -66,6 +74,7 @@ module VagrantPlugins
@network_adapters = {}
@gui = UNSET_VALUE
@linked_clone = UNSET_VALUE
+ @linked_clone_snapshot = UNSET_VALUE
# We require that network adapter 1 is a NAT device.
network_adapter(1, :nat)
@@ -145,6 +154,7 @@ module VagrantPlugins
# Do not create linked clone by default
@linked_clone = false if @linked_clone == UNSET_VALUE
+ @linked_clone_snapshot = nil if @linked_clone_snapshot == UNSET_VALUE
# The default name is just nothing, and we default it
@name = nil if @name == UNSET_VALUE
From 06f8595bc05646fec4534d010f05815037fa14ce Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 11:37:35 -0400
Subject: [PATCH 103/484] kernel/v2: clone option
---
plugins/kernel_v2/config/vm.rb | 7 +++++++
templates/locales/en.yml | 1 +
test/unit/plugins/kernel_v2/config/vm_test.rb | 6 ++++++
3 files changed, 14 insertions(+)
diff --git a/plugins/kernel_v2/config/vm.rb b/plugins/kernel_v2/config/vm.rb
index 2de1b343f..acd21f20d 100644
--- a/plugins/kernel_v2/config/vm.rb
+++ b/plugins/kernel_v2/config/vm.rb
@@ -29,6 +29,7 @@ module VagrantPlugins
attr_accessor :box_download_client_cert
attr_accessor :box_download_insecure
attr_accessor :box_download_location_trusted
+ attr_accessor :clone
attr_accessor :communicator
attr_accessor :graceful_halt_timeout
attr_accessor :guest
@@ -54,6 +55,7 @@ module VagrantPlugins
@box_download_location_trusted = UNSET_VALUE
@box_url = UNSET_VALUE
@box_version = UNSET_VALUE
+ @clone = UNSET_VALUE
@communicator = UNSET_VALUE
@graceful_halt_timeout = UNSET_VALUE
@guest = UNSET_VALUE
@@ -367,6 +369,7 @@ module VagrantPlugins
@box_download_location_trusted = false if @box_download_location_trusted == UNSET_VALUE
@box_url = nil if @box_url == UNSET_VALUE
@box_version = nil if @box_version == UNSET_VALUE
+ @clone = nil if @clone == UNSET_VALUE
@communicator = nil if @communicator == UNSET_VALUE
@graceful_halt_timeout = 60 if @graceful_halt_timeout == UNSET_VALUE
@guest = nil if @guest == UNSET_VALUE
@@ -558,6 +561,10 @@ module VagrantPlugins
errors << I18n.t("vagrant.config.vm.box_missing")
end
+ if box && clone
+ errors << I18n.t("vagrant.config.vm.clone_and_box")
+ end
+
errors << I18n.t("vagrant.config.vm.hostname_invalid_characters") if \
@hostname && @hostname !~ /^[a-z0-9][-.a-z0-9]*$/i
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 929962453..ff2f1fac1 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1404,6 +1404,7 @@ en:
box_download_checksum_notblank: |-
Checksum specified but must also specify "box_download_checksum_type"
box_missing: "A box must be specified."
+ clone_and_box: "Only one of clone or box can be specified."
hostname_invalid_characters: |-
The hostname set for the VM should only contain letters, numbers,
hyphens or dots. It cannot start with a hyphen or dot.
diff --git a/test/unit/plugins/kernel_v2/config/vm_test.rb b/test/unit/plugins/kernel_v2/config/vm_test.rb
index 3d9b01213..146b3f344 100644
--- a/test/unit/plugins/kernel_v2/config/vm_test.rb
+++ b/test/unit/plugins/kernel_v2/config/vm_test.rb
@@ -65,6 +65,12 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
subject.finalize!
assert_valid
end
+
+ it "is invalid if clone is set" do
+ subject.clone = "foo"
+ subject.finalize!
+ assert_invalid
+ end
end
context "#box_check_update" do
From 20310dce0ca82872d72d8f33540ae35aca1e3054 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 11:50:06 -0400
Subject: [PATCH 104/484] noop
---
plugins/kernel_v2/config/vm.rb | 4 +++-
plugins/providers/virtualbox/action.rb | 1 +
plugins/providers/virtualbox/action/create_clone.rb | 2 --
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/plugins/kernel_v2/config/vm.rb b/plugins/kernel_v2/config/vm.rb
index acd21f20d..3d87e2b87 100644
--- a/plugins/kernel_v2/config/vm.rb
+++ b/plugins/kernel_v2/config/vm.rb
@@ -29,7 +29,6 @@ module VagrantPlugins
attr_accessor :box_download_client_cert
attr_accessor :box_download_insecure
attr_accessor :box_download_location_trusted
- attr_accessor :clone
attr_accessor :communicator
attr_accessor :graceful_halt_timeout
attr_accessor :guest
@@ -38,6 +37,9 @@ module VagrantPlugins
attr_accessor :usable_port_range
attr_reader :provisioners
+ # This is an experimental feature that isn't public yet.
+ attr_accessor :clone
+
def initialize
@logger = Log4r::Logger.new("vagrant::config::vm")
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 9c4d68c72..a64782973 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -394,6 +394,7 @@ module VagrantPlugins
b2.use MatchMACAddress
end
end
+
b.use action_start
end
end
diff --git a/plugins/providers/virtualbox/action/create_clone.rb b/plugins/providers/virtualbox/action/create_clone.rb
index a76e23794..eae9eda5e 100644
--- a/plugins/providers/virtualbox/action/create_clone.rb
+++ b/plugins/providers/virtualbox/action/create_clone.rb
@@ -10,8 +10,6 @@ module VagrantPlugins
end
def call(env)
- @logger.info("Creating linked clone from master '#{env[:master_id]}'")
-
# Get the snapshot to base the linked clone on. This defaults
# to "base" which is automatically setup with linked clones.
snapshot = "base"
From 9f05d22eb063d3bedf0648a0447eaa690be63c34 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 12:03:58 -0400
Subject: [PATCH 105/484] providers/virtualbox: cloning can do a non-linked
clone
---
.../providers/virtualbox/action/create_clone.rb | 14 ++++++++------
plugins/providers/virtualbox/driver/version_4_3.rb | 14 ++++++++------
plugins/providers/virtualbox/driver/version_5_0.rb | 14 ++++++++------
templates/locales/en.yml | 2 +-
4 files changed, 25 insertions(+), 19 deletions(-)
diff --git a/plugins/providers/virtualbox/action/create_clone.rb b/plugins/providers/virtualbox/action/create_clone.rb
index eae9eda5e..ac3ca519e 100644
--- a/plugins/providers/virtualbox/action/create_clone.rb
+++ b/plugins/providers/virtualbox/action/create_clone.rb
@@ -12,16 +12,18 @@ module VagrantPlugins
def call(env)
# Get the snapshot to base the linked clone on. This defaults
# to "base" which is automatically setup with linked clones.
- snapshot = "base"
- if env[:machine].provider_config.linked_clone_snapshot
- snapshot = env[:machine].provider_config.linked_clone_snapshot
+ snapshot = nil
+ if env[:machine].provider_config.linked_clone
+ snapshot = "base"
+ if env[:machine].provider_config.linked_clone_snapshot
+ snapshot = env[:machine].provider_config.linked_clone_snapshot
+ end
end
# Do the actual clone
- env[:ui].info I18n.t(
- "vagrant.actions.vm.clone.creating", name: env[:machine].box.name)
+ env[:ui].info I18n.t("vagrant.actions.vm.clone.creating")
env[:machine].id = env[:machine].provider.driver.clonevm(
- env[:master_id], env[:machine].box.name, snapshot) do |progress|
+ env[:master_id], snapshot) do |progress|
env[:ui].clear_line
env[:ui].report_progress(progress, 100, false)
end
diff --git a/plugins/providers/virtualbox/driver/version_4_3.rb b/plugins/providers/virtualbox/driver/version_4_3.rb
index b51eec37a..f895739d3 100644
--- a/plugins/providers/virtualbox/driver/version_4_3.rb
+++ b/plugins/providers/virtualbox/driver/version_4_3.rb
@@ -35,13 +35,15 @@ module VagrantPlugins
end
end
- def clonevm(master_id, box_name, snapshot_name)
- @logger.debug("Creating linked clone from master vm with id #{master_id} from snapshot '#{snapshot_name}'")
+ def clonevm(master_id, snapshot_name)
+ machine_name = "temp_clone_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
+ args = ["--register", "--name", machine_name]
+ if snapshot_name
+ args += ["--snapshot", snapshot_name, "--options", "link"]
+ end
- machine_name = "#{box_name}_#{snapshot_name}_clone_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
- execute("clonevm", master_id, "--snapshot", snapshot_name, "--options", "link", "--register", "--name", machine_name)
-
- return get_machine_id machine_name
+ execute("clonevm", master_id, *args)
+ return get_machine_id(machine_name)
end
def create_dhcp_server(network, options)
diff --git a/plugins/providers/virtualbox/driver/version_5_0.rb b/plugins/providers/virtualbox/driver/version_5_0.rb
index 9762eda42..d13330c00 100644
--- a/plugins/providers/virtualbox/driver/version_5_0.rb
+++ b/plugins/providers/virtualbox/driver/version_5_0.rb
@@ -34,13 +34,15 @@ module VagrantPlugins
end
end
- def clonevm(master_id, box_name, snapshot_name)
- @logger.debug("Creating linked clone from master vm with id #{master_id} from snapshot '#{snapshot_name}'")
+ def clonevm(master_id, snapshot_name)
+ machine_name = "temp_clone_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
+ args = ["--register", "--name", machine_name]
+ if snapshot_name
+ args += ["--snapshot", snapshot_name, "--options", "link"]
+ end
- machine_name = "#{box_name}_#{snapshot_name}_clone_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
- execute("clonevm", master_id, "--snapshot", snapshot_name, "--options", "link", "--register", "--name", machine_name)
-
- return get_machine_id machine_name
+ execute("clonevm", master_id, *args)
+ return get_machine_id(machine_name)
end
def create_dhcp_server(network, options)
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index ff2f1fac1..d5fa23d2c 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1636,7 +1636,7 @@ en:
This is a one time operation. Once the master VM is prepared,
it will be used as a base for linked clones, making the creation
of new VMs take milliseconds on a modern system.
- creating: Creating linked clone...
+ creating: Cloning VM...
failure: Creation of the linked clone failed.
create_master:
failure: |-
From c5c3ba616bc8b8ef51d04286e3a760ab10ef5fac Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 12:09:46 -0400
Subject: [PATCH 106/484] providers/virtualbox: some progress
---
plugins/providers/virtualbox/action.rb | 9 +++++++-
.../virtualbox/action/prepare_clone.rb | 21 +++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
create mode 100644 plugins/providers/virtualbox/action/prepare_clone.rb
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index a64782973..186f8debd 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -35,6 +35,7 @@ module VagrantPlugins
autoload :NetworkFixIPv6, File.expand_path("../action/network_fix_ipv6", __FILE__)
autoload :Package, File.expand_path("../action/package", __FILE__)
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
+ autoload :PrepareClone, File.expand_path("../action/prepare_clone", __FILE__)
autoload :PrepareNFSSettings, File.expand_path("../action/prepare_nfs_settings", __FILE__)
autoload :PrepareNFSValidIds, File.expand_path("../action/prepare_nfs_valid_ids", __FILE__)
autoload :PrepareForwardedPortCollisionParams, File.expand_path("../action/prepare_forwarded_port_collision_params", __FILE__)
@@ -384,10 +385,16 @@ module VagrantPlugins
b2.use CheckAccessible
b2.use Customize, "pre-import"
- if env[:machine].provider_config.linked_clone
+ if env[:machine].config.vm.clone
+ # We are cloning from another Vagrant environment
+ b2.use PrepareClone
+ b2.use CreateClone
+ elsif env[:machine].provider_config.linked_clone
+ # We are cloning from the box
b2.use ImportMaster
b2.use CreateClone
else
+ # We are just doing a normal import from a box
b2.use Import
end
diff --git a/plugins/providers/virtualbox/action/prepare_clone.rb b/plugins/providers/virtualbox/action/prepare_clone.rb
new file mode 100644
index 000000000..e3451cfef
--- /dev/null
+++ b/plugins/providers/virtualbox/action/prepare_clone.rb
@@ -0,0 +1,21 @@
+require "log4r"
+
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ class PrepareClone
+ def initialize(app, env)
+ @app = app
+ @logger = Log4r::Logger.new("vagrant::action::vm::prepare_clone")
+ end
+
+ def call(env)
+ # We need to get the machine ID from this Vagrant environment
+
+ # Continue
+ @app.call(env)
+ end
+ end
+ end
+ end
+end
From f0ddac8c9a2a6c89b44fbc8cdd931a5fad3ac89c Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 12:33:55 -0400
Subject: [PATCH 107/484] providers/virtualbox: clone
---
lib/vagrant/environment.rb | 22 +++++++
lib/vagrant/errors.rb | 12 +++-
plugins/providers/virtualbox/action.rb | 3 +
.../virtualbox/action/create_clone.rb | 12 +---
.../virtualbox/action/import_master.rb | 26 ++------
.../virtualbox/action/prepare_clone.rb | 11 ++++
.../action/prepare_clone_snapshot.rb | 65 +++++++++++++++++++
templates/locales/en.yml | 11 ++++
8 files changed, 130 insertions(+), 32 deletions(-)
create mode 100644 plugins/providers/virtualbox/action/prepare_clone_snapshot.rb
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index c3dabd676..0981d9df6 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -9,6 +9,7 @@ require 'log4r'
require 'vagrant/util/file_mode'
require 'vagrant/util/platform'
+require "vagrant/util/silence_warnings"
require "vagrant/vagrantfile"
require "vagrant/version"
@@ -413,6 +414,27 @@ module Vagrant
@config_loader
end
+ # Loads another environment for the given Vagrantfile, sharing as much
+ # useful state from this Environment as possible (such as UI and paths).
+ # Any initialization options can be overidden using the opts hash.
+ #
+ # @param [String] vagrantfile Path to a Vagrantfile
+ # @return [Environment]
+ def environment(vagrantfile, **opts)
+ path = File.expand_path(vagrantfile, root_path)
+ file = File.basename(path)
+ path = File.dirname(path)
+
+ Util::SilenceWarnings.silence! do
+ Environment.new({
+ cwd: path,
+ home_path: home_path,
+ ui_class: ui_class,
+ vagrantfile_name: file,
+ }.merge(opts))
+ end
+ end
+
# This defines a hook point where plugin action hooks that are registered
# against the given name will be run in the context of this environment.
#
diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb
index 2ce133618..906b8d9bc 100644
--- a/lib/vagrant/errors.rb
+++ b/lib/vagrant/errors.rb
@@ -288,6 +288,14 @@ module Vagrant
error_key(:cli_invalid_options)
end
+ class CloneNotFound < VagrantError
+ error_key(:clone_not_found)
+ end
+
+ class CloneMachineNotFound < VagrantError
+ error_key(:clone_machine_not_found)
+ end
+
class CommandUnavailable < VagrantError
error_key(:command_unavailable)
end
@@ -787,11 +795,11 @@ module Vagrant
class VMCloneFailure < VagrantError
error_key(:failure, "vagrant.actions.vm.clone")
end
-
+
class VMCreateMasterFailure < VagrantError
error_key(:failure, "vagrant.actions.vm.clone.create_master")
end
-
+
class VMCustomizationFailed < VagrantError
error_key(:failure, "vagrant.actions.vm.customize")
end
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 186f8debd..9a67f0b37 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -36,6 +36,7 @@ module VagrantPlugins
autoload :Package, File.expand_path("../action/package", __FILE__)
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
autoload :PrepareClone, File.expand_path("../action/prepare_clone", __FILE__)
+ autoload :PrepareCloneSnapshot, File.expand_path("../action/prepare_clone_snapshot", __FILE__)
autoload :PrepareNFSSettings, File.expand_path("../action/prepare_nfs_settings", __FILE__)
autoload :PrepareNFSValidIds, File.expand_path("../action/prepare_nfs_valid_ids", __FILE__)
autoload :PrepareForwardedPortCollisionParams, File.expand_path("../action/prepare_forwarded_port_collision_params", __FILE__)
@@ -388,10 +389,12 @@ module VagrantPlugins
if env[:machine].config.vm.clone
# We are cloning from another Vagrant environment
b2.use PrepareClone
+ b2.use PrepareCloneSnapshot
b2.use CreateClone
elsif env[:machine].provider_config.linked_clone
# We are cloning from the box
b2.use ImportMaster
+ b2.use PrepareCloneSnapshot
b2.use CreateClone
else
# We are just doing a normal import from a box
diff --git a/plugins/providers/virtualbox/action/create_clone.rb b/plugins/providers/virtualbox/action/create_clone.rb
index ac3ca519e..526b5a5c1 100644
--- a/plugins/providers/virtualbox/action/create_clone.rb
+++ b/plugins/providers/virtualbox/action/create_clone.rb
@@ -10,20 +10,10 @@ module VagrantPlugins
end
def call(env)
- # Get the snapshot to base the linked clone on. This defaults
- # to "base" which is automatically setup with linked clones.
- snapshot = nil
- if env[:machine].provider_config.linked_clone
- snapshot = "base"
- if env[:machine].provider_config.linked_clone_snapshot
- snapshot = env[:machine].provider_config.linked_clone_snapshot
- end
- end
-
# Do the actual clone
env[:ui].info I18n.t("vagrant.actions.vm.clone.creating")
env[:machine].id = env[:machine].provider.driver.clonevm(
- env[:master_id], snapshot) do |progress|
+ env[:clone_id], env[:clone_snapshot]) do |progress|
env[:ui].clear_line
env[:ui].report_progress(progress, 100, false)
end
diff --git a/plugins/providers/virtualbox/action/import_master.rb b/plugins/providers/virtualbox/action/import_master.rb
index 985a346ba..17296bbcc 100644
--- a/plugins/providers/virtualbox/action/import_master.rb
+++ b/plugins/providers/virtualbox/action/import_master.rb
@@ -37,14 +37,14 @@ module VagrantPlugins
master_id_file = env[:machine].box.directory.join("master_id")
# Read the master ID if we have it in the file.
- env[:master_id] = master_id_file.read.chomp if master_id_file.file?
+ env[:clone_id] = master_id_file.read.chomp if master_id_file.file?
# If we have the ID and the VM exists already, then we
# have nothing to do. Success!
- if env[:master_id] && env[:machine].provider.driver.vm_exists?(env[:master_id])
+ if env[:clone_id] && env[:machine].provider.driver.vm_exists?(env[:clone_id])
@logger.info(
"Master VM for '#{env[:machine].box.name}' already exists " +
- " (id=#{env[:master_id]}) - skipping import step.")
+ " (id=#{env[:clone_id]}) - skipping import step.")
return
end
@@ -53,27 +53,15 @@ module VagrantPlugins
# Import the virtual machine
import_env = env[:action_runner].run(Import, env.dup.merge(skip_machine: true))
- env[:master_id] = import_env[:machine_id]
+ env[:clone_id] = import_env[:machine_id]
@logger.info(
"Imported box #{env[:machine].box.name} as master vm " +
- "with id #{env[:master_id]}")
+ "with id #{env[:clone_id]}")
- if !env[:machine].provider_config.linked_clone_snapshot
- snapshots = env[:machine].provider.driver.list_snapshots(env[:master_id])
- if !snapshots.include?("base")
- @logger.info("Creating base snapshot for master VM.")
- env[:machine].provider.driver.create_snapshot(
- env[:master_id], "base") do |progress|
- env[:ui].clear_line
- env[:ui].report_progress(progress, 100, false)
- end
- end
- end
-
- @logger.debug("Writing id of master VM '#{env[:master_id]}' to #{master_id_file}")
+ @logger.debug("Writing id of master VM '#{env[:clone_id]}' to #{master_id_file}")
master_id_file.open("w+") do |f|
- f.write(env[:master_id])
+ f.write(env[:clone_id])
end
end
end
diff --git a/plugins/providers/virtualbox/action/prepare_clone.rb b/plugins/providers/virtualbox/action/prepare_clone.rb
index e3451cfef..6b3bf34dd 100644
--- a/plugins/providers/virtualbox/action/prepare_clone.rb
+++ b/plugins/providers/virtualbox/action/prepare_clone.rb
@@ -11,6 +11,17 @@ module VagrantPlugins
def call(env)
# We need to get the machine ID from this Vagrant environment
+ clone_env = env[:machine].env.environment(
+ env[:machine].config.vm.clone)
+ raise Vagrant::Errors::CloneNotFound if !clone_env.root_path
+
+ # Get the machine itself
+ clone_machine = clone_env.machine(
+ clone_env.primary_machine_name, env[:machine].provider_name)
+ raise Vagrant::Errors::CloneMachineNotFound if !clone_machine.id
+
+ # Set the ID of the master so we know what to clone from
+ env[:clone_id] = clone_machine.id
# Continue
@app.call(env)
diff --git a/plugins/providers/virtualbox/action/prepare_clone_snapshot.rb b/plugins/providers/virtualbox/action/prepare_clone_snapshot.rb
new file mode 100644
index 000000000..08ce16a6d
--- /dev/null
+++ b/plugins/providers/virtualbox/action/prepare_clone_snapshot.rb
@@ -0,0 +1,65 @@
+require "log4r"
+
+require "digest/md5"
+
+module VagrantPlugins
+ module ProviderVirtualBox
+ module Action
+ class PrepareCloneSnapshot
+ def initialize(app, env)
+ @app = app
+ @logger = Log4r::Logger.new("vagrant::action::vm::prepare_clone")
+ end
+
+ def call(env)
+ if !env[:clone_id]
+ @logger.info("no clone master, not preparing clone snapshot")
+ return @app.call(env)
+ end
+
+ # If we're not doing a linked clone, snapshots don't matter
+ if !env[:machine].provider_config.linked_clone
+ return @app.call(env)
+ end
+
+ # We lock so that we don't snapshot in parallel
+ lock_key = Digest::MD5.hexdigest("#{env[:clone_id]}-snapshot")
+ env[:machine].env.lock(lock_key, retry: true) do
+ prepare_snapshot(env)
+ end
+
+ # Continue
+ @app.call(env)
+ end
+
+ protected
+
+ def prepare_snapshot(env)
+ name = env[:machine].provider_config.linked_clone_snapshot
+ name_set = !!name
+ name = "base" if !name
+ env[:clone_snapshot] = name
+
+ # Get the snapshots. We're done if it already exists
+ snapshots = env[:machine].provider.driver.list_snapshots(env[:clone_id])
+ if snapshots.include?(name)
+ @logger.info("clone snapshot already exists, doing nothing")
+ return
+ end
+
+ # If they asked for a specific snapshot, it is an error
+ if name_set
+ # TODO: Error
+ end
+
+ @logger.info("Creating base snapshot for master VM.")
+ env[:machine].provider.driver.create_snapshot(
+ env[:clone_id], name) do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index d5fa23d2c..9e8c680aa 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -650,6 +650,17 @@ en:
available below.
%{help}
+ clone_not_found: |-
+ The specified Vagrantfile to clone from was not found. Please verify
+ the `config.vm.clone` setting points to a valid Vagrantfile.
+ clone_machine_not_found: |-
+ The clone environment hasn't been created yet. To clone from
+ another Vagrantfile, it must already be created with `vagrant up`.
+ It doesn't need to be running.
+
+ Additionally, the created environment must be started with a provider
+ matching this provider. For example, if you're using VirtualBox,
+ the clone environment must also be using VirtualBox.
command_unavailable: |-
The executable '%{file}' Vagrant is trying to run was not
found in the PATH variable. This is an error. Please verify
From dbcc936a713d2d7683dfbe2d691a758754fd8083 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 12:41:16 -0400
Subject: [PATCH 108/484] kernel/v2: box is optional if clone is set
---
plugins/kernel_v2/config/vm.rb | 2 +-
plugins/providers/virtualbox/action/match_mac_address.rb | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/plugins/kernel_v2/config/vm.rb b/plugins/kernel_v2/config/vm.rb
index 3d87e2b87..3020611f4 100644
--- a/plugins/kernel_v2/config/vm.rb
+++ b/plugins/kernel_v2/config/vm.rb
@@ -559,7 +559,7 @@ module VagrantPlugins
def validate(machine)
errors = _detected_errors
- if !box && !machine.provider_options[:box_optional]
+ if !box && !clone && !machine.provider_options[:box_optional]
errors << I18n.t("vagrant.config.vm.box_missing")
end
diff --git a/plugins/providers/virtualbox/action/match_mac_address.rb b/plugins/providers/virtualbox/action/match_mac_address.rb
index a66f40bad..10e998b2e 100644
--- a/plugins/providers/virtualbox/action/match_mac_address.rb
+++ b/plugins/providers/virtualbox/action/match_mac_address.rb
@@ -7,6 +7,9 @@ module VagrantPlugins
end
def call(env)
+ # If we cloned, we don't need a base mac, it is already set!
+ return @app.call(env) if env[:machine].config.vm.clone
+
raise Vagrant::Errors::VMBaseMacNotSpecified if !env[:machine].config.vm.base_mac
# Create the proc which we want to use to modify the virtual machine
From e9922d17546fb9b0c5f72cf72e4bfc6e0c8ab092 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 12:50:02 -0400
Subject: [PATCH 109/484] providers/virtualbox: discard state if cloning
---
plugins/providers/virtualbox/action.rb | 2 ++
1 file changed, 2 insertions(+)
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index 9a67f0b37..e102625dc 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -391,11 +391,13 @@ module VagrantPlugins
b2.use PrepareClone
b2.use PrepareCloneSnapshot
b2.use CreateClone
+ b2.use DiscardState
elsif env[:machine].provider_config.linked_clone
# We are cloning from the box
b2.use ImportMaster
b2.use PrepareCloneSnapshot
b2.use CreateClone
+ b2.use DiscardState
else
# We are just doing a normal import from a box
b2.use Import
From 4908cd9cd956f1179b956787d3f4b7b043a7fe30 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 12:58:06 -0400
Subject: [PATCH 110/484] providers/virtualbox: copy SSH key
---
plugins/providers/virtualbox/action.rb | 6 +++---
.../action/{create_clone.rb => clone.rb} | 14 +++++++++++++-
.../providers/virtualbox/action/prepare_clone.rb | 1 +
3 files changed, 17 insertions(+), 4 deletions(-)
rename plugins/providers/virtualbox/action/{create_clone.rb => clone.rb} (78%)
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index e102625dc..f7984dca4 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -12,7 +12,7 @@ module VagrantPlugins
autoload :CleanMachineFolder, File.expand_path("../action/clean_machine_folder", __FILE__)
autoload :ClearForwardedPorts, File.expand_path("../action/clear_forwarded_ports", __FILE__)
autoload :ClearNetworkInterfaces, File.expand_path("../action/clear_network_interfaces", __FILE__)
- autoload :CreateClone, File.expand_path("../action/create_clone", __FILE__)
+ autoload :Clone, File.expand_path("../action/clone", __FILE__)
autoload :Created, File.expand_path("../action/created", __FILE__)
autoload :Customize, File.expand_path("../action/customize", __FILE__)
autoload :Destroy, File.expand_path("../action/destroy", __FILE__)
@@ -390,13 +390,13 @@ module VagrantPlugins
# We are cloning from another Vagrant environment
b2.use PrepareClone
b2.use PrepareCloneSnapshot
- b2.use CreateClone
+ b2.use Clone
b2.use DiscardState
elsif env[:machine].provider_config.linked_clone
# We are cloning from the box
b2.use ImportMaster
b2.use PrepareCloneSnapshot
- b2.use CreateClone
+ b2.use Clone
b2.use DiscardState
else
# We are just doing a normal import from a box
diff --git a/plugins/providers/virtualbox/action/create_clone.rb b/plugins/providers/virtualbox/action/clone.rb
similarity index 78%
rename from plugins/providers/virtualbox/action/create_clone.rb
rename to plugins/providers/virtualbox/action/clone.rb
index 526b5a5c1..6b389d4f1 100644
--- a/plugins/providers/virtualbox/action/create_clone.rb
+++ b/plugins/providers/virtualbox/action/clone.rb
@@ -1,9 +1,11 @@
require "log4r"
+require "fileutils"
+
module VagrantPlugins
module ProviderVirtualBox
module Action
- class CreateClone
+ class Clone
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::action::vm::clone")
@@ -25,6 +27,16 @@ module VagrantPlugins
# Flag as erroneous and return if clone failed
raise Vagrant::Errors::VMCloneFailure if !env[:machine].id
+ # Copy the SSH key from the clone machine if we can
+ if env[:clone_machine]
+ key_path = env[:clone_machine].data_dir.join("private_key")
+ if key_path.file?
+ FileUtils.cp(
+ key_path,
+ env[:machine].data_dir.join("private_key"))
+ end
+ end
+
# Continue
@app.call(env)
end
diff --git a/plugins/providers/virtualbox/action/prepare_clone.rb b/plugins/providers/virtualbox/action/prepare_clone.rb
index 6b3bf34dd..c306b9b54 100644
--- a/plugins/providers/virtualbox/action/prepare_clone.rb
+++ b/plugins/providers/virtualbox/action/prepare_clone.rb
@@ -22,6 +22,7 @@ module VagrantPlugins
# Set the ID of the master so we know what to clone from
env[:clone_id] = clone_machine.id
+ env[:clone_machine] = clone_machine
# Continue
@app.call(env)
From 5ea24e39d021875c2d6cc3830236364f42f78f9f Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 13:07:05 -0400
Subject: [PATCH 111/484] providers/virtualbox: unify import/clone
---
plugins/providers/virtualbox/action.rb | 13 +---
plugins/providers/virtualbox/action/clone.rb | 63 -------------------
plugins/providers/virtualbox/action/import.rb | 38 +++++++++++
3 files changed, 41 insertions(+), 73 deletions(-)
delete mode 100644 plugins/providers/virtualbox/action/clone.rb
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index f7984dca4..d0ef01bff 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -12,7 +12,6 @@ module VagrantPlugins
autoload :CleanMachineFolder, File.expand_path("../action/clean_machine_folder", __FILE__)
autoload :ClearForwardedPorts, File.expand_path("../action/clear_forwarded_ports", __FILE__)
autoload :ClearNetworkInterfaces, File.expand_path("../action/clear_network_interfaces", __FILE__)
- autoload :Clone, File.expand_path("../action/clone", __FILE__)
autoload :Created, File.expand_path("../action/created", __FILE__)
autoload :Customize, File.expand_path("../action/customize", __FILE__)
autoload :Destroy, File.expand_path("../action/destroy", __FILE__)
@@ -389,20 +388,14 @@ module VagrantPlugins
if env[:machine].config.vm.clone
# We are cloning from another Vagrant environment
b2.use PrepareClone
- b2.use PrepareCloneSnapshot
- b2.use Clone
- b2.use DiscardState
elsif env[:machine].provider_config.linked_clone
# We are cloning from the box
b2.use ImportMaster
- b2.use PrepareCloneSnapshot
- b2.use Clone
- b2.use DiscardState
- else
- # We are just doing a normal import from a box
- b2.use Import
end
+ b2.use PrepareCloneSnapshot
+ b2.use Import
+ b2.use DiscardState
b2.use MatchMACAddress
end
end
diff --git a/plugins/providers/virtualbox/action/clone.rb b/plugins/providers/virtualbox/action/clone.rb
deleted file mode 100644
index 6b389d4f1..000000000
--- a/plugins/providers/virtualbox/action/clone.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require "log4r"
-
-require "fileutils"
-
-module VagrantPlugins
- module ProviderVirtualBox
- module Action
- class Clone
- def initialize(app, env)
- @app = app
- @logger = Log4r::Logger.new("vagrant::action::vm::clone")
- end
-
- def call(env)
- # Do the actual clone
- env[:ui].info I18n.t("vagrant.actions.vm.clone.creating")
- env[:machine].id = env[:machine].provider.driver.clonevm(
- env[:clone_id], env[:clone_snapshot]) do |progress|
- env[:ui].clear_line
- env[:ui].report_progress(progress, 100, false)
- end
-
- # Clear the line one last time since the progress meter doesn't
- # disappear immediately.
- env[:ui].clear_line
-
- # Flag as erroneous and return if clone failed
- raise Vagrant::Errors::VMCloneFailure if !env[:machine].id
-
- # Copy the SSH key from the clone machine if we can
- if env[:clone_machine]
- key_path = env[:clone_machine].data_dir.join("private_key")
- if key_path.file?
- FileUtils.cp(
- key_path,
- env[:machine].data_dir.join("private_key"))
- end
- end
-
- # Continue
- @app.call(env)
- end
-
- def recover(env)
- if env[:machine].state.id != :not_created
- return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
-
- # If we're not supposed to destroy on error then just return
- return if !env[:destroy_on_error]
-
- # Interrupted, destroy the VM. We note that we don't want to
- # validate the configuration here, and we don't want to confirm
- # we want to destroy.
- destroy_env = env.clone
- destroy_env[:config_validate] = false
- destroy_env[:force_confirm_destroy] = true
- env[:action_runner].run(Action.action_destroy, destroy_env)
- end
- end
- end
- end
- end
-end
diff --git a/plugins/providers/virtualbox/action/import.rb b/plugins/providers/virtualbox/action/import.rb
index 92e004f01..fb540f50a 100644
--- a/plugins/providers/virtualbox/action/import.rb
+++ b/plugins/providers/virtualbox/action/import.rb
@@ -7,6 +7,44 @@ module VagrantPlugins
end
def call(env)
+ if env[:clone_id]
+ clone(env)
+ else
+ import(env)
+ end
+ end
+
+ def clone(env)
+ # Do the actual clone
+ env[:ui].info I18n.t("vagrant.actions.vm.clone.creating")
+ env[:machine].id = env[:machine].provider.driver.clonevm(
+ env[:clone_id], env[:clone_snapshot]) do |progress|
+ env[:ui].clear_line
+ env[:ui].report_progress(progress, 100, false)
+ end
+
+ # Clear the line one last time since the progress meter doesn't
+ # disappear immediately.
+ env[:ui].clear_line
+
+ # Flag as erroneous and return if clone failed
+ raise Vagrant::Errors::VMCloneFailure if !env[:machine].id
+
+ # Copy the SSH key from the clone machine if we can
+ if env[:clone_machine]
+ key_path = env[:clone_machine].data_dir.join("private_key")
+ if key_path.file?
+ FileUtils.cp(
+ key_path,
+ env[:machine].data_dir.join("private_key"))
+ end
+ end
+
+ # Continue
+ @app.call(env)
+ end
+
+ def import(env)
env[:ui].info I18n.t("vagrant.actions.vm.import.importing",
name: env[:machine].box.name)
From 681b50060e01ee05457b5c64e3225c3dea2d1263 Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 8 Oct 2015 13:52:21 -0400
Subject: [PATCH 112/484] Add shopt globs to include hidden files
---
scripts/website_push_docs.sh | 4 +++-
scripts/website_push_www.sh | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/scripts/website_push_docs.sh b/scripts/website_push_docs.sh
index 0f7674252..99ee08705 100755
--- a/scripts/website_push_docs.sh
+++ b/scripts/website_push_docs.sh
@@ -16,7 +16,8 @@ while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"
# Copy into tmpdir
-cp -R $DIR/website/docs/ $DEPLOY/
+shopt -s dotglob
+cp -R $DIR/website/docs/* $DEPLOY/
# Change into that directory
cd $DEPLOY
@@ -25,6 +26,7 @@ cd $DEPLOY
touch .gitignore
echo ".sass-cache" >> .gitignore
echo "build" >> .gitignore
+echo "vendor" >> .gitignore
# Add everything
git init .
diff --git a/scripts/website_push_www.sh b/scripts/website_push_www.sh
index ad74a7b63..f7f2c6ce4 100755
--- a/scripts/website_push_www.sh
+++ b/scripts/website_push_www.sh
@@ -16,7 +16,8 @@ while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"
# Copy into tmpdir
-cp -R $DIR/website/www/ $DEPLOY/
+shopt -s dotglob
+cp -R $DIR/website/www/* $DEPLOY/
# Change into that directory
cd $DEPLOY
@@ -25,6 +26,7 @@ cd $DEPLOY
touch .gitignore
echo ".sass-cache" >> .gitignore
echo "build" >> .gitignore
+echo "vendor" >> .gitignore
# Add everything
git init .
From 70e9079449333fbb11dd0a5cb7026d1986cc505b Mon Sep 17 00:00:00 2001
From: Jurnell Cockhren
Date: Thu, 8 Oct 2015 14:00:38 -0500
Subject: [PATCH 113/484] Revert "Fix alignment of initializer"
Refers to issues #6276, #5973 and #5936
This reverts commit 27d751863673435693b775bf44e79b9f688a8968.
---
plugins/provisioners/salt/config.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/provisioners/salt/config.rb b/plugins/provisioners/salt/config.rb
index 9c564179e..084dc457c 100644
--- a/plugins/provisioners/salt/config.rb
+++ b/plugins/provisioners/salt/config.rb
@@ -95,7 +95,7 @@ module VagrantPlugins
@install_args = nil if @install_args == UNSET_VALUE
@install_master = nil if @install_master == UNSET_VALUE
@install_syndic = nil if @install_syndic == UNSET_VALUE
- @install_command = nil if @install_command == UNSET_VALUE
+ @install_command = nil if @install_command == UNSET_VALUE
@no_minion = nil if @no_minion == UNSET_VALUE
@bootstrap_options = nil if @bootstrap_options == UNSET_VALUE
@config_dir = nil if @config_dir == UNSET_VALUE
From fb611c7389ea068a9aed010fd7693ff7d9c87b25 Mon Sep 17 00:00:00 2001
From: Jurnell Cockhren
Date: Thu, 8 Oct 2015 14:04:44 -0500
Subject: [PATCH 114/484] Revert "Initialize the install_command salt config
var"
Refers to issues #6276, #5973 and #5936
This reverts commit ccd735466524e5cdea353714e06d9a3c88d17bdc.
---
plugins/provisioners/salt/config.rb | 3 ---
1 file changed, 3 deletions(-)
diff --git a/plugins/provisioners/salt/config.rb b/plugins/provisioners/salt/config.rb
index 084dc457c..4d9550406 100644
--- a/plugins/provisioners/salt/config.rb
+++ b/plugins/provisioners/salt/config.rb
@@ -33,7 +33,6 @@ module VagrantPlugins
attr_accessor :install_args
attr_accessor :install_master
attr_accessor :install_syndic
- attr_accessor :install_command
attr_accessor :no_minion
attr_accessor :bootstrap_options
attr_accessor :version
@@ -62,7 +61,6 @@ module VagrantPlugins
@install_args = UNSET_VALUE
@install_master = UNSET_VALUE
@install_syndic = UNSET_VALUE
- @install_command = UNSET_VALUE
@no_minion = UNSET_VALUE
@bootstrap_options = UNSET_VALUE
@config_dir = UNSET_VALUE
@@ -95,7 +93,6 @@ module VagrantPlugins
@install_args = nil if @install_args == UNSET_VALUE
@install_master = nil if @install_master == UNSET_VALUE
@install_syndic = nil if @install_syndic == UNSET_VALUE
- @install_command = nil if @install_command == UNSET_VALUE
@no_minion = nil if @no_minion == UNSET_VALUE
@bootstrap_options = nil if @bootstrap_options == UNSET_VALUE
@config_dir = nil if @config_dir == UNSET_VALUE
From 1a7c6dcfeb7db6e726c4918a0c271c7cfe8a99cb Mon Sep 17 00:00:00 2001
From: Jurnell Cockhren
Date: Thu, 8 Oct 2015 14:51:40 -0500
Subject: [PATCH 115/484] Revert "Salt Provisioner: refactor custom
install_type option to add install_command instead"
Refers to issues #6276, #5973, #5936 and #5435
This reverts commit 72e63767ac5807277dfe7f2202d3ab25804fe0df.
Conflicts:
website/docs/source/v2/provisioning/salt.html.md
---
plugins/provisioners/salt/provisioner.rb | 13 +++++--------
website/docs/source/v2/provisioning/salt.html.md | 7 +------
2 files changed, 6 insertions(+), 14 deletions(-)
diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb
index 72365776e..fb021d418 100644
--- a/plugins/provisioners/salt/provisioner.rb
+++ b/plugins/provisioners/salt/provisioner.rb
@@ -136,20 +136,17 @@ module VagrantPlugins
end
if @config.install_type
- options = "%s %s" % [options, @config.install_type]
+ # Allow passing install_args as an arbitrary string rather
+ # than trying to format it based on known options
+ if @config.install_type != "custom"
+ options = "%s %s" % [options, @config.install_type]
+ end
end
if @config.install_args
options = "%s %s" % [options, @config.install_args]
end
- if @config.install_command
- # If this is defined, we will ignore both install_type and
- # install_args and use this instead. Every necessary command option
- # will need to be specified by the user.
- options = @config.install_command
- end
-
if @config.verbose
@machine.env.ui.info "Using Bootstrap Options: %s" % options
end
diff --git a/website/docs/source/v2/provisioning/salt.html.md b/website/docs/source/v2/provisioning/salt.html.md
index 938fec155..aab48b7bd 100644
--- a/website/docs/source/v2/provisioning/salt.html.md
+++ b/website/docs/source/v2/provisioning/salt.html.md
@@ -54,19 +54,14 @@ on this machine. Not supported on Windows guest machines.
* `install_syndic` (boolean) - Install the salt-syndic, default
`false`. Not supported on Windows guest machines.
-* `install_type` (stable | git | daily | testing) - Whether to install from a
+* `install_type` (stable | git | daily | testing | custom) - Whether to install from a
distribution's stable package manager, git tree-ish, daily ppa, or testing repository.
-Not supported on Windows guest machines.
* `install_args` (develop) - When performing a git install,
you can specify a branch, tag, or any treeish. If using the `custom` install type,
you can also specify a different repository to install from.
Not supported on Windows guest machines.
-* `install_command` (string) - Allow specifying an arbitrary string of arguments
-to the bootstrap script. This will completely ignore `install_type` and `install_args`
-to allow more flexibility with the bootstrap process.
-
* `always_install` (boolean) - Installs salt binaries even
if they are already detected, default `false`
From 86e56aeac334c4d1d1ce9e20d1935a05af81549a Mon Sep 17 00:00:00 2001
From: Jurnell Cockhren
Date: Thu, 8 Oct 2015 14:56:48 -0500
Subject: [PATCH 116/484] Revert "Salt Provisioner: Added a 'custom' option to
install_type to allow more flexibility in passing arguments to the bootstrap
script. Updated the docs."
This reverts commit 0289ab986c053f7d3bc825142c82a07bcf0ae3ec.
Refers to issues #6276, #5973, #5936 and #5435
Conflicts:
website/docs/source/v2/provisioning/salt.html.md
---
plugins/provisioners/salt/provisioner.rb | 6 +-----
website/docs/source/v2/provisioning/salt.html.md | 7 ++-----
2 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb
index fb021d418..f7b4406e9 100644
--- a/plugins/provisioners/salt/provisioner.rb
+++ b/plugins/provisioners/salt/provisioner.rb
@@ -136,11 +136,7 @@ module VagrantPlugins
end
if @config.install_type
- # Allow passing install_args as an arbitrary string rather
- # than trying to format it based on known options
- if @config.install_type != "custom"
- options = "%s %s" % [options, @config.install_type]
- end
+ options = "%s %s" % [options, @config.install_type]
end
if @config.install_args
diff --git a/website/docs/source/v2/provisioning/salt.html.md b/website/docs/source/v2/provisioning/salt.html.md
index aab48b7bd..d4d13bf61 100644
--- a/website/docs/source/v2/provisioning/salt.html.md
+++ b/website/docs/source/v2/provisioning/salt.html.md
@@ -54,13 +54,10 @@ on this machine. Not supported on Windows guest machines.
* `install_syndic` (boolean) - Install the salt-syndic, default
`false`. Not supported on Windows guest machines.
-* `install_type` (stable | git | daily | testing | custom) - Whether to install from a
+* `install_type` (stable | git | daily | testing) - Whether to install from a
distribution's stable package manager, git tree-ish, daily ppa, or testing repository.
-* `install_args` (develop) - When performing a git install,
-you can specify a branch, tag, or any treeish. If using the `custom` install type,
-you can also specify a different repository to install from.
-Not supported on Windows guest machines.
+* `install_args` (develop) - When performing a git install, you can specify a branch, tag, or any treeish. Not supported on Windows.
* `always_install` (boolean) - Installs salt binaries even
if they are already detected, default `false`
From 36cfc77167f0beb460e592908d6837e5f2b3d877 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Thu, 8 Oct 2015 16:02:37 -0400
Subject: [PATCH 117/484] providers/virtualbox: make prepare clone a core thing
---
lib/vagrant/action.rb | 1 +
.../vagrant/action/builtin}/prepare_clone.rb | 15 ++++++++++-----
plugins/providers/virtualbox/action.rb | 7 ++-----
3 files changed, 13 insertions(+), 10 deletions(-)
rename {plugins/providers/virtualbox/action => lib/vagrant/action/builtin}/prepare_clone.rb (70%)
diff --git a/lib/vagrant/action.rb b/lib/vagrant/action.rb
index db4875dbb..91b7959c1 100644
--- a/lib/vagrant/action.rb
+++ b/lib/vagrant/action.rb
@@ -24,6 +24,7 @@ module Vagrant
autoload :IsState, "vagrant/action/builtin/is_state"
autoload :Lock, "vagrant/action/builtin/lock"
autoload :Message, "vagrant/action/builtin/message"
+ autoload :PrepareClone, "vagrant/action/builtin/prepare_clone"
autoload :Provision, "vagrant/action/builtin/provision"
autoload :ProvisionerCleanup, "vagrant/action/builtin/provisioner_cleanup"
autoload :SetHostname, "vagrant/action/builtin/set_hostname"
diff --git a/plugins/providers/virtualbox/action/prepare_clone.rb b/lib/vagrant/action/builtin/prepare_clone.rb
similarity index 70%
rename from plugins/providers/virtualbox/action/prepare_clone.rb
rename to lib/vagrant/action/builtin/prepare_clone.rb
index c306b9b54..696d28bfb 100644
--- a/plugins/providers/virtualbox/action/prepare_clone.rb
+++ b/lib/vagrant/action/builtin/prepare_clone.rb
@@ -1,8 +1,8 @@
require "log4r"
-module VagrantPlugins
- module ProviderVirtualBox
- module Action
+module Vagrant
+ module Action
+ module Builtin
class PrepareClone
def initialize(app, env)
@app = app
@@ -10,15 +10,20 @@ module VagrantPlugins
end
def call(env)
+ # If we aren't cloning, then do nothing
+ if !env[:machine].config.vm.clone
+ return @app.call(env)
+ end
+
# We need to get the machine ID from this Vagrant environment
clone_env = env[:machine].env.environment(
env[:machine].config.vm.clone)
- raise Vagrant::Errors::CloneNotFound if !clone_env.root_path
+ raise Errors::CloneNotFound if !clone_env.root_path
# Get the machine itself
clone_machine = clone_env.machine(
clone_env.primary_machine_name, env[:machine].provider_name)
- raise Vagrant::Errors::CloneMachineNotFound if !clone_machine.id
+ raise Errors::CloneMachineNotFound if !clone_machine.id
# Set the ID of the master so we know what to clone from
env[:clone_id] = clone_machine.id
diff --git a/plugins/providers/virtualbox/action.rb b/plugins/providers/virtualbox/action.rb
index d0ef01bff..85f52f887 100644
--- a/plugins/providers/virtualbox/action.rb
+++ b/plugins/providers/virtualbox/action.rb
@@ -34,7 +34,6 @@ module VagrantPlugins
autoload :NetworkFixIPv6, File.expand_path("../action/network_fix_ipv6", __FILE__)
autoload :Package, File.expand_path("../action/package", __FILE__)
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
- autoload :PrepareClone, File.expand_path("../action/prepare_clone", __FILE__)
autoload :PrepareCloneSnapshot, File.expand_path("../action/prepare_clone_snapshot", __FILE__)
autoload :PrepareNFSSettings, File.expand_path("../action/prepare_nfs_settings", __FILE__)
autoload :PrepareNFSValidIds, File.expand_path("../action/prepare_nfs_valid_ids", __FILE__)
@@ -385,14 +384,12 @@ module VagrantPlugins
b2.use CheckAccessible
b2.use Customize, "pre-import"
- if env[:machine].config.vm.clone
- # We are cloning from another Vagrant environment
- b2.use PrepareClone
- elsif env[:machine].provider_config.linked_clone
+ if env[:machine].provider_config.linked_clone
# We are cloning from the box
b2.use ImportMaster
end
+ b2.use PrepareClone
b2.use PrepareCloneSnapshot
b2.use Import
b2.use DiscardState
From 1b19ce1cc3c5ce454e9ecd99fd542abe7d0ddb5c Mon Sep 17 00:00:00 2001
From: Pat O'Shea
Date: Thu, 8 Oct 2015 23:56:34 -0600
Subject: [PATCH 118/484] Add windows minion requirement for ipc_mode
If this is not set to tpc, then the minion will fail to communicate with the master.
---
website/docs/source/v2/provisioning/salt.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/provisioning/salt.html.md b/website/docs/source/v2/provisioning/salt.html.md
index 938fec155..5d41b302f 100644
--- a/website/docs/source/v2/provisioning/salt.html.md
+++ b/website/docs/source/v2/provisioning/salt.html.md
@@ -90,7 +90,7 @@ a custom salt minion config file.
* `minion_pub` (salt/key/minion.pub) - Path to your minion
public key
-* `grains_config` (string) - Path to a custom salt grains file.
+* `grains_config` (string) - Path to a custom salt grains file. On Windows, the minion needs `ipc_mode: tcp` set otherwise it will [fail to communicate](https://github.com/saltstack/salt/issues/22796) with the master.
* `masterless` (boolean) - Calls state.highstate in local mode. Uses `minion_id` and `pillar_data` when provided.
From e426455309597857d687678e0fc8dbd044e7fa7b Mon Sep 17 00:00:00 2001
From: Mikhail Zholobov
Date: Fri, 9 Oct 2015 14:54:10 +0300
Subject: [PATCH 119/484] guests/darwin: Configure network following the MAC
addresses matching
Currently `configure_networks` guest cap configures NICs following the device order and fails
when the device order is mixed. We should detect the appropriate NIC by its MAC address.
---
.../guests/darwin/cap/configure_networks.rb | 108 ++++++++++++++----
1 file changed, 86 insertions(+), 22 deletions(-)
diff --git a/plugins/guests/darwin/cap/configure_networks.rb b/plugins/guests/darwin/cap/configure_networks.rb
index fefd0a2e2..1f43acd6a 100644
--- a/plugins/guests/darwin/cap/configure_networks.rb
+++ b/plugins/guests/darwin/cap/configure_networks.rb
@@ -6,45 +6,109 @@ module VagrantPlugins
module GuestDarwin
module Cap
class ConfigureNetworks
+ @@logger = Log4r::Logger.new("vagrant::guest::darwin::configure_networks")
+
include Vagrant::Util
def self.configure_networks(machine, networks)
- # Slightly different than other plugins, using the template to build commands
- # rather than templating the files.
+ if !machine.provider.capability?(:nic_mac_addresses)
+ raise Errors::CantReadMACAddresses,
+ provider: machine.provider_name.to_s
+ end
- machine.communicate.sudo("networksetup -detectnewhardware")
- machine.communicate.sudo("networksetup -listnetworkserviceorder > /tmp/vagrant.interfaces")
- tmpints = File.join(Dir.tmpdir, File.basename("#{machine.id}.interfaces"))
- machine.communicate.download("/tmp/vagrant.interfaces",tmpints)
+ nic_mac_addresses = machine.provider.capability(:nic_mac_addresses)
+ @@logger.debug("mac addresses: #{nic_mac_addresses.inspect}")
- devlist = []
- ints = ::IO.read(tmpints)
+ mac_service_map = create_mac_service_map(machine)
+
+ networks.each do |network|
+ mac_address = nic_mac_addresses[network[:interface]+1]
+ if mac_address.nil?
+ @@logger.warn("Could not find mac address for network #{network.inspect}")
+ next
+ end
+
+ service_name = mac_service_map[mac_address]
+ if service_name.nil?
+ @@logger.warn("Could not find network service for mac address #{mac_address}")
+ next
+ end
+
+ network_type = network[:type].to_sym
+ if network_type == :static
+ command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}"
+ elsif network_type == :dhcp
+ command = "networksetup -setdhcp \"#{service_name}\""
+ else
+ raise "#{network_type} network type is not supported, try static or dhcp"
+ end
+
+ machine.communicate.sudo(command)
+ end
+ end
+
+ # Creates a hash mapping MAC addresses to network service name
+ # Example: { "00C100A1B2C3" => "Thunderbolt Ethernet" }
+ def self.create_mac_service_map(machine)
+ tmp_ints = File.join(Dir.tmpdir, File.basename("#{machine.id}.interfaces"))
+ tmp_hw = File.join(Dir.tmpdir, File.basename("#{machine.id}.hardware"))
+
+ machine.communicate.tap do |comm|
+ comm.sudo("networksetup -detectnewhardware")
+ comm.sudo("networksetup -listnetworkserviceorder > /tmp/vagrant.interfaces")
+ comm.sudo("networksetup -listallhardwareports > /tmp/vagrant.hardware")
+ comm.download("/tmp/vagrant.interfaces", tmp_ints)
+ comm.download("/tmp/vagrant.hardware", tmp_hw)
+ end
+
+ interface_map = {}
+ ints = ::IO.read(tmp_ints)
ints.split(/\n\n/m).each do |i|
- if i.match(/Hardware/) and not i.match(/Ethernet/).nil?
- devmap = {}
+ if i.match(/Hardware/) && i.match(/Ethernet/)
# Ethernet, should be 2 lines,
# (3) Thunderbolt Ethernet
# (Hardware Port: Thunderbolt Ethernet, Device: en1)
# multiline, should match "Thunderbolt Ethernet", "en1"
devicearry = i.match(/\([0-9]+\) (.+)\n.*Device: (.+)\)/m)
- devmap[:interface] = devicearry[2]
- devmap[:service] = devicearry[1]
- devlist << devmap
+ service = devicearry[1]
+ interface = devicearry[2]
+
+ # Should map interface to service { "en1" => "Thunderbolt Ethernet" }
+ interface_map[interface] = service
end
end
- File.delete(tmpints)
+ File.delete(tmp_ints)
- networks.each do |network|
- service_name = devlist[network[:interface]][:service]
- if network[:type].to_sym == :static
- command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}"
- elsif network[:type].to_sym == :dhcp
- command = "networksetup -setdhcp \"#{service_name}\""
+ mac_service_map = {}
+ macs = ::IO.read(tmp_hw)
+ macs.split(/\n\n/m).each do |i|
+ if i.match(/Hardware/) && i.match(/Ethernet/)
+ # Ethernet, should be 3 lines,
+ # Hardware Port: Thunderbolt 1
+ # Device: en1
+ # Ethernet Address: a1:b2:c3:d4:e5:f6
+
+ # multiline, should match "en1", "00:c1:00:a1:b2:c3"
+ devicearry = i.match(/Device: (.+)\nEthernet Address: (.+)/m)
+ interface = devicearry[1]
+ naked_mac = devicearry[2].gsub(':','').upcase
+
+ # Skip hardware ports without MAC (bridges, bluetooth, etc.)
+ next if naked_mac == "N/A"
+
+ if !interface_map[interface]
+ @@logger.warn("Could not find network service for interface #{interface}")
+ next
+ end
+
+ # Should map MAC to service, { "00C100A1B2C3" => "Thunderbolt Ethernet" }
+ mac_service_map[naked_mac] = interface_map[interface]
end
-
- machine.communicate.sudo(command)
end
+ File.delete(tmp_hw)
+
+ mac_service_map
end
end
end
From f930fa94af0b339b6f4498844a0ba429703074e7 Mon Sep 17 00:00:00 2001
From: Mikhail Zholobov
Date: Fri, 9 Oct 2015 14:56:18 +0300
Subject: [PATCH 120/484] Move "cant_read_mac_addresses" error to the global
space
Now it is used not only by Windows, but by Darwin guests as well.
---
lib/vagrant/errors.rb | 4 ++++
plugins/guests/darwin/cap/configure_networks.rb | 2 +-
plugins/guests/windows/cap/configure_networks.rb | 2 +-
plugins/guests/windows/errors.rb | 4 ----
templates/locales/en.yml | 8 ++++++++
templates/locales/guest_windows.yml | 8 --------
6 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb
index 906b8d9bc..82f8a5e24 100644
--- a/lib/vagrant/errors.rb
+++ b/lib/vagrant/errors.rb
@@ -248,6 +248,10 @@ module Vagrant
error_key(:bundler_error)
end
+ class CantReadMACAddresses < VagrantError
+ error_key(:cant_read_mac_addresses)
+ end
+
class CapabilityHostExplicitNotDetected < VagrantError
error_key(:capability_host_explicit_not_detected)
end
diff --git a/plugins/guests/darwin/cap/configure_networks.rb b/plugins/guests/darwin/cap/configure_networks.rb
index 1f43acd6a..1be71c82f 100644
--- a/plugins/guests/darwin/cap/configure_networks.rb
+++ b/plugins/guests/darwin/cap/configure_networks.rb
@@ -12,7 +12,7 @@ module VagrantPlugins
def self.configure_networks(machine, networks)
if !machine.provider.capability?(:nic_mac_addresses)
- raise Errors::CantReadMACAddresses,
+ raise Vagrant::Errors::CantReadMACAddresses,
provider: machine.provider_name.to_s
end
diff --git a/plugins/guests/windows/cap/configure_networks.rb b/plugins/guests/windows/cap/configure_networks.rb
index 8e766a319..a4f4685d9 100644
--- a/plugins/guests/windows/cap/configure_networks.rb
+++ b/plugins/guests/windows/cap/configure_networks.rb
@@ -53,7 +53,7 @@ module VagrantPlugins
def self.create_vm_interface_map(machine, guest_network)
if !machine.provider.capability?(:nic_mac_addresses)
- raise Errors::CantReadMACAddresses,
+ raise Vagrant::Errors::CantReadMACAddresses,
provider: machine.provider_name.to_s
end
diff --git a/plugins/guests/windows/errors.rb b/plugins/guests/windows/errors.rb
index d5be14ce6..e76753646 100644
--- a/plugins/guests/windows/errors.rb
+++ b/plugins/guests/windows/errors.rb
@@ -6,10 +6,6 @@ module VagrantPlugins
error_namespace("vagrant_windows.errors")
end
- class CantReadMACAddresses < WindowsError
- error_key(:cant_read_mac_addresses)
- end
-
class NetworkWinRMRequired < WindowsError
error_key(:network_winrm_required)
end
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
index 9e8c680aa..94f47371d 100644
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -606,6 +606,14 @@ en:
issues. The error from Bundler is:
%{message}
+ cant_read_mac_addresses: |-
+ The provider you are using ('%{provider}') doesn't support the
+ "nic_mac_addresses" provider capability which is required
+ for advanced networking to work with this guest OS. Please inform
+ the author of the provider to add this feature.
+
+ Until then, you must remove any networking configurations other
+ than forwarded ports from your Vagrantfile for Vagrant to continue.
capability_host_explicit_not_detected: |-
The explicit capability host specified of '%{value}' could not be
found.
diff --git a/templates/locales/guest_windows.yml b/templates/locales/guest_windows.yml
index a648f5a09..f9a3bf997 100644
--- a/templates/locales/guest_windows.yml
+++ b/templates/locales/guest_windows.yml
@@ -1,14 +1,6 @@
en:
vagrant_windows:
errors:
- cant_read_mac_addresses: |-
- The provider being used to start Windows ('%{provider}')
- doesn't support the "nic_mac_addresses" capability which is required
- for advanced networking to work with Windows guests. Please inform
- the author of the provider to add this feature.
-
- Until then, you must remove any networking configurations other
- than forwarded ports from your Vagrantfile for Vagrant to continue.
network_winrm_required: |-
Configuring networks on Windows requires the communicator to be
set to WinRM. To do this, add the following to your Vagrantfile:
From 99985449953d7c21fc2c4f6a4bb12f5de0f0128d Mon Sep 17 00:00:00 2001
From: Johannes Graf
Date: Sat, 10 Oct 2015 20:48:31 +0200
Subject: [PATCH 121/484] Fix for #6151 / provisioner puppet_server with Puppet
Collection 1
puppet_server provisioner fails with Puppet Collection 1 with the
following error:
```bash
==> default: Running provisioner: puppet_server...
The `puppet` binary appears not to be in the PATH of the guest. This
could be because the PATH is not properly setup or perhaps Puppet is not
installed on this guest. Puppet provisioning can not continue without
Puppet properly installed.
```
---
.../provisioners/puppet/config/puppet_server.rb | 6 ++++++
.../puppet/provisioner/puppet_server.rb | 15 +++++++++++++--
.../source/v2/provisioning/puppet_agent.html.md | 2 ++
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/plugins/provisioners/puppet/config/puppet_server.rb b/plugins/provisioners/puppet/config/puppet_server.rb
index 9c53672d5..5cab589b6 100644
--- a/plugins/provisioners/puppet/config/puppet_server.rb
+++ b/plugins/provisioners/puppet/config/puppet_server.rb
@@ -2,6 +2,10 @@ module VagrantPlugins
module Puppet
module Config
class PuppetServer < Vagrant.plugin("2", :config)
+ # The path to Puppet's bin/ directory.
+ # @return [String]
+ attr_accessor :binary_path
+
attr_accessor :client_cert_path
attr_accessor :client_private_key_path
attr_accessor :facter
@@ -12,6 +16,7 @@ module VagrantPlugins
def initialize
super
+ @binary_path = UNSET_VALUE
@client_cert_path = UNSET_VALUE
@client_private_key_path = UNSET_VALUE
@facter = {}
@@ -29,6 +34,7 @@ module VagrantPlugins
def finalize!
super
+ @binary_path = nil if @binary_path == UNSET_VALUE
@client_cert_path = nil if @client_cert_path == UNSET_VALUE
@client_private_key_path = nil if @client_private_key_path == UNSET_VALUE
@puppet_node = nil if @puppet_node == UNSET_VALUE
diff --git a/plugins/provisioners/puppet/provisioner/puppet_server.rb b/plugins/provisioners/puppet/provisioner/puppet_server.rb
index 9c9e9e6b7..29c1c23dc 100644
--- a/plugins/provisioners/puppet/provisioner/puppet_server.rb
+++ b/plugins/provisioners/puppet/provisioner/puppet_server.rb
@@ -17,8 +17,14 @@ module VagrantPlugins
end
def verify_binary(binary)
+ if @config.binary_path
+ test_cmd = "test -x #{@config.binary_path}/#{binary}"
+ else
+ test_cmd = "which #{binary}"
+ end
+
@machine.communicate.sudo(
- "which #{binary}",
+ test_cmd,
error_class: PuppetServerError,
error_key: :not_detected,
binary: binary)
@@ -83,8 +89,13 @@ module VagrantPlugins
facter = "#{facts.join(" ")} "
end
+
+ puppet_bin = "puppet"
+ if @config.binary_path
+ puppet_bin = File.join(@config.binary_path, puppet_bin)
+ end
options = options.join(" ")
- command = "#{facter}puppet agent --onetime --no-daemonize #{options} " +
+ command = "#{facter} #{puppet_bin} agent --onetime --no-daemonize #{options} " +
"--server #{config.puppet_server} --detailed-exitcodes || [ $? -eq 2 ]"
@machine.ui.info I18n.t("vagrant.provisioners.puppet_server.running_puppetd")
diff --git a/website/docs/source/v2/provisioning/puppet_agent.html.md b/website/docs/source/v2/provisioning/puppet_agent.html.md
index 14d2b8a7c..26f43cf2a 100644
--- a/website/docs/source/v2/provisioning/puppet_agent.html.md
+++ b/website/docs/source/v2/provisioning/puppet_agent.html.md
@@ -26,6 +26,8 @@ the set of modules and manifests from there.
The `puppet_server` provisioner takes various options. None are strictly
required. They are listed below:
+* `binary_path` (string) - Path on the guest to Puppet's `bin/` directory.
+
* `client_cert_path` (string) - Path to the client certificate for the
node on your disk. This defaults to nothing, in which case a client
cert won't be uploaded.
From 07a42daf9018e0d84bb2be52224289e25d32bd73 Mon Sep 17 00:00:00 2001
From: Gemma Peter
Date: Sun, 11 Oct 2015 16:11:33 +0100
Subject: [PATCH 122/484] Fix typo
---
website/docs/source/v2/provisioning/shell.html.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/docs/source/v2/provisioning/shell.html.md b/website/docs/source/v2/provisioning/shell.html.md
index 978d8cbda..ef4119668 100644
--- a/website/docs/source/v2/provisioning/shell.html.md
+++ b/website/docs/source/v2/provisioning/shell.html.md
@@ -136,7 +136,7 @@ end
If you're running a Batch of PowerShell script for Windows, make sure
that the external path has the proper extension (".bat" or ".ps1"), because
-Windows uses this to determine what kind fo file it is to execute. If you
+Windows uses this to determine what kind of file it is to execute. If you
exclude this extension, it likely won't work.
To run a script already available on the guest you can use an inline script to
From 29e60882ca87a006c29d0e3bb4f37746f75f8477 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tadej=20Jane=C5=BE?=
Date: Sun, 11 Oct 2015 23:09:10 +0200
Subject: [PATCH 123/484] Fixes Fedora network issues when biosdevname command
is not present.
Previously, configuring and enabling network interfaces failed with:
"The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!
/usr/sbin/biosdevname --policy=all_ethN -i bash: /usr/sbin/biosdevname:
No such file or directory
Stdout from the command:
bash: /usr/sbin/biosdevname: No such file or directory"
The previous attempt to fix this (ccc4162) doesn't work since it doesn't
properly parse the 'bash: /usr/sbin/biosdevname: No such file or
directory' error message.
This patch works around that problem and adds a comment explaining the
meaning of the return codes.
---
plugins/guests/fedora/cap/configure_networks.rb | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/plugins/guests/fedora/cap/configure_networks.rb b/plugins/guests/fedora/cap/configure_networks.rb
index 963996edc..364b744e4 100644
--- a/plugins/guests/fedora/cap/configure_networks.rb
+++ b/plugins/guests/fedora/cap/configure_networks.rb
@@ -17,7 +17,10 @@ module VagrantPlugins
virtual = false
interface_names = Array.new
interface_names_by_slot = Array.new
- machine.communicate.sudo("/usr/sbin/biosdevname; echo $?") do |_, result|
+ machine.communicate.sudo("/usr/sbin/biosdevname &>/dev/null; echo $?") do |_, result|
+ # The above command returns:
+ # - '4' if /usr/sbin/biosdevname detects it is running in a virtual machine
+ # - '127' if /usr/sbin/biosdevname doesn't exist
virtual = true if ['4', '127'].include? result.chomp
end
From 8ee97d5f81797f7bab973655e282bed080d525ea Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 12 Oct 2015 13:16:19 -0400
Subject: [PATCH 124/484] Update CHANGELOG
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c794b3ce0..aa52318c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,7 @@ BUG FIXES:
- communicators/ssh: use the same SSH args for `vagrant ssh` with and without
a command [GH-4986, GH-5928]
- guests/fedora: networks can be configured without nmcli [GH-5931]
+ - guests/fedora: biosdevname can return 4 or 127 [GH-6139]
- guests/redhat: systemd detection should happen on guest [GH-5948]
- guests/ubuntu: setting hostname fixed in 12.04 [GH-5937]
- hosts/linux: NFS can be configured without `$TMP` set on the host [GH-5954]
From 8c8a70798dc6d725afe509a82425e76d8bbe4870 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Mon, 12 Oct 2015 15:50:47 -0400
Subject: [PATCH 125/484] Update CHANGELOG.md
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa52318c1..f78eac8bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ IMPROVEMENTS:
BUG FIXES:
+ - communicator/winrm: respect `boot_timeout` setting [GH-6229]
- provisioners/ansible: use quotes for the `ansible_ssh_private_key_file`
value in the generated inventory [GH-6209]
From 8e879905996eb6e2f9bb75d0d16b892f2f405a12 Mon Sep 17 00:00:00 2001
From: Marc Siegfriedt
Date: Fri, 21 Aug 2015 13:37:10 -0700
Subject: [PATCH 126/484] add the option to make elevated interactive scripts
---
plugins/communicators/winrm/communicator.rb | 7 ++-
.../winrm/scripts/elevated_shell.ps1.erb | 8 ++--
plugins/communicators/winrm/shell.rb | 1 +
plugins/provisioners/shell/config.rb | 43 +++++++++++--------
plugins/provisioners/shell/provisioner.rb | 2 +-
templates/locales/en.yml | 1 +
.../docs/source/v2/provisioning/shell.html.md | 10 ++++-
7 files changed, 45 insertions(+), 27 deletions(-)
mode change 100644 => 100755 plugins/communicators/winrm/communicator.rb
mode change 100644 => 100755 plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
mode change 100644 => 100755 plugins/communicators/winrm/shell.rb
mode change 100644 => 100755 plugins/provisioners/shell/config.rb
mode change 100644 => 100755 plugins/provisioners/shell/provisioner.rb
mode change 100644 => 100755 templates/locales/en.yml
mode change 100644 => 100755 website/docs/source/v2/provisioning/shell.html.md
diff --git a/plugins/communicators/winrm/communicator.rb b/plugins/communicators/winrm/communicator.rb
old mode 100644
new mode 100755
index b14b28efa..d4d14e064
--- a/plugins/communicators/winrm/communicator.rb
+++ b/plugins/communicators/winrm/communicator.rb
@@ -136,10 +136,11 @@ module VagrantPlugins
error_key: nil, # use the error_class message key
good_exit: 0,
shell: :powershell,
+ interactive: false,
}.merge(opts || {})
opts[:good_exit] = Array(opts[:good_exit])
- command = wrap_in_scheduled_task(command) if opts[:elevated]
+ command = wrap_in_scheduled_task(command, opts[:interactive]) if opts[:elevated]
output = shell.send(opts[:shell], command, &block)
execution_output(output, opts)
end
@@ -195,7 +196,9 @@ module VagrantPlugins
# @return The wrapper command to execute
def wrap_in_scheduled_task(command)
path = File.expand_path("../scripts/elevated_shell.ps1", __FILE__)
- script = Vagrant::Util::TemplateRenderer.render(path)
+ script = Vagrant::Util::TemplateRenderer.render(path, options: {
+ interactive: interactive,
+ })
guest_script_path = "c:/tmp/vagrant-elevated-shell.ps1"
file = Tempfile.new(["vagrant-elevated-shell", "ps1"])
begin
diff --git a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
old mode 100644
new mode 100755
index 17767e436..778dcb0cd
--- a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
+++ b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
@@ -12,8 +12,8 @@ $task_xml = @'
- {username}
- Password
+ {user}
+ <%= options[:interactive] ? 'InteractiveTokenOrPassword' : 'Password' %>
HighestAvailable
@@ -55,7 +55,7 @@ $schedule.Connect()
$task = $schedule.NewTask($null)
$task.XmlText = $task_xml
$folder = $schedule.GetFolder("\")
-$folder.RegisterTaskDefinition($task_name, $task, 6, $username, $password, 1, $null) | Out-Null
+$folder.RegisterTaskDefinition($task_name, $task, 6, $user, $password, <%= options[:interactive] ? 3 : 1 %>, $null) | Out-Null
$registered_task = $folder.GetTask("\$task_name")
$registered_task.Run($null) | Out-Null
@@ -71,7 +71,7 @@ function SlurpOutput($out_file, $cur_line) {
if (Test-Path $out_file) {
get-content $out_file | select -skip $cur_line | ForEach {
$cur_line += 1
- Write-Host "$_"
+ Write-Host "$_"
}
}
return $cur_line
diff --git a/plugins/communicators/winrm/shell.rb b/plugins/communicators/winrm/shell.rb
old mode 100644
new mode 100755
index 9b0f4e302..1d277829a
--- a/plugins/communicators/winrm/shell.rb
+++ b/plugins/communicators/winrm/shell.rb
@@ -23,6 +23,7 @@ module VagrantPlugins
HTTPClient::KeepAliveDisconnected,
WinRM::WinRMHTTPTransportError,
WinRM::WinRMAuthorizationError,
+ WinRM::WinRMWSManFault,
Errno::EACCES,
Errno::EADDRINUSE,
Errno::ECONNREFUSED,
diff --git a/plugins/provisioners/shell/config.rb b/plugins/provisioners/shell/config.rb
old mode 100644
new mode 100755
index 2f4957214..19d5180a9
--- a/plugins/provisioners/shell/config.rb
+++ b/plugins/provisioners/shell/config.rb
@@ -12,29 +12,32 @@ module VagrantPlugins
attr_accessor :keep_color
attr_accessor :name
attr_accessor :powershell_args
+ attr_accessor :elevated_interactive
def initialize
- @args = UNSET_VALUE
- @inline = UNSET_VALUE
- @path = UNSET_VALUE
- @upload_path = UNSET_VALUE
- @privileged = UNSET_VALUE
- @binary = UNSET_VALUE
- @keep_color = UNSET_VALUE
- @name = UNSET_VALUE
- @powershell_args = UNSET_VALUE
+ @args = UNSET_VALUE
+ @inline = UNSET_VALUE
+ @path = UNSET_VALUE
+ @upload_path = UNSET_VALUE
+ @privileged = UNSET_VALUE
+ @binary = UNSET_VALUE
+ @keep_color = UNSET_VALUE
+ @name = UNSET_VALUE
+ @powershell_args = UNSET_VALUE
+ @elevated_interactive = UNSET_VALUE
end
def finalize!
- @args = nil if @args == UNSET_VALUE
- @inline = nil if @inline == UNSET_VALUE
- @path = nil if @path == UNSET_VALUE
- @upload_path = "/tmp/vagrant-shell" if @upload_path == UNSET_VALUE
- @privileged = true if @privileged == UNSET_VALUE
- @binary = false if @binary == UNSET_VALUE
- @keep_color = false if @keep_color == UNSET_VALUE
- @name = nil if @name == UNSET_VALUE
- @powershell_args = "-ExecutionPolicy Bypass" if @powershell_args == UNSET_VALUE
+ @args = nil if @args == UNSET_VALUE
+ @inline = nil if @inline == UNSET_VALUE
+ @path = nil if @path == UNSET_VALUE
+ @upload_path = "/tmp/vagrant-shell" if @upload_path == UNSET_VALUE
+ @privileged = true if @privileged == UNSET_VALUE
+ @binary = false if @binary == UNSET_VALUE
+ @keep_color = false if @keep_color == UNSET_VALUE
+ @name = nil if @name == UNSET_VALUE
+ @powershell_args = "-ExecutionPolicy Bypass" if @powershell_args == UNSET_VALUE
+ @elevated_interactive = false if @elevated_interactive == UNSET_VALUE
if @args && args_valid?
@args = @args.is_a?(Array) ? @args.map { |a| a.to_s } : @args.to_s
@@ -78,6 +81,10 @@ module VagrantPlugins
errors << I18n.t("vagrant.provisioners.shell.args_bad_type")
end
+ if @elevated_interactive == true && @privileged == false
+ errors << I18n.t("vagrant.provisioners.shell.interactive_not_elevated")
+ end
+
{ "shell provisioner" => errors }
end
diff --git a/plugins/provisioners/shell/provisioner.rb b/plugins/provisioners/shell/provisioner.rb
old mode 100644
new mode 100755
index 1b89d1f29..1abfc4889
--- a/plugins/provisioners/shell/provisioner.rb
+++ b/plugins/provisioners/shell/provisioner.rb
@@ -137,7 +137,7 @@ module VagrantPlugins
end
# Execute it with sudo
- comm.sudo(command, elevated: config.privileged) do |type, data|
+ comm.sudo(command, { elevated: config.privileged, interactive: config.elevated_interactive }) do |type, data|
handle_comm(type, data)
end
end
diff --git a/templates/locales/en.yml b/templates/locales/en.yml
old mode 100644
new mode 100755
index 9e8c680aa..56846292f
--- a/templates/locales/en.yml
+++ b/templates/locales/en.yml
@@ -1996,6 +1996,7 @@ en:
running: "Running: %{script}"
runningas: "Running: %{local} as %{remote}"
upload_path_not_set: "`upload_path` must be set for the shell provisioner."
+ interactive_not_elevated: "To be interactive, it must also be privileged."
ansible:
no_playbook: "`playbook` must be set for the Ansible provisioner."
diff --git a/website/docs/source/v2/provisioning/shell.html.md b/website/docs/source/v2/provisioning/shell.html.md
old mode 100644
new mode 100755
index ef4119668..783ce948e
--- a/website/docs/source/v2/provisioning/shell.html.md
+++ b/website/docs/source/v2/provisioning/shell.html.md
@@ -45,8 +45,9 @@ The remainder of the available options are optional:
defaults to "true".
* `privileged` (boolean) - Specifies whether to execute the shell script
- as a privileged user or not (`sudo`). By default this is "true". This has
- no effect for Windows guests.
+ as a privileged user or not (`sudo`). By default this is "true". Windows
+ guests use a scheduled task to run as a true administrator without the
+ WinRM limitations.
* `upload_path` (string) - Is the remote path where the shell script will
be uploaded to. The script is uploaded as the SSH user over SCP, so this
@@ -65,6 +66,11 @@ The remainder of the available options are optional:
* `powershell_args` (string) - Extra arguments to pass to `PowerShell`
if you're provisioning with PowerShell on Windows.
+* `elevated_interactive` (boolean) - Run an elevated script in interactive mode
+ on Windows. By default this is "false". Must also be `privileged`. Be sure to
+ enable auto-login for Windows as the user must be logged in for interactive
+ mode to work.
+
## Inline Scripts
From 9d87be51daa69abea4cc82457a96dfdb9b5bfd92 Mon Sep 17 00:00:00 2001
From: Dan Dunckel
Date: Mon, 12 Oct 2015 17:55:48 -0700
Subject: [PATCH 127/484] Small refactor on conditional check and add tests
---
plugins/provisioners/shell/config.rb | 2 +-
.../communicators/winrm/communicator_test.rb | 9 +++++++++
test/unit/plugins/provisioners/shell/config_test.rb | 13 +++++++++++++
3 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/plugins/provisioners/shell/config.rb b/plugins/provisioners/shell/config.rb
index 19d5180a9..aaadb8081 100755
--- a/plugins/provisioners/shell/config.rb
+++ b/plugins/provisioners/shell/config.rb
@@ -81,7 +81,7 @@ module VagrantPlugins
errors << I18n.t("vagrant.provisioners.shell.args_bad_type")
end
- if @elevated_interactive == true && @privileged == false
+ if elevated_interactive && !privileged
errors << I18n.t("vagrant.provisioners.shell.interactive_not_elevated")
end
diff --git a/test/unit/plugins/communicators/winrm/communicator_test.rb b/test/unit/plugins/communicators/winrm/communicator_test.rb
index e98f646b3..829170bd6 100644
--- a/test/unit/plugins/communicators/winrm/communicator_test.rb
+++ b/test/unit/plugins/communicators/winrm/communicator_test.rb
@@ -93,6 +93,15 @@ describe VagrantPlugins::CommunicatorWinRM::Communicator do
expect(subject.execute("dir", { elevated: true })).to eq(0)
end
+ it "wraps command in elevated and interactive shell script when elevated and interactive are true" do
+ expect(shell).to receive(:upload).with(kind_of(String), "c:/tmp/vagrant-elevated-shell.ps1")
+ expect(shell).to receive(:powershell) do |cmd|
+ expect(cmd).to eq("powershell -executionpolicy bypass -file \"c:/tmp/vagrant-elevated-shell.ps1\" " +
+ "-username \"vagrant\" -password \"password\" -encoded_command \"ZABpAHIAOwAgAGUAeABpAHQAIAAkAEwAQQBTAFQARQBYAEkAVABDAE8ARABFAA==\"")
+ end.and_return({ exitcode: 0 })
+ expect(subject.execute("dir", { elevated: true, interactive: true })).to eq(0)
+ end
+
it "can use cmd shell" do
expect(shell).to receive(:cmd).with(kind_of(String)).and_return({ exitcode: 0 })
expect(subject.execute("dir", { shell: :cmd })).to eq(0)
diff --git a/test/unit/plugins/provisioners/shell/config_test.rb b/test/unit/plugins/provisioners/shell/config_test.rb
index 946b4c2a8..582740162 100644
--- a/test/unit/plugins/provisioners/shell/config_test.rb
+++ b/test/unit/plugins/provisioners/shell/config_test.rb
@@ -85,6 +85,19 @@ describe "VagrantPlugins::Shell::Config" do
I18n.t("vagrant.provisioners.shell.args_bad_type")
])
end
+
+ it "returns an error if elevated_interactive is true but privileged is false" do
+ subject.path = file_that_exists
+ subject.elevated_interactive = true
+ subject.privileged = false
+ subject.finalize!
+
+ result = subject.validate(machine)
+
+ expect(result["shell provisioner"]).to eq([
+ I18n.t("vagrant.provisioners.shell.interactive_not_elevated")
+ ])
+ end
end
describe 'finalize!' do
From d859a3b75207f75f31165aacf0ec0dc137fae5b1 Mon Sep 17 00:00:00 2001
From: Dan Dunckel
Date: Thu, 15 Oct 2015 12:36:19 -0700
Subject: [PATCH 128/484] Somehow I missed this param while resolving conflicts
---
plugins/communicators/winrm/communicator.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/communicators/winrm/communicator.rb b/plugins/communicators/winrm/communicator.rb
index d4d14e064..ade021aad 100755
--- a/plugins/communicators/winrm/communicator.rb
+++ b/plugins/communicators/winrm/communicator.rb
@@ -194,7 +194,7 @@ module VagrantPlugins
# in place.
#
# @return The wrapper command to execute
- def wrap_in_scheduled_task(command)
+ def wrap_in_scheduled_task(command, interactive)
path = File.expand_path("../scripts/elevated_shell.ps1", __FILE__)
script = Vagrant::Util::TemplateRenderer.render(path, options: {
interactive: interactive,
From aec65b5d66f48fa0036a5d1abe13557fbb1a0700 Mon Sep 17 00:00:00 2001
From: Dan Dunckel
Date: Thu, 15 Oct 2015 12:41:08 -0700
Subject: [PATCH 129/484] Fix user to username that was lost in merge conflict
resolution
---
plugins/communicators/winrm/scripts/elevated_shell.ps1.erb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
index 778dcb0cd..d98bc7554 100755
--- a/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
+++ b/plugins/communicators/winrm/scripts/elevated_shell.ps1.erb
@@ -12,7 +12,7 @@ $task_xml = @'
- {user}
+ {username}
<%= options[:interactive] ? 'InteractiveTokenOrPassword' : 'Password' %>
HighestAvailable
@@ -55,7 +55,7 @@ $schedule.Connect()
$task = $schedule.NewTask($null)
$task.XmlText = $task_xml
$folder = $schedule.GetFolder("\")
-$folder.RegisterTaskDefinition($task_name, $task, 6, $user, $password, <%= options[:interactive] ? 3 : 1 %>, $null) | Out-Null
+$folder.RegisterTaskDefinition($task_name, $task, 6, $username, $password, <%= options[:interactive] ? 3 : 1 %>, $null) | Out-Null
$registered_task = $folder.GetTask("\$task_name")
$registered_task.Run($null) | Out-Null
From 13be9731ab89a13fd3450bf6e56b66a7fa846bf1 Mon Sep 17 00:00:00 2001
From: Timotei Dolean
Date: Fri, 16 Oct 2015 16:20:15 +0300
Subject: [PATCH 130/484] Remove back tick in puppet facts definitions #6403
Starting with vagrant 1.7.3
(commit 1152b4e1df97fb5f468491954932d4f0c09875b1) we don't
save the command to be executed in the file anymore, but we send
it as a parameter, thus the back tick makes things worse.
---
plugins/provisioners/puppet/provisioner/puppet.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/provisioners/puppet/provisioner/puppet.rb b/plugins/provisioners/puppet/provisioner/puppet.rb
index f1987dbd5..89d39000f 100644
--- a/plugins/provisioners/puppet/provisioner/puppet.rb
+++ b/plugins/provisioners/puppet/provisioner/puppet.rb
@@ -212,7 +212,7 @@ module VagrantPlugins
# If we're on Windows, we need to use the PowerShell style
if windows?
- facts.map! { |v| "`$env:#{v};" }
+ facts.map! { |v| "$env:#{v};" }
end
facter = "#{facts.join(" ")} "
From c17efbed755df621d6571742e163e8dff61dd119 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Sun, 11 Oct 2015 18:38:08 -0400
Subject: [PATCH 131/484] core: ignore VAGRANT_DOTFILE_PATH if a child
environment
This causes issues since the child environment almost certainly doesn't
share data with the parent. In a larger scope, we should find a way to
encode the data path somehow on `vagrant up`.
---
lib/vagrant/environment.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index 0981d9df6..015e4b95f 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -159,7 +159,7 @@ module Vagrant
# Setup the local data directory. If a configuration path is given,
# then it is expanded relative to the working directory. Otherwise,
# we use the default which is expanded relative to the root path.
- opts[:local_data_path] ||= ENV["VAGRANT_DOTFILE_PATH"]
+ opts[:local_data_path] ||= ENV["VAGRANT_DOTFILE_PATH"] if !opts[:child]
opts[:local_data_path] ||= root_path.join(DEFAULT_LOCAL_DATA) if !root_path.nil?
if opts[:local_data_path]
@local_data_path = Pathname.new(File.expand_path(opts[:local_data_path], @cwd))
@@ -427,6 +427,7 @@ module Vagrant
Util::SilenceWarnings.silence! do
Environment.new({
+ child: true,
cwd: path,
home_path: home_path,
ui_class: ui_class,
From efa01abb124361daa19aa6e5683b7805aae08839 Mon Sep 17 00:00:00 2001
From: Mitchell Hashimoto
Date: Fri, 16 Oct 2015 10:30:04 -0700
Subject: [PATCH 132/484] providers/virtualbox: if no box, don't import the
master
---
plugins/providers/virtualbox/action/import_master.rb | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/plugins/providers/virtualbox/action/import_master.rb b/plugins/providers/virtualbox/action/import_master.rb
index 17296bbcc..ae8f52f32 100644
--- a/plugins/providers/virtualbox/action/import_master.rb
+++ b/plugins/providers/virtualbox/action/import_master.rb
@@ -12,6 +12,11 @@ module VagrantPlugins
end
def call(env)
+ # If we don't have a box, nothing to do
+ if !env[:machine].box
+ return @app.call(env)
+ end
+
# Do the import while locked so that nobody else imports
# a master at the same time. This is a no-op if we already
# have a master that exists.
From 61466c8e65b476b2d580a0eca06c7512026118c0 Mon Sep 17 00:00:00 2001
From: Markus Perl
Date: Sat, 17 Oct 2015 23:00:39 +0200
Subject: [PATCH 133/484] #5186: Warning: Authentication failure. Retrying...
after packaging box
---
plugins/providers/virtualbox/provider.rb | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/plugins/providers/virtualbox/provider.rb b/plugins/providers/virtualbox/provider.rb
index 969fb4718..b8b88d9ca 100644
--- a/plugins/providers/virtualbox/provider.rb
+++ b/plugins/providers/virtualbox/provider.rb
@@ -59,12 +59,20 @@ module VagrantPlugins
# If the VM is not running that we can't possibly SSH into it
return nil if state.id != :running
+ # If the insecure key was automatically replaced with a newly generated key pair,
+ # use this key to connect to the machine
+ private_key_path = nil
+ if @machine.data_dir.join("private_key").file?
+ private_key_path = @machine.data_dir.join("private_key")
+ end
+
# Return what we know. The host is always "127.0.0.1" because
# VirtualBox VMs are always local. The port we try to discover
# by reading the forwarded ports.
return {
host: "127.0.0.1",
- port: @driver.ssh_port(@machine.config.ssh.guest_port)
+ port: @driver.ssh_port(@machine.config.ssh.guest_port),
+ private_key_path: private_key_path
}
end
From a59dc04b6953c08c96d4f015be9b65599b6b7140 Mon Sep 17 00:00:00 2001
From: Joseph Frazier
Date: Sat, 17 Oct 2015 19:42:58 -0400
Subject: [PATCH 134/484] handle_forwarded_port_collisions.rb: fix typo:
"Reparied" -> "Repaired"
---
lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb b/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb
index b53ba35c2..cf6477915 100644
--- a/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb
+++ b/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb
@@ -128,7 +128,7 @@ module Vagrant
port_checker[repaired_port] ||
lease_check(repaired_port)
if in_use
- @logger.info("Reparied port also in use: #{repaired_port}. Trying another...")
+ @logger.info("Repaired port also in use: #{repaired_port}. Trying another...")
next
end
From d142640d853d8885117eea6cb7688abdddf43f1f Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Thu, 22 Oct 2015 12:18:43 -0400
Subject: [PATCH 135/484] Fix SHASUM file name
---
scripts/bintray_upload.sh | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/scripts/bintray_upload.sh b/scripts/bintray_upload.sh
index 030d56300..83a30e4e2 100755
--- a/scripts/bintray_upload.sh
+++ b/scripts/bintray_upload.sh
@@ -22,9 +22,13 @@ if [ -z $BINTRAY_API_KEY ]; then
exit 1
fi
-# Calculate the checksums
-pushd ./dist
-shasum -a256 * > ./${VERSION}_SHA256SUMS
+# Make the checksums
+pushd ./pkg/dist
+shasum -a256 * > ./vagrant_${VERSION}_SHA256SUMS
+if [ -z $NOSIGN ]; then
+ echo "==> Signing..."
+ gpg --default-key 348FFC4C --detach-sig ./vagrant_${VERSION}_SHA256SUMS
+fi
popd
# Upload
From 23990e34e93812ab98be1b8d51e73d86b36465fb Mon Sep 17 00:00:00 2001
From: Seth Vargo
Date: Mon, 26 Oct 2015 11:29:54 -0400
Subject: [PATCH 136/484] Use releases for releases
---
website/www/Gemfile.lock | 34 +++---
website/www/config.rb | 11 +-
website/www/config.ru | 4 +
website/www/helpers/download_helpers.rb | 85 ---------------
.../www/helpers/middleman_hashicorp_shim.rb | 103 ++++++++++++++++++
website/www/lib/redirect_to_releases.rb | 37 +++++++
website/www/source/_sidebar_downloads.erb | 2 +-
.../source/download-archive-single.html.erb | 51 ---------
website/www/source/downloads-archive.html.erb | 32 ------
website/www/source/downloads.html.erb | 76 +++++++------
website/www/source/images/fastly_logo.png | Bin 0 -> 3995 bytes
.../www/source/images/icons/icon_centos.png | Bin 0 -> 5002 bytes
.../www/source/images/icons/icon_darwin.png | Bin 848 -> 1850 bytes
.../www/source/images/icons/icon_debian.png | Bin 32226 -> 2906 bytes
.../www/source/images/icons/icon_freebsd.png | Bin 27639 -> 5852 bytes
.../www/source/images/icons/icon_hashios.png | Bin 0 -> 1842 bytes
.../www/source/images/icons/icon_linux.png | Bin 16563 -> 4229 bytes
.../www/source/images/icons/icon_macosx.png | Bin 0 -> 1956 bytes
.../www/source/images/icons/icon_openbsd.png | Bin 27660 -> 10634 bytes
website/www/source/images/icons/icon_rpm.png | Bin 36773 -> 5016 bytes
.../www/source/images/icons/icon_windows.png | Bin 12626 -> 3292 bytes
21 files changed, 207 insertions(+), 228 deletions(-)
delete mode 100644 website/www/helpers/download_helpers.rb
create mode 100644 website/www/helpers/middleman_hashicorp_shim.rb
create mode 100644 website/www/lib/redirect_to_releases.rb
delete mode 100644 website/www/source/download-archive-single.html.erb
delete mode 100644 website/www/source/downloads-archive.html.erb
create mode 100644 website/www/source/images/fastly_logo.png
create mode 100644 website/www/source/images/icons/icon_centos.png
create mode 100644 website/www/source/images/icons/icon_hashios.png
create mode 100644 website/www/source/images/icons/icon_macosx.png
diff --git a/website/www/Gemfile.lock b/website/www/Gemfile.lock
index 112d0d72d..946a40701 100644
--- a/website/www/Gemfile.lock
+++ b/website/www/Gemfile.lock
@@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
- activesupport (3.2.21)
+ activesupport (3.2.22)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
builder (3.2.2)
@@ -9,7 +9,7 @@ GEM
coffee-script (2.2.0)
coffee-script-source
execjs
- coffee-script-source (1.9.1)
+ coffee-script-source (1.9.1.1)
commonjs (0.2.7)
compass (1.0.3)
chunky_png (~> 1.2)
@@ -23,20 +23,20 @@ GEM
sass (>= 3.3.0, < 3.5)
compass-import-once (1.0.5)
sass (>= 3.2, < 3.5)
- daemons (1.1.9)
- eventmachine (1.0.7)
+ daemons (1.2.3)
+ eventmachine (1.0.8)
execjs (1.4.1)
multi_json (~> 1.0)
- ffi (1.9.6)
- haml (4.0.6)
+ ffi (1.9.10)
+ haml (4.0.7)
tilt
highline (1.6.21)
hike (1.2.3)
i18n (0.6.11)
- kramdown (1.5.0)
+ kramdown (1.9.0)
less (2.2.2)
commonjs (~> 0.2.6)
- libv8 (3.16.14.7)
+ libv8 (3.16.14.13)
listen (1.3.1)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
@@ -75,25 +75,25 @@ GEM
sprockets-helpers (~> 1.0.0)
sprockets-sass (~> 1.0.0)
mini_portile (0.6.2)
- multi_json (1.10.1)
+ multi_json (1.11.2)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
- rack (1.6.0)
+ rack (1.6.4)
rack-contrib (1.1.0)
rack (>= 0.9.1)
rack-protection (1.5.3)
rack
rack-test (0.6.3)
rack (>= 1.0)
- rb-fsevent (0.9.4)
+ rb-fsevent (0.9.6)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
- rb-kqueue (0.2.3)
+ rb-kqueue (0.2.4)
ffi (>= 0.5.0)
redcarpet (3.0.0)
- ref (1.0.5)
- sass (3.4.13)
- sprockets (2.12.3)
+ ref (2.0.0)
+ sass (3.4.19)
+ sprockets (2.12.4)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
@@ -103,7 +103,7 @@ GEM
sprockets-sass (1.0.3)
sprockets (~> 2.0)
tilt (~> 1.1)
- therubyracer (0.12.1)
+ therubyracer (0.12.2)
libv8 (~> 3.16.14.0)
ref
thin (1.5.1)
@@ -112,7 +112,7 @@ GEM
rack (>= 1.0.0)
thor (0.19.1)
tilt (1.3.7)
- tzinfo (0.3.43)
+ tzinfo (0.3.45)
uglifier (2.1.2)
execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2)
diff --git a/website/www/config.rb b/website/www/config.rb
index d30b7bd51..a5b2fa61a 100644
--- a/website/www/config.rb
+++ b/website/www/config.rb
@@ -1,13 +1,10 @@
-require File.expand_path("../helpers/download_helpers", __FILE__)
+require_relative "helpers/middleman_hashicorp_shim"
+helpers MiddlemanHashiCorpHelpers
page "/blog_feed.xml", layout: false
-ignore "/download-archive-single.html"
-# Archived download pages
-$vagrant_versions.each do |version|
- proxy "/download-archive/v#{version}.html", "/download-archive-single.html",
- locals: { version: version }, ignore: true
-end
+# The version of Vagrant - update this to update the downloads page
+set :latest_version, '1.7.4'
set :css_dir, 'stylesheets'
set :js_dir, 'javascripts'
diff --git a/website/www/config.ru b/website/www/config.ru
index 2cef78935..49f749c15 100644
--- a/website/www/config.ru
+++ b/website/www/config.ru
@@ -6,6 +6,7 @@ require "rack/contrib/try_static"
require "rack/protection"
require File.expand_path("../lib/legacy_redirect", __FILE__)
+require File.expand_path("../lib/redirect_to_releases", __FILE__)
# Protect against various bad things
use Rack::Protection::JsonCsrf
@@ -23,6 +24,9 @@ use Rack::Deflater
# Redirect the legacy URLs that point to www.vagrantup.com
use HashiCorp::Rack::LegacyRedirect
+# Redirect the archive page to releases
+use HashiCorp::Rack::RedirectToReleases
+
# Set the "forever expire" cache headers for these static assets. Since
# we hash the contents of the assets to determine filenames, this is safe
# to do.
diff --git a/website/www/helpers/download_helpers.rb b/website/www/helpers/download_helpers.rb
deleted file mode 100644
index 9244d9af4..000000000
--- a/website/www/helpers/download_helpers.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-require "json"
-require "net/http"
-require "net/https"
-
-$vagrant_files = {}
-$vagrant_os = []
-
-$vagrant_os_mappings = {
- ".deb" => "debian",
- ".dmg" => "darwin",
- ".msi" => "windows",
- ".rpm" => "rpm",
-}
-
-$vagrant_os_order = ["darwin", "windows", "debian", "rpm"]
-$vagrant_downloads = {}
-$vagrant_versions = []
-
-if ENV["VAGRANT_VERSION"]
- puts "Finding downloads for Vagrant"
- raise "BINTRAY_API_KEY must be set." if !ENV["BINTRAY_API_KEY"]
- http = Net::HTTP.new("bintray.com", 443)
- http.use_ssl = true
- req = Net::HTTP::Get.new("/api/v1/packages/mitchellh/vagrant/vagrant/files")
- req.basic_auth "mitchellh", ENV["BINTRAY_API_KEY"]
- response = http.request(req)
- data = JSON.parse(response.body)
-
- data.each do |file|
- filename = file["name"]
-
- # Ignore any files that don't appear to have a version in it
- next if filename !~ /[-_]?(\d+\.\d+\.\d+[^-_.]*)/
- version = Gem::Version.new($1.to_s)
- $vagrant_downloads[version] ||= {}
-
- $vagrant_os_mappings.each do |suffix, os|
- if filename.end_with?(suffix)
- $vagrant_downloads[version][os] ||= []
- $vagrant_downloads[version][os] << filename
- end
- end
- end
-
- $vagrant_versions = $vagrant_downloads.keys.sort.reverse
- $vagrant_versions.each do |v|
- puts "- Version #{v} found"
- end
-else
- puts "Not generating downloads."
-end
-
-module DownloadHelpers
- def download_arch(file)
- if file.include?("i686")
- return "32-bit"
- elsif file.include?("x86_64")
- return "64-bit"
- else
- return "Universal (32 and 64-bit)"
- end
- end
-
- def download_os_human(os)
- if os == "darwin"
- return "Mac OS X"
- elsif os == "debian"
- return "Linux (Deb)"
- elsif os == "rpm"
- return "Linux (RPM)"
- elsif os == "windows"
- return "Windows"
- else
- return os
- end
- end
-
- def download_url(file)
- "https://dl.bintray.com/mitchellh/vagrant/#{file}"
- end
-
- def latest_version
- $vagrant_versions.first
- end
-end
diff --git a/website/www/helpers/middleman_hashicorp_shim.rb b/website/www/helpers/middleman_hashicorp_shim.rb
new file mode 100644
index 000000000..9ac10b4d0
--- /dev/null
+++ b/website/www/helpers/middleman_hashicorp_shim.rb
@@ -0,0 +1,103 @@
+# This file is a shim that mirrors the behavior or middleman-hashicorp without
+# fully importing it. Vagrant is somewhat of a beast and cannot be easily
+# updated due to older versions of bootstrap and javascript and whatnot.
+
+require "open-uri"
+
+class MiddlemanHashiCorpReleases
+ RELEASES_URL = "https://releases.hashicorp.com".freeze
+
+ class Build < Struct.new(:name, :version, :os, :arch, :url); end
+
+ def self.fetch(product, version)
+ url = "#{RELEASES_URL}/#{product}/#{version}/index.json"
+ r = JSON.parse(open(url).string,
+ create_additions: false,
+ symbolize_names: true,
+ )
+
+ # Convert the builds into the following format:
+ #
+ # {
+ # "os" => {
+ # "arch" => "https://download.url"
+ # }
+ # }
+ #
+ {}.tap do |h|
+ r[:builds].each do |b|
+ build = Build.new(*b.values_at(*Build.members))
+
+ h[build.os] ||= {}
+ h[build.os][build.arch] = build.url
+ end
+ end
+ end
+end
+
+module MiddlemanHashiCorpHelpers
+ #
+ # Output an image that corresponds to the given operating system using the
+ # vendored image icons.
+ #
+ # @return [String] (html)
+ #
+ def system_icon(name)
+ image_tag("icons/icon_#{name.to_s.downcase}.png")
+ end
+
+ #
+ # The formatted operating system name.
+ #
+ # @return [String]
+ #
+ def pretty_os(os)
+ case os
+ when /darwin/
+ "Mac OS X"
+ when /freebsd/
+ "FreeBSD"
+ when /openbsd/
+ "OpenBSD"
+ when /linux/
+ "Linux"
+ when /windows/
+ "Windows"
+ else
+ os.capitalize
+ end
+ end
+
+ #
+ # The formatted architecture name.
+ #
+ # @return [String]
+ #
+ def pretty_arch(arch)
+ case arch
+ when /all/
+ "Universal (32 and 64-bit)"
+ when /686/, /386/
+ "32-bit"
+ when /86_64/, /amd64/
+ "64-bit"
+ else
+ parts = arch.split("_")
+
+ if parts.empty?
+ raise "Could not determine pretty arch `#{arch}'!"
+ end
+
+ parts.last.capitalize
+ end
+ end
+
+ #
+ # Query the Bintray API to get the real product download versions.
+ #
+ # @return [Hash]
+ #
+ def product_versions
+ MiddlemanHashiCorpReleases.fetch("vagrant", latest_version)
+ end
+end
diff --git a/website/www/lib/redirect_to_releases.rb b/website/www/lib/redirect_to_releases.rb
new file mode 100644
index 000000000..655c58d2e
--- /dev/null
+++ b/website/www/lib/redirect_to_releases.rb
@@ -0,0 +1,37 @@
+module HashiCorp
+ module Rack
+ # This redirects to releases.hashicorp.com when a user tries to download
+ # an old version of Vagrant.
+ class RedirectToReleases
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ if env["PATH_INFO"] =~ /^\/downloads-archive/
+ headers = {
+ "Content-Type" => "text/html",
+ "Location" => "https://releases.hashicorp.com/vagrant",
+ }
+
+ message = "Redirecting to releases archive..."
+
+ return [301, headers, [message]]
+ end
+
+ if env["PATH_INFO"] =~ /^\/download-archive\/v(.+)\.html/
+ headers = {
+ "Content-Type" => "text/html",
+ "Location" => "https://releases.hashicorp.com/vagrant/#{$1}",
+ }
+
+ message = "Redirecting to releases archive..."
+
+ return [301, headers, [message]]
+ end
+
+ @app.call(env)
+ end
+ end
+ end
+end
diff --git a/website/www/source/_sidebar_downloads.erb b/website/www/source/_sidebar_downloads.erb
index faf7b8f3b..939cd078a 100644
--- a/website/www/source/_sidebar_downloads.erb
+++ b/website/www/source/_sidebar_downloads.erb
@@ -1,4 +1,4 @@
diff --git a/website/www/source/download-archive-single.html.erb b/website/www/source/download-archive-single.html.erb
deleted file mode 100644
index 41b8e7fac..000000000
--- a/website/www/source/download-archive-single.html.erb
+++ /dev/null
@@ -1,51 +0,0 @@
----
-layout: "inner"
-sidebar_current: "downloads"
-sidebar_template: "downloads"
-sidebar_title: "Download"
-page_title: "Download Old Vagrant Version"
----
-
-Old Vagrant Version: <%= version %>
-
-
-This is the downloads page for an
old version of Vagrant.
-The latest version of Vagrant can always be found on the
-
main downloads page.
-
-
-
-
-
-You can find the SHA256 checksums for this version of Vagrant
-here.
-
-
-
-<% $vagrant_os_order.each do |os| %>
- <% downloads = $vagrant_downloads[version] %>
- <% if downloads[os] && !downloads[os].empty? %>
-
-
-
<%= image_tag "/images/icons/icon_#{os}.png" %>
-
-
<%= download_os_human(os) %>
-
-
-
-
-
- <% end %>
-<% end %>
-
-
-
-
diff --git a/website/www/source/downloads-archive.html.erb b/website/www/source/downloads-archive.html.erb
deleted file mode 100644
index 2e8da7f97..000000000
--- a/website/www/source/downloads-archive.html.erb
+++ /dev/null
@@ -1,32 +0,0 @@
----
-layout: "inner"
-sidebar_current: "downloads-archive"
-sidebar_template: "downloads"
-sidebar_title: "Download"
-page_title: "Download Old Versions of Vagrant"
----
-
-Old Versions
-
-
-This webpage lists the older versions of Vagrant that are available for
-download. Some even older versions are available from the
-legacy downloads page.
-
-
-
-The latest version of Vagrant can be found on the
-main downloads page.
-
-
-<% if $vagrant_versions.length > 1 %>
-
-<% else %>
-
-No old Vagrant versions could be found.
-
-<% end %>
diff --git a/website/www/source/downloads.html.erb b/website/www/source/downloads.html.erb
index 252b325a2..55b10484e 100644
--- a/website/www/source/downloads.html.erb
+++ b/website/www/source/downloads.html.erb
@@ -9,41 +9,47 @@ page_title: "Download Vagrant"
Download Vagrant
-
-
-Below are all available downloads for the latest version of Vagrant
-(<%= latest_version %>). Please download the proper package for your
-operating system and architecture. You can find SHA256 checksums
-for packages here,
-and you can find the version changelog here.
-
-
+
-<% if latest_version %>
-<% $vagrant_os_order.each do |os| %>
- <% downloads = $vagrant_downloads[latest_version] %>
- <% if downloads[os] && !downloads[os].empty? %>
-
-
-
<%= image_tag "/images/icons/icon_#{os}.png" %>
-
-
<%= download_os_human(os) %>
-
-
-
-
-
- <% end %>
-<% end %>
-<% end %>
+ <% product_versions.each do |os, arches| %>
+ <% next if os == "web" %>
+
+
+
<%= system_icon(os) %>
+
+
<%= pretty_os(os) %>
+
+
+
+
+
+ <% end %>
-
+
diff --git a/website/www/source/images/fastly_logo.png b/website/www/source/images/fastly_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..de82b3c0d00b2c16c2a04c6c4616cfff43ddfc77
GIT binary patch
literal 3995
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
Bx3mBN
literal 0
HcmV?d00001
diff --git a/website/www/source/images/icons/icon_centos.png b/website/www/source/images/icons/icon_centos.png
new file mode 100644
index 0000000000000000000000000000000000000000..53d423cff44264be05ab33bcde4bc857e350c30f
GIT binary patch
literal 5002
zcmV;56Lsu~P)002t}1^@s6I8J)%000wFNkl8=_0T@C$#{GG{ty53~E#N4qsea&jy)6wW3#E)H+OQ1@SZOb?4nQd|
z2!1sKo)51^sAO>xnAHo+;V1$1U$fv|c`>{jhQio9hJY>V1?F^=0=23yJgcuDSU1D>
z$z23&G{U{Ww4*erOW^rnfDM*!>v#s{aM(HPs5S|`z6^>q&<^X93FkC0r=v6|2P}hN
zovXkE6r_H#WYlxNcM-w4oB@g4BzqX%39WH3J|2ls@d8NuKG$IYen9#;sn0i+&*$UM
z-Jnhop`rqK)?O!2yc>s+RKNa42Bu-{ybu0e55m7&Y1aer?YI}=$`${&4!hxOznA*l
z54r=^KaZh~*yJ&2z<
z0>peAu&|4_K>@S)@48Hwo;VV|t|*4MpN@C)`S5vl2dqA30^We-Lb3m2lmxcgnWCTI>7t)fZuoy5Yv
zQ?cOUY%IKFsuHcUF3QHf8Jl3nO|%?6fwz7=8~NuyBggAwoyza?i~wVobt^1#jhtk5
z$uCG3bR+@xa>dPP4p)NPdI9xM$Woul(#ImJn73VshH!};*7hVUSMez<8897-FQ0}b
zS4_8ywh=@D#?4*r!aF192}pgM<8us*9oA#8^hw*rP9adkG^nO*+9sgvklK3%%i*j{
zutc(bK09ot2KKHEm_xKL8@1be)LBkYQ;L6%S1Nx+pei`@9FEe`z8)!QdK*$}Wbe@Fe$~*E2R$kA+O4U=d^{7W+yaGs|C}4lD
zO#%xEFoDUCBy6888$_UnvlOfx@(*R){cL(2u!yQ6x{
zSzEc_lsd{Kpe#z}%Mgrv7#IQiU1|grI7@5qrG0J%>;WkgUaGi}0g*-stUOxgFjTNI
z@UH@j_J>fu;cIX+8rT;V1iPoM6F6Tj+?@ng-zp&M_f>W;ES?lM
zgulj#&{1$(*CbOIDH(E)_Qm@Re?i0y3YgUmPq6zKgcPZ(8=qiz(f$AflYR3z468DP
zVX-|7)u_jzC)zc64OR@FgH_|^Q!zRhyRz0I8i*jOK)rMOT&%itzEt)pV4m6*v{p2O
zC)3>p>t`ev$p(s&G$(ll0VyaWxR>>?9hfa=r5_Ci7CTB@6!9rgQ`Tr0
zx6k8s-tGX!S~*SuTR^~cbMbj~2dwK!{+JbRugsq>yGBAuy0|e-}RZ&0@rj1j+)tC2Ta5;Vivw
z-`=^yDs>Ly7Wb6$4Ge}QcXblvG-}Qqb-NRk+SjR8YFKC_SYG=4kn3k*=8W|=U}qb8
zlnnP^#fUjrci-OyR%LKM)k(K#C{9S24EQ+MWcq~g_UFTvF`p9tbJTms`^Nz
zm-V`1KaF|}jG@?o@!W7u<*hgwDuuL|H~COVJRqy5%TCg@seDe%+EG3R71p4}%@?iI
z;*pQHIVJU&9oB#=rsC2|Cljy@8GvN~C12tW4U3$`b(Q3-Jd)}inx`e}syL-&{!Fsc
zPk7l;1nSpv)uB0B0n3EfwBV7k#Ds@$D7dR!ST$h*-W!`Q4htJ0nZoSJSuZEOYWxDy
zeChSF^m^I8kLQPWSOccw%7Hn!tS;R;Rt~7Bp%+qwrLmf>C=q
zshSq*S*KO6w@a_Kt99wEa11_w64pS1HR#IRB(O`TbQY2tly($bTN0vzRe-g>dlk(`
z8sM!x1Ebb+R`RLdLx00v-9jfHhqx#XA1wU0X_{-)_xTa`ybjQIm@)#ig`y}eJ%Mrp
zRaxCka)~PRvQx58dfRao^fwM2s=?5ko+ns21dAlVav5014g>H@%d(ClL7*1x;pC?*
ztMxvMLSgm9g-VMY(%WtO(;Y8A!ro~c5b^{;ttB4E1OWeF`w?kfIj!aNX+Qq>*mB7)
zR}G$a)*5VI7B`8=T?1LP%zfWWCS%sj^@znxDO{Nof1w5vs<)Nk)xk5d{Ko&p8#i^V
z<-dIKJJr$wGx!J6m9#iYH(r+?lG>8RyD@lBE^Z$B{I}9j`#Oc;3ml3pSsr%t3*6Jb
z7jW%0Gq8PoF}Tt9Xb@+~7bSxGrf*DM6Y8JKmqfJsi}*@ohg#CUJYDsfwWwdNTs;W3
z_{CZ5pmffnFWTZE2hNzj9(PU1$8YYLue3n-BIkCcw8z|iR{KE5&=)Q#Y2s3W
zn|(C2xKF_J6w5;*soG1f*?A5FM#Nn)FUN_g_YZ-{XIL172?sZg&umOj?F3F3;vK}
zrz;O3OPH~v1e84Nw(=7A_dEoPV9C^I?<4$lGe0@#)N1>(o1~Tna=bAGYbov=H;)}f
zpmt{fl>yj(0#R$+
zX%Rs&2+AY|#g9>HU{L}V^UGXP?dw$T)beUtUUg}^vmSh4DMpQ)ogwtP4ovEy*RFXE
zW*`MCiyhH*P*flJDNh;gpr*9%n?&mjkQ(1slS|OgmJZ_E`trCEH4Zxl)DbXJ7lAoo
z?V#M5z;Eweh=mJwrg79+0y~ty6LBMiZQB*Bw19FPjv`P3WRl%c0?shn5G2R?j0jFg
zt5HxrnqkQW#uMREAYzDvEb2P|CLjga-VDGb45b$(PJIfuH-;4}KF{E&vjhgq!Y5mc
zGKXQ;LDBvYa&p$7ywnAEq7L~Ct4zU)R>C@6$jO|6NJ#n!Q2LO3MDI(<4oy9?Iux-}
zpTV?X1NEI>gWtQiER~qQEhtI$fBoxwl3c4R&k(FyhNYbqAz1D*PRN|h1&A5_{|@V`
zl76O;6j#ZEzsBZK{QPQnJ@u^b?nELnzV0IF7^XNZcql6wdc}*t%?#8hL-y2uMB^~J71oX&M{&`GPhsrnIRebGfOly4
z^?2IYRpgr099}$y5cgzfeJI=8f_6|!3Rb3^rC~`pvIt7x;FGZ8L2*&=i^<|1M8m4%FtpcMtqK+=>2*V3Y#En&z0M9S#tusY^KBkw
z+ZR7`7=itdGbG;Lqp&!s^R;U}S($|1J+VM~b&10UYMLEX24~gTD)^I8@IP>>1xK2@E_+K#m;hq-Kt?ly4hLA
z!GqNpJ9bW5r;Hslhi+NDf%^JZP_qHcl;EAELj_>e>X*wI7%43%`>5y0Z9SQ@G^{ZK
ztINO^w*yNDt3W6C&R})sC{;%V6e#DhJ)g6T0|%;b`-qq1R?!{gu(8sU+WWcG&!uBt
zrYX;BsIGP)k&uv-WIt9P$IC1^zN(@{!z$CT;H{D5E&!-k%PbAb;ulM*xiaT!T^%<@
z2t(Myc|FIIbtV2RhL;T5_qo1Qy6wkCJ89SJx~v!^y#*Dqyejy
z6Frbn(#u+=7kb&PX7@p;7K0aY_-zWC2I||srV4&kdl*&+K1VR&M$q!ND`5HHGd&6s
zpx(W9@uZlY(p3?tR{f6j_vY<;k?rk!ej{Uk^&MDTdpDNU-jh_#Jy=w8mpq#ET-jh`
z6`zk;G%7w{b~UZDt`bc@+7H{CXDd?4x9@#EUr)Y$-}C?1VMp^Eyi{?MJjgb;>Nb&j
z>4~8TEP2nTgnL#WJV{SUuWOnDz&v;U5r%REcDm;A18%lQEAtdAhNRy~`~^REFVEjg
zbAUQWfvGTLSn3Vg44}?MV6!U)m@Q}Vn`KX*>!57URyZ8ip0j#EWp>ytRFn?pm#BI{
zWdgR#m51DtzF2o+N-wCc04p*+7D|?hvR+V~13Q{@RPX;O?Fz6VmSue}{{!y-0>t(<
UNyD7~asU7T07*qoM6N<$f?RKc^Z)<=
literal 0
HcmV?d00001
diff --git a/website/www/source/images/icons/icon_darwin.png b/website/www/source/images/icons/icon_darwin.png
index c9ad9fe041b552bb30f3f4f461739a4136ceaa8e..f5516bb8defdbd9a472ceec669d0c26b8e082e00 100644
GIT binary patch
literal 1850
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
Eg3D!#RsaA1
literal 32226
zcmYhjd011|);N3u0xje1RR)8=ZLLE^25TdT2DDbtiZV}O2xx_p$RviD5TI%+0#|JX
z5dsQAAS6LC41tg!0#$^dW>6pyO(l>p8UiFt-wyZvJ{-Twf9uuIRQaibidFBPu~9SDTbiT+S5NB_f3IK3vmsSiyxX3l7iBrk9YqV
zZLBr*Q-kqI!SiE}&8PU~W$%RN&xbz@tRMyMy+Qizn;Q>v-Was4gbb8MMe6(^oUM&(
z4?8H3I4{?9eJEWTEl*79#DGmse2gN;bj0>H`Gm3#)f-^ej2Tldc2qrCsj*YrK&yL{
zU`)2`L_KG12G>(<0f&Q%50V9U=`k?@WxQS-1?8Fe;gu7$pj^6|8$wXSNo2ca&=LM$;-{)h7M^YY3R5^Srf&
zu+TB8Uyl0Q_^vcBkOjON>6?=9O~3|H3%S!PrO$M*j^MY>V>%GTuagM$u+!()Gg}uaEdCa@`r%C2
zY#jyL5|3xrEz-{DYFa>$*$Dx)nWu?qNw|c3WN58_1%kre>%CTZeOTuCD;W%8=*Ird
zhrh+3b@*p*yuOlzeC!;&x$750ZKGm-#-)skMT(x@CN!9g-zIzAopP9A8PaQfAu<96
zL1MA1BJZ(W7%vIiq<eS&*7sFoYC0-!O9Ku
zovpn}|6a6?J4NwH=>`-khI!O2@&6+dG0>qX&1Y&l-sMWL5eB-3Bsall)XB}ST6{7Y
zCj2YxQAH2xWQ+Qwv8d|;ZLNc!QWe#xFE?-?$6a2n(*voyAkf9kBlG-pPOseGk|~{C!7W%`qMn}
zkq&Bl(xvZEAziwbemdNDmvhzNFK+2M++KUA?(r|`+e@z15j5oX%Xr=Im}>a-L2iO1
zgl>4W@L@sS;}6>4kSUA5=O+d-M}ze+`~OEF=`I9DX?k=j?^{e)dL)2T5
zYLG{Gx8Z&b(bK^@`_+dG^Q|-_ddUQ*zE|JovO~M0>beEcO|9W@jXjOce|D_g6ljKTzibGb
z4oQ5e#_A9W>t78G3rhb-YTdb1wS*GB)^N7lJn{H4U#Y2Y-u9BeFS0Y7*}rR_M(s)lk_-gIQ3ym3o!ge?;;w
z_5LQN|M!Q(Z~wn17hG-jL4-dN`+A9uqze>dl&`7aD(e$ECf){KuB_SRNdA
zI^Pj&VNVoD-%VXcW!&>(CgJ#X8?$<{pF<-XIL}jE%NRdyP#+;;NB*UeC%Xy%9&8>S
zPZKE?$lG
z#+ruQQb?--xK^CI#bKTu5M%#46Qvp%1ppp66B?yOz?|-sRl%)YHs)02vJ_9)
zhU_+~vFDok70AAaHu|{lV$ZSyTikh#p6+*hgL|uJ`*c?F5yyJA;!(6ffiQs
zt;1C&{N0LKxK>u(8LSs9@dq_e*uSI=KaLX8W*o6-m+XG&*v`*mSI^+rKPWt=x?=PK
zj~CeJFKpK&c;W99temAM_B)F(h@T5q%CimkQ(TNSjnwB2m~F`v(iZDwruNN;tU9yt
z&$uHq{!3&e=52`!Td`JZv#d-6H@rLQPc%jBjAJpd6rV2GyU6zI
zUzkmR8#ViM|H_n~5p@`-mkdHo?<|lw^uGYT30@r}v87^y;Xw%^m@nL0oqZL(wtMNI
zDqgH%o0wYwzKFn!YrWQgXQbsDhUcMZ17xrHw~VOH=Y6{rnV2A&O?JnHsRm6Sb;myms=dM3^k&W
zO+}JH$y+a6WQ=ck#X&Wv(i&XqEkoP3*>^OVKi+V*k(qX{RTwSpFaE`p?*UX7;Q;>X
z+H1NSC5XM;_Wsl;96m93htXhGxp~~Rf*Sr#tXyMvpCP?vK!KWFh04`N^_r4uvBJy5
zM!@bwM@)NP7m$`i%lz*fyVrH8VSZ)#37d5E=_0vI#)4wKt``nw_1#@coVc#|kgK=*
zb*e(G+QPS7SB_hF5T#PB_$}0D23zjz#J03wiuTs
zPx)|26pSA<(%unT`48dC9TRgW#Uo(%mW`69QQQldTn)45({AwMP$
zpKy9(G_~vnb6>Sd3k&Ge>v?@dT6+F>z(iBQeY)Y*Bbh&KT+16v&ZrF^DfOA%3*cQ_
zHCYR2oO@{=UO@|}oSx1Y3!
zw|6CQt>v0Uh$m-n&!q}Ykx6EBFJ8+&w2(@7TQ+DZ5a(3`))Vj3{lk32pkss+I(_Mmf~li=lF!^FI|5D~hX-mL5oH`?a}XmMhgtoDNkioc}Ry5H?r0;&H?|6v`cH
zA^xyC>(|u4UTfX)Av@Xo?%&k+f-ehza?|`Np<)q2QI^ws*&o?rYr8u`O{=w83z{9_
zcxa`i&-T1>x2&JaLK+S33Y_sXK*|Wl%+_^pur|yFe&-e*(<_uMl$>oqXVwDc|DQ>d
zwP(@mWn@S|z8=tXzG~yag+eD*q-J~5sMoU13>4ow_Fp{ff&fUUmFybsh1nWx+|mMF
zcM?PaU5XZU;1lv-4HE>@KQBv@7O!=F5*#6V+WT~Pd(@ME14eS>Au9_$c2lF&D_Agj
zVX^X<-Be0U=ap5`49b-6r(WM)HL#Cx{8EUWMVCu^Mp?OOWC=ca>A(PB@4&x;AHH=8
z^8%;G#Dt0?St@tRzU4$=<-mURg~j*f7LC!IeaHsH&r~NWr2W{HnV=u{x+wYR!%?)g
zUIDNW->GA);@=}W{Cn3GTorAFFSv2s;>rv&%`yZKn{H_JwmCoS_570@>%hR5l6$z*F#V5_imC(a!FHo>=LZ=r;U}%?b>I>ZrtQ91OdFeD
zA0ku#eov2CBWp`c)@*!EWc~|^668zcF0A$;l4qAMQ_yoIX{Ui24gaP`*?**b7wd5}x%0MGL7sM@;*f&Pg@967(?$nElE8-CYCw7&-T+4z}C*Z-!bKRd!6l8d5
z@WP(O477o+=xasmfeq|Fu)C5GbRcMelqt1FERLu#zK`1x5=TW~F51*Lo4%EIs?LJ%
zE$H*bV^tfi;wHtw`OB;INr%9-5KeEGw0Y!rrStz2i#Dn~{`i;q?^#!jimSnI+g0^j0<^ftt;m>?t0qsP}K7F
zg~!@vSfIwt2Dy2D-K
z)>SCx_z(+o->F7hvU^R8T(Sj<>zIY_R-nlsPl`}fGg^QGSZ!DCNV|Y!
zX-8F{8zuAf7HzHg$Z78^;@mADG0uwBp(o?o5`m8NZ0su#;km>)XW3HCc~;nXSCw9R
zM-x;nE@s4(`P`d$09>!H6wij5iY+AEHkl0$m7VRJz~IuHzdU${~JkMi98?@C3+A#6jssdzT9ZxUZ$(DLVPf_5^70$^r
ztgzmkU#0S}2rMU+`vX*N%G0l8beIVCrUoFHfW&b_^52G9plVq$<3w4Ib#EXmsCTC{
zj6VI_&Cj#ED5*IvAv@d99x-4wJl}!xt&EHoKE(%s&B|ZPrx9BrymvB1e#6gP2BJPn
zQn^!ey;rioMc8%T1KbrGJ8+%02M5sa=ik6Dj#1k9BK?Jv$U>?GW;c}4yhzFe=&mRN
z%w%Od=P!0aO`us>cVN0q7B|&Bn1;GDwTmgm{+fXM=%LtaQ!^Of{78$TF~q|H}Sd
zv-I7ArZ)EgT5D36Me<<_pCazhkfw$GfWyS{dEuj;?sDlhTmo3Qf#M+53!f}fKXp$T
zEalrCd>7|w&ex`|>&AFu`NlygNys^n2DLr-e8V4HiTj08beq_mej)$9L|~2uS8@nh
zSc||`L+#B(Z~fk4bmG;{juzYc#A+wjIAk_KNazrA9a%~Fm5G>PRTS7W%ZDT3x@)AI
zU{*x#U_T3XUM%H(8|{lJ9lIzsZ3=1Y;i(iu=hMRcYWUzQJd+B(%K20nTB8}hWq(k6
zGRKGqN6g$6*hq^Ij?EK=GG%8;G-Or3hxer9D@ac-d|Qw5Ogg@uPdeRDF&gI1ag&n3
z2Zc0EY`;c4kh|yhXs$d{@vh`2BQl388hJSOK=MJ$-n_$Si6+Nff@wR2m(t$L*$njA
zx;xkvCm?QBSxu4?y5Wab>u3CG1n*!#;>{$og;k7@w);I!s_b4kO0(Tdcpp!8YHuPv
z2I)kAH=Yy67g}$fZN&-I8exMjxvv}EG(svMSzz~r4%l7p
zSM-Z8kS4r_FO7REPsf!pFr}zr?t3*!t>&*=B!01+j3jlSq1eIf2RkGVGpWn_@)Hly
zicH?hpE=cxYp{9JBZ_CJz|9Zf5(k-*GW0YMVJgU%{ie2I5=F*|{#^ts?oQc1YO=pt
zab(4CW(|%G1T`+&RZC(Ny(MR$HvVgcX!Etqaf~Sm06AZv7sjZattVM=9NIQ^#&Qah
zIZ%68OHEQdjfk$N=S{9;3ZL3iI=4@b&7=x6ijDU0yJR(pJrKx5_9%sE_-NPO!w&T|
zz(TxYJcY))45Zf;S@cL4u;!7t(lM%}87nLaD)k!XW?|xEUyr?)M{C)auX}pbbzytd
zUx_m$L>0dUHWV;FIMAqMbEC
z*;HW}+{@po2ZXyCnbI_+EE}pX4kZhQZ%n45*Qn67&Pb5FZ*Hp1hVa_p@@TK+ZgjtX
ziy1VUdOTsUHF;85reU_*lrNL@qPLBO=rns2A2qB1gmQ&_;a#
zPe*oJ1Mp(}RdL1|aqNcyNxy;g9$>~cTU$azVt!ikT8E{#o-R1fdQ>S*C@16k&abz(
zP=j*Mzxe2)$iTw%$rM>5?iV5bHU#`4{Sri)rEmH+`RoO{hrs}LMz(acgX#r!&7>=G
zoSqcBJCG#2Cuu)}Ou$yB0n^1*U*uCW!#ir}wmJ^F49e%bd5HLxVCftk2
z%F!UR3HFwJxq~9(+<{U{ukt!@-ObZVv4+{nJ%V9rF7DicArr1ps)egzeBURHz=f;#
zupdCbk^6Pese)qyBm&XR1rJ3=Anaycqf}E-pb9>KIz)35h_NzMkg0$vO-JG>ZC$g^hC0^0!M&jQa$|%obdKgB04nFaV+eV%wwHewvGp8fm|u>$spjBy0#S!A
z?Vec9K(+uALwhTK$B4~0Cya63WOo$hCBY$-8MINI5UVJO-ouZPp%L2Z69NTKLL&
z5TYx6^Z~TH(@sYASz{Cv`=$7|R-fKp{#Dp$YwH@X#%B?kg)%p(oc>bL3Fy#~$k_?f
z74En11hfQgM3kXJS`|`5ToEHt_|$}(v66v&de?X-2&u#wcZe=zO5W>aOiXZ;dMl&F
zj1ZW6-5F^SZrRs`dNAOEm+9OE3U-{v&e}UZoQuasZ18>GaX{iB@Nd&`|HoE4SdaFMnL`^Ln>13Ou&KV
ziot$@8rs)Uy<98lKdSV#7_jY|5+ieg0fyW+iJ~|3yza(HR9**uQ|sE?QI0r`9;GXi6c}7o}P$;6P$l?$(OdT
zTCyP>(}F5zl=S2eQG?m33|Pi_&XVz+=;H$jEt#K;~+Mx1&rDGAt}9U#CnlO#)(
zAbOyL#aUNNa&cF{+hB5suYhtG)B<{x{z#T5cH5npW|ViXT>12=1dlL;L{bG0MYA8w
z4zk>8zOaglL2YQoQR$d?XPTib)iYlcYKhK#Vgj-wufAbDUTdVE=-fzNOY;XILTw&q
z2gF{J@<6uZ)olkJQqNX)64$?JFk2<-K%PV=6%8d3W)tB@k5)?#%09C{rez*L(#SrT
z5Qu$U=8rfrC#cU(z+WehQ4o66zdti@Ywgw7dn{weXZZ5}qCD+`ZEG!LE$R@ftvvYJc3f;(*v38Sg7HA3?4#eW(Ub$c66*wN
z!2OWZvTf{d4>!kp^#aiD|2VSJIAgwhUNPeM%>NTg>U5rU5~j>ItM*Q{)2GX>%iV~2
zKJ{$%&{Ha?R>(reM@T(d>;pKm6U%-u;$e?6hj^VU#8BBx>3y|8S+2W;Ouuq!I>#ve
zdcBBIvAg@DvCfKbu)qM@h9X0*FRn}H0k>^M43-Pz28be2%g|%nT5zR09)AyiA>qwd
zJ4M!w@y29zkJE$|u_^bOXgIy_!08~gjsBJ5-xKg;qDwsjL+xyoQV@=snZvb@8Ls)c
zj}&dH>5JEvPt)5YP4qB*j0j;>>|vgXmc9NtvIWrOd{DO;aF|N<4P}jMmIe*;qrqu2
zH;9}%uPd0fD|O{uJ863fI)oe>)Lh~e2XtNrD
zK`3Z?&OlU#abD}_U_RUHLMzr6ghkXRFLI!RG6}AY@zj2>7pScvV9<~7?Xz`wrfU6Y
zQR6xv;zaLg14|yQ>ork?vKd@6s<~QE^q1oEvtw3z|EJ3j#d}YCn(~3^;3zUY`>WC1
z8P(24e;8LH=%B
zQ(1)yYoKewrC>OO~47i*^UnnnZ7as4sP7Um|X+3vEVIN)bG1?nT-!1_Q^?&60W0_F-%)NCs_F}8KBgmHbzT=Eehdt2rj)C3y1umf3*~0HpjUbj7ipmR?y+T<
z5gACq#WH^fst@*CpxR1-bS~kh;l^`v2F`}oX*Qvkw%!u!QzR)@{Gke5>$qmTpA;(l
zpkNP?pmi2akcm+*t6;TBd@x*grIY~NFMJ-b!&(ZosUSdh0e8xV;-!J*S<*d(WRq>|
ztG#ibINTwlnmku89t*I8txWoVvWaY&TF5cjjeE=`M@
zazy$%BZ=gtMWdJs0PFFDe;yn^RNu>ci|NzY{k8~mTK$>+!iG%w8GbR|YuYo*mOxf@
zk&svx;{@zZ)alIHYoOxYqcljj^uzK=xw%pp{Rwm-v#9pL`oGY65f4kfkAT1fl%DO?
zE~S^SIy__wgvoV~z5=_DaT!^A$S!=93F6BWphm2@7L6PWvOiZq4aG!L_OU(DWJwoh
zj1dhJV^f6>@Ruq$4nW(zl_%5joh_-CnY3z6d;Tmpk;U+^*&n{T+L1)f!+v8^uhePp
zb&R^ntUFZK3ELmEy2e0T#RSLE5_Qe&9O_M5j+eWzZ+9C_D&OZMEG`bwph&4}W-hUi
zX3DSDx_LbhQ{%)xR*nrXje8?EqNjE`wmnTMy=vD)c+e5SG39p9&*eLduG6tLOE*?R
zG!`8O?)@uIO3|`!yu06-9OkHyuJmGp@(+m&6|m5p!!Pr;Kt{=??hhM5(up#zAv%=VPxK(0
z3U(u$2rS+rj%a?RIJ!qEMY{Nw**`v1FW`p2GS-+aqi@`TdFHZba0517b`sdDd(FSh
z%hNg{5aB_>dVFZ2L3|~?j7X!p-F$x4INnRxaPCU3;lXalv4@gAy$P8IlR2&_!hU|C
zAUO{`>Im&J2qce&9PBx!6XqxL*BE(h=_}W==VtjN&sMhay%6n$6+s#EqjM&>1c%8~
zUz>W!XWe^Pa1~Jw(U^8qt!O5LU;9CGl^TmWBdqYyY1sIL?|=!&68{xTy!7I&^>`9Qd-~EzVmUKxPH$VR$f8o`LK+JPBYyNyAso1ST3e(wfMu
zw&Sd$?DZbyQ#ML54#z_vFHtKg8=pR85l9;qX|H`I*u6;yF5FqGc!|?fXrx**ATo8@
z*RAci2Vqy9sUpJ%c2FEcPs@k1V^n?E)P95T5%LS2QAf3KY-by9l>B+QZ(v
zrSsn-90*A1p|FGvySeU^Tw+#zzi#p2joKLLO*n!OFxo6rej4hCw2BX$p3$~Qd63|2
z9sX9uf+NAXtORm@1-&Gb9g8#7%zW}8Zx)w66VRxc^7FK3rB3*ZkB#XwK{V1QL>oZ>
zpAfldUUmbqbMAaLq=t@aXfE|>)
zNkbvK9d&jO-0o)0ruL~KVF#n~((23?=C9d3Y@SU030%diG|$Xr1mse*UYF(te!Jk-
zoO%tMT97)_k$If8_-M9B@&-NPW>hc7szBlQee7WG){gkmrxF_YZ6(N*-qeMxN2-Cn
z7hrQsEJag{*s@RB7Cn7=7!~1!G`2@+tP!HS+8_y)E|ge;GKPBp9J@b<7gtZ%)OW&k
z_&Y%oqUCbz8=wb|&{GWz9qCQ=n@FT&bM8gw8gaXB%Ky@C`Hv$*Vj-JFIEKs9ZUPtt
zy8^+qvKLjUt=aw{%#&=$KC1!_IL%3COR4WL_fchLuHjLEW4TGnaUKB*Fo;6PUU?cf*lGH_Kb`0+y1!Uc+xD4Bl2#;V`^iYTZ@c}#SB
zsLxTS_;p@xmZIIqB8Y6*;w6mw0iB?O-r^ut{)s}cmAElg2+aNt(9KLqnaqtYC77B`
zRDMYWUf4^`0csoXYs3-g=0aooD6=D&3}kW|Q&DJ=@gbNd>7aim$fZPuxa2IfKPUsw
zK}xZ748asWQK>}?yw86Lvn8!?zd|^G^?7N|70vnmnsUiGad(%C5<2kH5IJM
z8bCe_tUt}U&g;c|f`JUNo90nQ(_T?ssJBsF9B&n}e^a!W;m)k_H=JV+^&GQ`UDjw$
z<4BC-d3X6crDUKPf#OR=(hEmJ*nYu*9K_&t^C>@vy`q;k6}(f=g({VbsO4=zU8D3n(RB$|7uW2N)*1DnU0-ATqXF?0n!2IAX^LDX=Q~|
z9l?5O8P#{p%6X0p-pOTUh!KERV)`g~-J5MZTyJ@)!pJn^t6_$uOt0lUjpV@J3jtZp
zT5OLh^EzP|!nLX2l9FLV>eI=nU#Ge15pJztCoYlmq@Q8Ub@$CDx?t!Q{#2_+sIzD=
z?Z^CYfR1!-msDa>!GmaRRXnf?kqQ>Ug{vvO4G)D}RoTe$fFh%mQ!$tdj!VklvZD{bRz1t_`dT3J9bZf9yV5b&6YONJAvs&R7$+BP`)T`R6)$BdK
z1mpcQrmRMbof3L(zf9TCw-$Fao;lQYtlVl@gYM693m_P`S9EwnH!FAL*-fODt1cL5
z&GmiMzmjq+1_i6mXc!HI#Qmo>k~!(zXyfpgp_n6@nH?XBx?p3qHQU&~*uUBM0o1|p
zyVyBO75>-G&%M;Qoj-lnioOo~(k+hFu>n!0(4BuO5|>tI-)e>Z=-5W}lME;foR&Yu
zv$x~W;*9e!TicE|^2xs-bM8(o$b>9^^E8R$<`@3ahUNxJAB5BNU*^-(Ozc0^YO6*F
zI=mj^;uIPsR}Uikv1-}R+q{GW$I7kM@Rp<(6=GBxf5Fw;RW@i`J
z9g;0%{DWa9O800%0snl5Tg9*|^%vg5jB4|BcfZe86ljQEw!Cv}1{*%iIh`aJ0zECP
z9fpxZj}}<=;!jAcpp7~|?XX0L!4F~du+A#w31$OSeA-pTs&-XU0W?EPU;ERx^==?tGz?V0Mw*f}yJbpW(*o>bSLXu!
zGlCJih
zS1=rL(t~ma(*X;w%6cd<+V^G4Nr%Dtv=yfA?#?LLpazr`udl5d%tm5_ISI+q&s>&!W`833bZBAT}WEE`tcLhGuH*kM&b{)lPWM@m;i5L(Hj*Sld;#7h6?J|UjVWuWG
z8+kJPCQ>gFBat*Hd|QXhiVsI%swQ&OvnemxwwsNnf?C8rNTg8o<|H(w$6Qilb#I58
zUu>$Kj;^^VF5L?FlWzXyF48x#pvw}+>VGuK4AA9%Ad
zk|;>Shlbc2c7Ujrq)ABTM{9|tGuml^*|$3CN8hXKb?%WBYY-CVXPlVfJEpw>>lGR8T>F@Yw-UZJ&H3tix8gH+%{b}O
zEC~kvPC1PG*#mza||<<
z%FV!hIholCfyn4JXG%H1(@@LHfj5N{t!LKiuYK809RRSC<7yKF^p<5HD{^xoYjK3x
z;ok*v=Sx5Zf)<`hI0&4`}ey|1*
z>H>0!l!&FW-wd&!;-6w)Zy>I@#C{>5#pnakKege{Il|kH0DZp-i3Z`cqK82WFCBS*
ztbDs#dQweyW){r#XoTNxJ?ZjDa$UFQ#k9e~z1&;tWMVSqAhwB}EG6+EfDD#m}MkPWHy45zSDS7P=%<~^q-sDuHx~+*M%u!6w3CUk6&xyE)`VLb!q>%M
znI&x-^j-I5nZg!bXe3ffGRywSO>ag
z57GVeZ#+`;IXyKbTk(_#vz=>1;3MZ@Jm+qvMXlKZjg|FUJ`OtLqhmrOW)r!=%-FCt
z-VCk{)!ftFt!Q+rHw1Z-ll0Fw7kZagj~Qs#l5C`}RA?x?V)m_kreYEXWQzE4!3=+Y3~h^S(<0`H6489{H$#&`26D}qs65h`#aubdB4
zymzWxFUsz41*P>R)OMf@J)w}p`XHJjdg@{R>{QYtLQw&~Mw~5~mgXurs$Yctjx6tH
z>JryQCg-`Jui5P=S_tv(<-Q~snLzP8)339nN(vm;5IY^>qrXrlO;oI;g;3Deg$P-;
z;*KhI+W+49s&bxuR51&>n-VNMt#zQ3Fv@
z8&uF=p=0`rTZG@P-)>3gZSZU`u?Zo}I_J>7JFI0J3Tq@<p;uD}BJj7vCc1jPfz;kte52dU=TU7W9w
zTjrKp;nIlr4K@*95UVaT>HPZBa}QM~
zK=)Q%oZxQ_h}CZ~QW58krZjWm-6=yfysw}f&`d9VCbY=pju?wefI$Zn^VS=Qd$>Db
z4in9_l~U*K<+hU+en!Qhlkyjiz$7eA2g=C2_y7tM#ZpV|8aSrR^O9l-E7qDONO~)lSENZfa0E
zRYAsbU6Y?-LuSBVb&(l7~lengzd#+YkW|$f0;lq+ZU42L=ZBD~@HQBdfxzg^UhQ
zEVm^k5p)?DW!*4>GH9+}T{=>vx%No$w8SQ!qdH|{b|-k@V2!JjdTva!Y`(ca#9%>(
zXN_&@+zCdOY)8XtcoQF*6`Yb_i2Xn-c96#QS3D@Op8Gt6bB}$^nO3S$+f$fe5aY@6
zpTw-aK#;d%`Pua2{l?kg{>H45yRwKGhue5ggGkXsjH?NSBY?e2(yAGa72URlKz5?Y$sw&
z^If3P7)4lo~z$tw0^GWH!lpU*!fsm*H
zfarHOS`Y|quz?`sNKk`FCV+Sib{vp&x0jc8UNh
zm<%EWU+LlR_IqnS5zHlH-gVxQMj~E1d-bVD3+)HDy9ml>j%A&ppt}rB`03aWUyMBj
zO+7}K<@hj=q1S}w8sUg|%B2268~+5xmu(}R-((b;$x!
zwtyFjsO#`F-KLgh>fg7!B@3%3^8fwr{9yL_>QJ?-!KIKmvk!t1&W!Reo_YuiIA|jk
zXl9sarLJYD1H}u+#;6CT^sneIMDd*vbs!5zas?d=Xv7Z3%JslRU2x#}8!N7gKY=x5
z55@krac+UbjTik5cZS$jn4r#gqZKYpKFteEid_Xq2~jgg%Qt6C(1Y^laN~vqO5+pF
zOy*E?c*xQArh2ahu~Q}J;(QwJzL@AII
z!QN~v<<&7XnFw6C#abK8woK-@=^2>^A_{^Wz(`0T)ke3cAEhXTpB$@ygveSx6B?4J
z@xKFev26P$Vqk!ICqRBeDK2r@f$q|S9GmVM-|RO~A*CuUF-8bl*B{b&pVSlp)zHDX
z%T^BBs!=U*Y@Ew==U1Rn6hw(B-I1678ou;(xYbma%*j+rC6Y`eS_&~2HRCk8Xl`U^oC
zAOzjHnD_CnVm10el1r8$kR|+JYx8ugABYcYECVaYe^-yNh3m%+S_RtQ(qH)N`IiV8
z*lch%#J+aMGY|9U>eIWtkq>c*JoQr}rzH$Bd4I8Qp3G$DV&X&;M`>px=9c(DP|NW#
zipe(jCqfK&wF5MTaFw)7osj*59;)G<0AXNh9FSHALi%4jcY)U2C_7)Q3K57
zEt-#*UWpBb`8ULdM*X&KyYL9Y0K#nu!k^yJ
z0Ge%w{|7}Y>9s6GgfGSTI^I(gvQj{qH
zwUeVB`&I)3QN{{}{YY_w*321-gL%?p8<#t)R6pmJ4D(0M-!H+bw;ZEp8M~J}QbcQJ?rMnX|6Z*jcIDN$>fU6*
zHsW6%i)t&mxOucay1V=LV4ecUosJG1*Ul`3Z4%y!Coj%9op3I*)wO^6#)0MSYNotm
z-26w}-r_B2l3x30$L&BCHE4tMwHCCxI;uDGX1)}z761C-`lIPpbaTcOrd*m53TBjb
zbhvf#xdTlnTn1r;P}vMZS5#%aV@y3mnYEPs@Zi_$C>OKNau=3A$J`ii2+Tx=L%kO)
z3+))o`aw^7t`-$m8CeKd&qsz=bbS|q7-R+32wHL;DL&lDc6J4PJ|~x8uUrZh1Amq|
zjt}b{#)foeD{8*VU}lyPlWoBlqR%ltd6=W&6&|TkWjT+%Nu=g@2{=*3~!&B3LJr;k)90MhpfB^Q2thF+?C^
zev9LPW_uA2G-?9Pt9KUnvz#1syxyZ;H+>skreGbT0v0B
z{NE0&*_1N|M;u8VL6uVv=&m0S$&l!!kO5i)d_nFr_2Sy2YsRGkD?C#A`Fty&3V`{K
z;<9RxgKZ~WSQp0N{&O##T3rRVyOSqV#qh9^C*xMovR1l`v?e)zx5?JV2ypkJ_lVTNu@z!Ps_gl`X?{(s?+{
zt5m>b_JaxO&RES%Ow~rc_$nembV4!tGH`^rfzG#_@s?{st7{Sms+VRjM|G_H^IfNk
zNb?EHwfBO|91$#&GAB_MhRevmQzIBh483DC?FUX`
zLDyf(;81&s8ng1F;8Qy@?k+m`KQ!jS4AC`Eb|GtnXclUT%m2pl!S_a+1n5u?r1@`F
zQjQ>E!@SK+*T1!b{E32L)51Bcn_UTVr@Zh!?d~HBBh5WJ
z$+agDZ4jYNfI{35Imn&WpC%tkBEOZ^v9Br!s#E!u$)Ne)`CZkFZ=)X6g3jOPh}o+a
z2A3z|B%F7r@!`f9e{}79<1h2M=`&&C>pJ`?7({EfleQ%1e-nseS(I!dJ<$?l5gH#<
z!?loIzu+_=khNyz@0mf9L8%v-2{ae%%@Ip;9>6DjcCJ}jB-eMzHgd(XCdDv3z>b0y
zq@0&CF2JC$xa)l?+{M2)_a}>I6pwPy+-a#Df_QiTC{@y^OKa7Ha^E+)8t*_nRZ|E3
zZoVQd?m%ltP#ceh28V!6}UNEnn3a_>WiA-V`!YEX@76@&v
z6SJZa2uVbY%p^!9y;Z;=gCavT6*OT8VjzU+TZg{i`~HKRbM`)apFOO-*7H0|6S9t%qAPf~s=XQ;S+N
zp_;$Gq&1#6ORS0Uf3Az{Z+F{N8kD(NeLmymjpcksh{RX<*n$-5$E~*%cj1DddwFB|
zhO_@h^z)>zq(GP|{91GDQ~}yra=_I4?g_v{xmW={_^R~6dPks0q=eb*c)>C=N9?aH
zfb!0tGUhK9?{tmSzDl3;X6h1W)H;)GAaYg~;o>dEs2>;8h#fM%gqvpu59C20c+1x!
z)2SD=tEj;CGnD
zdVAHcr;f%`Ix0B?u6-X2XNI$@_a1{L5J|*8QU;63d9xdH>OZwD6hnZySJiMYyNR8Bg4=^?7
ze+l+iF$S8DtVh;ktfa*jj&GF-$=7c869a2y$hkq#N*Ge&aWS6kDd`P$8NMNKK0c$V
z+(3FW*gwuK+Q(e7q60Qv1~6gc5x{O6eY|ct9&*fBJyZ?A&Eh@E1zI3Bn9q94QxwdU
z%r3$Kz@FKmT(9P%rdy(r2rlBg1GoB$JI=@4nX<=;V#%+h_rY74pRXvQg)ZGPVO3Fr
zjupjsp6a)jn&Gf2R%;L&L4E*gO?)W$P7V0AWjhjZPmE{vuu{%M^+3jjA})C9_bxUv
z*mB$F9=v;zSK>1|%15|1)NKMH5EJx}A1e902)>1Zs+_J+8J&}-4>6SD+*M+hl3cA;
zWaFdi8d;6YbD0ZN^|aOQKCTn4k4xU8*GU9G`4@#V$DBOt9^y=7;p$Dg>A3bKjtwzAdaYlYhVN<(hoObv?n>gw)R0q6603Rr2?y
zDA-UG|GO2G39>7*tx+AqPloJ2K8juzKQw&6TwuQtH7O=JDznlo(w84OT4AXxPK#5^6_&xzL^
z309vs$(_%pAF*C;(!*8AUILIa?D+l`PJn#P6-kouNB^Ao&O~99@;c5aOi2&J*sq0Z
zpMzEGplZZFI*@nS8kka=c;{w_QQZvy5gi0*(dO$PD<|~vJ@Z7TjG#8ro%0il-MBs^
zE)|NJSqH!;`xM}DK5*H8YcD%o&yGu@gkl78MKLZ$_ECEQjkonlr!*%zP>GTpD$w+;
zFtXXSUdEWzF?&k#wQkwY$kN!6>6z9{2*@3b_LJ))n|-CW=<&lPykI818i*OV??G1R
zVBvbOo4C6LQU^eWSmn+~s^7XSe#a(PeNyfdB5Fpm+(FaDs%uIyrLSFA8QvKs+%4Ys
zEUXOhR0gmLkVVrEbehKW@t0KjGDUZ~=Iuax4`$r=l?1|%9ZG#12SiS?<1>VeD&=mR
zXP8e%wc92nrr!Zh357eGD@`1pTu%m!JigO6MB4M5l9%uX6o3a}4j6pPXBrt&Npp^!=ar>^6y@QG>u6W8h*BiszeI{
z2!zGMuRk)THXO~a5qaWvA+l&*vmiDWMl;m=n^@Vws~ojNY`>qBObaXsa1=s1L$7{*
zG&@8ZL3P0Z#`kUPrtk+=A^g=R;)1wbmN*TQH71p)T?G>@=S?c?u6=-$e$)bKZ