kontena-cli 1.4.0.pre6 → 1.4.0.pre7

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.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/VERSION +1 -1
  4. data/bin/kontena +1 -1
  5. data/kontena-cli.gemspec +3 -3
  6. data/lib/kontena/cli/certificate/authorize_command.rb +67 -6
  7. data/lib/kontena/cli/certificate/get_command.rb +7 -0
  8. data/lib/kontena/cli/certificate/list_command.rb +75 -0
  9. data/lib/kontena/cli/certificate/register_command.rb +13 -2
  10. data/lib/kontena/cli/certificate/request_command.rb +20 -0
  11. data/lib/kontena/cli/certificate/show_command.rb +19 -0
  12. data/lib/kontena/cli/certificate_command.rb +4 -1
  13. data/lib/kontena/cli/cloud/master/add_command.rb +1 -1
  14. data/lib/kontena/cli/common.rb +21 -33
  15. data/lib/kontena/cli/etcd/health_command.rb +21 -27
  16. data/lib/kontena/cli/helpers/exec_helper.rb +15 -6
  17. data/lib/kontena/cli/helpers/health_helper.rb +12 -0
  18. data/lib/kontena/cli/helpers/log_helper.rb +2 -2
  19. data/lib/kontena/cli/helpers/time_helper.rb +29 -0
  20. data/lib/kontena/cli/master/init_cloud_command.rb +19 -0
  21. data/lib/kontena/cli/master/list_command.rb +1 -1
  22. data/lib/kontena/cli/master/ssh_command.rb +3 -1
  23. data/lib/kontena/cli/master/use_command.rb +1 -2
  24. data/lib/kontena/cli/node_command.rb +1 -0
  25. data/lib/kontena/cli/nodes/health_command.rb +28 -13
  26. data/lib/kontena/cli/nodes/list_command.rb +19 -3
  27. data/lib/kontena/cli/nodes/show_command.rb +4 -2
  28. data/lib/kontena/cli/nodes/ssh_command.rb +5 -2
  29. data/lib/kontena/cli/nodes/update_command.rb +2 -0
  30. data/lib/kontena/cli/plugins/install_command.rb +11 -8
  31. data/lib/kontena/cli/plugins/list_command.rb +5 -3
  32. data/lib/kontena/cli/plugins/search_command.rb +4 -2
  33. data/lib/kontena/cli/plugins/show_command.rb +17 -0
  34. data/lib/kontena/cli/plugins/uninstall_command.rb +9 -13
  35. data/lib/kontena/cli/registry/create_command.rb +1 -1
  36. data/lib/kontena/cli/services/create_command.rb +6 -0
  37. data/lib/kontena/cli/services/services_helper.rb +33 -6
  38. data/lib/kontena/cli/services/update_command.rb +6 -0
  39. data/lib/kontena/cli/stacks/build_command.rb +3 -3
  40. data/lib/kontena/cli/stacks/common.rb +105 -90
  41. data/lib/kontena/cli/stacks/deploy_command.rb +7 -3
  42. data/lib/kontena/cli/stacks/install_command.rb +39 -6
  43. data/lib/kontena/cli/stacks/list_command.rb +36 -4
  44. data/lib/kontena/cli/stacks/logs_command.rb +9 -2
  45. data/lib/kontena/cli/stacks/registry/pull_command.rb +2 -2
  46. data/lib/kontena/cli/stacks/registry/push_command.rb +20 -9
  47. data/lib/kontena/cli/stacks/registry/remove_command.rb +4 -4
  48. data/lib/kontena/cli/stacks/registry/show_command.rb +4 -4
  49. data/lib/kontena/cli/stacks/remove_command.rb +27 -1
  50. data/lib/kontena/cli/stacks/service_generator.rb +12 -2
  51. data/lib/kontena/cli/stacks/show_command.rb +35 -5
  52. data/lib/kontena/cli/stacks/stack_name.rb +71 -0
  53. data/lib/kontena/cli/stacks/upgrade_command.rb +127 -14
  54. data/lib/kontena/cli/stacks/validate_command.rb +38 -10
  55. data/lib/kontena/cli/stacks/yaml/custom_validators/certificates_validator.rb +22 -0
  56. data/lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb +1 -2
  57. data/lib/kontena/cli/stacks/yaml/reader.rb +211 -185
  58. data/lib/kontena/cli/stacks/yaml/service_extender.rb +6 -12
  59. data/lib/kontena/cli/stacks/yaml/stack_file_loader.rb +97 -0
  60. data/lib/kontena/cli/stacks/yaml/stack_file_loader/file_loader.rb +41 -0
  61. data/lib/kontena/cli/stacks/yaml/stack_file_loader/registry_loader.rb +24 -0
  62. data/lib/kontena/cli/stacks/yaml/stack_file_loader/uri_loader.rb +23 -0
  63. data/lib/kontena/cli/stacks/yaml/validations.rb +16 -0
  64. data/lib/kontena/cli/stacks/yaml/validator_v3.rb +25 -8
  65. data/lib/kontena/client.rb +2 -2
  66. data/lib/kontena/command.rb +11 -0
  67. data/lib/kontena/main_command.rb +3 -1
  68. data/lib/kontena/plugin_manager.rb +11 -198
  69. data/lib/kontena/plugin_manager/cleaner.rb +33 -0
  70. data/lib/kontena/plugin_manager/common.rb +86 -0
  71. data/lib/kontena/plugin_manager/installer.rb +54 -0
  72. data/lib/kontena/plugin_manager/loader.rb +93 -0
  73. data/lib/kontena/plugin_manager/rubygems_client.rb +42 -23
  74. data/lib/kontena/plugin_manager/uninstaller.rb +34 -0
  75. data/lib/kontena/util.rb +24 -0
  76. data/lib/kontena_cli.rb +1 -0
  77. data/omnibus/config/projects/kontena.rb +7 -1
  78. data/omnibus/config/software/{kontena.rb → kontena-cli.rb} +2 -0
  79. data/spec/fixtures/api/node.json +2 -1
  80. data/spec/fixtures/stack-internal-extend.yml +6 -1
  81. data/spec/fixtures/stack-with-dependencies-dep-1-1.yml +8 -0
  82. data/spec/fixtures/stack-with-dependencies-dep-1.yml +17 -0
  83. data/spec/fixtures/stack-with-dependencies-dep-2.yml +8 -0
  84. data/spec/fixtures/stack-with-dependencies-dep-3.yml +5 -0
  85. data/spec/fixtures/stack-with-dependencies-dep_2-removed.yml +17 -0
  86. data/spec/fixtures/stack-with-dependencies-dep_3-added.yml +25 -0
  87. data/spec/fixtures/stack-with-dependencies.yml +22 -0
  88. data/spec/fixtures/stack-with-variables.yml +3 -0
  89. data/spec/kontena/cli/etcd/health_command_spec.rb +45 -33
  90. data/spec/kontena/cli/helpers/exec_helper_spec.rb +2 -1
  91. data/spec/kontena/cli/master/init_cloud_command_spec.rb +14 -0
  92. data/spec/kontena/cli/nodes/health_command_spec.rb +74 -10
  93. data/spec/kontena/cli/nodes/list_command_spec.rb +381 -232
  94. data/spec/kontena/cli/nodes/show_command_spec.rb +31 -0
  95. data/spec/kontena/cli/nodes/ssh_command_spec.rb +18 -3
  96. data/spec/kontena/cli/plugins/install_command_spec.rb +1 -1
  97. data/spec/kontena/cli/stacks/build_command_spec.rb +6 -12
  98. data/spec/kontena/cli/stacks/common_spec.rb +42 -69
  99. data/spec/kontena/cli/stacks/install_command_spec.rb +57 -31
  100. data/spec/kontena/cli/stacks/list_command_spec.rb +44 -0
  101. data/spec/kontena/cli/stacks/logs_command_spec.rb +12 -1
  102. data/spec/kontena/cli/stacks/remove_command_spec.rb +39 -0
  103. data/spec/kontena/cli/stacks/show_command_spec.rb +16 -0
  104. data/spec/kontena/cli/stacks/stack_name_spec.rb +21 -0
  105. data/spec/kontena/cli/stacks/upgrade_command_spec.rb +73 -56
  106. data/spec/kontena/cli/stacks/validate_command_spec.rb +81 -0
  107. data/spec/kontena/cli/stacks/yaml/custom_validators/affinities_validator_spec.rb +22 -0
  108. data/spec/kontena/cli/stacks/yaml/reader_spec.rb +173 -169
  109. data/spec/kontena/cli/stacks/yaml/service_extender_spec.rb +12 -3
  110. data/spec/kontena/cli/stacks/yaml/stack_file_loader/file_loader_spec.rb +47 -0
  111. data/spec/kontena/cli/stacks/yaml/stack_file_loader/registry_loader_spec.rb +53 -0
  112. data/spec/kontena/cli/stacks/yaml/stack_file_loader/uri_loader_spec.rb +53 -0
  113. data/spec/kontena/cli/stacks/yaml/stack_file_loader_spec.rb +104 -0
  114. data/spec/kontena/cli/stacks/yaml/validator_v3_spec.rb +19 -0
  115. data/spec/kontena/plugin_manager/cleaner_spec.rb +20 -0
  116. data/spec/kontena/plugin_manager/common_spec.rb +39 -0
  117. data/spec/kontena/plugin_manager/installer_spec.rb +50 -0
  118. data/spec/kontena/plugin_manager/loader_spec.rb +5 -0
  119. data/spec/kontena/plugin_manager/rubygems_client_spec.rb +11 -25
  120. data/spec/kontena/plugin_manager/uninstaller_spec.rb +19 -0
  121. data/spec/kontena/plugin_manager_spec.rb +7 -7
  122. metadata +64 -97
  123. data/lib/kontena/cli/app_command.rb +0 -22
  124. data/lib/kontena/cli/apps/build_command.rb +0 -28
  125. data/lib/kontena/cli/apps/common.rb +0 -172
  126. data/lib/kontena/cli/apps/config_command.rb +0 -25
  127. data/lib/kontena/cli/apps/deploy_command.rb +0 -137
  128. data/lib/kontena/cli/apps/docker_compose_generator.rb +0 -61
  129. data/lib/kontena/cli/apps/docker_helper.rb +0 -80
  130. data/lib/kontena/cli/apps/dockerfile_generator.rb +0 -16
  131. data/lib/kontena/cli/apps/init_command.rb +0 -89
  132. data/lib/kontena/cli/apps/kontena_yml_generator.rb +0 -105
  133. data/lib/kontena/cli/apps/list_command.rb +0 -59
  134. data/lib/kontena/cli/apps/logs_command.rb +0 -37
  135. data/lib/kontena/cli/apps/monitor_command.rb +0 -93
  136. data/lib/kontena/cli/apps/remove_command.rb +0 -74
  137. data/lib/kontena/cli/apps/restart_command.rb +0 -39
  138. data/lib/kontena/cli/apps/scale_command.rb +0 -33
  139. data/lib/kontena/cli/apps/service_generator.rb +0 -114
  140. data/lib/kontena/cli/apps/service_generator_v2.rb +0 -27
  141. data/lib/kontena/cli/apps/show_command.rb +0 -23
  142. data/lib/kontena/cli/apps/start_command.rb +0 -40
  143. data/lib/kontena/cli/apps/stop_command.rb +0 -40
  144. data/lib/kontena/cli/apps/yaml/custom_validators/affinities_validator.rb +0 -19
  145. data/lib/kontena/cli/apps/yaml/custom_validators/build_validator.rb +0 -22
  146. data/lib/kontena/cli/apps/yaml/custom_validators/extends_validator.rb +0 -20
  147. data/lib/kontena/cli/apps/yaml/custom_validators/hooks_validator.rb +0 -54
  148. data/lib/kontena/cli/apps/yaml/custom_validators/secrets_validator.rb +0 -22
  149. data/lib/kontena/cli/apps/yaml/reader.rb +0 -213
  150. data/lib/kontena/cli/apps/yaml/service_extender.rb +0 -77
  151. data/lib/kontena/cli/apps/yaml/validations.rb +0 -71
  152. data/lib/kontena/cli/apps/yaml/validator.rb +0 -38
  153. data/lib/kontena/cli/apps/yaml/validator_v2.rb +0 -53
  154. data/spec/fixtures/app.json +0 -42
  155. data/spec/fixtures/health.yml +0 -26
  156. data/spec/fixtures/kontena-build.yml +0 -16
  157. data/spec/fixtures/kontena-internal-extend.yml +0 -8
  158. data/spec/fixtures/kontena-invalid.yml +0 -4
  159. data/spec/fixtures/kontena-with-env-file.yml +0 -18
  160. data/spec/fixtures/kontena-with-variables.yml +0 -19
  161. data/spec/fixtures/kontena.yml +0 -17
  162. data/spec/fixtures/kontena_build_v2.yml +0 -26
  163. data/spec/fixtures/kontena_numeric_version.yml +0 -9
  164. data/spec/fixtures/kontena_v2.yml +0 -35
  165. data/spec/fixtures/mysql.yml +0 -3
  166. data/spec/fixtures/wordpress-scaled.yml +0 -3
  167. data/spec/fixtures/wordpress.yml +0 -2
  168. data/spec/kontena/cli/app/build_command_spec.rb +0 -55
  169. data/spec/kontena/cli/app/common_spec.rb +0 -110
  170. data/spec/kontena/cli/app/config_command_spec.rb +0 -78
  171. data/spec/kontena/cli/app/deploy_command_spec.rb +0 -217
  172. data/spec/kontena/cli/app/docker_helper_spec.rb +0 -155
  173. data/spec/kontena/cli/app/init_command_spec.rb +0 -109
  174. data/spec/kontena/cli/app/logs_command_spec.rb +0 -131
  175. data/spec/kontena/cli/app/scale_spec.rb +0 -51
  176. data/spec/kontena/cli/app/service_generator_spec.rb +0 -384
  177. data/spec/kontena/cli/app/service_generator_v2_spec.rb +0 -73
  178. data/spec/kontena/cli/app/yaml/reader_spec.rb +0 -457
  179. data/spec/kontena/cli/app/yaml/service_extender_spec.rb +0 -127
  180. data/spec/kontena/cli/app/yaml/validator_spec.rb +0 -380
  181. data/spec/kontena/cli/app/yaml/validator_v2_spec.rb +0 -301
