Merge pull request #11916 from chrisroberts/e-vagrant-cloud-lib

Update cloud command to use refactored library implementation
This commit is contained in:
Chris Roberts 2020-10-30 09:57:49 -07:00 committed by GitHub
commit 57ddab2672
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 3506 additions and 2762 deletions

View File

@ -13,9 +13,11 @@ module Vagrant
# 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
# @param [String] destination Valid URL to upload file to
# @param [String] file Location of file to upload on disk
# @param [Hash] options
# @option options [Vagrant::UI] :ui UI interface for output
# @option options [String, Symbol] :method Request method for upload
def initialize(destination, file, options=nil)
options ||= {}
@logger = Log4r::Logger.new("vagrant::util::uploader")
@ -27,6 +29,7 @@ module Vagrant
if !@request_method
@request_method = "PUT"
end
@request_method = @request_method.to_s.upcase
end
def upload!
@ -51,7 +54,7 @@ module Vagrant
protected
def build_options
options = [@destination, "--request", @request_method, "--upload-file", @file]
options = [@destination, "--request", @request_method, "--upload-file", @file, "--fail"]
return options
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module AuthCommand
module Command
class Login < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -16,15 +18,10 @@ module VagrantPlugins
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
@ -37,26 +34,32 @@ module VagrantPlugins
# Parse the options
argv = parse_options(opts)
return if !argv
if !argv.empty?
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
@client = Client.new(@env)
@client.username_or_email = options[:login]
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
return execute_check(client)
elsif options[:token]
return execute_token(options[:token])
return execute_token(client, options[:token])
else
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options)
if client.logged_in?
@env.ui.success(I18n.t("cloud_command.check_logged_in"))
else
client_login(@env, options.slice(:login, :description))
end
end
0
end
def execute_check
if @client.logged_in?
def execute_check(client)
if client.logged_in?
@env.ui.success(I18n.t("cloud_command.check_logged_in"))
return 0
else
@ -65,17 +68,11 @@ module VagrantPlugins
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)
def execute_token(client, token)
client.store_token(token)
@env.ui.success(I18n.t("cloud_command.token_saved"))
if @client.logged_in?
if client.logged_in?
@env.ui.success(I18n.t("cloud_command.check_logged_in"))
return 0
else

View File

@ -9,15 +9,9 @@ module VagrantPlugins
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant cloud auth logout [options]"
o.banner = "Usage: vagrant cloud auth logout"
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
@ -28,9 +22,7 @@ module VagrantPlugins
help: opts.help.chomp
end
# Initializes client and deletes token on disk
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = Client.new(@env)
@client.clear_token
@env.ui.success(I18n.t("cloud_command.logged_out"))
return 0

View File

@ -5,19 +5,15 @@ module VagrantPlugins
module AuthCommand
module Command
class Whoami < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant cloud auth whoami [options] [token]"
o.banner = "Usage: vagrant cloud auth whoami [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
@ -28,28 +24,30 @@ module VagrantPlugins
help: opts.help.chomp
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:login])
if argv.first
token = argv.first
else
token = @client.token
client = Client.new(@env)
token = client.token
end
whoami(token, options[:username])
whoami(token)
end
def whoami(access_token, username)
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
account = VagrantPlugins::CloudCommand::Util.account(username, access_token, server_url)
def whoami(access_token)
if access_token.to_s.empty?
@env.ui.error(I18n.t("cloud_command.check_not_logged_in"))
return 1
end
begin
success = account.validate_token
user = success["user"]["username"]
@env.ui.success("Currently logged in as #{user}")
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
@env.ui.success("Currently logged in as #{account.username}")
return 0
rescue VagrantCloud::ClientError => e
@env.ui.error(I18n.t("cloud_command.errors.whoami.read_error", org: username))
rescue VagrantCloud::Error::ClientError => e
@env.ui.error(I18n.t("cloud_command.errors.whoami.read_error"))
@env.ui.error(e)
return 1
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module BoxCommand
module Command
class Create < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -19,13 +21,10 @@ module VagrantPlugins
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 |u|
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|
o.on("-p", "--[no-]private", "Makes box private") do |p|
options[:private] = p
end
end
@ -38,35 +37,40 @@ module VagrantPlugins
help: opts.help.chomp
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = client_login(@env)
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
create_box(org, box_name, options, @client.token)
org, box_name = argv.first.split('/', 2)
create_box(org, box_name, @client.token, options.slice(:description, :short, :private))
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)
# Create a new box
#
# @param [String] org Organization name of box
# @param [String] box_name Name of box
# @param [String] access_token User access token
# @param [Hash] options Options for box filtering
# @option options [String] :short Short description of box
# @option options [String] :description Full description of box
# @option options [Boolean] :private Set box visibility as private
# @return [Integer]
def create_box(org, box_name, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
box = account.organization(name: org).add_box(box_name)
box.short_description = options[:short] if options.key?(:short)
box.description = options[:description] if options.key?(:description)
box.private = options[:private] if options.key?(:private)
box.save
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
@env.ui.success(I18n.t("cloud_command.box.create_success", org: org, box_name: box_name))
format_box_results(box, @env)
0
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.box.create_fail", org: org, box_name: box_name))
@env.ui.error(e.message)
1
end
end
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module BoxCommand
module Command
class Delete < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -16,8 +18,8 @@ module VagrantPlugins
o.separator "Options:"
o.separator ""
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |u|
options[:username] = u
o.on("-f", "--[no-]force", "Do not prompt for deletion confirmation") do |f|
options[:force] = f
end
end
@ -29,34 +31,38 @@ module VagrantPlugins
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
if !options[:force]
@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"
end
return 1
@client = client_login(@env)
org, box_name = argv.first.split('/', 2)
delete_box(org, box_name, @client.token)
end
# Delete the requested box
#
# @param [String] org Organization name of box
# @param [String] box_name Name of box
# @param [String] access_token User access token
# @return [Integer]
def delete_box(org, box_name, access_token)
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_box(account: account, org: org, box: box_name) do |box|
box.delete
@env.ui.success(I18n.t("cloud_command.box.delete_success", org: org, box_name: box_name))
0
end
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.box.delete_fail", org: org, box_name: box_name))
@env.ui.error(e.message)
1
end
end
end

View File

@ -5,8 +5,10 @@ module VagrantPlugins
module BoxCommand
module Command
class Show < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
options = {quiet: true, versions: []}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant cloud box show [options] organization/box-name"
@ -16,11 +18,11 @@ module VagrantPlugins
o.separator "Options:"
o.separator ""
o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |u|
options[:username] = u
o.on("--versions VERSION", String, "Display box information for a specific version (can be defined multiple times)") do |v|
options[:versions] << v
end
o.on("--versions VERSION", String, "Display box information for a specific version") do |v|
options[:version] = v
o.on("--[no-]auth", "Authenticate with Vagrant Cloud if required before searching") do |l|
options[:quiet] = !l
end
end
@ -32,40 +34,48 @@ module VagrantPlugins
help: opts.help.chomp
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
box = argv.first.split('/', 2)
@client = client_login(@env, options.slice(:quiet))
org, box_name = argv.first.split('/', 2)
show_box(box[0], box[1], options, @client.token)
show_box(org, box_name, @client&.token, options.slice(:versions))
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
# Display the requested box to the user
#
# @param [String] org Organization name of box
# @param [String] box_name Name of box
# @param [String] access_token User access token
# @param [Hash] options Options for box filtering
# @option options [String] :versions Specific verisons of box
# @return [Integer]
def show_box(org, box_name, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_box(account: account, org: org, box: box_name) do |box|
if box && !Array(options[:versions]).empty?
box = box.versions.find_all{ |v| options[:versions].include?(v.version) }
else
results = success
box = [box]
end
if !box.empty?
box.each do |b|
format_box_results(b, @env)
@env.ui.output("")
end
0
else
@env.ui.warn(I18n.t("cloud_command.box.show_filter_empty",
version: options[:version], org: org, box_name: box_name))
1
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
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.box.show_fail", org: org,box_name:box_name))
@env.ui.error(e.message)
1
end
end
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module BoxCommand
module Command
class Update < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -19,13 +21,10 @@ module VagrantPlugins
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
options[:short] = s
end
o.on("-p", "--private", "Makes box private") do |p|
o.on("-p", "--[no-]private", "Makes box private") do |p|
options[:private] = p
end
end
@ -33,36 +32,45 @@ module VagrantPlugins
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 1 || options.length == 0
if argv.empty? || argv.length > 1 || options.slice(:description, :short, :private).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)
@client = client_login(@env)
org, box_name = argv.first.split('/', 2)
update_box(box[0], box[1], options, @client.token)
update_box(org, box_name, @client.token, options.slice(:short, :description, :private))
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)
# Update an existing box
#
# @param [String] org Organization name of box
# @param [String] box_name Name of box
# @param [String] access_token User access token
# @param [Hash] options Options for box filtering
# @option options [String] :short Short description of box
# @option options [String] :description Full description of box
# @option options [Boolean] :private Set box visibility as private
# @return [Integer]
def update_box(org, box_name, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_box(account: account, org: org, box: box_name) do |box|
box.short_description = options[:short] if options.key?(:short)
box.description = options[:description] if options.key?(:description)
box.private = options[:private] if options.key?(:private)
box.save
@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
format_box_results(box, @env)
0
end
return 1
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.box.update_fail", org: org, box_name: box_name))
@env.ui.error(e.message)
1
end
end
end

View File

@ -1,4 +1,3 @@
require "rest_client"
require "vagrant_cloud"
require "vagrant/util/downloader"
require "vagrant/util/presence"
@ -14,6 +13,7 @@ module VagrantPlugins
include Vagrant::Util::Presence
attr_accessor :client
attr_accessor :username_or_email
attr_accessor :password
attr_reader :two_factor_default_delivery_method
@ -25,6 +25,7 @@ module VagrantPlugins
def initialize(env)
@logger = Log4r::Logger.new("vagrant::cloud::client")
@env = env
@client = VagrantCloud::Client.new(access_token: token)
end
# Removes the token, effectively logging the user out.
@ -38,14 +39,11 @@ module VagrantPlugins
#
# @return [Boolean]
def logged_in?
token = self.token
return false if !token
Vagrant::Util::CredentialScrubber.sensitive(token)
return false if !client.access_token
Vagrant::Util::CredentialScrubber.sensitive(client.access_token)
with_error_handling do
url = "#{Vagrant.server_url}/api/v1/authenticate" +
"?access_token=#{token}"
RestClient.get(url, content_type: :json)
client.authentication_token_validate
true
end
rescue Errors::Unauthorized
@ -62,23 +60,14 @@ module VagrantPlugins
@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
}
}
)
with_error_handling do
r = client.authentication_token_create(username: username_or_email,
password: password, description: description, code: code)
Vagrant::Util::CredentialScrubber.sensitive(response["token"])
response["token"]
Vagrant::Util::CredentialScrubber.sensitive(r[:token])
@client = VagrantCloud::Client.new(access_token: r[:token])
r[:token]
end
end
# Requests a 2FA code
@ -87,50 +76,14 @@ module VagrantPlugins
@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)
r = client.authentication_request_2fa_code(
username: username_or_email, password: password, delivery_method: delivery_method)
proxy = nil
proxy ||= ENV["HTTPS_PROXY"] || ENV["https_proxy"]
proxy ||= ENV["HTTP_PROXY"] || ENV["http_proxy"]
RestClient.proxy = proxy
two_factor = r[:two_factor]
obfuscated_destination = two_factor[:obfuscated_destination]
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)
@env.ui.success("2FA code sent to #{obfuscated_destination}.")
end
end
@ -138,12 +91,16 @@ module VagrantPlugins
#
# @param [String] token
def store_token(token)
Vagrant::Util::CredentialScrubber.sensitive(token)
@logger.info("Storing token in #{token_path}")
token_path.open("w") do |f|
f.write(token)
end
# Reset after we store the token since this is now _our_ token
@client = VagrantCloud::Client.new(access_token: token)
nil
end
@ -167,17 +124,18 @@ EOH
if present?(ENV["VAGRANT_CLOUD_TOKEN"])
@logger.debug("Using authentication token from environment variable")
return ENV["VAGRANT_CLOUD_TOKEN"]
end
if token_path.exist?
t = ENV["VAGRANT_CLOUD_TOKEN"]
elsif token_path.exist?
@logger.debug("Using authentication token from disk at #{token_path}")
return token_path.read.strip
t = token_path.read.strip
elsif present?(ENV["ATLAS_TOKEN"])
@logger.warn("ATLAS_TOKEN detected within environment. Using ATLAS_TOKEN in place of VAGRANT_CLOUD_TOKEN.")
t = ENV["ATLAS_TOKEN"]
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"]
if !t.nil?
Vagrant::Util::CredentialScrubber.sensitive(t)
return t
end
@logger.debug("No authentication token in environment or #{token_path}")
@ -189,22 +147,22 @@ EOH
def with_error_handling(&block)
yield
rescue RestClient::Unauthorized
rescue Excon::Error::Unauthorized
@logger.debug("Unauthorized!")
raise Errors::Unauthorized
rescue RestClient::BadRequest => e
rescue Excon::Error::BadRequest => e
@logger.debug("Bad request:")
@logger.debug(e.message)
@logger.debug(e.backtrace.join("\n"))
parsed_response = JSON.parse(e.response)
parsed_response = JSON.parse(e.response.body)
errors = parsed_response["errors"].join("\n")
raise Errors::ServerError, errors: errors
rescue RestClient::NotAcceptable => e
rescue Excon::Error::NotAcceptable => e
@logger.debug("Got unacceptable response:")
@logger.debug(e.message)
@logger.debug(e.backtrace.join("\n"))
parsed_response = JSON.parse(e.response)
parsed_response = JSON.parse(e.response.body)
if two_factor = parsed_response['two_factor']
store_two_factor_information two_factor

View File

