Merge changes from master

This commit is contained in:
Brian Knight 2017-06-15 10:16:25 -04:00
commit 8b8ae6652e
48 changed files with 941 additions and 71 deletions

View File

@ -4,10 +4,27 @@ FEATURES:
IMPROVEMENTS:
- commands/snapshot: enforce unique snapshot names and introduce `--force` flag [GH-7810]
- commands/snapshot: Enforce unique snapshot names and introduce `--force` flag [GH-7810]
- commands/ssh: Introduce tty flag for `vagrant ssh -c` [GH-6827]
- core: Warn about vagrant CWD changes for a machine [GH-3921]
- core/box: Warn if user sets box as url [GH-7118]
- guests/kali: Add support for guest [GH-8553]
- guests/smartos: Update halt capability and add public key insert and remove capabilities [GH-8618]
- provisioners/ansible: Fix SSH keys only behavior to be consistent with Vagrant [GH-8467]
- snapshot/delete: Improve error message when given snapshot doesn't exist [GH-8653]
- snapshot/list: Raise exception if provider does not support snapshots [GH-8619]
- snapshot/restore: Improve error message when given snapshot doesn't exist [GH-8653]
- snapshot/save: Raise exception if provider does not support snapshots [GH-8619]
BUG FIXES:
- communicators/ssh: Move `none` cipher to end of default cipher list in Net::SSH [GH-8661]
- core: Add unique identifier to provisioner objects [GH-8680]
- guests/windows: Fix directory creation when using rsync for synced folders [GH-8588]
- providers/docker: Fix check for docker-compose [GH-8659, GH-8660]
- provisioners/ansible_local: Catch pip_args in FreeBSD's and SUSE's ansible_install [GH-8676]
- snapshot/restore: Exit 1 if vm has not been created when command is invoked [GH-8653]
## 1.9.5 (May 15, 2017)
FEATURES:

View File

@ -30,6 +30,12 @@ module Vagrant
def call(env)
@download_interrupted = false
unless env[:box_name].nil?
if URI.parse(env[:box_name]).kind_of?(URI::HTTP)
env[:ui].warn(I18n.t("vagrant.box_add_url_warn"))
end
end
url = Array(env[:box_url]).map do |u|
u = u.gsub("\\", "/")
if Util::Platform.windows? && u =~ /^[a-z]:/i

View File

@ -44,7 +44,9 @@ module Vagrant
# Allow the user to specify a tty or non-tty manually, but if they
# don't then we default to a TTY
if !opts[:extra_args].include?("-t") && !opts[:extra_args].include?("-T")
if !opts[:extra_args].include?("-t") &&
!opts[:extra_args].include?("-T") &&
env[:tty]
opts[:extra_args] << "-t"
end

View File

@ -656,6 +656,14 @@ module Vagrant
error_key(:snapshot_force)
end
class SnapshotNotFound < VagrantError
error_key(:snapshot_not_found)
end
class SnapshotNotSupported < VagrantError
error_key(:snapshot_not_supported)
end
class SSHAuthenticationFailed < VagrantError
error_key(:ssh_authentication_failed)
end

View File

@ -170,6 +170,8 @@ module Vagrant
# Extra env keys are the remaining opts
extra_env = opts.dup
check_cwd # Warns the UI if the machine was last used on a different dir
# Create a deterministic ID for this machine
vf = nil
vf = @env.vagrantfile_name[0] if @env.vagrantfile_name
@ -559,5 +561,26 @@ module Vagrant
return nil if !@data_dir
@data_dir.join("creator_uid")
end
# Checks the current directory for a given machine
# and displays a warning if that machine has moved
# from its previous location on disk. If the machine
# has moved, it prints a warning to the user.
def check_cwd
vagrant_cwd_filepath = @data_dir.join('vagrant_cwd')
vagrant_cwd = if File.exist?(vagrant_cwd_filepath)
File.read(vagrant_cwd_filepath).chomp
end
if vagrant_cwd.nil?
File.write(vagrant_cwd_filepath, @env.cwd)
elsif vagrant_cwd != @env.cwd.to_s
ui.warn(I18n.t(
'vagrant.moved_cwd',
old_wd: vagrant_cwd,
current_wd: @env.cwd.to_s))
File.write(vagrant_cwd_filepath, @env.cwd)
end
end
end
end

View File

@ -23,7 +23,19 @@ module VagrantPlugins
name = argv.pop
with_target_vms(argv) do |vm|
vm.action(:snapshot_delete, snapshot_name: name)
if !vm.provider.capability?(:snapshot_list)
raise Vagrant::Errors::SnapshotNotSupported
end
snapshot_list = vm.provider.capability(:snapshot_list)
if snapshot_list.include? name
vm.action(:snapshot_delete, snapshot_name: name)
else
raise Vagrant::Errors::SnapshotNotFound,
snapshot_name: name,
machine: vm.name.to_s
end
end
# Success, exit status 0

View File

@ -22,8 +22,7 @@ module VagrantPlugins
end
if !vm.provider.capability?(:snapshot_list)
vm.ui.info(I18n.t("vagrant.commands.snapshot.not_supported"))
next
raise Vagrant::Errors::SnapshotNotSupported
end
snapshots = vm.provider.capability(:snapshot_list)

View File

@ -36,7 +36,19 @@ module VagrantPlugins
options[:snapshot_name] = name
with_target_vms(argv) do |vm|
vm.action(:snapshot_restore, options)
if !vm.provider.capability?(:snapshot_list)
raise Vagrant::Errors::SnapshotNotSupported
end
snapshot_list = vm.provider.capability(:snapshot_list)
if snapshot_list.include? name
vm.action(:snapshot_restore, options)
else
raise Vagrant::Errors::SnapshotNotFound,
snapshot_name: name,
machine: vm.name.to_s
end
end
# Success, exit status 0