@@ -10,6 +10,8 @@ module Kontena::Cli::Stacks
10
10
 
11
11
  parameter "NAME", "Stack name"
12
12
 
13
+ option '--[no-]wait', :flag, 'Do not wait service deployment', default: true
14
+
13
15
  requires_current_master
14
16
  requires_current_master_token
15
17
 
@@ -18,10 +20,12 @@ module Kontena::Cli::Stacks
18
20
  spinner "Triggering deployment of stack #{pastel.cyan(name)}" do
19
21
  deployment = deploy_stack(name)
20
22
  end
21
- spinner "Waiting for deployment to start" do
22
- wait_for_deployment_to_start(deployment)
23
+ if wait?
24
+ spinner "Waiting for deployment to start" do
25
+ wait_for_deployment_to_start(deployment)
26
+ end
27
+ wait_for_deploy_to_finish(deployment)
23
28
  end
24
- wait_for_deploy_to_finish(deployment)
25
29
  end
26
30
 
27
31
  def deploy_stack(name)
@@ -1,4 +1,5 @@
1
1
  require_relative 'common'
2
+ require_relative 'yaml/stack_file_loader'
2
3
 
3
4
  module Kontena::Cli::Stacks
4
5
  class InstallCommand < Kontena::Command
@@ -16,21 +17,53 @@ module Kontena::Cli::Stacks
16
17
  include Common::StackValuesToOption
