Merge branch 'master' into winrm_error_handling
This commit is contained in:
commit
edc867986b
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -1,3 +1,29 @@
|
|||
## 1.7.2 (unreleased)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- provisioners/salt: add support for grains [GH-4895]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- core: private boxes still referencing vagrantcloud.com will have
|
||||
their vagrant login access token properly appended
|
||||
- commands/push: push lookups are by user-defined name, not push
|
||||
strategy name [GH-4975]
|
||||
- guests/arch: fix network configuration due to poor line breaks. [GH-4964]
|
||||
- provisioners/chef: remove Chef version check from solo.rb generation and
|
||||
make `roles_path` populate correctly
|
||||
|
||||
## 1.7.1 (December 11, 2014)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- provisioners/ansible: Use Docker proxy if needed. [GH-4906]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- providers/docker: Add support of SSH agent forwarding. [GH-4905]
|
||||
|
||||
## 1.7.0 (December 9, 2014)
|
||||
|
||||
BREAKING CHANGES:
|
||||
|
@ -102,6 +128,7 @@ BUG FIXES:
|
|||
- provisioners/ansible: Force `ssh` (OpenSSH) connection by default [GH-3396]
|
||||
- provisioners/ansible: Don't use or modify `~/.ssh/known_hosts` file by default,
|
||||
similarly to native vagrant commands [GH-3900]
|
||||
- provisioners/ansible: Use intermediate Docker host when needed. [GH-4071]
|
||||
- provisioners/docker: Get GPG key over SSL. [GH-4597]
|
||||
- provisioners/docker: Search for docker binary in multiple places. [GH-4580]
|
||||
- provisioners/salt: Highstate works properly with a master. [GH-4471]
|
||||
|
|
|
@ -13,6 +13,14 @@ Vagrant.configure("2") do |config|
|
|||
end
|
||||
|
||||
config.vm.provision "shell", inline: $shell
|
||||
|
||||
config.push.define "www", strategy: "local-exec" do |push|
|
||||
push.script = "scripts/website_push_www.sh"
|
||||
end
|
||||
|
||||
config.push.define "docs", strategy: "local-exec" do |push|
|
||||
push.script = "scripts/website_push_docs.sh"
|
||||
end
|
||||
end
|
||||
|
||||
$shell = <<-CONTENTS
|
||||
|
|
|
@ -0,0 +1,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
|
|
@ -83,10 +83,7 @@ module VagrantPlugins
|
|||
false
|
||||
rescue RestClient::NotAcceptable => e
|
||||
begin
|
||||
errors = JSON.parse(e.response)["errors"]
|
||||
.map { |h| h["message"] }
|
||||
.join("\n")
|
||||
|
||||
errors = JSON.parse(e.response)["errors"].join("\n")
|
||||
raise Errors::ServerError, errors: errors
|
||||
rescue JSON::ParserError; end
|
||||
|
||||
|
|
|
@ -18,7 +18,17 @@ module VagrantPlugins
|
|||
|
||||
env[:box_urls].map! do |url|
|
||||
u = URI.parse(url)
|
||||
if u.host == server_uri.host
|
||||
replace = u.host == server_uri.host
|
||||
if !replace
|
||||
# We need this in here for the transition we made from
|
||||
# Vagrant Cloud to Atlas. This preserves access tokens
|
||||
# appending to both without leaking access tokens to
|
||||
# unsavory URLs.
|
||||
replace = u.host == "vagrantcloud.com" &&
|
||||
server_uri.host == "atlas.hashicorp.com"
|
||||
end
|
||||
|
||||
if replace
|
||||
u.query ||= ""
|
||||
u.query += "&" if u.query != ""
|
||||
u.query += "access_token=#{token}"
|
||||
|
|
|
@ -80,7 +80,7 @@ module VagrantPlugins
|
|||
acc
|
||||
end
|
||||
|
||||
vm.action(:package, opts)
|
||||
vm.action(:package, **opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -51,17 +51,19 @@ module VagrantPlugins
|
|||
if pushes.length == 1
|
||||
return pushes.first.to_sym
|
||||
else
|
||||
raise Vagrant::Errors::PushStrategyNotProvided, pushes: pushes
|
||||
raise Vagrant::Errors::PushStrategyNotProvided,
|
||||
pushes: pushes.map(&:to_s)
|
||||
end
|
||||
end
|
||||
|
||||
name = name.to_sym
|
||||
if !pushes.include?(name)
|
||||
raise Vagrant::Errors::PushStrategyNotDefined,
|
||||
name: name,
|
||||
pushes: pushes
|
||||
name: name.to_s,
|
||||
pushes: pushes.map(&:to_s)
|
||||
end
|
||||
|
||||
return name.to_sym
|
||||
return name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -146,12 +146,21 @@ module VagrantPlugins
|
|||
alias_method :sudo, :execute
|
||||
|
||||
def test(command, opts=nil)
|
||||
# If this is a *nix command with no Windows equivilant, assume failure
|
||||
# If this is a *nix command (which we know about) with no Windows
|
||||
# equivilant, assume failure
|
||||
command = @cmd_filter.filter(command)
|
||||
return false if command.empty?
|
||||
|
||||
opts = { error_check: false }.merge(opts || {})
|
||||
execute(command, opts) == 0
|
||||
opts = {
|
||||
command: command,
|
||||
elevated: false,
|
||||
error_check: false,
|
||||
}.merge(opts || {})
|
||||
|
||||
# If we're passed a *nix command which PS can't parse we get exit code
|
||||
# 0, but output in stderr. We need to check both exit code and stderr.
|
||||
output = shell.send(:powershell, command)
|
||||
return output[:exitcode] == 0 && flatten_stderr(output).length == 0
|
||||
end
|
||||
|
||||
def upload(from, to)
|
||||
|
@ -220,8 +229,8 @@ module VagrantPlugins
|
|||
def raise_execution_error(output, opts)
|
||||
# WinRM can return multiple stderr and stdout entries
|
||||
error_opts = opts.merge(
|
||||
stdout: output[:data].collect { |e| e[:stdout] }.join,
|
||||
stderr: output[:data].collect { |e| e[:stderr] }.join
|
||||
stdout: flatten_stdout(output),
|
||||
stderr: flatten_stderr(output)
|
||||
)
|
||||
|
||||
# Use a different error message key if the caller gave us one,
|
||||
|
@ -231,6 +240,20 @@ module VagrantPlugins
|
|||
# Raise the error, use the type the caller gave us or the comm default
|
||||
raise opts[:error_class], error_opts
|
||||
end
|
||||
|
||||
|
||||
# TODO: Replace with WinRM Output class when WinRM 1.3 is released
|
||||
def flatten_stderr(output)
|
||||
output[:data].map do | line |
|
||||
line[:stderr]
|
||||
end.compact.join
|
||||
end
|
||||
|
||||
def flatten_stdout(output)
|
||||
output[:data].map do | line |
|
||||
line[:flatten_stdout]
|
||||
end.compact.join
|
||||
end
|
||||
end #WinRM class
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,20 +11,14 @@ module VagrantPlugins
|
|||
|
||||
def self.configure_networks(machine, networks)
|
||||
interfaces = Array.new
|
||||
machine.communicate.sudo("ip -o -0 addr | grep -v LOOPBACK | awk
|
||||
'{print $2}' | sed 's/://'") do |_, result|
|
||||
machine.communicate.sudo("ip -o -0 addr | grep -v LOOPBACK | awk '{print $2}' | sed 's/://'") do |_, result|
|
||||
interfaces = result.split("\n")
|
||||
end
|
||||
|
||||
networks.each do |network|
|
||||
# We use :device in the template instead of
|
||||
# eth#{network[:interface]} in order to support Predictable
|
||||
# Network Interfaces
|
||||
network[:device] = interfaces[network[:interface]]
|
||||
|
||||
entry =
|
||||
TemplateRenderer.render("guests/arch/network_#{network[:type]}",
|
||||
options: network)
|
||||
entry = TemplateRenderer.render("guests/arch/network_#{network[:type]}", options: network)
|
||||
|
||||
temp = Tempfile.new("vagrant")
|
||||
temp.binmode
|
||||
|
@ -32,10 +26,8 @@ module VagrantPlugins
|
|||
temp.close
|
||||
|
||||
machine.communicate.upload(temp.path, "/tmp/vagrant_network")
|
||||
machine.communicate.sudo("mv /tmp/vagrant_network
|
||||
/etc/netctl/#{network[:device]}")
|
||||
machine.communicate.sudo("ip link set #{network[:device]} down &&
|
||||
netctl start #{network[:device]}")
|
||||
machine.communicate.sudo("mv /tmp/vagrant_network /etc/netctl/#{network[:device]}")
|
||||
machine.communicate.sudo("ip link set #{network[:device]} down && netctl start #{network[:device]}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,9 +13,8 @@ module VagrantPlugins
|
|||
machine.communicate.tap do |comm|
|
||||
# First, remove any previous network modifications
|
||||
# from the interface file.
|
||||
comm.sudo("sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces")
|
||||
comm.sudo("su -c 'cat /tmp/vagrant-network-interfaces > /etc/network/interfaces'")
|
||||
comm.sudo("rm -f /tmp/vagrant-network-interfaces")
|
||||
comm.sudo("sed -e '/^#VAGRANT-BEGIN/,$ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces.pre")
|
||||
comm.sudo("sed -ne '/^#VAGRANT-END/,$ p' /etc/network/interfaces | tail -n +2 > /tmp/vagrant-network-interfaces.post")
|
||||
|
||||
# Accumulate the configurations to add to the interfaces file as
|
||||
# well as what interfaces we're actually configuring since we use that
|
||||
|
@ -47,8 +46,8 @@ module VagrantPlugins
|
|||
comm.sudo("/sbin/ip addr flush dev eth#{interface} 2> /dev/null")
|
||||
end
|
||||
|
||||
comm.sudo("cat /tmp/vagrant-network-entry >> /etc/network/interfaces")
|
||||
comm.sudo("rm -f /tmp/vagrant-network-entry")
|
||||
comm.sudo('cat /tmp/vagrant-network-interfaces.pre /tmp/vagrant-network-entry /tmp/vagrant-network-interfaces.post > /etc/network/interfaces')
|
||||
comm.sudo('rm -f /tmp/vagrant-network-interfaces.pre /tmp/vagrant-network-entry /tmp/vagrant-network-interfaces.post')
|
||||
|
||||
# Bring back up each network interface, reconfigured
|
||||
interfaces.each do |interface|
|
||||
|
|
|
@ -21,18 +21,18 @@ module VagrantPlugins
|
|||
|
||||
# Compile all the provider configurations
|
||||
@__defined_pushes.each do |name, tuples|
|
||||
# Find the configuration class for this push
|
||||
config_class = Vagrant.plugin("2").manager.push_configs[name]
|
||||
config_class ||= Vagrant::Config::V2::DummyConfig
|
||||
|
||||
# Load it up
|
||||
config = config_class.new
|
||||
|
||||
# Capture the strategy so we can use it later. This will be used in
|
||||
# the block iteration for merging/overwriting
|
||||
strategy = name
|
||||
strategy = tuples[0][0] if tuples[0]
|
||||
|
||||
# Find the configuration class for this push
|
||||
config_class = Vagrant.plugin("2").manager.push_configs[strategy]
|
||||
config_class ||= Vagrant::Config::V2::DummyConfig
|
||||
|
||||
# Load it up
|
||||
config = config_class.new
|
||||
|
||||
begin
|
||||
tuples.each do |s, b|
|
||||
# Update the strategy if it has changed, reseting the current
|
||||
|
|
|
@ -19,14 +19,19 @@ module VagrantPlugins
|
|||
# Modify the SSH options for when we `vagrant ssh`...
|
||||
ssh_opts = env[:ssh_opts] || {}
|
||||
|
||||
# Build the command we'll execute within the host machine
|
||||
# Build the command we'll execute within the Docker host machine:
|
||||
ssh_command = env[:machine].communicate.container_ssh_command
|
||||
if !Array(ssh_opts[:extra_args]).empty?
|
||||
ssh_command << " #{Array(ssh_opts[:extra_args]).join(" ")}"
|
||||
end
|
||||
|
||||
# Modify the SSH options for the original command:
|
||||
# Append "-t" to force a TTY allocation
|
||||
ssh_opts[:extra_args] = ["-t"]
|
||||
# Enable Agent forwarding when requested for the target VM
|
||||
if env[:machine].ssh_info[:forward_agent]
|
||||
ssh_opts[:extra_args] << "-o ForwardAgent=yes"
|
||||
end
|
||||
ssh_opts[:extra_args] << ssh_command
|
||||
|
||||
# Set the opts
|
||||
|
|
|
@ -137,18 +137,21 @@ module VagrantPlugins
|
|||
info[:port] ||= 22
|
||||
|
||||
# Make sure our private keys are synced over to the host VM
|
||||
key_args = sync_private_keys(info).map do |path|
|
||||
ssh_args = sync_private_keys(info).map do |path|
|
||||
"-i #{path}"
|
||||
end.join(" ")
|
||||
end
|
||||
|
||||
# Use ad-hoc SSH options for the hop on the docker proxy
|
||||
if info[:forward_agent]
|
||||
ssh_args << "-o ForwardAgent=yes"
|
||||
end
|
||||
ssh_args.concat(["-o Compression=yes",
|
||||
"-o ConnectTimeout=5",
|
||||
"-o StrictHostKeyChecking=no",
|
||||
"-o UserKnownHostsFile=/dev/null"])
|
||||
|
||||
# Build the SSH command
|
||||
"ssh #{key_args} " +
|
||||
"-o Compression=yes " +
|
||||
"-o ConnectTimeout=5 " +
|
||||
"-o StrictHostKeyChecking=no " +
|
||||
"-o UserKnownHostsFile=/dev/null " +
|
||||
"-p#{info[:port]} " +
|
||||
"#{info[:username]}@#{info[:host]}"
|
||||
"ssh #{info[:username]}@#{info[:host]} -p#{info[:port]} #{ssh_args.join(" ")}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -188,6 +188,24 @@ module VagrantPlugins
|
|||
def get_ansible_ssh_args
|
||||
ssh_options = []
|
||||
|
||||
# Use an SSH ProxyCommand when using the Docker provider with the intermediate host
|
||||
if @machine.provider_name == :docker && machine.provider.host_vm?
|
||||
docker_host_ssh_info = machine.provider.host_vm.ssh_info
|
||||
|
||||
proxy_cmd = "ssh #{docker_host_ssh_info[:username]}@#{docker_host_ssh_info[:host]}" +
|
||||
" -p #{docker_host_ssh_info[:port]} -i #{docker_host_ssh_info[:private_key_path][0]}"
|
||||
|
||||
# Use same options than plugins/providers/docker/communicator.rb
|
||||
# Note: this could be improved (DRY'ed) by sharing these settings.
|
||||
proxy_cmd += " -o Compression=yes -o ConnectTimeout=5 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||
|
||||
proxy_cmd += " -o ForwardAgent=yes" if @ssh_info[:forward_agent]
|
||||
|
||||
proxy_cmd += " exec nc %h %p 2>/dev/null"
|
||||
|
||||
ssh_options << "-o ProxyCommand='#{ proxy_cmd }'"
|
||||
end
|
||||
|
||||
# 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
|
||||
|
||||
|
|
|
@ -5,11 +5,11 @@ module VagrantPlugins
|
|||
module Cap
|
||||
module Debian
|
||||
module ChefInstall
|
||||
def self.chef_install(machine, version, prerelease)
|
||||
def self.chef_install(machine, version, prerelease, download_path)
|
||||
machine.communicate.sudo("apt-get update -y -qq")
|
||||
machine.communicate.sudo("apt-get install -y -qq curl")
|
||||
|
||||
command = Omnibus.build_command(version, prerelease)
|
||||
command = Omnibus.build_command(version, prerelease, download_path)
|
||||
machine.communicate.sudo(command)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,10 +5,10 @@ module VagrantPlugins
|
|||
module Cap
|
||||
module Redhat
|
||||
module ChefInstall
|
||||
def self.chef_install(machine, version, prerelease)
|
||||
def self.chef_install(machine, version, prerelease, download_path)
|
||||
machine.communicate.sudo("yum install -y -q curl")
|
||||
|
||||
command = Omnibus.build_command(version, prerelease)
|
||||
command = Omnibus.build_command(version, prerelease, download_path)
|
||||
machine.communicate.sudo(command)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,6 +48,14 @@ module VagrantPlugins
|
|||
# @return [String]
|
||||
attr_accessor :version
|
||||
|
||||
# The path where the Chef installer will be downloaded to. Only valid if
|
||||
# install is true or "force". It defaults to nil, which means that the
|
||||
# omnibus installer will choose the destination and you have no control
|
||||
# over it.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :installer_download_path
|
||||
|
||||
def initialize
|
||||
super
|
||||
|
||||
|
@ -57,6 +65,7 @@ module VagrantPlugins
|
|||
@log_level = UNSET_VALUE
|
||||
@prerelease = UNSET_VALUE
|
||||
@version = UNSET_VALUE
|
||||
@installer_download_path = UNSET_VALUE
|
||||
end
|
||||
|
||||
def finalize!
|
||||
|
@ -66,6 +75,7 @@ module VagrantPlugins
|
|||
@log_level = :info if @log_level == UNSET_VALUE
|
||||
@prerelease = false if @prerelease == UNSET_VALUE
|
||||
@version = :latest if @version == UNSET_VALUE
|
||||
@installer_download_path = nil if @installer_download_path == UNSET_VALUE
|
||||
|
||||
# Make sure the install is a symbol if it's not a boolean
|
||||
if @install.respond_to?(:to_sym)
|
||||
|
|
|
@ -6,6 +6,7 @@ module VagrantPlugins
|
|||
@version = options.fetch(:version, :latest)
|
||||
@prerelease = options.fetch(:prerelease, :latest)
|
||||
@force = options.fetch(:force, false)
|
||||
@download_path = options.fetch(:download_path, nil)
|
||||
end
|
||||
|
||||
# This handles verifying the Chef installation, installing it if it was
|
||||
|
@ -27,7 +28,7 @@ module VagrantPlugins
|
|||
|
||||
@machine.ui.detail(I18n.t("vagrant.chef_installing",
|
||||
version: @version.to_s))
|
||||
@machine.guest.capability(:chef_install, @version, @prerelease)
|
||||
@machine.guest.capability(:chef_install, @version, @prerelease, @download_path)
|
||||
|
||||
if !@machine.guest.capability(:chef_installed, @version)
|
||||
raise Provisioner::Base::ChefError, :install_failed
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
module VagrantPlugins
|
||||
module Chef
|
||||
module Omnibus
|
||||
OMNITRUCK = "https://www.getchef.com/chef/install.sh".freeze
|
||||
OMNITRUCK = "https://www.chef.io/chef/install.sh".freeze
|
||||
|
||||
# Read more about the Omnibus installer here:
|
||||
# https://docs.getchef.com/install_omnibus.html
|
||||
def build_command(version, prerelease = false)
|
||||
def build_command(version, prerelease = false, download_path = nil)
|
||||
command = "curl -sL #{OMNITRUCK} | sudo bash"
|
||||
|
||||
if prerelease || version != :latest
|
||||
if prerelease || version != :latest || download_path != nil
|
||||
command << " -s --"
|
||||
end
|
||||
|
||||
|
@ -20,6 +20,10 @@ module VagrantPlugins
|
|||
command << " -v \"#{version}\""
|
||||
end
|
||||
|
||||
if download_path
|
||||
command << " -d \"#{download_path}\""
|
||||
end
|
||||
|
||||
command
|
||||
end
|
||||
module_function :build_command
|
||||
|
|
|
@ -29,6 +29,7 @@ module VagrantPlugins
|
|||
force: config.install == :force,
|
||||
version: config.version,
|
||||
prerelease: config.prerelease,
|
||||
download_path: config.installer_download_path
|
||||
)
|
||||
installer.ensure_installed
|
||||
end
|
||||
|
|
|
@ -12,6 +12,7 @@ module VagrantPlugins
|
|||
attr_accessor :master_config
|
||||
attr_accessor :master_key
|
||||
attr_accessor :master_pub
|
||||
attr_accessor :grains_config
|
||||
attr_accessor :run_highstate
|
||||
attr_accessor :run_overstate
|
||||
attr_accessor :always_install
|
||||
|
@ -38,6 +39,7 @@ module VagrantPlugins
|
|||
@master_config = UNSET_VALUE
|
||||
@master_key = UNSET_VALUE
|
||||
@master_pub = UNSET_VALUE
|
||||
@grains_config = UNSET_VALUE
|
||||
@run_highstate = UNSET_VALUE
|
||||
@run_overstate = UNSET_VALUE
|
||||
@always_install = UNSET_VALUE
|
||||
|
@ -63,6 +65,7 @@ module VagrantPlugins
|
|||
@master_config = nil if @master_config == UNSET_VALUE
|
||||
@master_key = nil if @master_key == UNSET_VALUE
|
||||
@master_pub = nil if @master_pub == UNSET_VALUE
|
||||
@grains_config = nil if @grains_config == UNSET_VALUE
|
||||
@run_highstate = nil if @run_highstate == UNSET_VALUE
|
||||
@run_overstate = nil if @run_overstate == UNSET_VALUE
|
||||
@always_install = nil if @always_install == UNSET_VALUE
|
||||
|
@ -115,6 +118,13 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
if @grains_config
|
||||
expanded = Pathname.new(@grains_config).expand_path(machine.env.root_path)
|
||||
if !expanded.file?
|
||||
errors << I18n.t("vagrant.provisioners.salt.grains_config_nonexist")
|
||||
end
|
||||
end
|
||||
|
||||
if @install_master && !@no_minion && !@seed_master && @run_highstate
|
||||
errors << I18n.t("vagrant.provisioners.salt.must_accept_keys")
|
||||
end
|
||||
|
|
|
@ -75,7 +75,7 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def need_configure
|
||||
@config.minion_config or @config.minion_key or @config.master_config or @config.master_key
|
||||
@config.minion_config or @config.minion_key or @config.master_config or @config.master_key or @config.grains_config
|
||||
end
|
||||
|
||||
def need_install
|
||||
|
@ -181,6 +181,11 @@ module VagrantPlugins
|
|||
@machine.env.ui.info "Copying salt master config to vm."
|
||||
@machine.communicate.upload(expanded_path(@config.master_config).to_s, temp_config_dir + "/master")
|
||||
end
|
||||
|
||||
if @config.grains_config
|
||||
@machine.env.ui.info "Copying salt grains config to vm."
|
||||
@machine.communicate.upload(expanded_path(@config.grains_config).to_s, temp_config_dir + "/grains")
|
||||
end
|
||||
end
|
||||
|
||||
# Copy master and minion keys to VM
|
||||
|
|
|
@ -8,13 +8,13 @@ module VagrantPlugins
|
|||
Run a local command or script to push
|
||||
DESC
|
||||
|
||||
config(:local_exec, :push) do
|
||||
config(:"local-exec", :push) do
|
||||
require File.expand_path("../config", __FILE__)
|
||||
init!
|
||||
Config
|
||||
end
|
||||
|
||||
push(:local_exec) do
|
||||
push(:"local-exec") do
|
||||
require File.expand_path("../push", __FILE__)
|
||||
init!
|
||||
Push
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require "fileutils"
|
||||
require "tempfile"
|
||||
require "vagrant/util/subprocess"
|
||||
require "vagrant/util/safe_exec"
|
||||
|
||||
require_relative "errors"
|
||||
|
||||
|
@ -38,16 +38,7 @@ module VagrantPlugins
|
|||
|
||||
# Execute the script, raising an exception if it fails.
|
||||
def execute!(*cmd)
|
||||
result = Vagrant::Util::Subprocess.execute(*cmd)
|
||||
|
||||
if result.exit_code != 0
|
||||
raise Errors::CommandFailed,
|
||||
cmd: cmd.join(" "),
|
||||
stdout: result.stdout,
|
||||
stderr: result.stderr
|
||||
end
|
||||
|
||||
result
|
||||
Vagrant::Util::SafeExec.exec(cmd[0], *cmd[1..-1])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,5 +8,10 @@ DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"
|
|||
# Change into that directory
|
||||
cd $DIR
|
||||
|
||||
# Add the git remote if it doesn't exist
|
||||
git remote | grep heroku-docs || {
|
||||
git remote add heroku-docs git@heroku.com:vagrantup-docs.git
|
||||
}
|
||||
|
||||
# Push the subtree (force)
|
||||
git push heroku-docs `git subtree split --prefix website/docs master`:master --force
|
||||
|
|
|
@ -8,5 +8,10 @@ DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )"
|
|||
# Change into that directory
|
||||
cd $DIR
|
||||
|
||||
# Add the git remote if it doesn't exist
|
||||
git remote | grep heroku-www || {
|
||||
git remote add heroku-www git@heroku.com:vagrantup-www.git
|
||||
}
|
||||
|
||||
# Push the subtree (force)
|
||||
git push heroku-www `git subtree split --prefix website/www master`:master --force
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
Vagrant.configure(2) do |config|
|
||||
# The most common configuration options are documented and commented below.
|
||||
# For a complete reference, please see the online documentation at
|
||||
# vagrantup.com
|
||||
# https://docs.vagrantup.com.
|
||||
|
||||
# Every Vagrant virtual environment requires a box to build off of.
|
||||
# Every Vagrant development environment requires a box. You can search for
|
||||
# boxes at https://atlas.hashicorp.com/search.
|
||||
config.vm.box = "<%= box_name %>"
|
||||
|
||||
<% if box_url -%>
|
||||
|
@ -38,10 +39,6 @@ Vagrant.configure(2) do |config|
|
|||
# your network.
|
||||
# config.vm.network "public_network"
|
||||
|
||||
# If true, then any SSH connections made will enable agent forwarding.
|
||||
# Default value: false
|
||||
# config.ssh.forward_agent = true
|
||||
|
||||
# Share an additional folder to the guest VM. The first argument is
|
||||
# the path on the host to the actual folder. The second argument is
|
||||
# the path on the guest to mount the folder. And the optional third
|
||||
|
@ -53,134 +50,28 @@ Vagrant.configure(2) do |config|
|
|||
# Example for VirtualBox:
|
||||
#
|
||||
# config.vm.provider "virtualbox" do |vb|
|
||||
# # Don't boot with headless mode
|
||||
# # Display the VirtualBox GUI when booting the machine
|
||||
# vb.gui = true
|
||||
#
|
||||
# # Use VBoxManage to customize the VM. For example to change memory:
|
||||
# vb.customize ["modifyvm", :id, "--memory", "1024"]
|
||||
# # Customize the amount of memory on the VM:
|
||||
# vb.memory = "1024"
|
||||
# end
|
||||
#
|
||||
# View the documentation for the provider you're using for more
|
||||
# View the documentation for the provider you are using for more
|
||||
# information on available options.
|
||||
|
||||
# Enable provisioning with CFEngine. CFEngine Community packages are
|
||||
# automatically installed. For example, configure the host as a
|
||||
# policy server and optionally a policy file to run:
|
||||
#
|
||||
# config.vm.provision "cfengine" do |cf|
|
||||
# cf.am_policy_hub = true
|
||||
# # cf.run_file = "motd.cf"
|
||||
# end
|
||||
#
|
||||
# You can also configure and bootstrap a client to an existing
|
||||
# policy server:
|
||||
#
|
||||
# config.vm.provision "cfengine" do |cf|
|
||||
# cf.policy_server_address = "10.0.2.15"
|
||||
# Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
|
||||
# such as FTP and Heroku are also available. See the documentation at
|
||||
# https://docs.vagrantup.com/v2/push/atlas.html for more information.
|
||||
# config.push.define "atlas" do |push|
|
||||
# push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
|
||||
# end
|
||||
|
||||
# Enable provisioning with Puppet stand alone. Puppet manifests
|
||||
# are contained in a directory path relative to this Vagrantfile.
|
||||
# You will need to create the manifests directory and a manifest in
|
||||
# the file default.pp in the manifests_path directory.
|
||||
#
|
||||
# config.vm.provision "puppet" do |puppet|
|
||||
# puppet.manifests_path = "manifests"
|
||||
# puppet.manifest_file = "default.pp"
|
||||
# end
|
||||
|
||||
# Enable provisioning with Chef Solo, specifying a cookbooks path, roles
|
||||
# path, and data_bags path (all relative to this Vagrantfile), and adding
|
||||
# some recipes and/or roles.
|
||||
#
|
||||
# config.vm.provision "chef_solo" do |chef|
|
||||
# chef.cookbooks_path = "~/chef/cookbooks"
|
||||
# chef.roles_path = "~/chef/roles"
|
||||
# chef.data_bags_path = "~/chef/data_bags"
|
||||
#
|
||||
# chef.add_recipe "mysql"
|
||||
# chef.add_role "web"
|
||||
#
|
||||
# chef.json = { mysql_password: "foo" }
|
||||
# end
|
||||
#
|
||||
# Chef Solo will automatically install the latest version of Chef for you.
|
||||
# This can be configured in the provisioner block:
|
||||
#
|
||||
# config.vm.provision "chef_solo" do |chef|
|
||||
# chef.version = "11.16.4"
|
||||
# end
|
||||
#
|
||||
# Alternative you can disable the installation of Chef entirely:
|
||||
#
|
||||
# config.vm.provision "chef_solo" do |chef|
|
||||
# chef.install = false
|
||||
# end
|
||||
|
||||
# Enable provisioning with Chef Zero. The Chef Zero provisioner accepts the
|
||||
# exact same parameter as the Chef Solo provisioner:
|
||||
#
|
||||
# config.vm.provision "chef_zero" do |chef|
|
||||
# chef.cookbooks_path = "~/chef/cookbooks"
|
||||
# chef.roles_path = "~/chef/roles"
|
||||
# chef.data_bags_path = "~/chef/data_bags"
|
||||
#
|
||||
# chef.add_recipe "mysql"
|
||||
# chef.add_role "web"
|
||||
#
|
||||
# # You may also specify custom JSON attributes:
|
||||
# chef.json = { mysql_password: "foo" }
|
||||
# end
|
||||
|
||||
# Enable provisioning with Chef Server, specifying the chef server URL,
|
||||
# and the path to the validation key (relative to this Vagrantfile).
|
||||
#
|
||||
# The Hosted Chef platform uses HTTPS. Substitute your organization for
|
||||
# ORGNAME in the URL and validation key.
|
||||
#
|
||||
# If you have your own Chef Server, use the appropriate URL, which may be
|
||||
# HTTP instead of HTTPS depending on your configuration. Also change the
|
||||
# validation key to validation.pem.
|
||||
#
|
||||
# config.vm.provision "chef_client" do |chef|
|
||||
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
|
||||
# chef.validation_key_path = "ORGNAME-validator.pem"
|
||||
# end
|
||||
#
|
||||
# If you're using the Hosted Chef platform, your validator client is
|
||||
# ORGNAME-validator, replacing ORGNAME with your organization name.
|
||||
#
|
||||
# If you have your own Chef Server, the default validation client name is
|
||||
# chef-validator, unless you changed the configuration.
|
||||
#
|
||||
# chef.validation_client_name = "ORGNAME-validator"
|
||||
#
|
||||
# Chef Client will automatically install the latest version of Chef for you.
|
||||
# This can be configured in the provisioner block:
|
||||
#
|
||||
# config.vm.provision "chef_client" do |chef|
|
||||
# chef.version = "11.16.4"
|
||||
# end
|
||||
#
|
||||
# Alternative you can disable the installation of Chef entirely:
|
||||
#
|
||||
# config.vm.provision "chef_client" do |chef|
|
||||
# chef.install = false
|
||||
# end
|
||||
|
||||
# Enable provisioning with Chef Apply, specifying an inline recipe to execute
|
||||
# on the target system.
|
||||
#
|
||||
# config.vm.provision "chef_apply" do |chef|
|
||||
# chef.recipe = <<-RECIPE
|
||||
# package "curl"
|
||||
# RECIPE
|
||||
# end
|
||||
#
|
||||
# Chef Apply will automatically install the latest version of Chef for you.
|
||||
# This can be configured in the provisioner block:
|
||||
#
|
||||
# config.vm.provision "chef_apply" do |chef|
|
||||
# chef.version = "11.16.4"
|
||||
# end
|
||||
# Enable provisioning with a shell script. Additional provisioners such as
|
||||
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
|
||||
# documentation for more information about their specific syntax and use.
|
||||
# config.vm.provision "shell", inline: <<-SHELL
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y apache2
|
||||
# SHELL
|
||||
end
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.box = "<%= box_name %>"
|
||||
<% if box_url -%>
|
||||
|
|
|
@ -243,7 +243,7 @@ en:
|
|||
Press ctrl-c now to exit if you want to remove some boxes or free
|
||||
up some disk space.
|
||||
|
||||
Press any other key to continue.
|
||||
Press the Enter or Return key to continue.
|
||||
version_current: |-
|
||||
Installed Version: %{version}
|
||||
version_latest: |-
|
||||
|
@ -1909,6 +1909,8 @@ en:
|
|||
The specified minion_config file could not be found.
|
||||
master_config_nonexist: |-
|
||||
The specified master_config file could not be found.
|
||||
grains_config_nonexist: |-
|
||||
The specified grains_config file could not be found.
|
||||
missing_key: |-
|
||||
You must include both public and private keys.
|
||||
must_accept_keys: |-
|
||||
|
|
|
@ -5,11 +5,7 @@ file_cache_path "<%= file_cache_path %>"
|
|||
file_backup_path "<%= file_backup_path %>"
|
||||
cookbook_path <%= cookbooks_path.inspect %>
|
||||
<% if roles_path %>
|
||||
if Chef::VERSION.to_f < 11.8
|
||||
role_path <%= roles_path.first.inspect %>
|
||||
else
|
||||
role_path <%= roles_path.inspect %>
|
||||
end
|
||||
role_path <%= roles_path.size == 1 ? roles_path.first.inspect : roles_path.inspect %>
|
||||
<% end %>
|
||||
log_level <%= log_level.inspect %>
|
||||
verbose_logging <%= verbose_logging.inspect %>
|
||||
|
|
|
@ -5,19 +5,12 @@ require Vagrant.source_root.join("plugins/commands/login/command")
|
|||
describe VagrantPlugins::LoginCommand::Client do
|
||||
include_context "unit"
|
||||
|
||||
def stub_env(key, value = nil)
|
||||
allow(ENV).to receive(:[]).and_call_original
|
||||
allow(ENV).to receive(:[])
|
||||
.with(key)
|
||||
.and_return(value)
|
||||
end
|
||||
|
||||
let(:env) { isolated_environment.create_vagrant_env }
|
||||
|
||||
subject { described_class.new(env) }
|
||||
|
||||
before do
|
||||
stub_env("ATLAS_TOKEN", nil)
|
||||
stub_env("ATLAS_TOKEN" => nil)
|
||||
subject.clear_token
|
||||
end
|
||||
|
||||
|
@ -101,7 +94,7 @@ describe VagrantPlugins::LoginCommand::Client do
|
|||
|
||||
describe "#token" do
|
||||
it "reads ATLAS_TOKEN" do
|
||||
stub_env("ATLAS_TOKEN", "ABCD1234")
|
||||
stub_env("ATLAS_TOKEN" => "ABCD1234")
|
||||
expect(subject.token).to eq("ABCD1234")
|
||||
end
|
||||
|
||||
|
@ -111,7 +104,7 @@ describe VagrantPlugins::LoginCommand::Client do
|
|||
end
|
||||
|
||||
it "prefers the environment variable" do
|
||||
stub_env("ATLAS_TOKEN", "ABCD1234")
|
||||
stub_env("ATLAS_TOKEN" => "ABCD1234")
|
||||
subject.store_token("EFGH5678")
|
||||
expect(subject.token).to eq("ABCD1234")
|
||||
end
|
||||
|
|
|
@ -17,6 +17,7 @@ describe VagrantPlugins::LoginCommand::AddAuthentication do
|
|||
|
||||
before do
|
||||
allow(Vagrant).to receive(:server_url).and_return(server_url)
|
||||
stub_env("ATLAS_TOKEN" => nil)
|
||||
end
|
||||
|
||||
describe "#call" do
|
||||
|
@ -60,5 +61,28 @@ describe VagrantPlugins::LoginCommand::AddAuthentication do
|
|||
|
||||
expect(env[:box_urls]).to eq(expected)
|
||||
end
|
||||
|
||||
it "appends the access token to vagrantcloud.com URLs if Atlas" do
|
||||
server_url = "https://atlas.hashicorp.com"
|
||||
allow(Vagrant).to receive(:server_url).and_return(server_url)
|
||||
|
||||
token = "foobarbaz"
|
||||
VagrantPlugins::LoginCommand::Client.new(iso_env).store_token(token)
|
||||
|
||||
original = [
|
||||
"http://google.com/box.box",
|
||||
"http://vagrantcloud.com/foo.box",
|
||||
"http://vagrantcloud.com/bar.box?arg=true",
|
||||
]
|
||||
|
||||
expected = original.dup
|
||||
expected[1] = "#{original[1]}?access_token=#{token}"
|
||||
expected[2] = "#{original[2]}&access_token=#{token}"
|
||||
|
||||
env[:box_urls] = original.dup
|
||||
subject.call(env)
|
||||
|
||||
expect(env[:box_urls]).to eq(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -80,15 +80,23 @@ describe VagrantPlugins::CommunicatorWinRM::Communicator do
|
|||
|
||||
describe ".test" do
|
||||
it "returns true when exit code is zero" do
|
||||
expect(shell).to receive(:powershell).with(kind_of(String)).and_return({ exitcode: 0 })
|
||||
output = { exitcode: 0, data:[{ stderr: '' }] }
|
||||
expect(shell).to receive(:powershell).with(kind_of(String)).and_return(output)
|
||||
expect(subject.test("test -d c:/windows")).to be_true
|
||||
end
|
||||
|
||||
it "returns false when exit code is non-zero" do
|
||||
expect(shell).to receive(:powershell).with(kind_of(String)).and_return({ exitcode: 1 })
|
||||
output = { exitcode: 1, data:[{ stderr: '' }] }
|
||||
expect(shell).to receive(:powershell).with(kind_of(String)).and_return(output)
|
||||
expect(subject.test("test -d /tmp/foobar")).to be_false
|
||||
end
|
||||
|
||||
it "returns false when stderr contains output" do
|
||||
output = { exitcode: 0, data:[{ stderr: 'this is an error' }] }
|
||||
expect(shell).to receive(:powershell).with(kind_of(String)).and_return(output)
|
||||
expect(subject.test("[-x stuff] && foo")).to be_false
|
||||
end
|
||||
|
||||
it "returns false when command is testing for linux OS" do
|
||||
expect(subject.test("uname -s | grep Debian")).to be_false
|
||||
end
|
||||
|
|
|
@ -89,6 +89,7 @@ describe VagrantPlugins::Kernel_V2::PushConfig do
|
|||
let(:key) { pushes[:foo][0] }
|
||||
let(:config) { pushes[:foo][1] }
|
||||
let(:unset) { Vagrant.plugin("2", :config).const_get(:UNSET_VALUE) }
|
||||
let(:dummy_klass) { Vagrant::Config::V2::DummyConfig }
|
||||
|
||||
before do
|
||||
register_plugin("2") do |plugin|
|
||||
|
@ -112,6 +113,62 @@ describe VagrantPlugins::Kernel_V2::PushConfig do
|
|||
end
|
||||
end
|
||||
|
||||
it "compiles the proper configuration with a single strategy" do
|
||||
instance = described_class.new.tap do |i|
|
||||
i.define "foo"
|
||||
end
|
||||
|
||||
instance.finalize!
|
||||
|
||||
pushes = instance.__compiled_pushes
|
||||
strategy, config = pushes[:foo]
|
||||
expect(strategy).to eq(:foo)
|
||||
expect(config.bar).to be(unset)
|
||||
end
|
||||
|
||||
it "compiles the proper configuration with a single strategy and block" do
|
||||
instance = described_class.new.tap do |i|
|
||||
i.define "foo" do |b|
|
||||
b.bar = 42
|
||||
end
|
||||
end
|
||||
|
||||
instance.finalize!
|
||||
|
||||
pushes = instance.__compiled_pushes
|
||||
strategy, config = pushes[:foo]
|
||||
expect(strategy).to eq(:foo)
|
||||
expect(config.bar).to eq(42)
|
||||
end
|
||||
|
||||
it "compiles the proper config with a name and explicit strategy" do
|
||||
instance = described_class.new.tap do |i|
|
||||
i.define "bar", strategy: "foo"
|
||||
end
|
||||
|
||||
instance.finalize!
|
||||
|
||||
pushes = instance.__compiled_pushes
|
||||
strategy, config = pushes[:bar]
|
||||
expect(strategy).to eq(:foo)
|
||||
expect(config.bar).to be(unset)
|
||||
end
|
||||
|
||||
it "compiles the proper config with a name and explicit strategy with block" do
|
||||
instance = described_class.new.tap do |i|
|
||||
i.define "bar", strategy: "foo" do |b|
|
||||
b.bar = 42
|
||||
end
|
||||
end
|
||||
|
||||
instance.finalize!
|
||||
|
||||
pushes = instance.__compiled_pushes
|
||||
strategy, config = pushes[:bar]
|
||||
expect(strategy).to eq(:foo)
|
||||
expect(config.bar).to eq(42)
|
||||
end
|
||||
|
||||
context "with the same name but different strategy" do
|
||||
context "with no block" do
|
||||
let(:a) do
|
||||
|
@ -128,8 +185,7 @@ describe VagrantPlugins::Kernel_V2::PushConfig do
|
|||
|
||||
it "chooses the last config" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config.bar).to be(unset)
|
||||
expect(config.zip).to be(unset)
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -152,8 +208,7 @@ describe VagrantPlugins::Kernel_V2::PushConfig do
|
|||
|
||||
it "chooses the last config" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config.bar).to eq(unset)
|
||||
expect(config.zip).to eq("b")
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -174,8 +229,7 @@ describe VagrantPlugins::Kernel_V2::PushConfig do
|
|||
|
||||
it "chooses the last config" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config.bar).to be(unset)
|
||||
expect(config.zip).to be(unset)
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -196,8 +250,7 @@ describe VagrantPlugins::Kernel_V2::PushConfig do
|
|||
|
||||
it "chooses the last config" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config.bar).to eq("b")
|
||||
expect(config.zip).to eq("b")
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -286,8 +339,7 @@ describe VagrantPlugins::Kernel_V2::PushConfig do
|
|||
|
||||
it "merges the configs" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config.bar).to eq(unset)
|
||||
expect(config.zip).to eq("b")
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -68,4 +68,11 @@ describe VagrantPlugins::Chef::Config::Base do
|
|||
expect(subject.version).to eq(:latest)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#installer_download_path" do
|
||||
it "defaults to nil" do
|
||||
subject.finalize!
|
||||
expect(subject.installer_download_path).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,8 +7,9 @@ describe VagrantPlugins::Chef::Omnibus, :focus do
|
|||
|
||||
let(:version) { :latest }
|
||||
let(:prerelease) { false }
|
||||
let(:download_path) { nil }
|
||||
|
||||
let(:build_command) { described_class.build_command(version, prerelease) }
|
||||
let(:build_command) { described_class.build_command(version, prerelease, download_path) }
|
||||
|
||||
context "when prerelease is given" do
|
||||
let(:prerelease) { true }
|
||||
|
@ -18,6 +19,14 @@ describe VagrantPlugins::Chef::Omnibus, :focus do
|
|||
end
|
||||
end
|
||||
|
||||
context "when download_path is given" do
|
||||
let(:download_path) { '/tmp/path/to/omnibuses' }
|
||||
|
||||
it "returns the correct command" do
|
||||
expect(build_command).to eq("#{prefix} | sudo bash -s -- -d \"/tmp/path/to/omnibuses\"")
|
||||
end
|
||||
end
|
||||
|
||||
context "when version is :latest" do
|
||||
let(:version) { :latest }
|
||||
|
||||
|
@ -34,12 +43,13 @@ describe VagrantPlugins::Chef::Omnibus, :focus do
|
|||
end
|
||||
end
|
||||
|
||||
context "when prerelease and version are given" do
|
||||
context "when prerelease and version and download_path are given" do
|
||||
let(:version) { "1.2.3" }
|
||||
let(:prerelease) { true }
|
||||
let(:download_path) { "/some/path" }
|
||||
|
||||
it "returns the correct command" do
|
||||
expect(build_command).to eq("#{prefix} | sudo bash -s -- -p -v \"1.2.3\"")
|
||||
expect(build_command).to eq("#{prefix} | sudo bash -s -- -p -v \"1.2.3\" -d \"/some/path\"")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,5 +60,23 @@ describe VagrantPlugins::Salt::Config do
|
|||
expect(result[error_key]).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context "grains_config" do
|
||||
it "fails if grains_config is set and missing" do
|
||||
subject.grains_config = "/nope/still/not/here"
|
||||
subject.finalize!
|
||||
|
||||
result = subject.validate(machine)
|
||||
expect(result[error_key]).to_not be_empty
|
||||
end
|
||||
|
||||
it "is valid if is set and not missing" do
|
||||
subject.grains_config = File.expand_path(__FILE__)
|
||||
subject.finalize!
|
||||
|
||||
result = subject.validate(machine)
|
||||
expect(result[error_key]).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ describe VagrantPlugins::FTPPush::Push do
|
|||
let(:env) { isolated_environment }
|
||||
let(:config) do
|
||||
double("config",
|
||||
host: "127.0.0.1:21212",
|
||||
host: "127.0.0.1:51234",
|
||||
username: "sethvargo",
|
||||
password: "bacon",
|
||||
passive: false,
|
||||
|
@ -22,7 +22,7 @@ describe VagrantPlugins::FTPPush::Push do
|
|||
|
||||
describe "#push" do
|
||||
before(:all) do
|
||||
@server = FakeFtp::Server.new(21212, 21213)
|
||||
@server = FakeFtp::Server.new(51234, 21213)
|
||||
@server.start
|
||||
|
||||
@dir = Dir.mktmpdir
|
||||
|
|
|
@ -93,47 +93,9 @@ describe VagrantPlugins::LocalExecPush::Push do
|
|||
end
|
||||
|
||||
describe "#execute!" do
|
||||
let(:exit_code) { 0 }
|
||||
let(:stdout) { "This is the output" }
|
||||
let(:stderr) { "This is the errput" }
|
||||
|
||||
let(:process) do
|
||||
double("process",
|
||||
exit_code: exit_code,
|
||||
stdout: stdout,
|
||||
stderr: stderr,
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(Vagrant::Util::Subprocess).to receive(:execute)
|
||||
.and_return(process)
|
||||
end
|
||||
|
||||
it "creates a subprocess" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute)
|
||||
it "safe execs" do
|
||||
expect(Vagrant::Util::SafeExec).to receive(:exec)
|
||||
expect { subject.execute! }.to_not raise_error
|
||||
end
|
||||
|
||||
it "returns the resulting process" do
|
||||
expect(subject.execute!).to be(process)
|
||||
end
|
||||
|
||||
context "when the exit code is non-zero" do
|
||||
let(:exit_code) { 1 }
|
||||
|
||||
it "raises an exception" do
|
||||
klass = VagrantPlugins::LocalExecPush::Errors::CommandFailed
|
||||
cmd = ["foo", "bar"]
|
||||
|
||||
expect { subject.execute!(*cmd) }.to raise_error(klass) { |error|
|
||||
expect(error.message).to eq(I18n.t("local_exec_push.errors.command_failed",
|
||||
cmd: cmd.join(" "),
|
||||
stdout: stdout,
|
||||
stderr: stderr,
|
||||
))
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -83,6 +83,18 @@ shared_context "unit" do
|
|||
return Pathname.new(d)
|
||||
end
|
||||
|
||||
# Stub the given environment in ENV, without actually touching ENV. Keys and
|
||||
# values are converted to strings because that's how the real ENV works.
|
||||
def stub_env(hash)
|
||||
allow(ENV).to receive(:[]).and_call_original
|
||||
|
||||
hash.each do |key, value|
|
||||
allow(ENV).to receive(:[])
|
||||
.with(key.to_s)
|
||||
.and_return(value.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
# This helper provides temporary environmental variable changes.
|
||||
def with_temp_env(environment)
|
||||
# Build up the new environment, preserving the old values so we
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.7.0
|
||||
1.7.2.dev
|
||||
|
|
|
@ -173,6 +173,7 @@
|
|||
<li<%= sidebar_current("provisioning-ansible") %>><a href="/v2/provisioning/ansible.html">Ansible</a></li>
|
||||
<li<%= sidebar_current("provisioning-cfengine") %>><a href="/v2/provisioning/cfengine.html">CFEngine</a></li>
|
||||
<li<%= sidebar_current("provisioning-chefsolo") %>><a href="/v2/provisioning/chef_solo.html">Chef Solo</a></li>
|
||||
<li<%= sidebar_current("provisioning-chefzero") %>><a href="/v2/provisioning/chef_zero.html">Chef Zero</a></li>
|
||||
<li<%= sidebar_current("provisioning-chefclient") %>><a href="/v2/provisioning/chef_client.html">Chef Client</a></li>
|
||||
<li<%= sidebar_current("provisioning-chefapply") %>><a href="/v2/provisioning/chef_apply.html">Chef Apply</a></li>
|
||||
<li<%= sidebar_current("provisioning-docker") %>><a href="/v2/provisioning/docker.html">Docker</a></li>
|
||||
|
|
|
@ -36,7 +36,8 @@ General settings:
|
|||
but not to the host machine. Useful for links.
|
||||
|
||||
* `link` (method, string argument) - Link this container to another
|
||||
by name. Example: `docker.link("db:db")`. Note, if you're linking to
|
||||
by name. The argument should be in the format of `(name:alias)`.
|
||||
Example: `docker.link("db:db")`. Note, if you're linking to
|
||||
another container in the same Vagrantfile, make sure you call
|
||||
`vagrant up` with the `--no-parallel` flag.
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ it can greatly improve readability. Additionally, some provisioners, like
|
|||
the Chef provisioner, have special methods that can be called within that
|
||||
block to ease configuration that can't be done with the key/value approach.
|
||||
|
||||
Provisioners can also be named. These names are used cosmetically for output
|
||||
Provisioners can also be named (since 1.7.0). These names are used cosmetically for output
|
||||
as well as overriding provisioner settings (covered further below). An example
|
||||
of naming provisioners is shown below:
|
||||
|
||||
|
|
|
@ -29,9 +29,6 @@ This section lists the complete set of available options for the Chef Apply
|
|||
provisioner. More detailed examples of how to use the provisioner are
|
||||
available below this section.
|
||||
|
||||
Due to the unqiue nature of Chef Apply, the Chef Apply provisioner does not
|
||||
inherit the [common options for other Chef provisioners](/v2/provisioning/chef_common.html).
|
||||
|
||||
* `recipe` (string) - The raw recipe contents to execute using Chef Apply on
|
||||
the guest.
|
||||
|
||||
|
@ -44,6 +41,9 @@ inherit the [common options for other Chef provisioners](/v2/provisioning/chef_c
|
|||
`/tmp/vagrant-chef-apply-#` where `#` is a unique counter generated by
|
||||
Vagrant to prevent collisions.
|
||||
|
||||
In addition to all the options listed above, the Chef Apply provisioner supports
|
||||
the [common options for all Chef provisioners](/v2/provisioning/chef_common.html).
|
||||
|
||||
## Specifying a Recipe
|
||||
|
||||
The easiest way to get started with the Chef Apply provisioner is to just
|
||||
|
|
|
@ -82,12 +82,15 @@ end
|
|||
|
||||
There are a few more configuration options available. These generally don't
|
||||
need to be modified but are available if your Chef Server requires customization
|
||||
of these variables:
|
||||
of these variables.
|
||||
|
||||
* `client_key_path`
|
||||
* `node_name`
|
||||
* `validation_client_name`
|
||||
|
||||
In addition to all the options listed above, the Chef Client provisioner supports
|
||||
the [common options for all Chef provisioners](/v2/provisioning/chef_common.html).
|
||||
|
||||
## Cleanup
|
||||
|
||||
When you provision your Vagrant virtual machine with Chef Server, it creates a
|
||||
|
|
|
@ -5,12 +5,55 @@ sidebar_current: "provisioning-chefcommon"
|
|||
|
||||
# Shared Chef Options
|
||||
|
||||
This page documents the list of available options that are available in the
|
||||
[Chef Solo](/v2/provisioning/chef_solo.html),
|
||||
[Chef Zero](/v2/provisioning/chef_zero.html)
|
||||
and
|
||||
[Chef Client](/v2/provisioning/chef_client.html)
|
||||
provisioners.
|
||||
## All Chef Provisioners
|
||||
|
||||
The following options are available to all Chef provisioners. Many of these
|
||||
options are for advanced users only and should not be used unless you understand
|
||||
their purpose.
|
||||
|
||||
- `binary_path` (string) - The path to Chef's `bin/` directory on the guest
|
||||
machine.
|
||||
|
||||
- `binary_env` (string) - Arbitrary environment variables to set before running
|
||||
the Chef provisioner command. This should be of the format `KEY=value` as a
|
||||
string.
|
||||
|
||||
- `install` (boolean, string) - Install Chef on the system if it does not exist.
|
||||
The default value is "true", which will use the official Omnibus installer
|
||||
from Chef. This is a trinary attribute (it can have three values):
|
||||
|
||||
- `true` (boolean) - install Chef
|
||||
- `false` (boolean) - do not install Chef
|
||||
- `"force"` (string) - install Chef, even if it is already installed at the
|
||||
proper version on the guest
|
||||
|
||||
- `installer_download_path` (string) - The path where the Chef installer will be
|
||||
downloaded to. This option is only honored if the `install` attribute is
|
||||
`true` or `"force"`. The default value is to use the path provided by Chef's
|
||||
Omnibus installer, which varies between releases.
|
||||
|
||||
- `log_level` (string) - The Chef log level. See the Chef docs for acceptable
|
||||
values.
|
||||
|
||||
- `prerelease` (boolean) - Install a prerelease version of Chef. The default
|
||||
value is false.
|
||||
|
||||
- `version` (string) - The version of Chef to install on the guest. If Chef is
|
||||
already installed on the system, the installed version is compared with the
|
||||
requested version. If they match, no action is taken. If they do not match,
|
||||
the value specified in this attribute will be installed in favor of the
|
||||
existing version (a message will be displayed).
|
||||
|
||||
You can also specify "latest" (default), which will install the latest
|
||||
version of Chef on the system. In this case, Chef will use whatever
|
||||
version is on the system. To force the newest version of Chef to be
|
||||
installed on every provision, set the {#install} option to "force".
|
||||
|
||||
|
||||
## Runner Chef Provisioners
|
||||
|
||||
The following options are available to any of the Chef "runner" provisioners
|
||||
which include [Chef Solo](/v2/provisioning/chef_solo.html), [Chef Zero](/v2/provisioning/chef_zero.html), and [Chef Client](/v2/provisioning/chef_client.html).
|
||||
|
||||
* `arguments` (string) - A list of additional arguments to pass on the
|
||||
command-line to Chef. Since these are passed in a shell-like environment,
|
||||
|
@ -21,9 +64,6 @@ provisioners.
|
|||
This defaults to 1. This can be increased to a higher number if your Chef
|
||||
runs take multiple runs to reach convergence.
|
||||
|
||||
* `binary_path` (string) - The path to the directory of the Chef executable
|
||||
binaries. By default, Vagrant looks for the proper Chef binary on the PATH.
|
||||
|
||||
* `custom_config_path` (string) - A path to a custom Chef configuration local
|
||||
on your machine that will be used as the Chef configuration. This Chef
|
||||
configuration will be loaded _after_ the Chef configuration that Vagrant
|
||||
|
|
|
@ -32,10 +32,6 @@ This section lists the complete set of available options for the Chef Solo
|
|||
provisioner. More detailed examples of how to use the provisioner are
|
||||
available below this section.
|
||||
|
||||
Note that only the Chef-solo specific options are shown below. There is
|
||||
also a large set of [common options](/v2/provisioning/chef_common.html)
|
||||
that are available with all Chef provisioners.
|
||||
|
||||
* `cookbooks_path` (string or array) - A list of paths to where cookbooks
|
||||
are stored. By default this is "cookbooks", expecting a cookbooks folder
|
||||
relative to the Vagrantfile location.
|
||||
|
@ -62,6 +58,9 @@ that are available with all Chef provisioners.
|
|||
this will use the default synced folder type. For example, you can set this
|
||||
to "nfs" to use NFS synced folders.
|
||||
|
||||
In addition to all the options listed above, the Chef Solo provisioner supports
|
||||
the [common options for all Chef provisioners](/v2/provisioning/chef_common.html).
|
||||
|
||||
## Specifying a Run List
|
||||
|
||||
The easiest way to get started with the Chef Solo provisioner is to just
|
||||
|
|
|
@ -31,13 +31,12 @@ This section lists the complete set of available options for the Chef Zero
|
|||
provisioner. More detailed examples of how to use the provisioner are
|
||||
available below this section.
|
||||
|
||||
Note that only the Chef Zero specific options are shown below, but all [Chef
|
||||
Solo options](/v2/provisioning/chef_solo.html), including the [common Chef
|
||||
provisioner options](/v2/provisioning/chef_common.html), are also inherited.
|
||||
|
||||
* `nodes_path` (string) - A path where the Chef nodes are stored. Be default,
|
||||
no node path is set.
|
||||
|
||||
In addition to all the options listed above, the Chef Zero provisioner supports
|
||||
the [common options for all Chef provisioners](/v2/provisioning/chef_common.html).
|
||||
|
||||
## Usage
|
||||
|
||||
The Chef Zero provisioner is configured basically the same way as the Chef Solo
|
||||
|
|
|
@ -56,7 +56,7 @@ on this machine. Not supported on Windows.
|
|||
`false`. Not supported on Windows.
|
||||
|
||||
* `install_type` (stable | git | daily | testing) - Whether to install from a
|
||||
distribution's stable package manager, git tree-ish, daily ppa, or testing repository.
|
||||
distribution's stable package manager, git tree-ish, daily ppa, or testing repository.
|
||||
Not supported on Windows.
|
||||
|
||||
* `install_args` (develop) - When performing a git install,
|
||||
|
@ -77,6 +77,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.
|
||||
|
||||
## Master Options
|
||||
These only make sense when `install_master` is `true`.
|
||||
|
|
|
@ -10,7 +10,7 @@ description: |-
|
|||
|
||||
## Heroku Strategy
|
||||
|
||||
[Heroku][] is a public IAAS provider that makes it easy to deploy an
|
||||
[Heroku][] is a public PAAS provider that makes it easy to deploy an
|
||||
application. The Vagrant Push Heroku strategy pushes your application's code to
|
||||
Heroku.
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ machines. `vagrant connect` creates a tiny virtual machine that takes up
|
|||
only around 20 MB in RAM, using VirtualBox or VMware (more provider support
|
||||
is coming soon).
|
||||
|
||||
Any traffic sent to this tiny virtual machine is then proxies through to
|
||||
Any traffic sent to this tiny virtual machine is then proxied through to
|
||||
the shared Vagrant environment as if it were directed at it.
|
||||
|
||||
## Beware: Vagrant Insecure Key
|
||||
|
|
|
@ -90,7 +90,7 @@ Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -E -e /*/ d -ibak /etc/exports
|
|||
%admin ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE
|
||||
```
|
||||
|
||||
For Linux, sudoers should look like this:
|
||||
For Ubuntu Linux , sudoers should look like this:
|
||||
|
||||
```
|
||||
Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
|
||||
|
@ -101,3 +101,14 @@ 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
|
||||
```
|
||||
|
||||
For Fedora Linux, sudoers might look like this (given your user
|
||||
belongs to the vagrant group):
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
|
|
@ -4,13 +4,11 @@
|
|||
$script = <<SCRIPT
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install curl
|
||||
curl -sSL https://get.rvm.io | bash -s stable
|
||||
. ~/.bashrc
|
||||
. ~/.bash_profile
|
||||
rvm install 2.0.0
|
||||
rvm --default use 2.0.0
|
||||
cd /vagrant
|
||||
bundle
|
||||
sudo su -l -c 'gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3' vagrant
|
||||
sudo su -l -c 'curl -L https://get.rvm.io | bash -s stable --auto-dotfiles' vagrant
|
||||
sudo su -l -c 'rvm install 2.0.0' vagrant
|
||||
sudo su -l -c 'rvm --default use 2.0.0' vagrant
|
||||
sudo su -l -c 'cd /vagrant && bundle install --jobs 2' vagrant
|
||||
SCRIPT
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
---
|
||||
page_title: "Vagrant Push: One Command to Deploy Any Application"
|
||||
title: "Vagrant Push: One Command to Deploy Any Application"
|
||||
author: "Mitchell Hashimoto"
|
||||
author_url: https://github.com/mitchellh
|
||||
---
|
||||
|
||||
Vagrant 1.7 comes with a new command: `vagrant push`. Just as "vagrant up"
|
||||
is a single command to create a development environment for any application,
|
||||
`vagrant push` is a single command to _deploy_ any application.
|
||||
|
||||
The goal of Vagrant is to give developers a single workflow to develop
|
||||
applications effectively. "vagrant up" creates a development environment for any
|
||||
application and "vagrant share" enables collaboration for any application.
|
||||
Deploying was the next logical step for Vagrant, now possible with
|
||||
"vagrant push".
|
||||
|
||||
Like every other component of Vagrant, push can be configured using multiple
|
||||
strategies. "vagrant push" can deploy via FTP, Heroku,
|
||||
[Atlas](https://atlas.hashicorp.com), or by executing any local script.
|
||||
Other strategies can be added via plugins and more will be added to core
|
||||
as time goes on.
|
||||
|
||||
Read on to learn more.
|
||||
|
||||
READMORE
|
||||
|
||||
### Demo
|
||||
|
||||
We've prepared a short video showing Vagrant Push in action.
|
||||
|
||||
<iframe src="//player.vimeo.com/video/114328000" width="680" height="382" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
|
||||
### Push to Deploy
|
||||
|
||||
`vagrant push` works like anything else in Vagrant: configure it in the
|
||||
Vagrantfile, and it is immediately available to every developer. Push
|
||||
configuration is simple and easy to understand:
|
||||
|
||||
```
|
||||
config.push.define "ftp" do |push|
|
||||
push.host = "ftp.company.com"
|
||||
push.username = "username"
|
||||
push.password = "mypassword"
|
||||
end
|
||||
```
|
||||
|
||||
And then to push the application to the FTP or SFTP server:
|
||||
|
||||
```
|
||||
$ vagrant push
|
||||
...
|
||||
```
|
||||
|
||||
The "ftp" in the configuration above defines the strategy Vagrant will
|
||||
use to push. Below, we cover strategies in more detail.
|
||||
|
||||
Additionally, multiple `config.push.define` declarations can be in a Vagrantfile to
|
||||
define multiple pushes, perhaps one to staging and one to production, for
|
||||
example. To learn more about multiple push definitions,
|
||||
[read the complete documentation](https://docs.vagrantup.com/v2/push/index.html).
|
||||
|
||||
### A Single Command
|
||||
|
||||
The biggest benefit of Vagrant Push is being able to define a single command
|
||||
to deploy any application. Whether the deploy process is complex or
|
||||
is just a simple push to Heroku, developers only need to know that any
|
||||
application within their organizations can be deployed with `vagrant push`.
|
||||
|
||||
For complicated deploys, the benefit is obvious. For simpler deploys, such
|
||||
as a push to Heroku, Vagrant Push is still useful. Besides not having
|
||||
to know that Heroku is being used under the hood, Vagrant Push will
|
||||
automatically configure your Git remote so the push works. Prior to this,
|
||||
you'd at least have to know the Heroku application name and configure
|
||||
your local repository to be able to push to it.
|
||||
|
||||
Of course, not all applications stay that simple, and if your application
|
||||
outgrows Heroku, then the deploy process doesn't change with Vagrant:
|
||||
`vagrant push` to deploy any application.
|
||||
|
||||
### Push Strategies
|
||||
|
||||
Like providers, provisioners, and other features in Vagrant, pushes can
|
||||
be configured with multiple _strategies_. Vagrant 1.7 ships with four
|
||||
strategies:
|
||||
|
||||
* [Atlas](https://docs.vagrantup.com/v2/push/atlas.html) - Push application
|
||||
to [Atlas](https://atlas.hashicorp.com), a commercial
|
||||
product from HashiCorp.
|
||||
|
||||
* [FTP/SFTP](https://docs.vagrantup.com/v2/push/ftp.html) - Upload files
|
||||
via FTP or SFTP to a remote server. This is great for static sites,
|
||||
PHP, etc.
|
||||
|
||||
* [Heroku](https://docs.vagrantup.com/v2/push/heroku.html) - Push your
|
||||
Git repository to Heroku, and configure the Git remote for you if
|
||||
it doesn't already exist.
|
||||
|
||||
* [Local Exec](https://docs.vagrantup.com/v2/push/local-exec.html) -
|
||||
Executes a local script on the system using a shell, deferring deployment
|
||||
logic to the user. This is for custom behavior or more complicated
|
||||
interactions with systems.
|
||||
|
||||
In addition to these built-in strategies, new strategies can be
|
||||
[built just like any other Vagrant plugin](https://docs.vagrantup.com/v2/plugins/development-basics.html).
|
||||
This allows 3rd parties to extend the capabilities of `vagrant push`, and
|
||||
will surely result in future versions of Vagrant shipping with more push
|
||||
strategies.
|
||||
|
||||
### Next
|
||||
|
||||
To learn all the details about Vagrant Push, please read the
|
||||
[complete documentation](https://docs.vagrantup.com/v2/push/index.html).
|
||||
|
||||
This is a historic day for Vagrant. Vagrant 0.1 came out and defined
|
||||
"vagrant up" to build a development environment for any application.
|
||||
Vagrant 1.1 made it possible to have development environments on top of
|
||||
any provider (VMware, Docker, etc.). Vagrant 1.5 introduced the "share"
|
||||
command to collaborate. And now, Vagrant 1.7 completes the development
|
||||
process with "push" to deploy.
|
||||
|
||||
The mission of Vagrant has been the same since day one: development
|
||||
environments made easy. This mission spans any language choice, any
|
||||
provider choice, and likewise any choice of how to deploy these
|
||||
applications. Push continues this mission by adding a necessary
|
||||
feature to the development workflow.
|
||||
|
||||
With Vagrant 1.7 available, we'll be blogging about more of the features
|
||||
as well as creeping towards a 2.0!
|
|
@ -14,7 +14,8 @@ page_title: "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 <a href="https://dl.bintray.com/mitchellh/vagrant/<%= latest_version %>_SHA256SUMS?direct">here</a>.
|
||||
for packages <a href="https://dl.bintray.com/mitchellh/vagrant/<%= latest_version %>_SHA256SUMS?direct">here</a>,
|
||||
and you can find the version changelog <a href="https://github.com/mitchellh/vagrant/blob/master/CHANGELOG.md">here</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
Loading…
Reference in New Issue