kontena-cli 1.3.0.pre1 → 1.3.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/kontena +2 -1
  4. data/lib/kontena/callback.rb +1 -1
  5. data/lib/kontena/callbacks/auth/01_list_and_select_grid_after_master_auth.rb +1 -2
  6. data/lib/kontena/callbacks/master/01_clear_current_master_after_terminate.rb +2 -3
  7. data/lib/kontena/callbacks/master/deploy/01_show_logo_before_deploy.rb +1 -2
  8. data/lib/kontena/callbacks/master/deploy/05_before_deploy_configuration_wizard.rb +2 -2
  9. data/lib/kontena/callbacks/master/deploy/40_install_ssl_certificate_after_deploy.rb +2 -2
  10. data/lib/kontena/callbacks/master/deploy/50_authenticate_after_deploy.rb +9 -9
  11. data/lib/kontena/callbacks/master/deploy/55_create_initial_grid_after_deploy.rb +2 -2
  12. data/lib/kontena/callbacks/master/deploy/56_set_server_provider_after_deploy.rb +1 -2
  13. data/lib/kontena/callbacks/master/deploy/60_configure_auth_provider_after_deploy.rb +1 -2
  14. data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +2 -3
  15. data/lib/kontena/callbacks/master/deploy/90_proptip_after_deploy.rb +2 -2
  16. data/lib/kontena/cli/apps/common.rb +0 -1
  17. data/lib/kontena/cli/apps/init_command.rb +2 -0
  18. data/lib/kontena/cli/apps/kontena_yml_generator.rb +2 -1
  19. data/lib/kontena/cli/apps/list_command.rb +10 -2
  20. data/lib/kontena/cli/apps/yaml/reader.rb +2 -1
  21. data/lib/kontena/cli/apps/yaml/service_extender.rb +0 -1
  22. data/lib/kontena/cli/cloud/login_command.rb +51 -7
  23. data/lib/kontena/cli/cloud/master/list_command.rb +14 -11
  24. data/lib/kontena/cli/common.rb +36 -83
  25. data/lib/kontena/cli/config.rb +46 -29
  26. data/lib/kontena/cli/containers/list_command.rb +30 -41
  27. data/lib/kontena/cli/etcd/list_command.rb +12 -7
  28. data/lib/kontena/cli/external_registries/list_command.rb +14 -8
  29. data/lib/kontena/cli/grids/list_command.rb +18 -10
  30. data/lib/kontena/cli/grids/trusted_subnets/list_command.rb +7 -5
  31. data/lib/kontena/cli/grids/users/list_command.rb +9 -7
  32. data/lib/kontena/cli/localhost_web_server.rb +3 -3
  33. data/lib/kontena/cli/log_formatters/compact.rb +65 -0
  34. data/lib/kontena/cli/log_formatters/strip_color.rb +13 -0
  35. data/lib/kontena/cli/master/config/import_command.rb +2 -1
  36. data/lib/kontena/cli/master/config/set_command.rb +1 -1
  37. data/lib/kontena/cli/master/list_command.rb +16 -10
  38. data/lib/kontena/cli/master/token/list_command.rb +23 -12
  39. data/lib/kontena/cli/master/user/invite_command.rb +1 -1
  40. data/lib/kontena/cli/master/user/list_command.rb +17 -6
  41. data/lib/kontena/cli/nodes/labels/list_command.rb +3 -0
  42. data/lib/kontena/cli/nodes/list_command.rb +58 -37
  43. data/lib/kontena/cli/nodes/show_command.rb +1 -1
  44. data/lib/kontena/cli/plugins/install_command.rb +2 -2
  45. data/lib/kontena/cli/plugins/list_command.rb +19 -5
  46. data/lib/kontena/cli/plugins/uninstall_command.rb +1 -1
  47. data/lib/kontena/cli/services/containers_command.rb +7 -0
  48. data/lib/kontena/cli/services/envs/list_command.rb +6 -4
  49. data/lib/kontena/cli/services/list_command.rb +47 -36
  50. data/lib/kontena/cli/services/services_helper.rb +9 -16
  51. data/lib/kontena/cli/services/stats_command.rb +2 -1
  52. data/lib/kontena/cli/spinner.rb +3 -5
  53. data/lib/kontena/cli/stacks/common.rb +4 -4
  54. data/lib/kontena/cli/stacks/list_command.rb +42 -33
  55. data/lib/kontena/cli/stacks/registry/search_command.rb +6 -0
  56. data/lib/kontena/cli/stacks/registry/show_command.rb +2 -0
  57. data/lib/kontena/cli/stacks/registry_command.rb +1 -2
  58. data/lib/kontena/cli/stacks/validate_command.rb +1 -0
  59. data/lib/kontena/cli/stacks/yaml/reader.rb +3 -2
  60. data/lib/kontena/cli/stacks/yaml/service_extender.rb +0 -1
  61. data/lib/kontena/cli/stacks/yaml/validations.rb +1 -1
  62. data/lib/kontena/cli/table_generator.rb +125 -0
  63. data/lib/kontena/cli/vault/export_command.rb +7 -4
  64. data/lib/kontena/cli/vault/import_command.rb +3 -0
  65. data/lib/kontena/cli/vault/list_command.rb +23 -10
  66. data/lib/kontena/cli/volumes/create_command.rb +8 -4
  67. data/lib/kontena/cli/volumes/list_command.rb +15 -7
  68. data/lib/kontena/client.rb +44 -33
  69. data/lib/kontena/command.rb +7 -4
  70. data/lib/kontena/debug_instrumentor.rb +10 -9
  71. data/lib/kontena/main_command.rb +1 -3
  72. data/lib/kontena/plugin_manager.rb +15 -7
  73. data/lib/kontena/stacks_cache.rb +7 -7
  74. data/lib/kontena/stacks_client.rb +24 -5
  75. data/lib/kontena/util.rb +43 -15
  76. data/lib/kontena_cli.rb +71 -14
  77. data/spec/kontena/cli/cloud/login_command_spec.rb +42 -0
  78. data/spec/kontena/cli/containers/list_command_spec.rb +1 -2
  79. data/spec/kontena/cli/nodes/list_command_spec.rb +153 -126
  80. data/spec/kontena/cli/registry/create_spec.rb +22 -0
  81. data/spec/kontena/cli/services/stats_command_spec.rb +22 -0
  82. data/spec/kontena/cli/table_generator_spec.rb +118 -0
  83. data/spec/kontena/cli/version_command_spec.rb +2 -2
  84. data/spec/kontena/client_spec.rb +4 -3
  85. data/spec/support/client_helpers.rb +3 -3
  86. data/spec/support/output_helpers.rb +54 -8
  87. metadata +11 -2
