kontena-cli 1.5.0.pre5 → 1.5.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/kontena/callbacks/master/deploy/05_before_deploy_configuration_wizard.rb +2 -2
- data/lib/kontena/cli/services/deploy_command.rb +1 -1
- data/lib/kontena/cli/stacks/deploy_command.rb +1 -1
- data/lib/kontena/cli/stacks/install_command.rb +11 -0
- data/lib/kontena/cli/stacks/registry/create_command.rb +24 -0
- data/lib/kontena/cli/stacks/registry/make_private_command.rb +24 -0
- data/lib/kontena/cli/stacks/registry/make_public_command.rb +24 -0
- data/lib/kontena/cli/stacks/registry/pull_command.rb +1 -1
- data/lib/kontena/cli/stacks/registry/push_command.rb +1 -2
- data/lib/kontena/cli/stacks/registry/remove_command.rb +1 -1
- data/lib/kontena/cli/stacks/registry/search_command.rb +23 -10
- data/lib/kontena/cli/stacks/registry/show_command.rb +44 -11
- data/lib/kontena/cli/stacks/registry_command.rb +3 -0
- data/lib/kontena/cli/stacks/show_command.rb +15 -1
- data/lib/kontena/cli/stacks/upgrade_command.rb +9 -0
- data/lib/kontena/cli/stacks/yaml/reader.rb +2 -0
- data/lib/kontena/cli/stacks/yaml/stack_file_loader/registry_loader.rb +1 -1
- data/lib/kontena/client.rb +8 -0
- data/lib/kontena/scripts/completer.rb +2 -2
- data/lib/kontena/stacks_cache.rb +22 -25
- data/lib/kontena/stacks_client.rb +133 -20
- data/omnibus/wrappers/sh/kontena +1 -1
- data/spec/fixtures/kontena_v3_with_metadata.yml +28 -0
- data/spec/kontena/cli/stacks/install_command_spec.rb +26 -1
- data/spec/kontena/cli/stacks/upgrade_command_spec.rb +8 -1
- data/spec/kontena/cli/stacks/yaml/reader_spec.rb +8 -8
- data/spec/kontena/cli/stacks/yaml/stack_file_loader/registry_loader_spec.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b512497470a658b7be3dae937f44e65d8ebc673d867a20e7d5a04bf9dab2b89f
|
|
4
|
+
data.tar.gz: 8486842c3eba0ee7af57283f108e02fb610a3e83ceb30090e9309fb1eaa3b204
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 41400fae5d6590041c57594981ab97aea90e0e5103c0a0b8ea6215c8d00187259c529786f7230742f347666a525fb1fadfbcf0e6951c6971975e12823a2ba057
|
|
7
|
+
data.tar.gz: f60a87d8531854e09bea64fd2fa895dff9c6de9c7805ad7497a007910b80ec449d55dd7bed0af81cfacb051ad86dcf65a61ac882ca6a60b1b26151aa566d8d0e
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.5.0.
|
|
1
|
+
1.5.0.rc1
|
|
@@ -83,13 +83,13 @@ module Kontena
|
|
|
83
83
|
command.skip_auth_provider = false
|
|
84
84
|
when :custom
|
|
85
85
|
puts
|
|
86
|
-
puts 'Learn how to configure custom user authentication provider after installation at: www.kontena.io/docs/
|
|
86
|
+
puts 'Learn how to configure custom user authentication provider after installation at: www.kontena.io/docs/advanced/authentication'
|
|
87
87
|
puts
|
|
88
88
|
command.cloud_master_id = nil
|
|
89
89
|
command.skip_auth_provider = true
|
|
90
90
|
when :none
|
|
91
91
|
puts
|
|
92
|
-
puts "You have selected to use Kontena Master in single user mode. You can configure an authentication provider later. For more information, see here: www.kontena.io/docs/
|
|
92
|
+
puts "You have selected to use Kontena Master in single user mode. You can configure an authentication provider later. For more information, see here: www.kontena.io/docs/advanced/authentication"
|
|
93
93
|
puts
|
|
94
94
|
command.cloud_master_id = nil
|
|
95
95
|
command.skip_auth_provider = true
|
|
@@ -7,7 +7,7 @@ module Kontena::Cli::Services
|
|
|
7
7
|
include ServicesHelper
|
|
8
8
|
|
|
9
9
|
parameter "NAME", "Service name"
|
|
10
|
-
option '--[no-]wait', :flag, '
|
|
10
|
+
option '--[no-]wait', :flag, 'Wait for service deployment to finish', default: true
|
|
11
11
|
option '--force', :flag, 'Force deploy even if service does not have any changes'
|
|
12
12
|
|
|
13
13
|
def execute
|
|
@@ -10,7 +10,7 @@ module Kontena::Cli::Stacks
|
|
|
10
10
|
|
|
11
11
|
parameter "NAME ...", "Stack name", attribute_name: :names
|
|
12
12
|
|
|
13
|
-
option '--[no-]wait', :flag, '
|
|
13
|
+
option '--[no-]wait', :flag, 'Wait for deployment to finish', default: true
|
|
14
14
|
|
|
15
15
|
requires_current_master
|
|
16
16
|
requires_current_master_token
|
|
@@ -20,6 +20,8 @@ module Kontena::Cli::Stacks
|
|
|
20
20
|
option '--parent-name', '[PARENT_NAME]', "Set parent stack name", hidden: true
|
|
21
21
|
option '--skip-dependencies', :flag, "Do not install any stack dependencies"
|
|
22
22
|
|
|
23
|
+
option "--force", :flag, "Force install", default: false, attribute_name: :forced
|
|
24
|
+
|
|
23
25
|
requires_current_master
|
|
24
26
|
requires_current_master_token
|
|
25
27
|
|
|
@@ -30,6 +32,15 @@ module Kontena::Cli::Stacks
|
|
|
30
32
|
|
|
31
33
|
stack # runs validations
|
|
32
34
|
|
|
35
|
+
kontena_requirement = stack.dig('metadata', 'required_kontena_version')
|
|
36
|
+
unless kontena_requirement.nil?
|
|
37
|
+
master_version = Gem::Version.new(client.server_version)
|
|
38
|
+
unless Gem::Requirement.new(kontena_requirement).satisfied_by?(master_version)
|
|
39
|
+
puts "#{pastel.red("Warning: ")} Stack requires kontena version #{kontena_requirement} but Master version is #{master_version}"
|
|
40
|
+
confirm("Are you sure? You can skip this prompt by running this command with --force option") unless forced?
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
33
44
|
hint_on_validation_notifications(reader.notifications)
|
|
34
45
|
abort_on_validation_errors(reader.errors)
|
|
35
46
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require_relative '../common'
|
|
2
|
+
|
|
3
|
+
module Kontena::Cli::Stacks::Registry
|
|
4
|
+
class CreateCommand < Kontena::Command
|
|
5
|
+
include Kontena::Cli::Common
|
|
6
|
+
include Kontena::Cli::Stacks::Common
|
|
7
|
+
include Kontena::Cli::Stacks::Common::RegistryNameParam
|
|
8
|
+
|
|
9
|
+
banner "Creates a new Stack to Kontena Stack Registry"
|
|
10
|
+
|
|
11
|
+
option '--private', :flag, "Create as private", attribute_name: :is_private
|
|
12
|
+
|
|
13
|
+
requires_current_account_token
|
|
14
|
+
|
|
15
|
+
def execute
|
|
16
|
+
exit_with_error "Can't create a stack with a version number" unless stack_name.version.nil?
|
|
17
|
+
spinner "Creating #{is_private? ? pastel.yellow('private') : 'public'} stack #{pastel.cyan(stack_name)} in Kontena Stack Registry" do
|
|
18
|
+
stacks_client.create(stack_name, is_private: is_private?)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require_relative '../common'
|
|
2
|
+
|
|
3
|
+
module Kontena::Cli::Stacks::Registry
|
|
4
|
+
class MakePrivateCommand < Kontena::Command
|
|
5
|
+
include Kontena::Cli::Common
|
|
6
|
+
include Kontena::Cli::Stacks::Common
|
|
7
|
+
include Kontena::Cli::Stacks::Common::RegistryNameParam
|
|
8
|
+
|
|
9
|
+
banner "Changes Stack visibility private in the Kontena Cloud Stack Registry"
|
|
10
|
+
|
|
11
|
+
option '--force', :flag, "Don't ask for confirmation"
|
|
12
|
+
|
|
13
|
+
requires_current_account_token
|
|
14
|
+
|
|
15
|
+
def execute
|
|
16
|
+
unless force?
|
|
17
|
+
confirm("Change stack #{pastel.cyan(stack_name)} visibility to private?")
|
|
18
|
+
end
|
|
19
|
+
spinner "Updating Stack #{pastel.cyan(stack_name)} visibility to private" do
|
|
20
|
+
stacks_client.make_private(stack_name)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require_relative '../common'
|
|
2
|
+
|
|
3
|
+
module Kontena::Cli::Stacks::Registry
|
|
4
|
+
class MakePublicCommand < Kontena::Command
|
|
5
|
+
include Kontena::Cli::Common
|
|
6
|
+
include Kontena::Cli::Stacks::Common
|
|
7
|
+
include Kontena::Cli::Stacks::Common::RegistryNameParam
|
|
8
|
+
|
|
9
|
+
banner "Changes Stack visibility private in the Kontena Cloud Stack Registry"
|
|
10
|
+
|
|
11
|
+
option '--force', :flag, "Don't ask for confirmation"
|
|
12
|
+
|
|
13
|
+
requires_current_account_token
|
|
14
|
+
|
|
15
|
+
def execute
|
|
16
|
+
unless force?
|
|
17
|
+
confirm("Change stack #{pastel.cyan(stack_name)} visibility to public?")
|
|
18
|
+
end
|
|
19
|
+
spinner "Updating Stack #{pastel.cyan(stack_name)} visibility to public" do
|
|
20
|
+
stacks_client.make_public(stack_name)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -14,7 +14,7 @@ module Kontena::Cli::Stacks::Registry
|
|
|
14
14
|
|
|
15
15
|
def execute
|
|
16
16
|
target = no_cache? ? stacks_client : Kontena::StacksCache
|
|
17
|
-
content = target.pull(stack_name
|
|
17
|
+
content = target.pull(stack_name)
|
|
18
18
|
if return?
|
|
19
19
|
return content
|
|
20
20
|
elsif file
|
|
@@ -30,8 +30,7 @@ module Kontena::Cli::Stacks::Registry
|
|
|
30
30
|
spinner("Pushing #{pastel.cyan(source)} to stack registry as #{loader.stack_name}") do
|
|
31
31
|
unless dry_run?
|
|
32
32
|
stacks_client.push(
|
|
33
|
-
loader.stack_name
|
|
34
|
-
loader.stack_name.version,
|
|
33
|
+
loader.stack_name,
|
|
35
34
|
loader.content
|
|
36
35
|
)
|
|
37
36
|
end
|
|
@@ -4,25 +4,38 @@ module Kontena::Cli::Stacks::Registry
|
|
|
4
4
|
class SearchCommand < Kontena::Command
|
|
5
5
|
include Kontena::Cli::Common
|
|
6
6
|
include Kontena::Cli::Stacks::Common
|
|
7
|
+
include Kontena::Cli::TableGenerator::Helper
|
|
7
8
|
|
|
8
9
|
banner "Search for stacks on the stack registry"
|
|
9
10
|
|
|
10
11
|
parameter "[QUERY]", "Query string"
|
|
11
12
|
|
|
13
|
+
option ['--[no-]pre'], :flag, "Include pre-release versions", default: true
|
|
14
|
+
option ['--[no-]private'], :flag, "Include private stacks", default: true, attribute_name: :priv
|
|
15
|
+
|
|
16
|
+
option ['--tag', '-t'], '[TAG]', "Search by tags", multivalued: true
|
|
17
|
+
|
|
12
18
|
option ['-q', '--quiet'], :flag, "Output the identifying column only"
|
|
13
19
|
|
|
20
|
+
def fields
|
|
21
|
+
quiet? ? ['name'] : %w(name version pulls description)
|
|
22
|
+
end
|
|
23
|
+
|
|
14
24
|
def execute
|
|
15
|
-
results = stacks_client.search(query.to_s)
|
|
16
|
-
if quiet?
|
|
17
|
-
puts results.map { |s| s['stack'] }.join("\n")
|
|
18
|
-
exit 0
|
|
19
|
-
end
|
|
25
|
+
results = stacks_client.search(query.to_s, tags: tag_list, include_prerelease: pre?, include_private: priv?)
|
|
20
26
|
exit_with_error 'Nothing found' if results.empty?
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
print_table(results.map { |r| r['attributes'] }) do |row|
|
|
28
|
+
next if quiet?
|
|
29
|
+
row['name'] = '%s/%s' % [row['organization-id'], row['name']]
|
|
30
|
+
row['name'] = pastel.yellow(row['name']) if row['is-private']
|
|
31
|
+
if row['latest-version'] && row['latest-version']['version']
|
|
32
|
+
row['version'] = row['latest-version']['version']
|
|
33
|
+
row['description'] = row['latest-version']['description']
|
|
34
|
+
else
|
|
35
|
+
row['version'] = '?'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
row['description'] = '-' if row['description'].to_s.empty?
|
|
26
39
|
end
|
|
27
40
|
end
|
|
28
41
|
end
|
|
@@ -13,19 +13,52 @@ module Kontena::Cli::Stacks::Registry
|
|
|
13
13
|
requires_current_account_token
|
|
14
14
|
|
|
15
15
|
def execute
|
|
16
|
-
|
|
17
|
-
unless versions?
|
|
18
|
-
stack = ::YAML.safe_load(stacks_client.show(stack_name.stack_name, stack_name.version), [], [], true)
|
|
19
|
-
puts "#{stack['stack']}:"
|
|
20
|
-
puts " #{"latest_" unless stack_name.version}version: #{stack['version']}"
|
|
21
|
-
puts " expose: #{stack['expose'] || '-'}"
|
|
22
|
-
puts " description: #{stack['description'] || '-'}"
|
|
16
|
+
versions = stacks_client.versions(stack_name)
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
if versions?
|
|
19
|
+
stacks_client.versions(stack_name).each do |version|
|
|
20
|
+
puts version['attributes']['version']
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
data = stacks_client.show(stack_name).dig('data', 'attributes')
|
|
24
|
+
puts "#{data['organization-id']}/#{data['name']}:"
|
|
25
|
+
puts " description: #{data.dig('latest-version', 'description') || '-'}"
|
|
26
|
+
puts " latest_version: #{data.dig('latest-version', 'version') || '-'}"
|
|
27
|
+
puts " created_at: #{data.dig('created-at')}"
|
|
28
|
+
puts " pulls: #{data.dig('pulls')}"
|
|
29
|
+
puts " private: #{data.dig('is-private')}"
|
|
30
|
+
meta = data.dig('latest-version', 'meta')
|
|
31
|
+
if meta
|
|
32
|
+
puts " meta:"
|
|
33
|
+
readme = meta.delete('readme')
|
|
34
|
+
meta_lines = YAML.dump(meta).split(/[\r\n]/)
|
|
35
|
+
meta_lines.shift
|
|
36
|
+
meta_lines.each do |meta_line|
|
|
37
|
+
puts " %s" % meta_line
|
|
38
|
+
end
|
|
39
|
+
if readme
|
|
40
|
+
if readme =~ /^http\S+$/
|
|
41
|
+
puts " readme: readme"
|
|
42
|
+
else
|
|
43
|
+
puts " readme: |"
|
|
44
|
+
readme.gsub!(/(\S{#{70}})(?=\S)/, '\1 ')
|
|
45
|
+
readme.gsub!(/(.{1,#{70}})(?:\s+|$)/, "\\1\n")
|
|
46
|
+
readme.gsub!(/^/, ' ')
|
|
47
|
+
puts readme
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
puts " meta: -"
|
|
52
|
+
end
|
|
26
53
|
|
|
27
|
-
|
|
28
|
-
|
|
54
|
+
if versions.empty?
|
|
55
|
+
puts " versions: -"
|
|
56
|
+
else
|
|
57
|
+
puts " versions:"
|
|
58
|
+
versions.each do |version|
|
|
59
|
+
puts " - #{version['attributes']['version']} (#{version['attributes']['created-at']})"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
29
62
|
end
|
|
30
63
|
end
|
|
31
64
|
end
|
|
@@ -5,5 +5,8 @@ module Kontena::Cli::Stacks
|
|
|
5
5
|
subcommand ["search"], "Search for stacks in the stacks registry", load_subcommand('stacks/registry/search_command')
|
|
6
6
|
subcommand "show", "Show info about a stack in the stacks registry", load_subcommand('stacks/registry/show_command')
|
|
7
7
|
subcommand ["remove", "rm"], "Remove a stack (or version) from the stacks registry", load_subcommand('stacks/registry/remove_command')
|
|
8
|
+
subcommand "create", "Create a stack in the registry", load_subcommand('stacks/registry/create_command')
|
|
9
|
+
subcommand "make-private", "Change Stack visibility to private", load_subcommand('stacks/registry/make_private_command')
|
|
10
|
+
subcommand "make-public", "Change Stack visibility to public", load_subcommand('stacks/registry/make_public_command')
|
|
8
11
|
end
|
|
9
12
|
end
|
|
@@ -26,6 +26,10 @@ module Kontena::Cli::Stacks
|
|
|
26
26
|
@variables ||= stack['variables'] || {}
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def metadata
|
|
30
|
+
@metadata ||= stack['metadata'] || {}
|
|
31
|
+
end
|
|
32
|
+
|
|
29
33
|
def stack
|
|
30
34
|
@stack ||= client.get("stacks/#{current_grid}/#{name}")
|
|
31
35
|
end
|
|
@@ -41,7 +45,7 @@ module Kontena::Cli::Stacks
|
|
|
41
45
|
def write_variables
|
|
42
46
|
File.write(values_to, variable_yaml)
|
|
43
47
|
end
|
|
44
|
-
|
|
48
|
+
|
|
45
49
|
def show_stack
|
|
46
50
|
puts "#{stack['name']}:"
|
|
47
51
|
puts " created: #{stack['created_at']}"
|
|
@@ -51,10 +55,19 @@ module Kontena::Cli::Stacks
|
|
|
51
55
|
puts " version: #{stack['version']}"
|
|
52
56
|
puts " revision: #{stack['revision']}"
|
|
53
57
|
puts " expose: #{stack['expose'] || '-'}"
|
|
58
|
+
|
|
54
59
|
puts " variables:#{' -' if variables.empty?}"
|
|
55
60
|
variables.each do |var, val|
|
|
56
61
|
puts " #{var}: #{val}"
|
|
57
62
|
end
|
|
63
|
+
|
|
64
|
+
puts " metadata:#{' -' if metadata.empty?}"
|
|
65
|
+
unless metadata.empty?
|
|
66
|
+
output_lines = ::YAML.dump(metadata).split(/[\r\n]/)
|
|
67
|
+
output_lines.shift # get rid of "---"
|
|
68
|
+
puts output_lines.map { |line| ' %s' % line }.join("\n")
|
|
69
|
+
end
|
|
70
|
+
|
|
58
71
|
puts " parent: #{stack['parent'] ? stack['parent']['name'] : '-'}"
|
|
59
72
|
if stack['children'] && !stack['children'].empty?
|
|
60
73
|
puts " children:"
|
|
@@ -62,6 +75,7 @@ module Kontena::Cli::Stacks
|
|
|
62
75
|
puts " - #{child['name']}"
|
|
63
76
|
end
|
|
64
77
|
end
|
|
78
|
+
|
|
65
79
|
puts " services:"
|
|
66
80
|
stack['services'].each do |service|
|
|
67
81
|
show_service(service['id'])
|
|
@@ -33,6 +33,15 @@ module Kontena::Cli::Stacks
|
|
|
33
33
|
gather_master_data(stack_name)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
kontena_requirement = loader.yaml.dig('meta', 'required_kontena_version')
|
|
37
|
+
unless kontena_requirement.nil?
|
|
38
|
+
master_version = Gem::Version.new(client.server_version)
|
|
39
|
+
unless Gem::Requirement.new(kontena_requirement).satisfied_by?(master_version)
|
|
40
|
+
puts "#{pastel.red("Warning: ")} Stack requires kontena version #{kontena_requirement} but Master version is #{master_version}"
|
|
41
|
+
confirm("Are you sure? You can skip this prompt by running this command with --force option") unless force?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
36
45
|
new_data = spinner "Parsing #{pastel.cyan(source)}" do
|
|
37
46
|
loader.flat_dependencies(
|
|
38
47
|
stack_name,
|
|
@@ -213,7 +213,9 @@ module Kontena::Cli::Stacks
|
|
|
213
213
|
result['dependencies'] = dependencies
|
|
214
214
|
result['source'] = raw_content
|
|
215
215
|
result['variables'] = variable_values(without_defaults: true, without_vault: true)
|
|
216
|
+
result['metadata'] = raw_yaml['meta'] || {}
|
|
216
217
|
end
|
|
218
|
+
|
|
217
219
|
if parent_name
|
|
218
220
|
result['parent'] = { 'name' => parent_name }
|
|
219
221
|
else
|
data/lib/kontena/client.rb
CHANGED
|
@@ -542,6 +542,14 @@ module Kontena
|
|
|
542
542
|
|
|
543
543
|
if data.is_a?(Hash) && data.has_key?('error') && data['error'].is_a?(Hash)
|
|
544
544
|
raise Kontena::Errors::StandardErrorHash.new(response.status, response.reason_phrase, data['error'])
|
|
545
|
+
elsif data.is_a?(Hash) && data.has_key?('errors') && data['errors'].is_a?(Array) && data['errors'].all? { |e| e.is_a?(Hash) }
|
|
546
|
+
error_with_status = data['errors'].find { |error| error.key?('status') }
|
|
547
|
+
if error_with_status
|
|
548
|
+
status = error_with_status['status']
|
|
549
|
+
else
|
|
550
|
+
status = response.status
|
|
551
|
+
end
|
|
552
|
+
raise Kontena::Errors::StandardErrorHash.new(status, response.reason_phrase, data)
|
|
545
553
|
elsif data.is_a?(Hash) && data.has_key?('error')
|
|
546
554
|
raise Kontena::Errors::StandardError.new(response.status, data['error'] + request_path)
|
|
547
555
|
elsif data.is_a?(String) && !data.empty?
|
|
@@ -292,11 +292,11 @@ begin
|
|
|
292
292
|
logs monitor show registry inspect)
|
|
293
293
|
if words[1]
|
|
294
294
|
if words[1] == 'registry' || words[1] == 'reg'
|
|
295
|
-
registry_sub_commands = %(push pull search show remove)
|
|
295
|
+
registry_sub_commands = %(push pull search show remove make-public make-private create)
|
|
296
296
|
if words[2]
|
|
297
297
|
if words[2] == 'push'
|
|
298
298
|
completion.push helper.yml_files(words[3])
|
|
299
|
-
elsif %w(pull search show remove rm).include?(words[2]) && words[4].nil?
|
|
299
|
+
elsif %w(pull search show remove rm make-public make-private).include?(words[2]) && words[4].nil?
|
|
300
300
|
completion.push helper.registry_stacks(words[3].to_s)
|
|
301
301
|
else
|
|
302
302
|
completion.push registry_sub_commands
|
data/lib/kontena/stacks_cache.rb
CHANGED
|
@@ -4,15 +4,10 @@ module Kontena
|
|
|
4
4
|
class StacksCache
|
|
5
5
|
class CachedStack
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
attr_accessor :version
|
|
7
|
+
attr_reader :stack_name
|
|
9
8
|
|
|
10
|
-
def initialize(
|
|
11
|
-
|
|
12
|
-
stack, version = stack.split(':', 2)
|
|
13
|
-
end
|
|
14
|
-
@stack = stack
|
|
15
|
-
@version = version
|
|
9
|
+
def initialize(stack_name)
|
|
10
|
+
@stack_name = stack_name
|
|
16
11
|
end
|
|
17
12
|
|
|
18
13
|
def read
|
|
@@ -24,7 +19,8 @@ module Kontena
|
|
|
24
19
|
end
|
|
25
20
|
|
|
26
21
|
def write(content)
|
|
27
|
-
|
|
22
|
+
puts "WHATHAT??? #{stack_name.inspect} #{stack_name.version} #{stack_name.stack_name}"
|
|
23
|
+
raise ArgumentError, "Stack name and version required" unless stack_name.stack_name && stack_name.version
|
|
28
24
|
unless File.directory?(File.dirname(path))
|
|
29
25
|
require 'fileutils'
|
|
30
26
|
FileUtils.mkdir_p(File.dirname(path))
|
|
@@ -37,12 +33,12 @@ module Kontena
|
|
|
37
33
|
end
|
|
38
34
|
|
|
39
35
|
def cached?
|
|
40
|
-
return false unless version
|
|
36
|
+
return false unless stack_name.version
|
|
41
37
|
File.exist?(path)
|
|
42
38
|
end
|
|
43
39
|
|
|
44
40
|
def path
|
|
45
|
-
path = File.expand_path(File.join(base_path, "#{
|
|
41
|
+
path = File.expand_path(File.join(base_path, "#{stack_name.stack_name}-#{stack_name.version}.yml"))
|
|
46
42
|
raise "Path traversal attempted" unless path.start_with?(base_path)
|
|
47
43
|
path
|
|
48
44
|
end
|
|
@@ -62,39 +58,40 @@ module Kontena
|
|
|
62
58
|
end
|
|
63
59
|
|
|
64
60
|
class << self
|
|
65
|
-
def pull(
|
|
66
|
-
cache(
|
|
61
|
+
def pull(stack_name)
|
|
62
|
+
cache(stack_name).read
|
|
67
63
|
end
|
|
68
64
|
|
|
69
65
|
def dputs(msg)
|
|
70
66
|
Kontena.logger.debug { msg }
|
|
71
67
|
end
|
|
72
68
|
|
|
73
|
-
def cache(
|
|
74
|
-
stack = CachedStack.new(
|
|
69
|
+
def cache(stack_name)
|
|
70
|
+
stack = CachedStack.new(stack_name)
|
|
75
71
|
if stack.cached?
|
|
76
72
|
dputs "Reading from cache: #{stack.path}"
|
|
77
73
|
else
|
|
78
|
-
dputs "Retrieving #{stack.
|
|
79
|
-
content = client.pull(
|
|
80
|
-
yaml = ::YAML.safe_load(content, [], [], true, stack.
|
|
81
|
-
|
|
74
|
+
dputs "Retrieving #{stack.stack_name} from registry"
|
|
75
|
+
content = client.pull(stack_name)
|
|
76
|
+
yaml = ::YAML.safe_load(content, [], [], true, stack.stack_name.to_s)
|
|
77
|
+
new_stack_name = Kontena::Cli::Stacks::StackName.new(yaml['stack'], yaml['version'])
|
|
78
|
+
puts new_stack_name.inspect
|
|
79
|
+
new_stack = CachedStack.new(new_stack_name)
|
|
82
80
|
if new_stack.cached?
|
|
83
81
|
dputs "Already cached"
|
|
84
82
|
stack = new_stack
|
|
85
83
|
else
|
|
86
|
-
stack.stack = yaml['stack']
|
|
87
|
-
stack.version = yaml['version']
|
|
88
84
|
dputs "Writing #{stack.path}"
|
|
89
|
-
|
|
90
|
-
dputs "#{
|
|
85
|
+
new_stack.write(content)
|
|
86
|
+
dputs "#{new_stack.stack_name} cached to #{new_stack.path}"
|
|
87
|
+
stack = new_stack
|
|
91
88
|
end
|
|
92
89
|
end
|
|
93
90
|
stack
|
|
94
91
|
end
|
|
95
92
|
|
|
96
|
-
def registry_url(
|
|
97
|
-
client.full_uri(
|
|
93
|
+
def registry_url(stack_name)
|
|
94
|
+
client.full_uri(stack_name)
|
|
98
95
|
end
|
|
99
96
|
|
|
100
97
|
def client
|
|
@@ -3,9 +3,11 @@ require 'kontena/client'
|
|
|
3
3
|
module Kontena
|
|
4
4
|
class StacksClient < Client
|
|
5
5
|
|
|
6
|
-
ACCEPT_JSON
|
|
7
|
-
ACCEPT_YAML
|
|
8
|
-
|
|
6
|
+
ACCEPT_JSON = { 'Accept' => 'application/json' }
|
|
7
|
+
ACCEPT_YAML = { 'Accept' => 'application/yaml' }
|
|
8
|
+
ACCEPT_JSONAPI = { 'Accept' => 'application/vnd.api+json' }
|
|
9
|
+
CT_YAML = { 'Content-Type' => 'application/yaml' }
|
|
10
|
+
CT_JSONAPI = { 'Content-Type' => 'application/vnd.api+json' }
|
|
9
11
|
|
|
10
12
|
def raise_unless_token
|
|
11
13
|
unless token && token['access_token']
|
|
@@ -20,45 +22,156 @@ module Kontena
|
|
|
20
22
|
end
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
def full_uri(stack_name
|
|
24
|
-
URI.join(api_url,
|
|
25
|
+
def full_uri(stack_name)
|
|
26
|
+
URI.join(api_url, path_to_version(stack_name)).to_s
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
def
|
|
28
|
-
|
|
29
|
+
def path_to_version(stack_name)
|
|
30
|
+
path_to_stack(stack_name) + "/stack-versions/%s" % (stack_name.version || 'latest')
|
|
29
31
|
end
|
|
30
32
|
|
|
31
|
-
def
|
|
33
|
+
def path_to_stack(stack_name)
|
|
34
|
+
"/v2/organizations/%s/stacks/%s" % [stack_name.user, stack_name.stack]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def push(stack_name, data)
|
|
32
38
|
raise_unless_token
|
|
33
|
-
post(
|
|
39
|
+
post(
|
|
40
|
+
'/v2/stack-files',
|
|
41
|
+
{
|
|
42
|
+
'data' => {
|
|
43
|
+
'type' => 'stack-files',
|
|
44
|
+
'attributes' => { 'content' => data }
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{},
|
|
48
|
+
CT_JSONAPI,
|
|
49
|
+
true
|
|
50
|
+
)
|
|
34
51
|
end
|
|
35
52
|
|
|
36
|
-
def show(stack_name,
|
|
53
|
+
def show(stack_name, include_prerelease: true)
|
|
37
54
|
raise_unless_read_token
|
|
38
|
-
get("#{
|
|
55
|
+
result = get("#{path_to_stack(stack_name)}", { 'include' => 'latest-version', 'include-prerelease' => include_prerelease }, ACCEPT_JSONAPI)
|
|
56
|
+
if result['included']
|
|
57
|
+
latest = result['included'].find { |i| i['type'] == 'stack-versions' }
|
|
58
|
+
return result unless latest
|
|
59
|
+
result['data']['attributes']['latest-version'] = {}
|
|
60
|
+
result['data']['attributes']['latest-version']['version'] = latest['attributes']['version']
|
|
61
|
+
result['data']['attributes']['latest-version']['description'] = latest['attributes']['description']
|
|
62
|
+
result['data']['attributes']['latest-version']['meta'] = latest['meta']
|
|
63
|
+
end
|
|
64
|
+
result
|
|
39
65
|
end
|
|
40
66
|
|
|
41
|
-
def versions(stack_name)
|
|
67
|
+
def versions(stack_name, include_prerelease: true, include_deleted: false)
|
|
42
68
|
raise_unless_read_token
|
|
43
|
-
get("#{
|
|
69
|
+
get("#{path_to_stack(stack_name)}/stack-versions", { 'include-prerelease' => include_prerelease, 'include-deleted' => include_deleted}, ACCEPT_JSONAPI).dig('data')
|
|
44
70
|
end
|
|
45
71
|
|
|
46
|
-
def pull(stack_name
|
|
72
|
+
def pull(stack_name)
|
|
47
73
|
raise_unless_read_token
|
|
48
|
-
get(
|
|
74
|
+
get(path_to_version(stack_name) + '/yaml', nil, ACCEPT_YAML)
|
|
49
75
|
rescue StandardError => ex
|
|
50
|
-
ex.message << " : #{
|
|
76
|
+
ex.message << " : #{path_to_version(stack_name)}"
|
|
51
77
|
raise ex, ex.message
|
|
52
78
|
end
|
|
53
79
|
|
|
54
|
-
def search(query)
|
|
80
|
+
def search(query, tags: [], include_prerelease: true, include_private: true, include_versionless: true)
|
|
55
81
|
raise_unless_read_token
|
|
56
|
-
|
|
82
|
+
if tags.empty?
|
|
83
|
+
result = get('/v2/stacks', { 'query' => query, 'include' => 'latest-version', 'include-prerelease' => include_prerelease, 'include-private' => include_private, 'include-versionless' => include_versionless }, ACCEPT_JSONAPI)
|
|
84
|
+
else
|
|
85
|
+
result = get('/v2/tags/%s/stacks' % tags.join(','), { 'query' => query, 'include' => 'latest-version', 'include-prerelease' => include_prerelease, 'include-private' => include_private }, ACCEPT_JSONAPI)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
data = result.dig('data')
|
|
89
|
+
included = result.dig('included')
|
|
90
|
+
if included
|
|
91
|
+
data.each do |row|
|
|
92
|
+
name = '%s/%s' % [row.fetch('attributes', {}).fetch('organization-id'), row.fetch('attributes', {}).fetch('name')]
|
|
93
|
+
next if name.nil?
|
|
94
|
+
included_version = included.find { |i| i.fetch('attributes', {}).fetch('name') == name }
|
|
95
|
+
if included_version
|
|
96
|
+
row['attributes']['latest-version'] = {}
|
|
97
|
+
row['attributes']['latest-version']['version'] = included_version['attributes']['version']
|
|
98
|
+
row['attributes']['latest-version']['description'] = included_version['attributes']['description']
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
data
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def destroy(stack_name)
|
|
106
|
+
raise_unless_token
|
|
107
|
+
if stack_name.version
|
|
108
|
+
id = stack_version_id(stack_name)
|
|
109
|
+
if id.nil?
|
|
110
|
+
raise Kontena::Errors::StandardError.new(404, 'Not found')
|
|
111
|
+
end
|
|
112
|
+
delete('/v2/stack-versions/%s' % id, nil, {}, ACCEPT_JSONAPI)
|
|
113
|
+
else
|
|
114
|
+
id = stack_id(stack_name)
|
|
115
|
+
if id.nil?
|
|
116
|
+
raise Kontena::Errors::StandardError.new(404, 'Not found')
|
|
117
|
+
end
|
|
118
|
+
delete('/v2/stacks/%s' % id, nil, {}, ACCEPT_JSONAPI)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def make_private(stack_name)
|
|
123
|
+
change_visibility(stack_name, is_private: true)
|
|
57
124
|
end
|
|
58
125
|
|
|
59
|
-
def
|
|
126
|
+
def make_public(stack_name)
|
|
127
|
+
change_visibility(stack_name, is_private: false)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def create(stack_name, is_private: true)
|
|
131
|
+
post(
|
|
132
|
+
'/v2/stacks',
|
|
133
|
+
stack_data(stack_name, is_private: is_private),
|
|
134
|
+
{},
|
|
135
|
+
CT_JSONAPI.merge(ACCEPT_JSONAPI)
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
def stack_id(stack_name)
|
|
142
|
+
show(stack_name).dig('data', 'id')
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def stack_version_id(stack_name)
|
|
146
|
+
version = versions(stack_name, include_prerelease: true).find { |v| v.dig('attributes', 'version') == stack_name.version }
|
|
147
|
+
if version
|
|
148
|
+
version['id']
|
|
149
|
+
else
|
|
150
|
+
nil
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def change_visibility(stack_name, is_private: true)
|
|
60
155
|
raise_unless_token
|
|
61
|
-
|
|
156
|
+
put(
|
|
157
|
+
'/v2/stacks/%s' % stack_id(stack_name),
|
|
158
|
+
stack_data(stack_name, is_private: is_private),
|
|
159
|
+
{},
|
|
160
|
+
CT_JSONAPI.merge(ACCEPT_JSONAPI)
|
|
161
|
+
)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def stack_data(stack_name, is_private: true)
|
|
165
|
+
{
|
|
166
|
+
data: {
|
|
167
|
+
type: 'stacks',
|
|
168
|
+
attributes: {
|
|
169
|
+
'name' => stack_name.stack,
|
|
170
|
+
'organization-id' => stack_name.user,
|
|
171
|
+
'is-private' => is_private
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
62
175
|
end
|
|
63
176
|
end
|
|
64
177
|
end
|
data/omnibus/wrappers/sh/kontena
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
stack: user/stackname
|
|
2
|
+
version: 0.1.1
|
|
3
|
+
services:
|
|
4
|
+
wordpress:
|
|
5
|
+
extends:
|
|
6
|
+
file: docker-compose_v2.yml
|
|
7
|
+
service: wordpress
|
|
8
|
+
stateful: true
|
|
9
|
+
environment:
|
|
10
|
+
WORDPRESS_DB_PASSWORD: ${STACK}_secret
|
|
11
|
+
instances: 2
|
|
12
|
+
deploy:
|
|
13
|
+
strategy: ha
|
|
14
|
+
mysql:
|
|
15
|
+
extends:
|
|
16
|
+
file: docker-compose_v2.yml
|
|
17
|
+
service: mysql
|
|
18
|
+
stateful: true
|
|
19
|
+
environment:
|
|
20
|
+
- MYSQL_ROOT_PASSWORD=${STACK}_secret
|
|
21
|
+
meta:
|
|
22
|
+
tags:
|
|
23
|
+
- tag1
|
|
24
|
+
- tag2
|
|
25
|
+
readme: |
|
|
26
|
+
Text goes
|
|
27
|
+
here
|
|
28
|
+
required_kontena_version: ">= 0.5.0"
|
|
@@ -10,6 +10,7 @@ describe Kontena::Cli::Stacks::InstallCommand do
|
|
|
10
10
|
|
|
11
11
|
before(:each) do
|
|
12
12
|
ENV['STACK'] = nil
|
|
13
|
+
allow(client).to receive(:server_version).and_return(Kontena::Cli::VERSION)
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
describe '#execute' do
|
|
@@ -25,7 +26,8 @@ describe Kontena::Cli::Stacks::InstallCommand do
|
|
|
25
26
|
'dependencies' => nil,
|
|
26
27
|
'source' => /stack:/,
|
|
27
28
|
'parent' => nil,
|
|
28
|
-
'expose' => nil
|
|
29
|
+
'expose' => nil,
|
|
30
|
+
'metadata' => {}
|
|
29
31
|
}
|
|
30
32
|
end
|
|
31
33
|
|
|
@@ -85,6 +87,29 @@ describe Kontena::Cli::Stacks::InstallCommand do
|
|
|
85
87
|
subject.run(['-n', 'deptest', '--no-deploy', '-v', 'dep_1.dep_1.dep_var=1', fixture_path('stack-with-dependencies.yml')])
|
|
86
88
|
end
|
|
87
89
|
end
|
|
90
|
+
|
|
91
|
+
context 'with a stack including metadata' do
|
|
92
|
+
let(:stack_meta_expectation) do
|
|
93
|
+
stack_expectation.merge(
|
|
94
|
+
'metadata' => hash_including(
|
|
95
|
+
'tags' => array_including('tag1', 'tag2'),
|
|
96
|
+
'readme' => /Text goes/,
|
|
97
|
+
'required_kontena_version' => ">= 0.5.0"
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'includes the metadata in the json sent to master' do
|
|
103
|
+
expect(client).to receive(:post).with('grids/test-grid/stacks', hash_including(stack_meta_expectation))
|
|
104
|
+
subject.run(['--no-deploy', fixture_path('kontena_v3_with_metadata.yml')])
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'requires force if master version does not match metadata required_kontena_version' do
|
|
108
|
+
expect(client).to receive(:server_version).and_return('0.2.0')
|
|
109
|
+
expect(subject).to receive(:confirm).and_call_original
|
|
110
|
+
expect{subject.run(['--no-deploy', fixture_path('kontena_v3_with_metadata.yml')])}.to exit_with_error.and output(/version/).to_stdout
|
|
111
|
+
end
|
|
112
|
+
end
|
|
88
113
|
end
|
|
89
114
|
|
|
90
115
|
context 'variable value input' do
|
|
@@ -11,6 +11,7 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
|
|
|
11
11
|
|
|
12
12
|
before(:each) do
|
|
13
13
|
ENV['STACK'] = nil
|
|
14
|
+
allow(client).to receive(:server_version).and_return(Kontena::Cli::VERSION)
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
describe '#execute' do
|
|
@@ -69,6 +70,13 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
|
|
|
69
70
|
subject.run(['--force', 'stack-a', fixture_path('kontena_v3.yml')])
|
|
70
71
|
end
|
|
71
72
|
|
|
73
|
+
it 'requires force if master version does not match metadata required_kontena_version' do
|
|
74
|
+
expect(client).to receive(:get).with('stacks/test-grid/stack-a').and_return(stack_response)
|
|
75
|
+
expect(client).to receive(:server_version).and_return('0.2.0')
|
|
76
|
+
expect(subject).to receive(:confirm).and_call_original
|
|
77
|
+
expect{subject.run(['--no-deploy', 'stack-a', fixture_path('kontena_v3_with_metadata.yml')])}.to exit_with_error.and output(/version/).to_stdout
|
|
78
|
+
end
|
|
79
|
+
|
|
72
80
|
context '--no-deploy option' do
|
|
73
81
|
it 'does not trigger deploy' do
|
|
74
82
|
expect(client).to receive(:get).with('stacks/test-grid/stack-a').and_return(stack_response)
|
|
@@ -79,7 +87,6 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
|
|
|
79
87
|
subject.run(['--no-deploy', '--force', 'stack-a', fixture_path('kontena_v3.yml')])
|
|
80
88
|
end
|
|
81
89
|
end
|
|
82
|
-
|
|
83
90
|
context 'with a stack including dependencies' do
|
|
84
91
|
|
|
85
92
|
let(:expectation) {{ 'name' => 'deptest', 'stack' => 'user/depstack1' }}
|
|
@@ -61,8 +61,7 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
|
61
61
|
|
|
62
62
|
it 'returns result hash' do
|
|
63
63
|
result = subject.execute
|
|
64
|
-
|
|
65
|
-
%w(
|
|
64
|
+
top_level_fields = %w(
|
|
66
65
|
stack
|
|
67
66
|
version
|
|
68
67
|
name
|
|
@@ -74,9 +73,9 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
|
74
73
|
source
|
|
75
74
|
variables
|
|
76
75
|
parent
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
metadata
|
|
77
|
+
)
|
|
78
|
+
expect(result).to match hash_including(*top_level_fields)
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
context 'when extending services' do
|
|
@@ -178,7 +177,9 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
|
178
177
|
end
|
|
179
178
|
|
|
180
179
|
it 'extends services from a registry stack' do
|
|
181
|
-
expect(Kontena::StacksCache).to receive(:pull).at_least(:once)
|
|
180
|
+
expect(Kontena::StacksCache).to receive(:pull).at_least(:once) do |stackname|
|
|
181
|
+
expect(stackname.to_s).to eq 'registrystack/compose:1.0.0'
|
|
182
|
+
end.and_return(File.read(fixture_path('docker-compose_v2.yml')))
|
|
182
183
|
expect(subject.execute['services']).to match array_including(
|
|
183
184
|
hash_including(
|
|
184
185
|
"instances"=>2,
|
|
@@ -332,8 +333,7 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
|
332
333
|
|
|
333
334
|
it 'discards empty lines' do
|
|
334
335
|
result = env_file
|
|
335
|
-
result <<
|
|
336
|
-
'
|
|
336
|
+
result << " \n \n"
|
|
337
337
|
allow(File).to receive(:readlines).with('.env').and_return(result)
|
|
338
338
|
variables = subject.send(:read_env_file, '.env')
|
|
339
339
|
expect(variables).to eq([
|
|
@@ -23,7 +23,7 @@ describe Kontena::Cli::Stacks::YAML::RegistryLoader do
|
|
|
23
23
|
let(:subject) { described_class.new('user/stack') }
|
|
24
24
|
|
|
25
25
|
before do
|
|
26
|
-
allow(Kontena::StacksCache).to receive(:pull).with(
|
|
26
|
+
allow(Kontena::StacksCache).to receive(:pull).with(duck_type(:stack_name)).and_return(
|
|
27
27
|
fixture('kontena_v3.yml')
|
|
28
28
|
)
|
|
29
29
|
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.5.0.
|
|
4
|
+
version: 1.5.0.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: 2018-02-
|
|
11
|
+
date: 2018-02-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -407,6 +407,9 @@ files:
|
|
|
407
407
|
- lib/kontena/cli/stacks/list_command.rb
|
|
408
408
|
- lib/kontena/cli/stacks/logs_command.rb
|
|
409
409
|
- lib/kontena/cli/stacks/monitor_command.rb
|
|
410
|
+
- lib/kontena/cli/stacks/registry/create_command.rb
|
|
411
|
+
- lib/kontena/cli/stacks/registry/make_private_command.rb
|
|
412
|
+
- lib/kontena/cli/stacks/registry/make_public_command.rb
|
|
410
413
|
- lib/kontena/cli/stacks/registry/pull_command.rb
|
|
411
414
|
- lib/kontena/cli/stacks/registry/push_command.rb
|
|
412
415
|
- lib/kontena/cli/stacks/registry/remove_command.rb
|
|
@@ -535,6 +538,7 @@ files:
|
|
|
535
538
|
- spec/fixtures/kontena_build_v3.yml
|
|
536
539
|
- spec/fixtures/kontena_v3.yml
|
|
537
540
|
- spec/fixtures/kontena_v3_with_compose_variables.yml
|
|
541
|
+
- spec/fixtures/kontena_v3_with_metadata.yml
|
|
538
542
|
- spec/fixtures/kontena_v3_with_registry_extends.yml
|
|
539
543
|
- spec/fixtures/stack-internal-extend.yml
|
|
540
544
|
- spec/fixtures/stack-invalid.yml
|
|
@@ -718,6 +722,7 @@ test_files:
|
|
|
718
722
|
- spec/fixtures/kontena_build_v3.yml
|
|
719
723
|
- spec/fixtures/kontena_v3.yml
|
|
720
724
|
- spec/fixtures/kontena_v3_with_compose_variables.yml
|
|
725
|
+
- spec/fixtures/kontena_v3_with_metadata.yml
|
|
721
726
|
- spec/fixtures/kontena_v3_with_registry_extends.yml
|
|
722
727
|
- spec/fixtures/stack-internal-extend.yml
|
|
723
728
|
- spec/fixtures/stack-invalid.yml
|