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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/kontena +3 -2
  4. data/lib/kontena/cli/app_command.rb +6 -2
  5. data/lib/kontena/cli/apps/build_command.rb +0 -1
  6. data/lib/kontena/cli/apps/common.rb +1 -0
  7. data/lib/kontena/cli/apps/deploy_command.rb +17 -13
  8. data/lib/kontena/cli/apps/init_command.rb +1 -2
  9. data/lib/kontena/cli/apps/list_command.rb +13 -5
  10. data/lib/kontena/cli/apps/logs_command.rb +22 -13
  11. data/lib/kontena/cli/apps/monitor_command.rb +91 -0
  12. data/lib/kontena/cli/apps/remove_command.rb +0 -2
  13. data/lib/kontena/cli/apps/scale_command.rb +32 -0
  14. data/lib/kontena/cli/apps/show_command.rb +22 -0
  15. data/lib/kontena/cli/apps/start_command.rb +0 -1
  16. data/lib/kontena/cli/apps/stop_command.rb +0 -1
  17. data/lib/kontena/cli/common.rb +12 -0
  18. data/lib/kontena/cli/containers/inspect_command.rb +8 -3
  19. data/lib/kontena/cli/etcd/common.rb +8 -0
  20. data/lib/kontena/cli/etcd/get_command.rb +4 -0
  21. data/lib/kontena/cli/etcd/list_command.rb +4 -0
  22. data/lib/kontena/cli/etcd/mkdir_command.rb +5 -0
  23. data/lib/kontena/cli/etcd/remove_command.rb +5 -0
  24. data/lib/kontena/cli/etcd/set_command.rb +5 -0
  25. data/lib/kontena/cli/grid_command.rb +2 -0
  26. data/lib/kontena/cli/grids/env_command.rb +22 -0
  27. data/lib/kontena/cli/grids/logs_command.rb +12 -1
  28. data/lib/kontena/cli/node_command.rb +2 -0
  29. data/lib/kontena/cli/nodes/ssh_command.rb +30 -0
  30. data/lib/kontena/cli/service_command.rb +4 -0
  31. data/lib/kontena/cli/services/create_command.rb +9 -0
  32. data/lib/kontena/cli/services/deploy_command.rb +1 -7
  33. data/lib/kontena/cli/services/envs_command.rb +19 -0
  34. data/lib/kontena/cli/services/list_command.rb +15 -3
  35. data/lib/kontena/cli/services/monitor_command.rb +57 -0
  36. data/lib/kontena/cli/services/scale_command.rb +2 -6
  37. data/lib/kontena/cli/services/services_helper.rb +94 -43
  38. data/lib/kontena/cli/services/update_command.rb +12 -1
  39. data/lib/kontena/machine/aws/cloudinit_master.yml +2 -2
  40. data/lib/kontena/machine/azure/cloudinit_master.yml +2 -2
  41. data/lib/kontena/machine/digital_ocean/cloudinit_master.yml +2 -2
  42. data/lib/kontena/scripts/completer +4 -2
  43. data/spec/kontena/cli/app/deploy_command_spec.rb +24 -7
  44. data/spec/kontena/cli/app/scale_spec.rb +64 -0
  45. data/spec/kontena/cli/services/services_helper_spec.rb +0 -7
  46. metadata +12 -2
@@ -0,0 +1,8 @@
1
+ module Kontena::Cli::Etcd
2
+ module Common
3
+
4
+ def validate_key
5
+ abort("Invalid key, did you mean /#{key} ?") unless key[0] == '/'
6
+ end
7
+ end
8
+ end
@@ -1,13 +1,17 @@
1
+ require_relative 'common'
1
2
 
2
3
  module Kontena::Cli::Etcd
3
4
  class GetCommand < Clamp::Command
4
5
  include Kontena::Cli::Common
6
+ include Common
5
7
 
6
8
  parameter "KEY", "Etcd key"
7
9
 
8
10
  def execute
9
11
  require_api_url
10
12
  token = require_token