@ -4,6 +4,8 @@ module VagrantPlugins
module CloudCommand
module Command
class List < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -27,9 +29,6 @@ module VagrantPlugins
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
@ -40,7 +39,7 @@ module VagrantPlugins
help: opts.help.chomp
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = client_login(@env)
# TODO: This endpoint is not implemented yet

View File

@ -13,14 +13,8 @@ en:
Press ctrl-c to cancel...
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...
box_save:
Saving box information...
upload_provider:
Uploading provider with file %{file}
release:
@ -45,7 +39,7 @@ en:
version_desc: |-
Version Description: %{version_description}
continue: |-
Do you wish to continue? [y/N]
Do you wish to continue? [y/N]
box:
show_filter_empty: |-
No version matched %{version} for %{org}/%{box_name}
@ -57,6 +51,8 @@ en:
This will completely remove %{box} from Vagrant Cloud. This cannot be undone.
update_success: |-
Updated box %{org}/%{box_name}
not_found: |-
Failed to locate requested box: %{org}/%{box_name}
search:
no_results: |-
No results found for `%{query}`
@ -77,6 +73,8 @@ en:
Deleted provider %{provider} on %{org}/%{box_name} for version %{version}
update_success: |-
Updated provider %{provider} on %{org}/%{box_name} for version %{version}
not_found: |-
Failed to locate %{provider_name} provider for %{org}/%{box_name} on version %{version}
version:
create_success: |-
Created version %{version} on %{org}/%{box_name} for version %{version}
@ -94,6 +92,8 @@ en:
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.
not_found: |-
Failed to locate version %{version} for %{org}/%{box_name}
errors:
search:
fail: |-

View File

@ -12,6 +12,11 @@ module VagrantPlugins
DESC
command(:cloud) do
# Set this to match Vagant logging level so we get
# desired request/response information within the
# logger output
ENV["VAGRANT_CLOUD_LOG"] = Vagrant.log_level
require_relative "root"
init!
Command::Root

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module ProviderCommand
module Command
class Create < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -16,9 +18,6 @@ module VagrantPlugins
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("-c", "--checksum CHECKSUM_VALUE", String, "Checksum of the box for this provider. --checksum-type option is required.") do |c|
options[:checksum] = c
end
@ -30,48 +29,59 @@ module VagrantPlugins
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 4
if argv.count < 3 || argv.count > 4
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = client_login(@env)
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
org, box_name = argv.first.split('/', 2)
provider_name = argv[1]
version = argv[2]
url = argv[3]
upload_provider(org, box_name, provider_name, version, url, @client.token, options)
create_provider(org, box_name, version, provider_name, url, @client.token, options)
end
def upload_provider(org, box_name, provider_name, version, url, access_token, options)
# Create a provider for the box version
#
# @param [String] org Organization name
# @param [String] box Box name
# @param [String] version Box version
# @param [String] provider Provider name
# @param [String] url Provider asset URL
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options
# @option options [String] :checksum Checksum of the box asset
# @option options [String] :checksum_type Type of the checksum
# @return [Integer]
def create_provider(org, box, version, provider, url, access_token, options={})
if !url
@env.ui.warn(I18n.t("cloud_command.upload.no_url"))
end
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_version(account: account, org: org, box: box, version: version) do |version|
provider = version.add_provider(provider)
provider.checksum = options[:checksum] if options.key?(:checksum)
provider.checksum_type = options[:checksum_type] if options.key?(:checksum_type)
provider.url = url if url
org = options[:username] if options[:username]
provider.save
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, nil, options[:checksum], options[:checksum_type])
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.compact
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
@env.ui.success(I18n.t("cloud_command.provider.create_success",
provider: provider.name, org: org, box_name: box, version: version.version))
format_box_results(provider, @env)
0
end
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.provider.create_fail",
provider: provider, org: org, box_name: box, version: version))
@env.ui.error(e.message)
1
end
end
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module ProviderCommand
module Command
class Delete < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -15,53 +17,61 @@ module VagrantPlugins
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
o.on("-f", "--[no-]force", "Force deletion of box version provider without confirmation") do |f|
options[:force] = f
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 3
if argv.count != 3
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
org, box_name = argv.first.split('/', 2)
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"
@env.ui.warn(I18n.t("cloud_command.provider.delete_warn",
provider: provider_name, version:version, box: argv.first))
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
if !options[:force]
cont = @env.ui.ask(I18n.t("cloud_command.continue"))
return 1 if cont.strip.downcase != "y"
end
delete_provider(org, box_name, provider_name, version, @client.token, options)
@client = client_login(@env)
delete_provider(org, box_name, version, provider_name, @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
# Delete a provider for the box version
#
# @param [String] org Organization name
# @param [String] box Box name
# @param [String] version Box version
# @param [String] provider Provider name
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options Currently unused
# @return [Integer]
def delete_provider(org, box, version, provider, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_provider(account: account, org: org, box: box, version: version, provider: provider) do |p|
p.delete
@env.ui.error(I18n.t("cloud_command.provider.delete_success",
provider: provider, org: org, box_name: box, version: version))
0
end
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.provider.delete_fail",
provider: provider, org: org, box_name: box, version: version))
@env.ui.error(e)
1
end
end
end

View File

@ -5,20 +5,19 @@ module VagrantPlugins
module ProviderCommand
module Command
class Update < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant cloud provider update [options] organization/box-name provider-name version url"
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 |u|
options[:username] = u
end
o.on("-c", "--checksum CHECKSUM_VALUE", String, "Checksum of the box for this provider. --checksum-type option is required.") do |c|
options[:checksum] = c
end
@ -30,48 +29,58 @@ module VagrantPlugins
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 4
if argv.count < 3 || argv.count > 4
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = client_login(@env)
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
org, box_name = argv.first.split('/', 2)
provider_name = argv[1]
version = argv[2]
url = argv[3]
update_provider(org, box_name, provider_name, version, url, @client.token, options)
update_provider(org, box_name, version, provider_name, url, @client.token, options)
end
def update_provider(org, box_name, provider_name, version, url, access_token, options)
# Update a provider for the box version
#
# @param [String] org Organization name
# @param [String] box Box name
# @param [String] version Box version
# @param [String] provider Provider name
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options
# @option options [String] :checksum Checksum of the box asset
# @option options [String] :checksum_type Type of the checksum
# @return [Integer]
def update_provider(org, box, version, provider, url, access_token, options)
if !url
@env.ui.warn(I18n.t("cloud_command.upload.no_url"))
end
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
org = options[:username] if options[:username]
with_provider(account: account, org: org, box: box, version: version, provider: provider) do |p|
p.checksum = options[:checksum] if options.key?(:checksum)
p.checksum_type = options[:checksum_type] if options.key?(:checksum_type)
p.url = url if !url.nil?
p.save
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, nil, options[:checksum], options[:checksum_type])
@env.ui.success(I18n.t("cloud_command.provider.update_success",
provider: provider, org: org, box_name: box, version: version))
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
format_box_results(p, @env)
0
end
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.provider.update_fail",
provider: provider, org: org, box_name: box, version: version))
@env.ui.error(e.message)
1
end
end
end

View File

@ -6,8 +6,10 @@ module VagrantPlugins
module ProviderCommand
module Command
class Upload < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
options = {direct: true}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant cloud provider upload [options] organization/box-name provider-name version box-file"
@ -16,57 +18,65 @@ module VagrantPlugins
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
o.on("-D", "--[no-]direct", "Upload asset directly to backend storage") do |d|
options[:direct] = d
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 4
if argv.count != 4
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = client_login(@env)
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
org, box_name = argv.first.split('/', 2)
provider_name = argv[1]
version = argv[2]
file = argv[3] # path expand
file = File.expand_path(argv[3])
upload_provider(org, box_name, provider_name, version, file, @client.token, options)
upload_provider(org, box_name, version, provider_name, file, @client.token, options)
end
def upload_provider(org, box_name, provider_name, version, file, access_token, options)
org = options[:username] if options[:username]
# Upload an asset for a box version provider
#
# @param [String] org Organization name
# @param [String] box Box name
# @param [String] version Box version
# @param [String] provider Provider name
# @param [String] file Path to asset
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options
# @option options [Boolean] :direct Upload directly to backend storage
# @return [Integer]
def upload_provider(org, box, version, provider, file, access_token, options)
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: 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, 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
with_provider(account: account, org: org, box: box, version: version, provider: provider) do |p|
p.upload(direct: options[:direct]) do |upload_url|
m = options[:direct] ? :put : :put
uploader = Vagrant::Util::Uploader.new(upload_url, file, ui: @env.ui, method: m)
ui = Vagrant::UI::Prefixed.new(@env.ui, "cloud")
ui.output(I18n.t("cloud_command.provider.upload",
org: org, box_name: box, version: version, provider: provider))
ui.info("Upload File: #{file}")
uploader.upload!
ui.success(I18n.t("cloud_command.provider.upload_success",
org: org, box_name: box, version: version, provider: provider))
end
0
end
rescue Vagrant::Errors::UploaderError, VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.provider.upload_fail",
provider: provider, org: org, box_name: box, version: version))
@env.ui.error(e.message)
1
end
end
end

View File

@ -5,11 +5,13 @@ module VagrantPlugins
module CloudCommand
module Command
class Publish < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
options = {direct_upload: true}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant cloud publish [options] organization/box-name version provider-name provider-file"
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 ""
@ -19,7 +21,7 @@ module VagrantPlugins
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|
o.on("--url URL", String, "Remote URL to download this provider (cannot be used with provider-file)") do |u|
options[:url] = u
end
o.on("-d", "--description DESCRIPTION", String, "Full description of box") do |d|
@ -28,154 +30,229 @@ module VagrantPlugins
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|
o.on("-f", "--[no-]force", "Disables confirmation to create or update box") do |f|
options[:force] = f
end
o.on("-p", "--private", "Makes box private") do |p|
o.on("-p", "--[no-]private", "Makes box private") do |p|
options[:private] = p
end
o.on("-r", "--release", "Releases box") do |p|
o.on("-r", "--[no-]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 |u|
options[:username] = u
end
o.on("-c", "--checksum CHECKSUM_VALUE", String, "Checksum of the box for this provider. --checksum-type option is required.") do |c|
options[:checksum] = c
end
o.on("-C", "--checksum-type TYPE", String, "Type of checksum used (md5, sha1, sha256, sha384, sha512). --checksum option is required.") do |c|
options[:checksum_type] = c
end
o.on("--[no-]direct-upload", "Upload asset directly to backend storage") do |d|
options[:direct_upload] = d
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 4 || argv.length < 3 || (argv.length == 3 && !options[:url])
if argv.length < 3 || # missing required arguments
argv.length > 4 || # too many arguments
(argv.length < 4 && !options.key?(:url)) || # file argument required if url is not provided
(argv.length > 3 && options.key?(:url)) # cannot provider url and file argument
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
version = argv[1]
provider_name = argv[2]
box_file = argv[3]
org, box_name = argv.first.split('/', 2)
_, version, provider_name, box_file = argv
if !options[:url] && !File.file?(box_file)
if box_file && !File.file?(box_file)
raise Vagrant::Errors::BoxFileNotExist,
file: box_file
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = client_login(@env)
params = options.slice(:private, :release, :url, :short_description,
:description, :version_description, :checksum, :checksum_type)
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]
# Display output to user describing action to be taken
display_preamble(org, box_name, version, provider_name, params)
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, nil, options[:checksum], options[:checksum_type])
# Load up all the models we'll need to publish the asset
box = load_box(org, box_name, @client.token)
box_v = load_box_version(box, version)
box_p = load_version_provider(box_v, provider_name)
ui = Vagrant::UI::Prefixed.new(@env.ui, "cloud")
# Update all the data
set_box_info(box, params.slice(:private, :short_description, :description))
set_version_info(box_v, params.slice(:version_description))
set_provider_info(box_p, params.slice(:checksum, :checksum_type, :url))
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
# Save any updated state
@env.ui.warn(I18n.t("cloud_command.publish.box_save"))
box.save
# If we have a box file asset, upload it
if box_file
upload_box_file(box_p, box_file, options.slice(:direct_upload))
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
rescue VagrantCloud::InvalidVersion => e
@env.ui.error(I18n.t("cloud_command.errors.publish.fail", org: org, box_name: box_name))
@env.ui.error(e)
return 1
# If configured to release the box, release it
if options[:release] && !box_v.released?
release_version(box_v)
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
# And we're done!
@env.ui.success(I18n.t("cloud_command.publish.complete", org: org, box_name: box_name))
format_box_results(box, @env)
0
rescue VagrantCloud::Error => err
@env.ui.error(I18n.t("cloud_command.errors.publish.fail", org: org, box_name: box_name))
@env.ui.error(err.message)
1
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
# Upload the file for the given box provider
#
# @param [VagrantCloud::Box::Provider] provider Vagrant Cloud box version provider
# @param [String] box_file Path to local asset for upload
# @param [Hash] options
# @option options [Boolean] :direct_upload Upload directly to backend storage
# @return [nil]
def upload_box_file(provider, box_file, options={})
box_file = File.absolute_path(box_file)
@env.ui.info(I18n.t("cloud_command.publish.upload_provider", file: box_file))
provider.upload(direct: options[:direct_upload]) do |upload_url|
Vagrant::Util::Uploader.new(upload_url, box_file, ui: @env.ui, method: :put).upload!
end
return 1
nil
end
# Release the box version
#
# @param [VagrantCloud::Box::Version] version Vagrant Cloud box version
# @return [nil]
def release_version(version)
@env.ui.info(I18n.t("cloud_command.publish.release"))
version.release
nil
end
# Set any box related attributes that were provided
#
# @param [VagrantCloud::Box] box Vagrant Cloud box
# @param [Hash] options
# @option options [Boolean] :private Box access is private
# @option options [String] :short_description Short description of box
# @option options [String] :description Full description of box
# @return [VagrantCloud::Box]
def set_box_info(box, options={})
box.private = options[:private] if options.key?(:private)
box.short_description = options[:short_description] if options.key?(:short_description)
box.description = options[:description] if options.key?(:description)
box
end
# Set any version related attributes that were provided
#
# @param [VagrantCloud::Box::Version] version Vagrant Cloud box version
# @param [Hash] options
# @option options [String] :version_description Description for this version
# @return [VagrantCloud::Box::Version]
def set_version_info(version, options={})
version.description = options[:version_description] if options.key?(:version_description)
version
end
# Set any provider related attributes that were provided
#
# @param [VagrantCloud::Box::Provider] provider Vagrant Cloud box version provider
# @param [Hash] options
# @option options [String] :url Remote URL for self hosted
# @option options [String] :checksum_type Type of checksum value provided
# @option options [String] :checksum Checksum of the box asset
# @return [VagrantCloud::Box::Provider]
def set_provider_info(provider, options={})
provider.url = options[:url] if options.key?(:url)
provider.checksum_type = options[:checksum_type] if options.key?(:checksum_type)
provider.checksum = options[:checksum] if options.key?(:checksum)
provider
end
# Load the requested version provider
#
# @param [VagrantCloud::Box::Version] version The version of the Vagrant Cloud box
# @param [String] provider_name Name of the provider
# @return [VagrantCloud::Box::Provider]
def load_version_provider(version, provider_name)
provider = version.providers.detect { |pv| pv.name == provider_name }
return provider if provider
version.add_provider(provider_name)
end
# Load the requested box version
#
# @param [VagrantCloud::Box] box The Vagrant Cloud box
# @param [String] version Version of the box
# @return [VagrantCloud::Box::Version]
def load_box_version(box, version)
v = box.versions.detect { |v| v.version == version }
return v if v
box.add_version(version)
end
# Load the requested box
#
# @param [String] org Organization name for box
# @param [String] box_name Name of the box
# @param [String] access_token User access token
# @return [VagrantCloud::Box]
def load_box(org, box_name, access_token)
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
box = account.organization(name: org).boxes.detect { |b| b.name == box_name }
return box if box
account.organization(name: org).add_box(box_name)
end
# Display publishing information to user before starting process
#
# @param [String] org Organization name
# @param [String] box_name Name of the box to publish
# @param [String] version Version of the box to publish
# @param [String] provider_name Name of the provider being published
# @param [Hash] options
# @option options [Boolean] :private Box is private
# @option options [Boolean] :release Box should be released
# @option options [String] :url Remote URL for self-hosted boxes
# @option options [String] :description Description of the box
# @option options [String] :short_description Short description of the box
# @option options [String] :version_description Description of the box version
# @return [nil]
def display_preamble(org, box_name, version, provider_name, options={})
@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]
nil
end
end
end

