kontena-cli 1.1.0 → 1.1.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/kontena-cli.gemspec +1 -1
- data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +9 -6
- data/lib/kontena/cli/common.rb +2 -0
- data/lib/kontena/cli/plugins/install_command.rb +4 -0
- data/lib/kontena/cli/services/link_command.rb +12 -4
- data/lib/kontena/cli/services/unlink_command.rb +11 -5
- data/lib/kontena/cli/stacks/service_generator.rb +10 -7
- data/lib/kontena/cli/stacks/yaml/opto.rb +15 -0
- data/lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb +13 -5
- data/lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb +1 -1
- data/lib/kontena/cli/stacks/yaml/opto/service_link_resolver.rb +66 -35
- data/lib/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver.rb +33 -10
- data/lib/kontena/cli/stacks/yaml/opto/vault_resolver.rb +1 -1
- data/lib/kontena/cli/stacks/yaml/opto/vault_setter.rb +1 -2
- data/lib/kontena/cli/stacks/yaml/reader.rb +7 -8
- data/lib/kontena/plugin_manager.rb +1 -2
- data/lib/kontena_cli.rb +1 -1
- data/spec/kontena/cli/cloud/master/add_command_spec.rb +0 -1
- data/spec/kontena/cli/common_spec.rb +28 -21
- data/spec/kontena/cli/master/init_cloud_command_spec.rb +28 -0
- data/spec/kontena/cli/services/link_command_spec.rb +2 -2
- data/spec/kontena/cli/services/unlink_command_spec.rb +1 -1
- data/spec/kontena/cli/stacks/service_generator_spec.rb +7 -3
- data/spec/kontena/cli/stacks/yaml/opto/prompt_resolver_spec.rb +27 -0
- data/spec/kontena/cli/stacks/yaml/opto/service_link_resolver_spec.rb +54 -0
- data/spec/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver_spec.rb +73 -0
- data/spec/kontena/kontena_cli_spec.rb +15 -6
- data/spec/kontena/main_command_spec.rb +16 -0
- metadata +19 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76963be4ff231516ea09ffc1261b2945f7728f78
|
4
|
+
data.tar.gz: ea1f2e4fa944e33af0d7c5b9abea939485805346
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66580e1af2b505487e82ae8458f5fed6f2965438df752e0ae8581108fe067932dc8205276117f3fc0a00bba46ddb17f3c5b19f8d224b82c78cd2e90af8853b0c
|
7
|
+
data.tar.gz: ce4aef539d02fb0ee56f6850a7657d8d0b2466bca5db2d7633ae4d01c28e75ce36330ef1df8a7c46644abd6df79cd8fa9ffbe7d716595bc0155ad71466e8e27f
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.1.rc1
|
data/kontena-cli.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_runtime_dependency "launchy", "~> 2.4.3"
|
30
30
|
spec.add_runtime_dependency "hash_validator", "~> 0.7.0"
|
31
31
|
spec.add_runtime_dependency "retriable", "~> 2.1.0"
|
32
|
-
spec.add_runtime_dependency "opto", "
|
32
|
+
spec.add_runtime_dependency "opto", "1.8.3"
|
33
33
|
spec.add_runtime_dependency "semantic", "~> 1.5"
|
34
34
|
spec.add_runtime_dependency "safe_yaml", "~> 1.0"
|
35
35
|
spec.add_runtime_dependency "liquid", "~> 4.0.0"
|
@@ -4,7 +4,7 @@ module Kontena
|
|
4
4
|
|
5
5
|
include Kontena::Cli::Common
|
6
6
|
|
7
|
-
matches_commands 'master create'
|
7
|
+
matches_commands 'master create', 'master init_cloud'
|
8
8
|
|
9
9
|
def cloud_user_data
|
10
10
|
return @cloud_user_data if @cloud_user_data
|
@@ -27,8 +27,7 @@ module Kontena
|
|
27
27
|
def after
|
28
28
|
return unless current_master
|
29
29
|
return unless command.exit_code == 0
|
30
|
-
return
|
31
|
-
return nil if command.skip_auth_provider?
|
30
|
+
return nil if command.respond_to?(:skip_auth_provider?) && command.skip_auth_provider?
|
32
31
|
return nil unless cloud_user_data
|
33
32
|
|
34
33
|
invite_response = nil
|
@@ -51,11 +50,15 @@ module Kontena
|
|
51
50
|
|
52
51
|
return nil if role_status.to_i > 0
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
if current_master.grid
|
54
|
+
spinner "Adding #{cloud_user_data[:email]} to grid '#{current_master.grid}'" do |spin|
|
55
|
+
grid_add_status = Kontena.run("grid user add --grid #{current_master.grid} #{cloud_user_data[:email].shellescape}")
|
56
|
+
spin.fail if grid_add_status.to_i > 0
|
57
|
+
end
|
57
58
|
end
|
58
59
|
|
60
|
+
return unless current_master.username.to_s == 'admin'
|
61
|
+
|
59
62
|
new_user_token = nil
|
60
63
|
spinner "Creating an access token for #{cloud_user_data[:email]}" do |spin|
|
61
64
|
new_user_token = Kontena.run("master token create -e 0 -s user --return -u #{cloud_user_data[:email].shellescape}", returning: :result)
|
data/lib/kontena/cli/common.rb
CHANGED
@@ -247,6 +247,7 @@ module Kontena
|
|
247
247
|
if self.respond_to?(:force?) && self.force?
|
248
248
|
return
|
249
249
|
end
|
250
|
+
exit_with_error 'Command requires --force' unless $stdout.tty? && $stdin.tty?
|
250
251
|
puts message if message
|
251
252
|
puts "Destructive command. To proceed, type \"#{name}\" or re-run this command with --force option."
|
252
253
|
|
@@ -257,6 +258,7 @@ module Kontena
|
|
257
258
|
if self.respond_to?(:force?) && self.force?
|
258
259
|
return
|
259
260
|
end
|
261
|
+
exit_with_error 'Command requires --force' unless $stdout.tty? && $stdin.tty?
|
260
262
|
prompt.yes?(message) || error('Aborted command.')
|
261
263
|
end
|
262
264
|
|
@@ -23,6 +23,10 @@ module Kontena::Cli::Plugins
|
|
23
23
|
spin.fail!
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
spinner "Running cleanup" do |spin|
|
28
|
+
Kontena::PluginManager.instance.cleanup_plugin(name)
|
29
|
+
end
|
26
30
|
else
|
27
31
|
installed = spinner "Installing plugin #{name.colorize(:cyan)}" do |spin|
|
28
32
|
begin
|
@@ -13,12 +13,20 @@ module Kontena::Cli::Services
|
|
13
13
|
def execute
|
14
14
|
require_api_url
|
15
15
|
token = require_token
|
16
|
+
target_service = target
|
17
|
+
|
18
|
+
target_service = "null/#{target_service}" unless target_service.include?('/')
|
16
19
|
|
17
20
|
service = client(token).get("services/#{parse_service_id(name)}")
|
18
|
-
existing_targets = service['links'].map{|l| l['
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
existing_targets = service['links'].map{ |l| l['id'].split('/', 2)[1] }
|
22
|
+
if existing_targets.include?(target_service.to_s)
|
23
|
+
exit_with_error("Service is already linked to #{target.to_s}")
|
24
|
+
end
|
25
|
+
links = service['links'].map{ |l|
|
26
|
+
{ name: l['id'].split('/', 2)[1], alias: l['alias'] }
|
27
|
+
}
|
28
|
+
links << {name: target_service.to_s, alias: target.to_s}
|
29
|
+
links.compact!
|
22
30
|
data = {links: links}
|
23
31
|
spinner "Linking #{name.colorize(:cyan)} to #{target.colorize(:cyan)} " do
|
24
32
|
update_service(token, name, data)
|
@@ -13,13 +13,19 @@ module Kontena::Cli::Services
|
|
13
13
|
def execute
|
14
14
|
require_api_url
|
15
15
|
token = require_token
|
16
|
-
|
16
|
+
target_service = target
|
17
|
+
target_service = "null/#{target_service}" unless target_service.include?('/')
|
18
|
+
target_id = "#{current_grid}/#{target_service}"
|
17
19
|
service = client(token).get("services/#{parse_service_id(name)}")
|
18
|
-
links = service['links']
|
19
|
-
|
20
|
-
|
20
|
+
links = service['links']
|
21
|
+
unless links.find { |l| l['id'] == target_id }
|
22
|
+
exit_with_error("Service is not linked to #{target.to_s}")
|
23
|
+
end
|
24
|
+
links.delete_if { |l| l['id'] == target_id }
|
21
25
|
data = {links: links}
|
22
|
-
|
26
|
+
spinner "Unlinking #{name.colorize(:cyan)} from #{target.colorize(:cyan)} " do
|
27
|
+
update_service(token, name, data)
|
28
|
+
end
|
23
29
|
end
|
24
30
|
end
|
25
31
|
end
|
@@ -49,13 +49,16 @@ module Kontena::Cli::Stacks
|
|
49
49
|
data['log_opts'] = options['log_opt'] if options['log_opt'] && !options['log_opt'].empty?
|
50
50
|
deploy_opts = options['deploy'] || {}
|
51
51
|
data['strategy'] = deploy_opts['strategy'] if deploy_opts['strategy']
|
52
|
-
deploy = {
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
52
|
+
deploy = {
|
53
|
+
'wait_for_port' => deploy_opts['wait_for_port'],
|
54
|
+
'min_health' => deploy_opts['min_health']
|
55
|
+
}
|
56
|
+
if deploy_opts.has_key?('interval')
|
57
|
+
deploy['interval'] = parse_relative_time(deploy_opts['interval'])
|
58
|
+
else
|
59
|
+
deploy['interval'] = nil
|
60
|
+
end
|
61
|
+
data['deploy_opts'] = deploy
|
59
62
|
data['hooks'] = options['hooks'] || {}
|
60
63
|
data['secrets'] = options['secrets'] if options['secrets']
|
61
64
|
data['build'] = parse_build_options(options) if options['build']
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Kontena::Cli::Stacks
|
2
|
+
module YAML
|
3
|
+
module Opto
|
4
|
+
module Resolvers; end
|
5
|
+
module Setters; end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
require 'opto'
|
10
|
+
require_relative 'opto/vault_setter'
|
11
|
+
require_relative 'opto/vault_resolver'
|
12
|
+
require_relative 'opto/prompt_resolver'
|
13
|
+
require_relative 'opto/service_instances_resolver'
|
14
|
+
require_relative 'opto/vault_cert_prompt_resolver'
|
15
|
+
require_relative 'opto/service_link_resolver'
|
@@ -1,9 +1,12 @@
|
|
1
|
+
require 'kontena/cli/stacks/yaml/opto'
|
2
|
+
require 'kontena/cli/common'
|
3
|
+
|
1
4
|
module Kontena::Cli::Stacks
|
2
5
|
module YAML
|
3
|
-
class Prompt < Opto::Resolver
|
6
|
+
class Prompt < ::Opto::Resolver
|
4
7
|
include Kontena::Cli::Common
|
5
8
|
|
6
|
-
using Opto::Extension::HashStringOrSymbolKey
|
9
|
+
using ::Opto::Extension::HashStringOrSymbolKey
|
7
10
|
|
8
11
|
def enum?
|
9
12
|
option.type == 'enum'
|
@@ -50,10 +53,16 @@ module Kontena::Cli::Stacks
|
|
50
53
|
prompt.yes?(question_text, default: option.default == false ? false : true)
|
51
54
|
end
|
52
55
|
|
53
|
-
def
|
54
|
-
|
56
|
+
def echo?
|
57
|
+
return true if option.handler.nil?
|
58
|
+
return true if option.handler.options.nil?
|
59
|
+
return true if option.handler.options[:echo].nil?
|
60
|
+
option.handler.options[:echo]
|
55
61
|
end
|
56
62
|
|
63
|
+
def ask
|
64
|
+
prompt.ask(question_text, default: option.default, echo: echo?)
|
65
|
+
end
|
57
66
|
|
58
67
|
def resolve
|
59
68
|
return nil if option.skip?
|
@@ -68,4 +77,3 @@ module Kontena::Cli::Stacks
|
|
68
77
|
end
|
69
78
|
end
|
70
79
|
end
|
71
|
-
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Kontena::Cli::Stacks
|
2
2
|
module YAML
|
3
|
-
class Opto::Resolvers::ServiceInstances < Opto::Resolver
|
3
|
+
class Opto::Resolvers::ServiceInstances < ::Opto::Resolver
|
4
4
|
def resolve
|
5
5
|
read_command = Kontena::Cli::Stacks::ShowCommand.new([self.stack])
|
6
6
|
stack = read_command.fetch_stack(self.stack)
|
@@ -1,45 +1,76 @@
|
|
1
|
-
module Kontena::Cli::Stacks
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
else
|
21
|
-
name = "#{s.dig('stack', 'name')}/#{s['name']}"
|
22
|
-
end
|
23
|
-
menu.choice name, "#{s.dig('stack', 'name')}/#{s['name']}"
|
24
|
-
end
|
1
|
+
module Kontena::Cli::Stacks::YAML::Opto::Resolvers
|
2
|
+
class ServiceLink < ::Opto::Resolver
|
3
|
+
include Kontena::Cli::Common
|
4
|
+
|
5
|
+
def resolve
|
6
|
+
message = hint['prompt']
|
7
|
+
name_filter = hint['name']
|
8
|
+
image_filter = hint['image']
|
9
|
+
raise "prompt missing" unless message
|
10
|
+
|
11
|
+
services = get_services
|
12
|
+
services = filter_by_image(services, image_filter) if image_filter
|
13
|
+
services = filter_by_name(services, name_filter) if name_filter
|
14
|
+
return nil if services.size == 0
|
15
|
+
prompt.select(message) do |menu|
|
16
|
+
menu.default(default_index(services)) if option.default
|
17
|
+
menu.choice "<none>", nil unless option.required?
|
18
|
+
services.each do |s|
|
19
|
+
menu.choice service_name(s), service_link(s)
|
25
20
|
end
|
26
21
|
end
|
22
|
+
end
|
27
23
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
# @return [Array<Hash>]
|
25
|
+
def get_services
|
26
|
+
client.get("grids/#{current_grid}/services")['services']
|
27
|
+
rescue
|
28
|
+
[]
|
29
|
+
end
|
33
30
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
# @param [Array<Hash>] services
|
32
|
+
# @return [Integer]
|
33
|
+
def default_index(services)
|
34
|
+
index = services.index {|s| service_link(s) == option.default }
|
35
|
+
if index
|
36
|
+
index.to_i + 1
|
37
|
+
else
|
38
|
+
0
|
38
39
|
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param [Hash] service
|
43
|
+
# @return [String]
|
44
|
+
def service_link(service)
|
45
|
+
grid, stack, service = service['id'].split('/')
|
46
|
+
"#{stack}/#{service}"
|
47
|
+
end
|
39
48
|
|
40
|
-
|
41
|
-
|
49
|
+
# @param [Hash] service
|
50
|
+
# @return [String]
|
51
|
+
def service_name(service)
|
52
|
+
grid, stack, service = service['id'].split('/')
|
53
|
+
if stack == 'null'.freeze
|
54
|
+
service
|
55
|
+
else
|
56
|
+
"#{stack}/#{service}"
|
42
57
|
end
|
43
58
|
end
|
59
|
+
|
60
|
+
def filter_by_image(services, image)
|
61
|
+
services.select { |s|
|
62
|
+
s['image'].include?(image)
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def filter_by_name(services, name)
|
67
|
+
services.select { |s|
|
68
|
+
s['name'].include?(name)
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def stack
|
73
|
+
ENV['STACK']
|
74
|
+
end
|
44
75
|
end
|
45
76
|
end
|
@@ -1,15 +1,38 @@
|
|
1
|
-
module Kontena::Cli::Stacks
|
2
|
-
|
3
|
-
|
4
|
-
include Kontena::Cli::Common
|
1
|
+
module Kontena::Cli::Stacks::YAML::Opto::Resolvers
|
2
|
+
class VaultCertPrompt < ::Opto::Resolver
|
3
|
+
include Kontena::Cli::Common
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
def resolve
|
6
|
+
message = hint || 'Select SSL certs'
|
7
|
+
secrets = get_secrets.select{ |s|
|
8
|
+
s['name'].match(/(ssl|cert)/i)
|
9
|
+
}
|
10
|
+
if secrets.size > 0
|
11
|
+
prompt.multi_select(hint) do |menu|
|
12
|
+
menu.default(*default_indexes(secrets)) if option.default
|
13
|
+
secrets.each do |s|
|
14
|
+
menu.choice s['name']
|
15
|
+
end
|
16
|
+
end
|
12
17
|
end
|
13
18
|
end
|
19
|
+
|
20
|
+
# @return [Array<Hash>] secrets
|
21
|
+
def get_secrets
|
22
|
+
client.get("grids/#{current_grid}/secrets")['secrets']
|
23
|
+
rescue
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [Array<Hash>] secrets
|
28
|
+
# @return [Array<Integer>]
|
29
|
+
def default_indexes(secrets)
|
30
|
+
indexes = []
|
31
|
+
option.default.to_a.each do |name|
|
32
|
+
index = secrets.index { |s| s['name'] == name }
|
33
|
+
indexes << index.to_i + 1 if index
|
34
|
+
end
|
35
|
+
indexes
|
36
|
+
end
|
14
37
|
end
|
15
38
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Kontena::Cli::Stacks
|
2
2
|
module YAML
|
3
|
-
class Opto::Setters::Vault < Opto::Setter
|
3
|
+
class Opto::Setters::Vault < ::Opto::Setter
|
4
4
|
def set(value)
|
5
5
|
require 'shellwords'
|
6
6
|
ENV["DEBUG"] && STDERR.puts("Setting to vault: #{hint}")
|
@@ -9,4 +9,3 @@ module Kontena::Cli::Stacks
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
12
|
-
|
@@ -2,6 +2,11 @@ require_relative '../../../util'
|
|
2
2
|
|
3
3
|
module Kontena::Cli::Stacks
|
4
4
|
module YAML
|
5
|
+
module Opto
|
6
|
+
module Resolvers; end
|
7
|
+
module Setters; end
|
8
|
+
end
|
9
|
+
|
5
10
|
class Reader
|
6
11
|
include Kontena::Util
|
7
12
|
include Kontena::Cli::Common
|
@@ -12,13 +17,7 @@ module Kontena::Cli::Stacks
|
|
12
17
|
require 'yaml'
|
13
18
|
require_relative 'service_extender'
|
14
19
|
require_relative 'validator_v3'
|
15
|
-
|
16
|
-
require_relative 'opto/vault_setter'
|
17
|
-
require_relative 'opto/vault_resolver'
|
18
|
-
require_relative 'opto/prompt_resolver'
|
19
|
-
require_relative 'opto/service_instances_resolver'
|
20
|
-
require_relative 'opto/vault_cert_prompt_resolver'
|
21
|
-
require_relative 'opto/service_link_resolver'
|
20
|
+
require_relative 'opto'
|
22
21
|
require 'liquid'
|
23
22
|
|
24
23
|
@file = file
|
@@ -88,7 +87,7 @@ module Kontena::Cli::Stacks
|
|
88
87
|
# @return [Opto::Group]
|
89
88
|
def variables
|
90
89
|
return @variables if @variables
|
91
|
-
@variables = Opto::Group.new(
|
90
|
+
@variables = ::Opto::Group.new(
|
92
91
|
(internals_interpolated_yaml['variables'] || {}).merge('STACK' => { type: :string, value: env['STACK']}, 'GRID' => {type: :string, value: env['GRID']}),
|
93
92
|
defaults: {
|
94
93
|
from: :env,
|
@@ -33,7 +33,6 @@ module Kontena
|
|
33
33
|
)
|
34
34
|
plugin_version = version.nil? ? Gem::Requirement.default : Gem::Requirement.new(version)
|
35
35
|
without_safe { cmd.install(prefix(plugin_name), plugin_version) }
|
36
|
-
cleanup_plugin(plugin_name)
|
37
36
|
cmd.installed_gems
|
38
37
|
end
|
39
38
|
|
@@ -123,7 +122,7 @@ module Kontena
|
|
123
122
|
def cleanup_plugin(plugin_name)
|
124
123
|
require 'rubygems/commands/cleanup_command'
|
125
124
|
cmd = Gem::Commands::CleanupCommand.new
|
126
|
-
options = [
|
125
|
+
options = []
|
127
126
|
options += ['-q', '--no-verbose'] unless ENV["DEBUG"]
|
128
127
|
cmd.handle_options options
|
129
128
|
without_safe { cmd.execute }
|
data/lib/kontena_cli.rb
CHANGED
@@ -128,35 +128,42 @@ describe Kontena::Cli::Common do
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
expect(subject.confirm_command('name-to-confirm')).to be_truthy
|
136
|
-
expect{subject.confirm_command('name-to-confirm')}.to_not raise_error
|
131
|
+
context 'confirm' do
|
132
|
+
before(:each) do
|
133
|
+
expect($stdout).to receive(:tty?).at_least(:once).and_return(true)
|
134
|
+
expect($stdin).to receive(:tty?).at_least(:once).and_return(true)
|
137
135
|
end
|
138
136
|
|
139
|
-
|
140
|
-
|
141
|
-
|
137
|
+
describe '#confirm_command' do
|
138
|
+
it 'returns true if input matches' do
|
139
|
+
allow(subject).to receive(:ask).and_return('name-to-confirm')
|
142
140
|
|
143
|
-
|
144
|
-
|
145
|
-
|
141
|
+
expect(subject.confirm_command('name-to-confirm')).to be_truthy
|
142
|
+
expect{subject.confirm_command('name-to-confirm')}.to_not raise_error
|
143
|
+
end
|
146
144
|
|
147
|
-
|
148
|
-
|
149
|
-
|
145
|
+
it 'raises error unless input matches' do
|
146
|
+
expect(subject).to receive(:ask).and_return('wrong-name')
|
147
|
+
expect(subject).to receive(:error).with(/did not match/)
|
150
148
|
|
151
|
-
|
152
|
-
|
149
|
+
subject.confirm_command('name-to-confirm')
|
150
|
+
end
|
153
151
|
end
|
154
152
|
|
155
|
-
|
156
|
-
|
157
|
-
|
153
|
+
describe '#confirm' do
|
154
|
+
it 'returns true if confirmed' do
|
155
|
+
allow(subject.prompt).to receive(:yes?).and_return(true)
|
158
156
|
|
159
|
-
|
157
|
+
expect(subject.confirm).to be_truthy
|
158
|
+
expect{subject.confirm}.to_not raise_error
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'raises error unless confirmed' do
|
162
|
+
expect(subject.prompt).to receive(:yes?).and_return(false)
|
163
|
+
expect(subject).to receive(:error).with(/Aborted/)
|
164
|
+
|
165
|
+
subject.confirm
|
166
|
+
end
|
160
167
|
end
|
161
168
|
end
|
162
169
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative "../../../spec_helper"
|
2
|
+
require "kontena/cli/master/init_cloud_command"
|
3
|
+
|
4
|
+
describe Kontena::Cli::Master::InitCloudCommand do
|
5
|
+
|
6
|
+
include ClientHelpers
|
7
|
+
include RequirementsHelper
|
8
|
+
|
9
|
+
mock_current_master
|
10
|
+
|
11
|
+
let(:cloud_client) { double(:cc) }
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
allow(subject).to receive(:current_account).and_return('foo')
|
15
|
+
allow(subject).to receive(:cloud_auth?).and_return(true)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#execute' do
|
19
|
+
expect_to_require_current_master
|
20
|
+
expect_to_require_current_master_token
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'runs the invite self after deploy callback' do
|
24
|
+
expect(Kontena).to receive(:run).with('cloud master add --current --force').and_return(true)
|
25
|
+
expect_any_instance_of(Kontena::Callbacks::InviteSelfAfterDeploy).to receive(:after).and_return(true)
|
26
|
+
subject.run(['--force'])
|
27
|
+
end
|
28
|
+
end
|
@@ -25,7 +25,7 @@ describe Kontena::Cli::Services::LinkCommand do
|
|
25
25
|
it 'aborts if service is already linked' do
|
26
26
|
allow(client).to receive(:get).and_return({
|
27
27
|
'links' => [
|
28
|
-
{'alias' => 'service-b', '
|
28
|
+
{'alias' => 'service-b', 'id' => "grid/null/service-b"}
|
29
29
|
]
|
30
30
|
})
|
31
31
|
expect {
|
@@ -35,7 +35,7 @@ describe Kontena::Cli::Services::LinkCommand do
|
|
35
35
|
|
36
36
|
it 'sends link to master' do
|
37
37
|
expect(client).to receive(:put).with(
|
38
|
-
'services/test-grid/null/service-a', {links: [{name: 'service-b', alias: 'service-b'}]}
|
38
|
+
'services/test-grid/null/service-a', {links: [{name: 'null/service-b', alias: 'service-b'}]}
|
39
39
|
)
|
40
40
|
subject.run(['service-a', 'service-b'])
|
41
41
|
end
|
@@ -9,7 +9,7 @@ describe Kontena::Cli::Services::UnlinkCommand do
|
|
9
9
|
before(:each) do
|
10
10
|
allow(client).to receive(:get).and_return({
|
11
11
|
'links' => [
|
12
|
-
{'alias' => 'service-b', '
|
12
|
+
{'alias' => 'service-b', 'id' => "test-grid/null/service-b", 'name' => 'service-b'}
|
13
13
|
]
|
14
14
|
})
|
15
15
|
end
|
@@ -335,12 +335,16 @@ describe Kontena::Cli::Stacks::ServiceGenerator do
|
|
335
335
|
expect(result['deploy_opts']['interval']).to eq(60)
|
336
336
|
end
|
337
337
|
|
338
|
-
it '
|
338
|
+
it 'returns nil values if no deploy options are defined' do
|
339
339
|
data = {
|
340
340
|
'image' => 'foo/bar:latest'
|
341
341
|
}
|
342
342
|
result = subject.send(:parse_data, data)
|
343
|
-
expect(result['deploy_opts']).to
|
343
|
+
expect(result['deploy_opts']).to eq({
|
344
|
+
'interval' => nil,
|
345
|
+
'min_health' => nil,
|
346
|
+
'wait_for_port' => nil
|
347
|
+
})
|
344
348
|
end
|
345
349
|
end
|
346
350
|
|
@@ -381,5 +385,5 @@ describe Kontena::Cli::Stacks::ServiceGenerator do
|
|
381
385
|
expect(result['secrets']).to be_nil
|
382
386
|
end
|
383
387
|
end
|
384
|
-
end
|
388
|
+
end
|
385
389
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'opto'
|
2
|
+
require 'kontena_cli'
|
3
|
+
require 'kontena/cli/stacks/yaml/opto'
|
4
|
+
|
5
|
+
describe Kontena::Cli::Stacks::YAML::Prompt do
|
6
|
+
|
7
|
+
describe 'echoing' do
|
8
|
+
let(:option_without_echo) { Opto::Option.new(type: 'string', name: 'foo', from: 'prompt', echo: false) }
|
9
|
+
let(:option_with_echo) { Opto::Option.new(type: 'string', name: 'foo', from: 'prompt') }
|
10
|
+
let(:prompt) { double(:prompt) }
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
allow(Kontena).to receive(:prompt).and_return(prompt)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'turns echo off when variable has "echo: false"' do
|
17
|
+
expect(prompt).to receive(:ask).with(/Enter/, hash_including(echo: false))
|
18
|
+
option_without_echo.value
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'keeps echo on when variable does not have "echo: false"' do
|
22
|
+
expect(prompt).to receive(:ask).with(/Enter/, hash_not_including(echo: false))
|
23
|
+
option_with_echo.value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'opto'
|
2
|
+
require 'kontena/cli/stacks/yaml/opto/service_link_resolver'
|
3
|
+
|
4
|
+
describe Kontena::Cli::Stacks::YAML::Opto::Resolvers::ServiceLink do
|
5
|
+
let(:subject) do
|
6
|
+
described_class.new({'prompt' => 'foo'})
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#resolve' do
|
10
|
+
it 'returns nil if no matching services' do
|
11
|
+
expect(subject).to receive(:get_services).and_return([])
|
12
|
+
expect(subject).not_to receive(:prompt)
|
13
|
+
expect(subject.resolve).to be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'prompts user if matching services' do
|
17
|
+
prompt = double(:prompt)
|
18
|
+
allow(subject).to receive(:prompt).and_return(prompt)
|
19
|
+
expect(prompt).to receive(:select).and_return('null/bar')
|
20
|
+
expect(subject).to receive(:get_services).and_return([
|
21
|
+
{'id' => 'foo/null/bar'}
|
22
|
+
])
|
23
|
+
expect(subject.resolve).to eq('null/bar')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#default_index' do
|
28
|
+
let(:option) do
|
29
|
+
::Opto::Option.new(default: 'foo/bar')
|
30
|
+
end
|
31
|
+
let(:subject) do
|
32
|
+
described_class.new({'prompt' => 'foo'}, option)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns matching index' do
|
36
|
+
services = [
|
37
|
+
{'id' => 'test/foo/foo'},
|
38
|
+
{'id' => 'test/foo/bar'},
|
39
|
+
{'id' => 'test/asd/asd'}
|
40
|
+
]
|
41
|
+
index = subject.default_index(services)
|
42
|
+
expect(index).to eq(2)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns 0 if no matches' do
|
46
|
+
services = [
|
47
|
+
{'id' => 'test/foo/foo'},
|
48
|
+
{'id' => 'test/asd/asd'}
|
49
|
+
]
|
50
|
+
index = subject.default_index(services)
|
51
|
+
expect(index).to eq(0)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'opto'
|
2
|
+
require 'kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver'
|
3
|
+
|
4
|
+
describe Kontena::Cli::Stacks::YAML::Opto::Resolvers::VaultCertPrompt do
|
5
|
+
describe '#resolve' do
|
6
|
+
it 'returns nil if no matching secrets' do
|
7
|
+
expect(subject).to receive(:get_secrets).and_return([])
|
8
|
+
expect(subject).not_to receive(:prompt)
|
9
|
+
expect(subject.resolve).to be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'prompts user if matching secrets' do
|
13
|
+
prompt = double(:prompt)
|
14
|
+
allow(subject).to receive(:prompt).and_return(prompt)
|
15
|
+
expect(prompt).to receive(:multi_select).and_return('ssl-cert')
|
16
|
+
expect(subject).to receive(:get_secrets).and_return([{'name' => 'ssl-cert'}])
|
17
|
+
subject.resolve
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#default_indexes' do
|
22
|
+
let(:option) do
|
23
|
+
Opto::Option.new(default: ['ssl-cert-1', 'ssl-cert-3'])
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:subject) do
|
27
|
+
described_class.new('foo', option)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns all default indexes if found' do
|
31
|
+
secrets = [
|
32
|
+
{'name' => 'ssl-cert-1'},
|
33
|
+
{'name' => 'ssl-cert-2'},
|
34
|
+
{'name' => 'ssl-cert-3'}
|
35
|
+
]
|
36
|
+
indexes = subject.default_indexes(secrets)
|
37
|
+
expect(indexes).to eq([1, 3])
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns partially found defaults' do
|
41
|
+
secrets = [
|
42
|
+
{'name' => 'ssl-cert-a'},
|
43
|
+
{'name' => 'ssl-cert-b'},
|
44
|
+
{'name' => 'ssl-cert-3'}
|
45
|
+
]
|
46
|
+
indexes = subject.default_indexes(secrets)
|
47
|
+
expect(indexes).to eq([3])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns empty array if no matches' do
|
51
|
+
secrets = [
|
52
|
+
{'name' => 'ssl-cert-a'}
|
53
|
+
]
|
54
|
+
indexes = subject.default_indexes(secrets)
|
55
|
+
expect(indexes).to eq([])
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'returns empty array if no secrets' do
|
59
|
+
secrets = []
|
60
|
+
indexes = subject.default_indexes(secrets)
|
61
|
+
expect(indexes).to eq([])
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns empty array if no defaults' do
|
65
|
+
secrets = [
|
66
|
+
{'name' => 'ssl-cert-a'}
|
67
|
+
]
|
68
|
+
allow(subject.option).to receive(:default).and_return([])
|
69
|
+
indexes = subject.default_indexes(secrets)
|
70
|
+
expect(indexes).to eq([])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -1,28 +1,37 @@
|
|
1
1
|
require_relative '../spec_helper'
|
2
2
|
require 'kontena_cli'
|
3
|
+
require 'kontena/light_prompt'
|
3
4
|
|
4
5
|
describe Kontena do
|
5
|
-
|
6
|
+
context 'prompt' do
|
7
|
+
it 'uses light prompt on windows' do
|
8
|
+
allow(ENV).to receive(:[]).with('OS').and_return('Windows_NT')
|
9
|
+
expect(Kontena.prompt).to be_kind_of(Kontena::LightPrompt)
|
10
|
+
end
|
11
|
+
end
|
6
12
|
|
7
13
|
describe '#run' do
|
8
|
-
let(:whoami) { double(:
|
14
|
+
let(:whoami) { double(:whoami) }
|
9
15
|
|
10
16
|
before(:each) do
|
11
|
-
expect(Kontena::MainCommand).to receive(:new).and_call_original
|
12
17
|
expect(Kontena::Cli::WhoamiCommand).to receive(:new).and_return(whoami)
|
13
18
|
expect(whoami).to receive(:run).with(['--bash-completion-path']).and_return(true)
|
14
19
|
end
|
15
20
|
|
16
21
|
it 'accepts a command line as string' do
|
17
|
-
|
22
|
+
|
23
|
+
Kontena.run('whoami --bash-completion-path')
|
18
24
|
end
|
19
25
|
|
20
26
|
it 'accepts a command line as a list of parameters' do
|
21
|
-
|
27
|
+
Kontena.run('whoami', '--bash-completion-path')
|
22
28
|
end
|
23
29
|
|
24
30
|
it 'accepts a command line as an array' do
|
25
|
-
|
31
|
+
Kontena.run(['whoami', '--bash-completion-path'])
|
26
32
|
end
|
27
33
|
end
|
28
34
|
end
|
35
|
+
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require 'kontena/main_command'
|
3
|
+
|
4
|
+
describe Kontena::MainCommand do
|
5
|
+
let(:subject) { described_class.new('kontena') }
|
6
|
+
|
7
|
+
describe '--version' do
|
8
|
+
it 'outputs the version number and exits' do
|
9
|
+
expect do
|
10
|
+
expect{subject.run(['--version'])}.to output(/kontena-cli #{Kontena::Cli::VERSION}/).to_stdout
|
11
|
+
end.to raise_error(SystemExit) do |exc|
|
12
|
+
expect(exc.status).to eq 0
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kontena-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kontena, Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -140,16 +140,16 @@ dependencies:
|
|
140
140
|
name: opto
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- -
|
143
|
+
- - '='
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 1.8.
|
145
|
+
version: 1.8.3
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- -
|
150
|
+
- - '='
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 1.8.
|
152
|
+
version: 1.8.3
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: semantic
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -433,6 +433,7 @@ files:
|
|
433
433
|
- lib/kontena/cli/stacks/yaml/custom_validators/extends_validator.rb
|
434
434
|
- lib/kontena/cli/stacks/yaml/custom_validators/hooks_validator.rb
|
435
435
|
- lib/kontena/cli/stacks/yaml/custom_validators/secrets_validator.rb
|
436
|
+
- lib/kontena/cli/stacks/yaml/opto.rb
|
436
437
|
- lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb
|
437
438
|
- lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb
|
438
439
|
- lib/kontena/cli/stacks/yaml/opto/service_link_resolver.rb
|
@@ -555,6 +556,7 @@ files:
|
|
555
556
|
- spec/kontena/cli/helpers/log_helper_spec.rb
|
556
557
|
- spec/kontena/cli/main_command_spec.rb
|
557
558
|
- spec/kontena/cli/master/current_command_spec.rb
|
559
|
+
- spec/kontena/cli/master/init_cloud_command_spec.rb
|
558
560
|
- spec/kontena/cli/master/login_command_spec.rb
|
559
561
|
- spec/kontena/cli/master/logout_command_spec.rb
|
560
562
|
- spec/kontena/cli/master/use_command_spec.rb
|
@@ -582,6 +584,9 @@ files:
|
|
582
584
|
- spec/kontena/cli/stacks/service_generator_v2_spec.rb
|
583
585
|
- spec/kontena/cli/stacks/show_command_spec.rb
|
584
586
|
- spec/kontena/cli/stacks/upgrade_command_spec.rb
|
587
|
+
- spec/kontena/cli/stacks/yaml/opto/prompt_resolver_spec.rb
|
588
|
+
- spec/kontena/cli/stacks/yaml/opto/service_link_resolver_spec.rb
|
589
|
+
- spec/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver_spec.rb
|
585
590
|
- spec/kontena/cli/stacks/yaml/reader_spec.rb
|
586
591
|
- spec/kontena/cli/stacks/yaml/service_extender_spec.rb
|
587
592
|
- spec/kontena/cli/stacks/yaml/validator_v3_spec.rb
|
@@ -592,6 +597,7 @@ files:
|
|
592
597
|
- spec/kontena/client_spec.rb
|
593
598
|
- spec/kontena/config_spec.rb
|
594
599
|
- spec/kontena/kontena_cli_spec.rb
|
600
|
+
- spec/kontena/main_command_spec.rb
|
595
601
|
- spec/kontena/plugin_manager_spec.rb
|
596
602
|
- spec/spec_helper.rb
|
597
603
|
- spec/support/client_helpers.rb
|
@@ -615,9 +621,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
615
621
|
version: 2.1.0
|
616
622
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
617
623
|
requirements:
|
618
|
-
- - "
|
624
|
+
- - ">"
|
619
625
|
- !ruby/object:Gem::Version
|
620
|
-
version:
|
626
|
+
version: 1.3.1
|
621
627
|
requirements: []
|
622
628
|
rubyforge_project:
|
623
629
|
rubygems_version: 2.6.8
|
@@ -683,6 +689,7 @@ test_files:
|
|
683
689
|
- spec/kontena/cli/helpers/log_helper_spec.rb
|
684
690
|
- spec/kontena/cli/main_command_spec.rb
|
685
691
|
- spec/kontena/cli/master/current_command_spec.rb
|
692
|
+
- spec/kontena/cli/master/init_cloud_command_spec.rb
|
686
693
|
- spec/kontena/cli/master/login_command_spec.rb
|
687
694
|
- spec/kontena/cli/master/logout_command_spec.rb
|
688
695
|
- spec/kontena/cli/master/use_command_spec.rb
|
@@ -710,6 +717,9 @@ test_files:
|
|
710
717
|
- spec/kontena/cli/stacks/service_generator_v2_spec.rb
|
711
718
|
- spec/kontena/cli/stacks/show_command_spec.rb
|
712
719
|
- spec/kontena/cli/stacks/upgrade_command_spec.rb
|
720
|
+
- spec/kontena/cli/stacks/yaml/opto/prompt_resolver_spec.rb
|
721
|
+
- spec/kontena/cli/stacks/yaml/opto/service_link_resolver_spec.rb
|
722
|
+
- spec/kontena/cli/stacks/yaml/opto/vault_cert_prompt_resolver_spec.rb
|
713
723
|
- spec/kontena/cli/stacks/yaml/reader_spec.rb
|
714
724
|
- spec/kontena/cli/stacks/yaml/service_extender_spec.rb
|
715
725
|
- spec/kontena/cli/stacks/yaml/validator_v3_spec.rb
|
@@ -720,6 +730,7 @@ test_files:
|
|
720
730
|
- spec/kontena/client_spec.rb
|
721
731
|
- spec/kontena/config_spec.rb
|
722
732
|
- spec/kontena/kontena_cli_spec.rb
|
733
|
+
- spec/kontena/main_command_spec.rb
|
723
734
|
- spec/kontena/plugin_manager_spec.rb
|
724
735
|
- spec/spec_helper.rb
|
725
736
|
- spec/support/client_helpers.rb
|