13
+ validate_key
14
+
11
15
  response = client(token).get("etcd/#{current_grid}/#{key}")
12
16
  if response['value']
13
17
  puts response['value']
@@ -1,7 +1,9 @@
1
+ require_relative 'common'
1
2
 
2
3
  module Kontena::Cli::Etcd
3
4
  class ListCommand < Clamp::Command
4
5
  include Kontena::Cli::Common
6
+ include Common
5
7
 
6
8
  parameter "KEY", "Etcd key"
7
9
 
@@ -10,6 +12,8 @@ module Kontena::Cli::Etcd
10
12
  def execute
11
13
  require_api_url
12
14
  token = require_token
15
+ validate_key
16
+
13
17
  opts = []
14
18
  opts << 'recursive=true' if recursive?
15
19
  response = client(token).get("etcd/#{current_grid}/#{key}?#{opts.join('&')}")
@@ -1,12 +1,17 @@
1
+ require_relative 'common'
2
+
1
3
  module Kontena::Cli::Etcd
2
4
  class MkdirCommand < Clamp::Command
3
5
  include Kontena::Cli::Common
6
+ include Common
4
7
 
5
8
  parameter "KEY", "Etcd key"
6
9
 
7
10
  def execute
8
11
  require_api_url
9
12
  token = require_token
13
+ validate_key
14
+
10
15
  data = {}
11
16
  response = client(token).post("etcd/#{current_grid}/#{key}", data)
12
17
  if response['error']
@@ -1,6 +1,9 @@
1
+ require_relative 'common'
2
+
1
3
  module Kontena::Cli::Etcd
2
4
  class RemoveCommand < Clamp::Command
3
5
  include Kontena::Cli::Common
6
+ include Common
4
7
 
5
8
  parameter "KEY", "Etcd key"
6
9
 
@@ -9,6 +12,8 @@ module Kontena::Cli::Etcd
9
12
  def execute
10
13
  require_api_url
11
14
  token = require_token
15
+ validate_key
16
+
12
17
  data = {}
13
18
  data[:recursive] = true if recursive?
14
19
  response = client(token).delete("etcd/#{current_grid}/#{key}", data)
@@ -1,6 +1,9 @@
1
+ require_relative 'common'
2
+
1
3
  module Kontena::Cli::Etcd
2
4
  class SetCommand < Clamp::Command
3
5
  include Kontena::Cli::Common
6
+ include Common
4
7
 
5
8
  parameter "KEY", "Etcd key"
6
9
  parameter "VALUE", "Etcd value"
@@ -8,6 +11,8 @@ module Kontena::Cli::Etcd
8
11
  def execute
9
12
  require_api_url
10
13
  token = require_token
14
+ validate_key
15
+
11
16
  data = {value: value}
12
17
  response = client(token).post("etcd/#{current_grid}/#{key}", data)
13
18
  if response['error']
@@ -5,6 +5,7 @@ require_relative 'grids/show_command'
5
5
  require_relative 'grids/logs_command'
6
6
  require_relative 'grids/remove_command'
7
7
  require_relative 'grids/current_command'
8
+ require_relative 'grids/env_command'
8
9
  require_relative 'grids/audit_log_command'
9
10
  require_relative 'grids/list_users_command'
10
11
  require_relative 'grids/add_user_command'
@@ -19,6 +20,7 @@ class Kontena::Cli::GridCommand < Clamp::Command
19
20
  subcommand "logs", "Show logs from grid containers", Kontena::Cli::Grids::LogsCommand
20
21
  subcommand "remove", "Remove a grid", Kontena::Cli::Grids::RemoveCommand
21
22
  subcommand "current", "Show current grid details", Kontena::Cli::Grids::CurrentCommand
23
+ subcommand "env", "Show the current grid environment details", Kontena::Cli::Grids::EnvCommand
22
24
  subcommand "audit-log", "Show audit log of the current grid", Kontena::Cli::Grids::AuditLogCommand
23
25
  subcommand "list-users", "List current grid users", Kontena::Cli::Grids::ListUsersCommand
