kafo 5.1.0 → 6.0.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.
@@ -27,20 +27,71 @@ require 'kafo/hooking'
27
27
  require 'kafo/exit_handler'
28
28
  require 'kafo/scenario_manager'
29
29
  require 'kafo/execution_environment'
30
+ require 'kafo/logging'
31
+ require 'kafo/app_option/declaration'
30
32
 
31
33
  module Kafo
32
34
  class KafoConfigure < Clamp::Command
33
35
  include StringHelper
34
36
 
35
37
  class << self
38
+ include AppOption::Declaration
39
+
36
40
  attr_accessor :config, :root_dir, :config_file, :gem_root,
37
- :module_dirs, :kafo_modules_dir, :verbose, :app_options, :logger,
41
+ :module_dirs, :kafo_modules_dir, :verbose, :logger,
38
42
  :check_dirs, :exit_handler, :scenario_manager, :store
39
43
  attr_writer :hooking
40
44
 
41
45
  def hooking
42
46
  @hooking ||= Hooking.new
43
47
  end
48
+
49
+ def run
50
+ return super
51
+ rescue SystemExit
52
+ self.exit_handler.exit(self.exit_code) # fail in initialize
53
+ end
54
+
55
+ def exit(code, &block)
56
+ exit_handler.exit(code, &block)
57
+ end
58
+
59
+ def exit_code
60
+ self.exit_handler.exit_code
61
+ end
62
+
63
+ def in_help_mode?
64
+ ARGV.include?('--help') || ARGV.include?('--full-help') || ARGV.include?('-h')
65
+ end
66
+
67
+ def help(*args)
68
+ kafo = args.pop
69
+ builder_class = kafo.full_help? ? HelpBuilders::Advanced : HelpBuilders::Basic
70
+ args.push builder_class.new(kafo.params)
71
+ super(*args)
72
+ end
73
+
74
+ def use_colors?
75
+ if config
76
+ colors = config.app[:colors]
77
+ else
78
+ colors = ARGV.include?('--no-colors') ? false : nil
79
+ colors = ARGV.include?('--colors') ? true : nil if colors.nil?
80
+ end
81
+ colors
82
+ end
83
+
84
+ def preset_color_scheme
85
+ match = ARGV.join(' ').match(/--color-of-background[ =](\w+)/)
86
+ background = match && match[1]
87
+ ColorScheme.new(:background => background, :colors => use_colors?).setup
88
+ end
89
+
90
+ def set_color_scheme
91
+ ColorScheme.new(
92
+ :background => config.app[:color_of_background],
93
+ :colors => use_colors?).setup
94
+ end
44
95
  end
45
96
 
46
97
  def initialize(*args)
@@ -65,9 +116,9 @@ module Kafo
65
116
  request_config_reload if applied_total > 0
66
117
 
67
118
  if ARGV.include?('--migrations-only')
68
- self.class.verbose = (ARGV.include?('--verbose') || ARGV.include?('-v'))
69
- Logger.setup
70
- self.class.logger.info('Log buffers flushed')
119
+ verbose = (ARGV.include?('--verbose') || ARGV.include?('-v'))
120
+ Logging.setup(verbose: verbose)
121
+ self.class.logger.notice('Log buffers flushed')
71
122
  self.class.exit(0)
72
123
  end
73
124
 
@@ -80,7 +131,7 @@ module Kafo
80
131
  prev_config.run_migrations
81
132
  self.class.config.migrate_configuration(prev_config, :skip => [:log_name])
82
133
  setup_config(self.class.config_file)
83
- self.class.logger.info("Due to scenario change the configuration (#{self.class.config_file}) was updated with #{scenario_manager.previous_scenario} and reloaded.")
134
+ self.class.logger.notice("Due to scenario change the configuration (#{self.class.config_file}) was updated with #{scenario_manager.previous_scenario} and reloaded.")
84
135
  end
85
136
  end
86
137
 
@@ -92,7 +143,7 @@ module Kafo
92
143
  # so we limit parsing only to app config options (because of --help and later defined params)
93
144
  parse clamp_app_arguments
94
145
  parse_app_arguments # set values from ARGS to config.app
