kontena-cli 0.16.3 → 0.17.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +1 -0
- data/.gitignore +3 -1
- data/VERSION +1 -1
- data/lib/kontena/callbacks/master/deploy/40_install_ssl_certificate_after_deploy.rb +32 -0
- data/lib/kontena/cli/apps/deploy_command.rb +2 -2
- data/lib/kontena/cli/apps/scale_command.rb +2 -2
- data/lib/kontena/cli/apps/show_command.rb +3 -2
- data/lib/kontena/cli/apps/yaml/validations.rb +10 -6
- data/lib/kontena/cli/apps/yaml/validator.rb +1 -0
- data/lib/kontena/cli/apps/yaml/validator_v2.rb +1 -0
- data/lib/kontena/cli/cloud/login_command.rb +66 -64
- data/lib/kontena/cli/common.rb +0 -10
- data/lib/kontena/cli/grids/logs_command.rb +0 -1
- data/lib/kontena/cli/localhost_web_server.rb +11 -3
- data/lib/kontena/cli/master/login_command.rb +213 -163
- data/lib/kontena/cli/nodes/label_command.rb +2 -0
- data/lib/kontena/cli/nodes/labels/add_command.rb +7 -8
- data/lib/kontena/cli/nodes/labels/list_command.rb +17 -0
- data/lib/kontena/cli/nodes/labels/remove_command.rb +7 -12
- data/lib/kontena/cli/nodes/show_command.rb +1 -0
- data/lib/kontena/cli/plugins/common.rb +8 -0
- data/lib/kontena/cli/plugins/install_command.rb +21 -2
- data/lib/kontena/cli/plugins/list_command.rb +4 -2
- data/lib/kontena/cli/plugins/search_command.rb +4 -2
- data/lib/kontena/cli/registry/create_command.rb +19 -12
- data/lib/kontena/cli/registry/remove_command.rb +4 -4
- data/lib/kontena/cli/registry_command.rb +0 -1
- data/lib/kontena/cli/services/create_command.rb +6 -6
- data/lib/kontena/cli/services/deploy_command.rb +8 -4
- data/lib/kontena/cli/services/list_command.rb +34 -21
- data/lib/kontena/cli/services/logs_command.rb +1 -1
- data/lib/kontena/cli/services/scale_command.rb +3 -3
- data/lib/kontena/cli/services/services_helper.rb +18 -14
- data/lib/kontena/cli/services/show_command.rb +1 -0
- data/lib/kontena/cli/services/update_command.rb +6 -6
- data/lib/kontena/cli/stack_command.rb +12 -6
- data/lib/kontena/cli/stacks/build_command.rb +110 -0
- data/lib/kontena/cli/stacks/common.rb +85 -20
- data/lib/kontena/cli/stacks/deploy_command.rb +30 -7
- data/lib/kontena/cli/stacks/install_command.rb +30 -0
- data/lib/kontena/cli/stacks/list_command.rb +74 -14
- data/lib/kontena/cli/stacks/logs_command.rb +31 -0
- data/lib/kontena/cli/stacks/monitor_command.rb +91 -0
- data/lib/kontena/cli/stacks/remove_command.rb +24 -7
- data/lib/kontena/cli/stacks/service_generator.rb +115 -0
- data/lib/kontena/cli/stacks/service_generator_v2.rb +27 -0
- data/lib/kontena/cli/stacks/show_command.rb +65 -13
- data/lib/kontena/cli/stacks/upgrade_command.rb +28 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/affinities_validator.rb +19 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/build_validator.rb +22 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/extends_validator.rb +21 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/hooks_validator.rb +54 -0
- data/lib/kontena/cli/stacks/yaml/custom_validators/secrets_validator.rb +22 -0
- data/lib/kontena/cli/stacks/yaml/reader.rb +219 -0
- data/lib/kontena/cli/stacks/yaml/service_extender.rb +78 -0
- data/lib/kontena/cli/stacks/yaml/validations.rb +71 -0
- data/lib/kontena/cli/stacks/yaml/validator_v3.rb +52 -0
- data/lib/kontena/cli/version_command.rb +5 -1
- data/lib/kontena/cli/vpn/create_command.rb +20 -17
- data/lib/kontena/cli/vpn/remove_command.rb +4 -3
- data/lib/kontena/client.rb +21 -20
- data/lib/kontena/machine/cert_helper.rb +4 -0
- data/lib/kontena/machine/cloud_config/cloudinit.yml +1 -1
- data/lib/kontena/main_command.rb +1 -1
- data/spec/fixtures/kontena-build.yml +2 -2
- data/spec/fixtures/kontena-invalid.yml +1 -1
- data/spec/fixtures/kontena-not-hash-service-config.yml +1 -1
- data/spec/fixtures/kontena-with-env-file.yml +2 -2
- data/spec/fixtures/kontena_build_v3.yml +23 -0
- data/spec/fixtures/kontena_v3.yml +20 -0
- data/spec/fixtures/stack-internal-extend.yml +11 -0
- data/spec/fixtures/stack-with-env-file.yml +21 -0
- data/spec/fixtures/stack-with-variables.yml +22 -0
- data/spec/kontena/cli/app/scale_spec.rb +3 -1
- data/spec/kontena/cli/cloud/login_command_spec.rb +283 -0
- data/spec/kontena/cli/master/login_command_spec.rb +324 -145
- data/spec/kontena/cli/services/link_command_spec.rb +1 -1
- data/spec/kontena/cli/services/secrets/link_command_spec.rb +4 -4
- data/spec/kontena/cli/services/secrets/unlink_command_spec.rb +2 -2
- data/spec/kontena/cli/services/services_helper_spec.rb +15 -11
- data/spec/kontena/cli/services/unlink_command_spec.rb +1 -1
- data/spec/kontena/cli/stacks/deploy_command_spec.rb +26 -0
- data/spec/kontena/cli/stacks/install_command_spec.rb +54 -0
- data/spec/kontena/cli/stacks/list_command_spec.rb +27 -0
- data/spec/kontena/cli/stacks/remove_command_spec.rb +45 -0
- data/spec/kontena/cli/stacks/service_generator_spec.rb +385 -0
- data/spec/kontena/cli/stacks/service_generator_v2_spec.rb +74 -0
- data/spec/kontena/cli/stacks/show_command_spec.rb +26 -0
- data/spec/kontena/cli/stacks/upgrade_command_spec.rb +50 -0
- data/spec/kontena/cli/stacks/yaml/reader_spec.rb +370 -0
- data/spec/kontena/cli/stacks/yaml/service_extender_spec.rb +128 -0
- data/spec/kontena/cli/stacks/yaml/validator_v3_spec.rb +302 -0
- data/spec/spec_helper.rb +6 -4
- data/spec/support/client_helpers.rb +1 -0
- metadata +57 -7
- data/lib/kontena/cli/registry/delete_command.rb +0 -18
- data/lib/kontena/cli/stacks/create_command.rb +0 -27
- data/lib/kontena/cli/stacks/update_command.rb +0 -27
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kontena::Cli::Stacks
|
2
|
+
class LogsCommand < Clamp::Command
|
3
|
+
include Kontena::Cli::Common
|
4
|
+
include Kontena::Cli::GridOptions
|
5
|
+
include Kontena::Cli::Helpers::LogHelper
|
6
|
+
|
7
|
+
parameter "NAME", "Stack name"
|
8
|
+
option ["-t", "--tail"], :flag, "Tail (follow) logs", default: false
|
9
|
+
option ["-l", "--lines"], "LINES", "How many lines to show", default: '100'
|
10
|
+
option "--since", "SINCE", "Show logs since given timestamp"
|
11
|
+
|
12
|
+
def execute
|
13
|
+
require_api_url
|
14
|
+
token = require_token
|
15
|
+
|
16
|
+
query_params = {}
|
17
|
+
query_params[:limit] = lines if lines
|
18
|
+
query_params[:since] = since if since
|
19
|
+
|
20
|
+
show_logs("stacks/#{current_grid}/#{name}/container_logs", query_params) do |log|
|
21
|
+
show_log(log)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def show_log(log)
|
26
|
+
color = color_for_container(log['name'])
|
27
|
+
prefix = "#{log['created_at']} [#{log['name']}]:".colorize(color)
|
28
|
+
puts "#{prefix} #{log['data']}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative 'common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks
|
4
|
+
class MonitorCommand < Clamp::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Kontena::Cli::GridOptions
|
7
|
+
include Common
|
8
|
+
|
9
|
+
parameter "NAME", "Stack name"
|
10
|
+
|
11
|
+
attr_reader :services
|
12
|
+
|
13
|
+
def execute
|
14
|
+
require_api_url
|
15
|
+
token = require_token
|
16
|
+
|
17
|
+
response = client(token).get("grids/#{current_grid}/services?stack=#{name}")
|
18
|
+
show_monitor(response['services'])
|
19
|
+
|
20
|
+
@services = services_from_yaml(filename, service_list, service_prefix)
|
21
|
+
if services.size > 0
|
22
|
+
show_monitor(services)
|
23
|
+
elsif !service_list.empty?
|
24
|
+
puts "No such service: #{service_list.join(', ')}".colorize(:red)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def show_monitor(services)
|
29
|
+
loop do
|
30
|
+
nodes = {}
|
31
|
+
services.each do |service|
|
32
|
+
result = client(token).get("services/#{service['id']}/containers") rescue nil
|
33
|
+
if result
|
34
|
+
service['instances'] = result['containers'].size
|
35
|
+
result['containers'].each do |container|
|
36
|
+
container['service'] = service['name']
|
37
|
+
nodes[container['node']['name']] ||= []
|
38
|
+
nodes[container['node']['name']] << container
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
clear_terminal
|
43
|
+
puts "grid: #{current_grid}"
|
44
|
+
puts "stack: #{name}"
|
45
|
+
puts "services:"
|
46
|
+
services.each do |service|
|
47
|
+
color = color_for_service(service['name'])
|
48
|
+
puts " #{"■".colorize(color)} #{service['name']} (#{service['instances']} instances)"
|
49
|
+
end
|
50
|
+
puts "nodes:"
|
51
|
+
node_names = nodes.keys.sort
|
52
|
+
node_names.each do |name|
|
53
|
+
containers = nodes[name]
|
54
|
+
puts " #{name} (#{containers.size} instances)"
|
55
|
+
print " "
|
56
|
+
containers.each do |container|
|
57
|
+
icon = "■"
|
58
|
+
if container['status'] != 'running'
|
59
|
+
icon = "□"
|
60
|
+
end
|
61
|
+
color = color_for_service(container['service'])
|
62
|
+
print icon.colorize(color)
|
63
|
+
end
|
64
|
+
puts ''
|
65
|
+
end
|
66
|
+
sleep 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def color_for_service(service)
|
71
|
+
color_maps[service] = colors.shift unless color_maps[service]
|
72
|
+
color_maps[service].to_sym
|
73
|
+
end
|
74
|
+
|
75
|
+
def color_maps
|
76
|
+
@color_maps ||= {}
|
77
|
+
end
|
78
|
+
|
79
|
+
def colors
|
80
|
+
if(@colors.nil? || @colors.size == 0)
|
81
|
+
@colors = [:green, :magenta, :yellow, :cyan, :red,
|
82
|
+
:light_green, :light_yellow, :ligh_magenta, :light_cyan, :light_red]
|
83
|
+
end
|
84
|
+
@colors
|
85
|
+
end
|
86
|
+
|
87
|
+
def clear_terminal
|
88
|
+
print "\e[H\e[2J"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -6,21 +6,38 @@ module Kontena::Cli::Stacks
|
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Common
|
8
8
|
|
9
|
-
parameter "NAME", "
|
9
|
+
parameter "NAME", "Stack name"
|
10
|
+
option "--force", :flag, "Force remove", default: false, attribute_name: :forced
|
10
11
|
|
11
12
|
def execute
|
12
13
|
require_api_url
|
13
|
-
require_token
|
14
|
+
token = require_token
|
14
15
|
|
15
|
-
|
16
|
+
confirm_command(name) unless forced?
|
17
|
+
spinner "Removing stack #{pastel.cyan(name)} " do
|
18
|
+
remove_stack(token, name)
|
19
|
+
wait_stack_removal(token, name)
|
20
|
+
end
|
16
21
|
end
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def remove_stack(name)
|
23
|
+
def remove_stack(token, name)
|
22
24
|
client(token).delete("stacks/#{current_grid}/#{name}")
|
23
25
|
end
|
24
26
|
|
27
|
+
def wait_stack_removal(token, name)
|
28
|
+
removed = false
|
29
|
+
until removed == true
|
30
|
+
begin
|
31
|
+
client(token).get("stacks/#{current_grid}/#{name}")
|
32
|
+
sleep 1
|
33
|
+
rescue Kontena::Errors::StandardError => exc
|
34
|
+
if exc.status == 404
|
35
|
+
removed = true
|
36
|
+
else
|
37
|
+
raise exc
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
25
42
|
end
|
26
43
|
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'shellwords'
|
3
|
+
require_relative '../services/services_helper'
|
4
|
+
|
5
|
+
module Kontena::Cli::Stacks
|
6
|
+
class ServiceGenerator
|
7
|
+
include Kontena::Cli::Services::ServicesHelper
|
8
|
+
|
9
|
+
attr_reader :service_config
|
10
|
+
|
11
|
+
def initialize(service_config)
|
12
|
+
@service_config = service_config
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# @return [Hash]
|
17
|
+
def generate
|
18
|
+
parse_data(service_config)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
##
|
24
|
+
# @param [Hash] options
|
25
|
+
# @return [Hash]
|
26
|
+
def parse_data(options)
|
27
|
+
data = {}
|
28
|
+
data['container_count'] = options['instances']
|
29
|
+
data['image'] = parse_image(options['image'])
|
30
|
+
data['env'] = options['environment'] if options['environment']
|
31
|
+
data['container_count'] = options['instances']
|
32
|
+
data['links'] = parse_links(options['links'] || [])
|
33
|
+
data['external_links'] = parse_links(options['external_links'] || [])
|
34
|
+
data['ports'] = parse_stringified_ports(options['ports'] || [])
|
35
|
+
data['memory'] = parse_memory(options['mem_limit'].to_s) if options['mem_limit']
|
36
|
+
data['memory_swap'] = parse_memory(options['memswap_limit'].to_s) if options['memswap_limit']
|
37
|
+
data['cpu_shares'] = options['cpu_shares'] if options['cpu_shares']
|
38
|
+
data['volumes'] = options['volumes'] || []
|
39
|
+
data['volumes_from'] = options['volumes_from'] || []
|
40
|
+
data['cmd'] = Shellwords.split(options['command']) if options['command']
|
41
|
+
data['affinity'] = options['affinity'] || []
|
42
|
+
data['user'] = options['user'] if options['user']
|
43
|
+
data['stateful'] = options['stateful'] == true
|
44
|
+
data['privileged'] = options['privileged'] unless options['privileged'].nil?
|
45
|
+
data['cap_add'] = options['cap_add'] if options['cap_add']
|
46
|
+
data['cap_drop'] = options['cap_drop'] if options['cap_drop']
|
47
|
+
data['net'] = options['net'] if options['net']
|
48
|
+
data['pid'] = options['pid'] if options['pid']
|
49
|
+
data['log_driver'] = options['log_driver'] if options['log_driver']
|
50
|
+
data['log_opts'] = options['log_opt'] if options['log_opt'] && !options['log_opt'].empty?
|
51
|
+
deploy_opts = options['deploy'] || {}
|
52
|
+
data['strategy'] = deploy_opts['strategy'] if deploy_opts['strategy']
|
53
|
+
deploy = {}
|
54
|
+
deploy['wait_for_port'] = deploy_opts['wait_for_port'] if deploy_opts.has_key?('wait_for_port')
|
55
|
+
deploy['min_health'] = deploy_opts['min_health'] if deploy_opts.has_key?('min_health')
|
56
|
+
deploy['interval'] = parse_relative_time(deploy_opts['interval']) if deploy_opts.has_key?('interval')
|
57
|
+
unless deploy.empty?
|
58
|
+
data['deploy_opts'] = deploy
|
59
|
+
end
|
60
|
+
data['hooks'] = options['hooks'] || {}
|
61
|
+
data['secrets'] = options['secrets'] if options['secrets']
|
62
|
+
data['build'] = parse_build_options(options) if options['build']
|
63
|
+
health_check = {}
|
64
|
+
health_opts = options['health_check'] || {}
|
65
|
+
health_check['protocol'] = health_opts['protocol'] if health_opts.has_key?('protocol')
|
66
|
+
health_check['uri'] = health_opts['uri'] if health_opts.has_key?('uri')
|
67
|
+
health_check['port'] = health_opts['port'] if health_opts.has_key?('port')
|
68
|
+
health_check['timeout'] = health_opts['timeout'] if health_opts.has_key?('timeout')
|
69
|
+
health_check['interval'] = health_opts['interval'] if health_opts.has_key?('interval')
|
70
|
+
health_check['initial_delay'] = health_opts['initial_delay'] if health_opts.has_key?('initial_delay')
|
71
|
+
unless health_check.empty?
|
72
|
+
data['health_check'] = health_check
|
73
|
+
end
|
74
|
+
data
|
75
|
+
end
|
76
|
+
|
77
|
+
# @param [Array<String>] port_options
|
78
|
+
# @return [Array<Hash>]
|
79
|
+
def parse_stringified_ports(port_options)
|
80
|
+
parse_ports(port_options).map {|p|
|
81
|
+
{
|
82
|
+
'ip' => p[:ip],
|
83
|
+
'container_port' => p[:container_port],
|
84
|
+
'node_port' => p[:node_port],
|
85
|
+
'protocol' => p[:protocol]
|
86
|
+
}
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param [Array<String>] link_options
|
91
|
+
# @return [Array<Hash>]
|
92
|
+
def parse_links(link_options)
|
93
|
+
link_options.map{|l|
|
94
|
+
service_name, alias_name = l.split(':')
|
95
|
+
if service_name.nil?
|
96
|
+
raise ArgumentError.new("Invalid link value #{l}")
|
97
|
+
end
|
98
|
+
alias_name = service_name if alias_name.nil?
|
99
|
+
{
|
100
|
+
'name' => service_name,
|
101
|
+
'alias' => alias_name
|
102
|
+
}
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
# @param [Hash] options
|
107
|
+
# @return [Hash]
|
108
|
+
def parse_build_options(options)
|
109
|
+
build = {}
|
110
|
+
build['context'] = options['build'] if options['build']
|
111
|
+
build['dockerfile'] = options['dockerfile'] if options['dockerfile']
|
112
|
+
build
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require_relative 'service_generator'
|
3
|
+
|
4
|
+
module Kontena::Cli::Stacks
|
5
|
+
class ServiceGeneratorV2 < ServiceGenerator
|
6
|
+
|
7
|
+
def parse_data(options)
|
8
|
+
data = super(options)
|
9
|
+
data['net'] = options['network_mode'] if options['network_mode']
|
10
|
+
data['log_driver'] = options.dig('logging', 'driver')
|
11
|
+
data['log_opts'] = options.dig('logging', 'options')
|
12
|
+
if options['depends_on']
|
13
|
+
data['links'] ||= []
|
14
|
+
data['links'] = (data['links'] + parse_links(options['depends_on'])).uniq
|
15
|
+
end
|
16
|
+
data
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_build_options(options)
|
20
|
+
unless options['build'].is_a?(Hash)
|
21
|
+
options['build'] = { 'context' => options['build']}
|
22
|
+
end
|
23
|
+
options['build']['args'] = parse_build_args(options['build']['args']) if options['build']['args']
|
24
|
+
options['build']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -6,33 +6,85 @@ module Kontena::Cli::Stacks
|
|
6
6
|
include Kontena::Cli::GridOptions
|
7
7
|
include Common
|
8
8
|
|
9
|
-
parameter "NAME", "
|
9
|
+
parameter "NAME", "Stack name"
|
10
10
|
|
11
11
|
def execute
|
12
12
|
require_api_url
|
13
|
-
require_token
|
14
|
-
|
15
|
-
show_stack(name)
|
16
|
-
|
17
|
-
end
|
13
|
+
token = require_token
|
18
14
|
|
19
|
-
|
15
|
+
show_stack(token, name)
|
16
|
+
end
|
20
17
|
|
21
|
-
def show_stack(name)
|
18
|
+
def show_stack(token, name)
|
22
19
|
stack = client(token).get("stacks/#{current_grid}/#{name}")
|
23
20
|
|
24
|
-
puts stack
|
25
|
-
|
26
|
-
puts "#{stack['id']}:"
|
21
|
+
puts "#{stack['name']}:"
|
27
22
|
puts " state: #{stack['state']}"
|
28
23
|
puts " created_at: #{stack['created_at']}"
|
29
24
|
puts " updated_at: #{stack['updated_at']}"
|
30
25
|
puts " version: #{stack['version']}"
|
26
|
+
puts " expose: #{stack['expose'] || '-'}"
|
31
27
|
puts " services:"
|
32
|
-
stack['
|
33
|
-
|
28
|
+
stack['services'].each do |service|
|
29
|
+
show_service(token, service['id'])
|
34
30
|
end
|
35
31
|
end
|
36
32
|
|
33
|
+
# @param [String] token
|
34
|
+
# @param [String] service_id
|
35
|
+
def show_service(token, service_id)
|
36
|
+
service = get_service(token, service_id)
|
37
|
+
pad = ' '.freeze
|
38
|
+
puts "#{pad}#{service['name']}:"
|
39
|
+
puts "#{pad} image: #{service['image']}"
|
40
|
+
puts "#{pad} status: #{service['state'] }"
|
41
|
+
if service['health_status']
|
42
|
+
puts "#{pad} health_status:"
|
43
|
+
puts "#{pad} healthy: #{service['health_status']['healthy']}"
|
44
|
+
puts "#{pad} total: #{service['health_status']['total']}"
|
45
|
+
end
|
46
|
+
puts "#{pad} revision: #{service['revision']}"
|
47
|
+
puts "#{pad} stateful: #{service['stateful'] == true ? 'yes' : 'no' }"
|
48
|
+
puts "#{pad} scaling: #{service['container_count'] }"
|
49
|
+
puts "#{pad} strategy: #{service['strategy']}"
|
50
|
+
puts "#{pad} deploy_opts:"
|
51
|
+
puts "#{pad} min_health: #{service['deploy_opts']['min_health']}"
|
52
|
+
if service['deploy_opts']['wait_for_port']
|
53
|
+
puts "#{pad} wait_for_port: #{service['deploy_opts']['wait_for_port']}"
|
54
|
+
end
|
55
|
+
if service['deploy_opts']['interval']
|
56
|
+
puts "#{pad} interval: #{service['deploy_opts']['interval']}"
|
57
|
+
end
|
58
|
+
puts "#{pad} dns: #{service['dns']}"
|
59
|
+
|
60
|
+
if service['affinity'].to_a.size > 0
|
61
|
+
puts "#{pad} affinity: "
|
62
|
+
service['affinity'].to_a.each do |a|
|
63
|
+
puts "#{pad} - #{a}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
unless service['cmd'].to_s.empty?
|
68
|
+
if service['cmd']
|
69
|
+
puts "#{pad} cmd: #{service['cmd'].join(' ')}"
|
70
|
+
else
|
71
|
+
puts "#{pad} cmd: "
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if service['ports'].to_a.size > 0
|
76
|
+
puts "#{pad} ports:"
|
77
|
+
service['ports'].to_a.each do |p|
|
78
|
+
puts "#{pad} - #{p['node_port']}:#{p['container_port']}/#{p['protocol']}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if service['links'].to_a.size > 0
|
83
|
+
puts "#{pad} links: "
|
84
|
+
service['links'].to_a.each do |l|
|
85
|
+
puts "#{pad} - #{l['alias']} => #{l['id']}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
37
89
|
end
|
38
90
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Stacks
|
4
|
+
class UpgradeCommand < Kontena::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Kontena::Cli::GridOptions
|
7
|
+
include Common
|
8
|
+
|
9
|
+
parameter "NAME", "Stack name"
|
10
|
+
parameter "FILE", "Kontena stack file"
|
11
|
+
option '--deploy', :flag, 'Deploy after upgrade'
|
12
|
+
|
13
|
+
def execute
|
14
|
+
require_api_url
|
15
|
+
token = require_token
|
16
|
+
require_config_file(file)
|
17
|
+
stack = stack_from_yaml(file)
|
18
|
+
spinner "Upgrading stack #{pastel.cyan(name)} " do
|
19
|
+
update_stack(token, stack)
|
20
|
+
end
|
21
|
+
Kontena.run("stack deploy #{name}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_stack(token, stack)
|
25
|
+
client(token).put("stacks/#{current_grid}/#{name}", stack)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Kontena::Cli::Stacks::YAML::Validations::CustomValidators
|
2
|
+
class AffinitiesValidator < HashValidator::Validator::Base
|
3
|
+
def initialize
|
4
|
+
super('stacks_valid_affinities')
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate(key, value, validations, errors)
|
8
|
+
unless value.is_a?(Array)
|
9
|
+
errors[key] = 'affinity must be array'
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
invalid_formats = value.find_all { |a| !a.match(/(?<=\!|\=)=/) }
|
14
|
+
if invalid_formats.count > 0
|
15
|
+
errors[key] = "affinity contains invalid formats: #{invalid_formats.join(', ')}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|