24
26
  subcommand "add-user", "Add user to the current grid", Kontena::Cli::Grids::AddUserCommand
@@ -0,0 +1,22 @@
1
+ require_relative 'common'
2
+
3
+ module Kontena::Cli::Grids
4
+ class EnvCommand < Clamp::Command
5
+ include Kontena::Cli::Common
6
+ include Common
7
+
8
+ option ["-e", "--export"], :flag, "Add export", default: false
9
+
10
+ def execute
11
+ require_api_url
12
+ if current_grid.nil?
13
+ abort 'No grid selected. To select grid, please run: kontena grid use <grid name>'
14
+ else
15
+ grid = client(require_token).get("grids/#{current_grid}")
16
+ prefix = export? ? 'export ' : ''
17
+ puts "#{prefix}KONTENA_URI=#{settings['server']['url'].sub('http', 'ws')}"
18
+ puts "#{prefix}KONTENA_TOKEN=#{grid['token']}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -22,6 +22,7 @@ module Kontena::Cli::Grids
22
22
 
23
23
 
24
24
  if follow?
25
+ @buffer = ''
25
26
  query_params[:follow] = 1
26
27
  stream_logs(token, query_params)
27
28
  else
@@ -39,7 +40,17 @@ module Kontena::Cli::Grids
39
40
 
40
41
  def stream_logs(token, query_params)
41
42
  streamer = lambda do |chunk, remaining_bytes, total_bytes|
42
- log = JSON.parse(chunk)
43
+ begin
44
+ unless @buffer.empty?
45
+ chunk = @buffer + chunk
46
+ end
47
+ unless chunk.empty?
48
+ log = JSON.parse(chunk)
49
+ end
50
+ @buffer = ''
51
+ rescue => exc
52
+ @buffer << chunk
53
+ end
43
54
  if log
44
55
  color = color_for_container(log['name'])
45
56
  puts "#{log['name'].colorize(color)} | #{log['data']}"
@@ -2,6 +2,7 @@ require_relative 'nodes/list_command'
2
2
  require_relative 'nodes/remove_command'
3
3
  require_relative 'nodes/show_command'
4
4
  require_relative 'nodes/update_command'
5
+ require_relative 'nodes/ssh_command'
5
6
 
6
7
  require_relative 'nodes/vagrant_command'
7
8
  require_relative 'nodes/digital_ocean_command'
@@ -12,6 +13,7 @@ class Kontena::Cli::NodeCommand < Clamp::Command
12
13
 
13
14
  subcommand "list", "List grid nodes", Kontena::Cli::Nodes::ListCommand
14
15
  subcommand "show", "Show node", Kontena::Cli::Nodes::ShowCommand
16
+ subcommand "ssh", "Ssh into node", Kontena::Cli::Nodes::SshCommand
15
17
  subcommand "update", "Update node", Kontena::Cli::Nodes::UpdateCommand
16
18
  subcommand "remove", "Remove node", Kontena::Cli::Nodes::RemoveCommand
17
19
 
@@ -0,0 +1,30 @@
1
+ module Kontena::Cli::Nodes
2
+ class SshCommand < Clamp::Command
3
+ include Kontena::Cli::Common
4
+
5
+ parameter "NODE_ID", "Node id"
6
+ option ["-i", "--identity-file"], "IDENTITY_FILE", "Path to ssh private key"
7
+ option ["-u", "--user"], "USER", "Login as a user", default: "core"
8
+ option "--private-ip", :flag, "Connect to node's private IP address"
9
+ option "--internal-ip", :flag, "Connect to node's internal IP address (requires VPN connection)"
10
+
11
+ def execute
12
+ require_api_url
13
+ require_current_grid
14
+ token = require_token
15
+
16
+ node = client(token).get("grids/#{current_grid}/nodes/#{node_id}")
17
+ cmd = ['ssh']
18
+ cmd << "-i #{identity_file}" if identity_file
19
+ if internal_ip?
20
+ ip = "10.81.0.#{node['node_number']}"
21
+ elsif private_ip?
22
+ ip = node['private_ip']
23
+ else
24
+ ip = node['public_ip']
25
+ end
26
+ cmd << "#{user}@#{ip}"
27
+ exec(cmd.join(" "))
28
+ end
29
+ end
30
+ end
@@ -11,8 +11,10 @@ require_relative 'services/delete_command'
11
11
  require_relative 'services/containers_command'