@@ -1,26 +1,21 @@
1
- require 'tty-prompt'
2
- require 'pastel'
3
- require 'uri'
4
- require 'io/console'
5
-
6
- require 'kontena/cli/config'
7
- require 'kontena/cli/spinner'
1
+ require 'forwardable'
8
2
 
9
3
  module Kontena
10
4
  module Cli
11
5
  module Common
12
-
13
- def logger
14
- return @logger if @logger
15
- @logger = Logger.new(ENV["DEBUG"] ? $stderr : $stdout)
16
- @logger.level = ENV["DEBUG"].nil? ? Logger::INFO : Logger::DEBUG
17
- @logger.progname = 'COMMON'
18
- @logger
19
- end
20
-
21
- def pastel
22
- @pastel ||= Pastel.new(enabled: $stdout.tty?)
23
- end
6
+ extend Forwardable
7
+
8
+ def_delegators :Kontena, :pastel, :prompt, :logger
9
+ def_delegators :prompt, :ask, :yes?
10
+ def_delegators :config,
11
+ :current_grid=, :require_current_grid, :current_master,
12
+ :current_master=, :require_current_master, :require_current_account,
13
+ :current_account
14
+ def_delegator Kontena::Cli::Spinner, :spin, :spinner
15
+ def_delegator Kontena::Cli::Config, :instance, :config
16
+ def_delegator Kontena::Cli::Config, :instance, :settings
17
+ def_delegator :config, :config_filename, :settings_filename
18
+ def_delegator :client, :server_version, :api_url_version
24
19
 
25
20
  # Read from STDIN. If stdin is a console, use prompt to ask.
26
21
  # @param [String] message
@@ -43,6 +38,10 @@ module Kontena
43
38
  self.respond_to?(:verbose?) && self.verbose?
44
39
  end
45
40
 
41
+ def running_quiet?
42
+ self.respond_to?(:quiet?) && self.quiet?
43
+ end
44
+
46
45
  # Puts that puts even when self.silent?