View File

@ -34,8 +34,7 @@ module VagrantPlugins
name = argv.pop
with_target_vms(argv) do |vm|
if !vm.provider.capability?(:snapshot_list)
vm.ui.info(I18n.t("vagrant.commands.snapshot.not_supported"))
next
raise Vagrant::Errors::SnapshotNotSupported
end
snapshot_list = vm.provider.capability(:snapshot_list)

View File

@ -9,6 +9,7 @@ module VagrantPlugins
def execute
options = {}
options[:tty] = true
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant ssh [options] [name|id] [-- extra ssh args]"
@ -23,6 +24,10 @@ module VagrantPlugins
o.on("-p", "--plain", "Plain mode, leaves authentication up to user") do |p|
options[:plain_mode] = p
end
o.on("-t", "--[no-]tty", "Enables tty when executing an ssh command (defaults to true)") do |t|
options[:tty] = t
end
end
# Parse out the extra args to send to SSH, which is everything
@ -48,7 +53,8 @@ module VagrantPlugins
@logger.debug("Executing single command on remote machine: #{options[:command]}")
env = vm.action(:ssh_run,
ssh_opts: ssh_opts,
ssh_run_command: options[:command],)
ssh_run_command: options[:command],
tty: options[:tty],)
# Exit with the exit status of the command or a 0 if we didn't
# get one.

View File

@ -348,6 +348,14 @@ module VagrantPlugins
auth_methods << "publickey" if ssh_info[:private_key_path]
auth_methods << "password" if ssh_info[:password]
# yanked directly from ruby's Net::SSH, but with `none` last
# TODO: Remove this once Vagrant has updated its dependency on Net:SSH
# to be > 4.1.0, which should include this fix.
cipher_array = Net::SSH::Transport::Algorithms::ALGORITHMS[:encryption].dup
if cipher_array.delete("none")
cipher_array.push("none")
end
# Build the options we'll use to initiate the connection via Net::SSH
common_connect_opts = {
auth_methods: auth_methods,
@ -361,6 +369,7 @@ module VagrantPlugins
timeout: 15,
user_known_hosts_file: [],
verbose: :debug,
encryption: cipher_array,
}
# Connect to SSH, giving it a few tries

10
plugins/guests/kali/guest.rb Executable file
View File

@ -0,0 +1,10 @@
require_relative '../linux/guest'
module VagrantPlugins
module GuestKali
class Guest < VagrantPlugins::GuestLinux::Guest
# Name used for guest detection
GUEST_DETECTION_NAME = "kali".freeze
end
end
end

15
plugins/guests/kali/plugin.rb Executable file
View File

@ -0,0 +1,15 @@
require "vagrant"
module VagrantPlugins
module GuestKali
class Plugin < Vagrant.plugin("2")
name "Kali guest"
description "Kali guest support."
guest(:kali, :debian) do
require_relative "guest"
Guest
end
end
end
end

View File

@ -10,7 +10,7 @@ module VagrantPlugins
# does not exist in /etc/user_attr. TODO
begin
machine.communicate.execute(
"#{machine.config.smartos.suexec_cmd} /usr/sbin/shutdown -y -i5 -g0")
"#{machine.config.smartos.suexec_cmd} /usr/sbin/poweroff")
rescue IOError, Vagrant::Errors::SSHDisconnected
# Ignore, this probably means connection closed because it
# shut down.

View File

@ -0,0 +1,28 @@
require "vagrant/util/shell_quote"
module VagrantPlugins
module GuestSmartos
module Cap
class InsertPublicKey
def self.insert_public_key(machine, contents)
contents = contents.chomp
contents = Vagrant::Util::ShellQuote.escape(contents, "'")
machine.communicate.tap do |comm|
comm.execute <<-EOH.sub(/^ */, '')
if [ -d /usbkey ] && [ "$(zonename)" == "global" ] ; then
printf '#{contents}\\n' >> /usbkey/config.inc/authorized_keys
cp /usbkey/config.inc/authorized_keys ~/.ssh/authorized_keys
else
mkdir -p ~/.ssh
chmod 0700 ~/.ssh
printf '#{contents}\\n' >> ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
fi
EOH
end
end
end
end
end
end

View File

@ -0,0 +1,25 @@
require "vagrant/util/shell_quote"
module VagrantPlugins
module GuestSmartos
module Cap
class RemovePublicKey
def self.remove_public_key(machine, contents)
contents = contents.chomp
contents = Vagrant::Util::ShellQuote.escape(contents, "'")
machine.communicate.tap do |comm|
comm.execute <<-EOH.sub(/^ */, '')
if test -f /usbkey/config.inc/authorized_keys ; then
sed -i '' '/^.*#{contents}.*$/d' /usbkey/config.inc/authorized_keys
fi
if test -f ~/.ssh/authorized_keys ; then
sed -i '' '/^.*#{contents}.*$/d' ~/.ssh/authorized_keys
fi
EOH
end
end
end
end
end
end

View File

@ -31,11 +31,21 @@ module VagrantPlugins
Cap::Halt
end
guest_capability(:smartos, :insert_public_key) do
require_relative "cap/insert_public_key"
Cap::InsertPublicKey
end
guest_capability(:smartos, :mount_nfs_folder) do
require_relative "cap/mount_nfs"
Cap::MountNFS
end
guest_capability(:smartos, :remove_public_key) do
require_relative "cap/remove_public_key"
Cap::RemovePublicKey
end
guest_capability(:smartos, :rsync_installed) do
require_relative "cap/rsync"
Cap::RSync
@ -58,3 +68,4 @@ module VagrantPlugins
end
end
end