17
18
  include Common::StackValuesFromOption
18
19
 
20
+ option '--parent-name', '[PARENT_NAME]', "Set parent stack name", hidden: true
21
+ option '--skip-dependencies', :flag, "Do not install any stack dependencies"
22
+
19
23
  requires_current_master
20
24
  requires_current_master_token
21
25
 
22
26
  def execute
23
- stack = stack_read_and_dump(filename, name: name, values: values)
27
+ set_env_variables(stack_name, current_grid)
28
+
29
+ install_dependencies unless skip_dependencies?
30
+
31
+ hint_on_validation_notifications(reader.notifications)
32
+ abort_on_validation_errors(reader.errors)
33
+
34
+ dump_variables if values_to
35
+
36
+ create_stack
37
+ deploy_stack if deploy?
38
+ end
39
+
40
+ def install_dependencies
41
+ dependencies = loader.dependencies
42
+ return if dependencies.nil?
43
+ dependencies.each do |dependency|
44
+ target_name = "#{stack_name}-#{dependency['name']}"
45
+ caret "Installing dependency #{pastel.cyan(dependency[:stack])} as #{pastel.cyan(target_name)}"
46
+ cmd = ['stack', 'install', '-n', target_name, '--parent-name', stack_name]
47
+
48
+ dependency['variables'].merge(dependency_values_from_options(dependency['name'])).each do |key, value|
49
+ cmd.concat ['-v', "#{key}=#{value}"]
50
+ end
51
+
52
+ cmd << '--no-deploy' unless deploy?
53
+
54
+ cmd << dependency['stack']
55
+ Kontena.run!(cmd)
56
+ end
57
+ end
24
58
 
