kontena-cli 1.4.0.pre6 → 1.4.0.pre7

Sign up to get free protection for your applications and to get access to all the features.
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