kontena-cli 1.4.3 → 1.5.0.pre1

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