kontena-cli 1.4.3 → 1.5.0.pre1

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +7 -3
  3. data/Gemfile +7 -3
  4. data/README.md +1 -1
  5. data/VERSION +1 -1
  6. data/bin/kontena +1 -0
  7. data/kontena-cli.gemspec +5 -6
  8. data/lib/kontena/cli/browser_launcher.rb +61 -0
  9. data/lib/kontena/cli/certificate/authorize_command.rb +40 -16
  10. data/lib/kontena/cli/certificate/get_command.rb +1 -1
  11. data/lib/kontena/cli/cloud/login_command.rb +3 -4
  12. data/lib/kontena/cli/cloud/master/add_command.rb +1 -1
  13. data/lib/kontena/cli/cloud/master/list_command.rb +1 -1
  14. data/lib/kontena/cli/cloud/master/remove_command.rb +1 -1
  15. data/lib/kontena/cli/cloud/master/update_command.rb +1 -1
  16. data/lib/kontena/cli/common.rb +2 -2
  17. data/lib/kontena/cli/etcd_command.rb +1 -1
  18. data/lib/kontena/cli/external_registries/add_command.rb +2 -2
  19. data/lib/kontena/cli/external_registries/remove_command.rb +1 -1
  20. data/lib/kontena/cli/grids/common.rb +14 -4
  21. data/lib/kontena/cli/grids/events_command.rb +2 -2
  22. data/lib/kontena/cli/grids/list_command.rb +1 -1
  23. data/lib/kontena/cli/grids/logs_command.rb +1 -1
  24. data/lib/kontena/cli/grids/remove_command.rb +12 -10
  25. data/lib/kontena/cli/grids/trusted_subnets/add_command.rb +1 -1
  26. data/lib/kontena/cli/grids/trusted_subnets/remove_command.rb +12 -10
  27. data/lib/kontena/cli/grids/use_command.rb +1 -1
  28. data/lib/kontena/cli/helpers/log_helper.rb +1 -1
  29. data/lib/kontena/cli/logout_command.rb +1 -1
  30. data/lib/kontena/cli/master/login_command.rb +2 -3
  31. data/lib/kontena/cli/master/logout_command.rb +2 -2
  32. data/lib/kontena/cli/master/token/common.rb +2 -1
  33. data/lib/kontena/cli/master/token/create_command.rb +5 -2
  34. data/lib/kontena/cli/master/token/current_command.rb +9 -4
  35. data/lib/kontena/cli/master/token/list_command.rb +1 -1
  36. data/lib/kontena/cli/master/token/show_command.rb +11 -1
  37. data/lib/kontena/cli/master/user/invite_command.rb +1 -1
  38. data/lib/kontena/cli/master_command.rb +0 -1
  39. data/lib/kontena/cli/nodes/create_command.rb +1 -1
  40. data/lib/kontena/cli/nodes/labels/remove_command.rb +17 -3
  41. data/lib/kontena/cli/nodes/remove_command.rb +12 -10
  42. data/lib/kontena/cli/nodes/reset_token_command.rb +1 -1
  43. data/lib/kontena/cli/nodes/update_command.rb +1 -1
  44. data/lib/kontena/cli/plugin_command.rb +2 -1
  45. data/lib/kontena/cli/plugins/install_command.rb +2 -2
  46. data/lib/kontena/cli/plugins/uninstall_command.rb +19 -10
  47. data/lib/kontena/cli/plugins/upgrade_command.rb +60 -0
  48. data/lib/kontena/cli/registry/create_command.rb +1 -1
  49. data/lib/kontena/cli/registry/remove_command.rb +2 -2
  50. data/lib/kontena/cli/services/containers_command.rb +1 -1
  51. data/lib/kontena/cli/services/create_command.rb +1 -1
  52. data/lib/kontena/cli/services/deploy_command.rb +1 -1
  53. data/lib/kontena/cli/services/envs/add_command.rb +1 -1
  54. data/lib/kontena/cli/services/envs/remove_command.rb +5 -3
  55. data/lib/kontena/cli/services/link_command.rb +1 -1
  56. data/lib/kontena/cli/services/logs_command.rb +1 -1
  57. data/lib/kontena/cli/services/monitor_command.rb +1 -1
  58. data/lib/kontena/cli/services/remove_command.rb +11 -9
  59. data/lib/kontena/cli/services/restart_command.rb +1 -1
  60. data/lib/kontena/cli/services/secrets/link_command.rb +1 -1
  61. data/lib/kontena/cli/services/services_helper.rb +6 -12
  62. data/lib/kontena/cli/services/start_command.rb +5 -3
  63. data/lib/kontena/cli/services/stop_command.rb +5 -3
  64. data/lib/kontena/cli/services/unlink_command.rb +1 -1
  65. data/lib/kontena/cli/services/update_command.rb +1 -1
  66. data/lib/kontena/cli/spinner.rb +10 -10
  67. data/lib/kontena/cli/stack_command.rb +1 -0
  68. data/lib/kontena/cli/stacks/build_command.rb +6 -6
  69. data/lib/kontena/cli/stacks/deploy_command.rb +12 -10
  70. data/lib/kontena/cli/stacks/inspect_command.rb +17 -0
  71. data/lib/kontena/cli/stacks/install_command.rb +15 -4
  72. data/lib/kontena/cli/stacks/list_command.rb +2 -3
  73. data/lib/kontena/cli/stacks/logs_command.rb +1 -1
  74. data/lib/kontena/cli/stacks/monitor_command.rb +2 -2
  75. data/lib/kontena/cli/stacks/remove_command.rb +28 -19
  76. data/lib/kontena/cli/stacks/restart_command.rb +5 -4
  77. data/lib/kontena/cli/stacks/stop_command.rb +6 -5
  78. data/lib/kontena/cli/stacks/upgrade_command.rb +84 -64
  79. data/lib/kontena/cli/stacks/yaml/reader.rb +9 -4
  80. data/lib/kontena/cli/vault/remove_command.rb +7 -5
  81. data/lib/kontena/cli/vault/update_command.rb +1 -1
  82. data/lib/kontena/cli/vault/write_command.rb +1 -1
  83. data/lib/kontena/cli/volumes/remove_command.rb +6 -4
  84. data/lib/kontena/cli/vpn/create_command.rb +1 -1
  85. data/lib/kontena/cli/vpn/remove_command.rb +1 -1
  86. data/lib/kontena/client.rb +23 -14
  87. data/lib/kontena/command.rb +2 -2
  88. data/lib/kontena/debug_instrumentor.rb +11 -2
  89. data/lib/kontena/plugin_manager/common.rb +5 -2
  90. data/lib/kontena/plugin_manager/installer.rb +34 -10
  91. data/lib/kontena/scripts/completer.rb +91 -43
  92. data/lib/kontena/{cli/stacks → stacks}/change_resolver.rb +38 -16
  93. data/lib/kontena/stacks/stack_data.rb +58 -0
  94. data/lib/kontena/stacks/stack_data_set.rb +51 -0
  95. data/lib/kontena_cli.rb +1 -0
  96. data/omnibus/Gemfile.lock +32 -22
  97. data/omnibus/config/projects/kontena.rb +2 -0
  98. data/omnibus/config/software/kontena-cli.rb +6 -4
  99. data/omnibus/package-scripts/kontena/postinstall +1 -1
  100. data/omnibus/wrappers/sh/kontena +1 -1
  101. data/spec/fixtures/kontena_v3_with_registry_extends.yml +20 -0
  102. data/spec/kontena/cli/certificates/authorize_command_spec.rb +81 -0
  103. data/spec/kontena/cli/cloud/login_command_spec.rb +4 -4
  104. data/spec/kontena/cli/common_spec.rb +8 -1
  105. data/spec/kontena/cli/grids/update_command_spec.rb +13 -0
  106. data/spec/kontena/cli/master/join_command_spec.rb +1 -4
  107. data/spec/kontena/cli/master/login_command_spec.rb +4 -4
  108. data/spec/kontena/cli/master/token/create_command_spec.rb +132 -0
  109. data/spec/kontena/cli/master/token/show_command_spec.rb +90 -0
  110. data/spec/kontena/cli/nodes/labels/remove_command_spec.rb +35 -5
  111. data/spec/kontena/cli/stacks/install_command_spec.rb +16 -6
  112. data/spec/kontena/cli/stacks/remove_command_spec.rb +23 -2
  113. data/spec/kontena/cli/stacks/validate_command_spec.rb +1 -1
  114. data/spec/kontena/cli/stacks/yaml/reader_spec.rb +33 -1
  115. data/spec/kontena/client_spec.rb +38 -1
  116. data/spec/kontena/stacks/change_resolver_spec.rb +44 -0
  117. data/spec/kontena/stacks/stack_data_set_spec.rb +59 -0
  118. metadata +36 -34
  119. data/lib/kontena/cli/master/users_command.rb +0 -13