View File

@ -4,8 +4,10 @@ module VagrantPlugins
module CloudCommand
module Command
class Search < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
options = {quiet: true}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant cloud search [options] query"
@ -37,45 +39,56 @@ module VagrantPlugins
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 to login with") do |u|
options[:username] = u
o.on("--[no-]auth", "Authenticate with Vagrant Cloud if required before searching") do |l|
options[:quiet] = !l
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.length > 1
if argv.length != 1
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = client_login(@env, options.slice(:quiet))
query = argv.first
options[:limit] = 25 if !(options[:limit].to_i < 1) && !options[:limit]
search(query, options, @client.token)
search(query, @client&.token, options)
end
def search(query, options, access_token)
server_url = VagrantPlugins::CloudCommand::Util.api_server_url
search = VagrantCloud::Search.new(access_token, server_url)
# Perform requested search and display results to user
#
# @param [String] query Search query string
# @param [Hash] options
# @option options [String] :provider Filter by provider
# @option options [String] :sort Field to sort results
# @option options [Integer] :limit Number of results to display
# @option options [Integer] :page Page of results to display
# @param [String] access_token User access token
# @return [Integer]
def search(query, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
params = {query: query}.merge(options.slice(:provider, :sort, :order, :limit, :page))
result = account.searcher.search(**params)
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
if result.boxes.empty?
@env.ui.warn(I18n.t("cloud_command.search.no_results", query: query))
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
format_search_results(result.boxes, options[:short], options[:json], @env)
0
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.search.fail"))
@env.ui.error(e.message)
1
end
end
end

View File

@ -1,205 +1,309 @@
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
module Util
# @return [String] Vagrant Cloud server URL
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
# @option options [String] :login Username or email
# @option options [String] :description Description of login usage for token
# @option options [String] :code 2FA code for login
# @option options [Boolean] :quiet Do not prompt user
# @returns [VagrantPlugins::CloudCommand::Client, nil]
def client_login(env, options={})
return @_client if defined?(@_client)
@_client = Client.new(env)
return @_client if @_client.logged_in?
# If directed to be quiet, do not continue and
# just return nil
return if options[:quiet]
# 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
def api_server_url
if Vagrant.server_url == Vagrant::DEFAULT_SERVER_URL
return "#{Vagrant.server_url}/api/v1"
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
# Print search results from Vagrant Cloud to the console
#
# @param [Array<VagrantCloud::Box>] search_results Box search results from Vagrant Cloud
# @param [Boolean] short Print short summary
# @param [Boolean] json Print output in JSON format
# @param [Vagrant::Environment] env Current Vagrant environment
# @return [nil]
def format_search_results(search_results, short, json, env)
result = search_results.map do |b|
{
name: b.tag,
version: b.current_version.version,
downloads: format_downloads(b.downloads.to_s),
providers: b.current_version.providers.map(&:name).join(", ")
}
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
nil
end
# Output box details result from Vagrant Cloud
#
# @param [VagrantCloud::Box, VagrantCloud::Box::Version] box Box or box version to display
# @param [Vagrant::Environment] env Current Vagrant environment
# @return [nil]
def format_box_results(box, env)
if box.is_a?(VagrantCloud::Box)
info = box_info(box)
elsif box.is_a?(VagrantCloud::Box::Provider)
info = version_info(box.version)
else
info = version_info(box)
end
width = info.keys.map(&:size).max
info.each do |k, v|
whitespace = width - k.size
env.ui.info "#{k}: #{"".ljust(whitespace)} #{v}"
end
nil
end
# Load box and yield
#
# @param [VagrantCloud::Account] account Vagrant Cloud account
# @param [String] org Organization name
# @param [String] box Box name
# @yieldparam [VagrantCloud::Box] box Requested Vagrant Cloud box
# @yieldreturn [Integer]
# @return [Integer]
def with_box(account:, org:, box:)
org = account.organization(name: org)
b = org.boxes.detect { |b| b.name == box }
if !b
@env.ui.error(I18n.t("cloud_command.box.not_found",
org: org.username, box_name: box))
return 1
end
yield b
end
# Load box version and yield
#
# @param [VagrantCloud::Account] account Vagrant Cloud account
# @param [String] org Organization name
# @param [String] box Box name
# @param [String] version Box version
# @yieldparam [VagrantCloud::Box::Version] version Requested Vagrant Cloud box version
# @yieldreturn [Integer]
# @return [Integer]
def with_version(account:, org:, box:, version:)
with_box(account: account, org: org, box: box) do |b|
v = b.versions.detect { |v| v.version == version }
if !v
@env.ui.error(I18n.t("cloud_command.version.not_found",
box_name: box, org: org, version: version))
return 1
end
yield v
end
end
# Load box version and yield
#
# @param [VagrantCloud::Account] account Vagrant Cloud account
# @param [String] org Organization name
# @param [String] box Box name
# @param [String] version Box version
# @param [String] provider Box version provider name
# @yieldparam [VagrantCloud::Box::Provider] provider Requested Vagrant Cloud box version provider
# @yieldreturn [Integer]
# @return [Integer]
def with_provider(account:, org:, box:, version:, provider:)
with_version(account: account, org: org, box: box, version: version) do |v|
p = v.providers.detect { |p| p.name == provider }
if !p
@env.ui.error(I18n.t("cloud_command.provider.not_found",
org: org, box_name: box, version: version, provider_name: provider))
return 1
end
yield p
end
end
protected
# Extract box information for display
#
# @param [VagrantCloud::Box] box Box for extracting information
# @return [Hash<String,String>]
def box_info(box)
Hash.new.tap do |i|
i["Box"] = box.tag
i["Description"] = box.description
i["Private"] = box.private ? "yes" : "no"
i["Created"] = box.created_at
i["Updated"] = box.updated_at
if !box.current_version.nil?
i["Current Version"] = box.current_version.version
else
return Vagrant.server_url
i["Current Version"] = "N/A"
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
i["Versions"] = box.versions.slice(0, 5).map(&:version).join(", ")
if box.versions.size > 5
i["Versions"] += " ..."
end
@_client
i["Downloads"] = format_downloads(box.downloads)
end
end
# Extract version information for display
#
# @param [VagrantCloud::Box::Version] version Box version for extracting information
# @return [Hash<String,String>]
def version_info(version)
Hash.new.tap do |i|
i["Box"] = version.box.tag
i["Version"] = version.version
i["Description"] = version.description
i["Status"] = version.status
i["Providers"] = version.providers.map(&:name).sort.join(", ")
i["Created"] = version.created_at
i["Updated"] = version.updated_at
end
end
# Print table results from search request
#
# @param [Vagrant::Environment] env Current Vagrant environment
# @param [Hash] column_labels A hash of key/value pairs for table labels (i.e. {col1: "COL1"})
# @param [Array] results An array of hashes representing search resuls
# @param [Array] to_jrust_keys - List of columns keys to right justify (left justify is defualt)
# @return [nil]
# @note Modified from https://stackoverflow.com/a/28685559
def print_search_table(env, column_labels, results, to_rjust_keys)
columns = column_labels.each_with_object({}) do |(col,label),h|
h[col] = {
label: label,
width: [results.map { |g| g[col].size }.max, label.size].max
}
end
# ===================================================
# Modified from https://stackoverflow.com/a/28685559
# for printing arrays of hashes in formatted tables
# ===================================================
write_header(env, columns)
write_divider(env, columns)
results.each { |h| write_line(env, columns, h, to_rjust_keys) }
write_divider(env, columns)
end
# @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 the header for a table
#
# @param [Vagrant::Environment] env Current Vagrant environment
# @param [Array<Hash>] columns List of columns in Hash format with `:label` and `:width` keys
# @return [nil]
def write_header(env, columns)
env.ui.info "| #{ columns.map { |_,g| g[:label].ljust(g[:width]) }.join(' | ') } |"
nil
end
write_header(env, columns)
write_divider(env, columns)
results.each { |h| write_line(env, columns, h,to_rjust_keys) }
write_divider(env, columns)
end
# Write a row divider for a table
#
# @param [Vagrant::Environment] env Current Vagrant environment
# @param [Array<Hash>] columns List of columns in Hash format with `:label` and `:width` keys
# @return [nil]
def write_divider(env, columns)
env.ui.info "+-#{ columns.map { |_,g| "-"*g[:width] }.join("-+-") }-+"
nil
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)
# Write a line of content for a table
#
# @param [Vagrant::Environment] env Current Vagrant environment
# @param [Array<Hash>] columns List of columns in Hash format with `:label` and `:width` keys
# @param [Hash] h Values to print in row
# @param [Array<String>] to_rjust_keys List of columns to right justify
# @return [nil]
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
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])
h[k].ljust(columns[k][:width])
end
end
}.join(" | ")
env.ui.info "| #{str} |"
nil
end
# Converts a string of numbers into a formatted number
#
# 1234 -> 1,234
#
# @param [String] number Numer to format
def format_downloads(number)
number.to_s.chars.reverse.each_slice(3).map(&:join).join(",").reverse
end
end
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module VersionCommand
module Command
class Create < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -19,48 +21,51 @@ module VagrantPlugins
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 |u|
options[:username] = u
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 2
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]
@client = client_login(@env)
org, box_name = argv.first.split('/', 2)
version = argv[1]
create_version(org, box_name, version, @client.token, options)
create_version(org, box_name, version, @client.token, options.slice(:description))
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
# Create a new version of the box
#
# @param [String] org Organization box is within
# @param [String] box_name Name of box
# @param [String] box_version Version of box to create
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options
# @option options [String] :description Description of box version
# @return [Integer]
def create_version(org, box_name, box_version, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_box(account: account, org: org, box: box_name) do |box|
version = box.add_version(box_version)
version.description = options[:description] if options.key?(:description)
version.save
@env.ui.success(I18n.t("cloud_command.version.create_success",
version: box_version, org: org, box_name: box_name))
format_box_results(version, @env)
0
end
return 1
rescue VagrantCloud::Error => 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.message)
1
end
end
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module VersionCommand
module Command
class Delete < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -15,51 +17,56 @@ module VagrantPlugins
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
o.on("-f", "--[no-]force", "Force deletion without confirmation") do |f|
options[:force] = f
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 2
if argv.size != 2
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
org, box_name = argv.first.split('/', 2)
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"
if !options[:force]
@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"
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
@client = client_login(@env)
delete_version(org, box_name, version, options, @client.token)
delete_version(org, box_name, version, @client.token, options.slice)
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
# Delete the requested box version
#
# @param [String] org Box organization name
# @param [String] box_name Name of the box
# @param [String] box_version Version of the box
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options Current unsued
def delete_version(org, box_name, box_version, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_version(account: account, org: org, box: box_name, version: box_version) do |version|
version.delete
@env.ui.success(I18n.t("cloud_command.version.delete_success",
version: box_version, org: org, box_name: box_name))
0
end
return 1
rescue VagrantCloud::Error => 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.message)
1
end
end
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module VersionCommand
module Command
class Release < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -15,11 +17,7 @@ module VagrantPlugins
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
options[:force] = false
o.on("-f", "--force", "Release without confirmation") do |f|
o.on("-f", "--[no-]force", "Release without confirmation") do |f|
options[:force] = f
end
end
@ -27,46 +25,48 @@ module VagrantPlugins
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 2
if argv.size != 2
raise Vagrant::Errors::CLIInvalidUsage,
help: opts.help.chomp
end
if not options[:force]
@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"
if !options[:force]
@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"
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
@client = client_login(@env)
org, box_name = argv.first.split('/', 2)
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
# Release the box version
#
# @param [String] org Organization name
# @param [String] box_name Box name
# @param [String] version Version of the box
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options Currently unused
# @return [Integer]
def release_version(org, box_name, version, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_version(account: account, org: org, box: box_name, version: version) do |v|
v.release
@env.ui.success(I18n.t("cloud_command.version.release_success",
version: version, org: org, box_name: box_name))
0
end
return 1
rescue VagrantCloud::Error => e
@env.ui.error(I18n.t("cloud_command.errors.version.release_fail",
version: version, org: org, box_name: box_name))
@env.ui.error(e.message)
1
end
end
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module VersionCommand
module Command
class Revoke < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -15,52 +17,57 @@ module VagrantPlugins
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
o.on("-f", "--[no-]force", "Force revocation without confirmation") do |f|
options[:force] = f
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 2
if argv.size != 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"
if !options[:force]
@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"
end
@client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
box = argv.first.split('/', 2)
org = box[0]
box_name = box[1]
@client = client_login(@env)
org, box_name = argv.first.split('/', 2)
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
# Revoke release of box version
#
# @param [String] org Organization name
# @param [String] box_name Box name
# @param [String] version Version of the box
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options Currently unused
# @return [Integer]
def revoke_version(org, box_name, box_version, access_token, options={})
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_version(account: account, org: org, box: box_name, version: box_version) do |version|
version.revoke
@env.ui.success(I18n.t("cloud_command.version.revoke_success",
version: box_version, org: org, box_name: box_name))
format_box_results(version, @env)
0
end
return 1
rescue VagrantCloud::Error => 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.message)
1
end
end
end