95
- Logger.setup
146
+ Logging.setup(verbose: config.app[:verbose])
96
147
  self.class.set_color_scheme
97
148
 
98
149
  self.class.hooking.execute(:init)
@@ -114,19 +165,17 @@ module Kafo
114
165
 
115
166
  def run(*args)
116
167
  started_at = Time.now
117
- logger.info("Running installer with args #{args.inspect}")
168
+ logger.debug("Running installer with args #{args.inspect}")
118
169
  super
119
170
  ensure
120
- logger.info("Installer finished in #{Time.now - started_at} seconds")
171
+ logger.debug("Installer finished in #{Time.now - started_at} seconds")
121
172
  end
122
173
 
123
174
  def execute
124
175
  parse_cli_arguments
125
176
 
126
- if (self.class.verbose = !!verbose?)
127
- Logger.setup_verbose
128
- else
129
- @progress_bar = self.class.config.app[:colors] ? ProgressBars::Colored.new : ProgressBars::BlackWhite.new
177
+ if !config.app[:verbose]
178
+ @progress_bar = config.app[:colors] ? ProgressBars::Colored.new : ProgressBars::BlackWhite.new
130
179
  end
131
180
 
132
181
  unless skip_checks_i_know_better?
@@ -149,6 +198,7 @@ module Kafo
149
198
 
150
199
  self.class.hooking.execute(:pre_commit)
151
200
  unless dont_save_answers? || noop?
201
+ config.configure_application
152
202
  store_params
153
203
  self.class.scenario_manager.link_last_scenario(self.class.config_file) if self.class.scenario_manager.configured?
154
204
  end
@@ -158,46 +208,14 @@ module Kafo
158
208
  return self
159
209
  end
160
210
 
161
- def self.run
162
- return super
163
- rescue SystemExit
164
- self.exit_handler.exit(self.exit_code) # fail in initialize
165
- end
166
-
167
- def self.exit(code, &block)
168
- exit_handler.exit(code, &block)
169
- end
170
-
171
- def self.exit_code
172
- self.exit_handler.exit_code
173
- end
174
-
175
- def self.in_help_mode?
176
- ARGV.include?('--help') || ARGV.include?('--full-help') || ARGV.include?('-h')
177
- end
178
-
179
211
  def exit_code
180
212
  self.class.exit_code
181
213
  end
182
214
 
183
-
184
215
  def help
185
216
  self.class.help(invocation_path, self)
186
217
  end
187
218
 
188
- def self.help(*args)
189
- kafo = args.pop
190
- builder_class = kafo.full_help? ? HelpBuilders::Advanced : HelpBuilders::Basic
191
- args.push builder_class.new(kafo.params)
192
- super(*args)
193
- end
194
-
195
- def self.app_option(*args, &block)
196
- self.app_options ||= []
197
- self.app_options.push self.option(*args, &block)
198
- self.app_options.last
199
- end
200
-
201
219
  def params
202
220
  @params ||= modules.map(&:params).flatten
203
221
  rescue KafoParsers::ModuleName => e
@@ -236,7 +254,6 @@ module Kafo
236
254
  @config_reload_requested = true
237
255
  end
238
256
 
239
-
240
257
  private
241
258
 
242
259
  def setup_config(conf_file)
@@ -263,7 +280,7 @@ module Kafo
263
280
  scenario_manager = setup_scenario_manager
264
281
  self.class.scenario_manager = scenario_manager
265
282
  setup_config(self.class.config_file)
266
- self.class.logger.info('Installer configuration was reloaded')
283
+ self.class.logger.notice('Installer configuration was reloaded')
267
284
  @config_reload_requested = false
268
285
  end
269
286
  end
@@ -290,55 +307,66 @@ module Kafo
290
307
  end
291
308
  end
292
309
 
310
+ def app_option(*args, &block)
311
+ self.class.app_option(*args, &block)
312
+ end
313
+
293
314
  def set_app_options
294
- self.class.app_option ['--[no-]colors'], :flag, 'Use color output on STDOUT',
295
- :default => !!config.app[:colors]
296
- self.class.app_option ['--color-of-background'], 'COLOR', 'Your terminal background is :bright or :dark',
297
- :default => config.app[:color_of_background]
298
- self.class.app_option ['--dont-save-answers'], :flag, "Skip saving answers to '#{self.class.config.answer_file}'?",
299
- :default => !!config.app[:dont_save_answers]
300
- self.class.app_option '--ignore-undocumented', :flag, 'Ignore inconsistent parameter documentation',
301
- :default => false
302
- self.class.app_option ['-i', '--interactive'], :flag, 'Run in interactive mode'
303
- self.class.app_option '--log-level', 'LEVEL', 'Log level for log file output',
304
- :default => config.app[:log_level]
305
- self.class.app_option ['-n', '--noop'], :flag, 'Run puppet in noop mode?',
306
- :default => false
307
- self.class.app_option ['-p', '--profile'], :flag, 'Run puppet in profile mode?',
308
- :default => false
309
- self.class.app_option ['-s', '--skip-checks-i-know-better'], :flag, 'Skip all system checks', :default => false
310
- self.class.app_option ['--skip-puppet-version-check'], :flag, 'Skip check for compatible Puppet versions', :default => false
311
- self.class.app_option ['-v', '--verbose'], :flag, 'Display log on STDOUT instead of progressbar'
312
- self.class.app_option ['-l', '--verbose-log-level'], 'LEVEL', 'Log level for verbose mode output',
313
- :default => 'info'
314
- self.class.app_option ['-S', '--scenario'], 'SCENARIO', 'Use installation scenario'
315
- self.class.app_option ['--disable-scenario'], 'SCENARIO', 'Disable installation scenario'
316
- self.class.app_option ['--enable-scenario'], 'SCENARIO', 'Enable installation scenario'
317
- self.class.app_option ['--list-scenarios'], :flag, 'List available installation scenarios'
318
- self.class.app_option ['--force'], :flag, 'Force change of installation scenario'
319
- self.class.app_option ['--compare-scenarios'], :flag, 'Show changes between last used scenario and the scenario specified with -S or --scenario argument'
320
- self.class.app_option ['--migrations-only'], :flag, 'Apply migrations to a selected scenario and exit'
321
- self.class.app_option ['--[no-]parser-cache'], :flag, 'Force use or bypass of Puppet module parser cache'
315
+ app_option ['--[no-]colors'], :flag, 'Use color output on STDOUT',
316
+ :default => config.app[:colors], :advanced => true
317
+ app_option ['--color-of-background'], 'COLOR', 'Your terminal background is :bright or :dark',
318
+ :default => config.app[:color_of_background], :advanced => true
319
+ app_option ['--dont-save-answers'], :flag, "Skip saving answers to '#{self.class.config.answer_file}'?",
320
+ :default => config.app[:dont_save_answers], :advanced => true
321
+ app_option '--ignore-undocumented', :flag, 'Ignore inconsistent parameter documentation',
322
+ :default => config.app[:ignore_undocumented], :advanced => true
323
+ app_option ['-i', '--interactive'], :flag, 'Run in interactive mode'
324
+ app_option '--log-level', 'LEVEL', 'Log level for log file output',
325
+ :default => config.app[:log_level], :advanced => true
326
+ app_option ['-n', '--noop'], :flag, 'Run puppet in noop mode?',
327
+ :default => false
328
+ app_option ['-p', '--profile'], :flag, 'Run puppet in profile mode?',
329
+ :default => false, :advanced => true
330
+ app_option ['-s', '--skip-checks-i-know-better'], :flag, 'Skip all system checks',
331
+ :default => false
332
+ app_option ['--skip-puppet-version-check'], :flag, 'Skip check for compatible Puppet versions',
333
+ :default => false, :advanced => true
334
+ app_option ['-v', '--[no-]verbose'], :flag, 'Display log on STDOUT instead of progressbar',
335
+ :default => config.app[:verbose]
336
+ app_option ['-l', '--verbose-log-level'], 'LEVEL', 'Log level for verbose mode output',
337
+ :default => 'notice'
338
+ app_option ['-S', '--scenario'], 'SCENARIO', 'Use installation scenario'
339
+ app_option ['--disable-scenario'], 'SCENARIO', 'Disable installation scenario',
340
+ :advanced => true
341
+ app_option ['--enable-scenario'], 'SCENARIO', 'Enable installation scenario',
342
+ :advanced => true
343
+ app_option ['--list-scenarios'], :flag, 'List available installation scenarios'
344
+ app_option ['--force'], :flag, 'Force change of installation scenario',
345
+ :advanced => true
346
+ app_option ['--compare-scenarios'], :flag, 'Show changes between last used scenario and the scenario specified with -S or --scenario argument',
347
+ :advanced => true
348
+ app_option ['--migrations-only'], :flag, 'Apply migrations to a selected scenario and exit',
349
+ :advanced => true
350
+ app_option ['--[no-]parser-cache'], :flag, 'Force use or bypass of Puppet module parser cache',
351
+ :advanced => true
322
352
  end
323
353
 
324
354
  def set_options
325
- self.class.option '--full-help', :flag, "print complete help" do
355
+ app_option '--full-help', :flag, "print complete help" do
326
356
  @full_help = true
327
357
  request_help
328
358
  end
329
359
 
330
360
  modules.each do |mod|
331
- self.class.option d("--[no-]enable-#{mod.name}"),
332
- :flag,
333
- "Enable '#{mod.name}' puppet module",
334
- :default => mod.enabled?
361
+ app_option d("--[no-]enable-#{mod.name}"), :flag, "Enable '#{mod.name}' puppet module",
362
+ :default => mod.enabled?
335
363
  end
336
364
 
337
365
  params.sort.each do |param|
338
366
  doc = param.doc.nil? ? 'UNDOCUMENTED' : param.doc.join("\n")
339
- self.class.option parametrize(param), '', doc + " (current: #{param.value_to_s})",
367
+ app_option parametrize(param), '', doc + " (current: #{param.value_to_s})",
340
368
  :multivalued => param.multivalued?
341
- self.class.option parametrize(param, 'reset-'), :flag,
369
+ app_option parametrize(param, 'reset-'), :flag,
342
370
  "Reset #{param.name} to the default value (#{param.default_to_s})"
343
371
  end
344
372
  end
@@ -347,13 +375,15 @@ module Kafo
347
375
  # so we accept either allowed args or those that does not start with '-' and are right after
348
376
  # accepted argument
349
377
  def clamp_app_arguments
350
- @allowed_clamp_app_arguments = self.class.app_options.map do |option|
378
+ @allowed_clamp_app_arguments = self.class.declared_options.map do |option|
351
379
  option.switches.map { |s| is_yes_no_flag?(s) ? build_yes_no_variants(s) : s }
352
380
  end
353
381
  @allowed_clamp_app_arguments.flatten!
354
382
 
355
383
  last_was_accepted = false
356
- ARGV.select { |arg| last_was_accepted = is_allowed_attribute_name?(arg) || (last_was_accepted && is_value?(arg)) }
384
+ ARGV.select do |arg|
385
+ last_was_accepted = is_allowed_attribute_name?(arg) || (last_was_accepted && is_value?(arg))
386
+ end
357
387
  end
358
388
 
359
389
  def is_yes_no_flag?(s)
@@ -373,7 +403,7 @@ module Kafo
373
403
  end
374
404
 
375
405
  def parse_app_arguments
376
- self.class.app_options.each do |option|
406
+ self.class.declared_options.each do |option|
377
407
  name = option.attribute_name
378
408
  value = send(option.flag? ? "#{name}?" : name)
379
409
  config.app[name.to_sym] = value.nil? ? option.default_value : value
@@ -410,11 +440,11 @@ module Kafo
410
440
  end
411
441
 
412
442
  def validate_all(logging = true)
413
- logger.info 'Running validation checks'
443
+ logger.notice 'Running validation checks'
414
444
  results = enabled_params.map do |param|
415
445
  result = param.valid?
416
446
  errors = param.validation_errors.join(', ')
417
- progress_log(:error, "Parameter #{with_prefix(param)} invalid: #{errors}") if logging && !result
447
+ progress_log(:error, "Parameter #{with_prefix(param)} invalid: #{errors}", logger) if logging && !result
418
448
  result
419
449
  end
420
450
  results.all?
@@ -445,11 +475,15 @@ module Kafo
445
475
  begin
446
476
  command = PuppetCommand.new('include kafo_configure', options, puppetconf).command
447
477
  log_parser = PuppetLogParser.new
478
+ logger = Logger.new('configure')
479
+ logger.notice("Starting system configuration")
480
+
448
481
  PTY.spawn(*PuppetCommand.format_command(command)) do |stdin, stdout, pid|
449
482
  begin
450
483
  stdin.each do |line|
451
484
  line = normalize_encoding(line)
452
- progress_log(*log_parser.parse(line))
485
+ method, message = log_parser.parse(line)
486
+ progress_log(method, message, logger)
453
487
  @progress_bar.update(line) if @progress_bar
454
488
  end
455
489
  rescue Errno::EIO # we reach end of input
@@ -466,14 +500,15 @@ module Kafo
466
500
  rescue PTY::ChildExited => e # could be raised by Process.wait on older ruby or by PTY.check
467
501
  exit_code = e.status.exitstatus
468
502
  end
503
+
469
504
  @progress_bar.close if @progress_bar
470
- logger.info "Puppet has finished, bye!"
471
- self.class.exit(exit_code) do
472
- self.class.hooking.execute(:post)
473
- end
505
+ logger.notice "Puppet has finished, bye!"
506
+
507
+ self.class.hooking.execute(:post)
508
+ self.class.exit(exit_code)
474
509
  end
475
510
 
476
- def progress_log(method, message)
511
+ def progress_log(method, message, logger)
477
512
  @progress_bar.print_error(message + "\n") if method == :error && @progress_bar
478
513
  logger.send(method, message)
479
514
  end
@@ -490,30 +525,6 @@ module Kafo
490
525
  File.join(Dir.pwd, 'config', 'kafo.yaml')
491
526
  end
492
527
 
493
- def self.use_colors?
494
- if config
495
- colors = config.app[:colors]
496
- else
497
- colors = ARGV.include?('--no-colors') ? false : nil
498
- colors = ARGV.include?('--colors') ? true : nil if colors.nil?
499
- end
500
- colors
501
- end
502
-
503
- def self.preset_color_scheme
504
- match = ARGV.join(' ').match(/--color-of-background[ =](\w+)/)
505
- background = match && match[1]
506
- ColorScheme.new(:background => background, :colors => use_colors?).setup
507
- end
508
-
509
- def self.set_color_scheme
510
- ColorScheme.new(
511
- :background => config.app[:color_of_background],
512
- :colors => use_colors?).setup
513
- end
514
-
515
- private
516
-
517
528
  def normalize_encoding(line)
518
529
  if line.respond_to?(:encode) && line.respond_to?(:valid_encoding?)
519
530
  line.valid_encoding? ? line : line.encode('UTF-16be', :invalid => :replace, :replace => '?').encode('UTF-8')
@@ -1,138 +1,28 @@
1
1
  # encoding: UTF-8
2
- require 'fileutils'
3
- require 'logging'
2
+ require 'kafo/logging'
4
3
 
5
4
  module Kafo
6
5
  class Logger
7
- class << self
8
- attr_writer :loggers
9
6
 
10
- def loggers
11
- @loggers ||= []
12
- end
13
-
14
- def buffer
15
- @buffer ||= []
16
- end
17
-
18
- def error_buffer
19
- @error_buffer ||= []
20
- end
21
- end
22
-
23
- PATTERN = "[%5l %d %c] %m\n"
24
- Logging.color_scheme('bright',
25
- :levels => {
26
- :info => :green,
27
- :warn => :yellow,
28
- :error => :red,
29
- :fatal => [:white, :on_red]
30
- },
31
- :date => :blue,
32
- :logger => :cyan,
33
- :line => :yellow,
34
- :file => :yellow,
35
- :method => :yellow
36
- )
37
- COLOR_LAYOUT = Logging::Layouts::Pattern.new(:pattern => PATTERN, :color_scheme => 'bright')
38
- NOCOLOR_LAYOUT = Logging::Layouts::Pattern.new(:pattern => PATTERN, :color_scheme => nil)
39
-
40
- def self.setup_fatal_logger(layout)
41
- fatal_logger = Logging.logger['fatal']
42
- fatal_logger.level = 'fatal'
43
- fatal_logger.appenders = [::Logging.appenders.stderr(:layout => layout)]
44
- self.loggers << fatal_logger
45
- end
46
-
47
- def self.setup
48
- begin
49
- FileUtils.mkdir_p(KafoConfigure.config.app[:log_dir], :mode => 0750)
50
- rescue Errno::EACCES
51
- puts "No permissions to create log dir #{KafoConfigure.config.app[:log_dir]}"
52
- end
53
-
54
- logger = Logging.logger['main']
55
- filename = KafoConfigure.config.log_file
56
- begin
57
- logger.appenders = ::Logging.appenders.rolling_file('configure',
58
- :filename => filename,
59
- :layout => NOCOLOR_LAYOUT,
60
- :truncate => true
61
- )
62
- # set owner and group (it's ignored if attribute is nil)
63
- FileUtils.chown KafoConfigure.config.app[:log_owner], KafoConfigure.config.app[:log_group], filename
64
- rescue ArgumentError
65
- puts "File #{filename} not writeable, won't log anything to file!"
66
- end
67
-
68
- logger.level = KafoConfigure.config.app[:log_level]
69
- self.loggers << logger
70
-
71
- setup_fatal_logger(color_layout) unless loggers.detect {|l| l.name == 'verbose'}
72
- end
73
-
74
- def self.setup_verbose
75
- logger = Logging.logger['verbose']
76
- logger.level = (KafoConfigure.config && KafoConfigure.config.app[:verbose_log_level]) || :info
77
- layout = color_layout
78
- logger.appenders = [::Logging.appenders.stdout(:layout => layout)]
79
- self.loggers<< logger
80
- end
7
+ attr_reader :logger, :name
81
8
 
82
- def self.buffering?
83
- KafoConfigure.verbose.nil? || ((KafoConfigure.verbose && !loggers.detect {|l| l.name == 'verbose'}) || self.loggers.empty?)
9
+ def initialize(name = 'root')
10
+ @name = name
11
+ @logger = (name == 'root') ? Logging.root_logger : Logging.add_logger(name)
84
12
  end
85
13
 
86
- def self.dump_needed?
87
- !self.buffer.empty?
88
- end
89
-
90
- def self.to_buffer(buffer, *args)
91
- buffer << args
92
- end
93
-
94
- def self.dump_errors
95
- setup_fatal_logger(color_layout) if loggers.empty?
96
- unless self.error_buffer.empty?
97
- loggers.each { |logger| logger.error 'Errors encountered during run:' }
98
- self.dump_buffer(self.error_buffer)
99
- end
100
- end
101
-
102
- def dump_errors
103
- self.class.dump_errors
104
- end
105
-
106
- def self.dump_buffer(buffer)
107
- buffer.each do |log|
108
- self.loggers.each { |logger| logger.send log[0], *([log[1]].flatten(1)), &log[2] }
109
- end
110
- buffer.clear
111
- end
112
-
113
- def self.color_layout
114
- KafoConfigure.use_colors? ? COLOR_LAYOUT : NOCOLOR_LAYOUT
115
- end
116
-
117
- def log(name, *args, &block)
118
- if self.class.buffering?
119
- self.class.to_buffer(self.class.buffer, name, args, &block)
14
+ def log(level, *args, &block)
15
+ if Logging.buffering?
16
+ Logging.to_buffer(@name, level, args, &block)
120
17
  else
121
- self.class.dump_buffer(self.class.buffer) if self.class.dump_needed?
122
- self.class.loggers.each { |logger| logger.send name, *args, &block }
123
- end
124
- end
125
-
126
- %w(warn info debug).each do |name|
127
- define_method(name) do |*args, &block|
128
- self.log(name, *args, &block)
18
+ Logging.dump_buffer if Logging.dump_needed?
19
+ @logger.send(level, *args, &block)
129
20
  end
130
21
  end
131
22
 
132
- %w(fatal error).each do |name|
133
- define_method(name) do |*args, &block|
134
- self.class.to_buffer(self.class.error_buffer, name, *args, &block)
135
- self.log(name, *args, &block)
23
+ Logging::LOG_LEVELS.each do |level|
24
+ define_method(level) do |*args, &block|
25
+ log(level, *args, &block)
136
26
  end
137
27
  end
138
28
  end