@@ -6,9 +6,9 @@ module Kontena::Cli::Stacks
6
6
  include Kontena::Cli::GridOptions
7
7
  include StacksHelper
8
8
 
9
- banner "Deploys all services of a stack that has been installed in a grid on Kontena Master"
9
+ banner "Deploys all services of a stack"
10
10
 
11
- parameter "NAME", "Stack name"
11
+ parameter "NAME ...", "Stack name", attribute_name: :names
12
12
 
13
13
  option '--[no-]wait', :flag, 'Do not wait for service deployment', default: true
14
14
 
@@ -16,15 +16,17 @@ module Kontena::Cli::Stacks
16
16
  requires_current_master_token
17
17
 
18
18
  def execute
19
- deployment = nil
20
- spinner "Triggering deployment of stack #{pastel.cyan(name)}" do
21
- deployment = deploy_stack(name)
22
- end
23
- if wait?
24
- spinner "Waiting for deployment to start" do
25
- wait_for_deployment_to_start(deployment)
19
+ names.each do |name|
20
+ deployment = nil
21
+ spinner "Triggering deployment of stack #{pastel.cyan(name)}" do
22
+ deployment = deploy_stack(name)
23
+ end
24
+ if wait?
25
+ spinner "Waiting for deployment to start" do
26
+ wait_for_deployment_to_start(deployment)
27
+ end
28
+ wait_for_deploy_to_finish(deployment)
26
29
  end