47
46
  def sputs(*msgs)
48
47
  ::Kernel.puts(*msgs)
@@ -87,9 +86,19 @@ module Kontena
87
86
  def vspinner(msg, &block)
88
87
  return vfakespinner(msg) unless block_given?
89
88
 
90
- if running_verbose?
89
+ if running_verbose? && $stdout.tty?
91
90
  spinner(msg, &block)
92
91
  else
92
+ logger.debug { msg }
93
+ yield
94
+ end
95
+ end
96
+
97
+ def spin_if(obj_or_proc, message, &block)
98
+ if (obj_or_proc.respond_to?(:call) && obj_or_proc.call) || obj_or_proc
99
+ spinner(message, &block)
100
+ else
101
+ logger.debug { message }
93
102
  yield
94
103
  end
95
104
  end
@@ -97,7 +106,7 @@ module Kontena
97
106
  # Like vspinner but without actually running any block
98
107
  def vfakespinner(msg, success: true)
99
108
  if !running_verbose?
100
- logger.debug msg
109
+ logger.debug { msg }
101
110
  return
102
111
  end
103
112
  puts " [#{ success ? 'done'.colorize(:green) : 'fail'.colorize(:red)}] #{msg}"
@@ -113,10 +122,7 @@ module Kontena
113
122
  $stderr.puts " [#{error}] #{msg}"
114
123
  exit code
115
124
  end
116
-
117
- def config
118
- Kontena::Cli::Config.instance
119
- end
125
+ module_function :exit_with_error
120
126
 
121
127
  def require_api_url
122
128
  config.require_current_master.url
@@ -148,20 +154,8 @@ module Kontena
148
154
  logger.debug "Refreshing failed: #{ex.class.name} : #{ex.message}"
149
155
  end
150
156
 
151
- def require_current_master
152
- config.require_current_master
153
- end
154
-
155
- def require_current_account
156
- config.require_current_account
157
- end
158
-
159
- def current_account
160
- config.current_account
161
- end
162
-
163
157
  def kontena_account
164
- @kontena_account ||= config.find_account(ENV['KONTENA_ACCOUNT'] || 'kontena')
158
+ @kontena_account ||= config.current_account
165
159
  end
166
160
 
167
161
  def cloud_auth?
@@ -171,10 +165,6 @@ module Kontena
171
165
  true
172
166
  end
173
167
 
174
- def api_url_version
175
- client.server_version
176
- end
177
-
178
168
  def cloud_client
179
169
  @cloud_client ||= Kontena::Client.new(kontena_account.url, kontena_account.token, prefix: '/')
180
170
  end
@@ -184,11 +174,13 @@ module Kontena
184
174
  end
185
175
 
186
176
  def client(token = nil, api_url = nil)
177
+ return @client if @client
178
+
187
179
  if token.kind_of?(String)
188
180
  token = Kontena::Cli::Config::Token.new(access_token: token)
189
181
  end
190
182
 