12
12
  require_relative 'services/logs_command'
13
13
  require_relative 'services/stats_command'
14
+ require_relative 'services/envs_command'
14
15
  require_relative 'services/add_env_command'
15
16
  require_relative 'services/remove_env_command'
17
+ require_relative 'services/monitor_command'
16
18
 
17
19
  class Kontena::Cli::ServiceCommand < Clamp::Command
18
20
 
@@ -29,8 +31,10 @@ class Kontena::Cli::ServiceCommand < Clamp::Command
29
31
  subcommand "containers", "List service containers", Kontena::Cli::Services::ContainersCommand
30
32
  subcommand "logs", "Show service logs", Kontena::Cli::Services::LogsCommand
31
33
  subcommand "stats", "Show service statistics", Kontena::Cli::Services::StatsCommand
34
+ subcommand "envs", "Show environment variables", Kontena::Cli::Services::EnvsCommand
32
35
  subcommand "add-env", "Add environment variable", Kontena::Cli::Services::AddEnvCommand
33
36
  subcommand "remove-env", "Remove environment variable", Kontena::Cli::Services::RemoveEnvCommand
37
+ subcommand "monitor", "Monitor", Kontena::Cli::Services::MonitorCommand
34
38
 
35
39
  def execute
36
40
  end
@@ -27,6 +27,10 @@ module Kontena::Cli::Services
27
27
  option "--net", "NET", "Network mode"
28
28
  option "--log-driver", "LOG_DRIVER", "Set logging driver"
29
29
  option "--log-opt", "LOG_OPT", "Add logging options", multivalued: true
30
+ option "--deploy-strategy", "STRATEGY", "Deploy strategy to use (ha, random)"
31
+ option "--deploy-wait-for-port", "PORT", "Wait for port to respond when deploying"
32
+ option "--deploy-min-health", "FLOAT", "The minimum percentage (0.0 - 1.0) of healthy instances that do not sacrifice overall service availability while deploying"
33
+ option "--pid", "PID", "Pid namespace to use"
30
34
 
31
35
  def execute
32
36
  require_api_url
@@ -64,6 +68,11 @@ module Kontena::Cli::Services
64
68
  data[:net] = net if net
65
69
  data[:log_driver] = log_driver if log_driver
66
70
  data[:log_opts] = parse_log_opts(log_opt_list)
71
+ data[:strategy] = deploy_strategy if deploy_strategy
72
+ data[:deploy_opts] = {}
73
+ data[:deploy_opts][:min_health] = deploy_min_health.to_f if deploy_min_health
74
+ data[:deploy_opts][:wait_for_port] = deploy_wait_for_port.to_i if deploy_wait_for_port
75
+ data[:pid] = pid if pid
67
76
  data
68
77
  end
69
78
  end
@@ -6,18 +6,12 @@ module Kontena::Cli::Services
6
6
  include ServicesHelper
7
7
 
8
8
  parameter "NAME", "Service name"
9
- option '--strategy', 'STRATEGY', 'Define deploy strategy (ha / random)'
10
- option '--wait-for-port', 'WAIT_FOR_PORT', 'Wait for given container port to open before deploying next container'
11
9
 
12
10
  def execute
13
11
  require_api_url
14
12
  token = require_token
15
13
  service_id = name
16
- data = {}
17
- data[:strategy] = strategy if strategy
18
- data[:wait_for_port] = wait_for_port if wait_for_port
19
- deploy_service(token, service_id, data)
20
- show_service(token, service_id)
14
+ deploy_service(token, service_id, {})
21
15
  end
22
16
  end
23
17
  end