View File

@ -5,6 +5,8 @@ module VagrantPlugins
module VersionCommand
module Command
class Update < Vagrant.plugin("2", :command)
include Util
def execute
options = {}
@ -19,48 +21,50 @@ module VagrantPlugins
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 |u|
options[:username] = u
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.empty? || argv.length > 2
if argv.size != 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]
@client = client_login(@env)
org, box_name = argv.first.split('/', 2)
version = argv[1]
update_version(org, box_name, version, @client.token, options)
end
# Update the version of the box
# @param [String] org Organization name
# @param [String] box_name Box name
# @param [String] version Version of the box
# @param [String] access_token User Vagrant Cloud access token
# @param [Hash] options
# @options options [String] :description Description of box version
# @return [Integer]
def update_version(org, box_name, box_version, access_token, options)
org = options[:username] if options[:username]
account = VagrantCloud::Account.new(
custom_server: api_server_url,
access_token: access_token
)
with_version(account: account, org: org, box: box_name, version: box_version) do |version|
version.description = options[:description] if options.key?(:description)
version.save
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
@env.ui.success(I18n.t("cloud_command.version.update_success",
version: box_version, org: org, box_name: box_name))
format_box_results(version, @env)
0
end
return 1
rescue VagrantCloud::Error => 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.message)
1
end
end
end

View File

@ -1,253 +0,0 @@
require "rest_client"
require "vagrant/util/downloader"
require "vagrant/util/presence"
module VagrantPlugins
module LoginCommand
class Client
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::login::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
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}'")
response = post(
"/api/v1/authenticate", {
user: {
login: username_or_email,
password: password
},
token: {
description: description
},
two_factor: {
code: code
}
}
)
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}...")
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
raise "An unexpected error occurred: #{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

View File

@ -1,137 +0,0 @@
require 'socket'
module VagrantPlugins
module LoginCommand
class Command < Vagrant.plugin("2", "command")
def self.synopsis
"log in to HashiCorp's Vagrant Cloud"
end
def execute
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant login"
o.separator ""
o.on("-c", "--check", "Only checks if you're logged in") do |c|
options[:check] = c
end
o.on("-d", "--description DESCRIPTION", String, "Description for the Vagrant Cloud token") do |t|
options[:description] = t
end
o.on("-k", "--logout", "Logs you out if you're logged in") 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, "Specify your Vagrant Cloud username or email address") do |t|
options[:login] = t
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])
end
# Let the user know what is going on.
@env.ui.output(I18n.t("login_command.command_header") + "\n")
# If it is a private cloud installation, show that
if Vagrant.server_url != Vagrant::DEFAULT_SERVER_URL
@env.ui.output("Vagrant Cloud URL: #{Vagrant.server_url}")
end
# Ask for the username
if @client.username_or_email
@env.ui.output("Vagrant Cloud username or email: #{@client.username_or_email}")
end
until @client.username_or_email
@client.username_or_email = @env.ui.ask("Vagrant Cloud username or email: ")
end
until @client.password
@client.password = @env.ui.ask("Password (will be hidden): ", echo: false)
end
description = options[:description]
if description
@env.ui.output("Token description: #{description}")
else
description_default = "Vagrant login from #{Socket.gethostname}"
until description
description =
@env.ui.ask("Token description (Defaults to #{description_default.inspect}): ")
end
description = description_default if description.empty?
end
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)
@env.ui.success(I18n.t("login_command.logged_in"))
0
end
def execute_check
if @client.logged_in?
@env.ui.success(I18n.t("login_command.check_logged_in"))
return 0
else
@env.ui.error(I18n.t("login_command.check_not_logged_in"))
return 1
end
end
def execute_logout
@client.clear_token
@env.ui.success(I18n.t("login_command.logged_out"))
return 0
end
def execute_token(token)
@client.store_token(token)
@env.ui.success(I18n.t("login_command.token_saved"))
if @client.logged_in?
@env.ui.success(I18n.t("login_command.check_logged_in"))
return 0
else
@env.ui.error(I18n.t("login_command.invalid_token"))
return 1
end
end
end
end
end

View File

@ -1,24 +0,0 @@
module VagrantPlugins
module LoginCommand
module Errors
class Error < Vagrant::Errors::VagrantError
error_namespace("login_command.errors")
end
class ServerError < Error
error_key(:server_error)
end
class ServerUnreachable < Error
error_key(:server_unreachable)
end
class Unauthorized < Error
error_key(:unauthorized)
end
class TwoFactorRequired < Error
end
end
end
end

View File

@ -1,49 +0,0 @@
en:
login_command:
middleware:
authentication:
different_target: |-
Vagrant has detected a custom Vagrant server in use for downloading
box files. An authentication token is currently set which will be
added to the box request. If the custom Vagrant server should not
be receiving the authentication token, please unset it.
Known Vagrant server: %{known_host}
Custom Vagrant server: %{custom_host}
Press ctrl-c to cancel...
errors:
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.
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.

View File

@ -2,9 +2,6 @@ require "vagrant"
module VagrantPlugins
module LoginCommand
autoload :Client, File.expand_path("../client", __FILE__)
autoload :Errors, File.expand_path("../errors", __FILE__)
class Plugin < Vagrant.plugin("2")
name "vagrant-login"
description <<-DESC
@ -13,18 +10,8 @@ module VagrantPlugins
command(:login) do
require File.expand_path("../../cloud/auth/login", __FILE__)
init!
VagrantPlugins::CloudCommand::AuthCommand::Command::Login
end
protected
def self.init!
return if defined?(@_init)
I18n.load_path << File.expand_path("../../cloud/locales/en.yml", __FILE__)
I18n.reload!
@_init = true
end
end
end
end

View File

@ -7,95 +7,169 @@ describe VagrantPlugins::CloudCommand::AuthCommand::Command::Login do
let(:argv) { [] }
let(:env) { isolated_environment.create_vagrant_env }
let(:action_runner) { double("action_runner") }
let(:client) { double("client", logged_in?: logged_in) }
let(:logged_in) { true }
let(:token_path) { env.data_dir.join("vagrant_login_token") }
let(:stdout) { StringIO.new }
let(:stderr) { StringIO.new }
before do
allow(env).to receive(:action_runner).
and_return(action_runner)
allow(VagrantPlugins::CloudCommand::Client).
to receive(:new).and_return(client)
end
subject { described_class.new(argv, env) }
before do
stub_env("ATLAS_TOKEN" => "")
describe "#execute_check" do
context "when user is logged in" do
let(:logged_in) { true }
it "should output a success message" do
expect(env.ui).to receive(:success)
subject.execute_check(client)
end
it "should return zero value" do
expect(subject.execute_check(client)).to eq(0)
end
end
context "when user is not logged in" do
let(:logged_in) { false }
it "should output an error message" do
expect(env.ui).to receive(:error)
subject.execute_check(client)
end
it "should return a non-zero value" do
r = subject.execute_check(client)
expect(r).not_to eq(0)
expect(r).to be_a(Integer)
end
end
end
let(:action_runner) { double("action_runner") }
describe "#execute_token" do
let(:token) { double("token") }
before do
allow(env).to receive(:action_runner).and_return(action_runner)
before { allow(client).to receive(:store_token) }
it "should store the token" do
expect(client).to receive(:store_token).with(token)
subject.execute_token(client, token)
end
context "when token is valid" do
let(:logged_in) { true }
it "should output a success message" do
expect(env.ui).to receive(:success).twice
subject.execute_token(client, token)
end
it "should return a zero value" do
expect(subject.execute_token(client, token)).to eq(0)
end
end
context "when token is invalid" do
let(:logged_in) { false }
it "should output an error message" do
expect(env.ui).to receive(:error)
subject.execute_token(client, token)
end
it "should return a non-zero value" do
r = subject.execute_token(client, token)
expect(r).not_to eq(0)
expect(r).to be_a(Integer)
end
end
end
describe "#execute" do
context "with no args" do
let(:argv) { [] }
before do
allow(client).to receive(:username_or_email=)
allow(client).to receive(:store_token)
end
context "with --check" do
let(:argv) { ["--check"] }
context "when arguments are passed" do
before { argv << "argument" }
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
it "should print help" do
expect { subject.execute }.to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with --logout" do
let(:argv) { ["--logout"] }
context "when --check flag is used" do
before { argv << "--check" }
it "returns 0" do
it "should run login check" do
expect(subject).to receive(:execute_check).with(client)
subject.execute
end
it "should return the value of the check execution" do
result = double("result")
expect(subject).to receive(:execute_check).with(client).and_return(result)
expect(subject.execute).to eq(result)
end
end
context "when --token flag is used" do
let(:new_token) { "NEW-TOKEN" }
before { argv.push("--token").push(new_token) }
it "should execute the token action" do
expect(subject).to receive(:execute_token).with(client, new_token)
subject.execute
end
it "should return value of token action" do
result = double("result")
expect(subject).to receive(:execute_token).with(client, new_token).and_return(result)
expect(subject.execute).to eq(result)
end
it "should store the new token" do
expect(client).to receive(:store_token).with(new_token)
subject.execute
end
end
context "when user is logged in" do
let(:logged_in) { true }
it "should output success message" do
expect(env.ui).to receive(:success)
subject.execute
end
it "should return a zero value" 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 user is not logged in" do
let(:logged_in) { false }
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
it "should run the client login" do
expect(subject).to receive(:client_login)
subject.execute
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
context "when username and description flags are supplied" do
let(:username) { "my-username" }
let(:description) { "my-description" }
it "returns 1" do
expect(subject.execute).to eq(1)
before { argv.push("--username").push(username).push("--description").push(description) }
it "should include login and description to login" do
expect(subject).to receive(:client_login).with(env, hash_including(login: username, description: description))
subject.execute
end
end
end

View File

@ -12,17 +12,15 @@ describe VagrantPlugins::CloudCommand::AuthCommand::Command::Logout do
env.vagrantfile("")
env.create_vagrant_env
end
let(:client) { double("client") }
subject { described_class.new(argv, iso_env) }
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: "1234token1234") }
before do
allow(VagrantPlugins::CloudCommand::Client).to receive(:new).and_return(client)
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

View File

@ -6,49 +6,105 @@ describe VagrantPlugins::CloudCommand::AuthCommand::Command::Whoami do
include_context "unit"
let(:argv) { [] }
let(:iso_env) do
let(: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(:client) { double("client", token: token) }
let(:token) { double("token") }
let(:account_username) { "account-username" }
let(:account) { double("account", username: account_username) }
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: "1234token1234") }
let(:account) { double("account") }
subject { described_class.new(argv, env) }
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)
allow(env).to receive(:action_runner).and_return(action_runner)
allow(VagrantPlugins::CloudCommand::Client).to receive(:new).and_return(client)
allow(VagrantCloud::Account).to receive(:new).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)
describe "whoami" do
context "when token is unset" do
let(:token) { "" }
it "should output an error" do
expect(env.ui).to receive(:error)
subject.whoami(token)
end
it "should return non-zero" do
r = subject.whoami(token)
expect(r).not_to eq(0)
expect(r).to be_a(Integer)
end
end
context "when token is set" do
let(:token) { "my-token" }
it "should load an account to validate" do
expect(VagrantCloud::Account).to receive(:new).
with(hash_including(access_token: token)).and_return(account)
subject.whoami(token)
end
it "should output the account username" do
expect(env.ui).to receive(:success).with(/#{account_username}/)
subject.whoami(token)
end
it "should return zero value" do
expect(subject.whoami(token)).to eq(0)
end
context "when error is encountered" do
before { allow(VagrantCloud::Account).to receive(:new).and_raise(VagrantCloud::Error::ClientError) }
it "should output an error" do
expect(env.ui).to receive(:error).twice
subject.execute
end
it "should return a non-zero value" do
r = subject.execute
expect(r).not_to eq(0)
expect(r).to be_a(Integer)
end
end
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)
describe "#execute" do
before do
allow(subject).to receive(:whoami)
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)
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 no argument" do
it "should use stored token via client" do
expect(subject).to receive(:whoami).with(token)
subject.execute
end
end
context "with token argument" do
let(:token_arg) { "TOKEN_ARG" }
let(:argv) { [token_arg] }
it "should use the passed token" do
expect(subject).to receive(:whoami).with(token_arg)
subject.execute
end
end
end
end