27
- wait_for_deploy_to_finish(deployment)
28
30
  end
29
31
  end
30
32
 
@@ -0,0 +1,17 @@
1
+ module Kontena::Cli::Stacks
2
+ class InspectCommand < Kontena::Command
3
+ include Kontena::Cli::Common
4
+ include Kontena::Cli::GridOptions
5
+
6
+ banner "Inspect a stack"
7
+
8
+ parameter "NAME", "Stack name"
9
+
10
+ requires_current_master
11
+ requires_current_master_token
12
+
13
+ def execute
14
+ puts client.get("stacks/#{current_grid}/#{name}")['source']
15
+ end
16
+ end
17
+ end
@@ -36,7 +36,11 @@ module Kontena::Cli::Stacks
36
36
  dump_variables if values_to
37
37
 
38
38
  create_stack
39
- deploy_stack if deploy?
39
+
40
+ if deploy?
41
+ deploy_dependencies
42
+ deploy_stack
43
+ end
40
44
  end
41
45
 
42
46
  def install_dependencies
@@ -46,18 +50,25 @@ module Kontena::Cli::Stacks
46
50
  dependencies.each do |dependency|
47
51
  target_name = "#{stack_name}-#{dependency['name']}"
48
52
  caret "Installing dependency #{pastel.cyan(dependency['stack'])} as #{pastel.cyan(target_name)}"