25
- stack['name'] = name if name
59
+ def create_stack
26
60
  spinner "Creating stack #{pastel.cyan(stack['name'])} " do
27
- create_stack(stack)
61
+ client.post("grids/#{current_grid}/stacks", stack)
28
62
  end
29
- Kontena.run!(['stack', 'deploy', stack['name']]) if deploy?
30
63
  end
31
64
 
32
- def create_stack(stack)
33
- client.post("grids/#{current_grid}/stacks", stack)
65
+ def deploy_stack
66
+ Kontena.run!(['stack', 'deploy', stack['name']])
34
67
  end
35
68
  end
36
69
  end
@@ -19,8 +19,22 @@ module Kontena::Cli::Stacks
19
19
  default: Kontena.pastel.dim('⊝').freeze
20
20
  }
21
21
 
22
- def stacks
23
- client.get("grids/#{current_grid}/stacks")['stacks']
22
+ def stacks_by_names(stacks, name_list)
23
+ name_list.map { |name| stacks.find { |stack| stack['name'] == name } }.compact
24
+ end
25
+
26
+ def build_depths(stacks)
27
+ stacks.sort_by { |s| s['name'] }.each do |stack|
28
+ stack['depth'] += 1
29
+ stacks_by_names(stacks, stack['children'].map { |n| n['name'] }).each do |child_stack|
30
+ child_stack['depth'] += stack['depth']
31
+ end
32
+ end
33
+ stacks
34
+ end
35
+
36
+ def get_stacks
37
+ client.get("grids/#{current_grid}/stacks")['stacks'].tap { |stacks| stacks.map { |stack| stack['depth'] = 0 } }
24
38
  end