@@ -0,0 +1,19 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Kontena::Cli::Services
4
+ class EnvsCommand < Clamp::Command
5
+ include Kontena::Cli::Common
6
+ include ServicesHelper
7
+
8
+ parameter "NAME", "Service name"
9
+
10
+ def execute
11
+ require_api_url
12
+ token = require_token
13
+ service = client(token).get("services/#{parse_service_id(name)}")
14
+ service["env"].each do |env|
15
+ puts env
16
+ end
17
+ end
18
+ end
19
+ end
@@ -10,10 +10,22 @@ module Kontena::Cli::Services
10
10
  token = require_token
11
11
 
12
12
  grids = client(token).get("grids/#{current_grid}/services")
13
- puts "%-30.30s %-40.40s %-10s %-8s" % ['NAME', 'IMAGE', 'INSTANCES', 'STATEFUL']
13
+ titles = ['NAME', 'IMAGE', 'INSTANCES', 'STATEFUL', 'STATE']
14
+ puts "%-30.30s %-50.50s %-10s %-8s %-10s" % titles
14
15
  grids['services'].each do |service|
15
- state = service['stateful'] ? 'yes' : 'no'
16
- puts "%-30.30s %-40.40s %-10.10s %-8s" % [service['name'], service['image'], service['container_count'], state]
16
+ stateful = service['stateful'] ? 'yes' : 'no'
17
+ image = service['image']
18
+ if image.length > 50
19
+ image = image[0..10] << '...' << image[-35..-1]
20
+ end
21
+ vars = [
22
+ service['name'],
23
+ image,
24
+ service['container_count'],
25
+ stateful,
26
+ service['state']
27
+ ]
28
+ puts "%-30.30s %-50.50s %-10.10s %-8s %-10s" % vars
17
29
  end
18
30
  end
19
31
  end
@@ -0,0 +1,57 @@
1
+ require_relative 'services_helper'
2
+
3
+ module Kontena::Cli::Services
4
+ class MonitorCommand < Clamp::Command
5
+ include Kontena::Cli::Common
6
+ include ServicesHelper
7
+
8
+ parameter "NAME", "Service name"
9
+ option "--interval", "SECONDS", "How often view is refreshed", default: 2
10
+
11
+ def execute
12
+ require_api_url
13
+ token = require_token
14
+
15
+ loop do
16
+ nodes = {}
17
+ service = client(token).get("services/#{current_grid}/#{name}")
18
+ result = client(token).get("services/#{current_grid}/#{name}/containers")
19
+ result['containers'].each do |container|
20
+ nodes[container['node']['name']] ||= []
21
+ nodes[container['node']['name']] << container
22
+ end
23
+ clear_terminal
24
+ puts "service: #{name} (#{result['containers'].size}/#{service['container_count']} instances)"
25
+ puts "strategy: #{service['strategy']}"
26
+ puts "status: #{service['state']}"
27
+ puts "stateful: #{service['stateful'] == true ? 'yes' : 'no' }"
28
+ puts "nodes:"
29
+ node_names = nodes.keys.sort
30
+ node_names.each do |name|
31
+ containers = nodes[name]
32
+ puts " #{name} (#{containers.size} instances)"
33
+ print " "
34
+ containers.each do |container|
35
+ color = container['status']
36
+ if container['status'] == 'running'
37
+ color = :green
38
+ elsif container['status'] == 'killed'
39
+ color = :red
40
+ elsif container['status'] == 'stopped'
41
+ color = :gray
42
+ else
43
+ color = :yellow
44
+ end
45
+ print "■".colorize(color)
46
+ end
47
+ puts ''
48
+ end
49
+ sleep interval.to_f
50
+ end
51
+ end
52
+
53
+ def clear_terminal
54
+ print "\e[H\e[2J"
55
+ end
56
+ end
57
+ end
@@ -7,14 +7,10 @@ module Kontena::Cli::Services
7
7
 
8
8
  parameter "NAME", "Service name"
9
9
  parameter "INSTANCES", "Scales service to given number of instances"