View File

@ -13,7 +13,7 @@ module VagrantPlugins
machine.communicate.tap do |comm|
# rsync does not construct any gaps in the path to the target directory
# make sure that all subdirectories are created
comm.execute("mkdir '#{opts[:guestpath]}'")
comm.execute("mkdir -p '#{opts[:guestpath]}'")
end
end
end

View File

@ -145,18 +145,16 @@ module VagrantPlugins
new_provs = []
other_provs = other.provisioners.dup
@provisioners.each do |p|
if p.name
other_p = other_provs.find { |o| p.name == o.name }
if other_p
# There is an override. Take it.
other_p.config = p.config.merge(other_p.config)
other_p.run ||= p.run
next if !other_p.preserve_order
other_p = other_provs.find { |o| p.id == o.id }
if other_p
# There is an override. Take it.
other_p.config = p.config.merge(other_p.config)
other_p.run ||= p.run
next if !other_p.preserve_order
# We're preserving order, delete from other
p = other_p
other_provs.delete(other_p)
end
# We're preserving order, delete from other
p = other_p
other_provs.delete(other_p)
end
# There is an override, merge it into the

View File

@ -9,6 +9,15 @@ module VagrantPlugins
# @return [String]
attr_reader :name
# Internal unique name for this provisioner
# Set to the given :name if exists, otherwise
# it's set as a UUID.
#
# Note: This is for internal use only.
#
# @return [String]
attr_reader :id
# The type of the provisioner that should be registered
# as a plugin.
#
@ -35,6 +44,7 @@ module VagrantPlugins
@logger = Log4r::Logger.new("vagrant::config::vm::provisioner")
@logger.debug("Provisioner defined: #{name}")
@id = name || SecureRandom.uuid
@config = nil
@invalid = false
@name = name

View File

@ -20,7 +20,7 @@ module VagrantPlugins
#
# @param [Vagrant::Machine] machine Machine instance for this driver
def initialize(machine)
if !Vagrant::Util::Which.which("vagrant-compose")
if !Vagrant::Util::Which.which("docker-compose")
raise Errors::DockerComposeNotInstalledError
end
super()

View File

@ -245,14 +245,13 @@ module VagrantPlugins
end
end
# This is the action that is primarily responsible for saving a snapshot
# This is the action that is primarily responsible for restoring 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
raise Vagrant::Errors::VMNotCreatedError
end
b2.use CheckAccessible

View File

@ -7,7 +7,7 @@ module VagrantPlugins
module FreeBSD
module AnsibleInstall
def self.ansible_install(machine, install_mode, ansible_version)
def self.ansible_install(machine, install_mode, ansible_version, pip_args)
if install_mode != :default
raise Ansible::Errors::AnsiblePipInstallIsNotSupported
else

View File

@ -6,7 +6,7 @@ module VagrantPlugins
module SUSE
module AnsibleInstall
def self.ansible_install(machine, install_mode, ansible_version)
def self.ansible_install(machine, install_mode, ansible_version, pip_args)
if install_mode != :default
raise Ansible::Errors::AnsiblePipInstallIsNotSupported
else

View File

@ -249,11 +249,8 @@ module VagrantPlugins
# Don't access user's known_hosts file, except when host_key_checking is enabled.
ssh_options << "-o UserKnownHostsFile=/dev/null" unless config.host_key_checking
# Set IdentitiesOnly=yes to avoid authentication errors when the host has more than 5 ssh keys.
# Notes:
# - Solaris/OpenSolaris/Illumos uses SunSSH which doesn't support the IdentitiesOnly option.
# - this could be improved by sharing logic with lib/vagrant/util/ssh.rb
ssh_options << "-o IdentitiesOnly=yes" unless Vagrant::Util::Platform.solaris?
# Compare to lib/vagrant/util/ssh.rb
ssh_options << "-o IdentitiesOnly=yes" if !Vagrant::Util::Platform.solaris? && @ssh_info[:keys_only]
# Multiple Private Keys
unless !config.inventory_path && @ssh_info[:private_key_path].size == 1

View File

@ -22,6 +22,9 @@ en:
Successfully added box '%{name}' (v%{version}) for '%{provider}'!
box_adding_direct: |-
Box file was not detected as metadata. Adding it directly...
box_add_url_warn: |-
It looks like you attempted to add a box with a URL for the name...
Instead, use box_url instead of box for box URLs.
box_downloading: |-
Downloading: %{url}
box_download_error: |-
@ -162,6 +165,10 @@ en:
description of what they do.
%{list}
moved_cwd: |-
This machine used to live in %{old_wd} but it's now at %{current_wd}.
Please change the name of the machine if you want to run it as a different
machine.
guest_deb_installing_smb: |-
Installing SMB "mount.cifs"...
global_status_footer: |-
@ -1158,6 +1165,15 @@ en:
guest system. Please report a bug with your Vagrantfile and debug log.
snapshot_force: |-
You must include the `--force` option to replace an existing 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.
snapshot_not_found: |-
The snapshot name `%{snapshot_name}` was not found for the
virtual machine `%{machine}`.
ssh_authentication_failed: |-
SSH authentication failed! This is typically caused by the public/private
keypair for the SSH user not being properly set on the guest VM. Please
@ -1539,7 +1555,7 @@ en:
unexpected errors. To learn more about this, and the options that are available,
please refer to the Vagrant documentation:
https://www.vagrantup.com/docs/other/wsl
https://www.vagrantup.com/docs/other/wsl.html
wsl_virtualbox_windows_access: |-
Vagrant is unable to use the VirtualBox provider from the Windows Subsystem for
Linux without access to the Windows environment. Enabling this access must be
@ -1547,7 +1563,7 @@ en:
on enabing Windows access and using VirtualBox from the Windows Subsystem for
Linux, please refer to the Vagrant documentation:
https://www.vagrantup.com/docs/other/wsl
https://www.vagrantup.com/docs/other/wsl.html
#-------------------------------------------------------------------------------
# Translations for config validation errors
#-------------------------------------------------------------------------------