49
- cmd = ['stack', 'install', '-n', target_name, '--parent-name', stack_name]
53
+ cmd = ['stack', 'install', '-n', target_name, '--parent-name', stack_name, '--no-deploy']
50
54
 
51
55
  dependency['variables'].merge(dependency_values_from_options(dependency['name'])).each do |key, value|
52
56
  cmd.concat ['-v', "#{key}=#{value}"]
53
57
  end
54
58
 
55
- cmd << '--no-deploy' unless deploy?
56
-
57
59
  cmd << dependency['stack']
58
60
  Kontena.run!(cmd)
59
61
  end
62
+ end
63
+
64
+ def deploy_dependencies
65
+ dependencies = loader.dependencies
66
+ return if dependencies.nil?
60
67
 
68
+ dependencies.each do |dependency|
69
+ target_name = "#{stack_name}-#{dependency['name']}"
70
+ Kontena.run!(['stack', 'deploy', target_name])
71
+ end
61
72
  end
62
73
 
63
74
  def create_stack
@@ -53,7 +53,7 @@ module Kontena::Cli::Stacks
53
53
 
54
54
  print_table(stacks) do |row|
55
55
  next if quiet?
56
- row['name'] = health_icon(stack_health(row)) + " " + tree_icon(row) + row['name']
56
+ row['name'] = health_icon(stack_health(row)) + " " + tree_icon(row) + " " + row['name']
57
57
  row['stack'] = "#{row['stack']}:#{row['version']}"
58
58
  row['services_count'] = row['services'].size
59
59
  row['ports'] = stack_ports(row).join(',')
@@ -88,8 +88,7 @@ module Kontena::Cli::Stacks
88
88
  char = '┗━'
89
89
  end
90
90
  left_pad = ' ' * (2 * (row['depth'] - 1))
91
- right_pad = row['depth'] > 1 ? '━' : ''
92
- left_pad + char + right_pad
91
+ left_pad + char
93
92
  end
94
93
 
95
94
  # @param [Hash] stack
@@ -28,7 +28,7 @@ module Kontena::Cli::Stacks
28
28
 
29
29
  def show_log(log)
30
30
  color = color_for_container(log['name'])
31
- prefix = "#{log['created_at']} [#{log['name']}]:".colorize(color)
31
+ prefix = pastel.send(color, "#{log['created_at']} [#{log['name']}]:")
32
32
  puts "#{prefix} #{log['data']}"
33
33
  end
34
34
  end
@@ -45,7 +45,7 @@ module Kontena::Cli::Stacks
45
45
  puts "services:"
46
46
  services.each do |service|
47
47
  color = color_for_service(service['name'])
48
- puts " #{"■".colorize(color)} #{service['name']} (#{service['instances']} instances)"
48
+ puts " #{pastel.send(color, "■")} #{service['name']} (#{service['instances']} instances)"
49
49
  end
50
50
  puts "nodes:"
51
51
  node_names = nodes.keys.sort
@@ -59,7 +59,7 @@ module Kontena::Cli::Stacks
59
59
  icon = "□"
60
60
  end
61
61
  color = color_for_service(container['service'])
62
- print icon.colorize(color)
62
+ print pastel.send(color, icon)
63
63
  end
64
64
  puts ''
65
65
  end
@@ -8,22 +8,38 @@ module Kontena::Cli::Stacks
8
8
 
9
9
  banner "Removes a stack in a grid on Kontena Master"
10
10
 
11
- parameter "NAME", "Stack name"
11
+ parameter "NAME ...", "Stack name", attribute_name: :names
12
12
  option "--force", :flag, "Force remove", default: false, attribute_name: :forced
13
13
  option "--keep-dependencies", :flag, "Do not remove dependencies"
14
14
 
15
15
  requires_current_master
16
16
  requires_current_master_token
17
17
 