10
- option '--strategy', 'STRATEGY', 'Define deploy strategy (ha / random)'
11
10
 
12
11
  def execute
13
- token = require_token
14
- client(token).put("services/#{parse_service_id(name)}", {container_count: instances})
15
- opts = {}
16
- opts[:strategy] = strategy if strategy
17
- deploy_service(token, name, opts)
12
+ token = require_token
13
+ scale_service(token, name, instances)
18
14
  end
19
15
  end
20
16
  end
@@ -22,6 +22,14 @@ module Kontena
22
22
  client(token).put("services/#{param}", data)
23
23
  end
24
24
 
25
+ # @param [String] token
26
+ # @param [String] service_id
27
+ # @param [Integer] instances
28
+ def scale_service(token, service_id, instances)
29
+ param = parse_service_id(service_id)
30
+ client(token).post("services/#{param}/scale", {instances: instances})
31
+ end
32
+
25
33
  # @param [String] token
26
34
  # @param [String] service_id
27
35
  def get_service(token, service_id)
@@ -36,76 +44,126 @@ module Kontena
36
44
  grid = service['id'].split('/')[0]
37
45
  puts "#{service['id']}:"
38
46
  puts " status: #{service['state'] }"
47
+ puts " image: #{service['image']}"
39
48
  puts " stateful: #{service['stateful'] == true ? 'yes' : 'no' }"
40
49
  puts " scaling: #{service['container_count'] }"
41
- puts " image: #{service['image']}"
50
+ puts " strategy: #{service['strategy']}"
51
+ puts " deploy_opts:"
52
+ puts " wait_for_port: #{service['deploy_opts']['wait_for_port'] || '-'}"
53
+ puts " min_health: #{service['deploy_opts']['min_health']}"
42
54
  puts " dns: #{service['name']}.#{grid}.kontena.local"
43
55
 
44
- puts " affinity: "
45
- service['affinity'].to_a.each do |a|
46
- puts " - #{a}"
56
+ if service['affinity'].to_a.size > 0
57
+ puts " affinity: "
58
+ service['affinity'].to_a.each do |a|
59
+ puts " - #{a}"
60
+ end
47
61
  end
48
62
 
49
- if service['cmd']
50
- puts " cmd: #{service['cmd'].join(' ')}"
51
- else
52
- puts " cmd: "
63
+ unless service['cmd'].to_s.empty?
64
+ if service['cmd']
65
+ puts " cmd: #{service['cmd'].join(' ')}"
66
+ else
67
+ puts " cmd: "
68
+ end
69
+ end
70
+
71
+ if service['hooks'].to_a.size > 0
72
+ puts " hooks: "
73
+ service['hooks'].to_a.each do |hook|
74
+ puts " - name: #{hook['name']}"
75
+ puts " type: #{hook['type']}"
76
+ puts " cmd: #{hook['cmd']}"
77
+ puts " oneshot: #{hook['oneshot']}"
78
+ end
53
79
  end
54
80
 
55
- puts " env: "
56
- service['env'].to_a.each{|e| puts " - #{e}"}
81
+ if service['env'].to_a.size > 0
82
+ puts " env: "
83
+ service['env'].to_a.each do |e|
84
+ if e.length > 50
85
+ puts " - #{e[0..50]}..."
86
+ else
87
+ puts " - #{e}"
88
+ end
89
+ end
90
+ end
57
91
 
58
- puts " ports:"
59
- service['ports'].to_a.each do |p|
60
- puts " - #{p['node_port']}:#{p['container_port']}/#{p['protocol']}"
92
+ unless service['net'].to_s.empty?
93
+ puts " net: #{service['net']}"
61
94
  end
62
95
 
63
- puts " volumes:"
64
- service['volumes'].to_a.each do |v|
65
- puts " - #{v}"
96
+ if service['ports'].to_a.size > 0
97
+ puts " ports:"
98
+ service['ports'].to_a.each do |p|
99
+ puts " - #{p['node_port']}:#{p['container_port']}/#{p['protocol']}"
100
+ end
66
101
  end