25
39
 
26
40
  def fields
@@ -35,9 +49,11 @@ module Kontena::Cli::Stacks
35
49
  end
36
50
 
37
51
  def execute
38
- print_table(stacks) do |row|
52
+ stacks = build_depths(get_stacks)
53
+
54
+ print_table(stacks) do |row|
39
55
  next if quiet?
40
- row['name'] = health_icon(stack_health(row)) + " " + row['name']
56
+ row['name'] = health_icon(stack_health(row)) + " " + tree_icon(row) + row['name']
41
57
  row['stack'] = "#{row['stack']}:#{row['version']}"
42
58
  row['services_count'] = row['services'].size
43
59
  row['ports'] = stack_ports(row).join(',')
@@ -59,6 +75,22 @@ module Kontena::Cli::Stacks
59
75
  HEALTH_ICONS.fetch(health) { HEALTH_ICONS[:default] }
60
76
  end
61
77
 
78
+ def tree_icon(row)
79
+ parent = row['parent']
80
+ children = row['children'] || []
81
+ if parent.nil? && children.empty?
82
+ # solo
83
+ char = ''
84
+ elsif parent.nil? && !children.empty?
85
+ char = ''
86
+ elsif !parent.nil?
87
+ char = '┗━'
88
+ end
89
+ left_pad = ' ' * (2 * (row['depth'] - 1))
90
+ right_pad = row['depth'] > 1 ? '━' : ''
91
+ left_pad + char + right_pad
92
+ end
93
+
62
94
  # @param [Hash] stack
63
95
  # @return [Array<String>]
64
96
  def stack_ports(stack)
@@ -9,13 +9,20 @@ module Kontena::Cli::Stacks
9
9
  banner "Shows logs from services in a stack"
10
10
 
11
11
  parameter "NAME", "Stack name"
12
+ parameter "[SERVICE] ...", "Service names"
12
13
 
13
14
  requires_current_master
14
15
  requires_current_master_token
15
16
 
16
17
  def execute
17
- show_logs("stacks/#{current_grid}/#{name}/container_logs") do |log|
18
- show_log(log)
18
+ if service_list.empty?
19
+ show_logs("stacks/#{current_grid}/#{name}/container_logs") do |log|
20
+ show_log(log)
21
+ end
22
+ else
23
+ show_logs("grids/#{current_grid}/container_logs", services: service_list.map {|s| [name, s].join('/')}.join(',')) do |log|
24
+ show_log(log)
25
+ end
19
26
  end
20
27
  end
21
28
 
@@ -4,7 +4,7 @@ module Kontena::Cli::Stacks::Registry
4
4
  class PullCommand < Kontena::Command
5
5
  include Kontena::Cli::Common
6
6
  include Kontena::Cli::Stacks::Common
7
- include Kontena::Cli::Stacks::Common::StackNameParam
7
+ include Kontena::Cli::Stacks::Common::RegistryNameParam
8
8
 
9
9
  banner "Pulls / downloads a stack from the stack registry"
10
10
 
@@ -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, stack_version)
17
+ content = target.pull(stack_name.stack_name, stack_name.version)
18
18
  if return?
19
19
  return content
20
20
  elsif file
@@ -7,19 +7,30 @@ module Kontena::Cli::Stacks::Registry
7
7
 
8
8
  banner "Pushes (uploads) a stack to the stack registry"
9
9
 
10
- parameter "FILENAME", "Stack file path"
10
+ include Kontena::Cli::Stacks::Common::StackFileOrNameParam
11
+ include Kontena::Cli::Stacks::Common::StackValuesFromOption
11
12
 