191
- @client ||= Kontena::Client.new(
183
+ @client = Kontena::Client.new(
192
184
  api_url || require_current_master.url,
193
185
  token || require_current_master.token
194
186
  )
@@ -198,26 +190,10 @@ module Kontena
198
190
  @client = nil
199
191
  end
200
192
 
201
- def settings_filename
202
- config.config_filename
203
- end
204
-
205
- def settings
206
- config
207
- end
208
-
209
193
  def api_url
210
194
  config.require_current_master.url
211
195
  end
212
196
 
213
- def current_grid=(grid)
214
- config.current_grid=(grid)
215
- end
216
-
217
- def require_current_grid
218
- config.require_current_grid
219
- end
220
-
221
197
  def clear_current_grid
222
198
  current_master.delete_field(:grid) if require_current_master.respond_to?(:grid)
223
199
  config.write
@@ -231,31 +207,11 @@ module Kontena
231
207
  config.find_server_index(require_current_master.name)
232
208
  end
233
209
 
234
- def current_master
235
- config.current_master
236
- end
237
-
238
- def current_master=(master_alias)
239
- config.current_master = master_alias
240
- end
241
-
242
210
  def error(message = "Error")
243
211
  prompt.error(message)
244
212
  exit(1)
245
213
  end
246
214
 
247
- def ask(question = "")
248
- prompt.ask(question)
249
- end
250
-
251
- def yes?(question = "")
252
- prompt.yes?(question)
253
- end
254
-
255
- def prompt
256
- ::Kontena.prompt
257
- end
258
-
259
215
  def confirm_command(name, message = nil)
260
216
  if self.respond_to?(:force?) && self.force?
261
217
  return
@@ -289,10 +245,6 @@ module Kontena
289
245
  config.add_server(master_info.merge('name' => server_name))
290
246
  end
291
247
 
292
- def spinner(msg, &block)
293
- Kontena::Cli::Spinner.spin(msg, &block)
294
- end
295
-
296
248
  def any_key_to_continue_with_timeout(timeout=9)
297
249
  return nil if running_silent?
298
250
  return nil unless $stdout.tty?
@@ -352,6 +304,7 @@ module Kontena
352
304
  def display_logo
353
305
  puts File.read(File.expand_path('../../../../LOGO', __FILE__))
354
306
  end
307
+ module_function :display_logo
355
308
  end
356
309
  end
357
310
  end
@@ -1,8 +1,8 @@
1
1
  require 'ostruct'
2
2
  require 'singleton'
3
3
  require 'forwardable'
4
- require 'json'
5
4
  require 'logger'
5
+ autoload :JSON, 'json'
6
6
 
7
7
  module Kontena
8
8
  module Cli
@@ -13,10 +13,23 @@ module Kontena
13
13
  class Config < OpenStruct
14
14
  include Singleton
15
15
 
16
+ module Fields
17
+ def keys
18
+ @table.keys
19
+ end
20
+
21
+ def values_at(*fields)
22
+ (fields.first.is_a?(Array) ? fields.first : fields).map { |field| self[field] }
23
+ end
24
+ end
25
+
26
+ include Fields
27
+
16
28
  attr_accessor :logger
17
29
  attr_accessor :current_server
18
30
  attr_reader :current_account
19
31
 
32
+
20
33
  def self.reset_instance
21
34
  Singleton.send :__init__, self
22
35
  self
@@ -26,20 +39,22 @@ module Kontena
26
39
 
27
40
  def initialize
28
41
  super
29
- @logger = Logger.new(ENV["DEBUG"] ? $stderr : $stdout)
30
- @logger.level = ENV["DEBUG"].nil? ? Logger::INFO : Logger::DEBUG
31
- @logger.progname = 'CONFIG'
42
+ @logger = Kontena.logger
32
43
  load_settings_from_env || load_settings_from_config_file
33
44
 
34
- logger.debug "Configuration loaded with #{servers.count} servers."
35
- logger.debug "Current master: #{current_server || '(not selected)'}"
36
- logger.debug "Current grid: #{current_grid || '(not selected)'}"
45
+ debug { "Configuration loaded with #{servers.count} servers." }
46
+ debug { "Current master: #{current_server || '(not selected)'}" }
47
+ debug { "Current grid: #{current_grid || '(not selected)'}" }
48
+ end
49
+
50
+ def debug(&block)
51
+ Kontena.logger.add(Logger::DEBUG, nil, 'CONFIG', &block)
37
52
  end
38
53
 
39
54
  # Craft a regular looking configuration based on ENV variables
40
55
  def load_settings_from_env
41
56
  return nil unless ENV['KONTENA_URL']
42
- logger.debug 'Loading configuration from ENV'
57
+ debug { 'Loading configuration from ENV' }
43
58
  servers << Server.new(
44
59
  url: ENV['KONTENA_URL'],
45
60
  name: 'default',
@@ -48,11 +63,9 @@ module Kontena
48
63
  parent_type: :master,
49
64
  parent_name: 'default'
50
65
  )
51
- accounts << Account.new(
52
- url: ENV['AUTH_API_URL'] || 'https://auth.kontena.io',
53
- name: 'kontena',
54
- token: Token.new(access_token: ENV['KONTENA_ACCOUNT_TOKEN'], parent_type: :account, parent_name: 'default')
55
- )
66
+ accounts << Account.new(kontena_account_data.merge(
67
+ token: Token.new(access_token: ENV['KONTENA_CLOUD_TOKEN'], parent_type: :account, parent_name: 'default')
68
+ ))
56
69
 
57
70
  self.current_master = 'default'
58
71
  self.current_account = 'kontena'
@@ -84,7 +97,7 @@ module Kontena
84
97
  if servers.find { |s| s['name'] == server.name}
85
98
  server.name = "#{server.name}-2"
86
99
  server.name.succ! until servers.find { |s| s['name'] == server.name }.nil?
87
- logger.debug "Renamed server to #{server.name} because a duplicate was found in config"
100
+ debug { "Renamed server to #{server.name} because a duplicate was found in config" }
88
101
  end
89
102
  servers << server
90
103
  end
@@ -115,22 +128,23 @@ module Kontena
115
128
  accounts.delete_at(master_index) if master_index
116
129
  accounts << Account.new(master_account_data)
117
130
 
118
- self.current_account = settings['current_account'] || 'kontena'
131
+ self.current_account = ENV['KONTENA_CLOUD'] || settings['current_account'] || 'kontena'
119
132
  end
120
133
 
121
134
  def kontena_account_data
122
135
  {
123
136
  name: 'kontena',
124
- url: 'https://cloud-api.kontena.io',
125
- stacks_url: 'https://stacks.kontena.io',
126
- token_endpoint: 'https://cloud-api.kontena.io/oauth2/token',
127
- authorization_endpoint: 'https://cloud.kontena.io/login/oauth/authorize',
128
- userinfo_endpoint: 'https://cloud-api.kontena.io/user',
129
- token_post_content_type: 'application/x-www-form-urlencoded',
130
- code_requires_basic_auth: false,
131
- token_method: 'post',
132
- scope: 'user',
133
- client_id: nil
137
+ url: ENV['KONTENA_CLOUD_URL'] || 'https://cloud-api.kontena.io',
138
+ stacks_url: ENV['KONTENA_STACK_REGISTRY_URL'] || 'https://stacks.kontena.io',
139
+ token_endpoint: ENV['AUTH_TOKEN_ENDPOINT'] || 'https://cloud-api.kontena.io/oauth2/token',
140
+ authorization_endpoint: ENV['AUTH_AUTHORIZE_ENDPOINT'] || 'https://cloud.kontena.io/login/oauth/authorize',
141
+ userinfo_endpoint: ENV['AUTH_USERINFO_ENDPOINT'] || 'https://cloud-api.kontena.io/user',
142
+ token_post_content_type: ENV['AUTH_TOKEN_POST_CONTENT_TYPE'] || 'application/x-www-form-urlencoded',
143
+ code_requires_basic_auth: ENV['AUTH_CODE_REQUIRES_BASIC_AUTH'].to_s == true,
144
+ token_method: ENV['AUTH_TOKEN_METHOD'] || 'post',
145
+ scope: ENV['AUTH_USERINFO_SCOPE'] || 'user',
146
+ client_id: nil,
147
+ stacks_read_authentication: ENV['KONTENA_STACK_REGISTRY_READ_AUTHENTICATION'].to_s == 'true'
134
148
  }
135
149
  end
136
150
 
@@ -157,7 +171,7 @@ module Kontena
157
171
  #
158
172
  # @return [Hash]
159
173
  def default_settings
160
- logger.debug 'Configuration file not found, using default settings.'
174
+ debug { 'Configuration file not found, using default settings.' }
161
175
  {
162
176
  'current_server' => 'default',
163
177
  'servers' => []
@@ -169,7 +183,7 @@ module Kontena
169
183
  # @param [Hash] settings_hash
170
184
  # @return [Hash] migrated_settings_hash
171
185
  def migrate_legacy_settings(settings)
172
- logger.debug "Migrating from legacy style configuration"
186
+ debug { "Migrating from legacy style configuration" }
173
187
  {
174
188
  'current_server' => 'default',
175
189
  'servers' => [
@@ -186,7 +200,7 @@ module Kontena
186
200
  #
187
201
  # @return [Hash] config_data
188
202
  def parse_config_file
189
- logger.debug "Loading configuration from #{config_filename}"
203
+ debug { "Loading configuration from #{config_filename}" }
190
204
  settings = JSON.load(File.read(config_filename))
191
205
  if settings.has_key?('server')
192
206
  settings = migrate_legacy_settings(settings)
@@ -437,7 +451,7 @@ module Kontena
437
451
  # Does nothing if using settings from environment variables.
438
452
  def write
439
453
  return nil if ENV['KONTENA_URL']
440
- logger.debug "Writing configuration to #{config_filename}"
454
+ debug { "Writing configuration to #{config_filename}" }
441
455
  File.write(config_filename, to_json)
442
456
  end
443
457
 
@@ -468,6 +482,7 @@ module Kontena
468
482
  end
469
483
 
470
484
  class Account < OpenStruct
485
+ include Fields
471
486
  include TokenSerializer
472
487
  include ConfigurationInstance
473
488
 
@@ -484,6 +499,7 @@ module Kontena
484
499
  end
485
500
 
486
501
  class Server < OpenStruct
502
+ include Fields
487
503
  include TokenSerializer
488
504
  include ConfigurationInstance
489
505
 
@@ -494,6 +510,7 @@ module Kontena
494
510
  end
495
511
 
496
512
  class Token < OpenStruct
513
+ include Fields
497
514
  include ConfigurationInstance
498
515
 
499
516
  # Hash representation of token data
@@ -3,56 +3,45 @@ module Kontena::Cli::Containers
3
3
  include Kontena::Util
4
4
  include Kontena::Cli::Common
5
5
  include Kontena::Cli::GridOptions
6
+ include Kontena::Cli::TableGenerator::Helper
6
7
 
7
- option ['--all', '-a'], :flag, 'Show all containers'
8
+ option ['-a', '--all'], :flag, 'Show all containers'
9
+
10
+ requires_current_master
11
+ requires_current_master_token
12
+
13
+ NON_STOP_STATES = ['paused', 'restarting', 'oom_killed', 'dead', 'running']
14
+
15
+ def fields
16
+ return ['id'] if quiet?
17
+ { container_id: 'id', image: 'image', command: 'cmd', created: 'created_at', status: 'state' }
18
+ end
8
19
 
9
20
  def execute
10
- require_api_url
11
- token = require_token
12
-
13
- params = '?'
14
- params << 'all=1' if all?
15
- result = client(token).get("containers/#{current_grid}#{params}")
16
- containers = result['containers']
17
- id_column = longest_string_in_array(containers.map {|c| "#{c['node']['name']}/#{c['name']}"})
18
- image_column = longest_string_in_array(containers.map {|c| c['image'] })
19
- columns = "%-#{id_column + 2}s %-#{image_column + 2}s %-30s %-20s %-10s"
20
- puts columns % [ 'CONTAINER ID', 'IMAGE', 'COMMAND', 'CREATED', 'STATUS']
21
- result['containers'].reverse.each do |container|
22
- puts columns % [
23
- "#{container['node']['name']}/#{container['name']}",
24
- container['image'],
25
- "\"#{container['cmd'].to_a.join(' ')[0..26]}\"",
26
- "#{time_ago(container['created_at'])} ago",
27
- container_status(container)
28
- ]
21
+ result = spin_if(!quiet?, "Retrieving container list") do
22
+ Array(client.get("containers/#{current_grid}#{'?all=1' if all?}")['containers'])
29
23
  end
30
- end
31
24
 
32
- def longest_string_in_array(array)
33
- longest = 0
34
- array.each do |item|
35
- longest = item.length if item.length > longest
25
+ print_table(result.reverse) do |row|
26
+ row['id'] = container_id(row)
27
+ row['created_at'] = time_ago(row['created_at'])
28
+ row['cmd'] = truncate_cmd(row)
29
+ row['state'] = container_state(row)
36
30
  end
31
+ end
37
32
 
38
- longest
33
+ def container_id(row)
34
+ "#{row['node']['name']}/#{row['name']}"
39
35
  end
40
36
 
41
- def container_status(container)
42
- s = container['state']
43
- if s['paused']
44
- 'paused'.freeze
45
- elsif s['restarting']
46
- 'restarting'.freeze
47
- elsif s['oom_killed']
48
- 'oom_killed'.freeze
49
- elsif s['dead']
50
- 'dead'.freeze
51
- elsif s['running']
52
- 'running'.freeze
53
- else
54
- 'stopped'.freeze
55
- end
37
+ def truncate_cmd(row)
38
+ cmd = row['cmd'].nil? ? '' : row['cmd'].join(' ')
39
+ cmd = "#{cmd[0..24]}#{pastel.cyan('..')}" if cmd.length > 26
40
+ "\"#{cmd}\""
41
+ end
42
+
43
+ def container_state(row)
44
+ NON_STOP_STATES.find { |state| row.fetch('state', {})[state] == true } || pastel.cyan('stopped')
56
45
  end
57
46
  end
58
47
  end