View File

@ -0,0 +1,97 @@
require File.expand_path("../../../../../base", __FILE__)
require Vagrant.source_root.join("plugins/commands/snapshot/command/delete")
describe VagrantPlugins::CommandSnapshot::Command::Delete 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(machine.provider).to receive(:capability).with(:snapshot_list).
and_return([])
allow(machine.provider).to receive(:capability?).with(:snapshot_list).
and_return(true)
allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
end
describe "execute" do
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with an unsupported provider" do
let(:argv) { ["test"] }
before do
allow(machine.provider).to receive(:capability?).with(:snapshot_list).
and_return(false)
end
it "raises an exception" do
machine.id = "foo"
expect { subject.execute }.
to raise_error(Vagrant::Errors::SnapshotNotSupported)
end
end
context "with a snapshot name given" do
let(:argv) { ["test"] }
it "calls snapshot_delete with a snapshot name" do
machine.id = "foo"
allow(machine.provider).to receive(:capability).with(:snapshot_list).
and_return(["test"])
expect(machine).to receive(:action) do |name, opts|
expect(name).to eq(:snapshot_delete)
expect(opts[:snapshot_name]).to eq("test")
end
expect(subject.execute).to eq(0)
end
it "doesn't delete a snapshot on a non-existent machine" do
machine.id = nil
expect(subject).to receive(:with_target_vms){}
expect(machine).to_not receive(:action)
expect(subject.execute).to eq(0)
end
end
context "with a snapshot name that doesn't exist" do
let(:argv) { ["nopetest"] }
it "fails to take a snapshot and prints a warning to the user" do
machine.id = "foo"
allow(machine.provider).to receive(:capability).with(:snapshot_list).
and_return(["test"])
expect(machine).to_not receive(:action)
expect { subject.execute }.
to raise_error(Vagrant::Errors::SnapshotNotFound)
end
end
end
end

View File

@ -0,0 +1,83 @@
require File.expand_path("../../../../../base", __FILE__)
require Vagrant.source_root.join("plugins/commands/snapshot/command/list")
describe VagrantPlugins::CommandSnapshot::Command::List 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(machine.provider).to receive(:capability?).with(:snapshot_list).
and_return(true)
allow(machine.provider).to receive(:capability).with(:snapshot_list).
and_return([])
allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
end
describe "execute" do
context "with an unsupported provider" do
let(:argv) { ["foo"] }
before do
allow(machine.provider).to receive(:capability?).with(:snapshot_list).
and_return(false)
end
it "raises an exception" do
machine.id = "foo"
expect { subject.execute }.
to raise_error(Vagrant::Errors::SnapshotNotSupported)
end
end
context "with a vm given" do
let(:argv) { ["foo"] }
it "prints a message if the vm does not exist" do
machine.id = nil
expect(iso_env.ui).to receive(:info).with { |message, _|
expect(message).to include("VM not created")
}
expect(machine).to_not receive(:action)
expect(subject.execute).to eq(0)
end
it "prints a message if no snapshots have been taken" do
machine.id = "foo"
expect(iso_env.ui).to receive(:output)
.with(/No snapshots have been taken yet!/, anything)
expect(subject.execute).to eq(0)
end
it "prints a list of snapshots" do
machine.id = "foo"
allow(machine.provider).to receive(:capability).with(:snapshot_list).
and_return(["foo", "bar", "baz"])
expect(iso_env.ui).to receive(:output).with(/foo/, anything)
expect(iso_env.ui).to receive(:output).with(/bar/, anything)
expect(iso_env.ui).to receive(:output).with(/baz/, anything)
expect(subject.execute).to eq(0)
end
end
end
end

View File

@ -0,0 +1,97 @@
require File.expand_path("../../../../../base", __FILE__)
require Vagrant.source_root.join("plugins/commands/snapshot/command/restore")
describe VagrantPlugins::CommandSnapshot::Command::Restore 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(machine.provider).to receive(:capability).with(:snapshot_list).
and_return([])
allow(machine.provider).to receive(:capability?).with(:snapshot_list).
and_return(true)
allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
end
describe "execute" do
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with an unsupported provider" do
let(:argv) { ["test"] }
before do
allow(machine.provider).to receive(:capability?).with(:snapshot_list).
and_return(false)
end
it "raises an exception" do
machine.id = "foo"
expect { subject.execute }.
to raise_error(Vagrant::Errors::SnapshotNotSupported)
end
end
context "with a snapshot name given" do
let(:argv) { ["test"] }
it "calls snapshot_delete with a snapshot name" do
machine.id = "foo"
allow(machine.provider).to receive(:capability).with(:snapshot_list).
and_return(["test"])
expect(machine).to receive(:action) do |name, opts|
expect(name).to eq(:snapshot_restore)
expect(opts[:snapshot_name]).to eq("test")
end
expect(subject.execute).to eq(0)
end
it "doesn't delete a snapshot on a non-existent machine" do
machine.id = nil
expect(subject).to receive(:with_target_vms){}
expect(machine).to_not receive(:action)
expect(subject.execute).to eq(0)
end
end
context "with a snapshot name that doesn't exist" do
let(:argv) { ["nopetest"] }
it "fails to take a snapshot and prints a warning to the user" do
machine.id = "foo"
allow(machine.provider).to receive(:capability).with(:snapshot_list).
and_return(["test"])
expect(machine).to_not receive(:action)
expect { subject.execute }.
to raise_error(Vagrant::Errors::SnapshotNotFound)
end
end
end
end