67
102
 
68
- puts " volumes_from:"
69
- service['volumes_from'].to_a.each do |v|
70
- puts " - #{v}"
103
+ if service['volumes'].to_a.size > 0
104
+ puts " volumes:"
105
+ service['volumes'].to_a.each do |v|
106
+ puts " - #{v}"
107
+ end
108
+ end
109
+
110
+ if service['volumes_from'].to_a.size > 0
111
+ puts " volumes_from:"
112
+ service['volumes_from'].to_a.each do |v|
113
+ puts " - #{v}"
114
+ end
71
115
  end
72
116
 
73
- puts " links: "
74
- service['links'].to_a.each do |l|
75
- puts " - #{l['alias']}"
117
+ if service['links'].to_a.size > 0
118
+ puts " links: "
119
+ service['links'].to_a.each do |l|
120
+ puts " - #{l['alias']}"
121
+ end
76
122
  end
77
123
 
78
- puts " cap_add:"
79
- service['cap_add'].to_a.each do |c|
80
- puts " - #{c}"
124
+ if service['cap_add'].to_a.size > 0
125
+ puts " cap_add:"
126
+ service['cap_add'].to_a.each do |c|
127
+ puts " - #{c}"
128
+ end
81
129
  end
82
130
 
83
- puts " cap_drop:"
84
- service['cap_drop'].to_a.each do |c|
85
- puts " - #{c}"
131
+ if service['cap_drop'].to_a.size > 0
132
+ puts " cap_drop:"
133
+ service['cap_drop'].to_a.each do |c|
134
+ puts " - #{c}"
135
+ end
86
136
  end
87
137
 
88
- puts " log_driver: #{service['log_driver']}"
138
+ unless service['log_driver'].to_s.empty?
139
+ puts " log_driver: #{service['log_driver']}"
140
+ puts " log_opts:"
141
+ service['log_opts'].each do |opt, value|
142
+ puts " #{opt}: #{value}"
143
+ end
144
+ end
89
145
 
90
- puts " log_opts:"
91
- service['log_opts'].each do |opt, value|
92
- puts " #{opt}: #{value}"
146
+ unless service['pid'].to_s.empty?
147
+ puts " pid: #{service['pid']}"
93
148
  end
94
149
 
95
- puts " containers:"
150
+ puts " instances:"
96
151
  result = client(token).get("services/#{parse_service_id(service_id)}/containers")
97
152
  result['containers'].each do |container|
98
153
  puts " #{container['name']}:"
99
154
  puts " rev: #{container['deploy_rev']}"
100
- puts " node: #{container['node']['name']}"
155
+ puts " node: #{container['node']['name'] rescue 'unknown'}"
101
156
  puts " dns: #{container['name']}.#{grid}.kontena.local"
102
- puts " ip: #{container['overlay_cidr'].split('/')[0]}"
103
- puts " public ip: #{container['node']['public_ip']}"
157
+ puts " ip: #{container['overlay_cidr'].to_s.split('/')[0]}"
158
+ puts " public ip: #{container['node']['public_ip'] rescue 'unknown'}"
104
159
  if container['status'] == 'unknown'
105
160
  puts " status: #{container['status'].colorize(:yellow)}"
106
161
  else
107
162
  puts " status: #{container['status']}"
108
163
  end
164
+ if container['state']['error'] && container['state']['error'] != ''
165
+ puts " reason: #{container['state']['error']}"
166
+ end
109
167
  end
110
168
  end
111
169
 
@@ -115,13 +173,6 @@ module Kontena
115
173
  def deploy_service(token, service_id, data)
116
174
  param = parse_service_id(service_id)
117
175
  client(token).post("services/#{param}/deploy", data)
118
- print 'deploying '
119
- until client(token).get("services/#{param}")['state'] != 'deploying' do
120
- print '.'
121
- sleep 1
122
- end
123
- puts ' done'.colorize(:green)
124
- puts ''
125
176
  end
126
177
 
127
178
  # @param [String] token