kafo 5.1.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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