View File

@ -38,6 +38,21 @@ describe VagrantPlugins::CommandSnapshot::Command::Save do
end
end
context "with an unsupported provider" do
let(:argv) { ["test"] }
before do
allow(machine.provider).to receive(:capability?).with(:snapshot_list).
and_return(false)
end
it "raises an exception" do
machine.id = "foo"
expect { subject.execute }.
to raise_error(Vagrant::Errors::SnapshotNotSupported)
end
end
context "with a snapshot name given" do
let(:argv) { ["test"] }
it "calls snapshot_save with a snapshot name" do

View File

@ -396,6 +396,20 @@ describe VagrantPlugins::CommunicatorSSH::Communicator do
).and_return(true)
communicator.send(:connect)
end
it "includes the default cipher array for encryption" do
cipher_array = %w(aes128-cbc 3des-cbc blowfish-cbc cast128-cbc
aes192-cbc aes256-cbc rijndael-cbc@lysator.liu.se
idea-cbc arcfour128 arcfour256 arcfour
aes128-ctr aes192-ctr aes256-ctr
cast128-ctr blowfish-ctr 3des-ctr none)
expect(Net::SSH).to receive(:start).with(
nil, nil, hash_including(
encryption: cipher_array
)
).and_return(true)
communicator.send(:connect)
end
end
context "with keys_only disabled and paranoid enabled" do

View File

@ -5,7 +5,7 @@ describe "VagrantPlugins::GuestSmartos::Cap::Halt" do
let(:machine) { double("machine") }
let(:config) { double("config", smartos: double("smartos", suexec_cmd: 'pfexec')) }
let(:communicator) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
let(:shutdown_command){ "pfexec /usr/sbin/shutdown -y -i5 -g0" }
let(:shutdown_command){ "pfexec /usr/sbin/poweroff" }
before do
machine.stub(:communicate).and_return(communicator)

View File

@ -0,0 +1,38 @@
require_relative "../../../../base"
describe "VagrantPlugins::GuestSmartos::Cap::InsertPublicKey" do
let(:caps) do
VagrantPlugins::GuestSmartos::Plugin
.components
.guest_capabilities[:smartos]
end
let(:machine) { double("machine") }
let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
before do
allow(machine).to receive(:communicate).and_return(comm)
end
after do
comm.verify_expectations!
end
describe ".insert_public_key" do
let(:cap) { caps.get(:insert_public_key) }
it "inserts the public key" do
cap.insert_public_key(machine, "ssh-rsa ...")
expect(comm.received_commands[0]).to match(/if \[ -d \/usbkey \] && \[ "\$\(zonename\)" == "global" \] ; then/)
expect(comm.received_commands[0]).to match(/printf 'ssh-rsa ...\\n' >> \/usbkey\/config.inc\/authorized_keys/)
expect(comm.received_commands[0]).to match(/cp \/usbkey\/config.inc\/authorized_keys ~\/.ssh\/authorized_keys/)
expect(comm.received_commands[0]).to match(/else/)
expect(comm.received_commands[0]).to match(/mkdir -p ~\/.ssh/)
expect(comm.received_commands[0]).to match(/chmod 0700 ~\/.ssh/)
expect(comm.received_commands[0]).to match(/printf 'ssh-rsa ...\\n' >> ~\/.ssh\/authorized_keys/)
expect(comm.received_commands[0]).to match(/chmod 0600 ~\/.ssh\/authorized_keys/)
expect(comm.received_commands[0]).to match(/fi/)
end
end
end

View File

@ -0,0 +1,34 @@
require_relative "../../../../base"
describe "VagrantPlugins::GuestSmartos::Cap::RemovePublicKey" do
let(:caps) do
VagrantPlugins::GuestSmartos::Plugin
.components
.guest_capabilities[:smartos]
end
let(:machine) { double("machine") }
let(:comm) { VagrantTests::DummyCommunicator::Communicator.new(machine) }
before do
allow(machine).to receive(:communicate).and_return(comm)
end
after do
comm.verify_expectations!
end
describe ".remove_public_key" do
let(:cap) { caps.get(:remove_public_key) }
it "removes the public key" do
cap.remove_public_key(machine, "ssh-rsa keyvalue comment")
expect(comm.received_commands[0]).to match(/if test -f \/usbkey\/config.inc\/authorized_keys ; then/)
expect(comm.received_commands[0]).to match(/sed -i '' '\/\^.*ssh-rsa keyvalue comment.*\$\/d' \/usbkey\/config.inc\/authorized_keys/)
expect(comm.received_commands[0]).to match(/fi/)
expect(comm.received_commands[0]).to match(/if test -f ~\/.ssh\/authorized_keys ; then/)
expect(comm.received_commands[0]).to match(/sed -i '' '\/\^.*ssh-rsa keyvalue comment.*\$\/d' ~\/.ssh\/authorized_keys/)
expect(comm.received_commands[0]).to match(/fi/)
end
end
end

View File

@ -19,7 +19,7 @@ describe "VagrantPlugins::GuestWindows::Cap::RSync" do
describe ".rsync_pre" do
it 'makes the guestpath directory with mkdir' do
communicator.expect_command("mkdir '/sync_dir'")
communicator.expect_command("mkdir -p '/sync_dir'")
described_class.rsync_pre(machine, guestpath: '/sync_dir')
end
end