18
- def fetch_stack
19
- client.get("stacks/#{current_grid}/#{name}")
18
+ def execute
19
+ names.each do |name|
20
+ stack = fetch_stack(name)
21
+ confirm_remove(stack, name) unless forced?
22
+ unless keep_dependencies?
23
+ stack.fetch('children', Hash.new).each do |child_stack|
24
+ caret"Removing dependency #{pastel.cyan(child_stack['name'])}"
25
+ Kontena.run!(['stack', 'remove', '--force', child_stack['name']])
26
+ end
27
+ end
28
+
29
+ spinner "Removing stack #{pastel.cyan(name)} " do
30
+ remove_stack(name)
31
+ wait_stack_removal(name)
32
+ end
33
+ end
20
34
  end
21
35
 
22
- def confirm_remove(stack)
36
+ # @param stack [Hash]
37
+ # @param name [String]
38
+ def confirm_remove(stack, name)
23
39
  if stack['parent']
24
40
  puts "#{pastel.yellow('Warning:')} The stack #{pastel.cyan(stack['parent']['name'])} depends on stack #{name}"
25
41
  end
26
- if stack['children'] && !stack['children'].empty?
42
+ if !keep_dependencies? && stack['children'] && !stack['children'].empty?
27
43
  puts "#{pastel.yellow('Warning:')} The stack #{pastel.cyan(name)} has dependencies that will be removed:"
28
44
  stack['children'].each do |child|
29
45
  puts "- #{pastel.yellow(child['name'])}"
@@ -32,26 +48,19 @@ module Kontena::Cli::Stacks
32
48
  confirm_command(name)
33
49
  end
34
50
 
35
- def execute
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
-
45
- spinner "Removing stack #{pastel.cyan(name)} " do
46
- remove_stack(name)
47
- wait_stack_removal(name)
48
- end
51
+ # @param name [String]
52
+ # @return [Hash]
53
+ def fetch_stack(name)
54
+ client.get("stacks/#{current_grid}/#{name}")
49
55
  end
50
56
 
57
+ # @param name [String]
58
+ # @return [Hash]
51
59
  def remove_stack(name)
52
60
  client.delete("stacks/#{current_grid}/#{name}")
53
61
  end
54
62
 
63
+ # @param name [String]
55
64
  def wait_stack_removal(name)
56
65
  removed = false
57
66
  until removed == true
@@ -8,16 +8,17 @@ module Kontena::Cli::Stacks
8
8
 
9
9
  banner "Restarts all services of a stack that has been installed in a grid on Kontena Master"
10
10
 
11
- parameter "NAME", "Stack name"
11
+ parameter "NAME ...", "Stack name", attribute_name: :names
12
12
 
13
13
  requires_current_master
14
14
  requires_current_master_token
15
15
 
16
16
  def execute
17
- spinner "Sending restart signal for stack services" do
18
- client.post("stacks/#{current_grid}/#{name}/restart", {})
17
+ names.each do |name|
18
+ spinner "Sending restart signal for stack #{name} services" do
19
+ client.post("stacks/#{current_grid}/#{name}/restart", {})
20
+ end
19
21
  end
20
22
  end
21
-
22
23
  end
23
24
  end
@@ -6,18 +6,19 @@ module Kontena::Cli::Stacks
6
6
  include Kontena::Cli::GridOptions
7
7
  include Common
8
8
 
9
- banner "Stops all services of a stack that has been installed in a grid on Kontena Master"
9
+ banner "Stops all services of a stack"
10
10
 
11
- parameter "NAME", "Stack name"
11
+ parameter "NAME ...", "Stack name", attribute_name: :names
12
12
 
13
13
  requires_current_master
14
14
  requires_current_master_token
15
15
 
16
16
  def execute
17
- spinner "Sending stop signal for stack services" do
18
- client.post("stacks/#{current_grid}/#{name}/stop", {})
17
+ names.each do |name|
18
+ spinner "Sending stop signal for stack #{name} services" do
19
+ client.post("stacks/#{current_grid}/#{name}/stop", {})
20
+ end
19
21
  end