View File

@ -5,57 +5,146 @@ 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(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:account) { double("account") }
let(:organization) { double("organization") }
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
describe "#create_box" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(account).to receive(:organization).with(name: org_name).
and_return(organization)
allow(subject).to receive(:format_box_results).with(box, env)
allow(organization).to receive(:add_box).and_return(box)
allow(box).to receive(:save)
end
subject { described_class.new(argv, env) }
it "should add a new box to the organization" do
expect(organization).to receive(:add_box).with(box_name).
and_return(box)
subject.create_box(org_name, box_name, access_token, options)
end
it "should save the new box" do
expect(box).to receive(:save)
subject.create_box(org_name, box_name, access_token, options)
end
it "should return a zero value on success" do
expect(subject.create_box(org_name, box_name, access_token, options)).
to eq(0)
end
it "should return a non-zero value on error" do
expect(box).to receive(:save).and_raise(VagrantCloud::Error)
result = subject.create_box(org_name, box_name, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
context "with option set" do
let(:options) { {short: short, description: description, private: priv} }
let(:short) { double("short") }
let(:description) { double("description") }
let(:priv) { double("private") }
it "should set info into box" do
expect(box).to receive(:short_description=).with(short)
expect(box).to receive(:description=).with(description)
expect(box).to receive(:private=).with(priv)
subject.create_box(org_name, box_name, access_token, options)
end
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)
describe "#execute" do
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
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)
subject { described_class.new(argv, iso_env) }
allow(box).to receive(:create).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 422))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
let(:box) { double("box") }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).and_return(client)
allow(subject).to receive(:format_box_results)
allow(subject).to receive(:create_box)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "should create the box" do
expect(subject).to receive(:create_box).with(org_name, box_name, any_args)
subject.execute
end
context "when description flag is provided" do
let(:description) { "my-description" }
before { argv.push("--description").push(description) }
it "should create box with given description" do
expect(subject).to receive(:create_box).
with(org_name, box_name, access_token, hash_including(description: description))
subject.execute
end
end
context "when short flag is provided" do
let(:description) { "my-description" }
before { argv.push("--short").push(description) }
it "should create box with given short description" do
expect(subject).to receive(:create_box).
with(org_name, box_name, access_token, hash_including(short: description))
subject.execute
end
end
context "when private flag is provided" do
before { argv.push("--private") }
it "should create box as private" do
expect(subject).to receive(:create_box).
with(org_name, box_name, access_token, hash_including(private: true))
subject.execute
end
end
end
end
end

View File

@ -5,58 +5,109 @@ 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(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:account) { double("account") }
let(:organization) { double("organization") }
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
describe "#delete_box" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_box).with(account: account, org: org_name, box: box_name).
and_yield(box)
allow(account).to receive(:organization).with(name: org_name).
and_return(organization)
allow(box).to receive(:delete)
end
subject { described_class.new(argv, env) }
it "should return 0 on success" do
expect(subject.delete_box(org_name, box_name, access_token)).to eq(0)
end
it "should delete the box" do
expect(box).to receive(:delete)
subject.delete_box(org_name, box_name, access_token)
end
it "should return non-zero on error" do
expect(box).to receive(:delete).and_raise(VagrantCloud::Error)
result = subject.delete_box(org_name, box_name, access_token)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
end
context "with arguments" do
let (:argv) { ["vagrant/box-name"] }
describe "#execute" do
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)
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
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)
subject { described_class.new(argv, iso_env) }
allow(box).to receive(:delete).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
let(:box) { double("box") }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(iso_env.ui).to receive(:ask).
and_return("y")
allow(subject).to receive(:delete_box)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with box name argument" do
let (:argv) { ["#{org_name}/#{box_name}"] }
it "should delete the box" do
expect(subject).to receive(:delete_box).
with(org_name, box_name, access_token)
subject.execute
end
it "should prompt for confirmation" do
expect(iso_env.ui).to receive(:ask).and_return("y")
subject.execute
end
context "with force flag" do
before { argv.push("--force") }
it "should not prompt for confirmation" do
expect(iso_env.ui).not_to receive(:ask)
subject.execute
end
end
end
end
end

View File

@ -5,59 +5,147 @@ 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(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:account) { double("account") }
let(:organization) { double("organization") }
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
describe "#show_box" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(ui).to receive(:output)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_box).with(account: account, org: org_name, box: box_name).
and_yield(box)
allow(account).to receive(:organization).with(name: org_name).
and_return(organization)
allow(subject).to receive(:format_box_results)
end
subject { described_class.new(argv, env) }
it "should return 0 on success" do
expect(subject.show_box(org_name, box_name, access_token, options)).to eq(0)
end
it "should display the box results" do
expect(subject).to receive(:format_box_results).with(box, env)
subject.show_box(org_name, box_name, access_token, options)
end
it "should return non-zero on error" do
expect(subject).to receive(:with_box).and_raise(VagrantCloud::Error)
result = subject.show_box(org_name, box_name, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
context "with version defined" do
let(:options) { {versions: [version]} }
let(:box_version) { double("box_version", version: version) }
let(:box_versions) { [box_version] }
let(:version) { double("version") }
before do
allow(box).to receive(:versions).and_return(box_versions)
end
it "should print the version details" do
expect(subject).to receive(:format_box_results).with(box_version, env)
subject.show_box(org_name, box_name, access_token, options)
end
context "when version is not found" do
let(:box_versions) { [] }
it "should return non-zero" do
result = subject.show_box(org_name, box_name, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
it "should not print any box information" do
expect(subject).not_to receive(:format_box_results)
subject.show_box(org_name, box_name, access_token, options)
end
end
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)
describe "#execute" do
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
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)
subject { described_class.new(argv, iso_env) }
allow(box).to receive(:read).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:show_box)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with box name argument" do
let (:argv) { ["#{org_name}/#{box_name}"] }
it "should show the box" do
expect(subject).to receive(:show_box).with(org_name, box_name, any_args)
subject.execute
end
it "should create the client login quietly" do
expect(subject).to receive(:client_login).with(iso_env, hash_including(quiet: true))
subject.execute
end
context "with auth flag" do
before { argv.push("--auth") }
it "should set quiet option to false when creating client" do
expect(subject).to receive(:client_login).with(iso_env, hash_including(quiet: false))
subject.execute
end
end
context "with versions flag set" do
let(:version_option) { "1.0.0" }
before { argv.push("--versions").push(version_option) }
it "should show box with version option set" do
expect(subject).to receive(:show_box).
with(org_name, box_name, access_token, hash_including(versions: [version_option]))
subject.execute
end
end
end
end
end

View File

@ -1,64 +1,146 @@
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(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:account) { double("account") }
let(:organization) { double("organization") }
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
describe "#update_box" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_box).with(account: account, org: org_name, box: box_name).
and_yield(box)
allow(account).to receive(:organization).with(name: org_name).
and_return(organization)
allow(subject).to receive(:format_box_results)
allow(box).to receive(:save)
end
subject { described_class.new(argv, env) }
it "should save the box" do
expect(box).to receive(:save)
subject.update_box(org_name, box_name, access_token, options)
end
it "should return 0 on success" do
result = subject.update_box(org_name, box_name, access_token, options)
expect(result).to eq(0)
end
it "should return non-zero on error" do
expect(box).to receive(:save).and_raise(VagrantCloud::Error)
result = subject.update_box(org_name, box_name, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
it "should display the box information" do
expect(subject).to receive(:format_box_results).with(box, env)
subject.update_box(org_name, box_name, access_token, options)
end
context "with options set" do
let(:options) { {short: short, description: description, private: priv} }
let(:short) { double("short") }
let(:description) { double("description") }
let(:priv) { double("private") }
it "should set box info" do
expect(box).to receive(:short_description=).with(short)
expect(box).to receive(:description=).with(description)
expect(box).to receive(:private=).with(priv)
subject.update_box(org_name, box_name, access_token, options)
end
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)
describe "#execute" do
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
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)
subject { described_class.new(argv, iso_env) }
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)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).and_return(client)
allow(subject).to receive(:update_box)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "should show help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with description flag set" do
let(:description) { "my-description" }
before { argv.push("--description").push(description) }
it "should update box with description" do
expect(subject).to receive(:update_box).
with(org_name, box_name, access_token, hash_including(description: description))
subject.execute
end
end
context "with short flag set" do
let(:description) { "my-description" }
before { argv.push("--short-description").push(description) }
it "should update box with short description" do
expect(subject).to receive(:update_box).
with(org_name, box_name, access_token, hash_including(short: description))
subject.execute
end
end
context "with private flag set" do
before { argv.push("--private") }
it "should update box with private" do
expect(subject).to receive(:update_box).
with(org_name, box_name, access_token, hash_including(private: true))
subject.execute
end
end
end
end
end

View File

@ -6,6 +6,8 @@ describe VagrantPlugins::CloudCommand::Client do
include_context "unit"
let(:env) { isolated_environment.create_vagrant_env }
let(:token) { nil }
let(:vc_client) { double("vagrantcloud-client", access_token: token) }
subject(:client) { described_class.new(env) }
@ -16,246 +18,246 @@ describe VagrantPlugins::CloudCommand::Client do
before do
stub_env("ATLAS_TOKEN" => nil)
subject.clear_token
stub_env("VAGRANT_CLOUD_TOKEN" => nil)
allow(VagrantCloud::Client).to receive(:new).and_return(vc_client)
allow(Vagrant::Util::CredentialScrubber).to receive(:sensitive)
end
after do
Vagrant::Util::CredentialScrubber.reset!
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)
context "when token is not set" do
it "should return false" do
expect(subject.logged_in?).to be_falsey
end
end
context "when there is a token" do
let(:token) { "ABCD1234" }
context "when token is set" do
let(:token) { double("token") }
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)
before do
allow(vc_client).to receive(:authentication_token_validate)
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)
it "should return true when token is valid" do
expect(subject.logged_in?).to be_truthy
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)
it "should validate the set token" do
expect(vc_client).to receive(:authentication_token_validate)
subject.logged_in?
end
it "should return false when token does not validate" do
expect(vc_client).to receive(:authentication_token_validate).
and_raise(Excon::Error::Unauthorized.new(StandardError.new))
expect(subject.logged_in?).to be_falsey
end
it "should add token to scrubber" do
expect(Vagrant::Util::CredentialScrubber).to receive(:sensitive).with(token)
subject.logged_in?
end
end
end
describe "#login" do
let(:request) {
{
user: {
login: login,
password: password,
},
token: {
description: description,
},
two_factor: {
code: nil
}
}
}
let(:new_token) { double("new-token") }
let(:result) { {token: new_token} }
let(:password) { double("password") }
let(:username) { double("username") }
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")
before do
subject.username_or_email = username
subject.password = password
allow(vc_client).to receive(:authentication_token_create).
and_return(result)
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
it "should add password to scrubber" do
expect(Vagrant::Util::CredentialScrubber).to receive(:sensitive).with(password)
subject.login
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
it "should create an authentication token" do
expect(vc_client).to receive(:authentication_token_create).
and_return(result)
subject.login
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 "should wrap remote request to handle errors" do
expect(subject).to receive(:with_error_handling)
subject.login
end
it "raises an exception" do
expect {
subject.login
}.to raise_error(VagrantPlugins::CloudCommand::Errors::ServerUnreachable)
it "should add new token to scrubber" do
expect(Vagrant::Util::CredentialScrubber).to receive(:sensitive).with(new_token)
subject.login
end
it "should create a new internal client" do
expect(VagrantCloud::Client).to receive(:new).with(access_token: new_token)
subject.login
end
it "should create authentication token using username and password" do
expect(vc_client).to receive(:authentication_token_create).
with(hash_including(username: username, password: password)).and_return(result)
subject.login
end
it "should return the new token" do
expect(subject.login).to eq(new_token)
end
context "with description and code" do
let(:description) { double("description") }
let(:code) { double("code") }
it "should create authentication token using description and code" do
expect(vc_client).to receive(:authentication_token_create).with(
hash_including(username: username, password: password,
description: description, code: code))
subject.login(description: description, code: code)
end
end
end
describe "#request_code" do
let(:request) {
{
user: {
login: login,
password: password,
},
two_factor: {
delivery_method: delivery_method
}
}
}
let(:password) { double("password") }
let(:username) { double("username") }
let(:delivery_method) { double("delivery-method", upcase: nil) }
let(:result) { {two_factor: two_factor} }
let(:two_factor) { {obfuscated_destination: obfuscated_destination} }
let(:obfuscated_destination) { double("obfuscated-destination", to_s: "2FA_DESTINATION") }
let(:login) { "foo" }
let(:password) { "supersecretpassword" }
let(:delivery_method) { "sms" }
before do
subject.password = password
subject.username_or_email = username
allow(vc_client).to receive(:authentication_request_2fa_code).and_return(result)
end
let(:headers) {
{
"Accept" => "application/json",
"Content-Type" => "application/json"
}
}
it "should add password to scrubber" do
expect(Vagrant::Util::CredentialScrubber).to receive(:sensitive).with(password)
subject.request_code(delivery_method)
end
let(:response) {
{
two_factor: {
obfuscated_destination: "SMS number ending in 1234"
}
}
}
it "should request the code" do
expect(vc_client).to receive(:authentication_request_2fa_code).with(
hash_including(username: username, password: password, delivery_method: delivery_method))
subject.request_code(delivery_method)
end
it "displays that the code was sent" do
expect(env.ui)
.to receive(:success)
.with("2FA code sent to SMS number ending in 1234.")
it "should print the destination" do
expect(env.ui).to receive(:success).with(/2FA_DESTINATION/)
subject.request_code(delivery_method)
end
end
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))
describe "#store_token" do
let(:token_path) { double("token-path") }
let(:new_token) { double("new-token") }
client.username_or_email = login
client.password = password
before do
allow(subject).to receive(:token_path).and_return(token_path)
allow(token_path).to receive(:open)
end
client.request_code delivery_method
it "should add token to scrubber" do
expect(Vagrant::Util::CredentialScrubber).to receive(:sensitive).with(new_token)
subject.store_token(new_token)
end
it "should create a new internal client with token" do
expect(VagrantCloud::Client).to receive(:new).with(access_token: new_token)
subject.store_token(new_token)
end
it "should open the token path and write the new token" do
f = double("file")
expect(token_path).to receive(:open).with("w").and_yield(f)
expect(f).to receive(:write).with(new_token)
subject.store_token(new_token)
end
end
describe "#token" do
it "reads ATLAS_TOKEN" do
stub_env("ATLAS_TOKEN" => "ABCD1234")
expect(subject.token).to eq("ABCD1234")
let(:env_token) { "ENV_TOKEN" }
let(:file_token) { "FILE_TOKEN" }
let(:token_path) { double("token-path", read: file_token) }
let(:path_exists) { false }
before do
expect(subject).to receive(:token).and_call_original
allow(subject).to receive(:token_path).and_return(token_path)
allow(token_path).to receive(:exist?).and_return(path_exists)
end
it "reads the stored file" do
subject.store_token("EFGH5678")
expect(subject.token).to eq("EFGH5678")
context "when VAGRANT_CLOUD_TOKEN env var is set" do
before { stub_env("VAGRANT_CLOUD_TOKEN" => env_token) }
it "should return the env token" do
expect(subject.token).to eq(env_token)
end
context "when token path exists" do
let(:path_exists) { true }
it "should return the env token" do
expect(subject.token).to eq(env_token)
end
it "should print warning of two tokens" do
expect(env.ui).to receive(:warn)
subject.token
end
end
end
it "prefers the environment variable" do
stub_env("VAGRANT_CLOUD_TOKEN" => "ABCD1234")
subject.store_token("EFGH5678")
expect(subject.token).to eq("ABCD1234")
context "when token path exists" do
let(:path_exists) { true }
it "should return the stored token" do
expect(subject.token).to eq(file_token)
end
context "when VAGRANT_CLOUD_TOKEN env var is set" do
before { stub_env("VAGRANT_CLOUD_TOKEN" => env_token) }
it "should return the env token" do
expect(subject.token).to eq(env_token)
end
end
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
context "when ATLAS_TOKEN env var is set" do
before { stub_env("ATLAS_TOKEN" => env_token) }
it "returns nil if there's no token set" do
expect(subject.token).to be(nil)
end
end
it "should return the env token" do
expect(subject.token).to eq(env_token)
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
context "when VAGRANT_CLOUD_TOKEN is set" do
let(:vc_token) { "VC_TOKEN" }
it "deletes the token" do
subject.store_token("foo")
subject.clear_token
expect(subject.token).to be_nil
before { stub_env("VAGRANT_CLOUD_TOKEN" => vc_token) }
it "should return the VAGRANT_CLOUD_TOKEN value" do
expect(subject.token).to eq(vc_token)
end
end
context "when file exists" do
let(:path_exists) { true }
it "should return the file token" do
expect(subject.token).to eq(file_token)
end
end
end
end
end