View File

@ -424,6 +424,24 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
expect{ subject.finalize! }.to_not raise_error
end
it "generates a uuid if no name was provided" do
allow(SecureRandom).to receive(:uuid).and_return("MY_CUSTOM_VALUE")
subject.provision("shell", path: "foo") { |s| s.inline = "foo" }
subject.finalize!
r = subject.provisioners
expect(r[0].id).to eq("MY_CUSTOM_VALUE")
end
it "sets id as name if a name was provided" do
subject.provision("ghost", type: "shell", path: "motoko") { |s| s.inline = "motoko" }
subject.finalize!
r = subject.provisioners
expect(r[0].id).to eq(:ghost)
end
describe "merging" do
it "ignores non-overriding runs" do
subject.provision("shell", inline: "foo", run: "once")
@ -439,6 +457,16 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
expect(merged_provs[1].run).to eq("always")
end
it "does not merge duplicate provisioners" do
subject.provision("shell", inline: "foo")
subject.provision("shell", inline: "bar")
merged = subject.merge(subject)
merged_provs = merged.provisioners
expect(merged_provs.length).to eql(2)
end
it "copies the configs" do
subject.provision("shell", inline: "foo")
subject_provs = subject.provisioners

View File

@ -40,6 +40,7 @@ VF
let(:config) { VagrantPlugins::Ansible::Config::Host.new }
let(:ssh_info) {{
private_key_path: ['/path/to/my/key'],
keys_only: true,
username: 'testuser',
host: '127.0.0.1',
port: 2223
@ -988,5 +989,20 @@ VF
end
end
describe 'with config.ssh.keys_only = false' do
it 'does not set IdentitiesOnly=yes in ANSIBLE_SSH_ARGS' do
ssh_info[:keys_only] = false
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
cmd_opts = args.last
expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to_not include("-o IdentitiesOnly=yes")
# Ending this block with a negative expectation (to_not / not_to)
# would lead to a failure of the above expectation.
true
}
end
end
end
end

View File

@ -280,6 +280,31 @@ describe Vagrant::Action::Builtin::BoxAdd, :skip_windows do
subject.call(env)
end
context "with a box name accidentally set as a URL" do
it "displays a warning to the user" do
box_path = iso_env.box2_file(:virtualbox)
with_web_server(box_path) do |port|
box_url_name = "http://127.0.0.1:#{port}/#{box_path.basename}"
env[:box_name] = box_url_name
expect(box_collection).to receive(:add).with { |path, name, version, **opts|
expect(name).to eq(box_url_name)
expect(version).to eq("0")
expect(opts[:metadata_url]).to be_nil
true
}.and_return(box)
expect(app).to receive(:call).with(env)
expect(env[:ui]).to receive(:warn)
.with(/It looks like you attempted to add a box with a URL for the name/)
subject.call(env)
end
end
end
context "with URL containing credentials" do
let(:username){ "box-username" }
let(:password){ "box-password" }

View File

@ -0,0 +1,83 @@
require File.expand_path("../../../../base", __FILE__)
describe Vagrant::Action::Builtin::SSHRun do
let(:app) { lambda { |env| } }
let(:env) { { machine: machine, tty: true } }
# SSH configuration information mock
let(:ssh) do
double("ssh",
timeout: 1,
host: nil,
port: 5986,
guest_port: 5986,
pty: false,
keep_alive: false,
insert_key: false,
shell: 'bash -l'
)
end
# Configuration mock
let(:config) { double("config", ssh: ssh) }
let(:machine) do
double("machine",
config: config,)
end
let(:machine_ssh_info) { {} }
let(:ssh_klass) { Vagrant::Util::SSH }
before(:each) do
# Stub the methods so that even if we test incorrectly, no side
# effects actually happen.
allow(ssh_klass).to receive(:exec)
allow(machine).to receive(:ssh_info).and_return(machine_ssh_info)
end
it "should raise an exception if SSH is not ready" do
not_ready_machine = double("machine")
allow(not_ready_machine).to receive(:ssh_info).and_return(nil)
env[:machine] = not_ready_machine
expect { described_class.new(app, env).call(env) }.
to raise_error(Vagrant::Errors::SSHNotReady)
end
it "should exec with the SSH info in the env if given" do
ssh_info = { foo: :bar }
opts = {:extra_args=>["-t", "bash -l -c 'echo test'"], :subprocess=>true}
expect(ssh_klass).to receive(:exec).
with(ssh_info, opts)
env[:ssh_info] = ssh_info
env[:ssh_run_command] = "echo test"
described_class.new(app, env).call(env)
end
it "should exec with the SSH info in the env if given and disable tty" do
ssh_info = { foo: :bar }
opts = {:extra_args=>["bash -l -c 'echo test'"], :subprocess=>true}
env[:tty] = false
expect(ssh_klass).to receive(:exec).
with(ssh_info, opts)
env[:ssh_info] = ssh_info
env[:ssh_run_command] = "echo test"
described_class.new(app, env).call(env)
end
it "should exec with the options given in `ssh_opts`" do
ssh_opts = { foo: :bar }
expect(ssh_klass).to receive(:exec).
with(machine_ssh_info, ssh_opts)
env[:ssh_opts] = ssh_opts
env[:ssh_run_command] = "echo test"
described_class.new(app, env).call(env)
end
end

View File

@ -307,6 +307,45 @@ describe Vagrant::Machine do
expect { instance.action(action_name) }.
to raise_error(Vagrant::Errors::UnimplementedProviderAction)
end
it 'should not warn if the machines cwd has not changed' do
initial_action_name = :up
second_action_name = :reload
callable = lambda { |_env| }
original_cwd = env.cwd.to_s
allow(provider).to receive(:action).with(initial_action_name).and_return(callable)
allow(provider).to receive(:action).with(second_action_name).and_return(callable)
allow(subject.ui).to receive(:warn)
instance.action(initial_action_name)
expect(subject.ui).to_not have_received(:warn)
instance.action(second_action_name)
expect(subject.ui).to_not have_received(:warn)
end
it 'should warn if the machine was last run under a different directory' do
action_name = :up
callable = lambda { |_env| }
original_cwd = env.cwd.to_s
allow(provider).to receive(:action).with(action_name).and_return(callable)
allow(subject.ui).to receive(:warn)
instance.action(action_name)
expect(subject.ui).to_not have_received(:warn)
# Whenever the machine is run on a different directory, the user is warned
allow(env).to receive(:cwd).and_return('/a/new/path')
instance.action(action_name)
expect(subject.ui).to have_received(:warn) do |warn_msg|
expect(warn_msg).to include(original_cwd)
expect(warn_msg).to include('/a/new/path')
end
end
end
describe "#action_raw" do

View File

@ -1,3 +1,3 @@
source "https://rubygems.org"
gem "middleman-hashicorp", "0.3.22"
gem "middleman-hashicorp", "0.3.26"

View File

@ -6,7 +6,7 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
autoprefixer-rails (6.7.7.1)
autoprefixer-rails (7.1.1)
execjs
bootstrap-sass (3.3.7)
autoprefixer-rails (>= 5.2.1)
@ -42,14 +42,15 @@ GEM
eventmachine (1.2.3)
execjs (2.7.0)
ffi (1.9.18)
haml (4.0.7)
haml (5.0.1)
temple (>= 0.8.0)
tilt
hike (1.2.3)
hooks (0.4.1)
uber (~> 0.0.14)
http_parser.rb (0.6.0)
i18n (0.7.0)
json (2.0.3)
json (2.1.0)
kramdown (1.13.2)
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
@ -77,7 +78,7 @@ GEM
rack (>= 1.4.5, < 2.0)
thor (>= 0.15.2, < 2.0)
tilt (~> 1.4.1, < 2.0)
middleman-hashicorp (0.3.22)
middleman-hashicorp (0.3.26)
bootstrap-sass (~> 3.3)
builder (~> 3.2)
middleman (~> 3.4)
@ -100,18 +101,18 @@ GEM
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mini_portile2 (2.1.0)
minitest (5.10.1)
mini_portile2 (2.2.0)
minitest (5.10.2)
multi_json (1.12.1)
nokogiri (1.7.1)
mini_portile2 (~> 2.1.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
padrino-helpers (0.12.8.1)
i18n (~> 0.6, >= 0.6.7)
padrino-support (= 0.12.8.1)
tilt (~> 1.4.1)
padrino-support (0.12.8.1)
activesupport (>= 3.1)
rack (1.6.5)
rack (1.6.8)
rack-livereload (0.3.16)
rack
rack-test (0.6.3)
@ -121,7 +122,7 @@ GEM
ffi (>= 0.5.0)
redcarpet (3.4.0)
rouge (2.0.7)
sass (3.4.23)
sass (3.4.24)
sprockets (2.12.4)
hike (~> 1.2)
multi_json (~> 1.0)
@ -132,26 +133,27 @@ GEM
sprockets-sass (1.3.1)
sprockets (~> 2.0)
tilt (~> 1.1)
temple (0.8.0)
thor (0.19.4)
thread_safe (0.3.6)
tilt (1.4.1)
turbolinks (5.0.1)
turbolinks-source (~> 5)
turbolinks-source (5.0.0)
turbolinks-source (5.0.3)
tzinfo (1.2.3)
thread_safe (~> 0.1)
uber (0.0.15)
uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
xpath (2.0.0)
xpath (2.1.0)
nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
middleman-hashicorp (= 0.3.22)
middleman-hashicorp (= 0.3.26)
BUNDLED WITH
1.14.6

View File

@ -1,4 +1,4 @@
VERSION?="0.3.22"
VERSION?="0.3.26"
build:
@echo "==> Starting build in Docker..."

View File

@ -8,7 +8,7 @@
"builders": [
{
"type": "docker",
"image": "hashicorp/middleman-hashicorp:0.3.22",
"image": "hashicorp/middleman-hashicorp:0.3.26",
"discard": "true",
"run_command": ["-d", "-i", "-t", "{{ .Image }}", "/bin/sh"]
}

View File

@ -69,8 +69,8 @@ $ vagrant init hashicorp/precise64
or you can update your `Vagrantfile` as follows:
```ruby
Vagrant.configure("2") do
config.box = "hashicorp/precise64"
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
end
```

View File

@ -16,13 +16,13 @@ This is the command used to manage (add, remove, etc.) [boxes](/docs/boxes.html)
The main functionality of this command is exposed via even more subcommands:
* `add`
* `list`
* `outdated`
* `prune`
* `remove`
* `repackage`
* `update`
* [`add`](#box-add)
* [`list`](#box-list)
* [`outdated`](#box-outdated)
* [`prune`](#box-prune)
* [`remove`](#box-remove)
* [`repackage`](#box-repackage)
* [`update`](#box-update)
# Box Add

View File

@ -165,7 +165,7 @@ jailbreak by setting `VAGRANT_SKIP_SUBPROCESS_JAILBREAK`.
## `VAGRANT_VAGRANTFILE`
This specifies the filename of the Vagrantfile that Vagrant searches for.
By default, this is "Vagrantfile." Note that this is _not_ a file path,
By default, this is "Vagrantfile". Note that this is _not_ a file path,
but just a filename.
This environmental variable is commonly used in scripting environments

View File

@ -7,19 +7,116 @@ sidebar_current: "vagrant-cloud-migration"
# Vagrant Cloud Migration
Vagrant-related functionality will be moved from Terraform Enterprise into its own product, Vagrant Cloud.
This migration is currently planned for **June 27th, 2017**.
This migration is currently planned for **June 27th, 2017** at 6PM EDT/3PM PDT/10PM UTC.
All existing Vagrant boxes will be moved to the new system on that date.
All existing Vagrant boxes will be moved to the new system at that time.
All users, organizations, and teams will be copied as well.
~> If you only use Vagrant to download and run public boxes, then nothing is changing.
~> All box names, versions, and URLs will stay the same (or redirect) with no changes to your workflow or Vagrantfiles.
## Vagrant Boxes, Users, Organizations, and Teams
All Vagrant boxes will be moved to the new Vagrant Cloud on June 27th.
Additionally, all users and organizations will be copied.
Any existing box collaborations or team ACLs will persist into the new system.
All existing box names (hashicorp/precise64) and URLs will continue working as-is, or permanently redirect to the correct location.
If youre only using public Vagrant boxes, no changes will be required to your Vagrantfiles or workflow.
Users of private Vagrant boxes will need to create a new authentication (see below), and activate their Vagrant Cloud account after the migration has completed.
Vagrant Cloud users and organizations will be considered inactive in the future if they have not logged into Vagrant Cloud after the migration and do not have any published Vagrant boxes.
Inactive user accounts will be deleted on or after October 1st, 2017.
## Vagrant Cloud Account Activation
In order to begin using Vagrant Cloud with your Atlas account, you will first need to activate your Vagrant Cloud account.
This will require you to login to Atlas, as well as confirm your password (and 2FA credentials, if configured).
There will be links and instructions on the Vagrant Cloud login screen directing you to do this.
During Vagrant Cloud account activation, you will create a new password for Vagrant Cloud and optionally configure 2FA.
Your pre-existing Atlas account, password, and 2FA configuration will remain unchanged within Atlas.
~> New users of Vagrant Cloud can always create a new account for free, at any time.
## Authentication Tokens
No existing Terraform Enterprise authentication tokens will be transferred.
To prevent a disruption of service for Vagrant-related operations, users must create a new authentication token and check "Migrate to Vagrant Cloud" and begin using these tokens for creating and modifying Vagrant boxes.
These tokens will be moved on the migration date.
If you are currently using an authentication token to interact with Atlas for Vagrant features, you will need to generate a new Vagrant Cloud token prior to June 27th.
You can see your existing tokens and generate new tokens on the Tokens page of your account settings.
Creating a token via `vagrant login` will also mark a token as "Migrate to Vagrant Cloud".
When creating this new token, select Migrate to Vagrant Cloud.
## More Information
You can see which authentication tokens which will be copied to Vagrant Cloud in the token list.
At least 1 month prior to the migration, we will be releasing more information on the specifics and impact of the migration.
Only these authentication tokens will be moved to Vagrant Cloud on June 27th.
They will also be removed from Terraform Enterprise at this time, and will no longer work for Terraform or Packer operations.
If you do not create a token in Atlas by June 27th, you will need to create a token within Vagrant Cloud after the migration.
~> Creating a token in Atlas via `vagrant login` will also mark a token as "Migrate to Vagrant Cloud".
## Packer and Terraform Enterprise
Packer has two post-processors which can create Vagrant boxes in Terraform Enterprise (Atlas): `atlas` and `vagrant-cloud`.
The `atlas post-processor` will no longer create Vagrant boxes after June 27th.
If you are currently publishing Vagrant boxes with Packer, please ensure that you are using the vagrant-cloud post-processor.
For example, if your Packer post-processor JSON looks like this:
```json
{
"variables": {
"atlas_token": "{{env `ATLAS_TOKEN`}}",
"version": "1.0.{{timestamp}}"
},
"builders": [
],
"post-processors": [
{
"type": "atlas",
"token": "{{user `atlas_token`}}",
"artifact": "hashicorp/example",
"artifact_type": "vagrant.box",
"metadata": {
"version": "{{user `version`}}"
}
}
]
}
```
You must replace the `atlas` post-processor with the `vagrant` and `vagrant-cloud` post-processors (note the nested array, which tells Packer to run these steps serially).
```json
{
"variables": {
"vagrantcloud_token": "{{env `VAGRANTCLOUD_TOKEN`}}",
"version": "1.0.{{timestamp}}"
},
"builders": [
],
"post-processors": [
[
{
"type": "vagrant",
"output": "output.box"
},
{
"type": "vagrant-cloud",
"access_token": "{{user `vagrantcloud_token`}}",
"box_tag": "hashicorp/example",
"version": "{{user `version`}}"
}
]
]
}
```
## Vagrant Share
Vagrant Share via Atlas has been deprecated, and instead Vagrant supports native integration with [ngrok](https://ngrok.com).
Users of Vagrant Share should switch to the [ngrok-powered Vagrant Share driver](https://www.vagrantup.com/docs/share/ngrok.html) prior to June 27th, which will become the default in the next version of Vagrant
## Downtime
There will be a brief outage of Vagrant services within Atlas/Terraform Enterprise on June 27th at 6PM EDT/3PM PDT until the migration is complete.
We estimate that this will take less than 30 minutes.