20
22
  end
21
-
22
23
  end
23
24
  end
@@ -1,7 +1,6 @@
1
- require_relative 'common'
2
- require_relative 'change_resolver'
3
-
4
1
  require 'json'
2
+ require 'kontena/stacks/change_resolver'
3
+ require_relative 'common'
5
4
 
6
5
  module Kontena::Cli::Stacks
7
6
  class UpgradeCommand < Kontena::Command
@@ -21,13 +20,14 @@ module Kontena::Cli::Stacks
21
20
  option '--[no-]deploy', :flag, 'Trigger deploy after upgrade', default: true
22
21
 
23
22
  option '--force', :flag, 'Force upgrade'
24
- option '--skip-dependencies', :flag, "Do not install any stack dependencies"
23
+ option '--skip-dependencies', :flag, "Do not upgrade any stack dependencies", default: false
24
+ option '--reuse-values', :flag, "Reuse existing values"
25
25
  option '--dry-run', :flag, "Simulate upgrade"
26
26
 
27
27
  requires_current_master
28
28
  requires_current_master_token
29
29
 
30
- # @return [Kontena::Cli::Stacks::ChangeResolver]
30
+ # @return [Kontena::Stacks::ChangeResolver]
31
31
  def execute
32
32
  old_data = spinner "Reading stack #{pastel.cyan(stack_name)} from master" do
33
33
  gather_master_data(stack_name)
@@ -81,66 +81,72 @@ module Kontena::Cli::Stacks
81
81
  logger.debug { "Master stacks: #{old_data.keys.join(",")} YAML stacks: #{new_data.keys.join(",")}" }
82
82
 
83
83
  new_data.reverse_each do |stackname, data|
84
- reader = data[:loader].reader
85
- set_env_variables(stackname, current_grid) # set envs for execution time
86
- data[:stack_data] = reader.execute(
87
- values: data[:variables],
88
- defaults: old_data[stackname].nil? ? nil : old_data[stackname][:stack_data]['variables'],
89
- parent_name: data[:parent_name],
90
- name: data[:name]
91
- )
84
+ spinner "Processing stack #{pastel.cyan(stackname)}"
85
+ process_stack_data(stackname, data, old_data)
92
86
  hint_on_validation_notifications(reader.notifications, reader.loader.source)
93
87
  abort_on_validation_errors(reader.errors, reader.loader.source)
94
88
  end
95
89
 
96
- set_env_variables(stack_name, current_grid) # restore envs
97
-
90
+ old_set = Kontena::Stacks::StackDataSet.new(old_data)
91
+ new_set = Kontena::Stacks::StackDataSet.new(new_data)
92
+ if skip_dependencies?
93
+ [old_set, new_set].each(&:remove_dependencies)
94
+ end
98
95
  spinner "Analyzing upgrade" do
99
- Kontena::Cli::Stacks::ChangeResolver.new(old_data, new_data)
96
+ Kontena::Stacks::ChangeResolver.new(old_set, new_set)
100
97
  end
101
98
  end
102
99
 
103
- def display_report(changes)
104
- if !dry_run? && changes.removed_stacks.empty? && changes.replaced_stacks.empty? && changes.upgraded_stacks.size == 1 && changes.removed_services.empty?
105
- return
106
- end
107
-
108
- will = dry_run? ? "would" : "will"
109
-
110
- puts "SERVICES:"
111
- puts "-" * 40
112
-
113
- unless changes.removed_services.empty?
114
- puts pastel.yellow("These services #{will} be removed from master:")
115
- changes.removed_services.each { |svc| puts pastel.yellow(" - #{svc}") }
116
- puts
117
- end
118
-
119
- unless changes.added_services.empty?
120
- puts pastel.green("These new services #{will} be created to master:")
121
- changes.added_services.each { |svc| puts pastel.green(" - #{svc}") }
122
- puts
123
- end
124
-
125
- unless changes.upgraded_services.empty?
126
- puts pastel.cyan("These services #{will} be upgraded:")
127
- changes.upgraded_services.each do |svc|
128
- puts pastel.cyan("- #{svc}")
129
- end
130
- puts
131
- end
100
+ # @param stackname [String]
101
+ # @param data [Hash]
102
+ # @param old_data [Hash]
103
+ def process_stack_data(stackname, data, old_data)
104
+ prev_env = ENV.clone
105
+ reader = data[:loader].reader
106
+ values = data[:variables]
107
+ if reuse_values? && old_data[stackname]
108
+ old_vars = old_data[stackname][:stack_data]['variables']
109
+ values = old_vars.merge(values)
110
+ end
111
+ set_env_variables(stackname, current_grid) # set envs for execution time
112
+ parsed_stack = reader.execute(
113
+ values: values,
114
+ defaults: old_data[stackname].nil? ? nil : old_data[stackname][:stack_data]['variables'],
115
+ parent_name: data[:parent_name],
116
+ name: data[:name]
117
+ )
118
+ data[:stack_data] = parsed_stack
119
+ ensure
120
+ prev_env.each { |k, v| ENV[k] = v }
121
+ end
132
122
 
133
- puts "STACKS:"
134
- puts "-" * 40
123
+ # @param changes [Kontena::Stacks::ChangeResolver]
124
+ def display_report(changes)
125
+ puts
126
+ caret "Calculated changes:", dots: false
135
127
 
136
128
  unless changes.removed_stacks.empty?
137
- puts pastel.red("These stacks #{will} be removed because they are no longer depended on:")
138
- changes.removed_stacks.each { |stack| puts pastel.red("- #{stack}") }
139
- puts
129
+ changes.removed_stacks.each { |stack|
130
+ puts " #{pastel.red('-')} #{stack}"
131
+ changes.removed_services.select { |s| s.split('/')[0] == stack }.each do |s|
132
+ puts " #{pastel.red('-')} #{s}"
133
+ end
134
+ }
140
135
  end
141
136
 
142
137
  unless changes.replaced_stacks.empty?
143
- puts pastel.yellow("These stacks #{will} be replaced by other stacks:")
138
+ changes.replaced_stacks.each { |stack|
139
+ puts " #{pastel.yellow('-/+')} #{stack}"
140
+ changes.upgraded_services.select { |s| s.split('/')[0] == stack }.each do |s|
141
+ puts " #{pastel.cyan('~')} #{s}"
142
+ end
143
+ changes.added_services.select { |s| s.split('/')[0] == stack }.each do |s|
144
+ puts " #{pastel.green('+')} #{s}"
145
+ end
146
+ changes.removed_services.select { |s| s.split('/')[0] == stack }.each do |s|
147
+ puts " #{pastel.red('-')} #{s}"
148
+ end
149
+ }
144
150
  changes.replaced_stacks.each do |installed_name, data|
145
151
  puts "- #{pastel.yellow(installed_name)} from #{pastel.cyan(data[:from])} to #{pastel.cyan(data[:to])}"
146
152
  end
@@ -148,24 +154,35 @@ module Kontena::Cli::Stacks
148
154
  end
149
155
 
150
156
  unless changes.added_stacks.empty?
151
- puts pastel.green("These new stack dependencies #{will} be installed:")
152
- changes.added_stacks.each { |stack| puts pastel.green("- #{stack}") }
153
- puts
157
+ changes.added_stacks.each { |stack|
158
+ puts " #{pastel.green('+')} #{stack}"
159
+ changes.added_services.select { |s| s.split('/')[0] == stack }.each do |s|
160
+ puts " #{pastel.green('+')} #{s}"
161
+ end
162
+ }
154
163
  end
155
164
 
156
165
  unless changes.upgraded_stacks.empty?
