Merge branch 'master' into GH4201-ShowRSyncOutput
This commit is contained in:
commit
dd62d3c5f1
58
CHANGELOG.md
58
CHANGELOG.md
|
@ -1,7 +1,58 @@
|
|||
## 1.7.0 (unreleased)
|
||||
## 1.7.2 (unreleased)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- provisioners/salt: add support for grains [GH-4895]
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- commands/reload,up: `--provision-with` implies `--provision` [GH-5085]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- core: private boxes still referencing vagrantcloud.com will have
|
||||
their vagrant login access token properly appended
|
||||
- core: push plugin configuration is properly validated
|
||||
- core: restore box packaging functionality
|
||||
- commands/push: push lookups are by user-defined name, not push
|
||||
strategy name [GH-4975]
|
||||
- commands/push: validate the configuration
|
||||
- guests/arch: fix network configuration due to poor line breaks. [GH-4964]
|
||||
- guests/solaris: Merge configurations properly so configs can be set
|
||||
in default Vagrantfiles. [GH-5092]
|
||||
- providers/docker: Symlinks in shared folders work. [GH-5093]
|
||||
- providers/hyperv: VM start errors turn into proper Vagrant errors. [GH-5101]
|
||||
- provisioners/chef: remove Chef version check from solo.rb generation and
|
||||
make `roles_path` populate correctly
|
||||
- pushes/ftp: expand file paths relative to the Vagrantfile
|
||||
- pushes/ftp: improved debugging output
|
||||
- pushes/ftp: create parent directories if they do not exist on the remote
|
||||
server
|
||||
|
||||
## 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:
|
||||
|
||||
- provisioners/ansible: `raw_arguments` has now highest priority
|
||||
- provisioners/ansible: only the `ssh` connection transport is supported
|
||||
(`paramiko` can be enabled with `raw_arguments` at your own risks)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- **Vagrant Push**: Vagrant can now deploy! `vagrant push` is a single
|
||||
command to deploy your application. Deploy to Heroku, FTP, or
|
||||
HashiCorp's commercial product Atlas. New push strategies can be
|
||||
added with plugins.
|
||||
- **Named provisioners**: Provisioners can now be named. This name is used
|
||||
for output as well as `--provision-with` for better control.
|
||||
- Default provider logic improved: Providers in `config.vm.provider` blocks
|
||||
|
@ -9,6 +60,7 @@ FEATURES:
|
|||
providers are chosen before later ones. [GH-3812]
|
||||
- If the default insecure keypair is used, Vagrant will automatically replace
|
||||
it with a randomly generated keypair on first `vagrant up`. [GH-2608]
|
||||
- Vagrant Login is now part of Vagrant core
|
||||
- Chef Zero provisioner: Use Chef 11's "local" mode to run recipes against an
|
||||
in-memory Chef Server
|
||||
- Chef Apply provisioner: Specify inline Chef recipes and recipe snippets
|
||||
|
@ -88,6 +140,10 @@ BUG FIXES:
|
|||
IP address and don't allow it. [GH-4671]
|
||||
- providers/virtualbox: Show more descriptive error if VirtualBox is
|
||||
reporting an empty version. [GH-4657]
|
||||
- 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
|
||||
|
|
|
@ -65,7 +65,7 @@ _vagrant() {
|
|||
then
|
||||
case "$prev" in
|
||||
"init")
|
||||
local box_list=$(find $HOME/.vagrant.d/boxes -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
|
||||
local box_list=$(find "${VAGRANT_HOME:-${HOME}/.vagrant.d}/boxes" -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
|
||||
COMPREPLY=($(compgen -W "${box_list}" -- ${cur}))
|
||||
return 0
|
||||
;;
|
||||
|
@ -111,7 +111,7 @@ _vagrant() {
|
|||
then
|
||||
case "$prev" in
|
||||
"remove"|"repackage")
|
||||
local box_list=$(find $HOME/.vagrant.d/boxes -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
|
||||
local box_list=$(find "${VAGRANT_HOME:-${HOME}/.vagrant.d}/boxes" -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
|
||||
COMPREPLY=($(compgen -W "${box_list}" -- ${cur}))
|
||||
return 0
|
||||
;;
|
||||
|
|
|
@ -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
|
|
@ -123,6 +123,7 @@ module Vagrant
|
|||
c.register([:"2", :host]) { Plugin::V2::Host }
|
||||
c.register([:"2", :provider]) { Plugin::V2::Provider }
|
||||
c.register([:"2", :provisioner]) { Plugin::V2::Provisioner }
|
||||
c.register([:"2", :push]) { Plugin::V2::Push }
|
||||
c.register([:"2", :synced_folder]) { Plugin::V2::SyncedFolder }
|
||||
end
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ module Vagrant
|
|||
# element is an authenticated URL.
|
||||
# @param [Hash] env
|
||||
# @param [Bool] expanded True if the metadata URL was expanded with
|
||||
# a Vagrant Cloud server URL.
|
||||
# a Atlas server URL.
|
||||
def add_from_metadata(url, env, expanded)
|
||||
original_url = env[:box_url]
|
||||
provider = env[:box_provider]
|
||||
|
|
|
@ -539,6 +539,41 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
# This executes the push with the given name, raising any exceptions that
|
||||
# occur.
|
||||
#
|
||||
# Precondition: the push is not nil and exists.
|
||||
def push(name)
|
||||
@logger.info("Getting push: #{name}")
|
||||
|
||||
name = name.to_sym
|
||||
|
||||
pushes = self.vagrantfile.config.push.__compiled_pushes
|
||||
if !pushes.key?(name)
|
||||
raise Vagrant::Errors::PushStrategyNotDefined,
|
||||
name: name,
|
||||
pushes: pushes.keys
|
||||
end
|
||||
|
||||
strategy, config = pushes[name]
|
||||
push_registry = Vagrant.plugin("2").manager.pushes
|
||||
klass, _ = push_registry.get(strategy)
|
||||
if klass.nil?
|
||||
raise Vagrant::Errors::PushStrategyNotLoaded,
|
||||
name: strategy,
|
||||
pushes: push_registry.keys
|
||||
end
|
||||
|
||||
klass.new(self, config).push
|
||||
end
|
||||
|
||||
# The list of pushes defined in this Vagrantfile.
|
||||
#
|
||||
# @return [Array<Symbol>]
|
||||
def pushes
|
||||
self.vagrantfile.config.push.__compiled_pushes.keys
|
||||
end
|
||||
|
||||
# This returns a machine with the proper provider for this environment.
|
||||
# The machine named by `name` must be in this environment.
|
||||
#
|
||||
|
|
|
@ -556,6 +556,22 @@ module Vagrant
|
|||
error_key(:plugin_uninstall_system)
|
||||
end
|
||||
|
||||
class PushesNotDefined < VagrantError
|
||||
error_key(:pushes_not_defined)
|
||||
end
|
||||
|
||||
class PushStrategyNotDefined < VagrantError
|
||||
error_key(:push_strategy_not_defined)
|
||||
end
|
||||
|
||||
class PushStrategyNotLoaded < VagrantError
|
||||
error_key(:push_strategy_not_loaded)
|
||||
end
|
||||
|
||||
class PushStrategyNotProvided < VagrantError
|
||||
error_key(:push_strategy_not_provided)
|
||||
end
|
||||
|
||||
class RSyncError < VagrantError
|
||||
error_key(:rsync_error)
|
||||
end
|
||||
|
|
|
@ -150,9 +150,11 @@ module Vagrant
|
|||
# @param [Hash] extra_env This data will be passed into the action runner
|
||||
# as extra data set on the environment hash for the middleware
|
||||
# runner.
|
||||
def action(name, **opts)
|
||||
def action(name, opts=nil)
|
||||
@logger.info("Calling action: #{name} on provider #{@provider}")
|
||||
|
||||
opts ||= {}
|
||||
|
||||
# Determine whether we lock or not
|
||||
lock = true
|
||||
lock = opts.delete(:lock) if opts.has_key?(:lock)
|
||||
|
|
|
@ -16,6 +16,7 @@ module Vagrant
|
|||
autoload :Manager, "vagrant/plugin/v2/manager"
|
||||
autoload :Plugin, "vagrant/plugin/v2/plugin"
|
||||
autoload :Provider, "vagrant/plugin/v2/provider"
|
||||
autoload :Push, "vagrant/plugin/v2/push"
|
||||
autoload :Provisioner, "vagrant/plugin/v2/provisioner"
|
||||
autoload :SyncedFolder, "vagrant/plugin/v2/synced_folder"
|
||||
end
|
||||
|
|
|
@ -54,6 +54,11 @@ module Vagrant
|
|||
# @return [Hash<Symbol, Registry>]
|
||||
attr_reader :provider_capabilities
|
||||
|
||||
# This contains all the push implementations by name.
|
||||
#
|
||||
# @return [Registry<Symbol, Array<Class, Hash>>]
|
||||
attr_reader :pushes
|
||||
|
||||
# This contains all the synced folder implementations by name.
|
||||
#
|
||||
# @return [Registry<Symbol, Array<Class, Integer>>]
|
||||
|
@ -71,6 +76,7 @@ module Vagrant
|
|||
@host_capabilities = Hash.new { |h, k| h[k] = Registry.new }
|
||||
@providers = Registry.new
|
||||
@provider_capabilities = Hash.new { |h, k| h[k] = Registry.new }
|
||||
@pushes = Registry.new
|
||||
@synced_folders = Registry.new
|
||||
end
|
||||
end
|
||||
|
|
|
@ -172,6 +172,28 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
# This returns all registered pushes.
|
||||
#
|
||||
# @return [Registry]
|
||||
def pushes
|
||||
Registry.new.tap do |result|
|
||||
@registered.each do |plugin|
|
||||
result.merge!(plugin.components.pushes)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This returns all the config classes for the various pushes.
|
||||
#
|
||||
# @return [Registry]
|
||||
def push_configs
|
||||
Registry.new.tap do |result|
|
||||
@registered.each do |plugin|
|
||||
result.merge!(plugin.components.configs[:push])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This returns all synced folder implementations.
|
||||
#
|
||||
# @return [Registry]
|
||||
|
|
|
@ -221,6 +221,18 @@ module Vagrant
|
|||
data[:provisioners]
|
||||
end
|
||||
|
||||
# Registers additional pushes to be available.
|
||||
#
|
||||
# @param [String] name Name of the push.
|
||||
# @param [Hash] options List of options for the push.
|
||||
def self.push(name, options=nil, &block)
|
||||
components.pushes.register(name.to_sym) do
|
||||
[block.call, options]
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Registers additional synced folder implementations.
|
||||
#
|
||||
# @param [String] name Name of the implementation.
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
module Vagrant
|
||||
module Plugin
|
||||
module V2
|
||||
class Push
|
||||
attr_reader :env
|
||||
attr_reader :config
|
||||
|
||||
# Initializes the pusher with the given environment the push
|
||||
# configuration.
|
||||
#
|
||||
# @param [Environment] env
|
||||
# @param [Object] config Push configuration
|
||||
def initialize(env, config)
|
||||
@env = env
|
||||
@config = config
|
||||
end
|
||||
|
||||
# This is the method called when the actual pushing should be
|
||||
# done.
|
||||
#
|
||||
# No return value is expected.
|
||||
def push
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -34,7 +34,7 @@ module Vagrant
|
|||
def has_key?(key)
|
||||
@items.has_key?(key)
|
||||
end
|
||||
|
||||
|
||||
# Returns an array populated with the keys of this object.
|
||||
#
|
||||
# @return [Array]
|
||||
|
@ -49,6 +49,21 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
# Return the number of elements in this registry.
|
||||
#
|
||||
# @return [Fixnum]
|
||||
def length
|
||||
@items.keys.length
|
||||
end
|
||||
alias_method :size, :length
|
||||
|
||||
# Checks if this registry has any items.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def empty?
|
||||
@items.keys.empty?
|
||||
end
|
||||
|
||||
# Merge one registry with another and return a completely new
|
||||
# registry. Note that the result cache is completely busted, so
|
||||
# any gets on the new registry will result in a cache miss.
|
||||
|
|
|
@ -5,12 +5,12 @@ require "thread"
|
|||
module Vagrant
|
||||
@@global_lock = Mutex.new
|
||||
|
||||
# This is the default endpoint of the Vagrant Cloud in
|
||||
# This is the default endpoint of the Atlas in
|
||||
# use. API calls will be made to this for various functions
|
||||
# of Vagrant that may require remote access.
|
||||
#
|
||||
# @return [String]
|
||||
DEFAULT_SERVER_URL = "https://vagrantcloud.com"
|
||||
DEFAULT_SERVER_URL = "https://atlas.hashicorp.com"
|
||||
|
||||
# This holds a global lock for the duration of the block. This should
|
||||
# be invoked around anything that is modifying process state (such as
|
||||
|
|
|
@ -25,7 +25,7 @@ module Vagrant
|
|||
def initialize(*command)
|
||||
@options = command.last.is_a?(Hash) ? command.pop : {}
|
||||
@command = command.dup
|
||||
@command.each { |s| s.encode!(Encoding.default_external) }
|
||||
@command.each { |s| s.encode(Encoding.default_external) }
|
||||
@command[0] = Which.which(@command[0]) if !File.file?(@command[0])
|
||||
if !@command[0]
|
||||
raise Errors::CommandUnavailableWindows, file: command[0] if Platform.windows?
|
||||
|
|
|
@ -47,7 +47,7 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
o.separator ""
|
||||
o.separator "The box descriptor can be the name of a box on Vagrant Cloud,"
|
||||
o.separator "The box descriptor can be the name of a box on HashiCorp's Atlas,"
|
||||
o.separator "or a URL, or a local .box file, or a local .json file containing"
|
||||
o.separator "the catalog metadata."
|
||||
o.separator ""
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
require "rest_client"
|
||||
|
||||
module VagrantPlugins
|
||||
module LoginCommand
|
||||
class Client
|
||||
# Initializes a login client with the given Vagrant::Environment.
|
||||
#
|
||||
# @param [Vagrant::Environment] env
|
||||
def initialize(env)
|
||||
@env = env
|
||||
end
|
||||
|
||||
# Removes the token, effectively logging the user out.
|
||||
def clear_token
|
||||
token_path.delete if token_path.file?
|
||||
end
|
||||
|
||||
# Checks if the user is logged in by verifying their authentication
|
||||
# token.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def logged_in?
|
||||
token = self.token
|
||||
return false if !token
|
||||
|
||||
with_error_handling do
|
||||
url = "#{Vagrant.server_url}/api/v1/authenticate" +
|
||||
"?access_token=#{token}"
|
||||
RestClient.get(url, content_type: :json)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Login logs a user in and returns the token for that user. The token
|
||||
# is _not_ stored unless {#store_token} is called.
|
||||
#
|
||||
# @param [String] user
|
||||
# @param [String] pass
|
||||
# @return [String] token The access token, or nil if auth failed.
|
||||
def login(user, pass)
|
||||
with_error_handling do
|
||||
url = "#{Vagrant.server_url}/api/v1/authenticate"
|
||||
request = { "user" => { "login" => user, "password" => pass } }
|
||||
response = RestClient.post(
|
||||
url, JSON.dump(request), content_type: :json)
|
||||
data = JSON.load(response.to_s)
|
||||
data["token"]
|
||||
end
|
||||
end
|
||||
|
||||
# Stores the given token locally, removing any previous tokens.
|
||||
#
|
||||
# @param [String] token
|
||||
def store_token(token)
|
||||
token_path.open("w") do |f|
|
||||
f.write(token)
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# Reads the access token if there is one. This will first read the
|
||||
# `ATLAS_TOKEN` environment variable and then fallback to the stored
|
||||
# access token on disk.
|
||||
#
|
||||
# @return [String]
|
||||
def token
|
||||
if ENV["ATLAS_TOKEN"] && !ENV["ATLAS_TOKEN"].empty?
|
||||
return ENV["ATLAS_TOKEN"]
|
||||
end
|
||||
|
||||
if token_path.exist?
|
||||
return token_path.read.strip
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def with_error_handling(&block)
|
||||
yield
|
||||
rescue RestClient::Unauthorized
|
||||
false
|
||||
rescue RestClient::NotAcceptable => e
|
||||
begin
|
||||
errors = JSON.parse(e.response)["errors"].join("\n")
|
||||
raise Errors::ServerError, errors: errors
|
||||
rescue JSON::ParserError; end
|
||||
|
||||
raise "An unexpected error occurred: #{e.inspect}"
|
||||
rescue SocketError
|
||||
raise Errors::ServerUnreachable, url: Vagrant.server_url.to_s
|
||||
end
|
||||
|
||||
def token_path
|
||||
@env.data_dir.join("vagrant_login_token")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,83 @@
|
|||
module VagrantPlugins
|
||||
module LoginCommand
|
||||
class Command < Vagrant.plugin("2", "command")
|
||||
def self.synopsis
|
||||
"log in to HashiCorp's Atlas"
|
||||
end
|
||||
|
||||
def execute
|
||||
options = {}
|
||||
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant login"
|
||||
o.separator ""
|
||||
o.on("-c", "--check", "Only checks if you're logged in") do |c|
|
||||
options[:check] = c
|
||||
end
|
||||
|
||||
o.on("-k", "--logout", "Logs you out if you're logged in") do |k|
|
||||
options[:logout] = k
|
||||
end
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
|
||||
@client = Client.new(@env)
|
||||
|
||||
# Determine what task we're actually taking based on flags
|
||||
if options[:check]
|
||||
return execute_check
|
||||
elsif options[:logout]
|
||||
return execute_logout
|
||||
end
|
||||
|
||||
# Let the user know what is going on.
|
||||
@env.ui.output(I18n.t("login_command.command_header") + "\n")
|
||||
|
||||
# If it is a private cloud installation, show that
|
||||
if Vagrant.server_url != Vagrant::DEFAULT_SERVER_URL
|
||||
@env.ui.output("Atlas URL: #{Vagrant.server_url}")
|
||||
end
|
||||
|
||||
# Ask for the username
|
||||
login = nil
|
||||
password = nil
|
||||
while !login
|
||||
login = @env.ui.ask("Atlas Username: ")
|
||||
end
|
||||
|
||||
while !password
|
||||
password = @env.ui.ask("Password (will be hidden): ", echo: false)
|
||||
end
|
||||
|
||||
token = @client.login(login, password)
|
||||
if !token
|
||||
@env.ui.error(I18n.t("login_command.invalid_login"))
|
||||
return 1
|
||||
end
|
||||
|
||||
@client.store_token(token)
|
||||
@env.ui.success(I18n.t("login_command.logged_in"))
|
||||
0
|
||||
end
|
||||
|
||||
def execute_check
|
||||
if @client.logged_in?
|
||||
@env.ui.success(I18n.t("login_command.check_logged_in"))
|
||||
return 0
|
||||
else
|
||||
@env.ui.error(I18n.t("login_command.check_not_logged_in"))
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
def execute_logout
|
||||
@client.clear_token
|
||||
@env.ui.success(I18n.t("login_command.logged_out"))
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
module VagrantPlugins
|
||||
module LoginCommand
|
||||
module Errors
|
||||
class Error < Vagrant::Errors::VagrantError
|
||||
error_namespace("login_command.errors")
|
||||
end
|
||||
|
||||
class ServerError < Error
|
||||
error_key(:server_error)
|
||||
end
|
||||
|
||||
class ServerUnreachable < Error
|
||||
error_key(:server_unreachable)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
en:
|
||||
login_command:
|
||||
errors:
|
||||
server_error: |-
|
||||
The Atlas server responded with an not-OK response:
|
||||
|
||||
%{errors}
|
||||
server_unreachable: |-
|
||||
The Atlas server is not currently accepting connections. Please check
|
||||
your network connection and try again later.
|
||||
|
||||
check_logged_in: |-
|
||||
You are already logged in.
|
||||
check_not_logged_in: |-
|
||||
You are not currently logged in. Please run `vagrant login` and provide
|
||||
your login information to authenticate.
|
||||
command_header: |-
|
||||
In a moment we will ask for your username and password to HashiCorp's
|
||||
Atlas. After authenticating, we will store an access token locally on
|
||||
disk. Your login details will be transmitted over a secure connection, and
|
||||
are never stored on disk locally.
|
||||
|
||||
If you do not have an Atlas account, sign up at
|
||||
https://atlas.hashicorp.com.
|
||||
invalid_login: |-
|
||||
Invalid username or password. Please try again.
|
||||
logged_in: |-
|
||||
You are now logged in.
|
||||
logged_out: |-
|
||||
You are logged out.
|
|
@ -0,0 +1,45 @@
|
|||
require "uri"
|
||||
|
||||
require_relative "../client"
|
||||
|
||||
module VagrantPlugins
|
||||
module LoginCommand
|
||||
class AddAuthentication
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
client = Client.new(env[:env])
|
||||
token = client.token
|
||||
|
||||
if token && Vagrant.server_url
|
||||
server_uri = URI.parse(Vagrant.server_url)
|
||||
|
||||
env[:box_urls].map! do |url|
|
||||
u = URI.parse(url)
|
||||
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}"
|
||||
end
|
||||
|
||||
u.to_s
|
||||
end
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module LoginCommand
|
||||
autoload :Client, File.expand_path("../client", __FILE__)
|
||||
autoload :Errors, File.expand_path("../errors", __FILE__)
|
||||
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "vagrant-login"
|
||||
description <<-DESC
|
||||
Provides the login command and internal API access to Atlas.
|
||||
DESC
|
||||
|
||||
command(:login) do
|
||||
require_relative "command"
|
||||
init!
|
||||
Command
|
||||
end
|
||||
|
||||
action_hook(:cloud_authenticated_boxes, :authenticate_box_url) do |hook|
|
||||
require_relative "middleware/add_authentication"
|
||||
hook.prepend(AddAuthentication)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.init!
|
||||
return if defined?(@_init)
|
||||
I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
|
||||
I18n.reload!
|
||||
@_init = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -80,7 +80,7 @@ module VagrantPlugins
|
|||
acc
|
||||
end
|
||||
|
||||
vm.action(:package, opts)
|
||||
vm.action(:package, **opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
require 'optparse'
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPush
|
||||
class Command < Vagrant.plugin("2", :command)
|
||||
def self.synopsis
|
||||
"deploys code in this environment to a configured destination"
|
||||
end
|
||||
|
||||
# @todo support multiple strategies if requested by the community
|
||||
def execute
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = "Usage: vagrant push [strategy] [options]"
|
||||
end
|
||||
|
||||
# Parse the options
|
||||
argv = parse_options(opts)
|
||||
return if !argv
|
||||
|
||||
name = validate_pushes!(@env.pushes, argv[0])
|
||||
|
||||
# Validate the configuration
|
||||
@env.machine(@env.machine_names.first, @env.default_provider).action_raw(
|
||||
:config_validate,
|
||||
Vagrant::Action::Builtin::ConfigValidate)
|
||||
|
||||
@logger.debug("'push' environment with strategy: `#{name}'")
|
||||
@env.push(name)
|
||||
|
||||
0
|
||||
end
|
||||
|
||||
# Validate that the given list of names corresponds to valid pushes.
|
||||
#
|
||||
# @raise Vagrant::Errors::PushesNotDefined
|
||||
# if there are no pushes defined
|
||||
# @raise Vagrant::Errors::PushStrategyNotProvided
|
||||
# if there are multiple push strategies defined and none were specified
|
||||
# @raise Vagrant::Errors::PushStrategyNotDefined
|
||||
# if the given push name do not correspond to a push strategy
|
||||
#
|
||||
# @param [Array<Symbol>] pushes
|
||||
# the list of pushes defined by the environment
|
||||
# @param [String] name
|
||||
# the name provided by the user on the command line
|
||||
#
|
||||
# @return [Symbol]
|
||||
# the compiled list of pushes
|
||||
#
|
||||
def validate_pushes!(pushes, name = nil)
|
||||
if pushes.nil? || pushes.empty?
|
||||
raise Vagrant::Errors::PushesNotDefined
|
||||
end
|
||||
|
||||
if name.nil?
|
||||
if pushes.length == 1
|
||||
return pushes.first.to_sym
|
||||
else
|
||||
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.to_s,
|
||||
pushes: pushes.map(&:to_s)
|
||||
end
|
||||
|
||||
return name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module CommandPush
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "push command"
|
||||
description <<-DESC
|
||||
The `push` command deploys code in this environment.
|
||||
DESC
|
||||
|
||||
command("push") do
|
||||
require File.expand_path("../command", __FILE__)
|
||||
Command
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -19,6 +19,8 @@ module VagrantPlugins
|
|||
parser.on("--provision-with x,y,z", Array,
|
||||
"Enable only certain provisioners, by type.") do |list|
|
||||
options[:provision_types] = list.map { |type| type.to_sym }
|
||||
options[:provision_enabled] = true
|
||||
options[:provision_ignore_sentinel] = true
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -79,12 +79,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)
|
||||
|
@ -156,8 +165,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,
|
||||
|
@ -167,6 +176,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|
|
||||
|
|
|
@ -26,7 +26,7 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
interface_names = networks.map do |network|
|
||||
"eth#{network[:interface]}"
|
||||
"#{interface_names[network[:interface]]}"
|
||||
end
|
||||
else
|
||||
machine.communicate.sudo("/usr/sbin/biosdevname -d | grep Kernel | cut -f2 -d: | sed -e 's/ //;'") do |_, result|
|
||||
|
|
|
@ -8,6 +8,8 @@ module VagrantPlugins
|
|||
nfs_version_mount_option="-o nfsv#{opts[:nfs_version]}"
|
||||
end
|
||||
|
||||
machine.communicate.sudo("mkdir -p #{opts[:guestpath]}", {shell: "sh"})
|
||||
|
||||
machine.communicate.sudo(
|
||||
"mount -t nfs #{nfs_version_mount_option} " +
|
||||
"'#{ip}:#{opts[:hostpath]}' '#{opts[:guestpath]}'", {shell: "sh"})
|
||||
|
|
|
@ -17,10 +17,10 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def self.rsync_post(machine, opts)
|
||||
su_cmd = machine.config.solaris.su_cmd
|
||||
suexec_cmd = machine.config.solaris.suexec_cmd
|
||||
machine.communicate.execute(
|
||||
"#{su_cmd} find '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
|
||||
"xargs -0 -r chown #{opts[:owner]}:#{opts[:group]}")
|
||||
"#{suexec_cmd} find '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
|
||||
"xargs -0 chown #{opts[:owner]}:#{opts[:group]}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,24 +3,28 @@ module VagrantPlugins
|
|||
class Config < Vagrant.plugin("2", :config)
|
||||
attr_accessor :halt_timeout
|
||||
attr_accessor :halt_check_interval
|
||||
# This sets the command to use to execute items as a superuser. sudo is default
|
||||
|
||||
attr_accessor :suexec_cmd
|
||||
attr_accessor :device
|
||||
|
||||
def initialize
|
||||
@halt_timeout = UNSET_VALUE
|
||||
@halt_check_interval = UNSET_VALUE
|
||||
@suexec_cmd = 'sudo'
|
||||
@device = "e1000g"
|
||||
@suexec_cmd = UNSET_VALUE
|
||||
@device = UNSET_VALUE
|
||||
end
|
||||
|
||||
def finalize!
|
||||
if @halt_timeout != UNSET_VALUE
|
||||
puts "solaris.halt_timeout is deprecated and will be removed in Vagrant 1.7"
|
||||
end
|
||||
|
||||
if @halt_check_interval != UNSET_VALUE
|
||||
puts "solaris.halt_check_interval is deprecated and will be removed in Vagrant 1.7"
|
||||
end
|
||||
|
||||
@suexec_cmd = "sudo" if @suexec_cmd == UNSET_VALUE
|
||||
@device = "e1000g" if @device == UNSET_VALUE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,10 +17,10 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def self.rsync_post(machine, opts)
|
||||
su_cmd = machine.config.solaris11.su_cmd
|
||||
suexec_cmd = machine.config.solaris11.suexec_cmd
|
||||
machine.communicate.execute(
|
||||
"#{su_cmd} '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
|
||||
"xargs -0 -r chown #{opts[:owner]}:#{opts[:group]}")
|
||||
"#{suexec_cmd} '#{opts[:guestpath]}' '(' ! -user #{opts[:owner]} -or ! -group #{opts[:group]} ')' -print0 | " +
|
||||
"xargs -0 chown #{opts[:owner]}:#{opts[:group]}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -137,7 +137,7 @@ module VagrantPlugins
|
|||
user = Process.uid
|
||||
|
||||
File.read("/etc/exports").lines.each do |line|
|
||||
if id = line[/^# VAGRANT-BEGIN:( #{user})? ([\.\/A-Za-z0-9-_]+?)$/, 2]
|
||||
if id = line[/^# VAGRANT-BEGIN:( #{user})? ([\.\/A-Za-z0-9\-_]+?)$/, 2]
|
||||
if valid_ids.include?(id)
|
||||
logger.debug("Valid ID: #{id}")
|
||||
else
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module Kernel_V2
|
||||
class PushConfig < Vagrant.plugin("2", :config)
|
||||
VALID_OPTIONS = [:strategy].freeze
|
||||
|
||||
attr_accessor :name
|
||||
|
||||
def initialize
|
||||
@logger = Log4r::Logger.new("vagrant::config::push")
|
||||
|
||||
# Internal state
|
||||
@__defined_pushes = {}
|
||||
@__compiled_pushes = {}
|
||||
@__finalized = false
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@logger.debug("finalizing")
|
||||
|
||||
# Compile all the provider configurations
|
||||
@__defined_pushes.each do |name, tuples|
|
||||
# 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
|
||||
# config object.
|
||||
if s != strategy
|
||||
@logger.warn("duplicate strategy defined, overwriting config")
|
||||
strategy = s
|
||||
config = config_class.new
|
||||
end
|
||||
|
||||
# If we don't have any blocks, then ignore it
|
||||
next if b.nil?
|
||||
|
||||
new_config = config_class.new
|
||||
b.call(new_config, Vagrant::Config::V2::DummyConfig.new)
|
||||
config = config.merge(new_config)
|
||||
end
|
||||
rescue Exception => e
|
||||
raise Vagrant::Errors::VagrantfileLoadError,
|
||||
path: "<push config: #{name}>",
|
||||
message: e.message
|
||||
end
|
||||
|
||||
config.finalize!
|
||||
|
||||
# Store it for retrieval later
|
||||
@__compiled_pushes[name] = [strategy, config]
|
||||
end
|
||||
|
||||
@__finalized = true
|
||||
end
|
||||
|
||||
# Define a new push in the Vagrantfile with the given name.
|
||||
#
|
||||
# @example
|
||||
# vm.push.define "ftp"
|
||||
#
|
||||
# @example
|
||||
# vm.push.define "ftp" do |s|
|
||||
# s.host = "..."
|
||||
# end
|
||||
#
|
||||
# @example
|
||||
# vm.push.define "production", strategy: "docker" do |s|
|
||||
# # ...
|
||||
# end
|
||||
#
|
||||
# @param [#to_sym] name The name of the this strategy. By default, this
|
||||
# is also the name of the strategy, but the `:strategy` key can be given
|
||||
# to customize this behavior
|
||||
# @param [Hash] options The list of options
|
||||
#
|
||||
def define(name, **options, &block)
|
||||
name = name.to_sym
|
||||
strategy = options[:strategy] || name
|
||||
|
||||
@__defined_pushes[name] ||= []
|
||||
@__defined_pushes[name] << [strategy.to_sym, block]
|
||||
end
|
||||
|
||||
# The String representation of this Push.
|
||||
#
|
||||
# @return [String]
|
||||
def to_s
|
||||
"Push"
|
||||
end
|
||||
|
||||
# Custom merge method
|
||||
def merge(other)
|
||||
super.tap do |result|
|
||||
other_pushes = other.instance_variable_get(:@__defined_pushes)
|
||||
new_pushes = @__defined_pushes.dup
|
||||
|
||||
other_pushes.each do |key, tuples|
|
||||
new_pushes[key] ||= []
|
||||
new_pushes[key] += tuples
|
||||
end
|
||||
|
||||
result.instance_variable_set(:@__defined_pushes, new_pushes)
|
||||
end
|
||||
end
|
||||
|
||||
# This returns the list of compiled pushes as a hash by name.
|
||||
#
|
||||
# @return [Hash<Symbol, Array<Class, Object>>]
|
||||
def __compiled_pushes
|
||||
raise "Must finalize first!" if !@__finalized
|
||||
@__compiled_pushes.dup
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,6 +25,11 @@ module VagrantPlugins
|
|||
PackageConfig
|
||||
end
|
||||
|
||||
config("push") do
|
||||
require File.expand_path("../config/push", __FILE__)
|
||||
PushConfig
|
||||
end
|
||||
|
||||
config("vagrant") do
|
||||
require File.expand_path("../config/vagrant", __FILE__)
|
||||
VagrantConfig
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,7 +10,7 @@ forEach ($module in $modules) { . $module }
|
|||
|
||||
try {
|
||||
$vm = Get-VM -Id $VmId -ErrorAction "stop"
|
||||
Start-VM $vm
|
||||
Start-VM $vm -ErrorAction "stop"
|
||||
$state = $vm.state
|
||||
$status = $vm.status
|
||||
$name = $vm.name
|
||||
|
@ -24,4 +24,4 @@ try {
|
|||
}
|
||||
catch {
|
||||
Write-Error-Message "Failed to start a VM $_"
|
||||
}
|
||||
}
|
|
@ -143,7 +143,7 @@ module VagrantPlugins
|
|||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
|
||||
valid_events = ["pre-import", "pre-boot", "post-boot"]
|
||||
valid_events = ["pre-import", "pre-boot", "post-boot", "post-comm"]
|
||||
@customizations.each do |event, _|
|
||||
if !valid_events.include?(event)
|
||||
errors << I18n.t(
|
||||
|
|
|
@ -452,11 +452,11 @@ module VagrantPlugins
|
|||
folder[:hostpath]]
|
||||
args << "--transient" if folder.has_key?(:transient) && folder[:transient]
|
||||
|
||||
# Add the shared folder
|
||||
execute("sharedfolder", "add", @uuid, *args)
|
||||
|
||||
# Enable symlinks on the shared folder
|
||||
execute("setextradata", @uuid, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/#{folder[:name]}", "1")
|
||||
|
||||
# Add the shared folder
|
||||
execute("sharedfolder", "add", @uuid, *args)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -483,11 +483,11 @@ module VagrantPlugins
|
|||
folder[:hostpath]]
|
||||
args << "--transient" if folder.has_key?(:transient) && folder[:transient]
|
||||
|
||||
# Add the shared folder
|
||||
execute("sharedfolder", "add", @uuid, *args)
|
||||
|
||||
# Enable symlinks on the shared folder
|
||||
execute("setextradata", @uuid, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/#{folder[:name]}", "1")
|
||||
|
||||
# Add the shared folder
|
||||
execute("sharedfolder", "add", @uuid, *args)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -500,11 +500,11 @@ module VagrantPlugins
|
|||
folder[:hostpath]]
|
||||
args << "--transient" if folder.has_key?(:transient) && folder[:transient]
|
||||
|
||||
# Add the shared folder
|
||||
execute("sharedfolder", "add", @uuid, *args)
|
||||
|
||||
# Enable symlinks on the shared folder
|
||||
execute("setextradata", @uuid, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/#{folder[:name]}", "1")
|
||||
|
||||
# Add the shared folder
|
||||
execute("sharedfolder", "add", @uuid, *args)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -12,31 +12,24 @@ module VagrantPlugins
|
|||
@ssh_info = @machine.ssh_info
|
||||
|
||||
#
|
||||
# 1) Default Settings (lowest precedence)
|
||||
# Ansible provisioner options
|
||||
#
|
||||
|
||||
# Connect with Vagrant SSH identity
|
||||
options = %W[--private-key=#{@ssh_info[:private_key_path][0]} --user=#{@ssh_info[:username]}]
|
||||
|
||||
# Multiple SSH keys and/or SSH forwarding can be passed via
|
||||
# ANSIBLE_SSH_ARGS environment variable, which requires 'ssh' mode.
|
||||
# Note that multiple keys and ssh-forwarding settings are not supported
|
||||
# by deprecated 'paramiko' mode.
|
||||
options << "--connection=ssh" unless ansible_ssh_args.empty?
|
||||
# Connect with native OpenSSH client
|
||||
# Other modes (e.g. paramiko) are not officially supported,
|
||||
# but can be enabled via raw_arguments option.
|
||||
options << "--connection=ssh"
|
||||
|
||||
# By default we limit by the current machine.
|
||||
# This can be overridden by the limit config option.
|
||||
options << "--limit=#{@machine.name}" unless config.limit
|
||||
|
||||
#
|
||||
# 2) Configuration Joker
|
||||
#
|
||||
|
||||
options.concat(self.as_array(config.raw_arguments)) if config.raw_arguments
|
||||
|
||||
#
|
||||
# 3) Append Provisioner options (highest precedence):
|
||||
#
|
||||
# By default we limit by the current machine, but
|
||||
# this can be overridden by the `limit` option.
|
||||
if config.limit
|
||||
options << "--limit=#{as_list_argument(config.limit)}"
|
||||
else
|
||||
options << "--limit=#{@machine.name}"
|
||||
end
|
||||
|
||||
options << "--inventory-file=#{self.setup_inventory_file}"
|
||||
options << "--extra-vars=#{self.get_extra_vars_argument}" if config.extra_vars
|
||||
|
@ -48,22 +41,29 @@ module VagrantPlugins
|
|||
options << "--vault-password-file=#{config.vault_password_file}" if config.vault_password_file
|
||||
options << "--tags=#{as_list_argument(config.tags)}" if config.tags
|
||||
options << "--skip-tags=#{as_list_argument(config.skip_tags)}" if config.skip_tags
|
||||
options << "--limit=#{as_list_argument(config.limit)}" if config.limit
|
||||
options << "--start-at-task=#{config.start_at_task}" if config.start_at_task
|
||||
|
||||
# Finally, add the raw configuration options, which has the highest precedence
|
||||
# and can therefore potentially override any other options of this provisioner.
|
||||
options.concat(self.as_array(config.raw_arguments)) if config.raw_arguments
|
||||
|
||||
#
|
||||
# Assemble the full ansible-playbook command
|
||||
#
|
||||
|
||||
command = (%w(ansible-playbook) << options << config.playbook).flatten
|
||||
|
||||
# Some Ansible options must be passed as environment variables
|
||||
env = {
|
||||
"ANSIBLE_FORCE_COLOR" => "true",
|
||||
"ANSIBLE_HOST_KEY_CHECKING" => "#{config.host_key_checking}",
|
||||
|
||||
# Ensure Ansible output isn't buffered so that we receive output
|
||||
# on a task-by-task basis.
|
||||
"PYTHONUNBUFFERED" => 1
|
||||
"PYTHONUNBUFFERED" => 1,
|
||||
|
||||
# Some Ansible options must be passed as environment variables,
|
||||
# as there is no equivalent command line arguments
|
||||
"ANSIBLE_FORCE_COLOR" => "true",
|
||||
"ANSIBLE_HOST_KEY_CHECKING" => "#{config.host_key_checking}",
|
||||
}
|
||||
# Support Multiple SSH keys and SSH forwarding:
|
||||
# ANSIBLE_SSH_ARGS is required for Multiple SSH keys, SSH forwarding and custom SSH settings
|
||||
env["ANSIBLE_SSH_ARGS"] = ansible_ssh_args unless ansible_ssh_args.empty?
|
||||
|
||||
show_ansible_playbook_command(env, command) if (config.verbose || @logger.debug?)
|
||||
|
@ -183,9 +183,32 @@ module VagrantPlugins
|
|||
@ansible_ssh_args ||= get_ansible_ssh_args
|
||||
end
|
||||
|
||||
# Use ANSIBLE_SSH_ARGS to pass some OpenSSH options that are not wrapped by
|
||||
# an ad-hoc Ansible option. Last update corresponds to Ansible 1.8
|
||||
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
|
||||
|
||||
# Multiple Private Keys
|
||||
@ssh_info[:private_key_path].drop(1).each do |key|
|
||||
ssh_options << "-o IdentityFile=#{key}"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,7 +10,7 @@ module VagrantPlugins
|
|||
name "chef"
|
||||
description <<-DESC
|
||||
Provides support for provisioning your virtual machines with
|
||||
Chef via `chef-solo`, `chef-client`, or `chef-apply`.
|
||||
Chef via `chef-solo`, `chef-client`, `chef-zero` or `chef-apply`.
|
||||
DESC
|
||||
|
||||
config(:chef_apply, :provisioner) do
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -34,7 +34,7 @@ module VagrantPlugins
|
|||
share_folders(root_config, "cse", @environments_folders)
|
||||
end
|
||||
|
||||
def provision
|
||||
def provision(mode = :solo)
|
||||
install_chef
|
||||
# Verify that the proper shared folders exist.
|
||||
check = []
|
||||
|
@ -51,7 +51,7 @@ module VagrantPlugins
|
|||
upload_encrypted_data_bag_secret
|
||||
setup_json
|
||||
setup_solo_config
|
||||
run_chef_solo
|
||||
run_chef(mode)
|
||||
delete_encrypted_data_bag_secret
|
||||
end
|
||||
|
||||
|
@ -130,7 +130,7 @@ module VagrantPlugins
|
|||
}
|
||||
end
|
||||
|
||||
def run_chef_solo
|
||||
def run_chef(mode)
|
||||
if @config.run_list && @config.run_list.empty?
|
||||
@machine.ui.warn(I18n.t("vagrant.chef_run_list_empty"))
|
||||
end
|
||||
|
@ -143,9 +143,9 @@ module VagrantPlugins
|
|||
|
||||
@config.attempts.times do |attempt|
|
||||
if attempt == 0
|
||||
@machine.ui.info I18n.t("vagrant.provisioners.chef.running_solo")
|
||||
@machine.ui.info I18n.t("vagrant.provisioners.chef.running_#{mode}")
|
||||
else
|
||||
@machine.ui.info I18n.t("vagrant.provisioners.chef.running_solo_again")
|
||||
@machine.ui.info I18n.t("vagrant.provisioners.chef.running_#{mode}_again")
|
||||
end
|
||||
|
||||
opts = { error_check: false, elevated: true }
|
||||
|
|
|
@ -22,6 +22,10 @@ module VagrantPlugins
|
|||
share_folders(root_config, "csn", @node_folders)
|
||||
end
|
||||
|
||||
def provision
|
||||
super(:zero)
|
||||
end
|
||||
|
||||
def solo_config
|
||||
super.merge(
|
||||
local_mode: true,
|
||||
|
|
|
@ -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
|
||||
|
@ -306,7 +311,7 @@ module VagrantPlugins
|
|||
@machine.communicate.sudo("salt '*' saltutil.sync_all")
|
||||
@machine.communicate.sudo("salt '*' state.highstate --verbose#{get_loglevel}#{get_colorize}#{get_pillar}") do |type, data|
|
||||
if @config.verbose
|
||||
@machine.env.ui.info(data)
|
||||
@machine.env.ui.info(data.rstrip)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
@ -315,14 +320,14 @@ module VagrantPlugins
|
|||
@machine.communicate.execute("C:\\salt\\salt-call.exe saltutil.sync_all", opts)
|
||||
@machine.communicate.execute("C:\\salt\\salt-call.exe state.highstate --retcode-passthrough #{get_loglevel}#{get_colorize}#{get_pillar}", opts) do |type, data|
|
||||
if @config.verbose
|
||||
@machine.env.ui.info(data)
|
||||
@machine.env.ui.info(data.rstrip)
|
||||
end
|
||||
end
|
||||
else
|
||||
@machine.communicate.sudo("salt-call saltutil.sync_all")
|
||||
@machine.communicate.sudo("salt-call state.highstate --retcode-passthrough #{get_loglevel}#{get_colorize}#{get_pillar}") do |type, data|
|
||||
if @config.verbose
|
||||
@machine.env.ui.info(data)
|
||||
@machine.env.ui.info(data.rstrip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
module VagrantPlugins
|
||||
module AtlasPush
|
||||
class Config < Vagrant.plugin("2", :config)
|
||||
# The address of the Atlas server to upload to. By default this will
|
||||
# be the public Atlas server.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :address
|
||||
|
||||
# The Atlas token to use. If the user has run `vagrant login`, this will
|
||||
# use that token. If the environment variable `ATLAS_TOKEN` is set, the
|
||||
# uploader will use this value. By default, this is nil.
|
||||
#
|
||||
# @return [String, nil]
|
||||
attr_accessor :token
|
||||
|
||||
# The name of the application to push to. This will be created (with
|
||||
# user confirmation) if it doesn't already exist.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :app
|
||||
|
||||
# The base directory with file contents to upload. By default this
|
||||
# is the same directory as the Vagrantfile, but you can specify this
|
||||
# if you have a `src` folder or `bin` folder or some other folder
|
||||
# you want to upload.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :dir
|
||||
|
||||
# Lists of files to include/exclude in what is uploaded. Exclude is
|
||||
# always the last run filter, so if a file is matched in both include
|
||||
# and exclude, it will be excluded.
|
||||
#
|
||||
# The value of the array elements should be a simple file glob relative
|
||||
# to the directory being packaged.
|
||||
#
|
||||
# @return [Array<String>]
|
||||
attr_accessor :includes
|
||||
attr_accessor :excludes
|
||||
|
||||
# If set to true, Vagrant will automatically use VCS data to determine
|
||||
# the files to upload. As a caveat: uncommitted changes will not be
|
||||
# deployed.
|
||||
#
|
||||
# @return [Boolean]
|
||||
attr_accessor :vcs
|
||||
|
||||
# The path to the uploader binary to shell out to. This usually
|
||||
# is only set for debugging/development. If not set, the uploader
|
||||
# will be looked for within the Vagrant installer dir followed by
|
||||
# the PATH.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :uploader_path
|
||||
|
||||
def initialize
|
||||
@address = UNSET_VALUE
|
||||
@token = UNSET_VALUE
|
||||
@app = UNSET_VALUE
|
||||
@dir = UNSET_VALUE
|
||||
@vcs = UNSET_VALUE
|
||||
@includes = []
|
||||
@excludes = []
|
||||
@uploader_path = UNSET_VALUE
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
super.tap do |result|
|
||||
result.includes = self.includes.dup.concat(other.includes).uniq
|
||||
result.excludes = self.excludes.dup.concat(other.excludes).uniq
|
||||
end
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@address = nil if @address == UNSET_VALUE
|
||||
@token = nil if @token == UNSET_VALUE
|
||||
@app = nil if @app == UNSET_VALUE
|
||||
@dir = "." if @dir == UNSET_VALUE
|
||||
@uploader_path = nil if @uploader_path == UNSET_VALUE
|
||||
@vcs = true if @vcs == UNSET_VALUE
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
|
||||
if missing?(@token)
|
||||
token = token_from_vagrant_login(machine.env)
|
||||
if missing?(token)
|
||||
errors << I18n.t("atlas_push.errors.missing_token")
|
||||
else
|
||||
@token = token
|
||||
end
|
||||
end
|
||||
|
||||
if missing?(@app)
|
||||
errors << I18n.t("atlas_push.errors.missing_attribute",
|
||||
attribute: "app",
|
||||
)
|
||||
end
|
||||
|
||||
if missing?(@dir)
|
||||
errors << I18n.t("atlas_push.errors.missing_attribute",
|
||||
attribute: "dir",
|
||||
)
|
||||
end
|
||||
|
||||
{ "Atlas push" => errors }
|
||||
end
|
||||
|
||||
# Add the filepath to the list of includes
|
||||
# @param [String] filepath
|
||||
def include(filepath)
|
||||
@includes << filepath
|
||||
end
|
||||
alias_method :include=, :include
|
||||
|
||||
# Add the filepath to the list of excludes
|
||||
# @param [String] filepath
|
||||
def exclude(filepath)
|
||||
@excludes << filepath
|
||||
end
|
||||
alias_method :exclude=, :exclude
|
||||
|
||||
private
|
||||
|
||||
# Determine if the given string is "missing" (blank)
|
||||
# @return [true, false]
|
||||
def missing?(obj)
|
||||
obj.to_s.strip.empty?
|
||||
end
|
||||
|
||||
# Attempt to load the token from disk using the vagrant-login plugin. If
|
||||
# the constant is not defined, that means the user is operating in some
|
||||
# bespoke and unsupported Ruby environment.
|
||||
#
|
||||
# @param [Vagrant::Environment] env
|
||||
#
|
||||
# @return [String, nil]
|
||||
# the token, or nil if it does not exist
|
||||
def token_from_vagrant_login(env)
|
||||
client = VagrantPlugins::LoginCommand::Client.new(env)
|
||||
client.token
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module VagrantPlugins
|
||||
module AtlasPush
|
||||
module Errors
|
||||
class Error < Vagrant::Errors::VagrantError
|
||||
error_namespace("atlas_push.errors")
|
||||
end
|
||||
|
||||
class UploaderNotFound < Error
|
||||
error_key(:uploader_not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
en:
|
||||
atlas_push:
|
||||
errors:
|
||||
missing_attribute: |-
|
||||
Missing required attribute '%{attribute}'. The Vagrant Atlas Push plugin
|
||||
requires you set this attribute. Please set this attribute in your
|
||||
Vagrantfile, for example:
|
||||
|
||||
config.push.define "atlas" do |push|
|
||||
push.%{attribute} = "..."
|
||||
end
|
||||
missing_token: |-
|
||||
Missing required configuration parameter 'token'. This is required for
|
||||
Vagrant to securely communicate with your Atlas account.
|
||||
|
||||
To generate an access token, run 'vagrant login'.
|
||||
uploader_not_found: |-
|
||||
Vagrant was unable to find the Atlas uploader CLI. If your Vagrantfile
|
||||
specifies the path explicitly with "uploader_path", then make sure that
|
||||
path is valid. Otherwise, make sure that you have a valid install of
|
||||
Vagrant. If you installed Vagrant outside of the official installers,
|
||||
the "atlas-upload" binary must exist on your PATH.
|
|
@ -0,0 +1,35 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module AtlasPush
|
||||
autoload :Errors, File.expand_path("../errors", __FILE__)
|
||||
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "atlas"
|
||||
description <<-DESC
|
||||
Deploy using HashiCorp's Atlas service.
|
||||
DESC
|
||||
|
||||
config(:atlas, :push) do
|
||||
require_relative "config"
|
||||
init!
|
||||
Config
|
||||
end
|
||||
|
||||
push(:atlas) do
|
||||
require_relative "push"
|
||||
init!
|
||||
Push
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.init!
|
||||
return if defined?(@_init)
|
||||
I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
|
||||
I18n.reload!
|
||||
@_init = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
require "vagrant/util/safe_exec"
|
||||
require "vagrant/util/subprocess"
|
||||
require "vagrant/util/which"
|
||||
|
||||
module VagrantPlugins
|
||||
module AtlasPush
|
||||
class Push < Vagrant.plugin("2", :push)
|
||||
UPLOADER_BIN = "atlas-upload".freeze
|
||||
|
||||
def push
|
||||
uploader = self.uploader_path
|
||||
|
||||
# If we didn't find the uploader binary it is a critical error
|
||||
raise Errors::UploaderNotFound if !uploader
|
||||
|
||||
# We found it. Build up the command and the args.
|
||||
execute(uploader)
|
||||
return 0
|
||||
end
|
||||
|
||||
# Executes the uploader with the proper flags based on the configuration.
|
||||
# This function shouldn't return since it will exec, but might return
|
||||
# if we're on a system that doesn't support exec, so handle that properly.
|
||||
def execute(uploader)
|
||||
cmd = []
|
||||
cmd << "-vcs" if config.vcs
|
||||
cmd += config.includes.map { |v| ["-include", v] }
|
||||
cmd += config.excludes.map { |v| ["-exclude", v] }
|
||||
cmd += ["-address", config.address] if config.address
|
||||
cmd += ["-token", config.token] if config.token
|
||||
cmd << config.app
|
||||
cmd << File.expand_path(config.dir, env.root_path)
|
||||
Vagrant::Util::SafeExec.exec(uploader, *cmd.flatten)
|
||||
end
|
||||
|
||||
# This returns the path to the uploader binary, or nil if it can't
|
||||
# be found.
|
||||
#
|
||||
# @return [String]
|
||||
def uploader_path
|
||||
# Determine the uploader path
|
||||
uploader = config.uploader_path
|
||||
if uploader
|
||||
return uploader
|
||||
end
|
||||
|
||||
if Vagrant.in_installer?
|
||||
path = File.join(
|
||||
Vagrant.installer_embedded_dir, "bin", UPLOADER_BIN)
|
||||
return path if File.file?(path)
|
||||
end
|
||||
|
||||
return Vagrant::Util::Which.which(UPLOADER_BIN)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,118 @@
|
|||
require "pathname"
|
||||
|
||||
module VagrantPlugins
|
||||
module FTPPush
|
||||
class Adapter
|
||||
attr_reader :host
|
||||
attr_reader :port
|
||||
attr_reader :username
|
||||
attr_reader :password
|
||||
attr_reader :options
|
||||
attr_reader :server
|
||||
|
||||
def initialize(host, username, password, options = {})
|
||||
@host, @port = parse_host(host)
|
||||
@username = username
|
||||
@password = password
|
||||
@options = options
|
||||
@server = nil
|
||||
end
|
||||
|
||||
# Parse the host into it's url and port parts.
|
||||
# @return [Array]
|
||||
def parse_host(host)
|
||||
if host.include?(":")
|
||||
split = host.split(":", 2)
|
||||
[split[0], split[1].to_i]
|
||||
else
|
||||
[host, default_port]
|
||||
end
|
||||
end
|
||||
|
||||
def default_port
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def connect(&block)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def upload(local, remote)
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# The FTP Adapter
|
||||
#
|
||||
class FTPAdapter < Adapter
|
||||
def initialize(*)
|
||||
require "net/ftp"
|
||||
super
|
||||
end
|
||||
|
||||
def default_port
|
||||
21
|
||||
end
|
||||
|
||||
def connect(&block)
|
||||
@server = Net::FTP.new
|
||||
@server.passive = options.fetch(:passive, true)
|
||||
@server.connect(host, port)
|
||||
@server.login(username, password)
|
||||
|
||||
begin
|
||||
yield self
|
||||
ensure
|
||||
@server.close
|
||||
end
|
||||
end
|
||||
|
||||
def upload(local, remote)
|
||||
parent = File.dirname(remote)
|
||||
fullpath = Pathname.new(File.expand_path(parent, pwd))
|
||||
|
||||
# Create the parent directories if they does not exist (naive mkdir -p)
|
||||
fullpath.descend do |path|
|
||||
if @server.list(path.to_s).empty?
|
||||
@server.mkdir(path.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
# Upload the file
|
||||
@server.putbinaryfile(local, remote)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def pwd
|
||||
@pwd ||= @server.pwd
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# The SFTP Adapter
|
||||
#
|
||||
class SFTPAdapter < Adapter
|
||||
def initialize(*)
|
||||
require "net/sftp"
|
||||
super
|
||||
end
|
||||
|
||||
def default_port
|
||||
22
|
||||
end
|
||||
|
||||
def connect(&block)
|
||||
Net::SFTP.start(@host, @username, password: @password, port: @port) do |server|
|
||||
@server = server
|
||||
yield self
|
||||
end
|
||||
end
|
||||
|
||||
def upload(local, remote)
|
||||
@server.upload!(local, remote, mkdir: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,130 @@
|
|||
module VagrantPlugins
|
||||
module FTPPush
|
||||
class Config < Vagrant.plugin("2", :config)
|
||||
# The (S)FTP host to use.
|
||||
# @return [String]
|
||||
attr_accessor :host
|
||||
|
||||
# The username to use for authentication with the (S)FTP server.
|
||||
# @return [String]
|
||||
attr_accessor :username
|
||||
|
||||
# The password to use for authentication with the (S)FTP server.
|
||||
# @return [String]
|
||||
attr_accessor :password
|
||||
|
||||
# Use passive FTP (default is true).
|
||||
# @return [true, false]
|
||||
attr_accessor :passive
|
||||
|
||||
# Use secure (SFTP) (default is false).
|
||||
# @return [true, false]
|
||||
attr_accessor :secure
|
||||
|
||||
# The root destination on the target system to sync the files (default is
|
||||
# /).
|
||||
# @return [String]
|
||||
attr_accessor :destination
|
||||
|
||||
# Lists of files to include/exclude in what is uploaded. Exclude is
|
||||
# always the last run filter, so if a file is matched in both include
|
||||
# and exclude, it will be excluded.
|
||||
#
|
||||
# The value of the array elements should be a simple file glob relative
|
||||
# to the directory being packaged.
|
||||
# @return [Array<String>]
|
||||
attr_accessor :includes
|
||||
attr_accessor :excludes
|
||||
|
||||
# The base directory with file contents to upload. By default this
|
||||
# is the same directory as the Vagrantfile, but you can specify this
|
||||
# if you have a `src` folder or `bin` folder or some other folder
|
||||
# you want to upload.
|
||||
# @return [String]
|
||||
attr_accessor :dir
|
||||
|
||||
def initialize
|
||||
@host = UNSET_VALUE
|
||||
@username = UNSET_VALUE
|
||||
@password = UNSET_VALUE
|
||||
@passive = UNSET_VALUE
|
||||
@secure = UNSET_VALUE
|
||||
@destination = UNSET_VALUE
|
||||
|
||||
@includes = []
|
||||
@excludes = []
|
||||
|
||||
@dir = UNSET_VALUE
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
super.tap do |result|
|
||||
result.includes = self.includes.dup.concat(other.includes).uniq
|
||||
result.excludes = self.excludes.dup.concat(other.excludes).uniq
|
||||
end
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@host = nil if @host == UNSET_VALUE
|
||||
@username = nil if @username == UNSET_VALUE
|
||||
@password = nil if @password == UNSET_VALUE
|
||||
@passive = true if @passive == UNSET_VALUE
|
||||
@secure = false if @secure == UNSET_VALUE
|
||||
@destination = "/" if @destination == UNSET_VALUE
|
||||
@dir = "." if @dir == UNSET_VALUE
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
|
||||
if missing?(@host)
|
||||
errors << I18n.t("ftp_push.errors.missing_attribute",
|
||||
attribute: "host",
|
||||
)
|
||||
end
|
||||
|
||||
if missing?(@username)
|
||||
errors << I18n.t("ftp_push.errors.missing_attribute",
|
||||
attribute: "username",
|
||||
)
|
||||
end
|
||||
|
||||
if missing?(@destination)
|
||||
errors << I18n.t("ftp_push.errors.missing_attribute",
|
||||
attribute: "destination",
|
||||
)
|
||||
end
|
||||
|
||||
if missing?(@dir)
|
||||
errors << I18n.t("ftp_push.errors.missing_attribute",
|
||||
attribute: "dir",
|
||||
)
|
||||
end
|
||||
|
||||
{ "FTP push" => errors }
|
||||
end
|
||||
|
||||
# Add the filepath to the list of includes
|
||||
# @param [String] filepath
|
||||
def include(filepath)
|
||||
@includes << filepath
|
||||
end
|
||||
alias_method :include=, :include
|
||||
|
||||
# Add the filepath to the list of excludes
|
||||
# @param [String] filepath
|
||||
def exclude(filepath)
|
||||
@excludes << filepath
|
||||
end
|
||||
alias_method :exclude=, :exclude
|
||||
|
||||
private
|
||||
|
||||
# Determine if the given string is "missing" (blank)
|
||||
# @return [true, false]
|
||||
def missing?(obj)
|
||||
obj.to_s.strip.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
en:
|
||||
ftp_push:
|
||||
errors:
|
||||
missing_attribute: |-
|
||||
Missing required attribute '%{attribute}'. The Vagrant FTP Push plugin
|
||||
requires you set this attribute. Please set this attribute in your
|
||||
Vagrantfile, for example:
|
||||
|
||||
config.push.define "ftp" do |push|
|
||||
push.%{attribute} = "..."
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module FTPPush
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "ftp"
|
||||
description <<-DESC
|
||||
Deploy to a remote FTP or SFTP server.
|
||||
DESC
|
||||
|
||||
config(:ftp, :push) do
|
||||
require File.expand_path("../config", __FILE__)
|
||||
init!
|
||||
Config
|
||||
end
|
||||
|
||||
push(:ftp) do
|
||||
require File.expand_path("../push", __FILE__)
|
||||
init!
|
||||
Push
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.init!
|
||||
return if defined?(@_init)
|
||||
I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
|
||||
I18n.reload!
|
||||
@_init = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,120 @@
|
|||
require "net/ftp"
|
||||
require "pathname"
|
||||
|
||||
require_relative "adapter"
|
||||
|
||||
module VagrantPlugins
|
||||
module FTPPush
|
||||
class Push < Vagrant.plugin("2", :push)
|
||||
IGNORED_FILES = %w(. ..).freeze
|
||||
DEFAULT_EXCLUDES = %w(.git .hg .svn .vagrant).freeze
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
@logger = Log4r::Logger.new("vagrant::pushes::ftp")
|
||||
end
|
||||
|
||||
def push
|
||||
# Grab files early so if there's an exception or issue, we don't have to
|
||||
# wait and close the (S)FTP connection as well
|
||||
files = Hash[*all_files.flat_map do |file|
|
||||
relative_path = relative_path_for(file, config.dir)
|
||||
destination = File.expand_path(File.join(config.destination, relative_path))
|
||||
file = File.expand_path(file, env.root_path)
|
||||
[file, destination]
|
||||
end]
|
||||
|
||||
ftp = "#{config.username}@#{config.host}:#{config.destination}"
|
||||
env.ui.info "Uploading #{env.root_path} to #{ftp}"
|
||||
|
||||
connect do |ftp|
|
||||
files.each do |local, remote|
|
||||
@logger.info "Uploading #{local} => #{remote}"
|
||||
ftp.upload(local, remote)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Helper method for creating the FTP or SFTP connection.
|
||||
# @yield [Adapter]
|
||||
def connect(&block)
|
||||
klass = config.secure ? SFTPAdapter : FTPAdapter
|
||||
ftp = klass.new(config.host, config.username, config.password,
|
||||
passive: config.passive)
|
||||
ftp.connect(&block)
|
||||
end
|
||||
|
||||
# The list of all files that should be pushed by this push. This method
|
||||
# only returns **files**, not folders or symlinks!
|
||||
# @return [Array<String>]
|
||||
def all_files
|
||||
files = glob("#{config.dir}/**/*") + includes_files
|
||||
filter_excludes!(files, config.excludes)
|
||||
files.reject! { |f| !File.file?(f) }
|
||||
files
|
||||
end
|
||||
|
||||
# The list of files to include in addition to those specified in `dir`.
|
||||
# @return [Array<String>]
|
||||
def includes_files
|
||||
includes = config.includes.flat_map do |i|
|
||||
path = absolute_path_for(i, config.dir)
|
||||
[path, "#{path}/**/*"]
|
||||
end
|
||||
|
||||
glob("{#{includes.join(",")}}")
|
||||
end
|
||||
|
||||
# Filter the excludes out of the given list. This method modifies the
|
||||
# given list in memory!
|
||||
#
|
||||
# @param [Array<String>] list
|
||||
# the filepaths
|
||||
# @param [Array<String>] excludes
|
||||
# the exclude patterns or files
|
||||
def filter_excludes!(list, excludes)
|
||||
excludes = Array(excludes)
|
||||
excludes = excludes + DEFAULT_EXCLUDES
|
||||
excludes = excludes.flat_map { |e| [e, "#{e}/*"] }
|
||||
|
||||
list.reject! do |file|
|
||||
basename = relative_path_for(file, config.dir)
|
||||
|
||||
# Handle the special case where the file is outside of the working
|
||||
# directory...
|
||||
if basename.start_with?("../")
|
||||
basename = file
|
||||
end
|
||||
|
||||
excludes.any? { |e| File.fnmatch?(e, basename, File::FNM_DOTMATCH) }
|
||||
end
|
||||
end
|
||||
|
||||
# Get the list of files that match the given pattern.
|
||||
# @return [Array<String>]
|
||||
def glob(pattern)
|
||||
Dir.glob(pattern, File::FNM_DOTMATCH).sort.reject do |file|
|
||||
IGNORED_FILES.include?(File.basename(file))
|
||||
end
|
||||
end
|
||||
|
||||
# The absolute path to the given `path` and `parent`, unless the given
|
||||
# path is absolute.
|
||||
# @return [String]
|
||||
def absolute_path_for(path, parent)
|
||||
path = Pathname.new(path)
|
||||
return path if path.absolute?
|
||||
File.expand_path(path, parent)
|
||||
end
|
||||
|
||||
# The relative path from the given `parent`. If files exist on another
|
||||
# device, this will probably blow up.
|
||||
# @return [String]
|
||||
def relative_path_for(path, parent)
|
||||
Pathname.new(path).relative_path_from(Pathname.new(parent)).to_s
|
||||
rescue ArgumentError
|
||||
return path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,74 @@
|
|||
module VagrantPlugins
|
||||
module HerokuPush
|
||||
class Config < Vagrant.plugin("2", :config)
|
||||
# The name of the Heroku application to push to.
|
||||
# @return [String]
|
||||
attr_accessor :app
|
||||
|
||||
# The base directory with file contents to upload. By default this
|
||||
# is the same directory as the Vagrantfile, but you can specify this
|
||||
# if you have a `src` folder or `bin` folder or some other folder
|
||||
# you want to upload. This directory must be a git repository.
|
||||
# @return [String]
|
||||
attr_accessor :dir
|
||||
|
||||
# The path to the git binary to shell out to. This usually is only set for
|
||||
# debugging/development. If not set, the git bin will be searched for
|
||||
# in the PATH.
|
||||
# @return [String]
|
||||
attr_accessor :git_bin
|
||||
|
||||
# The Git remote to push to (default: "heroku").
|
||||
# @return [String]
|
||||
attr_accessor :remote
|
||||
|
||||
def initialize
|
||||
@app = UNSET_VALUE
|
||||
@dir = UNSET_VALUE
|
||||
|
||||
@git_bin = UNSET_VALUE
|
||||
@remote = UNSET_VALUE
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@app = nil if @app == UNSET_VALUE
|
||||
@dir = "." if @dir == UNSET_VALUE
|
||||
|
||||
@git_bin = "git" if @git_bin == UNSET_VALUE
|
||||
@remote = "heroku" if @remote == UNSET_VALUE
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
|
||||
if missing?(@dir)
|
||||
errors << I18n.t("heroku_push.errors.missing_attribute",
|
||||
attribute: "dir",
|
||||
)
|
||||
end
|
||||
|
||||
if missing?(@git_bin)
|
||||
errors << I18n.t("heroku_push.errors.missing_attribute",
|
||||
attribute: "git_bin",
|
||||
)
|
||||
end
|
||||
|
||||
if missing?(@remote)
|
||||
errors << I18n.t("heroku_push.errors.missing_attribute",
|
||||
attribute: "remote",
|
||||
)
|
||||
end
|
||||
|
||||
{ "Heroku push" => errors }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Determine if the given string is "missing" (blank)
|
||||
# @return [true, false]
|
||||
def missing?(obj)
|
||||
obj.to_s.strip.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
module VagrantPlugins
|
||||
module HerokuPush
|
||||
module Errors
|
||||
class Error < Vagrant::Errors::VagrantError
|
||||
error_namespace("heroku_push.errors")
|
||||
end
|
||||
|
||||
class CommandFailed < Error
|
||||
error_key(:command_failed)
|
||||
end
|
||||
|
||||
class GitNotFound < Error
|
||||
error_key(:git_not_found)
|
||||
end
|
||||
|
||||
class NotAGitRepo < Error
|
||||
error_key(:not_a_git_repo)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
en:
|
||||
heroku_push:
|
||||
errors:
|
||||
command_failed: |-
|
||||
The following command exited with a non-zero exit status:
|
||||
|
||||
%{cmd}
|
||||
|
||||
stdout: %{stdout}
|
||||
stderr: %{stderr}
|
||||
git_not_found: |-
|
||||
The Git binary '%{bin}' could not be found. Please ensure you
|
||||
have downloaded and installed the latest version of Git:
|
||||
|
||||
http://git-scm.com/downloads
|
||||
missing_attribute: |-
|
||||
Missing required attribute '%{attribute}'. The Vagrant Heroku Push
|
||||
plugin requires you set this attribute. Please set this attribute in
|
||||
your Vagrantfile, for example:
|
||||
|
||||
config.push.define "heroku" do |push|
|
||||
push.%{attribute} = "..."
|
||||
end
|
||||
not_a_git_repo: |-
|
||||
The following path is not a valid Git repository:
|
||||
|
||||
%{path}
|
||||
|
||||
Please ensure you are working in the correct directory. In order to use
|
||||
the Vagrant Heroku Push plugin, you must have a git repository.
|
|
@ -0,0 +1,33 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module HerokuPush
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "heroku"
|
||||
description <<-DESC
|
||||
Deploy to a Heroku
|
||||
DESC
|
||||
|
||||
config(:heroku, :push) do
|
||||
require File.expand_path("../config", __FILE__)
|
||||
init!
|
||||
Config
|
||||
end
|
||||
|
||||
push(:heroku) do
|
||||
require File.expand_path("../push", __FILE__)
|
||||
init!
|
||||
Push
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.init!
|
||||
return if defined?(@_init)
|
||||
I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
|
||||
I18n.reload!
|
||||
@_init = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,136 @@
|
|||
require "vagrant/util/subprocess"
|
||||
require "vagrant/util/which"
|
||||
|
||||
require_relative "errors"
|
||||
|
||||
module VagrantPlugins
|
||||
module HerokuPush
|
||||
class Push < Vagrant.plugin("2", :push)
|
||||
def push
|
||||
# Expand any paths relative to the root
|
||||
dir = File.expand_path(config.dir, env.root_path)
|
||||
|
||||
# Verify git is installed
|
||||
verify_git_bin!(config.git_bin)
|
||||
|
||||
# Verify we are operating in a git repo
|
||||
verify_git_repo!(dir)
|
||||
|
||||
# Get the current branch
|
||||
branch = git_branch(dir)
|
||||
|
||||
# Get the name of the app
|
||||
app = config.app || interpret_app(dir)
|
||||
|
||||
# Check if we need to add the git remote
|
||||
if !has_git_remote?(config.remote, dir)
|
||||
add_heroku_git_remote(config.remote, app, dir)
|
||||
end
|
||||
|
||||
# Push to Heroku
|
||||
git_push_heroku(config.remote, branch, dir)
|
||||
end
|
||||
|
||||
# Verify that git is installed.
|
||||
# @raise [Errors::GitNotFound]
|
||||
def verify_git_bin!(path)
|
||||
if Vagrant::Util::Which.which(path).nil?
|
||||
raise Errors::GitNotFound, bin: path
|
||||
end
|
||||
end
|
||||
|
||||
# Verify that the given path is a git directory.
|
||||
# @raise [Errors::NotAGitRepo]
|
||||
# @param [String]
|
||||
def verify_git_repo!(path)
|
||||
if !File.directory?(git_dir(path))
|
||||
raise Errors::NotAGitRepo, path: path
|
||||
end
|
||||
end
|
||||
|
||||
# Interpret the name of the Heroku application from the given path.
|
||||
# @param [String] path
|
||||
# @return [String]
|
||||
def interpret_app(path)
|
||||
File.basename(path)
|
||||
end
|
||||
|
||||
# The git directory for the given path.
|
||||
# @param [String] path
|
||||
# @return [String]
|
||||
def git_dir(path)
|
||||
"#{path}/.git"
|
||||
end
|
||||
|
||||
# The name of the current git branch.
|
||||
# @param [String] path
|
||||
# @return [String]
|
||||
def git_branch(path)
|
||||
result = execute!("git",
|
||||
"--git-dir", git_dir(path),
|
||||
"--work-tree", path,
|
||||
"branch",
|
||||
)
|
||||
|
||||
# Returns something like "* master"
|
||||
result.stdout.sub("*", "").strip
|
||||
end
|
||||
|
||||
# Push to the Heroku remote.
|
||||
# @param [String] remote
|
||||
# @param [String] branch
|
||||
def git_push_heroku(remote, branch, path)
|
||||
execute!("git",
|
||||
"--git-dir", git_dir(path),
|
||||
"--work-tree", path,
|
||||
"push", remote, "#{branch}:master",
|
||||
)
|
||||
end
|
||||
|
||||
# Check if the git remote has the given remote.
|
||||
# @param [String] remote
|
||||
# @return [true, false]
|
||||
def has_git_remote?(remote, path)
|
||||
result = execute!("git",
|
||||
"--git-dir", git_dir(path),
|
||||
"--work-tree", path,
|
||||
"remote",
|
||||
)
|
||||
remotes = result.stdout.split(/\r?\n/).map(&:strip)
|
||||
remotes.include?(remote.to_s)
|
||||
end
|
||||
|
||||
# Add the Heroku to the current repository.
|
||||
# @param [String] remote
|
||||
# @param [String] app
|
||||
def add_heroku_git_remote(remote, app, path)
|
||||
execute!("git",
|
||||
"--git-dir", git_dir(path),
|
||||
"--work-tree", path,
|
||||
"remote", "add", remote, heroku_git_url(app),
|
||||
)
|
||||
end
|
||||
|
||||
# The URL for this project on Heroku.
|
||||
# @return [String]
|
||||
def heroku_git_url(app)
|
||||
"git@heroku.com:#{app}.git"
|
||||
end
|
||||
|
||||
# Execute the command, raising an exception if it fails.
|
||||
# @return [Vagrant::Util::Subprocess::Result]
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,48 @@
|
|||
module VagrantPlugins
|
||||
module LocalExecPush
|
||||
class Config < Vagrant.plugin("2", :config)
|
||||
# The path (relative to the machine root) to a local script that will be
|
||||
# executed.
|
||||
# @return [String]
|
||||
attr_accessor :script
|
||||
|
||||
# The command (as a string) to execute.
|
||||
# @return [String]
|
||||
attr_accessor :inline
|
||||
|
||||
def initialize
|
||||
@script = UNSET_VALUE
|
||||
@inline = UNSET_VALUE
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@script = nil if @script == UNSET_VALUE
|
||||
@inline = nil if @inline == UNSET_VALUE
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
|
||||
if missing?(@script) && missing?(@inline)
|
||||
errors << I18n.t("local_exec_push.errors.missing_attribute",
|
||||
attribute: "script",
|
||||
)
|
||||
end
|
||||
|
||||
if !missing?(@script) && !missing?(@inline)
|
||||
errors << I18n.t("local_exec_push.errors.cannot_specify_script_and_inline")
|
||||
end
|
||||
|
||||
{ "Local Exec push" => errors }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Determine if the given string is "missing" (blank)
|
||||
# @return [true, false]
|
||||
def missing?(obj)
|
||||
obj.to_s.strip.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module VagrantPlugins
|
||||
module LocalExecPush
|
||||
module Errors
|
||||
class Error < Vagrant::Errors::VagrantError
|
||||
error_namespace("local_exec_push.errors")
|
||||
end
|
||||
|
||||
class CommandFailed < Error
|
||||
error_key(:command_failed)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
en:
|
||||
local_exec_push:
|
||||
errors:
|
||||
cannot_specify_script_and_inline: |-
|
||||
You have specified both the 'script' and 'inline' attributes for the
|
||||
Vagrant Local Exec Push plugin. You may only specify one of these
|
||||
attributes.
|
||||
command_failed: |-
|
||||
The following command exited with a non-zero exit status:
|
||||
|
||||
%{cmd}
|
||||
|
||||
stdout: %{stdout}
|
||||
stderr: %{stderr}
|
||||
missing_attribute: |-
|
||||
Missing required attribute '%{attribute}'. The Vagrant Local Exec Push
|
||||
plugin requires you set this attribute. Please set this attribute in
|
||||
your Vagrantfile, for example:
|
||||
|
||||
config.push.define "local-exec" do |push|
|
||||
push.%{attribute} = "..."
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module LocalExecPush
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "local-exec"
|
||||
description <<-DESC
|
||||
Run a local command or script to push
|
||||
DESC
|
||||
|
||||
config(:"local-exec", :push) do
|
||||
require File.expand_path("../config", __FILE__)
|
||||
init!
|
||||
Config
|
||||
end
|
||||
|
||||
push(:"local-exec") do
|
||||
require File.expand_path("../push", __FILE__)
|
||||
init!
|
||||
Push
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.init!
|
||||
return if defined?(@_init)
|
||||
I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
|
||||
I18n.reload!
|
||||
@_init = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,45 @@
|
|||
require "fileutils"
|
||||
require "tempfile"
|
||||
require "vagrant/util/safe_exec"
|
||||
|
||||
require_relative "errors"
|
||||
|
||||
module VagrantPlugins
|
||||
module LocalExecPush
|
||||
class Push < Vagrant.plugin("2", :push)
|
||||
def push
|
||||
if config.inline
|
||||
execute_inline!(config.inline)
|
||||
else
|
||||
execute_script!(config.script)
|
||||
end
|
||||
end
|
||||
|
||||
# Execute the inline script by writing it to a tempfile and executing.
|
||||
def execute_inline!(inline)
|
||||
script = Tempfile.new(["vagrant-local-exec-script", ".sh"])
|
||||
script.write(inline)
|
||||
script.rewind
|
||||
|
||||
execute_script!(script.path)
|
||||
ensure
|
||||
if script
|
||||
script.close
|
||||
script.unlink
|
||||
end
|
||||
end
|
||||
|
||||
# Execute the script, expanding the path relative to the current env root.
|
||||
def execute_script!(path)
|
||||
path = File.expand_path(path, env.root_path)
|
||||
FileUtils.chmod("+x", path)
|
||||
execute!(path)
|
||||
end
|
||||
|
||||
# Execute the script, raising an exception if it fails.
|
||||
def execute!(*cmd)
|
||||
Vagrant::Util::SafeExec.exec(cmd[0], *cmd[1..-1])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
module VagrantPlugins
|
||||
module NoopDeploy
|
||||
class Config < Vagrant.plugin("2", :config)
|
||||
def initialize
|
||||
end
|
||||
|
||||
def finalize!
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
{ "Noop push" => errors }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
require "vagrant"
|
||||
|
||||
module VagrantPlugins
|
||||
module NoopDeploy
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "noop"
|
||||
description <<-DESC
|
||||
Literally do nothing
|
||||
DESC
|
||||
|
||||
config(:noop, :push) do
|
||||
require File.expand_path("../config", __FILE__)
|
||||
Config
|
||||
end
|
||||
|
||||
push(:noop) do
|
||||
require File.expand_path("../push", __FILE__)
|
||||
Push
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
module VagrantPlugins
|
||||
module NoopDeploy
|
||||
class Push < Vagrant.plugin("2", :push)
|
||||
def push
|
||||
puts "pushed"
|
||||
end
|
||||
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 -%>
|
||||
|
|
|
@ -244,7 +244,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: |-
|
||||
|
@ -370,7 +370,7 @@ en:
|
|||
provider. Double-check your requested provider to verify you didn't
|
||||
simply misspell it.
|
||||
|
||||
If you're adding a box from Vagrant Cloud, make sure the box is
|
||||
If you're adding a box from HashiCorp's Atlas, make sure the box is
|
||||
released.
|
||||
|
||||
Name: %{name}
|
||||
|
@ -389,7 +389,7 @@ en:
|
|||
box_add_short_not_found: |-
|
||||
The box '%{name}' could not be found or
|
||||
could not be accessed in the remote catalog. If this is a private
|
||||
box on Vagrant Cloud, please verify you're logged in via
|
||||
box on HashiCorp's Atlas, please verify you're logged in via
|
||||
`vagrant login`. Also, please double-check the name. The expanded
|
||||
URL and error message are shown below:
|
||||
|
||||
|
@ -551,16 +551,14 @@ en:
|
|||
|
||||
%{versions}
|
||||
box_server_not_set: |-
|
||||
A URL to a Vagrant Cloud server is not set, so boxes cannot
|
||||
be added with a shorthand ("mitchellh/precise64") format.
|
||||
You may also be seeing this error if you meant to type in
|
||||
a path to a box file which doesn't exist locally on your
|
||||
system.
|
||||
A URL to an Atlas server is not set, so boxes cannot be added with a
|
||||
shorthand ("mitchellh/precise64") format. You may also be seeing this
|
||||
error if you meant to type in a path to a box file which doesn't exist
|
||||
locally on your system.
|
||||
|
||||
To set a URL to a Vagrant Cloud server, set the
|
||||
`VAGRANT_SERVER_URL` environmental variable. Or, if you
|
||||
meant to use a file path, make sure the path to the file
|
||||
is valid.
|
||||
To set a URL to an Atlas server, set the `VAGRANT_SERVER_URL`
|
||||
environmental variable. Or, if you meant to use a file path, make sure
|
||||
the path to the file is valid.
|
||||
box_update_multi_provider: |-
|
||||
You requested to update the box '%{name}'. This box has
|
||||
multiple providers. You must explicitly select a single
|
||||
|
@ -947,6 +945,29 @@ en:
|
|||
You can however, install a plugin with the same name to replace
|
||||
these plugins. User-installed plugins take priority over
|
||||
system-installed plugins.
|
||||
pushes_not_defined: |-
|
||||
The Vagrantfile does not define any 'push' strategies. In order to use
|
||||
`vagrant push`, you must define at least one push strategy:
|
||||
|
||||
config.push.define "ftp" do |push|
|
||||
# ... push-specific options
|
||||
end
|
||||
push_strategy_not_defined: |-
|
||||
The push strategy '%{name}' is not defined in the Vagrantfile. Defined
|
||||
strategy names are:
|
||||
|
||||
%{pushes}
|
||||
push_strategy_not_loaded: |-
|
||||
There are no push strategies named '%{name}'. Please make sure you
|
||||
spelled it correctly. If you are using an external push strategy, you
|
||||
may need to install a plugin. Loaded push strategies are:
|
||||
|
||||
%{pushes}
|
||||
push_strategy_not_provided: |-
|
||||
The Vagrantfile defines more than one 'push' strategy. Please specify a
|
||||
strategy. Defined strategy names are:
|
||||
|
||||
%{pushes}
|
||||
package_include_symlink: |-
|
||||
A file or directory you're attempting to include with your packaged
|
||||
box has symlinks in it. Vagrant cannot include symlinks in the
|
||||
|
@ -1789,6 +1810,8 @@ en:
|
|||
running_apply: "Running chef-apply..."
|
||||
running_solo: "Running chef-solo..."
|
||||
running_solo_again: "Running chef-solo again (failed to converge)..."
|
||||
running_zero: "Running chef-zero..."
|
||||
running_zero_again: "Running chef-zero again (failed to converge)..."
|
||||
missing_shared_folders: |-
|
||||
Shared folders that Chef requires are missing on the virtual machine.
|
||||
This is usually due to configuration changing after already booting the
|
||||
|
@ -1889,7 +1912,13 @@ 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: |-
|
||||
You must accept keys when running highstate with master!
|
||||
|
||||
pushes:
|
||||
file:
|
||||
no_destination: "File destination must be specified."
|
||||
|
|
|
@ -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 %>
|
||||
|
|
|
@ -4,6 +4,7 @@ require "rubygems"
|
|||
# Gems
|
||||
require "checkpoint"
|
||||
require "rspec/autorun"
|
||||
require "webmock/rspec"
|
||||
|
||||
# Require Vagrant itself so we can reference the proper
|
||||
# classes to test.
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
require File.expand_path("../../../../base", __FILE__)
|
||||
|
||||
require Vagrant.source_root.join("plugins/commands/login/command")
|
||||
|
||||
describe VagrantPlugins::LoginCommand::Client do
|
||||
include_context "unit"
|
||||
|
||||
let(:env) { isolated_environment.create_vagrant_env }
|
||||
|
||||
subject { described_class.new(env) }
|
||||
|
||||
before do
|
||||
stub_env("ATLAS_TOKEN" => nil)
|
||||
subject.clear_token
|
||||
end
|
||||
|
||||
describe "#logged_in?" do
|
||||
let(:url) { "#{Vagrant.server_url}/api/v1/authenticate?access_token=#{token}" }
|
||||
let(:headers) { { "Content-Type" => "application/json" } }
|
||||
|
||||
before { allow(subject).to receive(:token).and_return(token) }
|
||||
|
||||
context "when there is no token" do
|
||||
let(:token) { nil }
|
||||
|
||||
it "returns false" do
|
||||
expect(subject.logged_in?).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a token" do
|
||||
let(:token) { "ABCD1234" }
|
||||
|
||||
it "returns true if the endpoint returns a 200" do
|
||||
stub_request(:get, url)
|
||||
.with(headers: headers)
|
||||
.to_return(body: JSON.pretty_generate("token" => token))
|
||||
expect(subject.logged_in?).to be(true)
|
||||
end
|
||||
|
||||
it "returns false if the endpoint returns a non-200" do
|
||||
stub_request(:get, url)
|
||||
.with(headers: headers)
|
||||
.to_return(body: JSON.pretty_generate("bad" => true), status: 401)
|
||||
expect(subject.logged_in?).to be(false)
|
||||
end
|
||||
|
||||
it "raises an exception if the server cannot be found" do
|
||||
stub_request(:get, url)
|
||||
.to_raise(SocketError)
|
||||
expect { subject.logged_in? }
|
||||
.to raise_error(VagrantPlugins::LoginCommand::Errors::ServerUnreachable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#login" do
|
||||
it "returns the access token after successful login" do
|
||||
request = {
|
||||
"user" => {
|
||||
"login" => "foo",
|
||||
"password" => "bar",
|
||||
},
|
||||
}
|
||||
|
||||
response = {
|
||||
"token" => "baz",
|
||||
}
|
||||
|
||||
headers = { "Content-Type" => "application/json" }
|
||||
|
||||
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
||||
with(body: JSON.dump(request), headers: headers).
|
||||
to_return(status: 200, body: JSON.dump(response))
|
||||
|
||||
expect(subject.login("foo", "bar")).to eq("baz")
|
||||
end
|
||||
|
||||
it "returns nil on bad login" do
|
||||
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
||||
to_return(status: 401, body: "")
|
||||
|
||||
expect(subject.login("foo", "bar")).to be(false)
|
||||
end
|
||||
|
||||
it "raises an exception if it can't reach the sever" do
|
||||
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
||||
to_raise(SocketError)
|
||||
|
||||
expect { subject.login("foo", "bar") }.
|
||||
to raise_error(VagrantPlugins::LoginCommand::Errors::ServerUnreachable)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#token" do
|
||||
it "reads ATLAS_TOKEN" do
|
||||
stub_env("ATLAS_TOKEN" => "ABCD1234")
|
||||
expect(subject.token).to eq("ABCD1234")
|
||||
end
|
||||
|
||||
it "reads the stored file" do
|
||||
subject.store_token("EFGH5678")
|
||||
expect(subject.token).to eq("EFGH5678")
|
||||
end
|
||||
|
||||
it "prefers the environment variable" do
|
||||
stub_env("ATLAS_TOKEN" => "ABCD1234")
|
||||
subject.store_token("EFGH5678")
|
||||
expect(subject.token).to eq("ABCD1234")
|
||||
end
|
||||
|
||||
it "returns nil if there's no token set" do
|
||||
expect(subject.token).to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#store_token, #clear_token" do
|
||||
it "stores the token and can re-access it" do
|
||||
subject.store_token("foo")
|
||||
expect(subject.token).to eq("foo")
|
||||
expect(described_class.new(env).token).to eq("foo")
|
||||
end
|
||||
|
||||
it "deletes the token" do
|
||||
subject.store_token("foo")
|
||||
subject.clear_token
|
||||
expect(subject.token).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,88 @@
|
|||
require File.expand_path("../../../../../base", __FILE__)
|
||||
|
||||
require Vagrant.source_root.join("plugins/commands/login/middleware/add_authentication")
|
||||
|
||||
describe VagrantPlugins::LoginCommand::AddAuthentication do
|
||||
include_context "unit"
|
||||
|
||||
let(:app) { lambda { |env| } }
|
||||
let(:env) { {
|
||||
env: iso_env,
|
||||
} }
|
||||
|
||||
let(:iso_env) { isolated_environment.create_vagrant_env }
|
||||
let(:server_url) { "http://foo.com" }
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
before do
|
||||
allow(Vagrant).to receive(:server_url).and_return(server_url)
|
||||
stub_env("ATLAS_TOKEN" => nil)
|
||||
end
|
||||
|
||||
describe "#call" do
|
||||
it "does nothing if we have no server set" do
|
||||
allow(Vagrant).to receive(:server_url).and_return(nil)
|
||||
VagrantPlugins::LoginCommand::Client.new(iso_env).store_token("foo")
|
||||
|
||||
original = ["foo", "#{server_url}/bar"]
|
||||
env[:box_urls] = original.dup
|
||||
|
||||
subject.call(env)
|
||||
|
||||
expect(env[:box_urls]).to eq(original)
|
||||
end
|
||||
|
||||
it "does nothing if we aren't logged in" do
|
||||
original = ["foo", "#{server_url}/bar"]
|
||||
env[:box_urls] = original.dup
|
||||
|
||||
subject.call(env)
|
||||
|
||||
expect(env[:box_urls]).to eq(original)
|
||||
end
|
||||
|
||||
it "appends the access token to the URL of server URLs" do
|
||||
token = "foobarbaz"
|
||||
VagrantPlugins::LoginCommand::Client.new(iso_env).store_token(token)
|
||||
|
||||
original = [
|
||||
"http://google.com/box.box",
|
||||
"#{server_url}/foo.box",
|
||||
"#{server_url}/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
|
||||
|
||||
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
|
|
@ -0,0 +1,132 @@
|
|||
require File.expand_path("../../../../base", __FILE__)
|
||||
|
||||
require Vagrant.source_root.join("plugins/commands/push/command")
|
||||
|
||||
describe VagrantPlugins::CommandPush::Command do
|
||||
include_context "unit"
|
||||
include_context "command plugin helpers"
|
||||
|
||||
let(:iso_env) { isolated_environment }
|
||||
let(:env) do
|
||||
iso_env.vagrantfile(<<-VF)
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "nope"
|
||||
end
|
||||
VF
|
||||
iso_env.create_vagrant_env
|
||||
end
|
||||
|
||||
let(:argv) { [] }
|
||||
let(:pushes) { {} }
|
||||
|
||||
subject { described_class.new(argv, env) }
|
||||
|
||||
before do
|
||||
Vagrant.plugin("2").manager.stub(pushes: pushes)
|
||||
end
|
||||
|
||||
describe "#execute" do
|
||||
before do
|
||||
allow(subject).to receive(:validate_pushes!)
|
||||
.and_return(:noop)
|
||||
allow(env).to receive(:pushes)
|
||||
allow(env).to receive(:push)
|
||||
end
|
||||
|
||||
it "validates the pushes" do
|
||||
expect(subject).to receive(:validate_pushes!).once
|
||||
subject.execute
|
||||
end
|
||||
|
||||
it "validates the configuration" do
|
||||
iso_env.vagrantfile("")
|
||||
|
||||
subject = described_class.new(argv, iso_env.create_vagrant_env)
|
||||
allow(subject).to receive(:validate_pushes!)
|
||||
.and_return(:noop)
|
||||
|
||||
expect { subject.execute }.to raise_error(
|
||||
Vagrant::Errors::ConfigInvalid)
|
||||
end
|
||||
|
||||
it "delegates to Environment#push" do
|
||||
expect(env).to receive(:push).once
|
||||
subject.execute
|
||||
end
|
||||
end
|
||||
|
||||
describe "#validate_pushes!" do
|
||||
context "when there are no pushes defined" do
|
||||
let(:pushes) { [] }
|
||||
|
||||
context "when a strategy is given" do
|
||||
it "raises an exception" do
|
||||
expect { subject.validate_pushes!(pushes, :noop) }
|
||||
.to raise_error(Vagrant::Errors::PushesNotDefined)
|
||||
end
|
||||
end
|
||||
|
||||
context "when no strategy is given" do
|
||||
it "raises an exception" do
|
||||
expect { subject.validate_pushes!(pushes) }
|
||||
.to raise_error(Vagrant::Errors::PushesNotDefined)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is one push defined" do
|
||||
let(:noop) { double("noop") }
|
||||
let(:pushes) { [:noop] }
|
||||
|
||||
context "when a strategy is given" do
|
||||
context "when that strategy is not defined" do
|
||||
it "raises an exception" do
|
||||
expect { subject.validate_pushes!(pushes, :bacon) }
|
||||
.to raise_error(Vagrant::Errors::PushStrategyNotDefined)
|
||||
end
|
||||
end
|
||||
|
||||
context "when that strategy is defined" do
|
||||
it "returns that push" do
|
||||
expect(subject.validate_pushes!(pushes, :noop)).to eq(:noop)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when no strategy is given" do
|
||||
it "returns the strategy" do
|
||||
expect(subject.validate_pushes!(pushes)).to eq(:noop)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are multiple pushes defined" do
|
||||
let(:noop) { double("noop") }
|
||||
let(:ftp) { double("ftp") }
|
||||
let(:pushes) { [:noop, :ftp] }
|
||||
|
||||
context "when a strategy is given" do
|
||||
context "when that strategy is not defined" do
|
||||
it "raises an exception" do
|
||||
expect { subject.validate_pushes!(pushes, :bacon) }
|
||||
.to raise_error(Vagrant::Errors::PushStrategyNotDefined)
|
||||
end
|
||||
end
|
||||
|
||||
context "when that strategy is defined" do
|
||||
it "returns the strategy" do
|
||||
expect(subject.validate_pushes!(pushes, :noop)).to eq(:noop)
|
||||
expect(subject.validate_pushes!(pushes, :ftp)).to eq(:ftp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when no strategy is given" do
|
||||
it "raises an exception" do
|
||||
expect { subject.validate_pushes!(pushes) }
|
||||
.to raise_error(Vagrant::Errors::PushStrategyNotProvided)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -75,15 +75,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
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
require File.expand_path("../../../../base", __FILE__)
|
||||
|
||||
require Vagrant.source_root.join("plugins/kernel_v2/config/push")
|
||||
|
||||
describe VagrantPlugins::Kernel_V2::PushConfig do
|
||||
include_context "unit"
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
describe "#define" do
|
||||
let(:pushes) { subject.instance_variable_get(:@__defined_pushes) }
|
||||
|
||||
it "pushes the strategy and block onto the defined pushes array" do
|
||||
subject.define("foo") { "bar" }
|
||||
subject.define("foo") { "zip" }
|
||||
subject.define("foo") { "zap" }
|
||||
|
||||
expect(pushes.size).to eq(1)
|
||||
expect(pushes[:foo].size).to eq(3)
|
||||
expect(pushes[:foo][0]).to be_a(Array)
|
||||
expect(pushes[:foo][0][0]).to eq(:foo)
|
||||
expect(pushes[:foo][0][1]).to be_a(Proc)
|
||||
end
|
||||
|
||||
context "when no strategy is given" do
|
||||
it "defaults to the name" do
|
||||
subject.define("foo") { "bar" }
|
||||
|
||||
expect(pushes.size).to eq(1)
|
||||
expect(pushes[:foo].size).to eq(1)
|
||||
expect(pushes[:foo][0]).to be_a(Array)
|
||||
expect(pushes[:foo][0][0]).to eq(:foo)
|
||||
expect(pushes[:foo][0][1]).to be_a(Proc)
|
||||
end
|
||||
end
|
||||
|
||||
context "when a strategy is given" do
|
||||
it "uses the strategy" do
|
||||
subject.define("foo", strategy: "bacon") { "bar" }
|
||||
|
||||
expect(pushes.size).to eq(1)
|
||||
expect(pushes[:foo].size).to eq(1)
|
||||
expect(pushes[:foo][0]).to be_a(Array)
|
||||
expect(pushes[:foo][0][0]).to eq(:bacon)
|
||||
expect(pushes[:foo][0][1]).to be_a(Proc)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#merge" do
|
||||
it "appends defined pushes" do
|
||||
a = described_class.new.tap do |i|
|
||||
i.define("foo") { "bar" }
|
||||
i.define("bar") { "bar" }
|
||||
end
|
||||
b = described_class.new.tap do |i|
|
||||
i.define("foo") { "zip" }
|
||||
end
|
||||
|
||||
result = a.merge(b)
|
||||
pushes = result.instance_variable_get(:@__defined_pushes)
|
||||
|
||||
expect(pushes[:foo]).to be_a(Array)
|
||||
expect(pushes[:foo].size).to eq(2)
|
||||
|
||||
expect(pushes[:bar]).to be_a(Array)
|
||||
expect(pushes[:bar].size).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#__compiled_pushes" do
|
||||
it "raises an exception if not finalized" do
|
||||
subject.instance_variable_set(:@__finalized, false)
|
||||
expect { subject.__compiled_pushes }.to raise_error
|
||||
end
|
||||
|
||||
it "returns a copy of the compiled pushes" do
|
||||
pushes = { foo: "bar" }
|
||||
subject.instance_variable_set(:@__finalized, true)
|
||||
subject.instance_variable_set(:@__compiled_pushes, pushes)
|
||||
|
||||
expect(subject.__compiled_pushes).to_not be(pushes)
|
||||
expect(subject.__compiled_pushes).to eq(pushes)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#finalize!" do
|
||||
let(:pushes) { a.merge(b).tap { |r| r.finalize! }.__compiled_pushes }
|
||||
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|
|
||||
plugin.name "foo"
|
||||
|
||||
plugin.push(:foo) do
|
||||
Class.new(Vagrant.plugin("2", :push))
|
||||
end
|
||||
|
||||
plugin.config(:foo, :push) do
|
||||
Class.new(Vagrant.plugin("2", :config)) do
|
||||
attr_accessor :bar
|
||||
attr_accessor :zip
|
||||
|
||||
def initialize
|
||||
@bar = self.class.const_get(:UNSET_VALUE)
|
||||
@zip = self.class.const_get(:UNSET_VALUE)
|
||||
end
|
||||
end
|
||||
end
|
||||
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
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "bar")
|
||||
end
|
||||
end
|
||||
|
||||
let(:b) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "zip")
|
||||
end
|
||||
end
|
||||
|
||||
it "chooses the last config" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a block" do
|
||||
let(:a) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "bar") do |p|
|
||||
p.bar = "a"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:b) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "zip") do |p|
|
||||
p.zip = "b"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "chooses the last config" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a block, then no block" do
|
||||
let(:a) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "bar") do |p|
|
||||
p.bar, p.zip = "a", "a"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:b) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "zip")
|
||||
end
|
||||
end
|
||||
|
||||
it "chooses the last config" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
|
||||
context "with no block, then a block" do
|
||||
let(:a) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "bar")
|
||||
end
|
||||
end
|
||||
|
||||
let(:b) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "zip") do |p|
|
||||
p.bar, p.zip = "b", "b"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "chooses the last config" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with the same name twice" do
|
||||
context "with no block" do
|
||||
let(:a) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo")
|
||||
end
|
||||
end
|
||||
|
||||
let(:b) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo")
|
||||
end
|
||||
end
|
||||
|
||||
it "merges the configs" do
|
||||
expect(key).to eq(:foo)
|
||||
expect(config.bar).to be(unset)
|
||||
expect(config.zip).to be(unset)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a block" do
|
||||
let(:a) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo") do |p|
|
||||
p.bar = "a"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:b) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo") do |p|
|
||||
p.zip = "b"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "merges the configs" do
|
||||
expect(key).to eq(:foo)
|
||||
expect(config.bar).to eq("a")
|
||||
expect(config.zip).to eq("b")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a block, then no block" do
|
||||
let(:a) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo") do |p|
|
||||
p.bar = "a"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:b) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo")
|
||||
end
|
||||
end
|
||||
|
||||
it "merges the configs" do
|
||||
expect(key).to eq(:foo)
|
||||
expect(config.bar).to eq("a")
|
||||
expect(config.zip).to be(unset)
|
||||
end
|
||||
end
|
||||
|
||||
context "with no block, then a block" do
|
||||
let(:a) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "bar")
|
||||
end
|
||||
end
|
||||
|
||||
let(:b) do
|
||||
described_class.new.tap do |i|
|
||||
i.define("foo", strategy: "zip") do |p|
|
||||
p.zip = "b"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "merges the configs" do
|
||||
expect(key).to eq(:zip)
|
||||
expect(config).to be_kind_of(dummy_klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "sets @__finalized to true" do
|
||||
subject.finalize!
|
||||
expect(subject.instance_variable_get(:@__finalized)).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -62,13 +62,16 @@ VF
|
|||
# Class methods for code reuse across examples
|
||||
#
|
||||
|
||||
def self.it_should_set_arguments_and_environment_variables(expected_args_count = 5, expected_vars_count = 3, expected_host_key_checking = false)
|
||||
def self.it_should_set_arguments_and_environment_variables(
|
||||
expected_args_count = 6, expected_vars_count = 4, expected_host_key_checking = false, expected_transport_mode = "ssh")
|
||||
|
||||
it "sets implicit arguments in a specific order" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
|
||||
expect(args[0]).to eq("ansible-playbook")
|
||||
expect(args[1]).to eq("--private-key=#{machine.ssh_info[:private_key_path][0]}")
|
||||
expect(args[2]).to eq("--user=#{machine.ssh_info[:username]}")
|
||||
expect(args[3]).to eq("--connection=ssh")
|
||||
|
||||
inventory_count = args.count { |x| x =~ /^--inventory-file=.+$/ }
|
||||
expect(inventory_count).to be > 0
|
||||
|
@ -79,18 +82,18 @@ VF
|
|||
|
||||
it "sets --limit argument" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
raw_limits = []
|
||||
all_limits = args.select { |x| x =~ /^(--limit=|-l)/ }
|
||||
if config.raw_arguments
|
||||
raw_limits = config.raw_arguments.select { |x| x =~ /^(--limit=|-l)/ }
|
||||
end
|
||||
all_limits = args.select { |x| x =~ /^(--limit=|-l)/ }
|
||||
expect(all_limits.length - raw_limits.length).to eq(1)
|
||||
|
||||
if config.limit
|
||||
limit = config.limit.kind_of?(Array) ? config.limit.join(',') : config.limit
|
||||
expect(all_limits.last).to eq("--limit=#{limit}")
|
||||
expect(all_limits.length - raw_limits.length).to eq(1)
|
||||
expect(all_limits.last).to eq(raw_limits.last)
|
||||
else
|
||||
expect(all_limits.first).to eq("--limit=#{machine.name}")
|
||||
if config.limit
|
||||
limit = config.limit.kind_of?(Array) ? config.limit.join(',') : config.limit
|
||||
expect(all_limits.last).to eq("--limit=#{limit}")
|
||||
else
|
||||
expect(all_limits.first).to eq("--limit=#{machine.name}")
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -98,6 +101,12 @@ VF
|
|||
it "exports environment variables" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
cmd_opts = args.last
|
||||
|
||||
if expected_host_key_checking
|
||||
expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to be_nil unless config.raw_arguments
|
||||
else
|
||||
expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to include("-o UserKnownHostsFile=/dev/null")
|
||||
end
|
||||
expect(cmd_opts[:env]['ANSIBLE_FORCE_COLOR']).to eql("true")
|
||||
expect(cmd_opts[:env]['ANSIBLE_HOST_KEY_CHECKING']).to eql(expected_host_key_checking.to_s)
|
||||
expect(cmd_opts[:env]['PYTHONUNBUFFERED']).to eql(1)
|
||||
|
@ -111,6 +120,15 @@ VF
|
|||
expect(args.last[:env].length).to eq(expected_vars_count)
|
||||
}
|
||||
end
|
||||
|
||||
it "enables '#{expected_transport_mode}' transport mode" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
index = args.rindex("--connection=#{expected_transport_mode}")
|
||||
expect(index).to be > 0
|
||||
expect(find_last_argument_after(index, args, /--connection=\w+/)).to be_false
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.it_should_set_optional_arguments(arg_map)
|
||||
|
@ -128,35 +146,7 @@ VF
|
|||
end
|
||||
end
|
||||
|
||||
def self.it_should_use_smart_transport_mode
|
||||
it "does not export ANSIBLE_SSH_ARGS" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
cmd_opts = args.last
|
||||
expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to be_nil
|
||||
}
|
||||
end
|
||||
|
||||
it "does not force any transport mode" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
total = args.count { |x| x =~ /^--connection=\w+$/ }
|
||||
expect(total).to eql(0)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.it_should_use_transport_mode(transport_mode)
|
||||
it "enables '#{transport_mode}' transport mode" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
index = args.rindex("--connection=#{transport_mode}")
|
||||
expect(index).to be > 0
|
||||
expect(find_last_argument_after(index, args, /--connection=\w+/)).to be_false
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.it_should_force_ssh_transport_mode
|
||||
it_should_use_transport_mode('ssh')
|
||||
|
||||
def self.it_should_explicitly_enable_ansible_ssh_control_persist_defaults
|
||||
it "configures ControlPersist (like Ansible defaults) via ANSIBLE_SSH_ARGS" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
cmd_opts = args.last
|
||||
|
@ -212,7 +202,6 @@ VF
|
|||
|
||||
describe "with default options" do
|
||||
it_should_set_arguments_and_environment_variables
|
||||
it_should_use_smart_transport_mode
|
||||
it_should_create_and_use_generated_inventory
|
||||
|
||||
it "does not add any group section to the generated inventory" do
|
||||
|
@ -281,8 +270,7 @@ VF
|
|||
config.host_key_checking = true
|
||||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 5, 3, true
|
||||
it_should_use_smart_transport_mode
|
||||
it_should_set_arguments_and_environment_variables 6, 3, true
|
||||
end
|
||||
|
||||
describe "with boolean (flag) options disabled" do
|
||||
|
@ -294,7 +282,7 @@ VF
|
|||
config.sudo_user = 'root'
|
||||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 6
|
||||
it_should_set_arguments_and_environment_variables 7
|
||||
it_should_set_optional_arguments({ "sudo_user" => "--sudo-user=root" })
|
||||
|
||||
it "it does not set boolean flag when corresponding option is set to false" do
|
||||
|
@ -310,6 +298,7 @@ VF
|
|||
before do
|
||||
config.sudo = false
|
||||
config.skip_tags = %w(foo bar)
|
||||
config.limit = "all"
|
||||
config.raw_arguments = ["--connection=paramiko",
|
||||
"--skip-tags=ignored",
|
||||
"--module-path=/other/modules",
|
||||
|
@ -318,12 +307,11 @@ VF
|
|||
"--limit=foo",
|
||||
"--limit=bar",
|
||||
"--inventory-file=/forget/it/my/friend",
|
||||
"--user=lion",
|
||||
"--new-arg=yeah"]
|
||||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 15
|
||||
it_should_create_and_use_generated_inventory
|
||||
it_should_use_transport_mode('paramiko')
|
||||
it_should_set_arguments_and_environment_variables 17, 4, false, "paramiko"
|
||||
|
||||
it "sets all raw arguments" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
|
@ -333,9 +321,12 @@ VF
|
|||
}
|
||||
end
|
||||
|
||||
it "sets raw arguments before arguments related to supported options" do
|
||||
it "sets raw arguments after arguments related to supported options" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
expect(args.index("--skip-tags=foo,bar")).to be > args.index("--skip-tags=ignored")
|
||||
expect(args.index("--user=lion")).to be > args.index("--user=testuser")
|
||||
expect(args.index("--inventory-file=/forget/it/my/friend")).to be > args.index("--inventory-file=#{generated_inventory_dir}")
|
||||
expect(args.index("--limit=bar")).to be > args.index("--limit=all")
|
||||
expect(args.index("--skip-tags=ignored")).to be > args.index("--skip-tags=foo,bar")
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -361,7 +352,6 @@ VF
|
|||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables
|
||||
it_should_use_smart_transport_mode
|
||||
|
||||
it "does not generate the inventory and uses given inventory path instead" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
|
@ -377,7 +367,7 @@ VF
|
|||
config.ask_vault_pass = true
|
||||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 6
|
||||
it_should_set_arguments_and_environment_variables 7
|
||||
|
||||
it "should ask the vault password" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
|
@ -391,7 +381,7 @@ VF
|
|||
config.vault_password_file = existing_file
|
||||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 6
|
||||
it_should_set_arguments_and_environment_variables 7
|
||||
|
||||
it "uses the given vault password file" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
|
@ -406,7 +396,7 @@ VF
|
|||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 6, 4
|
||||
it_should_force_ssh_transport_mode
|
||||
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
|
||||
|
||||
it "passes custom SSH options via ANSIBLE_SSH_ARGS with the highest priority" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
|
@ -440,7 +430,7 @@ VF
|
|||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 6, 4
|
||||
it_should_force_ssh_transport_mode
|
||||
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
|
||||
|
||||
it "passes additional Identity Files via ANSIBLE_SSH_ARGS" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
|
@ -457,7 +447,7 @@ VF
|
|||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 6, 4
|
||||
it_should_force_ssh_transport_mode
|
||||
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
|
||||
|
||||
it "enables SSH-Forwarding via ANSIBLE_SSH_ARGS" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
|
@ -475,7 +465,7 @@ VF
|
|||
|
||||
it "shows the ansible-playbook command" do
|
||||
expect(machine.env.ui).to receive(:detail).with { |full_command|
|
||||
expect(full_command).to eq("ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false PYTHONUNBUFFERED=1 ansible-playbook --private-key=/path/to/my/key --user=testuser --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml")
|
||||
expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -485,12 +475,12 @@ VF
|
|||
config.verbose = 'v'
|
||||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 6
|
||||
it_should_set_arguments_and_environment_variables 7
|
||||
it_should_set_optional_arguments({ "verbose" => "-v" })
|
||||
|
||||
it "shows the ansible-playbook command" do
|
||||
expect(machine.env.ui).to receive(:detail).with { |full_command|
|
||||
expect(full_command).to eq("ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false PYTHONUNBUFFERED=1 ansible-playbook --private-key=/path/to/my/key --user=testuser --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml")
|
||||
expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -524,7 +514,7 @@ VF
|
|||
end
|
||||
|
||||
it_should_set_arguments_and_environment_variables 20, 4, true
|
||||
it_should_force_ssh_transport_mode
|
||||
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
|
||||
it_should_set_optional_arguments({ "extra_vars" => "--extra-vars=@#{File.expand_path(__FILE__)}",
|
||||
"sudo" => "--sudo",
|
||||
"sudo_user" => "--sudo-user=deployer",
|
||||
|
@ -537,7 +527,7 @@ VF
|
|||
"limit" => "--limit=machine*:&vagrant:!that_one",
|
||||
"start_at_task" => "--start-at-task=an awesome task",
|
||||
})
|
||||
|
||||
|
||||
it "also includes given raw arguments" do
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
expect(args).to include("--su-user=foot")
|
||||
|
@ -548,7 +538,7 @@ VF
|
|||
|
||||
it "shows the ansible-playbook command, with additional quotes when required" do
|
||||
expect(machine.env.ui).to receive(:detail).with { |full_command|
|
||||
expect(full_command).to eq("ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=true PYTHONUNBUFFERED=1 ANSIBLE_SSH_ARGS='-o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/my/key1 --user=testuser --connection=ssh --why-not --su-user=foot --ask-su-pass --limit='all' --inventory-file=#{generated_inventory_dir} --extra-vars=@#{File.expand_path(__FILE__)} --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --limit='machine*:&vagrant:!that_one' --start-at-task='an awesome task' playbook.yml")
|
||||
expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_SSH_ARGS='-o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/my/key1 --user=testuser --connection=ssh --limit='machine*:&vagrant:!that_one' --inventory-file=#{generated_inventory_dir} --extra-vars=@#{File.expand_path(__FILE__)} --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --start-at-task='an awesome task' --why-not --su-user=foot --ask-su-pass --limit='all' playbook.yml")
|
||||
}
|
||||
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
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
require_relative "../../../base"
|
||||
|
||||
require Vagrant.source_root.join("plugins/pushes/atlas/config")
|
||||
|
||||
describe VagrantPlugins::AtlasPush::Config do
|
||||
include_context "unit"
|
||||
|
||||
before(:all) do
|
||||
I18n.load_path << Vagrant.source_root.join("plugins/pushes/atlas/locales/en.yml")
|
||||
I18n.reload!
|
||||
end
|
||||
|
||||
let(:machine) { double("machine") }
|
||||
|
||||
before do
|
||||
subject.token = "foo"
|
||||
end
|
||||
|
||||
describe "#address" do
|
||||
it "defaults to nil" do
|
||||
subject.finalize!
|
||||
expect(subject.address).to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#app" do
|
||||
it "defaults to nil" do
|
||||
subject.finalize!
|
||||
expect(subject.app).to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#dir" do
|
||||
it "defaults to ." do
|
||||
subject.finalize!
|
||||
expect(subject.dir).to eq(".")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#vcs" do
|
||||
it "defaults to true" do
|
||||
subject.finalize!
|
||||
expect(subject.vcs).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#uploader_path" do
|
||||
it "defaults to nil" do
|
||||
subject.finalize!
|
||||
expect(subject.uploader_path).to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#validate" do
|
||||
before do
|
||||
allow(machine).to receive(:env)
|
||||
.and_return(double("env",
|
||||
root_path: "",
|
||||
data_dir: Pathname.new(""),
|
||||
))
|
||||
|
||||
subject.app = "sethvargo/bacon"
|
||||
subject.dir = "."
|
||||
subject.vcs = true
|
||||
subject.uploader_path = "uploader"
|
||||
end
|
||||
|
||||
let(:result) { subject.validate(machine) }
|
||||
let(:errors) { result["Atlas push"] }
|
||||
|
||||
context "when the token is missing" do
|
||||
context "when a vagrant-login token exists" do
|
||||
before do
|
||||
allow(subject).to receive(:token_from_vagrant_login)
|
||||
.and_return("token_from_vagrant_login")
|
||||
end
|
||||
|
||||
it "uses the token from vagrant-login" do
|
||||
subject.token = ""
|
||||
subject.finalize!
|
||||
expect(errors).to be_empty
|
||||
expect(subject.token).to eq("token_from_vagrant_login")
|
||||
end
|
||||
end
|
||||
|
||||
context "when a token is given in the Vagrantfile" do
|
||||
before do
|
||||
allow(subject).to receive(:token_from_vagrant_login)
|
||||
.and_return("token_from_vagrant_login")
|
||||
end
|
||||
|
||||
it "uses the token in the Vagrantfile" do
|
||||
subject.token = "token_from_vagrantfile"
|
||||
subject.finalize!
|
||||
expect(errors).to be_empty
|
||||
expect(subject.token).to eq("token_from_vagrantfile")
|
||||
end
|
||||
end
|
||||
|
||||
context "when no token is given" do
|
||||
before do
|
||||
allow(subject).to receive(:token_from_vagrant_login)
|
||||
.and_return(nil)
|
||||
end
|
||||
|
||||
it "returns an error" do
|
||||
subject.token = ""
|
||||
subject.finalize!
|
||||
expect(errors).to include(I18n.t("atlas_push.errors.missing_token"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the app is missing" do
|
||||
it "returns an error" do
|
||||
subject.app = ""
|
||||
subject.finalize!
|
||||
expect(errors).to include(I18n.t("atlas_push.errors.missing_attribute",
|
||||
attribute: "app",
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
context "when the dir is missing" do
|
||||
it "returns an error" do
|
||||
subject.dir = ""
|
||||
subject.finalize!
|
||||
expect(errors).to include(I18n.t("atlas_push.errors.missing_attribute",
|
||||
attribute: "dir",
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
context "when the vcs is missing" do
|
||||
it "does not return an error" do
|
||||
subject.vcs = ""
|
||||
subject.finalize!
|
||||
expect(errors).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context "when the uploader_path is missing" do
|
||||
it "returns an error" do
|
||||
subject.uploader_path = ""
|
||||
subject.finalize!
|
||||
expect(errors).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#merge" do
|
||||
context "when includes are given" do
|
||||
let(:one) { described_class.new }
|
||||
let(:two) { described_class.new }
|
||||
|
||||
it "merges the result" do
|
||||
one.includes = %w(a b c)
|
||||
two.includes = %w(c d e)
|
||||
result = one.merge(two)
|
||||
expect(result.includes).to eq(%w(a b c d e))
|
||||
end
|
||||
end
|
||||
|
||||
context "when excludes are given" do
|
||||
let(:one) { described_class.new }
|
||||
let(:two) { described_class.new }
|
||||
|
||||
it "merges the result" do
|
||||
one.excludes = %w(a b c)
|
||||
two.excludes = %w(c d e)
|
||||
result = one.merge(two)
|
||||
expect(result.excludes).to eq(%w(a b c d e))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#include" do
|
||||
it "adds the item to the list" do
|
||||
subject.include("me")
|
||||
expect(subject.includes).to include("me")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#exclude" do
|
||||
it "adds the item to the list" do
|
||||
subject.exclude("not me")
|
||||
expect(subject.excludes).to include("not me")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,153 @@
|
|||
require_relative "../../../base"
|
||||
|
||||
require Vagrant.source_root.join("plugins/pushes/atlas/config")
|
||||
require Vagrant.source_root.join("plugins/pushes/atlas/push")
|
||||
|
||||
describe VagrantPlugins::AtlasPush::Push do
|
||||
include_context "unit"
|
||||
|
||||
let(:bin) { VagrantPlugins::AtlasPush::Push::UPLOADER_BIN }
|
||||
|
||||
let(:env) do
|
||||
double("env",
|
||||
root_path: File.expand_path("..", __FILE__)
|
||||
)
|
||||
end
|
||||
|
||||
let(:config) do
|
||||
VagrantPlugins::AtlasPush::Config.new.tap do |c|
|
||||
c.finalize!
|
||||
end
|
||||
end
|
||||
|
||||
subject { described_class.new(env, config) }
|
||||
|
||||
before do
|
||||
# Stub this right away to avoid real execs
|
||||
allow(Vagrant::Util::SafeExec).to receive(:exec)
|
||||
end
|
||||
|
||||
describe "#push" do
|
||||
it "pushes with the uploader" do
|
||||
allow(subject).to receive(:uploader_path).and_return("foo")
|
||||
|
||||
expect(subject).to receive(:execute).with("foo")
|
||||
|
||||
subject.push
|
||||
end
|
||||
|
||||
it "raises an exception if the uploader couldn't be found" do
|
||||
expect(subject).to receive(:uploader_path).and_return(nil)
|
||||
|
||||
expect { subject.push }.to raise_error(
|
||||
VagrantPlugins::AtlasPush::Errors::UploaderNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#execute" do
|
||||
let(:app) { "foo/bar" }
|
||||
|
||||
before do
|
||||
config.app = app
|
||||
end
|
||||
|
||||
it "sends the basic flags" do
|
||||
expect(Vagrant::Util::SafeExec).to receive(:exec).
|
||||
with("foo", "-vcs", app, env.root_path.to_s)
|
||||
|
||||
subject.execute("foo")
|
||||
end
|
||||
|
||||
it "doesn't send VCS if disabled" do
|
||||
expect(Vagrant::Util::SafeExec).to receive(:exec).
|
||||
with("foo", app, env.root_path.to_s)
|
||||
|
||||
config.vcs = false
|
||||
subject.execute("foo")
|
||||
end
|
||||
|
||||
it "sends includes" do
|
||||
expect(Vagrant::Util::SafeExec).to receive(:exec).
|
||||
with("foo", "-vcs", "-include", "foo", "-include",
|
||||
"bar", app, env.root_path.to_s)
|
||||
|
||||
config.includes = ["foo", "bar"]
|
||||
subject.execute("foo")
|
||||
end
|
||||
|
||||
it "sends excludes" do
|
||||
expect(Vagrant::Util::SafeExec).to receive(:exec).
|
||||
with("foo", "-vcs", "-exclude", "foo", "-exclude",
|
||||
"bar", app, env.root_path.to_s)
|
||||
|
||||
config.excludes = ["foo", "bar"]
|
||||
subject.execute("foo")
|
||||
end
|
||||
|
||||
it "sends custom server address" do
|
||||
expect(Vagrant::Util::SafeExec).to receive(:exec).
|
||||
with("foo", "-vcs", "-address", "foo", app, env.root_path.to_s)
|
||||
|
||||
config.address = "foo"
|
||||
subject.execute("foo")
|
||||
end
|
||||
|
||||
it "sends custom token" do
|
||||
expect(Vagrant::Util::SafeExec).to receive(:exec).
|
||||
with("foo", "-vcs", "-token", "atlas_token", app, env.root_path.to_s)
|
||||
|
||||
config.token = "atlas_token"
|
||||
subject.execute("foo")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#uploader_path" do
|
||||
it "should return the configured path if set" do
|
||||
config.uploader_path = "foo"
|
||||
expect(subject.uploader_path).to eq("foo")
|
||||
end
|
||||
|
||||
it "should look up the uploader via PATH if not set" do
|
||||
allow(Vagrant).to receive(:in_installer?).and_return(false)
|
||||
|
||||
expect(Vagrant::Util::Which).to receive(:which).
|
||||
with(described_class.const_get(:UPLOADER_BIN)).
|
||||
and_return("bar")
|
||||
|
||||
expect(subject.uploader_path).to eq("bar")
|
||||
end
|
||||
|
||||
it "should look up the uploader in the embedded dir if installer" do
|
||||
dir = temporary_dir
|
||||
|
||||
allow(Vagrant).to receive(:in_installer?).and_return(true)
|
||||
allow(Vagrant).to receive(:installer_embedded_dir).and_return(dir.to_s)
|
||||
|
||||
bin_path = dir.join("bin", bin)
|
||||
bin_path.dirname.mkpath
|
||||
bin_path.open("w+") { |f| f.write("hi") }
|
||||
|
||||
expect(subject.uploader_path).to eq(bin_path.to_s)
|
||||
end
|
||||
|
||||
it "should look up the uploader in the PATH if not in the installer" do
|
||||
dir = temporary_dir
|
||||
|
||||
allow(Vagrant).to receive(:in_installer?).and_return(true)
|
||||
allow(Vagrant).to receive(:installer_embedded_dir).and_return(dir.to_s)
|
||||
|
||||
expect(Vagrant::Util::Which).to receive(:which).
|
||||
with(described_class.const_get(:UPLOADER_BIN)).
|
||||
and_return("bar")
|
||||
|
||||
expect(subject.uploader_path).to eq("bar")
|
||||
end
|
||||
|
||||
it "should return nil if its not found anywhere" do
|
||||
allow(Vagrant).to receive(:in_installer?).and_return(false)
|
||||
allow(Vagrant::Util::Which).to receive(:which).and_return(nil)
|
||||
|
||||
expect(subject.uploader_path).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue