kontena-cli 1.3.0.pre1 → 1.3.0.pre2

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 (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,14 +1,15 @@
1
1
  require 'clamp'
2
2
  require 'kontena/cli/subcommand_loader'
3
- require 'kontena/cli/common'
4
3
  require 'kontena/util'
5
4
  require 'kontena/cli/bytes_helper'
6
5
  require 'kontena/cli/grid_options'
6
+ require 'excon/errors'
7
7
 
8
8
  class Kontena::Command < Clamp::Command
9
9
 
10
10
  option ['-D', '--debug'], :flag, "Enable debug", environment_variable: 'DEBUG' do
11
11
  ENV['DEBUG'] ||= 'true'
12
+ Kontena.reset_logger
12
13
  end
13
14
 
14
15
  attr_accessor :arguments
@@ -182,7 +183,7 @@ class Kontena::Command < Clamp::Command
182
183
  end
183
184
 
184
185
  def run(arguments)
185
- ENV["DEBUG"] && $stderr.puts("Running #{self} -- callback matcher = '#{self.class.callback_matcher.nil? ? "nil" : self.class.callback_matcher.map(&:to_s).join(' ')}'")
186
+ Kontena.logger.debug { "Running #{self.class.name} with #{arguments.inspect} -- callback matcher = '#{self.class.callback_matcher.nil? ? "nil" : self.class.callback_matcher.map(&:to_s).join(' ')}'" }
186
187
  @arguments = arguments
187
188
 
188
189
  run_callbacks :before_parse unless help_requested?
@@ -218,7 +219,8 @@ class Kontena::Command < Clamp::Command
218
219
  end
219
220
  rescue Kontena::Errors::StandardError => ex
220
221
  raise ex if ENV['DEBUG']
221
- abort(" [#{Kontena.pastel.red('error')}] #{ex.class.name} : #{ex.message}")
222
+ Kontena.logger.error(ex)
223
+ abort(" [#{Kontena.pastel.red('error')}] #{ex.status} : #{ex.message}")
222
224
  rescue Errno::EPIPE
223
225
  # If user is piping the command outputs to some other command that might exit before CLI has outputted everything
224
226
  abort
@@ -226,7 +228,8 @@ class Kontena::Command < Clamp::Command
226
228
  raise
227
229
  rescue => ex
228
230
  raise ex if ENV['DEBUG']
229
- abort(" [#{Kontena.pastel.red('error')}] #{ex.class.name} : #{ex.message}\n Rerun the command with environment DEBUG=true set to get the full exception")
231
+ Kontena.logger.error(ex)
232
+ abort(" [#{Kontena.pastel.red('error')}] #{ex.class.name} : #{ex.message}\n See #{Kontena.log_target} or run the command again with environment DEBUG=true set to see the full exception")
230
233
  end
231
234
  end
232
235
 
@@ -22,6 +22,7 @@ module Kontena
22
22
  heads << "Accept: #{params[:headers]['Accept']}" if params[:headers]['Accept']
23
23
  heads << "Content-Type: #{params[:headers]['Content-Type']}" if params[:headers]['Content-Type']
24
24
  heads << "Authorization: #{params[:headers]['Authorization'].split(' ', 2).first}" if params[:headers]['Authorization']
25
+ heads << "X-Kontena-Version: #{params[:headers]['X-Kontena-Version']}" if params[:headers]['X-Kontena-Version']
25
26
  str << heads.join(', ')
26
27
  str << "} "
27
28
  result << str
@@ -50,17 +51,17 @@ module Kontena
50
51
  end
51
52
  end
52
53
  result << str
54
+ elsif params[:error]
55
+ result << params[:error]
53
56
  end
54
57
 
55
- if $stderr.tty?
56
- if direction == 'Request'
57
- $stderr.puts(Kontena.pastel.blue("[API Client #{direction}]: #{result.join(" | ")}"))
58
- else
59
- $stderr.puts(Kontena.pastel.magenta("[API Client #{direction}]: #{result.join(" | ")}"))
60
- end
61
- else
62
- $stderr.puts("[API Client #{direction}]: #{result.join(" | ")}")
63
- end
58
+ color = case direction
59
+ when 'Request' then :blue
60
+ when 'Response' then :magenta
61
+ else :red
62
+ end
63
+
64
+ Kontena.logger.debug("CLIENT") { Kontena.pastel.send(color, "[#{direction}]: #{result.join(" | ")}") }
64
65
 
65
66
  if block_given?
66
67
  yield
@@ -1,9 +1,6 @@
1
1
  require 'kontena/command'
2
2
 
3
3
  class Kontena::MainCommand < Kontena::Command
4
- include Kontena::Util
5
- include Kontena::Cli::Common
6
-
7
4
  option ['-v', '--version'], :flag, "Output Kontena CLI version #{Kontena::Cli::VERSION}" do
8
5
  build_tags = [ 'ruby' + RUBY_VERSION ]
9
6
  build_tags << RUBY_PLATFORM
@@ -44,6 +41,7 @@ class Kontena::MainCommand < Kontena::Command
44
41
 
45
42
  def subcommand_missing(name)
46
43
  if known_plugin_subcommand?(name)
44
+ extend Kontena::Cli::Common
47
45
  exit_with_error "The '#{name}' plugin has not been installed. Use: kontena plugin install #{name}"
48
46
  else
49
47
  super(name)
@@ -159,6 +159,10 @@ module Kontena
159
159
  SafeYAML::OPTIONS[:default_mode] = :safe if Object.const_defined?(:SafeYAML)
160
160
  end
161
161
 
162
+ def plugin_debug?
163
+ @plugin_debug ||= ENV['DEBUG'] == 'plugin'
164
+ end
165
+
162
166
  def load_plugins
163
167
  plugins = []
164
168
  Gem::Specification.to_a.each do |spec|
@@ -167,21 +171,25 @@ module Kontena
167
171
  if File.exist?(plugin) && !plugins.find{ |p| p.name == spec.name }
168
172
  begin
169
173
  if spec_has_valid_dependency?(spec)
174
+
170
175
  loaded_features_before = $LOADED_FEATURES.dup
171
176
  load_path_before = $LOAD_PATH.dup
172
177
 
173
- ENV["DEBUG"] && $stderr.puts("Activating plugin #{spec.name}")
178
+ Kontena.logger.debug { "Activating plugin #{spec.name}" } if plugin_debug?
174
179
  spec.activate
175
180
  spec.activate_dependencies
176
181
 
177
- ENV["DEBUG"] && $stderr.puts("Loading plugin #{spec.name}")
182
+ Kontena.logger.debug { "Loading plugin #{spec.name}" }
178
183
  require(plugin)
184
+ Kontena.logger.debug { "Loaded plugin #{spec.name}" } if plugin_debug?
179
185
 
180
- if ENV['DEBUG'] == 'plugin'
186
+ if plugin_debug?
181
187
  added_features = ($LOADED_FEATURES - loaded_features_before).map {|feat| "- #{feat}"}
182
188
  added_paths = ($LOAD_PATH - load_path_before).map {|feat| "- #{feat}"}
183
- $stderr.puts "Plugin manager loaded features for #{spec.name}: \n#{added_features.join("\n")}" unless added_features.empty?
184
- $stderr.puts "Plugin manager load paths added for #{spec.name}: \n#{added_paths.join("\n")}" unless added_paths.empty?
189
+ Kontena.logger.debug { "Plugin manager loaded features for #{spec.name}:" } unless added_features.empty?
190
+ added_features.each { |feat| Kontena.logger.debug { feat } }
191
+ Kontena.logger.debug { "Plugin manager load paths added for #{spec.name}:" } unless added_paths.empty?
192
+ added_paths.each { |path| Kontena.logger.debug { path } }
185
193
  end
186
194
 
187
195
  plugins << spec
@@ -192,7 +200,7 @@ module Kontena
192
200
  end
193
201
  rescue ScriptError, StandardError => ex
194
202
  warn " [#{Kontena.pastel.red('error')}] Failed to load plugin: #{spec.name}\n\tRerun the command with environment DEBUG=true set to get the full exception."
195
- ENV['DEBUG'] && $stderr.puts("#{ex.class.name} : #{ex.message}\n#{ex.backtrace.join("\n ")}")
203
+ Kontena.logger.error(ex)
196
204
  end
197
205
  end
198
206
  end
@@ -200,7 +208,7 @@ module Kontena
200
208
  plugins
201
209
  rescue => ex
202
210
  $stderr.puts Kontena.pastel.red(ex.message)
203
- ENV['DEBUG'] && $stderr.puts("#{ex.class.name} : #{ex.message}\n#{ex.backtrace.join("\n ")}")
211
+ Kontena.logger.error(ex)
204
212
  end
205
213
 
206
214
  def prefix(plugin_name)
@@ -1,10 +1,6 @@
1
- require_relative 'stacks_client'
2
- require_relative 'cli/common'
3
- require_relative 'cli/stacks/common'
4
- require 'yaml'
5
- require 'uri'
6
-
7
1
  module Kontena
2
+ autoload :StacksClient, 'kontena/stacks_client'
3
+
8
4
  class StacksCache
9
5
  class CachedStack
10
6
 
@@ -12,6 +8,8 @@ module Kontena
12
8
  attr_accessor :version
13
9
 
14
10
  def initialize(stack, version = nil)
11
+ require "safe_yaml"
12
+ SafeYAML::OPTIONS[:default_mode] = :safe
15
13
  unless version
16
14
  stack, version = stack.split(':', 2)
17
15
  end
@@ -59,6 +57,8 @@ module Kontena
59
57
  end
60
58
 
61
59
  class RegistryClientFactory
60
+ require 'kontena/cli/common'
61
+ require 'kontena/cli/stacks/common'
62
62
  include Kontena::Cli::Common
63
63
  include Kontena::Cli::Stacks::Common
64
64
  end
@@ -69,7 +69,7 @@ module Kontena
69
69
  end
70
70
 
71
71
  def dputs(msg)
72
- ENV["DEBUG"] && $stderr.puts(msg)
72
+ Kontena.logger.debug { msg }
73
73
  end
74
74
 
75
75
  def cache(stack, version = nil)
@@ -7,6 +7,19 @@ module Kontena
7
7
  ACCEPT_YAML = { 'Accept' => 'application/yaml' }
8
8
  CT_YAML = { 'Content-Type' => 'application/yaml' }
9
9
 
10
+ def raise_unless_token
11
+ unless token && token['access_token']
12
+ raise Kontena::Errors::StandardError.new(401, "Stack registry write operations require authentication")
13
+ end
14
+ end
15
+
16
+ def raise_unless_read_token
17
+ return false unless options[:read_requires_token]
18
+ unless token && token['access_token']
19
+ raise Kontena::Errors::StandardError.new(401, "Stack registry requires authentication")
20
+ end
21
+ end
22
+
10
23
  def full_uri(stack_name, version = nil)
11
24
  URI.join(api_url, path_to(stack_name, version)).to_s
12
25
  end
@@ -16,29 +29,35 @@ module Kontena
16
29
  end
17
30
 
18
31
  def push(stack_name, version, data)
19
- post('/stack/', data, {}, CT_YAML)
32
+ raise_unless_token
33
+ post('/stack/', data, {}, CT_YAML, true)
20
34
  end
21
35
 
22
36
  def show(stack_name, stack_version = nil)
23
- get("#{path_to(stack_name, stack_version)}", {}, ACCEPT_JSON)
37
+ raise_unless_read_token
38
+ get("#{path_to(stack_name, stack_version)}", nil, ACCEPT_JSON, options[:read_requires_token])
24
39
  end
25
40
 
26
41
  def versions(stack_name)
27
- get("#{path_to(stack_name, nil)}/versions", {}, ACCEPT_JSON)['versions']
42
+ raise_unless_read_token
43
+ get("#{path_to(stack_name, nil)}/versions", nil, ACCEPT_JSON, options[:read_requires_token])['versions']
28
44
  end
29
45
 
30
46
  def pull(stack_name, version = nil)
31
- get(path_to(stack_name, version), {}, ACCEPT_YAML)
47
+ raise_unless_read_token
48
+ get(path_to(stack_name, version), nil, ACCEPT_YAML, options[:read_requires_token])
32
49
  rescue StandardError => ex
33
50
  ex.message << " : #{path_to(stack_name, version)}"
34
51
  raise ex, ex.message
35
52
  end
36
53
 
37
54
  def search(query)
38
- get('/search', { q: query }, {}, ACCEPT_JSON)['stacks']
55
+ raise_unless_read_token
56
+ get('/search', { q: query }, ACCEPT_JSON, options[:read_requires_token])['stacks']
39
57
  end
40
58
 
41
59
  def destroy(stack_name, version = nil)
60
+ raise_unless_token
42
61
  delete(path_to(stack_name, version), {})
43
62
  end
44
63
  end
data/lib/kontena/util.rb CHANGED
@@ -1,9 +1,33 @@
1
1
  module Kontena
2
2
  module Util
3
3
  def self.included(base)
4
- base.extend(ClassMethods)
4
+ base.extend(ClassMethods)
5
5
  end
6
6
 
7
+ def symbolize_keys(obj)
8
+ case obj
9
+ when Hash
10
+ obj.map { |k,v| [k.to_sym, symbolize_keys(v)] }.to_h
11
+ when Array
12
+ obj.map { |v| symbolize_keys(v) }
13
+ else
14
+ obj
15
+ end
16
+ end
17
+ module_function :symbolize_keys
18
+
19
+ def symbolize_keys!(obj)
20
+ case obj
21
+ when Hash
22
+ obj.keys.each { |k| obj[k.to_sym] = symbolize_keys!(obj.delete(k)) }
23
+ when Array
24
+ obj.map! { |v| symbolize_keys!(v) }
25
+ else
26
+ end
27
+ obj
28
+ end
29
+ module_function :symbolize_keys!
30
+
7
31
  # @param [String] cmd
8
32
  def which(cmd)
9
33
  exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
@@ -30,26 +54,30 @@ module Kontena
30
54
 
31
55
  def time_ago(time)
32
56
  now = Time.now.to_i
33
- time = DateTime.parse(time).to_time.to_i
57
+ time = time.kind_of?(Integer) ? time : DateTime.parse(time).to_time.to_i
34
58
  diff = now - time
35
- if diff > 60 * 60 * 24
36
- "#{diff / 60 / 60 / 24} days"
37
- elsif diff > 60 * 60
38
- "#{diff / 60 / 60} hours"
39
- elsif diff > 60
40
- "#{diff / 60} minutes"
59
+ seconds_to_human(diff) + ' ago'
60
+ end
61
+
62
+ def time_until(seconds)
63
+ 'in ' + seconds_to_human(seconds)
64
+ end
65
+
66
+ def seconds_to_human(seconds)
67
+ if seconds > 60 * 60 * 24
68
+ result = "#{seconds / 60 / 60 / 24} days"
69
+ elsif seconds > 60 * 60
70
+ result = "#{seconds / 60 / 60} hours"
71
+ elsif seconds > 60
72
+ result = "#{seconds / 60} minutes"
41
73
  else
42
- "#{diff} seconds"
74
+ result = "#{seconds} seconds"
43
75
  end
76
+ result.start_with?('1 ') ? result[0..-2] : result
44
77
  end
45
78
 
46
79
  def longest_string_in_array(array)
47
- longest = 0
48
- array.each do |item|
49
- longest = item.length if item.length > longest
50
- end
51
-
52
- longest
80
+ array.max_by(&:length).length
53
81
  end
54
82
 
55
83
  module_function(:which)
data/lib/kontena_cli.rb CHANGED
@@ -1,4 +1,26 @@
1
+ require 'logger'
2
+
3
+ $KONTENA_START_TIME = Time.now.to_f
4
+ at_exit do
5
+ Kontena.logger.debug { "Execution took #{(Time.now.to_f - $KONTENA_START_TIME).round(3)} seconds" }
6
+ Kontena.logger.debug { "#{$!.class.name}" + ($!.respond_to?(:status) ? " status #{$!.status}" : "") } if $!
7
+ end
8
+
1
9
  module Kontena
10
+ module Cli
11
+ autoload :Config, 'kontena/cli/config'
12
+ autoload :Spinner, 'kontena/cli/spinner'
13
+ autoload :Common, 'kontena/cli/common'
14
+ autoload :TableGenerator, 'kontena/cli/table_generator'
15
+ end
16
+
17
+ autoload :Command, 'kontena/command'
18
+ autoload :Client, 'kontena/client'
19
+ autoload :StacksCache, 'kontena/stacks_cache'
20
+ autoload :PluginManager, 'kontena/plugin_manager'
21
+ autoload :MainCommand, 'kontena/main_command'
22
+ autoload :Errors, 'kontena/errors'
23
+
2
24
  # Run a kontena command like it was launched from the command line. Re-raises any exceptions,
3
25
  # except a SystemExit with status 0, which is considered a success.
4
26
  #
@@ -12,16 +34,17 @@ module Kontena
12
34
  else
13
35
  command = cmdline
14
36
  end
15
- ENV["DEBUG"] && puts("Running Kontena.run(#{command.inspect}")
37
+ logger.debug { "Running Kontena.run(#{command.inspect}" }
16
38
  result = Kontena::MainCommand.new(File.basename(__FILE__)).run(command)
17
- ENV["DEBUG"] && puts("Command completed, result: #{result.inspect} status: 0")
39
+ logger.debug { "Command completed, result: #{result.inspect} status: 0" }
18
40
  result
19
41
  rescue SystemExit => ex
20
- ENV["DEBUG"] && $stderr.puts("Command caused SystemExit, result: #{result.inspect} status: #{ex.status}")
42
+ logger.debug { "Command caused SystemExit, status: #{ex.status}" }
21
43
  return true if ex.status.zero?
22
44
  raise ex
23
45
  rescue => ex
24
- ENV["DEBUG"] && $stderr.puts("Command raised #{ex.class.name} with message: #{ex.message}\n#{ex.backtrace.join("\n ")}")
46
+ logger.error { "Command #{cmdline.inspect} exception" }
47
+ logger.error { ex }
25
48
  raise ex
26
49
  end
27
50
 
@@ -37,6 +60,29 @@ module Kontena
37
60
  false
38
61
  end
39
62
 
63
+ def self.log_target
64
+ return @log_target if @log_target
65
+
66
+ @log_target = ENV['LOG_TARGET']
67
+
68
+ if ENV["DEBUG"]
69
+ @log_target ||= $stderr
70
+ elsif @log_target.nil?
71
+ @log_target = File.join(home, 'kontena.log')
72
+ end
73
+ end
74
+
75
+ def self.reset_logger
76
+ @log_target, @logger = nil
77
+ end
78
+
79
+ def self.home
80
+ return @home if @home
81
+ @home = File.join(Dir.home, '.kontena')
82
+ Dir.mkdir(@home, 0700) unless File.directory?(@home)
83
+ @home
84
+ end
85
+
40
86
  # @return [String] x.y
41
87
  def self.minor_version
42
88
  Kontena::Cli::VERSION.split('.')[0..1].join('.')
@@ -59,7 +105,9 @@ module Kontena
59
105
  end
60
106
 
61
107
  def self.pastel
62
- @pastel ||= Pastel.new(enabled: !simple_terminal?)
108
+ return @pastel if @pastel
109
+ require 'pastel'
110
+ @pastel = Pastel.new(enabled: !simple_terminal?)
63
111
  end
64
112
 
65
113
  def self.prompt
@@ -96,6 +144,23 @@ module Kontena
96
144
  File.join(Kontena.root, 'lib/kontena/cli', *joinables)
97
145
  end
98
146
  end
147
+
148
+ def self.logger
149
+ return @logger if @logger
150
+ if log_target.respond_to?(:tty?) && log_target.tty?
151
+ logger = Logger.new(log_target)
152
+ require 'kontena/cli/log_formatters/compact'
153
+ logger.formatter = Kontena::Cli::LogFormatter::Compact.new
154
+ else
155
+ logger = Logger.new(log_target, 1, 1_048_576)
156
+ require 'kontena/cli/log_formatters/strip_color'
157
+ logger.formatter = Kontena::Cli::LogFormatter::StripColor.new
158
+ end
159
+ logger.level = ENV["DEBUG"] ? Logger::DEBUG : Logger::INFO
160
+ logger.progname = 'CLI'
161
+ @logger = logger
162
+ end
163
+
99
164
  end
100
165
 
101
166
  # Monkeypatching string to mimick 'colorize' gem
@@ -115,13 +180,5 @@ end
115
180
 
116
181
  require 'ruby_dig'
117
182
  require 'shellwords'
118
- require "safe_yaml"
119
- SafeYAML::OPTIONS[:default_mode] = :safe
120
183
  require 'kontena/cli/version'
121
- require 'kontena/cli/common'
122
- require 'kontena/command'
123
- require 'kontena/client'
124
- require 'kontena/stacks_cache'
125
- require 'kontena/plugin_manager'
126
- require 'kontena/main_command'
127
- require 'kontena/cli/spinner'
184
+ Kontena.logger.debug { "Kontena CLI #{Kontena::Cli::VERSION} (ruby-#{RUBY_VERSION}+#{RUBY_PLATFORM})" }