View File

@ -1,85 +1,174 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { "0.1.0" }
let(:provider_name) { "my-provider" }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version, providers: [provider]) }
let(:provider) { double("provider", name: provider_name) }
let(:provider_url) { double("provider_url") }
subject { described_class.new(argv, iso_env) }
describe "#create_provider" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
let(:action_runner) { double("action_runner") }
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_version).with(account: account, org: org_name, box: box_name, version: box_version).
and_yield(version)
allow(account).to receive(:organization).with(name: org_name).
and_return(organization)
allow(version).to receive(:add_provider).and_return(provider)
allow(provider).to receive(:save)
allow(provider).to receive(:url=)
allow(subject).to receive(:format_box_results)
end
let(:client) { double("client", token: "1234token1234") }
let(:box) { double("box") }
let(:version) { double("version") }
let(:provider) { double("provider") }
subject { described_class.new(argv, env) }
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
it "should add a new provider to the box version" do
expect(version).to receive(:add_provider).with(provider_name)
subject.create_provider(org_name, box_name, box_version, provider_name, provider_url, access_token, options)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
it "should not set checksum or checksum_type when not provided" do
expect(provider).not_to receive(:checksum=)
expect(provider).not_to receive(:checksum_type=)
subject.create_provider(org_name, box_name, box_version, provider_name, provider_url, access_token, options)
end
context "with checksum and checksum type options set" do
let(:checksum) { double("checksum") }
let(:checksum_type) { double("checksum_type") }
let(:options) { {checksum: checksum, checksum_type: checksum_type} }
it "should set the checksum and checksum type" do
expect(provider).to receive(:checksum=).with(checksum)
expect(provider).to receive(:checksum_type=).with(checksum_type)
subject.create_provider(org_name, box_name, box_version, provider_name, provider_url, access_token, options)
end
end
context "when URL is set" do
it "should set the URL" do
expect(provider).to receive(:url=).with(provider_url)
subject.create_provider(org_name, box_name, box_version, provider_name, provider_url, access_token, options)
end
end
context "when URL is not set" do
let(:provider_url) { nil }
it "should not set the URL" do
expect(provider).not_to receive(:url=).with(provider_url)
subject.create_provider(org_name, box_name, box_version, provider_name, provider_url, access_token, options)
end
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, nil, nil, nil).
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)
describe "#execute" do
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
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, nil, nil, nil).
and_return(provider)
subject { described_class.new(argv, iso_env) }
allow(provider).to receive(:create_provider).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 422))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:create_provider)
end
end
context "with arguments and a remote url" do
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0", "https://example.com/box"] }
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
it "creates a provider" do
allow(VagrantCloud::Provider).to receive(:new).
with(version, "virtualbox", nil, "https://example.com/box", "vagrant", "box-name", client.token, nil, nil, nil).
and_return(provider)
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
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)
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with provider argument" do
let(:provider_arg) { "my-provider" }
before { argv << provider_arg }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "should create the provider" do
expect(subject).to receive(:create_provider).with(org_name, box_name, version_arg, provider_arg, any_args)
subject.execute
end
it "should not provide URL value" do
expect(subject).to receive(:create_provider).with(org_name, box_name, version_arg, provider_arg, nil, any_args)
subject.execute
end
context "with URL argument" do
let(:url_arg) { "provider-url" }
before { argv << url_arg }
it "should provide the URL value" do
expect(subject).to receive(:create_provider).with(org_name, box_name, version_arg, provider_arg, url_arg, any_args)
subject.execute
end
end
context "with checksum and checksum type flags" do
let(:checksum_arg) { "checksum" }
let(:checksum_type_arg) { "checksum_type" }
before { argv.push("--checksum").push(checksum_arg).push("--checksum-type").push(checksum_type_arg) }
it "should include the checksum options" do
expect(subject).to receive(:create_provider).
with(org_name, box_name, version_arg, provider_arg, any_args, hash_including(checksum: checksum_arg, checksum_type: checksum_type_arg))
subject.execute
end
end
end
end
end
end
end

View File

@ -1,70 +1,140 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { "1.0.0" }
let(:box_version_provider) { "my-provider" }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version, providers: [provider]) }
let(:provider) { double("provider", name: box_version_provider) }
subject { described_class.new(argv, iso_env) }
describe "#delete_provider" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
let(:action_runner) { double("action_runner") }
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_provider).
with(account: account, org: org_name, box: box_name, version: box_version, provider: box_version_provider).
and_yield(provider)
allow(provider).to receive(:delete)
end
let(:client) { double("client", token: "1234token1234") }
let(:box) { double("box") }
let(:version) { double("version") }
let(:provider) { double("provider") }
subject { described_class.new(argv, env) }
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
it "should delete the provider" do
expect(provider).to receive(:delete)
subject.delete_provider(org_name, box_name, box_version, box_version_provider, access_token, options)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
it "should return zero on success" do
r = subject.delete_provider(org_name, box_name, box_version, box_version_provider, access_token, options)
expect(r).to eq(0)
end
context "when error is encountered" do
before do
expect(provider).to receive(:delete).and_raise(VagrantCloud::Error)
end
it "should return non-zero" do
r = subject.delete_provider(org_name, box_name, box_version, box_version_provider, access_token, options)
expect(r).to be_a(Integer)
expect(r).not_to eq(0)
end
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)
describe "#execute" do
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
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)
subject { described_class.new(argv, iso_env) }
allow(provider).to receive(:delete).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(iso_env.ui).to receive(:ask).
and_return("y")
allow(subject).to receive(:delete_provider)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with provider argument" do
let(:provider_arg) { "my-provider" }
before { argv << provider_arg }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "should delete the provider" do
expect(subject).to receive(:delete_provider).
with(org_name, box_name, version_arg, provider_arg, access_token, anything)
subject.execute
end
it "should prompt for confirmation" do
expect(iso_env.ui).to receive(:ask).and_return("y")
subject.execute
end
context "with force flag" do
before { argv << "--force" }
it "should not prompt for confirmation" do
expect(iso_env.ui).not_to receive(:ask)
subject.execute
end
end
end
end
end
end
end

View File

@ -1,85 +1,175 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { "1.0.0" }
let(:box_version_provider) { "my-provider" }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version, provdiers: [provider]) }
let(:provider) { double("provider", name: box_version_provider) }
let(:provider_url) { nil }
subject { described_class.new(argv, iso_env) }
describe "#update_provider" do
let(:argv) { [] }
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:action_runner) { double("action_runner") }
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_provider).
with(account: account, org: org_name, box: box_name, version: box_version, provider: box_version_provider).
and_yield(provider)
allow(provider).to receive(:save)
allow(subject).to receive(:format_box_results)
end
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) }
subject { described_class.new(argv, env) }
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
it "should update the provider" do
expect(provider).to receive(:save)
subject.update_provider(org_name, box_name, box_version, box_version_provider, provider_url, access_token, options)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
it "should return 0 on success" do
result = subject.update_provider(org_name, box_name, box_version, box_version_provider, provider_url, access_token, options)
expect(result).to eq(0)
end
it "should return non-zero result on error" do
expect(provider).to receive(:save).and_raise(VagrantCloud::Error)
result = subject.update_provider(org_name, box_name, box_version, box_version_provider, provider_url, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
it "should not update the URL when unset" do
expect(provider).not_to receive(:url=)
subject.update_provider(org_name, box_name, box_version, box_version_provider, provider_url, access_token, options)
end
context "when URL is set" do
let(:provider_url) { double("provider-url") }
it "should update the URL" do
expect(provider).to receive(:url=).with(provider_url)
subject.update_provider(org_name, box_name, box_version, box_version_provider, provider_url, access_token, options)
end
end
context "with options set" do
let(:checksum) { double("checksum") }
let(:checksum_type) { double("checksum_type") }
let(:options) { {checksum: checksum, checksum_type: checksum_type} }
it "should set checksum options before saving" do
expect(provider).to receive(:checksum=).with(checksum)
expect(provider).to receive(:checksum_type=).with(checksum_type)
subject.update_provider(org_name, box_name, box_version, box_version_provider, provider_url, access_token, options)
end
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, nil, nil, nil).
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)
describe "#execute" do
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
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, nil, nil, nil).
and_return(provider)
subject { described_class.new(argv, iso_env) }
allow(provider).to receive(:update).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:update_provider)
end
end
context "with arguments and a remote url" do
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0", "https://example.com/box"] }
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
it "creates a provider" do
allow(VagrantCloud::Provider).to receive(:new).
with(version, "virtualbox", nil, "https://example.com/box", "vagrant", "box-name", client.token, nil, nil, nil).
and_return(provider)
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
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)
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with provider argument" do
let(:provider_arg) { "my-provider" }
before { argv << provider_arg }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "should create the provider" do
expect(subject).to receive(:update_provider).with(org_name, box_name, version_arg, provider_arg, any_args)
subject.execute
end
it "should not provide URL value" do
expect(subject).to receive(:update_provider).with(org_name, box_name, version_arg, provider_arg, nil, any_args)
subject.execute
end
context "with URL argument" do
let(:url_arg) { "provider-url" }
before { argv << url_arg }
it "should provide the URL value" do
expect(subject).to receive(:update_provider).with(org_name, box_name, version_arg, provider_arg, url_arg, any_args)
subject.execute
end
end
context "with checksum and checksum type flags" do
let(:checksum_arg) { "checksum" }
let(:checksum_type_arg) { "checksum_type" }
before { argv.push("--checksum").push(checksum_arg).push("--checksum-type").push(checksum_type_arg) }
it "should include the checksum options" do
expect(subject).to receive(:update_provider).
with(org_name, box_name, version_arg, provider_arg, any_args, hash_including(checksum: checksum_arg, checksum_type: checksum_type_arg))
subject.execute
end
end
end
end
end
end
end

View File

