kontena-cli 0.9.3 → 0.10.0
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/VERSION +1 -1
- data/bin/kontena +3 -2
- data/lib/kontena/cli/app_command.rb +6 -2
- data/lib/kontena/cli/apps/build_command.rb +0 -1
- data/lib/kontena/cli/apps/common.rb +1 -0
- data/lib/kontena/cli/apps/deploy_command.rb +17 -13
- data/lib/kontena/cli/apps/init_command.rb +1 -2
- data/lib/kontena/cli/apps/list_command.rb +13 -5
- data/lib/kontena/cli/apps/logs_command.rb +22 -13
- data/lib/kontena/cli/apps/monitor_command.rb +91 -0
- data/lib/kontena/cli/apps/remove_command.rb +0 -2
- data/lib/kontena/cli/apps/scale_command.rb +32 -0
- data/lib/kontena/cli/apps/show_command.rb +22 -0
- data/lib/kontena/cli/apps/start_command.rb +0 -1
- data/lib/kontena/cli/apps/stop_command.rb +0 -1
- data/lib/kontena/cli/common.rb +12 -0
- data/lib/kontena/cli/containers/inspect_command.rb +8 -3
- data/lib/kontena/cli/etcd/common.rb +8 -0
- data/lib/kontena/cli/etcd/get_command.rb +4 -0
- data/lib/kontena/cli/etcd/list_command.rb +4 -0
- data/lib/kontena/cli/etcd/mkdir_command.rb +5 -0
- data/lib/kontena/cli/etcd/remove_command.rb +5 -0
- data/lib/kontena/cli/etcd/set_command.rb +5 -0
- data/lib/kontena/cli/grid_command.rb +2 -0
- data/lib/kontena/cli/grids/env_command.rb +22 -0
- data/lib/kontena/cli/grids/logs_command.rb +12 -1
- data/lib/kontena/cli/node_command.rb +2 -0
- data/lib/kontena/cli/nodes/ssh_command.rb +30 -0
- data/lib/kontena/cli/service_command.rb +4 -0
- data/lib/kontena/cli/services/create_command.rb +9 -0
- data/lib/kontena/cli/services/deploy_command.rb +1 -7
- data/lib/kontena/cli/services/envs_command.rb +19 -0
- data/lib/kontena/cli/services/list_command.rb +15 -3
- data/lib/kontena/cli/services/monitor_command.rb +57 -0
- data/lib/kontena/cli/services/scale_command.rb +2 -6
- data/lib/kontena/cli/services/services_helper.rb +94 -43
- data/lib/kontena/cli/services/update_command.rb +12 -1
- data/lib/kontena/machine/aws/cloudinit_master.yml +2 -2
- data/lib/kontena/machine/azure/cloudinit_master.yml +2 -2
- data/lib/kontena/machine/digital_ocean/cloudinit_master.yml +2 -2
- data/lib/kontena/scripts/completer +4 -2
- data/spec/kontena/cli/app/deploy_command_spec.rb +24 -7
- data/spec/kontena/cli/app/scale_spec.rb +64 -0
- data/spec/kontena/cli/services/services_helper_spec.rb +0 -7
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70b337e81cf3345b89451a5c86ac5fdd5de1389d
|
4
|
+
data.tar.gz: a18d8b80661384607d290267e5729a473c816a07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9cc3f93437193fee63ae85aefbd44270044ebb70825a0eb1c7ca0c29c92f62589264b5f46ada6855f2b1116b508798a5b835964d02f481d9096ed2738674934
|
7
|
+
data.tar.gz: c151d8c9756635dcd2ed09e02365441ef78ef96b175c43b7cd8002bdcb16c38f5197a0e40c6fd7f33b5ca934ca84e7a44407e23b8400cba4b65419d95996efec
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.10.0
|
data/bin/kontena
CHANGED
@@ -66,8 +66,9 @@ begin
|
|
66
66
|
MainCommand.run
|
67
67
|
rescue Excon::Errors::SocketError => exc
|
68
68
|
if exc.message.include?('Unable to verify certificate')
|
69
|
-
puts "The server uses a certificate signed by an unknown authority.".colorize(:red)
|
70
|
-
puts "
|
69
|
+
$stderr.puts "The server uses a certificate signed by an unknown authority.".colorize(:red)
|
70
|
+
$stderr.puts "You can trust this server by copying server CA pem file to: #{"~/.kontena/certs/<hostname>.pem".colorize(:light_black)}"
|
71
|
+
$stderr.puts "Protip: you can bypass the certificate check by setting #{'SSL_IGNORE_ERRORS=true'.colorize(:yellow)} env variable, but any data you send to the server could be intercepted by others."
|
71
72
|
exit(1)
|
72
73
|
else
|
73
74
|
abort(exc.message)
|
@@ -6,6 +6,8 @@ require_relative 'apps/stop_command'
|
|
6
6
|
require_relative 'apps/remove_command'
|
7
7
|
require_relative 'apps/list_command'
|
8
8
|
require_relative 'apps/logs_command'
|
9
|
+
require_relative 'apps/monitor_command'
|
10
|
+
require_relative 'apps/show_command'
|
9
11
|
|
10
12
|
class Kontena::Cli::AppCommand < Clamp::Command
|
11
13
|
|
@@ -14,9 +16,11 @@ class Kontena::Cli::AppCommand < Clamp::Command
|
|
14
16
|
subcommand "deploy", "Deploy Kontena services", Kontena::Cli::Apps::DeployCommand
|
15
17
|
subcommand "start", "Start services", Kontena::Cli::Apps::StartCommand
|
16
18
|
subcommand "stop", "Stop services", Kontena::Cli::Apps::StopCommand
|
17
|
-
subcommand
|
19
|
+
subcommand "show", "Show service details", Kontena::Cli::Apps::ShowCommand
|
18
20
|
subcommand ["ps", "list"], "List services", Kontena::Cli::Apps::ListCommand
|
19
21
|
subcommand ["logs"], "Show service logs", Kontena::Cli::Apps::LogsCommand
|
22
|
+
subcommand "monitor", "Monitor services", Kontena::Cli::Apps::MonitorCommand
|
23
|
+
subcommand ["remove","rm"], "Remove services", Kontena::Cli::Apps::RemoveCommand
|
20
24
|
def execute
|
21
25
|
end
|
22
|
-
end
|
26
|
+
end
|
@@ -38,13 +38,10 @@ module Kontena::Cli::Apps
|
|
38
38
|
|
39
39
|
def deploy_services(queue)
|
40
40
|
queue.each do |service|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
data[:wait_for_port] = service['deploy']['wait_for_port'] if service['deploy']['wait_for_port']
|
46
|
-
end
|
47
|
-
deploy_service(token, service['id'].split('/').last, data)
|
41
|
+
name = service['id'].split('/').last
|
42
|
+
short_name = name.sub("#{service_prefix}-", "")
|
43
|
+
puts "deploying #{short_name.colorize(:cyan)}"
|
44
|
+
deploy_service(token, name, {})
|
48
45
|
end
|
49
46
|
end
|
50
47
|
|
@@ -57,7 +54,6 @@ module Kontena::Cli::Apps
|
|
57
54
|
parse_links(options['links']).each_with_index do |linked_service, index|
|
58
55
|
# change prefixed service name also to links options
|
59
56
|
options['links'][index] = "#{prefixed_name(linked_service[:name])}:#{linked_service[:alias]}"
|
60
|
-
|
61
57
|
create_or_update_service(linked_service[:name], services[linked_service[:name]]) unless in_deploy_queue?(linked_service[:name])
|
62
58
|
end
|
63
59
|
end
|
@@ -71,9 +67,6 @@ module Kontena::Cli::Apps
|
|
71
67
|
service = create(name, options)
|
72
68
|
end
|
73
69
|
|
74
|
-
# add deploy options to service
|
75
|
-
service['deploy'] = options['deploy']
|
76
|
-
|
77
70
|
deploy_queue.push service
|
78
71
|
end
|
79
72
|
|
@@ -82,17 +75,17 @@ module Kontena::Cli::Apps
|
|
82
75
|
end
|
83
76
|
|
84
77
|
def create(name, options)
|
85
|
-
name = prefixed_name(name)
|
86
78
|
puts "creating #{name.colorize(:cyan)}"
|
79
|
+
name = prefixed_name(name)
|
87
80
|
data = {name: name}
|
88
81
|
data.merge!(parse_data(options))
|
89
82
|
create_service(token, current_grid, data)
|
90
83
|
end
|
91
84
|
|
92
85
|
def update(id, options)
|
86
|
+
puts "updating #{id.colorize(:cyan)}"
|
93
87
|
id = prefixed_name(id)
|
94
88
|
data = parse_data(options)
|
95
|
-
puts "updating #{id.colorize(:cyan)}"
|
96
89
|
update_service(token, id, data)
|
97
90
|
end
|
98
91
|
|
@@ -150,6 +143,17 @@ module Kontena::Cli::Apps
|
|
150
143
|
data[:log_driver] = options['log_driver'] if options['log_driver']
|
151
144
|
data[:log_opts] = options['log_opt'] if options['log_opt'] && !options['log_opt'].empty?
|
152
145
|
|
146
|
+
deploy_opts = options['deploy'] || {}
|
147
|
+
data[:strategy] = deploy_opts['strategy'] if deploy_opts['strategy']
|
148
|
+
deploy = {}
|
149
|
+
deploy[:wait_for_port] = deploy_opts['wait_for_port'] if deploy_opts.has_key?('wait_for_port')
|
150
|
+
deploy[:min_health] = deploy_opts['min_health'] if deploy_opts.has_key?('min_health')
|
151
|
+
unless deploy.empty?
|
152
|
+
data[:deploy_opts] = deploy
|
153
|
+
end
|
154
|
+
|
155
|
+
data[:hooks] = options['hooks'] || {}
|
156
|
+
|
153
157
|
data
|
154
158
|
end
|
155
159
|
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'yaml'
|
2
1
|
require_relative 'common'
|
3
2
|
|
4
3
|
module Kontena::Cli::Apps
|
@@ -27,16 +26,25 @@ module Kontena::Cli::Apps
|
|
27
26
|
end
|
28
27
|
|
29
28
|
def show_services(services)
|
30
|
-
|
29
|
+
titles = ['NAME', 'IMAGE', 'INSTANCES', 'STATEFUL', 'STATE', 'PORTS']
|
30
|
+
puts "%-30.30s %-50.50s %-15s %-10.10s %-15.20s %-50s" % titles
|
31
31
|
|
32
32
|
services.each do |service_name, opts|
|
33
33
|
service = get_service(token, prefixed_name(service_name)) rescue false
|
34
34
|
if service
|
35
|
+
name = service['name'].sub("#{@service_prefix}-", '')
|
35
36
|
state = service['stateful'] ? 'yes' : 'no'
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
ports = service['ports'].map{|p|
|
38
|
+
"#{p['ip']}:#{p['node_port']}->#{p['container_port']}/#{p['protocol']}"
|
39
|
+
}.join(", ")
|
40
|
+
running = service['instances']['running']
|
41
|
+
desired = service['container_count']
|
42
|
+
instances = "#{running} / #{desired}"
|
43
|
+
vars = [name, service['image'], instances, state, service['state'], ports]
|
44
|
+
else
|
45
|
+
vars = [service_name, '-', '-', '-', '-', '-']
|
39
46
|
end
|
47
|
+
puts "%-30.30s %-50.50s %-15.10s %-10.10s %-15.20s %-50s" % vars
|
40
48
|
end
|
41
49
|
end
|
42
50
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'yaml'
|
2
1
|
require_relative 'common'
|
3
2
|
|
4
3
|
module Kontena::Cli::Apps
|
@@ -8,8 +7,9 @@ module Kontena::Cli::Apps
|
|
8
7
|
|
9
8
|
option ['-f', '--file'], 'FILE', 'Specify an alternate Kontena compose file', attribute_name: :filename, default: 'kontena.yml'
|
10
9
|
option ['-p', '--project-name'], 'NAME', 'Specify an alternate project name (default: directory name)'
|
11
|
-
|
12
|
-
|
10
|
+
option ["-s", "--search"], "SEARCH", "Search from logs"
|
11
|
+
option ["-t", "--follow"], :flag, "Follow (tail) logs", default: false
|
12
|
+
parameter "[SERVICE] ...", "Show only specified service logs"
|
13
13
|
|
14
14
|
attr_reader :services, :service_prefix
|
15
15
|
|
@@ -27,16 +27,25 @@ module Kontena::Cli::Apps
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def show_logs(services)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
30
|
+
last_id = nil
|
31
|
+
loop do
|
32
|
+
query_params = []
|
33
|
+
query_params << "from=#{last_id}" unless last_id.nil?
|
34
|
+
query_params << "search=#{search}" if search
|
35
|
+
logs = []
|
36
|
+
services.each do |service_name, opts|
|
37
|
+
service = get_service(token, prefixed_name(service_name)) rescue false
|
38
|
+
result = client(token).get("services/#{service['id']}/container_logs?#{query_params.join('&')}") if service
|
39
|
+
logs = logs + result['logs']
|
40
|
+
end
|
41
|
+
logs.sort!{|x,y| DateTime.parse(x['created_at']) <=> DateTime.parse(y['created_at'])}
|
42
|
+
logs.each do |log|
|
43
|
+
color = color_for_container(log['name'])
|
44
|
+
puts "#{log['name'].colorize(color)} | #{log['data']}"
|
45
|
+
last_id = log['id']
|
46
|
+
end
|
47
|
+
break unless follow?
|
48
|
+
sleep(2)
|
40
49
|
end
|
41
50
|
end
|
42
51
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative 'common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Apps
|
4
|
+
class MonitorCommand < Clamp::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Common
|
7
|
+
|
8
|
+
option ['-f', '--file'], 'FILE', 'Specify an alternate Kontena compose file', attribute_name: :filename, default: 'kontena.yml'
|
9
|
+
option ['-p', '--project-name'], 'NAME', 'Specify an alternate project name (default: directory name)'
|
10
|
+
|
11
|
+
parameter "[SERVICE] ...", "Services to start"
|
12
|
+
|
13
|
+
attr_reader :services, :service_prefix
|
14
|
+
|
15
|
+
def execute
|
16
|
+
require_config_file(filename)
|
17
|
+
|
18
|
+
@service_prefix = project_name || current_dir
|
19
|
+
@services = load_services(filename, service_list, service_prefix)
|
20
|
+
if services.size > 0
|
21
|
+
show_monitor(services)
|
22
|
+
elsif !service_list.empty?
|
23
|
+
puts "No such service: #{service_list.join(', ')}".colorize(:red)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def show_monitor(services)
|
28
|
+
require_api_url
|
29
|
+
token = require_token
|
30
|
+
loop do
|
31
|
+
nodes = {}
|
32
|
+
services.each do |name, data|
|
33
|
+
service = prefixed_name(name)
|
34
|
+
result = client(token).get("services/#{current_grid}/#{service}/containers") rescue nil
|
35
|
+
if result
|
36
|
+
services[name]['instances'] = result['containers'].size
|
37
|
+
result['containers'].each do |container|
|
38
|
+
container['service'] = name
|
39
|
+
nodes[container['node']['name']] ||= []
|
40
|
+
nodes[container['node']['name']] << container
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
clear_terminal
|
45
|
+
puts "services:"
|
46
|
+
services.each do |name, data|
|
47
|
+
color = color_for_service(name)
|
48
|
+
puts " #{"■".colorize(color)} #{name} (#{data['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
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'yaml'
|
2
1
|
require_relative 'common'
|
3
2
|
|
4
3
|
module Kontena::Cli::Apps
|
@@ -19,7 +18,6 @@ module Kontena::Cli::Apps
|
|
19
18
|
require_config_file(filename)
|
20
19
|
|
21
20
|
@service_prefix = project_name || current_dir
|
22
|
-
#Dir.chdir(File.dirname(filename))
|
23
21
|
@services = load_services(filename, service_list, service_prefix)
|
24
22
|
if services.size > 0
|
25
23
|
remove_services(services)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Apps
|
4
|
+
class ScaleCommand < Clamp::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Common
|
7
|
+
|
8
|
+
option ['-f', '--file'], 'FILE', 'Specify an alternate Kontena compose file', attribute_name: :filename, default: 'kontena.yml'
|
9
|
+
option ['-p', '--project-name'], 'NAME', 'Specify an alternate project name (default: directory name)'
|
10
|
+
|
11
|
+
parameter "SERVICE", "Service to show"
|
12
|
+
parameter "INSTANCES", "Scales service to given number of instances"
|
13
|
+
|
14
|
+
attr_reader :services, :service_prefix
|
15
|
+
|
16
|
+
def execute
|
17
|
+
require_config_file(filename)
|
18
|
+
@service_prefix = project_name || current_dir
|
19
|
+
yml_service = load_services(filename, [service], service_prefix)
|
20
|
+
if yml_service[service]
|
21
|
+
options = yml_service[service]
|
22
|
+
abort("Service has already instances defined in #{filename}. Please update #{filename} and deploy service instead") if options['instances']
|
23
|
+
@service_prefix = project_name || current_dir
|
24
|
+
scale_service(require_token, prefixed_name(service), instances)
|
25
|
+
else
|
26
|
+
abort("Service not found")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'common'
|
2
|
+
|
3
|
+
module Kontena::Cli::Apps
|
4
|
+
class ShowCommand < Clamp::Command
|
5
|
+
include Kontena::Cli::Common
|
6
|
+
include Common
|
7
|
+
|
8
|
+
option ['-f', '--file'], 'FILE', 'Specify an alternate Kontena compose file', attribute_name: :filename, default: 'kontena.yml'
|
9
|
+
option ['-p', '--project-name'], 'NAME', 'Specify an alternate project name (default: directory name)'
|
10
|
+
|
11
|
+
parameter "SERVICE", "Service to show"
|
12
|
+
|
13
|
+
attr_reader :services, :service_prefix
|
14
|
+
|
15
|
+
def execute
|
16
|
+
require_config_file(filename)
|
17
|
+
|
18
|
+
@service_prefix = project_name || current_dir
|
19
|
+
show_service(require_token, prefixed_name(service))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/kontena/cli/common.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'colorize'
|
2
|
+
require 'uri'
|
2
3
|
|
3
4
|
module Kontena
|
4
5
|
module Cli
|
@@ -52,9 +53,20 @@ module Kontena
|
|
52
53
|
unless url
|
53
54
|
raise ArgumentError.new("It seem's that you are not logged into Kontena master, please login with: kontena login")
|
54
55
|
end
|
56
|
+
ensure_custom_ssl_ca(url)
|
55
57
|
url
|
56
58
|
end
|
57
59
|
|
60
|
+
def ensure_custom_ssl_ca(url)
|
61
|
+
return if Excon.defaults[:ssl_ca_file]
|
62
|
+
|
63
|
+
uri = URI::parse(url)
|
64
|
+
cert_file = File.join(Dir.home, "/.kontena/certs/#{uri.host}.pem")
|
65
|
+
if File.exist?(cert_file)
|
66
|
+
Excon.defaults[:ssl_ca_file] = cert_file
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
58
70
|
def current_grid=(grid)
|
59
71
|
settings['server']['grid'] = grid['id']
|
60
72
|
save_settings
|
@@ -8,9 +8,14 @@ module Kontena::Cli::Containers
|
|
8
8
|
require_api_url
|
9
9
|
token = require_token
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
match = container_id.match(/(.+)-(\d+)/)
|
12
|
+
if match
|
13
|
+
service_name = match[1]
|
14
|
+
result = client(token).get("containers/#{current_grid}/#{service_name}/#{container_id}/inspect")
|
15
|
+
puts JSON.pretty_generate(result)
|
16
|
+
else
|
17
|
+
abort("Cannot resolve container service")
|
18
|
+
end
|
14
19
|
end
|
15
20
|
end
|
16
21
|
end
|