12
13
  requires_current_account_token
13
14
 
15
+ option '--dry-run', :flag, "Do not perform any uploading", hidden: true
16
+
17
+ def includes_local_dependencies?(dependencies = loader.dependencies)
18
+ return false if dependencies.nil?
19
+ dependencies.any? { |dep| Kontena::Cli::Stacks::YAML::StackFileLoader.for(dep['stack']).origin == 'file' || includes_local_dependencies(dep['depends']) }
20
+ end
21
+
22
+ def includes_local_extends?
23
+ stack.fetch(:services) { {} }.any? { |svc| svc['extends'] && svc[:extends]['file'] }
24
+ end
25
+
14
26
  def execute
15
- file = Kontena::Cli::Stacks::YAML::Reader.new(
16
- filename,
17
- skip_variables: true,
18
- skip_validation: true
19
- )
20
- name = "#{file.stack_name}:#{file.stack_version}"
21
- spinner("Pushing #{pastel.cyan(name)} to stacks registry") do
22
- stacks_client.push(file.stack_name, file.stack_version, file.raw_content)
27
+ set_env_variables(stack_name, 'validate', 'validate-platform')
28
+
29
+ exit_with_error "Stack file contains dependencies to local files" if includes_local_dependencies?
30
+ exit_with_error "Stack file has services that extend from local files" if includes_local_extends?
31
+
32
+ spinner("Pushing #{pastel.cyan(source)} to stacks registry as #{loader.stack_name}") do
33
+ stacks_client.push(stack_name, loader.stack_name.version, loader.content) unless dry_run?
23
34
  end
24
35
  end
25
36
  end
@@ -4,7 +4,7 @@ module Kontena::Cli::Stacks::Registry
4
4
  class RemoveCommand < Kontena::Command
5
5
  include Kontena::Cli::Common
6
6
  include Kontena::Cli::Stacks::Common
7
- include Kontena::Cli::Stacks::Common::StackNameParam
7
+ include Kontena::Cli::Stacks::Common::RegistryNameParam
8
8
 
9
9
  banner "Removes a stack (or version) from the stack registry. Use user/stack_name or user/stack_name:version."
10
10
 
@@ -14,8 +14,8 @@ module Kontena::Cli::Stacks::Registry
14
14
 
15
15
  def execute
16
16
  unless force?
17
- if stack_version
18
- puts "About to delete #{pastel.cyan("#{stack_name}:#{stack_version}")} from the stacks registry"
17
+ if stack_name.version
18
+ puts "About to delete #{pastel.cyan("#{stack_name}")} from the stacks registry"
19
19
  confirm
20
20
  else
21
21
  puts "About to delete an entire stack and all of its versions from the stacks registry"
@@ -23,7 +23,7 @@ module Kontena::Cli::Stacks::Registry
23
23
  end
24
24
  end
25
25
  spinner "Removing #{pastel.cyan(stack_name)} from the registry" do
26
- stacks_client.destroy(stack_name, stack_version)
26
+ stacks_client.destroy(stack_name.stack_name, stack_name.version)
27
27
  end
28
28
  end
29
29
  end
@@ -4,7 +4,7 @@ module Kontena::Cli::Stacks::Registry
4
4
  class ShowCommand < Kontena::Command
5
5
  include Kontena::Cli::Common
6
6
  include Kontena::Cli::Stacks::Common
7
- include Kontena::Cli::Stacks::Common::StackNameParam
7
+ include Kontena::Cli::Stacks::Common::RegistryNameParam
8
8
 
9
9
  banner "Shows information about a stack on the stacks registry"
10
10
 
@@ -15,16 +15,16 @@ module Kontena::Cli::Stacks::Registry
15
15
  def execute
16
16
  require 'semantic'
17
17
  unless versions?
18
- stack = ::YAML.safe_load(stacks_client.show(stack_name, stack_version))
18
+ stack = ::YAML.safe_load(stacks_client.show(stack_name.stack_name, stack_name.version))
19
19
  puts "#{stack['stack']}:"
20
- puts " #{"latest_" unless stack_version}version: #{stack['version']}"
20
+ puts " #{"latest_" unless stack_name.version}version: #{stack['version']}"
21
21
  puts " expose: #{stack['expose'] || '-'}"
22
22
  puts " description: #{stack['description'] || '-'}"
23
23
 
24
24
  puts " available_versions:"
25
25
  end
26
26
 
