kontena-cli 1.0.6 → 1.1.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.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/VERSION +1 -1
- data/bin/kontena +4 -1
- data/kontena-cli.gemspec +1 -1
- data/lib/kontena/callback.rb +1 -1
- data/lib/kontena/callbacks/master/01_clear_current_master_after_terminate.rb +1 -1
- data/lib/kontena/callbacks/master/deploy/50_authenticate_after_deploy.rb +5 -5
- data/lib/kontena/callbacks/master/deploy/55_create_initial_grid_after_deploy.rb +1 -1
- data/lib/kontena/callbacks/master/deploy/56_set_server_provider_after_deploy.rb +25 -0
- data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +1 -1
- data/lib/kontena/cli/common.rb +3 -3
- data/lib/kontena/cli/config.rb +1 -1
- data/lib/kontena/cli/grid_command.rb +2 -0
- data/lib/kontena/cli/grids/common.rb +12 -0
- data/lib/kontena/cli/grids/health_command.rb +69 -0
- data/lib/kontena/cli/helpers/health_helper.rb +53 -0
- data/lib/kontena/cli/localhost_web_server.rb +3 -3
- data/lib/kontena/cli/master/users/invite_command.rb +1 -1
- data/lib/kontena/cli/node_command.rb +2 -0
- data/lib/kontena/cli/nodes/health_command.rb +32 -0
- data/lib/kontena/cli/nodes/list_command.rb +40 -26
- data/lib/kontena/cli/nodes/show_command.rb +0 -1
- data/lib/kontena/cli/plugins/install_command.rb +28 -30
- data/lib/kontena/cli/plugins/search_command.rb +6 -14
- data/lib/kontena/cli/plugins/uninstall_command.rb +7 -11
- data/lib/kontena/cli/services/stats_command.rb +4 -2
- data/lib/kontena/cli/spinner.rb +20 -4
- data/lib/kontena/cli/stacks/show_command.rb +5 -1
- data/lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb +22 -0
- data/lib/kontena/cli/stacks/yaml/opto/vault_setter.rb +1 -1
- data/lib/kontena/cli/stacks/yaml/reader.rb +1 -0
- data/lib/kontena/cli/vault/export_command.rb +22 -0
- data/lib/kontena/cli/vault/import_command.rb +80 -0
- data/lib/kontena/cli/vault/list_command.rb +4 -0
- data/lib/kontena/cli/vault/read_command.rb +8 -3
- data/lib/kontena/cli/vault/remove_command.rb +2 -1
- data/lib/kontena/cli/vault/update_command.rb +5 -7
- data/lib/kontena/cli/vault_command.rb +5 -1
- data/lib/kontena/client.rb +25 -2
- data/lib/kontena/command.rb +1 -1
- data/lib/kontena/debug_instrumentor.rb +70 -0
- data/lib/kontena/light_prompt.rb +103 -0
- data/lib/kontena/plugin_manager.rb +167 -6
- data/lib/kontena/stacks_cache.rb +1 -1
- data/lib/kontena_cli.rb +23 -6
- data/spec/kontena/cli/grids/health_command_spec.rb +390 -0
- data/spec/kontena/cli/nodes/health_command_spec.rb +206 -0
- data/spec/kontena/cli/nodes/list_command_spec.rb +205 -0
- data/spec/kontena/cli/vault/export_spec.rb +32 -0
- data/spec/kontena/cli/vault/import_spec.rb +69 -0
- data/spec/kontena/client_spec.rb +39 -0
- data/spec/kontena/plugin_manager_spec.rb +7 -7
- data/spec/spec_helper.rb +1 -0
- data/spec/support/output_helpers.rb +51 -0
- metadata +27 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fa4fdfff0c1b90c0954ec7e31f8f916c8636f16
|
4
|
+
data.tar.gz: 62e78df6ba2b65b1bfcaacde2290d81719d93e82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2fb585c59f687236071ec28640e487f32e4b4a1426ef9152249bcdd0651dfb96d0250b1ec91df171e9c0c1b650c257c9bb0e9f2039d8fda9b5a553ddda9c55f
|
7
|
+
data.tar.gz: 7408e60150cbd48e54549a490af795bb6688af0e01c9969f2f53a20fb8b59417228b3d1fc798e877377a39d28540c9ba8c614a99be110ae86bc74bf07c60716a
|
data/Dockerfile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.1.0.pre1
|
data/bin/kontena
CHANGED
@@ -12,7 +12,7 @@ require 'kontena_cli'
|
|
12
12
|
STDOUT.sync = true
|
13
13
|
|
14
14
|
begin
|
15
|
-
Kontena::PluginManager.instance.
|
15
|
+
Kontena::PluginManager.instance.init
|
16
16
|
Kontena::MainCommand.run
|
17
17
|
rescue Excon::Errors::SocketError => exc
|
18
18
|
if exc.message.include?('Unable to verify certificate')
|
@@ -27,6 +27,9 @@ rescue Kontena::Errors::StandardError => exc
|
|
27
27
|
raise exc if ENV['DEBUG']
|
28
28
|
puts " [#{Kontena.pastel.red('error')}] #{exc.message}"
|
29
29
|
abort
|
30
|
+
rescue Errno::EPIPE
|
31
|
+
# If user is piping the command outputs to some other command that might exit before CLI has outputted everything
|
32
|
+
abort
|
30
33
|
rescue => exc
|
31
34
|
raise exc if ENV['DEBUG']
|
32
35
|
$stderr.puts " [#{Kontena.pastel.red('error')}] #{exc.message}"
|
data/kontena-cli.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.7"
|
24
24
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
25
|
spec.add_runtime_dependency "excon", "~> 0.49.0"
|
26
|
-
spec.add_runtime_dependency "tty-prompt", "~> 0.
|
26
|
+
spec.add_runtime_dependency "tty-prompt", "~> 0.10"
|
27
27
|
spec.add_runtime_dependency "clamp", "~> 1.1.0"
|
28
28
|
spec.add_runtime_dependency "ruby_dig", "~> 0.0.2"
|
29
29
|
spec.add_runtime_dependency "launchy", "~> 2.4.3"
|
data/lib/kontena/callback.rb
CHANGED
@@ -44,7 +44,7 @@ class Kontena::Callback
|
|
44
44
|
if klass.instance_methods.include?(state)
|
45
45
|
cb = klass.new(obj)
|
46
46
|
if cb.send(state).kind_of?(FalseClass)
|
47
|
-
ENV["DEBUG"] && puts("Execution aborted by #{klass}")
|
47
|
+
ENV["DEBUG"] && STDERR.puts("Execution aborted by #{klass}")
|
48
48
|
exit 1
|
49
49
|
end
|
50
50
|
end
|
@@ -10,7 +10,7 @@ module Kontena
|
|
10
10
|
return unless command.exit_code == 0
|
11
11
|
return unless config.current_master
|
12
12
|
|
13
|
-
ENV["DEBUG"] && puts("Removing current master from config")
|
13
|
+
ENV["DEBUG"] && STDERR.puts("Removing current master from config")
|
14
14
|
config.servers.delete_at(config.find_server_index(config.current_master.name))
|
15
15
|
config.current_server = nil
|
16
16
|
config.write
|
@@ -8,8 +8,8 @@ module Kontena
|
|
8
8
|
matches_commands 'master create'
|
9
9
|
|
10
10
|
def after
|
11
|
-
ENV["DEBUG"] && puts("Command result: #{command.result.inspect}")
|
12
|
-
ENV["DEBUG"] && puts("Command exit code: #{command.exit_code.inspect}")
|
11
|
+
ENV["DEBUG"] && STDERR.puts("Command result: #{command.result.inspect}")
|
12
|
+
ENV["DEBUG"] && STDERR.puts("Command exit code: #{command.exit_code.inspect}")
|
13
13
|
return unless command.exit_code == 0
|
14
14
|
return unless command.result.kind_of?(Hash)
|
15
15
|
return unless command.result.has_key?(:public_ip)
|
@@ -35,11 +35,11 @@ module Kontena
|
|
35
35
|
|
36
36
|
# Figure out if HTTPS works, if not, try HTTP
|
37
37
|
begin
|
38
|
-
ENV["DEBUG"] && puts("Trying to request / from #{new_master.url}")
|
38
|
+
ENV["DEBUG"] && STDERR.puts("Trying to request / from #{new_master.url}")
|
39
39
|
client = Kontena::Client.new(new_master.url, nil, ignore_ssl_errors: true)
|
40
40
|
client.get('/')
|
41
41
|
rescue
|
42
|
-
ENV["DEBUG"] && puts("HTTPS test failed: #{$!} #{$!.message}")
|
42
|
+
ENV["DEBUG"] && STDERR.puts("HTTPS test failed: #{$!} #{$!.message}")
|
43
43
|
unless retried
|
44
44
|
new_master.url = "http://#{command.result[:public_ip]}"
|
45
45
|
retried = true
|
@@ -51,7 +51,7 @@ module Kontena
|
|
51
51
|
require 'shellwords'
|
52
52
|
cmd = "master login --no-login-info --skip-grid-auto-select --verbose --name #{command.result[:name].shellescape} --code #{command.result[:code].shellescape} #{new_master.url.shellescape}"
|
53
53
|
Retriable.retriable do
|
54
|
-
ENV["DEBUG"] && puts("Running: #{cmd}")
|
54
|
+
ENV["DEBUG"] && STDERR.puts("Running: #{cmd}")
|
55
55
|
Kontena.run(cmd)
|
56
56
|
end
|
57
57
|
end
|
@@ -12,7 +12,7 @@ module Kontena
|
|
12
12
|
return unless config.current_master.name == command.result[:name]
|
13
13
|
|
14
14
|
cmd = "grid create --silent test"
|
15
|
-
ENV["DEBUG"] && puts("Running: #{cmd}")
|
15
|
+
ENV["DEBUG"] && STDERR.puts("Running: #{cmd}")
|
16
16
|
Retriable.retriable do
|
17
17
|
Kontena.run(cmd)
|
18
18
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kontena
|
2
|
+
module Callbacks
|
3
|
+
class SetServerProviderAfterDeploy < Kontena::Callback
|
4
|
+
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
|
7
|
+
matches_commands 'master create'
|
8
|
+
|
9
|
+
def after
|
10
|
+
return unless command.exit_code == 0
|
11
|
+
return unless config.current_master
|
12
|
+
return unless config.current_master.name == command.result[:name]
|
13
|
+
return unless command.result[:provider]
|
14
|
+
|
15
|
+
require 'shellwords'
|
16
|
+
|
17
|
+
cmd = ['master', 'config', 'set', "server.provider=#{command.result[:provider]}"]
|
18
|
+
spinner "Setting Master configuration server.provider to '#{command.result[:provider]}'" do
|
19
|
+
Kontena.run(cmd.shelljoin)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/lib/kontena/cli/common.rb
CHANGED
@@ -12,7 +12,7 @@ module Kontena
|
|
12
12
|
|
13
13
|
def logger
|
14
14
|
return @logger if @logger
|
15
|
-
@logger = Logger.new(STDOUT)
|
15
|
+
@logger = Logger.new(ENV["DEBUG"] ? STDERR : STDOUT)
|
16
16
|
@logger.level = ENV["DEBUG"].nil? ? Logger::INFO : Logger::DEBUG
|
17
17
|
@logger.progname = 'COMMON'
|
18
18
|
@logger
|
@@ -129,10 +129,10 @@ module Kontena
|
|
129
129
|
return unless server.token.refresh_token
|
130
130
|
return if server.token.expired?
|
131
131
|
client = Kontena::Client.new(server.url, server.token)
|
132
|
-
|
132
|
+
logger.debug "Trying to invalidate refresh token on #{server.name}"
|
133
133
|
client.refresh_token
|
134
134
|
rescue
|
135
|
-
|
135
|
+
logger.debug "Refreshing failed: #{$!} : #{$!.message}"
|
136
136
|
end
|
137
137
|
|
138
138
|
def require_current_master
|
data/lib/kontena/cli/config.rb
CHANGED
@@ -26,7 +26,7 @@ module Kontena
|
|
26
26
|
|
27
27
|
def initialize
|
28
28
|
super
|
29
|
-
@logger = Logger.new(STDOUT)
|
29
|
+
@logger = Logger.new(ENV["DEBUG"] ? STDERR : STDOUT)
|
30
30
|
@logger.level = ENV["DEBUG"].nil? ? Logger::INFO : Logger::DEBUG
|
31
31
|
@logger.progname = 'CONFIG'
|
32
32
|
load_settings_from_env || load_settings_from_config_file
|
@@ -11,6 +11,7 @@ require_relative 'grids/audit_log_command'
|
|
11
11
|
require_relative 'grids/user_command'
|
12
12
|
require_relative 'grids/cloud_config_command'
|
13
13
|
require_relative 'grids/trusted_subnet_command'
|
14
|
+
require_relative 'grids/health_command'
|
14
15
|
|
15
16
|
class Kontena::Cli::GridCommand < Kontena::Command
|
16
17
|
|
@@ -27,6 +28,7 @@ class Kontena::Cli::GridCommand < Kontena::Command
|
|
27
28
|
subcommand "user", "User specific commands", Kontena::Cli::Grids::UserCommand
|
28
29
|
subcommand "cloud-config", "Generate cloud-config", Kontena::Cli::Grids::CloudConfigCommand
|
29
30
|
subcommand "trusted-subnet", "Trusted subnet related commands", Kontena::Cli::Grids::TrustedSubnetCommand
|
31
|
+
subcommand "health", "Check grid health", Kontena::Cli::Grids::HealthCommand
|
30
32
|
|
31
33
|
def execute
|
32
34
|
end
|
@@ -7,6 +7,7 @@ module Kontena::Cli::Grids
|
|
7
7
|
host = ENV['KONTENA_URL'] || self.current_master['url']
|
8
8
|
puts "#{grid['name']}:"
|
9
9
|
puts " uri: #{host.sub('http', 'ws')}"
|
10
|
+
puts " initial_size: #{grid['initial_size']}"
|
10
11
|
root_dir = grid['engine_root_dir']
|
11
12
|
nodes = client(require_token).get("grids/#{grid['name']}/nodes")
|
12
13
|
nodes = nodes['nodes'].select{|n| n['connected'] == true }
|
@@ -92,5 +93,16 @@ module Kontena::Cli::Grids
|
|
92
93
|
return 0.0 if amount.nil?
|
93
94
|
(amount.to_f / 1024 / 1024 / 1024).to_f.round(2)
|
94
95
|
end
|
96
|
+
|
97
|
+
# @return [Hash] /v1/grids/:grid JSON { ... }
|
98
|
+
def get_grid(name = nil)
|
99
|
+
if name
|
100
|
+
client(require_token).get("grids/#{name}")
|
101
|
+
elsif current_grid
|
102
|
+
client(require_token).get("grids/#{current_grid}")
|
103
|
+
else
|
104
|
+
exit_with_error "No grid given or selected"
|
105
|
+
end
|
106
|
+
end
|
95
107
|
end
|
96
108
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative 'common'
|
2
|
+
require "kontena/cli/helpers/health_helper"
|
3
|
+
|
4
|
+
module Kontena::Cli::Grids
|
5
|
+
class HealthCommand < Kontena::Command
|
6
|
+
include Kontena::Cli::Common
|
7
|
+
include Kontena::Cli::Helpers::HealthHelper
|
8
|
+
include Common
|
9
|
+
|
10
|
+
parameter "[NAME]", "Grid name"
|
11
|
+
|
12
|
+
def execute
|
13
|
+
require_api_url
|
14
|
+
|
15
|
+
grid = get_grid(name)
|
16
|
+
grid_nodes = client(require_token).get("grids/#{grid['name']}/nodes")
|
17
|
+
|
18
|
+
return show_grid_health(grid, grid_nodes['nodes'])
|
19
|
+
end
|
20
|
+
|
21
|
+
# Validate grid/nodes configuration for grid operation
|
22
|
+
#
|
23
|
+
# @return [Boolean] false if unhealthy
|
24
|
+
def show_grid_health(grid, nodes)
|
25
|
+
initial_size = grid['initial_size']
|
26
|
+
minimum_size = grid['initial_size'] / 2 + 1 # a majority is required for etcd quorum
|
27
|
+
|
28
|
+
grid_health = grid_health(grid, nodes)
|
29
|
+
initial_nodes = nodes.select{|node| node['initial_member']}
|
30
|
+
online_nodes = initial_nodes.select{|node| node['connected']}
|
31
|
+
|
32
|
+
# configuration and status
|
33
|
+
if initial_nodes.length == 0
|
34
|
+
puts "#{health_icon :error} Grid does not have any initial nodes, and requires at least #{minimum_size} of #{initial_size} initial nodes for operation"
|
35
|
+
elsif online_nodes.empty?
|
36
|
+
puts "#{health_icon :error} Grid does not have any initial nodes online, and requires at least #{minimum_size} of #{initial_size} initial nodes for operation"
|
37
|
+
elsif initial_nodes.length < minimum_size
|
38
|
+
puts "#{health_icon :error} Grid only has #{initial_nodes.length} initial nodes, and requires at least #{minimum_size} of #{initial_size} initial nodes for operation"
|
39
|
+
elsif online_nodes.length < minimum_size
|
40
|
+
puts "#{health_icon :error} Grid only has #{online_nodes.length} initial nodes online, and requires at least #{minimum_size} of #{initial_size} initial nodes for operation"
|
41
|
+
elsif initial_nodes.length < initial_size
|
42
|
+
puts "#{health_icon :warning} Grid only has #{initial_nodes.length} initial nodes of #{initial_size} required for high-availability"
|
43
|
+
elsif online_nodes.length < initial_size
|
44
|
+
puts "#{health_icon :warning} Grid only has #{online_nodes.length} initial nodes online of #{initial_size} required for high-availability"
|
45
|
+
elsif initial_nodes.length == 2
|
46
|
+
puts "#{health_icon :warning} Grid only has #{initial_nodes.length} initial nodes, and is not high-availability"
|
47
|
+
elsif initial_nodes.length == 1
|
48
|
+
puts "#{health_icon :warning} Grid only has #{initial_nodes.length} initial node, and is not high-availability"
|
49
|
+
else
|
50
|
+
puts "#{health_icon :ok} Grid has all #{online_nodes.length} of #{initial_size} initial nodes online"
|
51
|
+
end
|
52
|
+
|
53
|
+
nodes.each do |node|
|
54
|
+
node_health = node_health(node, grid_health)
|
55
|
+
|
56
|
+
if node['connected']
|
57
|
+
|
58
|
+
elsif node['initial_member']
|
59
|
+
puts "#{health_icon grid_health} Initial node #{node['name']} is offline"
|
60
|
+
else
|
61
|
+
puts "#{health_icon node_health} Grid node #{node['name']} is offline"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# operational if we have etcd quorum
|
66
|
+
return online_nodes.length >= minimum_size
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Kontena::Cli::Helpers
|
2
|
+
module HealthHelper
|
3
|
+
def health_icon(health)
|
4
|
+
case health
|
5
|
+
when nil
|
6
|
+
" "
|
7
|
+
when :ok
|
8
|
+
pastel.green('⊛')
|
9
|
+
when :warning
|
10
|
+
pastel.yellow('⊙')
|
11
|
+
when :error
|
12
|
+
pastel.red('⊗')
|
13
|
+
when :offline
|
14
|
+
pastel.dark('⊝')
|
15
|
+
else
|
16
|
+
fail "Invalid health=#{health}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Validate grid nodes configuration and status
|
21
|
+
#
|
22
|
+
# @param grid [Hash] get(/grids/:grid) => { ... }
|
23
|
+
# @param nodes [Array<Hash>] get(/grids/:grid/nodes)[nodes] => [ { ... } ]
|
24
|
+
# @return [Symbol] health
|
25
|
+
def grid_health(grid, nodes)
|
26
|
+
initial = grid['initial_size']
|
27
|
+
minimum = grid['initial_size'] / 2 + 1 # a majority is required for etcd quorum
|
28
|
+
|
29
|
+
online = nodes.select{|node| node['initial_member'] && node['connected']}
|
30
|
+
|
31
|
+
if online.length < minimum
|
32
|
+
return :error
|
33
|
+
elsif online.length < initial
|
34
|
+
return :warning
|
35
|
+
else
|
36
|
+
return :ok
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Validate grid node status based on the grid health
|
41
|
+
#
|
42
|
+
# @param node [Hash] GET /nodes/:grid/:node
|
43
|
+
# @param grid_health [Symbol] @see #grid_health
|
44
|
+
# @return [Symbol] health
|
45
|
+
def node_health(node, grid_health)
|
46
|
+
if node['initial_member']
|
47
|
+
return node['connected'] ? grid_health : :offline
|
48
|
+
else
|
49
|
+
return node['connected'] ? :ok : :offline
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -39,7 +39,7 @@ module Kontena
|
|
39
39
|
#
|
40
40
|
# @return [Hash] query_params
|
41
41
|
def serve_one
|
42
|
-
ENV["DEBUG"] && puts("Waiting for connection on port #{port}..")
|
42
|
+
ENV["DEBUG"] && STDERR.puts("Waiting for connection on port #{port}..")
|
43
43
|
socket = server.accept
|
44
44
|
|
45
45
|
content = socket.recvfrom(2048).first.split(/(?:\r)?\n/)
|
@@ -56,7 +56,7 @@ module Kontena
|
|
56
56
|
|
57
57
|
body = content.join("\n")
|
58
58
|
|
59
|
-
ENV["DEBUG"] && puts("Got request: \"#{request.inspect}\n Headers: #{headers.inspect}\n Body: #{body}\"")
|
59
|
+
ENV["DEBUG"] && STDERR.puts("Got request: \"#{request.inspect}\n Headers: #{headers.inspect}\n Body: #{body}\"")
|
60
60
|
|
61
61
|
get_request = request[/GET (\/cb.+?) HTTP/, 1]
|
62
62
|
if get_request
|
@@ -81,7 +81,7 @@ module Kontena
|
|
81
81
|
socket.close
|
82
82
|
server.close
|
83
83
|
uri = URI.parse("http://localhost#{get_request}")
|
84
|
-
ENV["DEBUG"] && puts(" * Parsing params: \"#{uri.query}\"")
|
84
|
+
ENV["DEBUG"] && STDERR.puts(" * Parsing params: \"#{uri.query}\"")
|
85
85
|
params = {}
|
86
86
|
URI.decode_www_form(uri.query).each do |key, value|
|
87
87
|
if value.to_s == ''
|
@@ -43,7 +43,7 @@ module Kontena::Cli::Master::Users
|
|
43
43
|
end
|
44
44
|
rescue
|
45
45
|
STDERR.puts "Failed to invite #{email}".colorize(:red)
|
46
|
-
ENV["DEBUG"] && puts("#{$!} - #{$!.message} -- #{$!.backtrace}")
|
46
|
+
ENV["DEBUG"] && STDERR.puts("#{$!} - #{$!.message} -- #{$!.backtrace}")
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -4,6 +4,7 @@ require_relative 'nodes/show_command'
|
|
4
4
|
require_relative 'nodes/update_command'
|
5
5
|
require_relative 'nodes/ssh_command'
|
6
6
|
require_relative 'nodes/label_command'
|
7
|
+
require_relative 'nodes/health_command'
|
7
8
|
|
8
9
|
class Kontena::Cli::NodeCommand < Kontena::Command
|
9
10
|
|
@@ -13,6 +14,7 @@ class Kontena::Cli::NodeCommand < Kontena::Command
|
|
13
14
|
subcommand "update", "Update node", Kontena::Cli::Nodes::UpdateCommand
|
14
15
|
subcommand ["remove","rm"], "Remove node", Kontena::Cli::Nodes::RemoveCommand
|
15
16
|
subcommand "label", "Node label specific commands", Kontena::Cli::Nodes::LabelCommand
|
17
|
+
subcommand "health", "Check node health", Kontena::Cli::Nodes::HealthCommand
|
16
18
|
|
17
19
|
def execute
|
18
20
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative '../helpers/health_helper'
|
2
|
+
|
3
|
+
module Kontena::Cli::Nodes
|
4
|
+
class HealthCommand < Kontena::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Kontena::Cli::GridOptions
|
7
|
+
include Kontena::Cli::Helpers::HealthHelper
|
8
|
+
|
9
|
+
parameter "NODE_ID", "Node id"
|
10
|
+
|
11
|
+
def execute
|
12
|
+
require_api_url
|
13
|
+
require_current_grid
|
14
|
+
token = require_token
|
15
|
+
|
16
|
+
node = client(token).get("nodes/#{current_grid}/#{node_id}")
|
17
|
+
|
18
|
+
return show_node_health(node)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Boolean] true if healthy
|
22
|
+
def show_node_health(node)
|
23
|
+
if node['connected']
|
24
|
+
puts "#{health_icon(:ok)} Node is online"
|
25
|
+
return true
|
26
|
+
else
|
27
|
+
puts "#{health_icon(:offline)} Node is offline"
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,46 +1,60 @@
|
|
1
|
+
require_relative '../helpers/health_helper'
|
2
|
+
|
1
3
|
module Kontena::Cli::Nodes
|
2
4
|
class ListCommand < Kontena::Command
|
3
5
|
include Kontena::Cli::Common
|
4
6
|
include Kontena::Cli::GridOptions
|
7
|
+
include Kontena::Cli::Helpers::HealthHelper
|
5
8
|
|
6
9
|
option ["--all"], :flag, "List nodes for all grids", default: false
|
7
10
|
|
11
|
+
def node_initial(node, grid)
|
12
|
+
if node['initial_member']
|
13
|
+
return "#{node['node_number']} / #{grid['initial_size']}"
|
14
|
+
else
|
15
|
+
return "-"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def node_labels(node)
|
20
|
+
(node['labels'] || ['-']).join(",")
|
21
|
+
end
|
22
|
+
|
23
|
+
def show_grid_nodes(grid, nodes, multi: false)
|
24
|
+
grid_health = grid_health(grid, nodes)
|
25
|
+
|
26
|
+
nodes = nodes.sort_by{|n| n['node_number'] }
|
27
|
+
nodes.each do |node|
|
28
|
+
puts [
|
29
|
+
"%s" % health_icon(node_health(node, grid_health)),
|
30
|
+
"%-70.70s" % [multi ? "#{grid['name']}/#{node['name']}" : node['name']],
|
31
|
+
"%-10s" % node['agent_version'],
|
32
|
+
"%-10s" % (node['connected'] ? "online" : "offline"),
|
33
|
+
"%-10s" % node_initial(node, grid),
|
34
|
+
"%s" % [node_labels(node)],
|
35
|
+
].join ' '
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
8
39
|
def execute
|
9
40
|
require_api_url
|
10
41
|
require_current_grid
|
11
42
|
token = require_token
|
12
43
|
|
44
|
+
puts "%s %-70s %-10s %-10s %-10s %-s" % [health_icon(nil), "Name", "Version", "Status", "Initial", "Labels"]
|
45
|
+
|
13
46
|
if all?
|
14
47
|
grids = client(token).get("grids")
|
15
|
-
puts "%-70s %-10s %-40s" % [ 'Name', 'Status', 'Labels']
|
16
|
-
|
17
48
|
grids['grids'].each do |grid|
|
18
|
-
nodes = client(
|
19
|
-
|
20
|
-
|
21
|
-
status = 'online'
|
22
|
-
else
|
23
|
-
status = 'offline'
|
24
|
-
end
|
25
|
-
puts "%-70.70s %-10s %-40s" % [
|
26
|
-
"#{grid['name']}/#{node['name']}",
|
27
|
-
status,
|
28
|
-
(node['labels'] || ['-']).join(",")
|
29
|
-
]
|
30
|
-
end
|
49
|
+
nodes = client(require_token).get("grids/#{grid['id']}/nodes")['nodes']
|
50
|
+
|
51
|
+
show_grid_nodes(grid, nodes, multi: true)
|
31
52
|
end
|
32
53
|
else
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
nodes
|
37
|
-
puts "%-70.70s %-10s %-10s %-40s" % [
|
38
|
-
node['name'],
|
39
|
-
node['connected'] ? 'online' : 'offline',
|
40
|
-
node['initial_member'] ? 'yes' : 'no',
|
41
|
-
(node['labels'] || ['-']).join(",")
|
42
|
-
]
|
43
|
-
end
|
54
|
+
grid = client(token).get("grids/#{current_grid}")
|
55
|
+
nodes = client(require_token).get("grids/#{current_grid}/nodes")['nodes']
|
56
|
+
|
57
|
+
show_grid_nodes(grid, nodes)
|
44
58
|
end
|
45
59
|
end
|
46
60
|
end
|