Merge pull request #10148 from briancain/add-cloud-command
Introduce `vagrant cloud` subcommand to Vagrant
This commit is contained in:
commit
23de7f0898
|
@ -53,7 +53,7 @@ __vagrantinvestigate() {
|
||||||
_vagrant() {
|
_vagrant() {
|
||||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
commands="box connect destroy docker-exec docker-logs docker-run global-status halt help init list-commands login package plugin provision push rdp reload resume rsync rsync-auto share snapshot ssh ssh-config status suspend up version"
|
commands="box cloud connect destroy docker-exec docker-logs docker-run global-status halt help init list-commands login package plugin provision push rdp reload resume rsync rsync-auto share snapshot ssh ssh-config status suspend up version"
|
||||||
|
|
||||||
if [ $COMP_CWORD == 1 ]
|
if [ $COMP_CWORD == 1 ]
|
||||||
then
|
then
|
||||||
|
@ -95,6 +95,11 @@ _vagrant() {
|
||||||
COMPREPLY=($(compgen -W "${box_commands}" -- ${cur}))
|
COMPREPLY=($(compgen -W "${box_commands}" -- ${cur}))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
"cloud")
|
||||||
|
cloud_commands="auth box search provider publish version"
|
||||||
|
COMPREPLY=($(compgen -W "${cloud_commands}" -- ${cur}))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
"plugin")
|
"plugin")
|
||||||
plugin_commands="install license list uninstall update"
|
plugin_commands="install license list uninstall update"
|
||||||
COMPREPLY=($(compgen -W "${plugin_commands}" -- ${cur}))
|
COMPREPLY=($(compgen -W "${plugin_commands}" -- ${cur}))
|
||||||
|
|
|
@ -49,7 +49,16 @@ if ENV["VAGRANT_LOG"] && ENV["VAGRANT_LOG"] != ""
|
||||||
# Set the logging level on all "vagrant" namespaced
|
# Set the logging level on all "vagrant" namespaced
|
||||||
# logs as long as we have a valid level.
|
# logs as long as we have a valid level.
|
||||||
if level
|
if level
|
||||||
logger = Log4r::Logger.new("vagrant")
|
# NOTE: We must do this little hack to allow
|
||||||
|
# rest-client to write using the `<<` operator.
|
||||||
|
# See https://github.com/rest-client/rest-client/issues/34#issuecomment-290858
|
||||||
|
# for more information
|
||||||
|
class VagrantLogger < Log4r::Logger
|
||||||
|
def << (msg)
|
||||||
|
debug(msg.strip)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
logger = VagrantLogger.new("vagrant")
|
||||||
logger.outputters = Log4r::Outputter.stderr
|
logger.outputters = Log4r::Outputter.stderr
|
||||||
logger.level = level
|
logger.level = level
|
||||||
base_formatter = Log4r::BasicFormatter.new
|
base_formatter = Log4r::BasicFormatter.new
|
||||||
|
@ -59,6 +68,11 @@ if ENV["VAGRANT_LOG"] && ENV["VAGRANT_LOG"] != ""
|
||||||
date_pattern: "%F %T"
|
date_pattern: "%F %T"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
# Vagrant Cloud gem uses RestClient to make HTTP requests, so
|
||||||
|
# log them if debug is enabled and use Vagrants logger
|
||||||
|
require 'rest_client'
|
||||||
|
RestClient.log = logger
|
||||||
|
|
||||||
Log4r::Outputter.stderr.formatter = Vagrant::Util::LoggingFormatter.new(base_formatter)
|
Log4r::Outputter.stderr.formatter = Vagrant::Util::LoggingFormatter.new(base_formatter)
|
||||||
logger = nil
|
logger = nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -832,6 +832,14 @@ module Vagrant
|
||||||
error_key(:upload_source_missing)
|
error_key(:upload_source_missing)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class UploaderError < VagrantError
|
||||||
|
error_key(:uploader_error)
|
||||||
|
end
|
||||||
|
|
||||||
|
class UploaderInterrupted < UploaderError
|
||||||
|
error_key(:uploader_interrupted)
|
||||||
|
end
|
||||||
|
|
||||||
class VagrantInterrupt < VagrantError
|
class VagrantInterrupt < VagrantError
|
||||||
error_key(:interrupted)
|
error_key(:interrupted)
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
module Vagrant
|
||||||
|
module Util
|
||||||
|
class CurlHelper
|
||||||
|
|
||||||
|
# Hosts that do not require notification on redirect
|
||||||
|
SILENCED_HOSTS = [
|
||||||
|
"vagrantcloud.com".freeze,
|
||||||
|
"vagrantup.com".freeze
|
||||||
|
].freeze
|
||||||
|
|
||||||
|
def self.capture_output_proc(logger, ui, source=nil)
|
||||||
|
progress_data = ""
|
||||||
|
progress_regexp = /^\r\s*(\d.+?)\r/m
|
||||||
|
|
||||||
|
# Setup the proc that'll receive the real-time data from
|
||||||
|
# the downloader.
|
||||||
|
data_proc = Proc.new do |type, data|
|
||||||
|
# Type will always be "stderr" because that is the only
|
||||||
|
# type of data we're subscribed for notifications.
|
||||||
|
|
||||||
|
# Accumulate progress_data
|
||||||
|
progress_data << data
|
||||||
|
|
||||||
|
while true
|
||||||
|
# If the download has been redirected and we are no longer downloading
|
||||||
|
# from the original host, notify the user that the target host has
|
||||||
|
# changed from the source.
|
||||||
|
if progress_data.include?("Location")
|
||||||
|
location = progress_data.scan(/(^|[^\w-])Location: (.+?)$/m).flatten.compact.last.to_s.strip
|
||||||
|
if !location.empty?
|
||||||
|
location_uri = URI.parse(location)
|
||||||
|
|
||||||
|
unless location_uri.host.nil?
|
||||||
|
redirect_notify = false
|
||||||
|
logger.info("download redirected to #{location}")
|
||||||
|
source_uri = URI.parse(source)
|
||||||
|
source_host = source_uri.host.to_s.split(".", 2).last
|
||||||
|
location_host = location_uri.host.to_s.split(".", 2).last
|
||||||
|
if !redirect_notify && location_host != source_host && !SILENCED_HOSTS.include?(location_host)
|
||||||
|
ui.clear_line
|
||||||
|
ui.detail "Download redirected to host: #{location_uri.host}"
|
||||||
|
end
|
||||||
|
redirect_notify = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
progress_data.replace("")
|
||||||
|
break
|
||||||
|
end
|
||||||
|
# If we have a full amount of column data (two "\r") then
|
||||||
|
# we report new progress reports. Otherwise, just keep
|
||||||
|
# accumulating.
|
||||||
|
match = nil
|
||||||
|
check_match = true
|
||||||
|
|
||||||
|
while check_match
|
||||||
|
check_match = progress_regexp.match(progress_data)
|
||||||
|
if check_match
|
||||||
|
data = check_match[1].to_s
|
||||||
|
stop = progress_data.index(data) + data.length
|
||||||
|
progress_data.slice!(0, stop)
|
||||||
|
|
||||||
|
match = check_match
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
break if !match
|
||||||
|
|
||||||
|
# Ignore the first \r and split by whitespace to grab the columns
|
||||||
|
columns = data.strip.split(/\s+/)
|
||||||
|
|
||||||
|
# COLUMN DATA:
|
||||||
|
#
|
||||||
|
# 0 - % total
|
||||||
|
# 1 - Total size
|
||||||
|
# 2 - % received
|
||||||
|
# 3 - Received size
|
||||||
|
# 4 - % transferred
|
||||||
|
# 5 - Transferred size
|
||||||
|
# 6 - Average download speed
|
||||||
|
# 7 - Average upload speed
|
||||||
|
# 9 - Total time
|
||||||
|
# 9 - Time spent
|
||||||
|
# 10 - Time left
|
||||||
|
# 11 - Current speed
|
||||||
|
|
||||||
|
output = "Progress: #{columns[0]}% (Rate: #{columns[11]}/s, Estimated time remaining: #{columns[10]})"
|
||||||
|
ui.clear_line
|
||||||
|
ui.detail(output, new_line: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return data_proc
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,6 +6,7 @@ require "digest/sha1"
|
||||||
require "vagrant/util/busy"
|
require "vagrant/util/busy"
|
||||||
require "vagrant/util/platform"
|
require "vagrant/util/platform"
|
||||||
require "vagrant/util/subprocess"
|
require "vagrant/util/subprocess"
|
||||||
|
require "vagrant/util/curl_helper"
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
module Util
|
module Util
|
||||||
|
@ -88,85 +89,7 @@ module Vagrant
|
||||||
# tell us output so we can parse it out.
|
# tell us output so we can parse it out.
|
||||||
extra_subprocess_opts[:notify] = :stderr
|
extra_subprocess_opts[:notify] = :stderr
|
||||||
|
|
||||||
progress_data = ""
|
data_proc = Vagrant::Util::CurlHelper.capture_output_proc(@logger, @ui, @source)
|
||||||
progress_regexp = /^\r\s*(\d.+?)\r/m
|
|
||||||
|
|
||||||
# Setup the proc that'll receive the real-time data from
|
|
||||||
# the downloader.
|
|
||||||
data_proc = Proc.new do |type, data|
|
|
||||||
# Type will always be "stderr" because that is the only
|
|
||||||
# type of data we're subscribed for notifications.
|
|
||||||
|
|
||||||
# Accumulate progress_data
|
|
||||||
progress_data << data
|
|
||||||
|
|
||||||
while true
|
|
||||||
# If the download has been redirected and we are no longer downloading
|
|
||||||
# from the original host, notify the user that the target host has
|
|
||||||
# changed from the source.
|
|
||||||
if progress_data.include?("Location")
|
|
||||||
location = progress_data.scan(/(^|[^\w-])Location: (.+?)$/m).flatten.compact.last.to_s.strip
|
|
||||||
if !location.empty?
|
|
||||||
location_uri = URI.parse(location)
|
|
||||||
|
|
||||||
unless location_uri.host.nil?
|
|
||||||
@logger.info("download redirected to #{location}")
|
|
||||||
source_uri = URI.parse(source)
|
|
||||||
source_host = source_uri.host.to_s.split(".", 2).last
|
|
||||||
location_host = location_uri.host.to_s.split(".", 2).last
|
|
||||||
if !@redirect_notify && location_host != source_host && !SILENCED_HOSTS.include?(location_host)
|
|
||||||
@ui.clear_line
|
|
||||||
@ui.detail "Download redirected to host: #{location_uri.host}"
|
|
||||||
end
|
|
||||||
@redirect_notify = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
progress_data.replace("")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
# If we have a full amount of column data (two "\r") then
|
|
||||||
# we report new progress reports. Otherwise, just keep
|
|
||||||
# accumulating.
|
|
||||||
match = nil
|
|
||||||
check_match = true
|
|
||||||
|
|
||||||
while check_match
|
|
||||||
check_match = progress_regexp.match(progress_data)
|
|
||||||
if check_match
|
|
||||||
data = check_match[1].to_s
|
|
||||||
stop = progress_data.index(data) + data.length
|
|
||||||
progress_data.slice!(0, stop)
|
|
||||||
|
|
||||||
match = check_match
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
break if !match
|
|
||||||
|
|
||||||
# Ignore the first \r and split by whitespace to grab the columns
|
|
||||||
columns = data.strip.split(/\s+/)
|
|
||||||
|
|
||||||
# COLUMN DATA:
|
|
||||||
#
|
|
||||||
# 0 - % total
|
|
||||||
# 1 - Total size
|
|
||||||
# 2 - % received
|
|
||||||
# 3 - Received size
|
|
||||||
# 4 - % transferred
|
|
||||||
# 5 - Transferred size
|
|
||||||
# 6 - Average download speed
|
|
||||||
# 7 - Average upload speed
|
|
||||||
# 9 - Total time
|
|
||||||
# 9 - Time spent
|
|
||||||
# 10 - Time left
|
|
||||||
# 11 - Current speed
|
|
||||||
|
|
||||||
output = "Progress: #{columns[0]}% (Rate: #{columns[11]}/s, Estimated time remaining: #{columns[10]})"
|
|
||||||
@ui.clear_line
|
|
||||||
@ui.detail(output, new_line: false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@logger.info("Downloader starting download: ")
|
@logger.info("Downloader starting download: ")
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
require "uri"
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
require "vagrant/util/busy"
|
||||||
|
require "vagrant/util/platform"
|
||||||
|
require "vagrant/util/subprocess"
|
||||||
|
require "vagrant/util/curl_helper"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
module Util
|
||||||
|
# This class uploads files using various protocols by subprocessing
|
||||||
|
# to cURL. cURL is a much more capable and complete download tool than
|
||||||
|
# a hand-rolled Ruby library, so we defer to its expertise.
|
||||||
|
class Uploader
|
||||||
|
|
||||||
|
# @param [String] destination - valid URL to upload file to
|
||||||
|
# @param [String] file - location of file to upload on disk
|
||||||
|
# @param [Hash] options
|
||||||
|
def initialize(destination, file, options=nil)
|
||||||
|
options ||= {}
|
||||||
|
@logger = Log4r::Logger.new("vagrant::util::uploader")
|
||||||
|
@destination = destination.to_s
|
||||||
|
@file = file.to_s
|
||||||
|
@ui = options[:ui]
|
||||||
|
@request_method = options[:method]
|
||||||
|
|
||||||
|
if !@request_method
|
||||||
|
@request_method = "PUT"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload!
|
||||||
|
data_proc = Vagrant::Util::CurlHelper.capture_output_proc(@logger, @ui)
|
||||||
|
|
||||||
|
@logger.info("Uploader starting upload: ")
|
||||||
|
@logger.info(" -- Source: #{@file}")
|
||||||
|
@logger.info(" -- Destination: #{@destination}")
|
||||||
|
|
||||||
|
options = build_options
|
||||||
|
subprocess_options = {notify: :stderr}
|
||||||
|
|
||||||
|
begin
|
||||||
|
execute_curl(options, subprocess_options, &data_proc)
|
||||||
|
rescue Errors::UploaderError => e
|
||||||
|
raise
|
||||||
|
ensure
|
||||||
|
@ui.clear_line if @ui
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def build_options
|
||||||
|
options = [@destination, "--request", @request_method, "--upload-file", @file]
|
||||||
|
return options
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_curl(options, subprocess_options, &data_proc)
|
||||||
|
options = options.dup
|
||||||
|
options << subprocess_options
|
||||||
|
|
||||||
|
# Create the callback that is called if we are interrupted
|
||||||
|
interrupted = false
|
||||||
|
int_callback = Proc.new do
|
||||||
|
@logger.info("Uploader interrupted!")
|
||||||
|
interrupted = true
|
||||||
|
end
|
||||||
|
|
||||||
|
# Execute!
|
||||||
|
result = Busy.busy(int_callback) do
|
||||||
|
Subprocess.execute("curl", *options, &data_proc)
|
||||||
|
end
|
||||||
|
|
||||||
|
# If the upload was interrupted, then raise a specific error
|
||||||
|
raise Errors::UploaderInterrupted if interrupted
|
||||||
|
|
||||||
|
# If it didn't exit successfully, we need to parse the data and
|
||||||
|
# show an error message.
|
||||||
|
if result.exit_code != 0
|
||||||
|
@logger.warn("Uploader exit code: #{result.exit_code}")
|
||||||
|
check = result.stderr.match(/\n*curl:\s+\((?<code>\d+)\)\s*(?<error>.*)$/)
|
||||||
|
if !check
|
||||||
|
err_msg = result.stderr
|
||||||
|
else
|
||||||
|
err_msg = check[:error]
|
||||||
|
end
|
||||||
|
|
||||||
|
raise Errors::UploaderError,
|
||||||
|
exit_code: result.exit_code,
|
||||||
|
message: err_msg
|
||||||
|
end
|
||||||
|
|
||||||
|
if @ui
|
||||||
|
@ui.clear_line
|
||||||
|
# Windows doesn't clear properly for some reason, so we just
|
||||||
|
# output one more newline.
|
||||||
|
@ui.detail("") if Platform.windows?
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,90 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module AuthCommand
|
||||||
|
module Command
|
||||||
|
class Login < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud auth login [options]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
o.on("-c", "--check", "Checks if currently logged in") do |c|
|
||||||
|
options[:check] = c
|
||||||
|
end
|
||||||
|
|
||||||
|
o.on("-d", "--description DESCRIPTION", String, "Set description for the Vagrant Cloud token") do |d|
|
||||||
|
options[:description] = d
|
||||||
|
end
|
||||||
|
|
||||||
|
o.on("-k", "--logout", "Logout from Vagrant Cloud") do |k|
|
||||||
|
options[:logout] = k
|
||||||
|
end
|
||||||
|
|
||||||
|
o.on("-t", "--token TOKEN", String, "Set the Vagrant Cloud token") do |t|
|
||||||
|
options[:token] = t
|
||||||
|
end
|
||||||
|
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |l|
|
||||||
|
options[:login] = l
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
@client = Client.new(@env)
|
||||||
|
@client.username_or_email = options[:login]
|
||||||
|
|
||||||
|
# Determine what task we're actually taking based on flags
|
||||||
|
if options[:check]
|
||||||
|
return execute_check
|
||||||
|
elsif options[:logout]
|
||||||
|
return execute_logout
|
||||||
|
elsif options[:token]
|
||||||
|
return execute_token(options[:token])
|
||||||
|
else
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
0
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_check
|
||||||
|
if @client.logged_in?
|
||||||
|
@env.ui.success(I18n.t("cloud_command.check_logged_in"))
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
@env.ui.error(I18n.t("cloud_command.check_not_logged_in"))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_logout
|
||||||
|
@client.clear_token
|
||||||
|
@env.ui.success(I18n.t("cloud_command.logged_out"))
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_token(token)
|
||||||
|
@client.store_token(token)
|
||||||
|
@env.ui.success(I18n.t("cloud_command.token_saved"))
|
||||||
|
|
||||||
|
if @client.logged_in?
|
||||||
|
@env.ui.success(I18n.t("cloud_command.check_logged_in"))
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
@env.ui.error(I18n.t("cloud_command.invalid_token"))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,42 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module AuthCommand
|
||||||
|
module Command
|
||||||
|
class Logout < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud auth logout [options]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Log out of Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |l|
|
||||||
|
options[:login] = l
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if !argv.empty?
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
# Initializes client and deletes token on disk
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
@client.clear_token
|
||||||
|
@env.ui.success(I18n.t("cloud_command.logged_out"))
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module AuthCommand
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "vagrant cloud auth"
|
||||||
|
description <<-DESC
|
||||||
|
Authorization commands for Vagrant Cloud
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command(:auth) do
|
||||||
|
require_relative "root"
|
||||||
|
Command::Root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,73 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module AuthCommand
|
||||||
|
module Command
|
||||||
|
class Root < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"Manages Vagrant Cloud authorization related to Vagrant Cloud"
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(argv, env)
|
||||||
|
super
|
||||||
|
|
||||||
|
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||||
|
@subcommands = Vagrant::Registry.new
|
||||||
|
@subcommands.register(:login) do
|
||||||
|
require File.expand_path("../login", __FILE__)
|
||||||
|
Command::Login
|
||||||
|
end
|
||||||
|
@subcommands.register(:logout) do
|
||||||
|
require File.expand_path("../logout", __FILE__)
|
||||||
|
Command::Logout
|
||||||
|
end
|
||||||
|
@subcommands.register(:whoami) do
|
||||||
|
require File.expand_path("../whoami", __FILE__)
|
||||||
|
Command::Whoami
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
if @main_args.include?("-h") || @main_args.include?("--help")
|
||||||
|
# Print the help for all the box commands.
|
||||||
|
return help
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we reached this far then we must have a subcommand. If not,
|
||||||
|
# then we also just print the help and exit.
|
||||||
|
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||||
|
return help if !command_class || !@sub_command
|
||||||
|
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
||||||
|
|
||||||
|
# Initialize and execute the command class
|
||||||
|
command_class.new(@sub_args, @env).execute
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prints the help out for this command
|
||||||
|
def help
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: vagrant cloud auth <subcommand> [<args>]"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Authorization with Vagrant Cloud"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Available subcommands:"
|
||||||
|
|
||||||
|
# Add the available subcommands as separators in order to print them
|
||||||
|
# out as well.
|
||||||
|
keys = []
|
||||||
|
@subcommands.each { |key, value| keys << key.to_s }
|
||||||
|
|
||||||
|
keys.sort.each do |key|
|
||||||
|
opts.separator " #{key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For help on any individual subcommand run `vagrant cloud auth <subcommand> -h`"
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.info(opts.help, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,62 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module AuthCommand
|
||||||
|
module Command
|
||||||
|
class Whoami < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud auth whoami [options] [token]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Display currently logged in user"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |l|
|
||||||
|
options[:login] = l
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.size > 1
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:login])
|
||||||
|
|
||||||
|
if argv.first
|
||||||
|
token = argv.first
|
||||||
|
else
|
||||||
|
token = @client.token
|
||||||
|
end
|
||||||
|
|
||||||
|
whoami(token, options[:username])
|
||||||
|
end
|
||||||
|
|
||||||
|
def whoami(access_token, username)
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(username, access_token, server_url)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = account.validate_token
|
||||||
|
user = success["user"]["username"]
|
||||||
|
@env.ui.success("Currently logged in as #{user}")
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.whoami.read_error", org: username))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,75 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module BoxCommand
|
||||||
|
module Command
|
||||||
|
class Create < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud box create [options] organization/box-name"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Creates an empty box entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-d", "--description DESCRIPTION", String, "Full description of the box") do |d|
|
||||||
|
options[:description] = d
|
||||||
|
end
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
o.on("-s", "--short-description DESCRIPTION", String, "Short description of the box") do |s|
|
||||||
|
options[:short] = s
|
||||||
|
end
|
||||||
|
o.on("-p", "--private", "Makes box private") do |p|
|
||||||
|
options[:private] = p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 1
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
create_box(org, box_name, options, @client.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [String] - org
|
||||||
|
# @param [String] - box_name
|
||||||
|
# @param [Hash] - options
|
||||||
|
def create_box(org, box_name, options, access_token)
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, options[:short], options[:description], access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = box.create
|
||||||
|
@env.ui.success(I18n.t("cloud_command.box.create_success", org: org, box_name: box_name))
|
||||||
|
success = success.delete_if { |_, v| v.nil? }
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.box.create_fail", org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,65 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module BoxCommand
|
||||||
|
module Command
|
||||||
|
class Delete < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud box delete [options] organization/box-name"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Deletes box entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 1
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.box.delete_warn", box: argv.first))
|
||||||
|
cont = @env.ui.ask(I18n.t("cloud_command.continue"))
|
||||||
|
return 1 if cont.strip.downcase != "y"
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
delete_box(org, box_name, options[:username], @client.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_box(org, box_name, username, access_token)
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(username, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = box.delete(org, box_name)
|
||||||
|
@env.ui.success(I18n.t("cloud_command.box.delete_success", org: org, box_name: box_name))
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.box.delete_fail", org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module BoxCommand
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "vagrant cloud box"
|
||||||
|
description <<-DESC
|
||||||
|
Box life cycle commands for Vagrant Cloud
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command(:box) do
|
||||||
|
require_relative "root"
|
||||||
|
Command::Root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,77 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module BoxCommand
|
||||||
|
module Command
|
||||||
|
class Root < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"Commands to manage boxes on Vagrant Cloud"
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(argv, env)
|
||||||
|
super
|
||||||
|
|
||||||
|
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||||
|
@subcommands = Vagrant::Registry.new
|
||||||
|
@subcommands.register(:create) do
|
||||||
|
require File.expand_path("../create", __FILE__)
|
||||||
|
Command::Create
|
||||||
|
end
|
||||||
|
@subcommands.register(:delete) do
|
||||||
|
require File.expand_path("../delete", __FILE__)
|
||||||
|
Command::Delete
|
||||||
|
end
|
||||||
|
@subcommands.register(:show) do
|
||||||
|
require File.expand_path("../show", __FILE__)
|
||||||
|
Command::Show
|
||||||
|
end
|
||||||
|
@subcommands.register(:update) do
|
||||||
|
require File.expand_path("../update", __FILE__)
|
||||||
|
Command::Update
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
if @main_args.include?("-h") || @main_args.include?("--help")
|
||||||
|
# Print the help for all the box commands.
|
||||||
|
return help
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we reached this far then we must have a subcommand. If not,
|
||||||
|
# then we also just print the help and exit.
|
||||||
|
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||||
|
return help if !command_class || !@sub_command
|
||||||
|
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
||||||
|
|
||||||
|
# Initialize and execute the command class
|
||||||
|
command_class.new(@sub_args, @env).execute
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prints the help out for this command
|
||||||
|
def help
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: vagrant cloud box <subcommand> [<args>]"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Commands to manage boxes on Vagrant Cloud"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Available subcommands:"
|
||||||
|
|
||||||
|
# Add the available subcommands as separators in order to print them
|
||||||
|
# out as well.
|
||||||
|
keys = []
|
||||||
|
@subcommands.each { |key, value| keys << key.to_s }
|
||||||
|
|
||||||
|
keys.sort.each do |key|
|
||||||
|
opts.separator " #{key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For help on any individual subcommand run `vagrant cloud box <subcommand> -h`"
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.info(opts.help, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,74 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module BoxCommand
|
||||||
|
module Command
|
||||||
|
class Show < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud box show [options] organization/box-name"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Displays a boxes attributes on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |u|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
o.on("--versions VERSION", String, "Display box information for a specific version") do |v|
|
||||||
|
options[:version] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 1
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
|
||||||
|
show_box(box[0], box[1], options, @client.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_box(org, box_name, options, access_token)
|
||||||
|
username = options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(username, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = box.read(org, box_name)
|
||||||
|
|
||||||
|
if options[:version]
|
||||||
|
# show *this* version only
|
||||||
|
results = success["versions"].select{ |v| v if v["version"] == options[:version] }.first
|
||||||
|
if !results
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.box.show_filter_empty", version: options[:version], org: org, box_name: box_name))
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
results = success
|
||||||
|
end
|
||||||
|
results = results.delete_if { |_, v| v.nil? }
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(results, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.box.show_fail", org: org,box_name:box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,71 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module BoxCommand
|
||||||
|
module Command
|
||||||
|
class Update < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud box update [options] organization/box-name"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Updates a box entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-d", "--description DESCRIPTION", "Full description of the box") do |d|
|
||||||
|
options[:description] = d
|
||||||
|
end
|
||||||
|
o.on("-u", "--username", "The username of the organization that will own the box") do |u|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
o.on("-s", "--short-description DESCRIPTION", "Short description of the box") do |s|
|
||||||
|
options[:short_description] = s
|
||||||
|
end
|
||||||
|
o.on("-p", "--private", "Makes box private") do |p|
|
||||||
|
options[:private] = p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 1 || options.length == 0
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
|
||||||
|
update_box(box[0], box[1], options, @client.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_box(org, box_name, options, access_token)
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(options[:username], access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
|
||||||
|
options[:organization] = org
|
||||||
|
options[:name] = box_name
|
||||||
|
begin
|
||||||
|
success = box.update(options)
|
||||||
|
@env.ui.success(I18n.t("cloud_command.box.update_success", org: org, box_name: box_name))
|
||||||
|
success = success.delete_if{|_, v|v.nil?}
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.box.update_fail", org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,264 @@
|
||||||
|
require "rest_client"
|
||||||
|
require "vagrant_cloud"
|
||||||
|
require "vagrant/util/downloader"
|
||||||
|
require "vagrant/util/presence"
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/errors")
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
class Client
|
||||||
|
######################################################################
|
||||||
|
# Class that deals with managing users 'local' token for Vagrant Cloud
|
||||||
|
######################################################################
|
||||||
|
APP = "app".freeze
|
||||||
|
|
||||||
|
include Vagrant::Util::Presence
|
||||||
|
|
||||||
|
attr_accessor :username_or_email
|
||||||
|
attr_accessor :password
|
||||||
|
attr_reader :two_factor_default_delivery_method
|
||||||
|
attr_reader :two_factor_delivery_methods
|
||||||
|
|
||||||
|
# Initializes a login client with the given Vagrant::Environment.
|
||||||
|
#
|
||||||
|
# @param [Vagrant::Environment] env
|
||||||
|
def initialize(env)
|
||||||
|
@logger = Log4r::Logger.new("vagrant::cloud::client")
|
||||||
|
@env = env
|
||||||
|
end
|
||||||
|
|
||||||
|
# Removes the token, effectively logging the user out.
|
||||||
|
def clear_token
|
||||||
|
@logger.info("Clearing 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
|
||||||
|
Vagrant::Util::CredentialScrubber.sensitive(token)
|
||||||
|
|
||||||
|
with_error_handling do
|
||||||
|
url = "#{Vagrant.server_url}/api/v1/authenticate" +
|
||||||
|
"?access_token=#{token}"
|
||||||
|
RestClient.get(url, content_type: :json)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
rescue Errors::Unauthorized
|
||||||
|
false
|
||||||
|
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] description
|
||||||
|
# @param [String] code
|
||||||
|
# @return [String] token The access token, or nil if auth failed.
|
||||||
|
def login(description: nil, code: nil)
|
||||||
|
@logger.info("Logging in '#{username_or_email}'")
|
||||||
|
|
||||||
|
Vagrant::Util::CredentialScrubber.sensitive(password)
|
||||||
|
response = post(
|
||||||
|
"/api/v1/authenticate", {
|
||||||
|
user: {
|
||||||
|
login: username_or_email,
|
||||||
|
password: password
|
||||||
|
},
|
||||||
|
token: {
|
||||||
|
description: description
|
||||||
|
},
|
||||||
|
two_factor: {
|
||||||
|
code: code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Vagrant::Util::CredentialScrubber.sensitive(response["token"])
|
||||||
|
response["token"]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Requests a 2FA code
|
||||||
|
# @param [String] delivery_method
|
||||||
|
def request_code(delivery_method)
|
||||||
|
@env.ui.warn("Requesting 2FA code via #{delivery_method.upcase}...")
|
||||||
|
|
||||||
|
Vagrant::Util::CredentialScrubber.sensitive(password)
|
||||||
|
response = post(
|
||||||
|
"/api/v1/two-factor/request-code", {
|
||||||
|
user: {
|
||||||
|
login: username_or_email,
|
||||||
|
password: password
|
||||||
|
},
|
||||||
|
two_factor: {
|
||||||
|
delivery_method: delivery_method.downcase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
two_factor = response['two_factor']
|
||||||
|
obfuscated_destination = two_factor['obfuscated_destination']
|
||||||
|
|
||||||
|
@env.ui.success("2FA code sent to #{obfuscated_destination}.")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Issues a post to a Vagrant Cloud path with the given payload.
|
||||||
|
# @param [String] path
|
||||||
|
# @param [Hash] payload
|
||||||
|
# @return [Hash] response data
|
||||||
|
def post(path, payload)
|
||||||
|
with_error_handling do
|
||||||
|
url = File.join(Vagrant.server_url, path)
|
||||||
|
|
||||||
|
proxy = nil
|
||||||
|
proxy ||= ENV["HTTPS_PROXY"] || ENV["https_proxy"]
|
||||||
|
proxy ||= ENV["HTTP_PROXY"] || ENV["http_proxy"]
|
||||||
|
RestClient.proxy = proxy
|
||||||
|
|
||||||
|
response = RestClient::Request.execute(
|
||||||
|
method: :post,
|
||||||
|
url: url,
|
||||||
|
payload: JSON.dump(payload),
|
||||||
|
proxy: proxy,
|
||||||
|
headers: {
|
||||||
|
accept: :json,
|
||||||
|
content_type: :json,
|
||||||
|
user_agent: Vagrant::Util::Downloader::USER_AGENT,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
JSON.load(response.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Stores the given token locally, removing any previous tokens.
|
||||||
|
#
|
||||||
|
# @param [String] token
|
||||||
|
def store_token(token)
|
||||||
|
@logger.info("Storing token in #{token_path}")
|
||||||
|
|
||||||
|
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
|
||||||
|
# `VAGRANT_CLOUD_TOKEN` environment variable and then fallback to the stored
|
||||||
|
# access token on disk.
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def token
|
||||||
|
if present?(ENV["VAGRANT_CLOUD_TOKEN"]) && token_path.exist?
|
||||||
|
@env.ui.warn <<-EOH.strip
|
||||||
|
Vagrant detected both the VAGRANT_CLOUD_TOKEN environment variable and a Vagrant login
|
||||||
|
token are present on this system. The VAGRANT_CLOUD_TOKEN environment variable takes
|
||||||
|
precedence over the locally stored token. To remove this error, either unset
|
||||||
|
the VAGRANT_CLOUD_TOKEN environment variable or remove the login token stored on disk:
|
||||||
|
|
||||||
|
~/.vagrant.d/data/vagrant_login_token
|
||||||
|
|
||||||
|
EOH
|
||||||
|
end
|
||||||
|
|
||||||
|
if present?(ENV["VAGRANT_CLOUD_TOKEN"])
|
||||||
|
@logger.debug("Using authentication token from environment variable")
|
||||||
|
return ENV["VAGRANT_CLOUD_TOKEN"]
|
||||||
|
end
|
||||||
|
|
||||||
|
if token_path.exist?
|
||||||
|
@logger.debug("Using authentication token from disk at #{token_path}")
|
||||||
|
return token_path.read.strip
|
||||||
|
end
|
||||||
|
|
||||||
|
if present?(ENV["ATLAS_TOKEN"])
|
||||||
|
@logger.warn("ATLAS_TOKEN detected within environment. Using ATLAS_TOKEN in place of VAGRANT_CLOUD_TOKEN.")
|
||||||
|
return ENV["ATLAS_TOKEN"]
|
||||||
|
end
|
||||||
|
|
||||||
|
@logger.debug("No authentication token in environment or #{token_path}")
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def with_error_handling(&block)
|
||||||
|
yield
|
||||||
|
rescue RestClient::Unauthorized
|
||||||
|
@logger.debug("Unauthorized!")
|
||||||
|
raise Errors::Unauthorized
|
||||||
|
rescue RestClient::BadRequest => e
|
||||||
|
@logger.debug("Bad request:")
|
||||||
|
@logger.debug(e.message)
|
||||||
|
@logger.debug(e.backtrace.join("\n"))
|
||||||
|
parsed_response = JSON.parse(e.response)
|
||||||
|
errors = parsed_response["errors"].join("\n")
|
||||||
|
raise Errors::ServerError, errors: errors
|
||||||
|
rescue RestClient::NotAcceptable => e
|
||||||
|
@logger.debug("Got unacceptable response:")
|
||||||
|
@logger.debug(e.message)
|
||||||
|
@logger.debug(e.backtrace.join("\n"))
|
||||||
|
|
||||||
|
parsed_response = JSON.parse(e.response)
|
||||||
|
|
||||||
|
if two_factor = parsed_response['two_factor']
|
||||||
|
store_two_factor_information two_factor
|
||||||
|
|
||||||
|
if two_factor_default_delivery_method != APP
|
||||||
|
request_code two_factor_default_delivery_method
|
||||||
|
end
|
||||||
|
|
||||||
|
raise Errors::TwoFactorRequired
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
errors = parsed_response["errors"].join("\n")
|
||||||
|
raise Errors::ServerError, errors: errors
|
||||||
|
rescue JSON::ParserError; end
|
||||||
|
|
||||||
|
@logger.debug("Got an unexpected error:")
|
||||||
|
@logger.debug(e.inspect)
|
||||||
|
raise Errors::Unexpected, error: e.inspect
|
||||||
|
rescue SocketError
|
||||||
|
@logger.info("Socket error")
|
||||||
|
raise Errors::ServerUnreachable, url: Vagrant.server_url.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def token_path
|
||||||
|
@env.data_dir.join("vagrant_login_token")
|
||||||
|
end
|
||||||
|
|
||||||
|
def store_two_factor_information(two_factor)
|
||||||
|
@two_factor_default_delivery_method =
|
||||||
|
two_factor['default_delivery_method']
|
||||||
|
|
||||||
|
@two_factor_delivery_methods =
|
||||||
|
two_factor['delivery_methods']
|
||||||
|
|
||||||
|
@env.ui.warn "2FA is enabled for your account."
|
||||||
|
if two_factor_default_delivery_method == APP
|
||||||
|
@env.ui.info "Enter the code from your authenticator."
|
||||||
|
else
|
||||||
|
@env.ui.info "Default method is " \
|
||||||
|
"'#{two_factor_default_delivery_method}'."
|
||||||
|
end
|
||||||
|
|
||||||
|
other_delivery_methods =
|
||||||
|
two_factor_delivery_methods - [APP]
|
||||||
|
|
||||||
|
if other_delivery_methods.any?
|
||||||
|
other_delivery_methods_sentence = other_delivery_methods
|
||||||
|
.map { |word| "'#{word}'" }
|
||||||
|
.join(' or ')
|
||||||
|
@env.ui.info "You can also type #{other_delivery_methods_sentence} " \
|
||||||
|
"to request a new code."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,28 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module Errors
|
||||||
|
class Error < Vagrant::Errors::VagrantError
|
||||||
|
error_namespace("cloud_command.errors")
|
||||||
|
end
|
||||||
|
|
||||||
|
class ServerError < Error
|
||||||
|
error_key(:server_error)
|
||||||
|
end
|
||||||
|
|
||||||
|
class ServerUnreachable < Error
|
||||||
|
error_key(:server_unreachable)
|
||||||
|
end
|
||||||
|
|
||||||
|
class Unauthorized < Error
|
||||||
|
error_key(:unauthorized)
|
||||||
|
end
|
||||||
|
|
||||||
|
class Unexpected < Error
|
||||||
|
error_key(:unexpected_error)
|
||||||
|
end
|
||||||
|
|
||||||
|
class TwoFactorRequired < Error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,52 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module Command
|
||||||
|
class List < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud list [options] organization"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Search for boxes managed by a specific user/organization"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-j", "--json", "Formats results in JSON") do |j|
|
||||||
|
options[:check] = j
|
||||||
|
end
|
||||||
|
o.on("-l", "--limit", Integer, "Max number of search results (default is 25)") do |l|
|
||||||
|
options[:check] = l
|
||||||
|
end
|
||||||
|
o.on("-p", "--provider", "Comma separated list of providers to filter search. Defaults to all.") do |p|
|
||||||
|
options[:check] = p
|
||||||
|
end
|
||||||
|
o.on("-s", "--sort-by", "Column to sort list (created, downloads, updated)") do |s|
|
||||||
|
options[:check] = s
|
||||||
|
end
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.length > 1
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
# TODO: This endpoint is not implemented yet
|
||||||
|
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,159 @@
|
||||||
|
en:
|
||||||
|
cloud_command:
|
||||||
|
publish:
|
||||||
|
update_continue: |-
|
||||||
|
%{obj} already exists, updating instead...
|
||||||
|
box_create:
|
||||||
|
Creating a box entry...
|
||||||
|
version_create:
|
||||||
|
Creating a version entry...
|
||||||
|
provider_create:
|
||||||
|
Creating a provider entry...
|
||||||
|
upload_provider:
|
||||||
|
Uploading provider with file %{file}
|
||||||
|
release:
|
||||||
|
Releasing box...
|
||||||
|
complete:
|
||||||
|
Complete! Published %{org}/%{box_name}
|
||||||
|
confirm:
|
||||||
|
warn: |-
|
||||||
|
You are about to publish a box on Vagrant Cloud with the following options:
|
||||||
|
box: |-
|
||||||
|
%{org}/%{box_name}: (v%{version}) for provider '%{provider_name}'
|
||||||
|
private: |-
|
||||||
|
Private: true
|
||||||
|
release: |-
|
||||||
|
Automatic Release: true
|
||||||
|
box_url: |-
|
||||||
|
Remote Box file: %{url}
|
||||||
|
box_description: |-
|
||||||
|
Box Description: %{description}
|
||||||
|
box_short_desc: |-
|
||||||
|
Box Short Description: %{short_description}
|
||||||
|
version_desc: |-
|
||||||
|
Version Description: %{version_description}
|
||||||
|
continue: |-
|
||||||
|
Do you wish to continue? [y/N]
|
||||||
|
box:
|
||||||
|
show_filter_empty: |-
|
||||||
|
No version matched %{version} for %{org}/%{box_name}
|
||||||
|
create_success: |-
|
||||||
|
Created box %{org}/%{box_name}
|
||||||
|
delete_success: |-
|
||||||
|
Deleted box %{org}/%{box_name}
|
||||||
|
delete_warn: |-
|
||||||
|
This will completely remove %{box} from Vagrant Cloud. This cannot be undone.
|
||||||
|
update_success: |-
|
||||||
|
Updated box %{org}/%{box_name}
|
||||||
|
search:
|
||||||
|
no_results: |-
|
||||||
|
No results found for `%{query}`
|
||||||
|
upload:
|
||||||
|
no_url: |-
|
||||||
|
No URL was provided to upload the provider
|
||||||
|
You will need to run the `vagrant cloud provider upload` command to provide a box
|
||||||
|
provider:
|
||||||
|
upload: |-
|
||||||
|
Uploading box file for '%{org}/%{box_name}' (v%{version}) for provider: '%{provider}'
|
||||||
|
upload_success: |-
|
||||||
|
Uploaded provider %{provider} on %{org}/%{box_name} for version %{version}
|
||||||
|
delete_warn: |-
|
||||||
|
This will completely remove provider %{provider} on version %{version} from %{box} on Vagrant Cloud. This cannot be undone.
|
||||||
|
create_success: |-
|
||||||
|
Created provider %{provider} on %{org}/%{box_name} for version %{version}
|
||||||
|
delete_success: |-
|
||||||
|
Deleted provider %{provider} on %{org}/%{box_name} for version %{version}
|
||||||
|
update_success: |-
|
||||||
|
Updated provider %{provider} on %{org}/%{box_name} for version %{version}
|
||||||
|
version:
|
||||||
|
create_success: |-
|
||||||
|
Created version %{version} on %{org}/%{box_name} for version %{version}
|
||||||
|
delete_success: |-
|
||||||
|
Deleted version %{version} on %{org}/%{box_name}
|
||||||
|
release_success: |-
|
||||||
|
Released version %{version} on %{org}/%{box_name}
|
||||||
|
revoke_success: |-
|
||||||
|
Revoked version %{version} on %{org}/%{box_name}
|
||||||
|
update_success: |-
|
||||||
|
Updated version %{version} on %{org}/%{box_name}
|
||||||
|
revoke_warn: |-
|
||||||
|
This will revoke version %{version} from %{box} from Vagrant Cloud. This cannot be undone.
|
||||||
|
release_warn: |-
|
||||||
|
This will release version %{version} from %{box} to Vagrant Cloud and be available to download.
|
||||||
|
delete_warn: |-
|
||||||
|
This will completely remove version %{version} from %{box} from Vagrant Cloud. This cannot be undone.
|
||||||
|
errors:
|
||||||
|
search:
|
||||||
|
fail: |-
|
||||||
|
Could not complete search request
|
||||||
|
publish:
|
||||||
|
fail: |-
|
||||||
|
Failed to create box %{org}/%{box_name}
|
||||||
|
box:
|
||||||
|
create_fail: |-
|
||||||
|
Failed to create box %{org}/%{box_name}
|
||||||
|
delete_fail: |-
|
||||||
|
Failed to delete box %{org}/%{box_name}
|
||||||
|
show_fail: |-
|
||||||
|
Could not get information about box %{org}/%{box_name}
|
||||||
|
update_fail: |-
|
||||||
|
Failed to update box %{org}/%{box_name}
|
||||||
|
whoami:
|
||||||
|
read_error: |-
|
||||||
|
Failed to read organization %{org}
|
||||||
|
provider:
|
||||||
|
create_fail: |-
|
||||||
|
Failed to create provider %{provider} on box %{org}/%{box_name} for version %{version}
|
||||||
|
update_fail: |-
|
||||||
|
Failed to update provider %{provider} on box %{org}/%{box_name} for version %{version}
|
||||||
|
delete_fail: |-
|
||||||
|
Failed to delete provider %{provider} on box %{org}/%{box_name} for version %{version}
|
||||||
|
upload_fail: |-
|
||||||
|
Failed to upload provider %{provider} on box %{org}/%{box_name} for version %{version}
|
||||||
|
version:
|
||||||
|
create_fail: |-
|
||||||
|
Failed to create version %{version} on box %{org}/%{box_name}
|
||||||
|
delete_fail: |-
|
||||||
|
Failed to delete version %{version} on box %{org}/%{box_name}
|
||||||
|
release_fail: |-
|
||||||
|
Failed to release version %{version} on box %{org}/%{box_name}
|
||||||
|
revoke_fail: |-
|
||||||
|
Failed to revoke version %{version} on box %{org}/%{box_name}
|
||||||
|
update_fail: |-
|
||||||
|
Failed to update version %{version} on box %{org}/%{box_name}
|
||||||
|
server_error: |-
|
||||||
|
The Vagrant Cloud server responded with a not-OK response:
|
||||||
|
|
||||||
|
%{errors}
|
||||||
|
server_unreachable: |-
|
||||||
|
The Vagrant Cloud server is not currently accepting connections. Please check
|
||||||
|
your network connection and try again later.
|
||||||
|
|
||||||
|
unauthorized: |-
|
||||||
|
Invalid username or password. Please try again.
|
||||||
|
unexpected_error: |-
|
||||||
|
An unexpected error occured: %{error}
|
||||||
|
|
||||||
|
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
|
||||||
|
Vagrant Cloud. 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 Vagrant Cloud account, sign up at
|
||||||
|
https://www.vagrantcloud.com
|
||||||
|
invalid_login: |-
|
||||||
|
Invalid username or password. Please try again.
|
||||||
|
invalid_token: |-
|
||||||
|
Invalid token. Please try again.
|
||||||
|
logged_in: |-
|
||||||
|
You are now logged in.
|
||||||
|
logged_out: |-
|
||||||
|
You are logged out.
|
||||||
|
token_saved: |-
|
||||||
|
The token was successfully saved.
|
|
@ -0,0 +1,30 @@
|
||||||
|
require "vagrant"
|
||||||
|
require 'vagrant_cloud'
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/util")
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/client/client")
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "vagrant-cloud"
|
||||||
|
description <<-DESC
|
||||||
|
Provides the cloud command and internal API access to Vagrant Cloud.
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command(:cloud) do
|
||||||
|
require_relative "root"
|
||||||
|
init!
|
||||||
|
Command::Root
|
||||||
|
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,73 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module ProviderCommand
|
||||||
|
module Command
|
||||||
|
class Create < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud provider create [options] organization/box-name provider-name version [url]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Creates a provider entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 4
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
provider_name = argv[1]
|
||||||
|
version = argv[2]
|
||||||
|
url = argv[3]
|
||||||
|
|
||||||
|
upload_provider(org, box_name, provider_name, version, url, @client.token, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_provider(org, box_name, provider_name, version, url, access_token, options)
|
||||||
|
if !url
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.upload.no_url"))
|
||||||
|
end
|
||||||
|
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
cloud_version = VagrantCloud::Version.new(box, version, nil, nil, access_token)
|
||||||
|
provider = VagrantCloud::Provider.new(cloud_version, provider_name, nil, url, org, box_name, access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = provider.create_provider
|
||||||
|
@env.ui.success(I18n.t("cloud_command.provider.create_success", provider:provider_name, org: org, box_name: box_name, version: version))
|
||||||
|
success = success.delete_if{|_, v|v.nil?}
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.provider.create_fail", provider:provider_name, org: org, box_name: box_name, version: version))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,70 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module ProviderCommand
|
||||||
|
module Command
|
||||||
|
class Delete < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud provider delete [options] organization/box-name provider-name version"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Deletes a provider entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 3
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
provider_name = argv[1]
|
||||||
|
version = argv[2]
|
||||||
|
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.provider.delete_warn", provider: provider_name, version:version, box: argv.first))
|
||||||
|
cont = @env.ui.ask(I18n.t("cloud_command.continue"))
|
||||||
|
return 1 if cont.strip.downcase != "y"
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
delete_provider(org, box_name, provider_name, version, @client.token, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_provider(org, box_name, provider_name, version, access_token, options)
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
cloud_version = VagrantCloud::Version.new(box, version, nil, nil, access_token)
|
||||||
|
provider = VagrantCloud::Provider.new(cloud_version, provider_name, nil, nil, nil, nil, access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = provider.delete
|
||||||
|
@env.ui.error(I18n.t("cloud_command.provider.delete_success", provider: provider_name, org: org, box_name: box_name, version: version))
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.provider.delete_fail", provider: provider_name, org: org, box_name: box_name, version: version))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module ProviderCommand
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "vagrant cloud box"
|
||||||
|
description <<-DESC
|
||||||
|
Provider life cycle commands for Vagrant Cloud
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command(:provider) do
|
||||||
|
require_relative "root"
|
||||||
|
Command::Root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,77 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module ProviderCommand
|
||||||
|
module Command
|
||||||
|
class Root < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"Provider commands"
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(argv, env)
|
||||||
|
super
|
||||||
|
|
||||||
|
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||||
|
@subcommands = Vagrant::Registry.new
|
||||||
|
@subcommands.register(:create) do
|
||||||
|
require File.expand_path("../create", __FILE__)
|
||||||
|
Command::Create
|
||||||
|
end
|
||||||
|
@subcommands.register(:delete) do
|
||||||
|
require File.expand_path("../delete", __FILE__)
|
||||||
|
Command::Delete
|
||||||
|
end
|
||||||
|
@subcommands.register(:update) do
|
||||||
|
require File.expand_path("../update", __FILE__)
|
||||||
|
Command::Update
|
||||||
|
end
|
||||||
|
@subcommands.register(:upload) do
|
||||||
|
require File.expand_path("../upload", __FILE__)
|
||||||
|
Command::Upload
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
if @main_args.include?("-h") || @main_args.include?("--help")
|
||||||
|
# Print the help for all the provider commands.
|
||||||
|
return help
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we reached this far then we must have a subcommand. If not,
|
||||||
|
# then we also just print the help and exit.
|
||||||
|
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||||
|
return help if !command_class || !@sub_command
|
||||||
|
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
||||||
|
|
||||||
|
# Initialize and execute the command class
|
||||||
|
command_class.new(@sub_args, @env).execute
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prints the help out for this command
|
||||||
|
def help
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: vagrant cloud provider <subcommand> [<args>]"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For various provider actions with Vagrant Cloud"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Available subcommands:"
|
||||||
|
|
||||||
|
# Add the available subcommands as separators in order to print them
|
||||||
|
# out as well.
|
||||||
|
keys = []
|
||||||
|
@subcommands.each { |key, value| keys << key.to_s }
|
||||||
|
|
||||||
|
keys.sort.each do |key|
|
||||||
|
opts.separator " #{key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For help on any individual subcommand run `vagrant cloud provider <subcommand> -h`"
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.info(opts.help, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,73 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module ProviderCommand
|
||||||
|
module Command
|
||||||
|
class Update < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud provider update [options] organization/box-name provider-name version url"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Updates a provider entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 4
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
provider_name = argv[1]
|
||||||
|
version = argv[2]
|
||||||
|
url = argv[3]
|
||||||
|
|
||||||
|
update_provider(org, box_name, provider_name, version, url, @client.token, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_provider(org, box_name, provider_name, version, url, access_token, options)
|
||||||
|
if !url
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.upload.no_url"))
|
||||||
|
end
|
||||||
|
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
cloud_version = VagrantCloud::Version.new(box, version, nil, nil, access_token)
|
||||||
|
provider = VagrantCloud::Provider.new(cloud_version, provider_name, nil, url, org, box_name, access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = provider.update
|
||||||
|
@env.ui.success(I18n.t("cloud_command.provider.update_success", provider:provider_name, org: org, box_name: box_name, version: version))
|
||||||
|
success = success.delete_if{|_, v|v.nil?}
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.provider.update_fail", provider:provider_name, org: org, box_name: box_name, version: version))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,75 @@
|
||||||
|
require 'optparse'
|
||||||
|
require "vagrant/util/uploader"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module ProviderCommand
|
||||||
|
module Command
|
||||||
|
class Upload < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud provider upload [options] organization/box-name provider-name version box-file"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Uploads a box file to Vagrant Cloud for a specific provider"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 4
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
provider_name = argv[1]
|
||||||
|
version = argv[2]
|
||||||
|
file = argv[3] # path expand
|
||||||
|
|
||||||
|
upload_provider(org, box_name, provider_name, version, file, @client.token, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_provider(org, box_name, provider_name, version, file, access_token, options)
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
cloud_version = VagrantCloud::Version.new(box, version, nil, nil, access_token)
|
||||||
|
provider = VagrantCloud::Provider.new(cloud_version, provider_name, nil, nil, org, box_name, access_token)
|
||||||
|
|
||||||
|
ul = Vagrant::Util::Uploader.new(provider.upload_url, file, ui: @env.ui)
|
||||||
|
ui = Vagrant::UI::Prefixed.new(@env.ui, "cloud")
|
||||||
|
|
||||||
|
begin
|
||||||
|
ui.output(I18n.t("cloud_command.provider.upload", org: org, box_name: box_name, version: version, provider: provider_name))
|
||||||
|
ui.info("Upload File: #{file}")
|
||||||
|
|
||||||
|
ul.upload!
|
||||||
|
|
||||||
|
ui.success("Successfully uploaded box '#{org}/#{box_name}' (v#{version}) for '#{provider_name}'")
|
||||||
|
return 0
|
||||||
|
rescue Vagrant::Errors::UploaderError, VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.provider.upload_fail", provider: provider_name, org: org, box_name: box_name, version: version))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,165 @@
|
||||||
|
require 'optparse'
|
||||||
|
require "vagrant/util/uploader"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module Command
|
||||||
|
class Publish < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud publish [options] organization/box-name version provider-name [provider-file]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Create and release a new Vagrant Box on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("--box-version VERSION", String, "Version of box to create") do |v|
|
||||||
|
options[:box_version] = v
|
||||||
|
end
|
||||||
|
o.on("--url URL", String, "Remote URL to download this provider") do |u|
|
||||||
|
options[:url] = u
|
||||||
|
end
|
||||||
|
o.on("-d", "--description DESCRIPTION", String, "Full description of box") do |d|
|
||||||
|
options[:description] = d
|
||||||
|
end
|
||||||
|
o.on("--version-description DESCRIPTION", String, "Description of the version to create") do |v|
|
||||||
|
options[:version_description] = v
|
||||||
|
end
|
||||||
|
o.on("-f", "--force", "Disables confirmation to create or update box") do |f|
|
||||||
|
options[:force] = f
|
||||||
|
end
|
||||||
|
o.on("-p", "--private", "Makes box private") do |p|
|
||||||
|
options[:private] = p
|
||||||
|
end
|
||||||
|
o.on("-r", "--release", "Releases box") do |p|
|
||||||
|
options[:release] = p
|
||||||
|
end
|
||||||
|
o.on("-s", "--short-description DESCRIPTION", String, "Short description of the box") do |s|
|
||||||
|
options[:short_description] = s
|
||||||
|
end
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 4 || argv.length < 3
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
version = argv[1]
|
||||||
|
provider_name = argv[2]
|
||||||
|
box_file = argv[3] # path expand
|
||||||
|
publish_box(org, box_name, version, provider_name, box_file, options, @client.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def publish_box(org, box_name, version, provider_name, box_file, options, access_token)
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.publish.confirm.warn"))
|
||||||
|
|
||||||
|
@env.ui.info(I18n.t("cloud_command.publish.confirm.box", org: org,
|
||||||
|
box_name: box_name, version: version, provider_name: provider_name))
|
||||||
|
@env.ui.info(I18n.t("cloud_command.publish.confirm.private")) if options[:private]
|
||||||
|
@env.ui.info(I18n.t("cloud_command.publish.confirm.release")) if options[:release]
|
||||||
|
@env.ui.info(I18n.t("cloud_command.publish.confirm.box_url",
|
||||||
|
url: options[:url])) if options[:url]
|
||||||
|
@env.ui.info(I18n.t("cloud_command.publish.confirm.box_description",
|
||||||
|
description: options[:description])) if options[:description]
|
||||||
|
@env.ui.info(I18n.t("cloud_command.publish.confirm.box_short_desc",
|
||||||
|
short_description: options[:short_description])) if options[:short_description]
|
||||||
|
@env.ui.info(I18n.t("cloud_command.publish.confirm.version_desc",
|
||||||
|
version_description: options[:version_description])) if options[:version_description]
|
||||||
|
|
||||||
|
if !options[:force]
|
||||||
|
cont = @env.ui.ask(I18n.t("cloud_command.continue"))
|
||||||
|
return 1 if cont.strip.downcase != "y"
|
||||||
|
end
|
||||||
|
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, options[:short_description], options[:description], access_token)
|
||||||
|
cloud_version = VagrantCloud::Version.new(box, version, nil, options[:version_description], access_token)
|
||||||
|
provider = VagrantCloud::Provider.new(cloud_version, provider_name, nil, options[:url], org, box_name, access_token)
|
||||||
|
|
||||||
|
ui = Vagrant::UI::Prefixed.new(@env.ui, "cloud")
|
||||||
|
|
||||||
|
begin
|
||||||
|
ui.info(I18n.t("cloud_command.publish.box_create"))
|
||||||
|
box.create
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
if e.error_code == 422
|
||||||
|
ui.warn(I18n.t("cloud_command.publish.update_continue", obj: "Box"))
|
||||||
|
box.update(options)
|
||||||
|
else
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.publish.fail", org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
ui.info(I18n.t("cloud_command.publish.version_create"))
|
||||||
|
cloud_version.create_version
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
if e.error_code == 422
|
||||||
|
ui.warn(I18n.t("cloud_command.publish.update_continue", obj: "Version"))
|
||||||
|
cloud_version.update
|
||||||
|
else
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.publish.fail", org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
ui.info(I18n.t("cloud_command.publish.provider_create"))
|
||||||
|
provider.create_provider
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
if e.error_code == 422
|
||||||
|
ui.warn(I18n.t("cloud_command.publish.update_continue", obj: "Provider"))
|
||||||
|
provider.update
|
||||||
|
else
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.publish.fail", org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
if !options[:url]
|
||||||
|
box_file = File.absolute_path(box_file)
|
||||||
|
ui.info(I18n.t("cloud_command.publish.upload_provider", file: box_file))
|
||||||
|
ul = Vagrant::Util::Uploader.new(provider.upload_url, box_file, ui: @env.ui)
|
||||||
|
ul.upload!
|
||||||
|
end
|
||||||
|
if options[:release]
|
||||||
|
ui.info(I18n.t("cloud_command.publish.release"))
|
||||||
|
cloud_version.release
|
||||||
|
end
|
||||||
|
@env.ui.success(I18n.t("cloud_command.publish.complete", org: org, box_name: box_name))
|
||||||
|
success = box.read(org, box_name)
|
||||||
|
success = success.delete_if{|_, v|v.nil?}
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue Vagrant::Errors::UploaderError, VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.publish.fail", org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,104 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module Command
|
||||||
|
class Root < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"manages everything related to Vagrant Cloud"
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(argv, env)
|
||||||
|
super
|
||||||
|
|
||||||
|
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||||
|
@subcommands = Vagrant::Registry.new
|
||||||
|
@subcommand_helptext = {}
|
||||||
|
|
||||||
|
@subcommands.register(:auth) do
|
||||||
|
require File.expand_path("../auth/root", __FILE__)
|
||||||
|
AuthCommand::Command::Root
|
||||||
|
end
|
||||||
|
@subcommand_helptext[:auth] = "For various authorization operations on Vagrant Cloud"
|
||||||
|
|
||||||
|
@subcommands.register(:box) do
|
||||||
|
require File.expand_path("../box/root", __FILE__)
|
||||||
|
BoxCommand::Command::Root
|
||||||
|
end
|
||||||
|
@subcommand_helptext[:box] = "For managing a Vagrant box entry on Vagrant Cloud"
|
||||||
|
|
||||||
|
# TODO: Uncomment this when API endpoint exists
|
||||||
|
#@subcommands.register(:list) do
|
||||||
|
# require File.expand_path("../list", __FILE__)
|
||||||
|
# List
|
||||||
|
#end
|
||||||
|
#@subcommand_helptext[:list] = "Displays a list of Vagrant boxes that the current user manages"
|
||||||
|
|
||||||
|
@subcommands.register(:search) do
|
||||||
|
require File.expand_path("../search", __FILE__)
|
||||||
|
Search
|
||||||
|
end
|
||||||
|
@subcommand_helptext[:search] = "Search Vagrant Cloud for available boxes"
|
||||||
|
|
||||||
|
@subcommands.register(:provider) do
|
||||||
|
require File.expand_path("../provider/root", __FILE__)
|
||||||
|
ProviderCommand::Command::Root
|
||||||
|
end
|
||||||
|
@subcommand_helptext[:provider] = "For managing a Vagrant box's provider options"
|
||||||
|
|
||||||
|
@subcommands.register(:publish) do
|
||||||
|
require File.expand_path("../publish", __FILE__)
|
||||||
|
Publish
|
||||||
|
end
|
||||||
|
@subcommand_helptext[:publish] = "A complete solution for creating or updating a new box on Vagrant Cloud"
|
||||||
|
|
||||||
|
@subcommands.register(:version) do
|
||||||
|
require File.expand_path("../version/root", __FILE__)
|
||||||
|
VersionCommand::Command::Root
|
||||||
|
end
|
||||||
|
@subcommand_helptext[:version] = "For managing a Vagrant box's versions"
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
if @main_args.include?("-h") || @main_args.include?("--help")
|
||||||
|
# Print the help for all the box commands.
|
||||||
|
return help
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we reached this far then we must have a subcommand. If not,
|
||||||
|
# then we also just print the help and exit.
|
||||||
|
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||||
|
return help if !command_class || !@sub_command
|
||||||
|
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
||||||
|
|
||||||
|
# Initialize and execute the command class
|
||||||
|
command_class.new(@sub_args, @env).execute
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prints the help out for this command
|
||||||
|
def help
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: vagrant cloud <subcommand> [<args>]"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "The cloud command can be used for taking actions against"
|
||||||
|
opts.separator "Vagrant Cloud like searching or uploading a Vagrant Box"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Available subcommands:"
|
||||||
|
|
||||||
|
# Add the available subcommands as separators in order to print them
|
||||||
|
# out as well.
|
||||||
|
keys = []
|
||||||
|
@subcommands.each { |key, value| keys << key.to_s }
|
||||||
|
|
||||||
|
keys.sort.each do |key|
|
||||||
|
opts.separator " #{key.ljust(15)} #{@subcommand_helptext[key.to_sym]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For help on any individual subcommand run `vagrant cloud <subcommand> -h`"
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.info(opts.help, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,83 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module Command
|
||||||
|
class Search < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud search [options] query"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Search for boxes managed by a specific"
|
||||||
|
o.separator "user/organization on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-j", "--json", "Formats results in JSON") do |j|
|
||||||
|
options[:json] = j
|
||||||
|
end
|
||||||
|
o.on("-p", "--page PAGE", Integer, "The page to display Default: 1") do |j|
|
||||||
|
options[:page] = j
|
||||||
|
end
|
||||||
|
o.on("-s", "--short", "Shows a simple list of box names") do |s|
|
||||||
|
options[:short] = s
|
||||||
|
end
|
||||||
|
o.on("-o", "--order ORDER", String, "Order to display results ('desc' or 'asc') Default: 'desc'") do |o|
|
||||||
|
options[:order] = o
|
||||||
|
end
|
||||||
|
o.on("-l", "--limit LIMIT", Integer, "Max number of search results Default: 25") do |l|
|
||||||
|
options[:limit] = l
|
||||||
|
end
|
||||||
|
o.on("-p", "--provider PROVIDER", String, "Filter search results to a single provider. Defaults to all.") do |p|
|
||||||
|
options[:provider] = p
|
||||||
|
end
|
||||||
|
o.on("--sort-by SORT", "Field to sort results on (created, downloads, updated) Default: downloads") do |s|
|
||||||
|
options[:sort] = s
|
||||||
|
end
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.length > 1
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
query = argv.first
|
||||||
|
|
||||||
|
options[:limit] = 25 if !(options[:limit].to_i < 1) && !options[:limit]
|
||||||
|
|
||||||
|
search(query, options, @client.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def search(query, options, access_token)
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
search = VagrantCloud::Search.new(access_token, server_url)
|
||||||
|
|
||||||
|
begin
|
||||||
|
search_results = search.search(query, options[:provider], options[:sort], options[:order], options[:limit], options[:page])
|
||||||
|
if !search_results["boxes"].empty?
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_search_results(search_results["boxes"], options[:short], options[:json], @env)
|
||||||
|
else
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.search.no_results", query: query))
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.search.fail"))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,206 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
class Util
|
||||||
|
class << self
|
||||||
|
# @param [String] username - Vagrant Cloud username
|
||||||
|
# @param [String] access_token - Vagrant Cloud Token used to authenticate
|
||||||
|
# @param [String] vagrant_cloud_server - Vagrant Cloud server to make API request
|
||||||
|
# @return [VagrantCloud::Account]
|
||||||
|
def account(username, access_token, vagrant_cloud_server)
|
||||||
|
if !defined?(@_account)
|
||||||
|
@_account = VagrantCloud::Account.new(username, access_token, vagrant_cloud_server)
|
||||||
|
end
|
||||||
|
@_account
|
||||||
|
end
|
||||||
|
|
||||||
|
def api_server_url
|
||||||
|
if Vagrant.server_url == Vagrant::DEFAULT_SERVER_URL
|
||||||
|
return "#{Vagrant.server_url}/api/v1"
|
||||||
|
else
|
||||||
|
return Vagrant.server_url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [Vagrant::Environment] env
|
||||||
|
# @param [Hash] options
|
||||||
|
# @returns [VagrantPlugins::CloudCommand::Client]
|
||||||
|
def client_login(env, options)
|
||||||
|
if !defined?(@_client)
|
||||||
|
@_client = Client.new(env)
|
||||||
|
return @_client if @_client.logged_in?
|
||||||
|
|
||||||
|
# Let the user know what is going on.
|
||||||
|
env.ui.output(I18n.t("cloud_command.command_header") + "\n")
|
||||||
|
|
||||||
|
# If it is a private cloud installation, show that
|
||||||
|
if Vagrant.server_url != Vagrant::DEFAULT_SERVER_URL
|
||||||
|
env.ui.output("Vagrant Cloud URL: #{Vagrant.server_url}")
|
||||||
|
end
|
||||||
|
|
||||||
|
options = {} if !options
|
||||||
|
# Ask for the username
|
||||||
|
if options[:login]
|
||||||
|
@_client.username_or_email = options[:login]
|
||||||
|
env.ui.output("Vagrant Cloud username or email: #{@_client.username_or_email}")
|
||||||
|
else
|
||||||
|
@_client.username_or_email = env.ui.ask("Vagrant Cloud username or email: ")
|
||||||
|
end
|
||||||
|
|
||||||
|
@_client.password = env.ui.ask("Password (will be hidden): ", echo: false)
|
||||||
|
|
||||||
|
description_default = "Vagrant login from #{Socket.gethostname}"
|
||||||
|
if !options[:description]
|
||||||
|
description = env.ui.ask("Token description (Defaults to #{description_default.inspect}): ")
|
||||||
|
else
|
||||||
|
description = options[:description]
|
||||||
|
env.ui.output("Token description: #{description}")
|
||||||
|
end
|
||||||
|
|
||||||
|
description = description_default if description.empty?
|
||||||
|
|
||||||
|
code = nil
|
||||||
|
|
||||||
|
begin
|
||||||
|
token = @_client.login(description: description, code: code)
|
||||||
|
rescue Errors::TwoFactorRequired
|
||||||
|
until code
|
||||||
|
code = env.ui.ask("2FA code: ")
|
||||||
|
|
||||||
|
if @_client.two_factor_delivery_methods.include?(code.downcase)
|
||||||
|
delivery_method, code = code, nil
|
||||||
|
@_client.request_code delivery_method
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
|
||||||
|
@_client.store_token(token)
|
||||||
|
Vagrant::Util::CredentialScrubber.sensitive(token)
|
||||||
|
env.ui.success(I18n.t("cloud_command.logged_in"))
|
||||||
|
@_client
|
||||||
|
end
|
||||||
|
@_client
|
||||||
|
end
|
||||||
|
|
||||||
|
# ===================================================
|
||||||
|
# Modified from https://stackoverflow.com/a/28685559
|
||||||
|
# for printing arrays of hashes in formatted tables
|
||||||
|
# ===================================================
|
||||||
|
|
||||||
|
# @param [Vagrant::Environment] - env
|
||||||
|
# @param [Hash] - column_labels - A hash of key values for table labels (i.e. {:col1=>"COL1", :col2=>"COL2"})
|
||||||
|
# @param [Array] - results - An array of hashes
|
||||||
|
# @param [Array] - to_jrust_keys - An array of column keys that should be right justified (default is left justified for all columns)
|
||||||
|
def print_search_table(env, column_labels, results, to_rjust_keys)
|
||||||
|
columns = column_labels.each_with_object({}) { |(col,label),h|
|
||||||
|
h[col] = { label: label,
|
||||||
|
width: [results.map { |g| g[col].size }.max, label.size].max
|
||||||
|
}}
|
||||||
|
|
||||||
|
write_header(env, columns)
|
||||||
|
write_divider(env, columns)
|
||||||
|
results.each { |h| write_line(env, columns, h,to_rjust_keys) }
|
||||||
|
write_divider(env, columns)
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_header(env, columns)
|
||||||
|
env.ui.info "| #{ columns.map { |_,g| g[:label].ljust(g[:width]) }.join(' | ') } |"
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_divider(env, columns)
|
||||||
|
env.ui.info "+-#{ columns.map { |_,g| "-"*g[:width] }.join("-+-") }-+"
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_line(env, columns,h,to_rjust_keys)
|
||||||
|
str = h.keys.map { |k|
|
||||||
|
if to_rjust_keys.include?(k)
|
||||||
|
h[k].rjust(columns[k][:width])
|
||||||
|
else
|
||||||
|
h[k].ljust(columns[k][:width])
|
||||||
|
end
|
||||||
|
}.join(" | ")
|
||||||
|
env.ui.info "| #{str} |"
|
||||||
|
end
|
||||||
|
|
||||||
|
# ===================================================
|
||||||
|
# ===================================================
|
||||||
|
|
||||||
|
# Takes a "mostly" flat key=>value hash from Vagrant Cloud
|
||||||
|
# and prints its results in a list
|
||||||
|
#
|
||||||
|
# @param [Hash] - results - A response hash from vagrant cloud
|
||||||
|
# @param [Vagrant::Environment] - env
|
||||||
|
def format_box_results(results, env)
|
||||||
|
# TODO: remove other description fields? Maybe leave "short"?
|
||||||
|
results.delete("description_html")
|
||||||
|
|
||||||
|
if results["current_version"]
|
||||||
|
versions = results.delete("versions")
|
||||||
|
results["providers"] = results["current_version"]["providers"]
|
||||||
|
|
||||||
|
results["old_versions"] = versions.map{ |v| v["version"] }[1..5].join(", ") + "..."
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
width = results.keys.map{|k| k.size}.max
|
||||||
|
results.each do |k,v|
|
||||||
|
if k == "versions"
|
||||||
|
v = v.map{ |ver| ver["version"] }.join(", ")
|
||||||
|
elsif k == "current_version"
|
||||||
|
v = v["version"]
|
||||||
|
elsif k == "providers"
|
||||||
|
v = v.map{ |p| p["name"] }.join(", ")
|
||||||
|
elsif k == "downloads"
|
||||||
|
v = format_downloads(v.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
whitespace = width-k.size
|
||||||
|
env.ui.info "#{k}:" + "".ljust(whitespace) + " #{v}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Converts a string of numbers into a formatted number
|
||||||
|
#
|
||||||
|
# 1234 -> 1,234
|
||||||
|
#
|
||||||
|
# @param [String] - download_string
|
||||||
|
def format_downloads(download_string)
|
||||||
|
return download_string.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# @param [Array] search_results - Box search results from Vagrant Cloud
|
||||||
|
# @param [String,nil] short - determines if short version will be printed
|
||||||
|
# @param [String,nil] json - determines if json version will be printed
|
||||||
|
# @param [Vagrant::Environment] - env
|
||||||
|
def format_search_results(search_results, short, json, env)
|
||||||
|
result = []
|
||||||
|
search_results.each do |b|
|
||||||
|
box = {}
|
||||||
|
box = {
|
||||||
|
name: b["tag"],
|
||||||
|
version: b["current_version"]["version"],
|
||||||
|
downloads: format_downloads(b["downloads"].to_s),
|
||||||
|
providers: b["current_version"]["providers"].map{ |p| p["name"] }.join(",")
|
||||||
|
}
|
||||||
|
result << box
|
||||||
|
end
|
||||||
|
|
||||||
|
if short
|
||||||
|
result.map {|b| env.ui.info(b[:name])}
|
||||||
|
elsif json
|
||||||
|
env.ui.info(result.to_json)
|
||||||
|
else
|
||||||
|
column_labels = {}
|
||||||
|
columns = result.first.keys
|
||||||
|
columns.each do |c|
|
||||||
|
column_labels[c] = c.to_s.upcase
|
||||||
|
end
|
||||||
|
print_search_table(env, column_labels, result, [:downloads])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,69 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module VersionCommand
|
||||||
|
module Command
|
||||||
|
class Create < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud version create [options] organization/box-name version"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Creates a version entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-d", "--description DESCRIPTION", String, "A description for this version") do |d|
|
||||||
|
options[:description] = d
|
||||||
|
end
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
version = argv[1]
|
||||||
|
|
||||||
|
create_version(org, box_name, version, @client.token, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_version(org, box_name, box_version, access_token, options)
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
version = VagrantCloud::Version.new(box, box_version, nil, options[:description], access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = version.create_version
|
||||||
|
@env.ui.success(I18n.t("cloud_command.version.create_success", version: box_version, org: org, box_name: box_name))
|
||||||
|
success = success.delete_if{|_, v|v.nil?}
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.version.create_fail", version: box_version, org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,68 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module VersionCommand
|
||||||
|
module Command
|
||||||
|
class Delete < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud version delete [options] organization/box-name version"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Deletes a version entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
version = argv[1]
|
||||||
|
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.version.delete_warn", version: version, box: argv.first))
|
||||||
|
cont = @env.ui.ask(I18n.t("cloud_command.continue"))
|
||||||
|
return 1 if cont.strip.downcase != "y"
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
|
||||||
|
delete_version(org, box_name, version, options, @client.token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_version(org, box_name, box_version, options, access_token)
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
version = VagrantCloud::Version.new(box, box_version, nil, nil, access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = version.delete
|
||||||
|
@env.ui.success(I18n.t("cloud_command.version.delete_success", version: box_version, org: org, box_name: box_name))
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.version.delete_fail", version: box_version, org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module VersionCommand
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "vagrant cloud version"
|
||||||
|
description <<-DESC
|
||||||
|
Version life cycle commands for Vagrant Cloud
|
||||||
|
DESC
|
||||||
|
|
||||||
|
command(:version) do
|
||||||
|
require_relative "root"
|
||||||
|
Command::Root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,69 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module VersionCommand
|
||||||
|
module Command
|
||||||
|
class Release < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud version release [options] organization/box-name version"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Releases a version entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.version.release_warn", version: argv[1], box: argv.first))
|
||||||
|
cont = @env.ui.ask(I18n.t("cloud_command.continue"))
|
||||||
|
return 1 if cont.strip.downcase != "y"
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
version = argv[1]
|
||||||
|
|
||||||
|
release_version(org, box_name, version, @client.token, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def release_version(org, box_name, version, access_token, options)
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
version = VagrantCloud::Version.new(box, version, nil, nil, access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = version.release
|
||||||
|
@env.ui.success(I18n.t("cloud_command.version.release_success", version: version, org: org, box_name: box_name))
|
||||||
|
success = success.delete_if{|_, v|v.nil?}
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.version.release_fail", version: version, org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,69 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module VersionCommand
|
||||||
|
module Command
|
||||||
|
class Revoke < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud version revoke [options] organization/box-name version"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Revokes a version entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.warn(I18n.t("cloud_command.version.revoke_warn", version: argv[1], box: argv.first))
|
||||||
|
cont = @env.ui.ask(I18n.t("cloud_command.continue"))
|
||||||
|
return 1 if cont.strip.downcase != "y"
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
version = argv[1]
|
||||||
|
|
||||||
|
revoke_version(org, box_name, version, @client.token, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def revoke_version(org, box_name, box_version, access_token, options)
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
version = VagrantCloud::Version.new(box, box_version, nil, nil, access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = version.revoke
|
||||||
|
@env.ui.success(I18n.t("cloud_command.version.revoke_success", version: box_version, org: org, box_name: box_name))
|
||||||
|
success = success.delete_if{|_, v|v.nil?}
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.version.revoke_fail", version: box_version, org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,81 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module VersionCommand
|
||||||
|
module Command
|
||||||
|
class Root < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"Version commands"
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(argv, env)
|
||||||
|
super
|
||||||
|
|
||||||
|
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||||
|
@subcommands = Vagrant::Registry.new
|
||||||
|
@subcommands.register(:create) do
|
||||||
|
require File.expand_path("../create", __FILE__)
|
||||||
|
Command::Create
|
||||||
|
end
|
||||||
|
@subcommands.register(:delete) do
|
||||||
|
require File.expand_path("../delete", __FILE__)
|
||||||
|
Command::Delete
|
||||||
|
end
|
||||||
|
@subcommands.register(:revoke) do
|
||||||
|
require File.expand_path("../revoke", __FILE__)
|
||||||
|
Command::Revoke
|
||||||
|
end
|
||||||
|
@subcommands.register(:release) do
|
||||||
|
require File.expand_path("../release", __FILE__)
|
||||||
|
Command::Release
|
||||||
|
end
|
||||||
|
@subcommands.register(:update) do
|
||||||
|
require File.expand_path("../update", __FILE__)
|
||||||
|
Command::Update
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
if @main_args.include?("-h") || @main_args.include?("--help")
|
||||||
|
# Print the help for all the version commands.
|
||||||
|
return help
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we reached this far then we must have a subcommand. If not,
|
||||||
|
# then we also just print the help and exit.
|
||||||
|
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||||
|
return help if !command_class || !@sub_command
|
||||||
|
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
||||||
|
|
||||||
|
# Initialize and execute the command class
|
||||||
|
command_class.new(@sub_args, @env).execute
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prints the help out for this command
|
||||||
|
def help
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: vagrant cloud version <subcommand> [<args>]"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For taking various actions against a Vagrant box's version attribute on Vagrant Cloud"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Available subcommands:"
|
||||||
|
|
||||||
|
# Add the available subcommands as separators in order to print them
|
||||||
|
# out as well.
|
||||||
|
keys = []
|
||||||
|
@subcommands.each { |key, value| keys << key.to_s }
|
||||||
|
|
||||||
|
keys.sort.each do |key|
|
||||||
|
opts.separator " #{key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For help on any individual subcommand run `vagrant cloud version <subcommand> -h`"
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.info(opts.help, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,69 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CloudCommand
|
||||||
|
module VersionCommand
|
||||||
|
module Command
|
||||||
|
class Update < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant cloud version update [options] organization/box-name version"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Updates a version entry on Vagrant Cloud"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("-d", "--description DESCRIPTION", "A description for this version") do |d|
|
||||||
|
options[:description] = d
|
||||||
|
end
|
||||||
|
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |t|
|
||||||
|
options[:username] = u
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
|
||||||
|
box = argv.first.split('/', 2)
|
||||||
|
org = box[0]
|
||||||
|
box_name = box[1]
|
||||||
|
version = argv[1]
|
||||||
|
|
||||||
|
update_version(org, box_name, version, @client.token, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_version(org, box_name, box_version, access_token, options)
|
||||||
|
org = options[:username] if options[:username]
|
||||||
|
|
||||||
|
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
|
||||||
|
account = VagrantPlugins::CloudCommand::Util.account(org, access_token, server_url)
|
||||||
|
box = VagrantCloud::Box.new(account, box_name, nil, nil, nil, access_token)
|
||||||
|
version = VagrantCloud::Version.new(box, box_version, nil, options[:description], access_token)
|
||||||
|
|
||||||
|
begin
|
||||||
|
success = version.update
|
||||||
|
@env.ui.success(I18n.t("cloud_command.version.update_success", version: box_version, org: org, box_name: box_name))
|
||||||
|
success = success.delete_if{|_, v|v.nil?}
|
||||||
|
VagrantPlugins::CloudCommand::Util.format_box_results(success, @env)
|
||||||
|
return 0
|
||||||
|
rescue VagrantCloud::ClientError => e
|
||||||
|
@env.ui.error(I18n.t("cloud_command.errors.version.update_fail", version: box_version, org: org, box_name: box_name))
|
||||||
|
@env.ui.error(e)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -12,9 +12,10 @@ module VagrantPlugins
|
||||||
DESC
|
DESC
|
||||||
|
|
||||||
command(:login) do
|
command(:login) do
|
||||||
require_relative "command"
|
require File.expand_path("../../cloud/auth/login", __FILE__)
|
||||||
init!
|
init!
|
||||||
Command
|
$stderr.puts "WARNING: This command has been deprecated in favor of `vagrant cloud auth login`"
|
||||||
|
VagrantPlugins::CloudCommand::AuthCommand::Command::Login
|
||||||
end
|
end
|
||||||
|
|
||||||
action_hook(:cloud_authenticated_boxes, :authenticate_box_url) do |hook|
|
action_hook(:cloud_authenticated_boxes, :authenticate_box_url) do |hook|
|
||||||
|
@ -26,7 +27,7 @@ module VagrantPlugins
|
||||||
|
|
||||||
def self.init!
|
def self.init!
|
||||||
return if defined?(@_init)
|
return if defined?(@_init)
|
||||||
I18n.load_path << File.expand_path("../locales/en.yml", __FILE__)
|
I18n.load_path << File.expand_path("../../cloud/locales/en.yml", __FILE__)
|
||||||
I18n.reload!
|
I18n.reload!
|
||||||
@_init = true
|
@_init = true
|
||||||
end
|
end
|
||||||
|
|
|
@ -1509,6 +1509,16 @@ en:
|
||||||
the source location for upload an try again.
|
the source location for upload an try again.
|
||||||
|
|
||||||
Source Path: %{source}
|
Source Path: %{source}
|
||||||
|
uploader_error: |-
|
||||||
|
An error occurred while uploading the file. The error
|
||||||
|
message, if any, is reproduced below. Please fix this error and try
|
||||||
|
again.
|
||||||
|
|
||||||
|
exit code: %{exit_code}
|
||||||
|
%{message}
|
||||||
|
uploader_interrupted: |-
|
||||||
|
The upload was interrupted by an external signal. It did not
|
||||||
|
complete.
|
||||||
vagrantfile_exists: |-
|
vagrantfile_exists: |-
|
||||||
`Vagrantfile` already exists in this directory. Remove it before
|
`Vagrantfile` already exists in this directory. Remove it before
|
||||||
running `vagrant init`.
|
running `vagrant init`.
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/auth/login")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::AuthCommand::Command::Login do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:env) { isolated_environment.create_vagrant_env }
|
||||||
|
|
||||||
|
let(:token_path) { env.data_dir.join("vagrant_login_token") }
|
||||||
|
|
||||||
|
let(:stdout) { StringIO.new }
|
||||||
|
let(:stderr) { StringIO.new }
|
||||||
|
|
||||||
|
subject { described_class.new(argv, env) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_env("ATLAS_TOKEN" => "")
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#execute" do
|
||||||
|
context "with no args" do
|
||||||
|
let(:argv) { [] }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with --check" do
|
||||||
|
let(:argv) { ["--check"] }
|
||||||
|
|
||||||
|
context "when there is a token" do
|
||||||
|
before do
|
||||||
|
stub_request(:get, %r{^#{Vagrant.server_url}/api/v1/authenticate})
|
||||||
|
.to_return(status: 200)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
File.open(token_path, "w+") { |f| f.write("abcd1234") }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 0" do
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when there is no token" do
|
||||||
|
it "returns 1" do
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with --logout" do
|
||||||
|
let(:argv) { ["--logout"] }
|
||||||
|
|
||||||
|
it "returns 0" do
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "clears the token" do
|
||||||
|
subject.execute
|
||||||
|
expect(File.exist?(token_path)).to be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with --token" do
|
||||||
|
let(:argv) { ["--token", "efgh5678"] }
|
||||||
|
|
||||||
|
context "when the token is valid" do
|
||||||
|
before do
|
||||||
|
stub_request(:get, %r{^#{Vagrant.server_url}/api/v1/authenticate})
|
||||||
|
.to_return(status: 200)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets the token" do
|
||||||
|
subject.execute
|
||||||
|
token = File.read(token_path).strip
|
||||||
|
expect(token).to eq("efgh5678")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 0" do
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the token is invalid" do
|
||||||
|
before do
|
||||||
|
stub_request(:get, %r{^#{Vagrant.server_url}/api/v1/authenticate})
|
||||||
|
.to_return(status: 401)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 1" do
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,43 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/auth/logout")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::AuthCommand::Command::Logout do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with any arguments" do
|
||||||
|
let (:argv) { ["stuff", "things"] }
|
||||||
|
|
||||||
|
it "shows the help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "logs you out" do
|
||||||
|
expect(client).to receive(:clear_token)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,54 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/auth/whoami")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::AuthCommand::Command::Whoami do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:account) { double("account") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:account).
|
||||||
|
and_return(account)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with too many arguments" do
|
||||||
|
let(:argv) { ["token", "token", "token"] }
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with username" do
|
||||||
|
let(:argv) { ["token"] }
|
||||||
|
let(:org_hash) { {"user"=>{"username"=>"mario"}, "boxes"=>[{"name"=>"box"}]} }
|
||||||
|
|
||||||
|
it "gets information about a user" do
|
||||||
|
expect(account).to receive(:validate_token).and_return(org_hash)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 1 if encountering an error making request" do
|
||||||
|
allow(account).to receive(:validate_token).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,61 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/box/create")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::BoxCommand::Command::Create do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "-s", "short", "-d", "long"] }
|
||||||
|
|
||||||
|
it "creates a box" do
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, "short", "long", client.token)
|
||||||
|
.and_return(box)
|
||||||
|
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(box).to receive(:create).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, "short", "long", client.token)
|
||||||
|
.and_return(box)
|
||||||
|
|
||||||
|
allow(box).to receive(:create).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 422))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,62 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/box/delete")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::BoxCommand::Command::Delete do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(iso_env.ui).to receive(:ask).
|
||||||
|
and_return("y")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name"] }
|
||||||
|
|
||||||
|
it "creates a box" do
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
|
||||||
|
expect(box).to receive(:delete).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
|
||||||
|
allow(box).to receive(:delete).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,63 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/box/show")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::BoxCommand::Command::Show do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(iso_env.ui).to receive(:ask).
|
||||||
|
and_return("y")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name"] }
|
||||||
|
|
||||||
|
it "creates a box" do
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
|
||||||
|
expect(box).to receive(:read).and_return({})
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
|
||||||
|
allow(box).to receive(:read).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,64 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/box/update")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::BoxCommand::Command::Update do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "-d", "update", "-s", "short"] }
|
||||||
|
|
||||||
|
it "creates a box" do
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
|
||||||
|
expect(box).to receive(:update).
|
||||||
|
with(organization: "vagrant", name: "box-name", description: "update", short_description: "short").
|
||||||
|
and_return({})
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
|
||||||
|
allow(box).to receive(:update).
|
||||||
|
with(organization: "vagrant", name: "box-name", description: "update", short_description: "short").
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,261 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/client/client")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::Client do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:env) { isolated_environment.create_vagrant_env }
|
||||||
|
|
||||||
|
subject(:client) { described_class.new(env) }
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
I18n.load_path << Vagrant.source_root.join("plugins/commands/cloud/locales/en.yml")
|
||||||
|
I18n.reload!
|
||||||
|
end
|
||||||
|
|
||||||
|
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 "raises an error 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::CloudCommand::Errors::ServerUnreachable)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#login" do
|
||||||
|
let(:request) {
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
login: login,
|
||||||
|
password: password,
|
||||||
|
},
|
||||||
|
token: {
|
||||||
|
description: description,
|
||||||
|
},
|
||||||
|
two_factor: {
|
||||||
|
code: nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:login) { "foo" }
|
||||||
|
let(:password) { "supersecretpassword" }
|
||||||
|
let(:description) { "Token description" }
|
||||||
|
|
||||||
|
let(:headers) {
|
||||||
|
{
|
||||||
|
"Accept" => "application/json",
|
||||||
|
"Content-Type" => "application/json",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let(:response) {
|
||||||
|
{
|
||||||
|
token: "mysecrettoken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it "returns the access token after successful login" do
|
||||||
|
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
||||||
|
with(body: JSON.dump(request), headers: headers).
|
||||||
|
to_return(status: 200, body: JSON.dump(response))
|
||||||
|
|
||||||
|
client.username_or_email = login
|
||||||
|
client.password = password
|
||||||
|
|
||||||
|
expect(client.login(description: "Token description")).to eq("mysecrettoken")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when 2fa is required" do
|
||||||
|
let(:response) {
|
||||||
|
{
|
||||||
|
two_factor: {
|
||||||
|
default_delivery_method: default_delivery_method,
|
||||||
|
delivery_methods: delivery_methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let(:default_delivery_method) { "app" }
|
||||||
|
let(:delivery_methods) { ["app"] }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
||||||
|
to_return(status: 406, body: JSON.dump(response))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises a two-factor required error" do
|
||||||
|
expect {
|
||||||
|
client.login
|
||||||
|
}.to raise_error(VagrantPlugins::CloudCommand::Errors::TwoFactorRequired)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the default delivery method is not app" do
|
||||||
|
let(:default_delivery_method) { "sms" }
|
||||||
|
let(:delivery_methods) { ["app", "sms"] }
|
||||||
|
|
||||||
|
it "requests a code and then raises a two-factor required error" do
|
||||||
|
expect(client)
|
||||||
|
.to receive(:request_code)
|
||||||
|
.with(default_delivery_method)
|
||||||
|
|
||||||
|
expect {
|
||||||
|
client.login
|
||||||
|
}.to raise_error(VagrantPlugins::CloudCommand::Errors::TwoFactorRequired)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "on bad login" do
|
||||||
|
before do
|
||||||
|
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
||||||
|
to_return(status: 401, body: "")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an error" do
|
||||||
|
expect {
|
||||||
|
client.login
|
||||||
|
}.to raise_error(VagrantPlugins::CloudCommand::Errors::Unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "if it can't reach the server" do
|
||||||
|
before do
|
||||||
|
stub_request(:post, "#{Vagrant.server_url}/api/v1/authenticate").
|
||||||
|
to_raise(SocketError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an exception" do
|
||||||
|
expect {
|
||||||
|
subject.login
|
||||||
|
}.to raise_error(VagrantPlugins::CloudCommand::Errors::ServerUnreachable)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#request_code" do
|
||||||
|
let(:request) {
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
login: login,
|
||||||
|
password: password,
|
||||||
|
},
|
||||||
|
two_factor: {
|
||||||
|
delivery_method: delivery_method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:login) { "foo" }
|
||||||
|
let(:password) { "supersecretpassword" }
|
||||||
|
let(:delivery_method) { "sms" }
|
||||||
|
|
||||||
|
let(:headers) {
|
||||||
|
{
|
||||||
|
"Accept" => "application/json",
|
||||||
|
"Content-Type" => "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:response) {
|
||||||
|
{
|
||||||
|
two_factor: {
|
||||||
|
obfuscated_destination: "SMS number ending in 1234"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it "displays that the code was sent" do
|
||||||
|
expect(env.ui)
|
||||||
|
.to receive(:success)
|
||||||
|
.with("2FA code sent to SMS number ending in 1234.")
|
||||||
|
|
||||||
|
stub_request(:post, "#{Vagrant.server_url}/api/v1/two-factor/request-code").
|
||||||
|
with(body: JSON.dump(request), headers: headers).
|
||||||
|
to_return(status: 201, body: JSON.dump(response))
|
||||||
|
|
||||||
|
client.username_or_email = login
|
||||||
|
client.password = password
|
||||||
|
|
||||||
|
client.request_code delivery_method
|
||||||
|
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("VAGRANT_CLOUD_TOKEN" => "ABCD1234")
|
||||||
|
subject.store_token("EFGH5678")
|
||||||
|
expect(subject.token).to eq("ABCD1234")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a warning if the envvar and stored file are both present" do
|
||||||
|
stub_env("VAGRANT_CLOUD_TOKEN" => "ABCD1234")
|
||||||
|
subject.store_token("EFGH5678")
|
||||||
|
expect(env.ui).to receive(:warn).with(/detected both/)
|
||||||
|
subject.token
|
||||||
|
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,24 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/list")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::Command::List do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,85 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/provider/create")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::ProviderCommand::Command::Create do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
let(:version) { double("version") }
|
||||||
|
let(:provider) { double("provider") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
allow(VagrantCloud::Version).to receive(:new)
|
||||||
|
.with(box, "1.0.0", nil, nil, client.token)
|
||||||
|
.and_return(version)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0"] }
|
||||||
|
|
||||||
|
it "creates a provider" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, nil, "vagrant", "box-name", client.token).
|
||||||
|
and_return(provider)
|
||||||
|
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(iso_env.ui).to receive(:warn)
|
||||||
|
expect(provider).to receive(:create_provider).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, nil, "vagrant", "box-name", client.token).
|
||||||
|
and_return(provider)
|
||||||
|
|
||||||
|
allow(provider).to receive(:create_provider).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 422))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments and a remote url" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0", "https://box.com/box"] }
|
||||||
|
|
||||||
|
it "creates a provider" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, "https://box.com/box", "vagrant", "box-name", client.token).
|
||||||
|
and_return(provider)
|
||||||
|
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(iso_env.ui).not_to receive(:warn)
|
||||||
|
expect(provider).to receive(:create_provider).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,70 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/provider/delete")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::ProviderCommand::Command::Delete do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
let(:version) { double("version") }
|
||||||
|
let(:provider) { double("provider") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
allow(VagrantCloud::Version).to receive(:new)
|
||||||
|
.with(box, "1.0.0", nil, nil, client.token)
|
||||||
|
.and_return(version)
|
||||||
|
allow(iso_env.ui).to receive(:ask).
|
||||||
|
and_return("y")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0"] }
|
||||||
|
|
||||||
|
it "deletes a provider" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, nil, nil, nil, client.token).
|
||||||
|
and_return(provider)
|
||||||
|
|
||||||
|
expect(provider).to receive(:delete).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, nil, nil, nil, client.token).
|
||||||
|
and_return(provider)
|
||||||
|
|
||||||
|
allow(provider).to receive(:delete).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,85 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/provider/update")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::ProviderCommand::Command::Update do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box", create: true, read: {}) }
|
||||||
|
let(:version) { double("version", create_version: true, release: true) }
|
||||||
|
let(:provider) { double("provider", create_provider: true, upload_file: true) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
allow(VagrantCloud::Version).to receive(:new)
|
||||||
|
.with(box, "1.0.0", nil, nil, client.token)
|
||||||
|
.and_return(version)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0"] }
|
||||||
|
|
||||||
|
it "updates a provider" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, nil, "vagrant", "box-name", client.token).
|
||||||
|
and_return(provider)
|
||||||
|
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(iso_env.ui).to receive(:warn)
|
||||||
|
expect(provider).to receive(:update).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, nil, "vagrant", "box-name", client.token).
|
||||||
|
and_return(provider)
|
||||||
|
|
||||||
|
allow(provider).to receive(:update).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments and a remote url" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0", "https://box.com/box"] }
|
||||||
|
|
||||||
|
it "creates a provider" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, "https://box.com/box", "vagrant", "box-name", client.token).
|
||||||
|
and_return(provider)
|
||||||
|
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(iso_env.ui).not_to receive(:warn)
|
||||||
|
expect(provider).to receive(:update).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,79 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/provider/upload")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::ProviderCommand::Command::Upload do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
let(:version) { double("version") }
|
||||||
|
let(:provider) { double("provider") }
|
||||||
|
let(:uploader) { double("uploader") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
allow(VagrantCloud::Version).to receive(:new)
|
||||||
|
.with(box, "1.0.0", nil, nil, client.token)
|
||||||
|
.and_return(version)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0", "path/to/box.box"] }
|
||||||
|
|
||||||
|
it "uploads a provider" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, nil, "vagrant", "box-name", client.token).
|
||||||
|
and_return(provider)
|
||||||
|
allow(provider).to receive(:upload_url).
|
||||||
|
and_return("http://upload.here/there")
|
||||||
|
allow(Vagrant::Util::Uploader).to receive(:new).
|
||||||
|
with("http://upload.here/there", "path/to/box.box", {ui: anything}).
|
||||||
|
and_return(uploader)
|
||||||
|
|
||||||
|
expect(uploader).to receive(:upload!)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).
|
||||||
|
with(version, "virtualbox", nil, nil, "vagrant", "box-name", client.token).
|
||||||
|
and_return(provider)
|
||||||
|
allow(provider).to receive(:upload_url).
|
||||||
|
and_return("http://upload.here/there")
|
||||||
|
allow(Vagrant::Util::Uploader).to receive(:new).
|
||||||
|
with("http://upload.here/there", "path/to/box.box", {ui: anything}).
|
||||||
|
and_return(uploader)
|
||||||
|
|
||||||
|
allow(uploader).to receive(:upload!).
|
||||||
|
and_raise(Vagrant::Errors::UploaderError.new(exit_code: 1, message: "Error"))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,111 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/publish")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::Command::Publish do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
let(:box_path) { "path/to/the/virtualbox.box" }
|
||||||
|
|
||||||
|
let(:box) { double("box", create: true, read: {}) }
|
||||||
|
let(:version) { double("version", create_version: true, release: true) }
|
||||||
|
let(:provider) { double("provider", create_provider: true, upload_file: true) }
|
||||||
|
let(:uploader) { double("uploader") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(iso_env.ui).to receive(:ask).
|
||||||
|
and_return("y")
|
||||||
|
allow(VagrantCloud::Box).to receive(:new).and_return(box)
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).and_return(version)
|
||||||
|
allow(VagrantCloud::Provider).to receive(:new).and_return(provider)
|
||||||
|
|
||||||
|
allow(File).to receive(:absolute_path).and_return("/full/#{box_path}")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let(:argv) { ["vagrant/box", "1.0.0", "virtualbox", box_path] }
|
||||||
|
|
||||||
|
it "publishes a box given options" do
|
||||||
|
allow(provider).to receive(:upload_url).and_return("http://upload.here/there")
|
||||||
|
allow(Vagrant::Util::Uploader).to receive(:new).
|
||||||
|
with("http://upload.here/there", "/full/path/to/the/virtualbox.box", {ui: anything}).
|
||||||
|
and_return(uploader)
|
||||||
|
allow(uploader).to receive(:upload!)
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "catches a ClientError if something goes wrong" do
|
||||||
|
allow(provider).to receive(:upload_url).and_return("http://upload.here/there")
|
||||||
|
allow(Vagrant::Util::Uploader).to receive(:new).
|
||||||
|
with("http://upload.here/there", "/full/path/to/the/virtualbox.box", {ui: anything}).
|
||||||
|
and_return(uploader)
|
||||||
|
allow(uploader).to receive(:upload!)
|
||||||
|
allow(box).to receive(:create).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "calls update if entity already exists" do
|
||||||
|
allow(provider).to receive(:upload_url).and_return("http://upload.here/there")
|
||||||
|
allow(Vagrant::Util::Uploader).to receive(:new).
|
||||||
|
with("http://upload.here/there", "/full/path/to/the/virtualbox.box", {ui: anything}).
|
||||||
|
and_return(uploader)
|
||||||
|
allow(uploader).to receive(:upload!)
|
||||||
|
allow(box).to receive(:create).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 422))
|
||||||
|
expect(box).to receive(:update)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments and releasing a box" do
|
||||||
|
let(:argv) { ["vagrant/box", "1.0.0", "virtualbox", box_path, "--release"] }
|
||||||
|
|
||||||
|
it "releases the box" do
|
||||||
|
allow(provider).to receive(:upload_url).and_return("http://upload.here/there")
|
||||||
|
allow(Vagrant::Util::Uploader).to receive(:new).
|
||||||
|
with("http://upload.here/there", "/full/path/to/the/virtualbox.box", {ui: anything}).
|
||||||
|
and_return(uploader)
|
||||||
|
allow(uploader).to receive(:upload!)
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(version).to receive(:release)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments and a remote url" do
|
||||||
|
let(:argv) { ["vagrant/box", "1.0.0", "virtualbox", "--url", "https://www.boxes.com/path/to/the/virtualbox.box"] }
|
||||||
|
|
||||||
|
it "does not upload a file" do
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
expect(provider).not_to receive(:upload_file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,77 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/search")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::Command::Search do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_search_results).
|
||||||
|
and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
let (:search) { double("search", search: {"boxes"=>["all of them"]}) }
|
||||||
|
|
||||||
|
it "makes a request to search all boxes and formats them" do
|
||||||
|
allow(VagrantCloud::Search).to receive(:new).
|
||||||
|
and_return(search)
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_search_results)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments and an error occurs making requests" do
|
||||||
|
let (:search) { double("search") }
|
||||||
|
|
||||||
|
it "catches a ClientError if something goes wrong" do
|
||||||
|
allow(VagrantCloud::Search).to receive(:new).
|
||||||
|
and_return(search)
|
||||||
|
allow(search).to receive(:search).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments and no results" do
|
||||||
|
let (:search) { double("search", search: {"boxes"=>[]}) }
|
||||||
|
|
||||||
|
it "makes a request to search all boxes and formats them" do
|
||||||
|
allow(VagrantCloud::Search).to receive(:new).
|
||||||
|
and_return(search)
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).not_to receive(:format_search_results)
|
||||||
|
subject.execute
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:search) { double("search", search: {"boxes"=>["all of them"]}) }
|
||||||
|
let (:argv) { ["ubuntu", "--page", "1", "--order", "desc", "--limit", "100", "--provider", "provider", "--sort", "downloads"] }
|
||||||
|
|
||||||
|
it "sends the options to make a request with" do
|
||||||
|
allow(VagrantCloud::Search).to receive(:new).
|
||||||
|
and_return(search)
|
||||||
|
expect(search).to receive(:search).
|
||||||
|
with("ubuntu", "provider", "downloads", "desc", 100, 1)
|
||||||
|
subject.execute
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,65 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/version/create")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::VersionCommand::Command::Create do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
let(:version) { double("version") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "1.0.0", "-d", "description"] }
|
||||||
|
|
||||||
|
it "creates a version" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, "description", client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(version).to receive(:create_version).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, "description", client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
allow(version).to receive(:create_version).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 422))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,66 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/version/delete")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::VersionCommand::Command::Delete do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
let(:version) { double("version") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
allow(iso_env.ui).to receive(:ask).
|
||||||
|
and_return("y")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "1.0.0"] }
|
||||||
|
|
||||||
|
it "deletes a version" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, nil, client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
expect(version).to receive(:delete).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, nil, client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
allow(version).to receive(:delete).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,66 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/version/release")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::VersionCommand::Command::Release do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
let(:version) { double("version") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
allow(iso_env.ui).to receive(:ask).
|
||||||
|
and_return("y")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "1.0.0"] }
|
||||||
|
|
||||||
|
it "releases a version" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, nil, client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
expect(version).to receive(:release).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, nil, client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
allow(version).to receive(:release).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,66 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/version/revoke")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::VersionCommand::Command::Revoke do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
let(:version) { double("version") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
allow(iso_env.ui).to receive(:ask).
|
||||||
|
and_return("y")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "1.0.0"] }
|
||||||
|
|
||||||
|
it "revokes a version" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, nil, client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
expect(version).to receive(:revoke).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, nil, client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
expect(version).to receive(:revoke).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,65 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/cloud/version/update")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CloudCommand::VersionCommand::Command::Update do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
let(:action_runner) { double("action_runner") }
|
||||||
|
|
||||||
|
let(:client) { double("client", token: "1234token1234") }
|
||||||
|
let(:box) { double("box") }
|
||||||
|
let(:version) { double("version") }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(iso_env).to receive(:action_runner).and_return(action_runner)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:client_login).
|
||||||
|
and_return(client)
|
||||||
|
allow(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results).
|
||||||
|
and_return(true)
|
||||||
|
allow(VagrantCloud::Box).to receive(:new)
|
||||||
|
.with(anything, "box-name", nil, nil, nil, client.token)
|
||||||
|
.and_return(box)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no arguments" do
|
||||||
|
it "shows help" do
|
||||||
|
expect { subject.execute }.
|
||||||
|
to raise_error(Vagrant::Errors::CLIInvalidUsage)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with arguments" do
|
||||||
|
let (:argv) { ["vagrant/box-name", "1.0.0", "-d", "description"] }
|
||||||
|
|
||||||
|
it "updates a version" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, "description", client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
|
||||||
|
expect(version).to receive(:update).and_return({})
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "displays an error if encoutering a problem with the request" do
|
||||||
|
allow(VagrantCloud::Version).to receive(:new).
|
||||||
|
with(box, "1.0.0", nil, "description", client.token).
|
||||||
|
and_return(version)
|
||||||
|
|
||||||
|
allow(version).to receive(:update).
|
||||||
|
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
|
||||||
|
expect(subject.execute).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
require File.expand_path("../../../base", __FILE__)
|
||||||
|
|
||||||
|
require "vagrant/util/curl_helper"
|
||||||
|
|
||||||
|
describe Vagrant::Util::CurlHelper do
|
||||||
|
end
|
|
@ -0,0 +1,50 @@
|
||||||
|
require File.expand_path("../../../base", __FILE__)
|
||||||
|
|
||||||
|
require "vagrant/util/uploader"
|
||||||
|
|
||||||
|
describe Vagrant::Util::Uploader do
|
||||||
|
let(:destination) { "fake" }
|
||||||
|
let(:file) { "my/file.box" }
|
||||||
|
let(:curl_options) { [destination, "--request", "PUT", "--upload-file", file, {notify: :stderr}] }
|
||||||
|
|
||||||
|
let(:subprocess_result) do
|
||||||
|
double("subprocess_result").tap do |result|
|
||||||
|
allow(result).to receive(:exit_code).and_return(exit_code)
|
||||||
|
allow(result).to receive(:stderr).and_return("")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { described_class.new(destination, file, options) }
|
||||||
|
|
||||||
|
before :each do
|
||||||
|
allow(Vagrant::Util::Subprocess).to receive(:execute).and_return(subprocess_result)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#upload!" do
|
||||||
|
context "with a good exit status" do
|
||||||
|
let(:options) { {} }
|
||||||
|
let(:exit_code) { 0 }
|
||||||
|
|
||||||
|
it "uploads the file and returns true" do
|
||||||
|
expect(Vagrant::Util::Subprocess).to receive(:execute).
|
||||||
|
with("curl", *curl_options).
|
||||||
|
and_return(subprocess_result)
|
||||||
|
|
||||||
|
expect(subject.upload!).to be
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a bad exit status" do
|
||||||
|
let(:options) { {} }
|
||||||
|
let(:exit_code) { 1 }
|
||||||
|
it "raises an exception" do
|
||||||
|
expect(Vagrant::Util::Subprocess).to receive(:execute).
|
||||||
|
with("curl", *curl_options).
|
||||||
|
and_return(subprocess_result)
|
||||||
|
|
||||||
|
expect { subject.upload! }.
|
||||||
|
to raise_error(Vagrant::Errors::UploaderError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
||||||
s.add_dependency "winrm", "~> 2.1"
|
s.add_dependency "winrm", "~> 2.1"
|
||||||
s.add_dependency "winrm-fs", "~> 1.0"
|
s.add_dependency "winrm-fs", "~> 1.0"
|
||||||
s.add_dependency "winrm-elevated", "~> 1.1"
|
s.add_dependency "winrm-elevated", "~> 1.1"
|
||||||
|
s.add_dependency "vagrant_cloud", "~> 2.0.0"
|
||||||
|
|
||||||
# NOTE: The ruby_dep gem is an implicit dependency from the listen gem. Later versions
|
# NOTE: The ruby_dep gem is an implicit dependency from the listen gem. Later versions
|
||||||
# of the ruby_dep gem impose an aggressive constraint on the required ruby version (>= 2.2.5).
|
# of the ruby_dep gem impose an aggressive constraint on the required ruby version (>= 2.2.5).
|
||||||
|
|
|
@ -0,0 +1,339 @@
|
||||||
|
---
|
||||||
|
layout: "docs"
|
||||||
|
page_title: "vagrant cloud - Command-Line Interface"
|
||||||
|
sidebar_current: "cli-cloud"
|
||||||
|
description: |-
|
||||||
|
The "vagrant cloud" command can be used for taking actions against
|
||||||
|
Vagrant Cloud like searching or uploading a Vagrant Box
|
||||||
|
---
|
||||||
|
|
||||||
|
# Cloud
|
||||||
|
|
||||||
|
**Command: `vagrant cloud`**
|
||||||
|
|
||||||
|
This is the command used to manage anything related to [Vagrant Cloud](https://vagrantcloud.com).
|
||||||
|
|
||||||
|
The main functionality of this command is exposed via subcommands:
|
||||||
|
|
||||||
|
* [`auth`](#cloud-auth)
|
||||||
|
* [`box`](#cloud-box)
|
||||||
|
* [`provider`](#cloud-provider)
|
||||||
|
* [`publish`](#cloud-publish)
|
||||||
|
* [`search`](#cloud-search)
|
||||||
|
* [`version`](#cloud-version)
|
||||||
|
|
||||||
|
# Cloud Auth
|
||||||
|
|
||||||
|
**Command: `vagrant cloud auth`**
|
||||||
|
|
||||||
|
The `cloud auth` command is for handling all things related to authorization with
|
||||||
|
Vagrant Cloud.
|
||||||
|
|
||||||
|
* [`login`](#cloud-auth-login)
|
||||||
|
* [`logout`](#cloud-auth-logout)
|
||||||
|
* [`whoami`](#cloud-auth-whoami)
|
||||||
|
|
||||||
|
## Cloud Auth Login
|
||||||
|
|
||||||
|
**Command: `vagrant cloud auth login`**
|
||||||
|
|
||||||
|
The login command is used to authenticate with [HashiCorp's Vagrant Cloud](/docs/vagrant-cloud)
|
||||||
|
server. Logging in is only necessary if you are accessing protected boxes.
|
||||||
|
|
||||||
|
**Logging in is not a requirement to use Vagrant.** The vast majority
|
||||||
|
of Vagrant does _not_ require a login. Only certain features such as protected
|
||||||
|
boxes.
|
||||||
|
|
||||||
|
The reference of available command-line flags to this command
|
||||||
|
is available below.
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
* `--check` - This will check if you are logged in. In addition to outputting
|
||||||
|
whether you are logged in or not, the command exit status will be 0 if you are
|
||||||
|
logged in, or 1 if you are not.
|
||||||
|
|
||||||
|
* `--logout` - This will log you out if you are logged in. If you are already
|
||||||
|
logged out, this command will do nothing. It is not an error to call this
|
||||||
|
command if you are already logged out.
|
||||||
|
|
||||||
|
* `--token` - This will set the Vagrant Cloud login token manually to the provided
|
||||||
|
string. It is assumed this token is a valid Vagrant Cloud access token.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
Securely authenticate to Vagrant Cloud using a username and password:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ vagrant cloud auth login
|
||||||
|
# ...
|
||||||
|
Vagrant Cloud username:
|
||||||
|
Vagrant Cloud password:
|
||||||
|
```
|
||||||
|
|
||||||
|
Check if the current user is authenticated:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ vagrant cloud auth login --check
|
||||||
|
You are already logged in.
|
||||||
|
```
|
||||||
|
|
||||||
|
Securely authenticate with Vagrant Cloud using a token:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ vagrant cloud auth login --token ABCD1234
|
||||||
|
The token was successfully saved.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cloud Auth Logout
|
||||||
|
|
||||||
|
**Command: `vagrant cloud auth logout`**
|
||||||
|
|
||||||
|
This will log you out if you are logged in. If you are already
|
||||||
|
logged out, this command will do nothing. It is not an error to call this
|
||||||
|
command if you are already logged out.
|
||||||
|
|
||||||
|
## Cloud Auth Whomi
|
||||||
|
|
||||||
|
**Command: `vagrant cloud auth whoami [TOKEN]`**
|
||||||
|
|
||||||
|
This command will validate your Vagrant Cloud token and will print the user who
|
||||||
|
it belongs to. If a token is passed in, it will attempt to validate it instead
|
||||||
|
of the token stored stored on disk.
|
||||||
|
|
||||||
|
# Cloud Box
|
||||||
|
|
||||||
|
**Command: `vagrant cloud box`**
|
||||||
|
|
||||||
|
The `cloud box` command is used to manage life cycle operations for all `box`
|
||||||
|
entities on Vagrant Cloud.
|
||||||
|
|
||||||
|
* [`create`](#cloud-box-create)
|
||||||
|
* [`delete`](#cloud-box-delete)
|
||||||
|
* [`show`](#cloud-box-show)
|
||||||
|
* [`update`](#cloud-box-update)
|
||||||
|
|
||||||
|
## Cloud Box Create
|
||||||
|
|
||||||
|
**Command: `vagrant cloud box create ORGANIZATION/BOX-NAME`**
|
||||||
|
|
||||||
|
The box create command is used to create a new box entry on Vagrant Cloud.
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
* `--description DESCRIPTION` - A full description of the box. Can be
|
||||||
|
formatted with Markdown.
|
||||||
|
* `--short-description DESCRIPTION` - A short summary of the box.
|
||||||
|
* `--private` - Will make the new box private (Public by default)
|
||||||
|
|
||||||
|
## Cloud Box Delete
|
||||||
|
|
||||||
|
**Command: `vagrant cloud box delete ORGANIZATION/BOX-NAME`**
|
||||||
|
|
||||||
|
The box delete command will _permanently_ delete the given box entry on Vagrant Cloud. Before
|
||||||
|
making the request, it will ask if you are sure you want to delete the box.
|
||||||
|
|
||||||
|
## Cloud Box Show
|
||||||
|
|
||||||
|
**Command: `vagrant cloud box show ORGANIZATION/BOX-NAME`**
|
||||||
|
|
||||||
|
The box show command will display information about the latest version for the given Vagrant box.
|
||||||
|
|
||||||
|
## Cloud Box Update
|
||||||
|
|
||||||
|
**Command: `vagrant cloud box update ORGANIZATION/BOX-NAME`**
|
||||||
|
|
||||||
|
The box update command will update an already created box on Vagrant Cloud with the given options.
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
* `--description DESCRIPTION` - A full description of the box. Can be
|
||||||
|
formatted with Markdown.
|
||||||
|
* `--short-description DESCRIPTION` - A short summary of the box.
|
||||||
|
* `--private` - Will make the new box private (Public by default)
|
||||||
|
|
||||||
|
# Cloud Provider
|
||||||
|
|
||||||
|
**Command: `vagrant cloud provider`**
|
||||||
|
|
||||||
|
The `cloud provider` command is used to manage the life cycle operations for all
|
||||||
|
`provider` entities on Vagrant Cloud.
|
||||||
|
|
||||||
|
* [`create`](#cloud-provider-create)
|
||||||
|
* [`delete`](#cloud-provider-delete)
|
||||||
|
* [`update`](#cloud-provider-update)
|
||||||
|
* [`upload`](#cloud-provider-upload)
|
||||||
|
|
||||||
|
## Cloud Provider Create
|
||||||
|
|
||||||
|
**Command: `vagrant cloud provider create ORGANIZATION/BOX-NAME PROVIDER-NAME VERSION [URL]`**
|
||||||
|
|
||||||
|
|
||||||
|
The provider create command is used to create a new provider entry on Vagrant Cloud.
|
||||||
|
The `url` argument is expected to be a remote URL that Vagrant Cloud can use
|
||||||
|
to download the provider. If no `url` is specified, the provider entry can be updated
|
||||||
|
later with a url or the [upload](#cloud-provider-upload) command can be used to
|
||||||
|
upload a Vagrant [box file](/docs/boxes.html).
|
||||||
|
|
||||||
|
## Cloud Provider Delete
|
||||||
|
|
||||||
|
**Command: `vagrant cloud provider delete ORGANIZATION/BOX-NAME PROVIDER-NAME VERSION`**
|
||||||
|
|
||||||
|
The provider delete command is used to delete a provider entry on Vagrant Cloud.
|
||||||
|
Before making the request, it will ask if you are sure you want to delete the provider.
|
||||||
|
|
||||||
|
## Cloud Provider Update
|
||||||
|
|
||||||
|
**Command: `vagrant cloud provider update ORGANIZATION/BOX-NAME PROVIDER-NAME VERSION [URL]`**
|
||||||
|
|
||||||
|
The provider update command will update an already created provider for a box on
|
||||||
|
Vagrant Cloud with the given options.
|
||||||
|
|
||||||
|
## Cloud Provider Upload
|
||||||
|
|
||||||
|
**Command: `vagrant cloud provider upload ORGANIZATION/BOX-NAME PROVIDER-NAME VERSION BOX-FILE`**
|
||||||
|
|
||||||
|
The provider upload command will upload a Vagrant [box file](/docs/boxes.html) to Vagrant Cloud for
|
||||||
|
the specified version and provider.
|
||||||
|
|
||||||
|
# Cloud Publish
|
||||||
|
|
||||||
|
**Command: `vagrant cloud publish ORGANIZATION/BOX-NAME VERSION PROVIDER-NAME [PROVIDER-FILE]`**
|
||||||
|
|
||||||
|
The publish command is a complete solution for creating and updating a
|
||||||
|
Vagrant box on Vagrant Cloud. Instead of having to create each attribute of a Vagrant
|
||||||
|
box with separate commands, the publish command instead asks you to provide all
|
||||||
|
the information required before creating or updating a new box.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
* `--box-version VERSION` - Version to create for the box
|
||||||
|
* `--description DESCRIPTION` - A full description of the box. Can be
|
||||||
|
formatted with Markdown.
|
||||||
|
* `--force` - Disables confirmation when creating or updating a box.
|
||||||
|
* `--short-description DESCRIPTION` - A short summary of the box.
|
||||||
|
* `--private` - Will make the new box private (Public by default)
|
||||||
|
* `--release` - Automatically releases the box after creation (Unreleased by default)
|
||||||
|
* `--url` - Valid remote URL to download the box file
|
||||||
|
* `--version-description DESCRIPTION` - Description of the version that will be created.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Creating a new box on Vagrant Cloud:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ vagrant cloud publish briancain/supertest 1.0.0 virtualbox boxes/my/virtualbox.box -d "A really cool box to download and use" --version-description "A cool version" --release --short-description "Donwload me!"
|
||||||
|
You are about to create a box on Vagrant Cloud with the following options:
|
||||||
|
briancain/supertest (1.0.0) for virtualbox
|
||||||
|
Automatic Release: true
|
||||||
|
Box Description: A really cool box to download and use
|
||||||
|
Box Short Description: Download me!
|
||||||
|
Version Description: A cool version
|
||||||
|
Do you wish to continue? [y/N] y
|
||||||
|
Creating a box entry...
|
||||||
|
Creating a version entry...
|
||||||
|
Creating a provider entry...
|
||||||
|
Uploading provider with file /Users/vagrant/boxes/my/virtualbox.box
|
||||||
|
Releasing box...
|
||||||
|
Complete! Published briancain/supertest
|
||||||
|
tag: briancain/supertest
|
||||||
|
username: briancain
|
||||||
|
name: supertest
|
||||||
|
private: false
|
||||||
|
downloads: 0
|
||||||
|
created_at: 2018-07-25T17:53:04.340Z
|
||||||
|
updated_at: 2018-07-25T18:01:10.665Z
|
||||||
|
short_description: Download me!
|
||||||
|
description_markdown: A reall cool box to download and use
|
||||||
|
current_version: 1.0.0
|
||||||
|
providers: virtualbox
|
||||||
|
```
|
||||||
|
|
||||||
|
# Cloud Search
|
||||||
|
|
||||||
|
**Command: `vagrant cloud search QUERY`**
|
||||||
|
|
||||||
|
The cloud search command will take a query and search Vagrant Cloud for any matching
|
||||||
|
Vagrant boxes. Various filters can be applied to the results.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
* `--json` - Format search results in JSON.
|
||||||
|
* `--page PAGE` - The page to display. Defaults to the first page of results.
|
||||||
|
* `--short` - Shows a simple list of box names for the results.
|
||||||
|
* `--order ORDER` - Order to display results. Can either be `desc` or `asc`.
|
||||||
|
Defaults to `desc`.
|
||||||
|
* `--limit LIMIT` - Max number of search results to display. Defaults to 25.
|
||||||
|
* `--provider PROVIDER` - Filter search results to a single provider.
|
||||||
|
* `--sort-by SORT` - The field to sort results on. Can be `created`, `downloads`
|
||||||
|
, or `updated`. Defaults to `downloads`.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
If you are looking for a HashiCorp box:
|
||||||
|
|
||||||
|
```text
|
||||||
|
vagrant cloud search hashicorp --limit 5
|
||||||
|
| NAME | VERSION | DOWNLOADS | PROVIDERS |
|
||||||
|
+-------------------------+---------+-----------+---------------------------------+
|
||||||
|
| hashicorp/precise64 | 1.1.0 | 6,675,725 | virtualbox,vmware_fusion,hyperv |
|
||||||
|
| hashicorp/precise32 | 1.0.0 | 2,261,377 | virtualbox |
|
||||||
|
| hashicorp/boot2docker | 1.7.8 | 59,284 | vmware_desktop,virtualbox |
|
||||||
|
| hashicorp/connect-vm | 0.1.0 | 6,912 | vmware_desktop,virtualbox |
|
||||||
|
| hashicorp/vagrant-share | 0.1.0 | 3,488 | vmware_desktop,virtualbox |
|
||||||
|
+-------------------------+---------+-----------+---------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
# Cloud Version
|
||||||
|
|
||||||
|
**Command: `vagrant cloud version`**
|
||||||
|
|
||||||
|
The `cloud version` command is used to manage life cycle operations for all `version`
|
||||||
|
entities for a box on Vagrant Cloud.
|
||||||
|
|
||||||
|
* [`create`](#cloud-version-create)
|
||||||
|
* [`delete`](#cloud-version-delete)
|
||||||
|
* [`release`](#cloud-version-release)
|
||||||
|
* [`revoke`](#cloud-version-revoke)
|
||||||
|
* [`update`](#cloud-version-update)
|
||||||
|
|
||||||
|
## Cloud Version Create
|
||||||
|
|
||||||
|
**Command: `vagrant cloud version create ORGANIZATION/BOX-NAME VERSION`**
|
||||||
|
|
||||||
|
The cloud create command creates a version entry for a box on Vagrant Cloud.
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
* `--description DESCRIPTION` - Description of the version that will be created.
|
||||||
|
|
||||||
|
## Cloud Version Delete
|
||||||
|
|
||||||
|
**Command: `vagrant cloud version delete ORGANIZATION/BOX-NAME VERSION`**
|
||||||
|
|
||||||
|
The cloud delete command deletes a version entry for a box on Vagrant Cloud.
|
||||||
|
Before making the request, it will ask if you are sure you want to delete the version.
|
||||||
|
|
||||||
|
## Cloud Version Release
|
||||||
|
|
||||||
|
**Command: `vagrant cloud version release ORGANIZATION/BOX-NAME VERSION`**
|
||||||
|
|
||||||
|
The cloud release command releases a version entry for a box on Vagrant Cloud
|
||||||
|
if it already exists. Before making the request, it will ask if you are sure you
|
||||||
|
want to release the version.
|
||||||
|
|
||||||
|
## Cloud Version Revoke
|
||||||
|
|
||||||
|
**Command: `vagrant cloud version revoke ORGANIZATION/BOX-NAME VERSION`**
|
||||||
|
|
||||||
|
The cloud revoke command revokes a version entry for a box on Vagrant Cloud
|
||||||
|
if it already exists. Before making the request, it will ask if you are sure you
|
||||||
|
want to revoke the version.
|
||||||
|
|
||||||
|
## Cloud Version Update
|
||||||
|
|
||||||
|
**Command: `vagrant cloud version update ORGANIZATION/BOX-NAME VERSION`**
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
* `--description DESCRIPTION` - Description of the version that will be created.
|
|
@ -20,6 +20,7 @@
|
||||||
<a href="/docs/cli/">Commands (CLI)</a>
|
<a href="/docs/cli/">Commands (CLI)</a>
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
<li<%= sidebar_current("cli-box") %>><a href="/docs/cli/box.html">box</a></li>
|
<li<%= sidebar_current("cli-box") %>><a href="/docs/cli/box.html">box</a></li>
|
||||||
|
<li<%= sidebar_current("cli-cloud") %>><a href="/docs/cli/cloud.html">cloud</a></li>
|
||||||
<li<%= sidebar_current("cli-connect") %>><a href="/docs/cli/connect.html">connect</a></li>
|
<li<%= sidebar_current("cli-connect") %>><a href="/docs/cli/connect.html">connect</a></li>
|
||||||
<li<%= sidebar_current("cli-destroy") %>><a href="/docs/cli/destroy.html">destroy</a></li>
|
<li<%= sidebar_current("cli-destroy") %>><a href="/docs/cli/destroy.html">destroy</a></li>
|
||||||
<li<%= sidebar_current("cli-globalstatus") %>><a href="/docs/cli/global-status.html">global-status</a></li>
|
<li<%= sidebar_current("cli-globalstatus") %>><a href="/docs/cli/global-status.html">global-status</a></li>
|
||||||
|
|
Loading…
Reference in New Issue