@ -1,79 +1,184 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { "1.0.0" }
let(:box_version_provider) { "my-provider" }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version, provdiers: [provider]) }
let(:provider) { double("provider", name: box_version_provider) }
let(:provider_file) { double("provider-file") }
subject { described_class.new(argv, iso_env) }
describe "#upload_provider" do
let(:argv) { [] }
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:upload_url) { double("upload-url") }
let(:uploader) { double("uploader") }
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)
before do
allow(ui).to receive(:info)
allow(ui).to receive(:output)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(I18n).to receive(:t)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_provider).
with(account: account, org: org_name, box: box_name, version: box_version, provider: box_version_provider).
and_yield(provider)
allow(provider).to receive(:upload).and_yield(upload_url)
allow(uploader).to receive(:upload!)
allow(Vagrant::UI::Prefixed).to receive(:new).with(ui, "cloud").and_return(ui)
allow(Vagrant::Util::Uploader).to receive(:new).and_return(uploader)
end
end
context "with arguments" do
let (:argv) { ["vagrant/box-name", "virtualbox", "1.0.0", "path/to/box.box"] }
subject { described_class.new(argv, env) }
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://example.com/there")
allow(Vagrant::Util::Uploader).to receive(:new).
with("http://example.com/there", "path/to/box.box", {ui: anything}).
and_return(uploader)
it "should upload the provider file" do
expect(provider).to receive(:upload)
subject.upload_provider(org_name, box_name, box_version, box_version_provider, provider_file, access_token, options)
end
it "should return zero on success" do
r = subject.upload_provider(org_name, box_name, box_version, box_version_provider, provider_file, access_token, options)
expect(r).to eq(0)
end
it "should return non-zero on API error" do
expect(provider).to receive(:upload).and_raise(VagrantCloud::Error)
r = subject.upload_provider(org_name, box_name, box_version, box_version_provider, provider_file, access_token, options)
expect(r).not_to eq(0)
expect(r).to be_a(Integer)
end
it "should return non-zero on upload error" do
expect(provider).to receive(:upload).and_raise(Vagrant::Errors::UploaderError)
r = subject.upload_provider(org_name, box_name, box_version, box_version_provider, provider_file, access_token, options)
expect(r).not_to eq(0)
expect(r).to be_a(Integer)
end
it "should should upload via uploader" do
expect(uploader).to receive(:upload!)
expect(subject.execute).to eq(0)
subject.upload_provider(org_name, box_name, box_version, box_version_provider, provider_file, access_token, options)
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://example.com/there")
allow(Vagrant::Util::Uploader).to receive(:new).
with("http://example.com/there", "path/to/box.box", {ui: anything}).
and_return(uploader)
it "should not use direct upload by default" do
expect(provider).to receive(:upload) do |**args|
expect(args[:direct]).to be_falsey
end
subject.upload_provider(org_name, box_name, box_version, box_version_provider, provider_file, access_token, options)
end
allow(uploader).to receive(:upload!).
and_raise(Vagrant::Errors::UploaderError.new(exit_code: 1, message: "Error"))
expect(subject.execute).to eq(1)
context "with direct option" do
let(:options) { {direct: true} }
it "should use direct upload" do
expect(provider).to receive(:upload) do |**args|
expect(args[:direct]).to be_truthy
end
subject.upload_provider(org_name, box_name, box_version, box_version_provider, provider_file, access_token, options)
end
end
end
describe "#execute" do
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: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:upload_provider)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with provider argument" do
let(:provider_arg) { "my-provider" }
before { argv << provider_arg }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with file argument" do
let(:file_arg) { "/dev/null/file" }
before { argv << file_arg }
it "should upload the provider file" do
expect(subject).to receive(:upload_provider).
with(org_name, box_name, version_arg, provider_arg, file_arg, any_args)
subject.execute
end
it "should do direct upload by default" do
expect(subject).to receive(:upload_provider).
with(any_args, hash_including(direct: true))
subject.execute
end
context "with --no-direct flag" do
before { argv << "--no-direct" }
it "should not perform direct upload" do
expect(subject).to receive(:upload_provider).
with(any_args, hash_including(direct: false))
subject.execute
end
end
end
end
end
end
end
end

View File

@ -5,127 +5,316 @@ 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") }
let(:argv) { [] }
let(:iso_env) { double("iso_env") }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box") }
let(:version) { double("version") }
let(:provider) { double("provider") }
let(:uploader) { double("uploader") }
let(:ui) { double("ui") }
let(:upload_url) { double("upload_url") }
let(:access_token) { double("access_token") }
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}")
allow(File).to receive(:file?).and_return(true)
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(iso_env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: anything).
and_return(account)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "missing required arguments" do
let(:argv) { ["vagrant/box", "1.0.0", "virtualbox"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "missing box file" do
let(:argv) { ["vagrant/box", "1.0.0", "virtualbox", "/notreal/file.box"] }
it "raises an exception" do
allow(File).to receive(:file?).and_return(false)
expect { subject.execute }.
to raise_error(Vagrant::Errors::BoxFileNotExist)
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://example.com/there")
allow(Vagrant::Util::Uploader).to receive(:new).
with("http://example.com/there", "/full/path/to/the/virtualbox.box", {ui: anything}).
and_return(uploader)
describe "#upload_box_file" do
before do
allow(provider).to receive(:upload).and_yield(upload_url)
allow(uploader).to receive(:upload!)
expect(VagrantPlugins::CloudCommand::Util).to receive(:format_box_results)
expect(subject.execute).to eq(0)
allow(File).to receive(:absolute_path).and_return(box)
allow(Vagrant::Util::Uploader).to receive(:new).and_return(uploader)
end
it "catches a ClientError if something goes wrong" do
allow(provider).to receive(:upload_url).and_return("http://example.com/there")
allow(Vagrant::Util::Uploader).to receive(:new).
with("http://example.com/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)
it "should get absolute path for box file" do
expect(File).to receive(:absolute_path).and_return(box)
subject.upload_box_file(provider, box)
end
it "calls update if entity already exists" do
allow(provider).to receive(:upload_url).and_return("http://example.com/there")
allow(Vagrant::Util::Uploader).to receive(:new).
with("http://example.com/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)
it "should upload through provider" do
expect(provider).to receive(:upload).and_return(upload_url)
subject.upload_box_file(provider, box)
end
it "should create uploader with given url" do
expect(Vagrant::Util::Uploader).to receive(:new).
with(upload_url, any_args).and_return(uploader)
subject.upload_box_file(provider, box)
end
it "should upload with PUT method by default" do
expect(Vagrant::Util::Uploader).to receive(:new).
with(upload_url, anything, hash_including(method: :put)).and_return(uploader)
subject.upload_box_file(provider, box)
end
it "should upload with PUT method when direct upload option set" do
expect(Vagrant::Util::Uploader).to receive(:new).
with(upload_url, anything, hash_including(method: :put)).and_return(uploader)
subject.upload_box_file(provider, box, direct_upload: true)
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://example.com/there")
allow(Vagrant::Util::Uploader).to receive(:new).
with("http://example.com/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)
describe "#release_version" do
it "should release the version" do
expect(version).to receive(:release)
expect(subject.execute).to eq(0)
subject.release_version(version)
end
end
context "with arguments and a remote url" do
let(:argv) { ["vagrant/box", "1.0.0", "virtualbox", "--url", "https://www.example.com/path/to/the/virtualbox.box"] }
describe "#set_box_info" do
context "with no options set" do
let(:options) { {} }
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)
it "should not modify the box" do
subject.set_box_info(box, options)
end
end
context "with options set" do
let(:priv) { double("private") }
let(:short_description) { double("short_description") }
let(:description) { double("description") }
let(:options) {
{private: priv, description: description, short_description: short_description}
}
it "should set info on box" do
expect(box).to receive(:private=).with(priv)
expect(box).to receive(:short_description=).with(short_description)
expect(box).to receive(:description=).with(description)
subject.set_box_info(box, options)
end
end
end
describe "#set_version_info" do
context "with no options set" do
let(:options) { {} }
it "should not modify the verison" do
subject.set_version_info(version, options)
end
end
context "with options set" do
let(:options) { {version_description: version_description} }
let(:version_description) { double("version_description") }
it "should set info on version" do
expect(version).to receive(:description=).with(version_description)
subject.set_version_info(version, options)
end
end
end
describe "#set_provider_info" do
context "with no options set" do
let(:options) { {} }
it "should not modify the provider" do
subject.set_provider_info(provider, options)
end
end
context "with options set" do
let(:options) { {url: url, checksum: checksum, checksum_type: checksum_type} }
let(:url) { double("url") }
let(:checksum) { double("checksum") }
let(:checksum_type) { double("checksum_type") }
it "should set info on provider" do
expect(provider).to receive(:url=).with(url)
expect(provider).to receive(:checksum=).with(checksum)
expect(provider).to receive(:checksum_type=).with(checksum_type)
subject.set_provider_info(provider, options)
end
end
end
describe "load_box_version" do
let(:box_version) { "1.0.0" }
context "when vesion exists" do
before do
allow(box).to receive(:versions).and_return([version])
allow(version).to receive(:version).and_return(box_version)
end
it "should return the existing version" do
expect(subject.load_box_version(box, box_version)).to eq(version)
end
end
context "when version does not exist" do
let(:new_version) { double("new_version") }
before do
allow(box).to receive(:versions).and_return([version])
allow(version).to receive(:version)
end
it "should add a new version" do
expect(box).to receive(:add_version).with(box_version).
and_return(new_version)
expect(subject.load_box_version(box, box_version)).to eq(new_version)
end
end
end
describe "#load_box" do
let(:org_name) { "org-name" }
let(:box_name) { "my-box" }
before do
allow(account).to receive(:organization).with(name: org_name).
and_return(organization)
end
context "when box exists" do
before do
allow(box).to receive(:name).and_return(box_name)
allow(organization).to receive(:boxes).and_return([box])
end
it "should return the existing box" do
expect(subject.load_box(org_name, box_name, access_token)).to eq(box)
end
end
context "when box does not exist" do
let(:new_box) { double("new_box") }
before do
allow(organization).to receive(:boxes).and_return([])
end
it "should add a new box to organization" do
expect(organization).to receive(:add_box).with(box_name).
and_return(new_box)
expect(subject.load_box(org_name, box_name, access_token)).to eq(new_box)
end
end
end
context "#execute" do
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") }
let(:action_runner) { double("action_runner") }
let(:box_path) { "path/to/the/virtualbox.box" }
before do
allow(iso_env).to receive(:action_runner).
and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:format_box_results)
allow(iso_env.ui).to receive(:ask).and_return("y")
allow(File).to receive(:absolute_path).and_return("/full/#{box_path}")
allow(File).to receive(:file?).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 "missing required arguments" do
let(:argv) { ["vagrant/box", "1.0.0", "virtualbox"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "missing box file" do
let(:argv) { ["vagrant/box", "1.0.0", "virtualbox", "/notreal/file.box"] }
it "raises an exception" do
allow(File).to receive(:file?).and_return(false)
expect { subject.execute }.
to raise_error(Vagrant::Errors::BoxFileNotExist)
end
end
context "with arguments" do
let(:org_name) { "vagrant" }
let(:box_name) { "box" }
let(:box_version) { "1.0.0" }
let(:box_version_provider) { "virtualbox" }
let(:argv) { [
"#{org_name}/#{box_name}", box_version, box_version_provider, box_path
] }
before do
allow(account).to receive(:organization).with(name: org_name).
and_return(organization)
allow(subject).to receive(:load_box).and_return(box)
allow(subject).to receive(:load_box_version).and_return(version)
allow(subject).to receive(:load_version_provider).and_return(provider)
allow(provider).to receive(:upload)
allow(box).to receive(:save)
end
it "should prompt user for confirmation" do
expect(iso_env.ui).to receive(:ask).and_return("y")
expect(subject.execute).to eq(0)
end
context "when --force option is provided" do
before { argv << "--force" }
it "should not prompt user for confirmation" do
expect(iso_env.ui).not_to receive(:ask)
expect(subject.execute).to eq(0)
end
end
context "when --release option is provided" do
before do
argv << "--release"
end
it "should release box version when not released" do
expect(version).to receive(:released?).and_return(false)
expect(version).to receive(:release)
expect(subject.execute).to eq(0)
end
end
context "when Vagrant Cloud error is encountered" do
before { expect(box).to receive(:save).and_raise(VagrantCloud::Error) }
it "should return non-zero result" do
result = subject.execute
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
end
end
end
end

View File

@ -5,6 +5,7 @@ require Vagrant.source_root.join("plugins/commands/cloud/search")
describe VagrantPlugins::CloudCommand::Command::Search do
include_context "unit"
let(:token) { double("token") }
let(:argv) { [] }
let(:iso_env) do
# We have to create a Vagrantfile so there is a root path
@ -13,65 +14,146 @@ describe VagrantPlugins::CloudCommand::Command::Search do
env.create_vagrant_env
end
let(:client) { double("client", token: "1234token1234") }
subject { described_class.new(argv, iso_env) }
let(:action_runner) { double("action_runner") }
describe "#search" do
let(:query) { double("query") }
let(:options) { {} }
let(:account) { double("account", searcher: searcher) }
let(:searcher) { double("searcher") }
let(:results) { double("results", boxes: boxes) }
let(:boxes) { [] }
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
before do
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: token).and_return(account)
allow(searcher).to receive(:search).and_return(results)
allow(subject).to receive(:format_search_results)
end
context "with no arguments" do
let (:search) { double("search", search: {"boxes"=>["all of them"]}) }
it "should perform search" do
expect(searcher).to receive(:search).with(hash_including(query: query)).and_return(results)
subject.search(query, token, options)
end
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)
it "should print a warning when no results are found" do
expect(iso_env.ui).to receive(:warn)
subject.search(query, token, options)
end
context "with valid options" do
let(:provider) { double("provider") }
let(:sort) { double("sort") }
let(:order) { double("order") }
let(:limit) { double("limit") }
let(:page) { double("page") }
let(:options) { {
provider: provider,
sort: sort,
order: order,
limit: limit,
page: page
} }
it "should use options when performing search" do
expect(searcher).to receive(:search) do |**args|
options.each_pair do |k, v|
expect(args[k]).to eq(v)
end
results
end
subject.search(query, token, options)
end
context "with invalid options" do
before { options[:invalid_option] = "testing" }
it "should only pass supported options to search" do
expect(searcher).to receive(:search) do |**args|
options.each_pair do |k, v|
next if k == :invalid_option
expect(args[k]).to eq(v)
end
expect(args.key?(:invalid_option)).to be_falsey
results
end
subject.search(query, token, options)
end
end
end
context "with search results" do
let(:results) { double("results", boxes: [double("result")]) }
it "should format the results" do
expect(subject).to receive(:format_search_results).with(results.boxes, any_args)
subject.search(query, token, options)
end
context "with format options" do
let(:options) { {short: true, json: false} }
it "should pass options to format" do
expect(subject).to receive(:format_search_results).with(results.boxes, true, false, iso_env)
subject.search(query, token, options)
end
end
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)
describe "#execute" do
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
end
context "with no arguments and no results" do
let (:search) { double("search", search: {"boxes"=>[]}) }
subject { described_class.new(argv, iso_env) }
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
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: token) }
let(:box) { double("box") }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).and_return(client)
allow(subject).to receive(:search)
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"] }
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
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
context "with query argument" do
let(:query_arg) { "search-query" }
before { argv << query_arg }
it "should run the search" do
expect(subject).to receive(:search).with(query_arg, any_args)
subject.execute
end
it "should setup client login quietly by default" do
expect(subject).to receive(:client_login).with(iso_env, hash_including(quiet: true))
subject.execute
end
context "with --auth flag" do
before { argv << "--auth" }
it "should not setup login client quietly" do
expect(subject).to receive(:client_login).with(iso_env, hash_including(quiet: false))
subject.execute
end
end
end
end
end