27
- stacks_client.versions(stack_name).reject {|s| s['version'].nil? || s['version'].empty?}.map { |s| Semantic::Version.new(s['version'])}.sort.reverse_each do |version|
27
+ stacks_client.versions(stack_name.stack_name).reject {|s| s['version'].nil? || s['version'].empty?}.map { |s| Semantic::Version.new(s['version'])}.sort.reverse_each do |version|
28
28
  puts versions? ? version : " - #{version}"
29
29
  end
30
30
  end
@@ -10,12 +10,38 @@ module Kontena::Cli::Stacks
10
10
 
11
11
  parameter "NAME", "Stack name"
12
12
  option "--force", :flag, "Force remove", default: false, attribute_name: :forced
13
+ option "--keep-dependencies", :flag, "Do not remove dependencies"
13
14
 
14
15
  requires_current_master
15
16
  requires_current_master_token
16
17
 
18
+ def fetch_stack
19
+ client.get("stacks/#{current_grid}/#{name}")
20
+ end
21
+
22
+ def confirm_remove(stack)
23
+ if stack['parent']
24
+ puts "#{pastel.yellow('Warning:')} The stack #{pastel.cyan(stack['parent']['name'])} depends on stack #{name}"
25
+ end
26
+ if stack['children'] && !stack['children'].empty?
27
+ puts "#{pastel.yellow('Warning:')} The stack #{pastel.cyan(name)} has dependencies that will be removed:"
28
+ stack['children'].each do |child|
29
+ puts "- #{pastel.yellow(child['name'])}"
30
+ end
31
+ end
32
+ confirm_command(name)
33
+ end
34
+
17
35
  def execute
18
- confirm_command(name) unless forced?
36
+ stack = fetch_stack
37
+ confirm_remove(stack) unless forced?
38
+ unless keep_dependencies?
39
+ stack.fetch('children', Hash.new).each do |child_stack|
40
+ caret"Removing dependency #{pastel.cyan(child_stack['name'])}"
41
+ Kontena.run!(['stack', 'remove', '--force', child_stack['name']])
42
+ end
43
+ end
44
+
19
45
  spinner "Removing stack #{pastel.cyan(name)} " do
20
46
  remove_stack(name)
21
47
  wait_stack_removal(name)
@@ -27,12 +27,14 @@ module Kontena::Cli::Stacks
27
27
  data = {}
28
28
  data['instances'] = options['instances']
29
29
  data['image'] = parse_image(options['image'])
30
- data['env'] = options['environment'] if options['environment']
30
+ data['env'] = options['environment'] || options['env']
31
31
  data['links'] = parse_links(options['links'] || [])
32
32
  data['external_links'] = parse_links(options['external_links'] || [])
33
33
  data['ports'] = parse_stringified_ports(options['ports'] || [])
34
34
  data['memory'] = parse_memory(options['mem_limit'].to_s) if options['mem_limit']
35
35
  data['memory_swap'] = parse_memory(options['memswap_limit'].to_s) if options['memswap_limit']
36
+ data['shm_size'] = parse_memory(options['shm_size'].to_s) if options['shm_size']
37
+ data['cpus'] = options['cpus'] if options['cpus']
36
38
  data['cpu_shares'] = options['cpu_shares'] if options['cpu_shares']
37
39
  data['volumes'] = options['volumes'] || []
38
40
  data['volumes_from'] = options['volumes_from'] || []
@@ -61,6 +63,7 @@ module Kontena::Cli::Stacks
61
63
  data['deploy_opts'] = deploy
62
64
  data['hooks'] = options['hooks'] || {}
63
65
  data['secrets'] = options['secrets'] if options['secrets']
66
+ data['certificates'] = options['certificates'] if options['certificates']
64
67
  data['build'] = parse_build_options(options) if options['build']
65
68
  data['health_check'] = parse_health_check(options)
66
69
  data['stop_grace_period'] = options['stop_grace_period'] if options['stop_grace_period']
@@ -85,7 +88,14 @@ module Kontena::Cli::Stacks
85
88
  # @return [Array<Hash>]
86
89
  def parse_links(link_options)