157
- puts pastel.cyan("These stacks #{will} be upgraded#{' and deployed' if deploy?}:")
158
- changes.upgraded_stacks.each { |stack| puts pastel.cyan("- #{stack}") }
159
- puts
166
+ changes.upgraded_stacks.each { |stack|
167
+ puts " #{pastel.cyan('~')} #{stack}"
168
+ changes.upgraded_services.select { |s| s.split('/')[0] == stack }.each do |s|
169
+ puts " #{pastel.cyan('~')} #{s}"
170
+ end
171
+ changes.added_services.select { |s| s.split('/')[0] == stack }.each do |s|
172
+ puts " #{pastel.green('+')} #{s}"
173
+ end
174
+ changes.removed_services.select { |s| s.split('/')[0] == stack }.each do |s|
175
+ puts " #{pastel.red('-')} #{s}"
176
+ end
177
+ }
160
178
  end
161
-
162
179
  puts
163
180
  end
164
181
 
165
182
  # requires heavier confirmation when something very dangerous is going to happen
166
183
  def get_confirmation(changes)
167
184
  unless force?
168
- unless changes.removed_services.empty? && changes.removed_stacks.empty? && changes.replaced_stacks.empty?
185
+ unless changes.safe?
169
186
  puts "#{pastel.red('Warning:')} This can not be undone, data will be lost."
170
187
  confirm
171
188
  end
@@ -176,23 +193,25 @@ module Kontena::Cli::Stacks
176
193
  @deployable_stacks ||= []
177
194
  end
178
195
 
196
+ # @param removed_stacks [Array<String>]
179
197
  def run_removes(removed_stacks)
180
198
  removed_stacks.reverse_each do |removed_stack|
181
199
  Kontena.run!('stack', 'remove', '--force', '--keep-dependencies', removed_stack)
182
200
  end
183
201
  end
184
202
 
203
+ # @param changes [Kontena::Stacks::ChangeResolver]
185
204
  # @return [Array] an array of stack names that have been installed, but not yet deployed
186
205
  def run_installs(changes)
187
206
  deployable_stacks = []
188
207
  changes.added_stacks.reverse_each do |added_stack|
189
208
  data = changes.new_data[added_stack]
190
209
  cmd = ['stack', 'install', '--name', added_stack, '--no-deploy']
191
- cmd.concat ['--parent-name', data[:parent_name]] if data[:parent_name]
192
- data[:variables].each do |k,v|
210
+ cmd.concat ['--parent-name', data.parent] unless data.root?
211
+ data.variables.each do |k,v|
193
212
  cmd.concat ['-v', "#{k}=#{v}"]
194
213
  end
195
- cmd << data[:loader].source
214
+ cmd << data.loader.source
196
215
  caret "Installing new dependency #{cmd.last} as #{added_stack}"
197
216
  deployable_stacks << added_stack
198
217
  Kontena.run!(cmd)
@@ -200,14 +219,15 @@ module Kontena::Cli::Stacks
200
219
  deployable_stacks
201
220
  end
202
221
 
222
+ # @param changes [Kontena::Stacks::ChangeResolver]
203
223
  # @return [Array] an array of stack names that have been upgraded, but not yet deployed
204
224
  def run_upgrades(changes)
205
225
  deployable_stacks = []
206
226
  changes.upgraded_stacks.reverse_each do |upgraded_stack|
207
227
  data = changes.new_data[upgraded_stack]
208
- spinner "Upgrading #{stack_name == upgraded_stack ? 'stack' : 'dependency'} #{pastel.cyan(upgraded_stack)}" do |spin|
228
+ spinner "Upgrading #{data.root? ? 'stack' : 'dependency'} #{pastel.cyan(upgraded_stack)}" do |spin|
209
229
  deployable_stacks << upgraded_stack
210
- update_stack(upgraded_stack, data[:stack_data]) || spin.fail!
230
+ update_stack(upgraded_stack, data.data) || spin.fail!
211
231
  end
212
232
  end
213
233
  deployable_stacks