View File

@ -1,65 +1,135 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { double("box_version") }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version) }
subject { described_class.new(argv, iso_env) }
describe "#create_version" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
let(:action_runner) { double("action_runner") }
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_box).with(account: account, org: org_name, box: box_name).
and_yield(box)
allow(account).to receive(:organization).with(name: org_name).
and_return(organization)
allow(box).to receive(:add_version).and_return(version)
allow(version).to receive(:save)
allow(subject).to receive(:format_box_results)
end
let(:client) { double("client", token: "1234token1234") }
let(:box) { double("box") }
let(:version) { double("version") }
subject { described_class.new(argv, env) }
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
it "should add a new version to the box" do
expect(box).to receive(:add_version).with(box_version)
subject.create_version(org_name, box_name, box_version, access_token, options)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
it "should save the new version" do
expect(version).to receive(:save)
subject.create_version(org_name, box_name, box_version, access_token, options)
end
it "should return 0 on success" do
result = subject.create_version(org_name, box_name, box_version, access_token, options)
expect(result).to eq(0)
end
it "should return non-zero on error" do
expect(version).to receive(:save).and_raise(VagrantCloud::Error)
result = subject.create_version(org_name, box_name, box_version, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
context "with description option set" do
let(:description) { double("description") }
let(:options) { {description: description} }
it "should set description on version" do
expect(version).to receive(:description=).with(description)
subject.create_version(org_name, box_name, box_version, access_token, options)
end
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)
describe "#execute" do
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
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)
subject { described_class.new(argv, iso_env) }
allow(version).to receive(:create_version).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 422))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:create_version)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "should create the version" do
expect(subject).to receive(:create_version).with(org_name, box_name, version_arg, any_args)
subject.execute
end
context "with description flag" do
let(:description) { "my-description" }
before { argv.push("--description").push(description) }
it "should create version with description option set" do
expect(subject).to receive(:create_version).
with(org_name, box_name, version_arg, access_token, hash_including(description: description))
subject.execute
end
end
end
end
end
end

View File

@ -1,66 +1,122 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { double("box_version") }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version) }
subject { described_class.new(argv, iso_env) }
describe "#delete_version" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
let(:action_runner) { double("action_runner") }
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_version).
with(account: account, org: org_name, box: box_name, version: box_version).
and_yield(version)
allow(version).to receive(:delete)
end
let(:client) { double("client", token: "1234token1234") }
let(:box) { double("box") }
let(:version) { double("version") }
subject { described_class.new(argv, env) }
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
it "should delete the version" do
expect(version).to receive(:delete)
subject.delete_version(org_name, box_name, box_version, access_token, options)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
it "should return 0 on success" do
result = subject.delete_version(org_name, box_name, box_version, access_token, options)
expect(result).to eq(0)
end
it "should return non-zero on error" do
expect(version).to receive(:delete).and_raise(VagrantCloud::Error)
result = subject.delete_version(org_name, box_name, box_version, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
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)
describe "#execute" do
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
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)
subject { described_class.new(argv, iso_env) }
allow(version).to receive(:delete).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(iso_env.ui).to receive(:ask).
and_return("y")
allow(subject).to receive(:delete_version)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "should delete the version" do
expect(subject).to receive(:delete_version).
with(org_name, box_name, version_arg, access_token, anything)
subject.execute
end
it "should prompt for confirmation" do
expect(iso_env.ui).to receive(:ask).and_return("y")
subject.execute
end
context "with force flag" do
before { argv << "--force" }
it "should not prompt for confirmation" do
expect(iso_env.ui).not_to receive(:ask)
subject.execute
end
end
end
end
end
end

View File

@ -1,91 +1,121 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { double("box_version") }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version) }
subject { described_class.new(argv, iso_env) }
describe "#release_version" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
let(:action_runner) { double("action_runner") }
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_version).
with(account: account, org: org_name, box: box_name, version: box_version).
and_yield(version)
allow(version).to receive(:release)
end
let(:client) { double("client", token: "1234token1234") }
let(:box) { double("box") }
let(:version) { double("version") }
subject { described_class.new(argv, env) }
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
it "should release the version" do
expect(version).to receive(:release)
subject.release_version(org_name, box_name, box_version, access_token, options)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
it "should return 0 on success" do
result = subject.release_version(org_name, box_name, box_version, access_token, options)
expect(result).to eq(0)
end
it "should return a non-zero on error" do
expect(version).to receive(:release).and_raise(VagrantCloud::Error)
result = subject.release_version(org_name, box_name, box_version, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
end
context "interactive mode with arguments" do
let (:argv) { ["vagrant/box-name", "1.0.0"] }
it "releases a version" do
allow(iso_env.ui).to receive(:ask).
and_return("y")
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)
describe "#execute" do
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
it "displays an error if encoutering a problem with the request" do
allow(iso_env.ui).to receive(:ask).
and_return("y")
allow(VagrantCloud::Version).to receive(:new).
with(box, "1.0.0", nil, nil, client.token).
and_return(version)
subject { described_class.new(argv, iso_env) }
allow(version).to receive(:release).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
end
end
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
context "non-interactive mode with arguments" do
let (:argv) { ["--force", "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)
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:release_version)
allow(iso_env.ui).to receive(:ask).and_return("y")
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)
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
allow(version).to receive(:release).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
context "with box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "should release the version" do
expect(subject).to receive(:release_version).
with(org_name, box_name, version_arg, access_token, anything)
subject.execute
end
it "should prompt for confirmation" do
expect(iso_env.ui).to receive(:ask).and_return("y")
subject.execute
end
context "with force flag" do
before { argv << "--force" }
it "should not prompt for confirmation" do
expect(iso_env.ui).not_to receive(:ask)
subject.execute
end
end
end
end
end
end

View File

@ -1,66 +1,123 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { double("box_version") }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version) }
subject { described_class.new(argv, iso_env) }
describe "#revoke_version" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
let(:action_runner) { double("action_runner") }
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_version).
with(account: account, org: org_name, box: box_name, version: box_version).
and_yield(version)
allow(version).to receive(:revoke)
allow(subject).to receive(:format_box_results)
end
let(:client) { double("client", token: "1234token1234") }
let(:box) { double("box") }
let(:version) { double("version") }
subject { described_class.new(argv, env) }
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
it "should revoke the version" do
expect(version).to receive(:revoke)
subject.revoke_version(org_name, box_name, box_version, access_token, options)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
it "should return 0 on success" do
result = subject.revoke_version(org_name, box_name, box_version, access_token, options)
expect(result).to eq(0)
end
it "should return non-zero on error" do
expect(version).to receive(:revoke).and_raise(VagrantCloud::Error)
result = subject.revoke_version(org_name, box_name, box_version, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
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)
describe "#execute" do
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
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)
subject { described_class.new(argv, iso_env) }
expect(version).to receive(:revoke).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:revoke_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 box name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "should revoke the version" do
expect(subject).to receive(:revoke_version).
with(org_name, box_name, version_arg, access_token, anything)
subject.execute
end
it "should prompt for confirmation" do
expect(iso_env.ui).to receive(:ask).and_return("y")
subject.execute
end
context "with force flag" do
before { argv << "--force" }
it "should not prompt for confirmation" do
expect(iso_env.ui).not_to receive(:ask)
subject.execute
end
end
end
end
end
end

View File

@ -1,65 +1,129 @@
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
let(:access_token) { double("token") }
let(:org_name) { "my-org" }
let(:box_name) { "my-box" }
let(:box_version) { double("box_version") }
let(:account) { double("account") }
let(:organization) { double("organization") }
let(:box) { double("box", versions: [version]) }
let(:version) { double("version", version: box_version) }
subject { described_class.new(argv, iso_env) }
describe "#update_version" do
let(:options) { {} }
let(:env) { double("env", ui: ui) }
let(:ui) { double("ui") }
let(:argv) { [] }
let(:action_runner) { double("action_runner") }
before do
allow(ui).to receive(:info)
allow(ui).to receive(:warn)
allow(ui).to receive(:success)
allow(ui).to receive(:error)
allow(env).to receive(:ui).and_return(ui)
allow(VagrantCloud::Account).to receive(:new).
with(custom_server: anything, access_token: access_token).
and_return(account)
allow(subject).to receive(:with_version).
with(account: account, org: org_name, box: box_name, version: box_version).
and_yield(version)
allow(version).to receive(:save)
allow(subject).to receive(:format_box_results)
end
let(:client) { double("client", token: "1234token1234") }
let(:box) { double("box") }
let(:version) { double("version") }
subject { described_class.new(argv, env) }
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
it "should update the version" do
expect(version).to receive(:save)
subject.update_version(org_name, box_name, box_version, access_token, options)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
it "should return 0 on success" do
result = subject.update_version(org_name, box_name, box_version, access_token, options)
expect(result).to eq(0)
end
it "should return non-zero result on error" do
expect(version).to receive(:save).and_raise(VagrantCloud::Error)
result = subject.update_version(org_name, box_name, box_version, access_token, options)
expect(result).not_to eq(0)
expect(result).to be_a(Integer)
end
context "with options set" do
let(:description) { double("description") }
let(:options) { {description: description} }
it "should set version info before saving" do
expect(version).to receive(:description=).with(description)
subject.update_version(org_name, box_name, box_version, access_token, options)
end
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)
describe "#execute" do
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
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)
subject { described_class.new(argv, iso_env) }
allow(version).to receive(:update).
and_raise(VagrantCloud::ClientError.new("Fail Message", "Message", 404))
expect(subject.execute).to eq(1)
let(:action_runner) { double("action_runner") }
let(:client) { double("client", token: access_token) }
before do
allow(iso_env).to receive(:action_runner).and_return(action_runner)
allow(subject).to receive(:client_login).
and_return(client)
allow(subject).to receive(:update_version)
end
context "with no arguments" do
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
end
context "with name argument" do
let(:argv) { ["#{org_name}/#{box_name}"] }
it "shows help" do
expect { subject.execute }.
to raise_error(Vagrant::Errors::CLIInvalidUsage)
end
context "with version argument" do
let(:version_arg) { "1.0.0" }
before { argv << version_arg }
it "should update the version" do
expect(subject).to receive(:update_version).
with(org_name, box_name, version_arg, access_token, anything)
subject.execute
end
context "with description flag" do
let(:description) { "my-description" }
before { argv.push("--description").push(description) }
it "should update version with description" do
expect(subject).to receive(:update_version).
with(org_name, box_name, version_arg, access_token, hash_including(description: description))
subject.execute
end
end
end
end
end
end

View File

@ -1,261 +0,0 @@
require File.expand_path("../../../../base", __FILE__)
require Vagrant.source_root.join("plugins/commands/login/command")
describe VagrantPlugins::LoginCommand::Client do
include_context "unit"
let(:env) { isolated_environment.create_vagrant_env }
subject(:client) { described_class.new(env) }
before(:all) do
I18n.load_path << Vagrant.source_root.join("plugins/commands/login/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::LoginCommand::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) { "bar" }
let(:description) { "Token description" }
let(:headers) {
{
"Accept" => "application/json",
"Content-Type" => "application/json",
}
}
let(:response) {
{
token: "baz"
}
}
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("baz")
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::LoginCommand::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::LoginCommand::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::LoginCommand::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::LoginCommand::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) { "bar" }
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

View File

@ -1,96 +0,0 @@
require File.expand_path("../../../../base", __FILE__)
require Vagrant.source_root.join("plugins/commands/login/command")
describe VagrantPlugins::LoginCommand::Command do
include_context "unit"
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
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

View File

@ -5,7 +5,7 @@ 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(:curl_options) { [destination, "--request", "PUT", "--upload-file", file, "--fail", {notify: :stderr}] }
let(:subprocess_result) do
double("subprocess_result").tap do |result|

View File

@ -28,9 +28,8 @@ Gem::Specification.new do |s|
s.add_dependency "net-sftp", "~> 3.0"
s.add_dependency "net-scp", "~> 1.2.0"
s.add_dependency "rb-kqueue", "~> 0.2.0"
s.add_dependency "rest-client", ">= 1.6.0", "< 3.0"
s.add_dependency "rubyzip", "~> 2.0"
s.add_dependency "vagrant_cloud", "~> 2.0.3"
s.add_dependency "vagrant_cloud", "~> 3.0.2"
s.add_dependency "wdm", "~> 0.1.0"
s.add_dependency "winrm", ">= 2.3.4", "< 3.0"
s.add_dependency "winrm-elevated", ">= 1.2.1", "< 2.0"