87
90
  link_options.map{|l|
88
- service_name, alias_name = l.split(':')
91
+ if l.kind_of?(String)
92
+ service_name, alias_name = l.split(':')
93
+ elsif l.kind_of?(Hash)
94
+ service_name = l['name']
95
+ alias_name = l['alias']
96
+ else
97
+ raise TypeError, "Invalid link type #{l.class.name}, expecting String or Hash"
98
+ end
89
99
  if service_name.nil?
90
100
  raise ArgumentError.new("Invalid link value #{l}")
91
101
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'common'
2
+ require 'yaml'
2
3
 
3
4
  module Kontena::Cli::Stacks
4
5
  class ShowCommand < Kontena::Command
@@ -13,17 +14,35 @@ module Kontena::Cli::Stacks
13
14
  requires_current_master
14
15
  requires_current_master_token
15
16
 
17
+ option '--values', :flag, 'Output the variable-value pairs as YAML'
18
+ include Common::StackValuesToOption
19
+
16
20
  def execute
17
- show_stack(name)
21
+ write_variables if values_to
22
+ values? ? show_variables : show_stack
23
+ end
24
+
25
+ def variables
26
+ @variables ||= stack['variables'] || {}
27
+ end
28
+
29
+ def stack
30
+ @stack ||= client.get("stacks/#{current_grid}/#{name}")
18
31
  end
19
32
 
20
- def fetch_stack(name)
21
- client.get("stacks/#{current_grid}/#{name}")
33
+ def show_variables
34
+ puts variable_yaml
22
35
  end
23
36
 
24
- def show_stack(name)
25
- stack = fetch_stack(name)
37
+ def variable_yaml
38
+ ::YAML.dump(variables)
39
+ end
26
40
 
41
+ def write_variables
42
+ File.write(values_to, variable_yaml)
43
+ end
44
+
45
+ def show_stack
27
46
  puts "#{stack['name']}:"
28
47
  puts " created: #{stack['created_at']}"
29
48
  puts " updated: #{stack['updated_at']}"
@@ -32,6 +51,17 @@ module Kontena::Cli::Stacks
32
51
  puts " version: #{stack['version']}"
33
52
  puts " revision: #{stack['revision']}"
34
53
  puts " expose: #{stack['expose'] || '-'}"
54
+ puts " variables:#{' -' if variables.empty?}"
55
+ variables.each do |var, val|
56
+ puts " #{var}: #{val}"
57
+ end
58
+ puts " parent: #{stack['parent'] ? stack['parent']['name'] : '-'}"
59
+ if stack['children'] && !stack['children'].empty?
60
+ puts " children:"
61
+ stack['children'].each do |child|
62
+ puts " - #{child['name']}"
63
+ end
64
+ end
35
65
  puts " services:"
36
66
  stack['services'].each do |service|
37
67
  show_service(service['id'])
@@ -0,0 +1,71 @@
1
+ require 'semantic'
2
+
3
+ module Kontena::Cli::Stacks
4
+ class StackName
5
+ # A class for parsing stack name strings, such as kontena/foo:1.0.0
6
+
7
+ attr_reader :user, :stack, :version
8
+
9
+ # @param definition [String] such as kontena/foo:1.0.0
10
+ # @param version [String] set version separately
11
+ # @return [StackName]
12
+ # @example
13
+ # name = StackName.new('kontena/foo:0.1.0')
14
+ # name.user => 'kontena'
15
+ # name.stack => 'foo'
16
+ # name.version => '0.1.0'
17
+ # name.stack_name => 'kontena/foo'
18
+ # name.to_s => 'kontena/foo:0.1.0
19
+ def initialize(definition = nil, version = nil)
20
+ if definition.kind_of?(Hash)
21
+ @user = definition[:user] || definition['user']
22
+ @stack = definition[:stack] || definition['stack']
23
+ @version = definition[:version] || definition['version'] || version
24
+ elsif definition.kind_of?(String)
25
+ parsed = parse(definition)
26
+ @user = parsed[:user]
27
+ @stack = parsed[:stack]
28
+ @version = parsed[:version] || version
29
+ end
30
+ end
31
+
32
+ # Stack name without version
33
+ # @return [String] example: kontena/foo
34
+ def stack_name
35
+ [user, stack].compact.join('/')
36
+ end
37
+
38
+ # Full stack name including version if present
39
+ # @return [String] example: kontena/foo:0.1.0
40
+ def to_s
41
+ version ? "#{stack_name}:#{version}" : stack_name
42
+ end
43
+ alias to_str to_s
44
+
45
+ # True when version is a prerelease
46
+ # @return [NilClass,TrueClass,FalseClass] nil when no version, true when prerelease, false when not.
47
+ def pre?
48
+ return nil if version.nil?
49
+ !Semantic::Version.new(version).pre.nil?
50
+ end
51
+
52
+ private
53
+
54
+ def parse(definition)
55
+ return {} if definition.empty?
56
+ name, version = definition.split(':', 2)
57
+ if name.include?('/')
58
+ user, stack = name.split('/', 2)
59
+ else
60
+ user = nil
61
+ stack = name
62
+ end
63
+ {
64
+ user: user,
65
+ stack: stack,
66
+ version: version
67
+ }
68
+ end
69
+
70
+ end
71
+ end