test-kitchen 4.0.0 → 4.1.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.
- checksums.yaml +4 -4
- data/Gemfile +6 -4
- data/lib/kitchen/cli.rb +33 -8
- data/lib/kitchen/command/list.rb +49 -9
- data/lib/kitchen/command/logs.rb +185 -0
- data/lib/kitchen/command/test.rb +2 -1
- data/lib/kitchen/command.rb +22 -9
- data/lib/kitchen/config.rb +8 -0
- data/lib/kitchen/data_munger.rb +47 -12
- data/lib/kitchen/driver/base.rb +19 -0
- data/lib/kitchen/driver/dummy.rb +27 -0
- data/lib/kitchen/errors.rb +1 -0
- data/lib/kitchen/instance.rb +251 -88
- data/lib/kitchen/lifecycle_hook/remote.rb +5 -2
- data/lib/kitchen/logger.rb +407 -74
- data/lib/kitchen/logging.rb +2 -2
- data/lib/kitchen/provisioner/base.rb +27 -17
- data/lib/kitchen/provisioner/external.rb +420 -0
- data/lib/kitchen/shell_out.rb +1 -1
- data/lib/kitchen/state_file.rb +12 -2
- data/lib/kitchen/transport/base.rb +1 -1
- data/lib/kitchen/transport/ssh.rb +5 -5
- data/lib/kitchen/verifier/base.rb +17 -5
- data/lib/kitchen/version.rb +1 -1
- data/lib/kitchen.rb +21 -2
- data/test-kitchen.gemspec +1 -1
- metadata +12 -4
data/lib/kitchen/logger.rb
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
|
|
18
18
|
require "fileutils" unless defined?(FileUtils)
|
|
19
|
-
require "
|
|
19
|
+
require "json" unless defined?(JSON)
|
|
20
|
+
require "logger" unless defined?(Logger)
|
|
21
|
+
require "time" unless defined?(Time)
|
|
20
22
|
|
|
21
23
|
module Kitchen
|
|
22
24
|
# Logging implementation for Kitchen. By default the console/stdout output
|
|
@@ -31,6 +33,15 @@ module Kitchen
|
|
|
31
33
|
# @return [IO] the log device
|
|
32
34
|
attr_reader :logdev
|
|
33
35
|
|
|
36
|
+
# @return [IO] the structured log device
|
|
37
|
+
attr_reader :structured_logdev
|
|
38
|
+
|
|
39
|
+
# @return [String,nil] the expanded text log path, if configured
|
|
40
|
+
attr_reader :logdev_path
|
|
41
|
+
|
|
42
|
+
# @return [String,nil] the expanded structured log path, if configured
|
|
43
|
+
attr_reader :structured_logdev_path
|
|
44
|
+
|
|
34
45
|
# @return [Boolean] whether logger is configured for
|
|
35
46
|
# overwriting
|
|
36
47
|
attr_reader :log_overwrite
|
|
@@ -55,13 +66,23 @@ module Kitchen
|
|
|
55
66
|
# when Test Kitchen runs.
|
|
56
67
|
# (default: `$stdout.tty?`)
|
|
57
68
|
def initialize(options = {})
|
|
69
|
+
@base_metadata = options[:metadata] || {}
|
|
58
70
|
@log_overwrite = if options[:log_overwrite].nil?
|
|
59
71
|
default_log_overwrite
|
|
60
72
|
else
|
|
61
73
|
options[:log_overwrite]
|
|
62
74
|
end
|
|
63
75
|
|
|
64
|
-
@logdev = logdev_logger(options[:logdev], log_overwrite) if options[:logdev]
|
|
76
|
+
@logdev = device_factory.logdev_logger(options[:logdev], log_overwrite) if options[:logdev]
|
|
77
|
+
if options[:structured_logdev]
|
|
78
|
+
@structured_logdev = device_factory.structured_logdev_logger(
|
|
79
|
+
options[:structured_logdev],
|
|
80
|
+
log_overwrite,
|
|
81
|
+
-> { metadata }
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
@logdev_path = expanded_log_path(options[:logdev])
|
|
85
|
+
@structured_logdev_path = expanded_log_path(options[:structured_logdev])
|
|
65
86
|
|
|
66
87
|
populate_loggers(options)
|
|
67
88
|
|
|
@@ -77,10 +98,12 @@ module Kitchen
|
|
|
77
98
|
def populate_loggers(options)
|
|
78
99
|
@loggers = []
|
|
79
100
|
@loggers << logdev unless logdev.nil?
|
|
80
|
-
@loggers <<
|
|
101
|
+
@loggers << structured_logdev unless structured_logdev.nil?
|
|
102
|
+
@loggers << device_factory.stdout_logger(options[:stdout], options[:color], options[:colorize]) if
|
|
81
103
|
options[:stdout]
|
|
82
|
-
@loggers << stdout_logger($stdout, options[:color], options[:colorize]) if
|
|
104
|
+
@loggers << device_factory.stdout_logger($stdout, options[:color], options[:colorize]) if
|
|
83
105
|
@loggers.empty?
|
|
106
|
+
@sink_set = SinkSet.new(@loggers)
|
|
84
107
|
end
|
|
85
108
|
private :populate_loggers
|
|
86
109
|
|
|
@@ -91,18 +114,14 @@ module Kitchen
|
|
|
91
114
|
# @!macro delegate_to_first_logger
|
|
92
115
|
# @method $1()
|
|
93
116
|
def delegate_to_first_logger(meth)
|
|
94
|
-
define_method(meth) { |*args| @
|
|
117
|
+
define_method(meth) { |*args, &block| @sink_set.first(meth, *args, &block) }
|
|
95
118
|
end
|
|
96
119
|
|
|
97
120
|
# @api private
|
|
98
121
|
# @!macro delegate_to_all_loggers
|
|
99
122
|
# @method $1()
|
|
100
123
|
def delegate_to_all_loggers(meth)
|
|
101
|
-
define_method(meth)
|
|
102
|
-
result = nil
|
|
103
|
-
@loggers.each { |l| result = l.public_send(meth, *args) }
|
|
104
|
-
result
|
|
105
|
-
end
|
|
124
|
+
define_method(meth) { |*args, &block| @sink_set.all(meth, *args, &block) }
|
|
106
125
|
end
|
|
107
126
|
end
|
|
108
127
|
|
|
@@ -268,6 +287,23 @@ module Kitchen
|
|
|
268
287
|
# @see http://is.gd/b13cVn
|
|
269
288
|
delegate_to_all_loggers :close
|
|
270
289
|
|
|
290
|
+
# @return [Hash] metadata added to structured log events
|
|
291
|
+
def metadata
|
|
292
|
+
metadata_stack.inject(@base_metadata.dup) do |result, values|
|
|
293
|
+
result.merge(values)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Temporarily adds metadata to structured log events.
|
|
298
|
+
#
|
|
299
|
+
# @param values [Hash] metadata fields to add for the block duration
|
|
300
|
+
def with_metadata(values)
|
|
301
|
+
metadata_stack.push(values.compact)
|
|
302
|
+
yield
|
|
303
|
+
ensure
|
|
304
|
+
metadata_stack.pop
|
|
305
|
+
end
|
|
306
|
+
|
|
271
307
|
private
|
|
272
308
|
|
|
273
309
|
# @return [Integer] the default logger level
|
|
@@ -282,54 +318,188 @@ module Kitchen
|
|
|
282
318
|
Kitchen::DEFAULT_LOG_OVERWRITE
|
|
283
319
|
end
|
|
284
320
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
321
|
+
def device_factory
|
|
322
|
+
@device_factory ||= DeviceFactory.new
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def expanded_log_path(logdev)
|
|
326
|
+
File.expand_path(logdev) if logdev.is_a?(String)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def metadata_stack
|
|
330
|
+
Thread.current[metadata_stack_key] ||= []
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def metadata_stack_key
|
|
334
|
+
@metadata_stack_key ||= :"kitchen_logger_metadata_#{object_id}"
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Internal composite for forwarding stdlib Logger-compatible calls to all
|
|
338
|
+
# configured logging sinks.
|
|
339
|
+
class SinkSet
|
|
340
|
+
def initialize(loggers)
|
|
341
|
+
@loggers = loggers
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def first(meth, *args, &block)
|
|
345
|
+
@loggers.first.public_send(meth, *args, &block)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def all(meth, *args, &block)
|
|
349
|
+
result = nil
|
|
350
|
+
block = memoized_block(block) if block
|
|
351
|
+
@loggers.each { |logger| result = logger.public_send(meth, *args, &block) }
|
|
352
|
+
result
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
private
|
|
356
|
+
|
|
357
|
+
def memoized_block(block)
|
|
358
|
+
evaluated = false
|
|
359
|
+
value = nil
|
|
360
|
+
proc do
|
|
361
|
+
unless evaluated
|
|
362
|
+
value = block.call
|
|
363
|
+
evaluated = true
|
|
364
|
+
end
|
|
365
|
+
value
|
|
297
366
|
end
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# Internal factory for building the concrete logger devices.
|
|
371
|
+
class DeviceFactory
|
|
372
|
+
# Construct a new standard out logger.
|
|
373
|
+
#
|
|
374
|
+
# @param stdout [IO] the IO object that represents stdout (or similar)
|
|
375
|
+
# @param color [Symbol] color to use when outputting messages
|
|
376
|
+
# @param colorize [Boolean] whether to enable color
|
|
377
|
+
# @return [StdoutLogger] a new logger
|
|
378
|
+
# @api private
|
|
379
|
+
def stdout_logger(stdout, color, colorize)
|
|
380
|
+
logger = StdoutLogger.new(stdout)
|
|
381
|
+
logger.formatter = stdout_formatter(color, colorize)
|
|
382
|
+
logger
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# Construct a new logdev logger.
|
|
386
|
+
#
|
|
387
|
+
# @param filepath_or_logdev [String,IO] a filepath String or IO object
|
|
388
|
+
# @param log_overwrite [Boolean] apply log overwriting
|
|
389
|
+
# if filepath_or_logdev is a file path
|
|
390
|
+
# @return [LogdevLogger] a new logger
|
|
391
|
+
# @api private
|
|
392
|
+
def logdev_logger(filepath_or_logdev, log_overwrite)
|
|
393
|
+
LogdevLogger.new(resolve_logdev(filepath_or_logdev, log_overwrite))
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# Construct a new structured logdev logger.
|
|
397
|
+
#
|
|
398
|
+
# @param filepath_or_logdev [String,IO] a filepath String or IO object
|
|
399
|
+
# @param log_overwrite [Boolean] apply log overwriting
|
|
400
|
+
# if filepath_or_logdev is a file path
|
|
401
|
+
# @param metadata_provider [Proc] callable returning structured metadata
|
|
402
|
+
# @return [StructuredLogdevLogger] a new logger
|
|
403
|
+
# @api private
|
|
404
|
+
def structured_logdev_logger(filepath_or_logdev, log_overwrite, metadata_provider)
|
|
405
|
+
StructuredLogdevLogger.new(
|
|
406
|
+
resolve_logdev(filepath_or_logdev, log_overwrite),
|
|
407
|
+
metadata_provider
|
|
408
|
+
)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
private
|
|
412
|
+
|
|
413
|
+
def stdout_formatter(color, colorize)
|
|
414
|
+
if colorize
|
|
415
|
+
proc do |_severity, _datetime, _progname, msg|
|
|
416
|
+
Color.colorize(msg.dup.to_s, color).concat("\n")
|
|
417
|
+
end
|
|
418
|
+
else
|
|
419
|
+
proc do |_severity, _datetime, _progname, msg|
|
|
420
|
+
msg.dup.concat("\n")
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Return an IO object from a filepath String or the IO object itself.
|
|
426
|
+
#
|
|
427
|
+
# @param filepath_or_logdev [String,IO] a filepath String or IO object
|
|
428
|
+
# @param log_overwrite [Boolean] apply log overwriting
|
|
429
|
+
# if filepath_or_logdev is a file path
|
|
430
|
+
# @return [IO] an IO object
|
|
431
|
+
# @api private
|
|
432
|
+
def resolve_logdev(filepath_or_logdev, log_overwrite)
|
|
433
|
+
if filepath_or_logdev.is_a? String
|
|
434
|
+
mode = log_overwrite ? "wb" : "ab"
|
|
435
|
+
FileUtils.mkdir_p(File.dirname(filepath_or_logdev))
|
|
436
|
+
file = File.open(File.expand_path(filepath_or_logdev), mode)
|
|
437
|
+
file.sync = true
|
|
438
|
+
file
|
|
439
|
+
else
|
|
440
|
+
filepath_or_logdev
|
|
301
441
|
end
|
|
302
442
|
end
|
|
303
|
-
logger
|
|
304
443
|
end
|
|
305
444
|
|
|
306
|
-
#
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
445
|
+
# Buffers streamed output until a complete line is available for logging.
|
|
446
|
+
class LineBuffer
|
|
447
|
+
def initialize(&line_handler)
|
|
448
|
+
@buffer = +""
|
|
449
|
+
@line_handler = line_handler
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def <<(msg)
|
|
453
|
+
@buffer += msg
|
|
454
|
+
flush_lines
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
private
|
|
458
|
+
|
|
459
|
+
def flush_lines
|
|
460
|
+
while (i = @buffer.index("\n"))
|
|
461
|
+
@line_handler.call(@buffer[0, i].chomp)
|
|
462
|
+
@buffer[0, i + 1] = ""
|
|
463
|
+
end
|
|
464
|
+
end
|
|
315
465
|
end
|
|
316
466
|
|
|
317
|
-
#
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
467
|
+
# Rewrites already-prefixed stream lines into the matching logger call.
|
|
468
|
+
class StreamLineFormatter
|
|
469
|
+
def initialize(logger)
|
|
470
|
+
@logger = logger
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
def format(line)
|
|
474
|
+
case line
|
|
475
|
+
when /^-----> / then log_line(:banner, line.gsub(/^[ >-]{6} /, ""))
|
|
476
|
+
when /^D / then structured_line(:debug, line.gsub(/^D {6}/, ""), line)
|
|
477
|
+
when /^\$\$\$\$\$\$ / then structured_line(:warn, line.gsub(/^\${6} /, ""), line)
|
|
478
|
+
when /^>>>>>> / then log_line(:error, line.gsub(/^[ >-]{6} /, ""))
|
|
479
|
+
when /^!!!!!! / then structured_line(:fatal, line.gsub(/^!{6} /, ""), line)
|
|
480
|
+
when /^ / then log_line(:info, line.gsub(/^[ >-]{6} /, ""))
|
|
481
|
+
else log_line(:info, line)
|
|
482
|
+
end
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
private
|
|
486
|
+
|
|
487
|
+
def log_line(severity, message)
|
|
488
|
+
if severity == :banner
|
|
489
|
+
@logger.banner(message)
|
|
490
|
+
elsif @logger.respond_to?(:stream)
|
|
491
|
+
@logger.stream(severity, message)
|
|
492
|
+
else
|
|
493
|
+
@logger.public_send(severity, message)
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def structured_line(severity, message, original)
|
|
498
|
+
if @logger.respond_to?(:stream)
|
|
499
|
+
@logger.stream(severity, message)
|
|
500
|
+
else
|
|
501
|
+
@logger.info(original)
|
|
502
|
+
end
|
|
333
503
|
end
|
|
334
504
|
end
|
|
335
505
|
|
|
@@ -342,35 +512,174 @@ module Kitchen
|
|
|
342
512
|
#
|
|
343
513
|
# @param msg [String] a message
|
|
344
514
|
def <<(msg)
|
|
345
|
-
|
|
346
|
-
@buffer += msg
|
|
347
|
-
while (i = @buffer.index("\n"))
|
|
348
|
-
format_line(@buffer[0, i].chomp)
|
|
349
|
-
@buffer[0, i + 1] = ""
|
|
350
|
-
end
|
|
515
|
+
line_buffer << msg
|
|
351
516
|
end
|
|
352
517
|
|
|
353
518
|
# Log a banner message.
|
|
354
519
|
#
|
|
355
520
|
# @param msg [String] a message
|
|
356
521
|
def banner(msg = nil, &block)
|
|
357
|
-
|
|
522
|
+
if block
|
|
523
|
+
super_info(nil) { "-----> #{block.call}" }
|
|
524
|
+
else
|
|
525
|
+
super_info("-----> #{msg}")
|
|
526
|
+
end
|
|
358
527
|
end
|
|
359
528
|
|
|
360
529
|
private
|
|
361
530
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
531
|
+
def line_buffer
|
|
532
|
+
formatter = StreamLineFormatter.new(self)
|
|
533
|
+
@line_buffer ||= LineBuffer.new do |line|
|
|
534
|
+
formatter.format(line)
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
# Internal class that emits one JSON object per log event.
|
|
540
|
+
class StructuredLogdevLogger
|
|
541
|
+
include ::Logger::Severity
|
|
542
|
+
|
|
543
|
+
SEVERITY_NAMES = {
|
|
544
|
+
DEBUG => "debug",
|
|
545
|
+
INFO => "info",
|
|
546
|
+
WARN => "warn",
|
|
547
|
+
ERROR => "error",
|
|
548
|
+
FATAL => "fatal",
|
|
549
|
+
UNKNOWN => "unknown",
|
|
550
|
+
}.freeze
|
|
551
|
+
|
|
552
|
+
attr_accessor :level
|
|
553
|
+
attr_accessor :progname
|
|
554
|
+
attr_accessor :datetime_format
|
|
555
|
+
|
|
556
|
+
def initialize(logdev, metadata_provider)
|
|
557
|
+
@logdev = logdev
|
|
558
|
+
@metadata_provider = metadata_provider
|
|
559
|
+
@level = INFO
|
|
560
|
+
@progname = "Kitchen"
|
|
561
|
+
@sequence = 0
|
|
562
|
+
@mutex = Mutex.new
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
def add(severity, message = nil, progname = nil)
|
|
566
|
+
severity ||= UNKNOWN
|
|
567
|
+
return true if severity < level
|
|
568
|
+
|
|
569
|
+
message = if message.nil?
|
|
570
|
+
block_given? ? yield : progname
|
|
571
|
+
else
|
|
572
|
+
message
|
|
573
|
+
end
|
|
574
|
+
write_event(severity, message, "log")
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def <<(msg)
|
|
578
|
+
line_buffer << msg
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
def banner(msg = nil)
|
|
582
|
+
message = block_given? ? yield : msg
|
|
583
|
+
write_event(INFO, message, "banner") unless INFO < level
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
def stream(severity, msg)
|
|
587
|
+
severity = severity_const(severity)
|
|
588
|
+
write_event(severity, msg, "stream") unless severity < level
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
def debug(msg = nil, &block)
|
|
592
|
+
add(DEBUG, msg, nil, &block)
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
def info(msg = nil, &block)
|
|
596
|
+
add(INFO, msg, nil, &block)
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
def warn(msg = nil, &block)
|
|
600
|
+
add(WARN, msg, nil, &block)
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
def error(msg = nil, &block)
|
|
604
|
+
add(ERROR, msg, nil, &block)
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
def fatal(msg = nil, &block)
|
|
608
|
+
add(FATAL, msg, nil, &block)
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
def unknown(msg = nil, &block)
|
|
612
|
+
add(UNKNOWN, msg, nil, &block)
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
def debug?
|
|
616
|
+
level <= DEBUG
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
def info?
|
|
620
|
+
level <= INFO
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
def warn?
|
|
624
|
+
level <= WARN
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
def error?
|
|
628
|
+
level <= ERROR
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
def fatal?
|
|
632
|
+
level <= FATAL
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
def close
|
|
636
|
+
return unless @logdev.respond_to?(:close)
|
|
637
|
+
|
|
638
|
+
if @logdev.respond_to?(:closed?)
|
|
639
|
+
@logdev.close unless @logdev.closed?
|
|
640
|
+
else
|
|
641
|
+
@logdev.close
|
|
642
|
+
end
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
private
|
|
646
|
+
|
|
647
|
+
def line_buffer
|
|
648
|
+
formatter = StreamLineFormatter.new(self)
|
|
649
|
+
@line_buffer ||= LineBuffer.new do |line|
|
|
650
|
+
formatter.format(line)
|
|
372
651
|
end
|
|
373
652
|
end
|
|
653
|
+
|
|
654
|
+
def next_sequence
|
|
655
|
+
@sequence += 1
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
def severity_const(severity)
|
|
659
|
+
return severity if severity.is_a?(Integer)
|
|
660
|
+
|
|
661
|
+
::Logger.const_get(severity.to_s.upcase)
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
def severity_name(severity)
|
|
665
|
+
SEVERITY_NAMES.fetch(severity, "unknown")
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
def write_event(severity, message, event_type)
|
|
669
|
+
@mutex.synchronize do
|
|
670
|
+
event = @metadata_provider.call.merge(
|
|
671
|
+
timestamp: Time.now.utc.iso8601(6),
|
|
672
|
+
level: severity_name(severity),
|
|
673
|
+
event_type:,
|
|
674
|
+
message: message.to_s,
|
|
675
|
+
progname:,
|
|
676
|
+
sequence: next_sequence
|
|
677
|
+
).compact
|
|
678
|
+
@logdev.write(JSON.generate(event))
|
|
679
|
+
@logdev.write("\n")
|
|
680
|
+
end
|
|
681
|
+
true
|
|
682
|
+
end
|
|
374
683
|
end
|
|
375
684
|
|
|
376
685
|
# Internal class which reformats logging methods for display as console
|
|
@@ -380,42 +689,66 @@ module Kitchen
|
|
|
380
689
|
#
|
|
381
690
|
# @param msg [String] a message
|
|
382
691
|
def debug(msg = nil, &block)
|
|
383
|
-
|
|
692
|
+
if block
|
|
693
|
+
super(nil) { "D #{block.call}" }
|
|
694
|
+
else
|
|
695
|
+
super("D #{msg}")
|
|
696
|
+
end
|
|
384
697
|
end
|
|
385
698
|
|
|
386
699
|
# Log an info message
|
|
387
700
|
#
|
|
388
701
|
# @param msg [String] a message
|
|
389
702
|
def info(msg = nil, &block)
|
|
390
|
-
|
|
703
|
+
if block
|
|
704
|
+
super(nil) { " #{block.call}" }
|
|
705
|
+
else
|
|
706
|
+
super(" #{msg}")
|
|
707
|
+
end
|
|
391
708
|
end
|
|
392
709
|
|
|
393
710
|
# Log a warn message
|
|
394
711
|
#
|
|
395
712
|
# @param msg [String] a message
|
|
396
713
|
def warn(msg = nil, &block)
|
|
397
|
-
|
|
714
|
+
if block
|
|
715
|
+
super(nil) { "$$$$$$ #{block.call}" }
|
|
716
|
+
else
|
|
717
|
+
super("$$$$$$ #{msg}")
|
|
718
|
+
end
|
|
398
719
|
end
|
|
399
720
|
|
|
400
721
|
# Log an error message
|
|
401
722
|
#
|
|
402
723
|
# @param msg [String] a message
|
|
403
724
|
def error(msg = nil, &block)
|
|
404
|
-
|
|
725
|
+
if block
|
|
726
|
+
super(nil) { ">>>>>> #{block.call}" }
|
|
727
|
+
else
|
|
728
|
+
super(">>>>>> #{msg}")
|
|
729
|
+
end
|
|
405
730
|
end
|
|
406
731
|
|
|
407
732
|
# Log a fatal message
|
|
408
733
|
#
|
|
409
734
|
# @param msg [String] a message
|
|
410
735
|
def fatal(msg = nil, &block)
|
|
411
|
-
|
|
736
|
+
if block
|
|
737
|
+
super(nil) { "!!!!!! #{block.call}" }
|
|
738
|
+
else
|
|
739
|
+
super("!!!!!! #{msg}")
|
|
740
|
+
end
|
|
412
741
|
end
|
|
413
742
|
|
|
414
743
|
# Log an unknown message
|
|
415
744
|
#
|
|
416
745
|
# @param msg [String] a message
|
|
417
746
|
def unknown(msg = nil, &block)
|
|
418
|
-
|
|
747
|
+
if block
|
|
748
|
+
super(nil) { "?????? #{block.call}" }
|
|
749
|
+
else
|
|
750
|
+
super("?????? #{msg}")
|
|
751
|
+
end
|
|
419
752
|
end
|
|
420
753
|
end
|
|
421
754
|
end
|
data/lib/kitchen/logging.rb
CHANGED
|
@@ -36,8 +36,8 @@ module Kitchen
|
|
|
36
36
|
# @return [nil,true] when the given severity is not high enough (for
|
|
37
37
|
# this particular logger), log no message, and return true
|
|
38
38
|
def logger_method(meth)
|
|
39
|
-
define_method(meth) do |*args|
|
|
40
|
-
logger.public_send(meth, *args)
|
|
39
|
+
define_method(meth) do |*args, &block|
|
|
40
|
+
logger.public_send(meth, *args, &block)
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
end
|
|
@@ -105,18 +105,33 @@ module Kitchen
|
|
|
105
105
|
debug("Executing prepare command: #{prepare_command}")
|
|
106
106
|
conn.execute(prepare_command)
|
|
107
107
|
debug("Executing run command: #{run_command}")
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
108
|
+
begin
|
|
109
|
+
conn.execute_with_retry(
|
|
110
|
+
encode_for_powershell(run_command),
|
|
111
|
+
config[:retry_on_exit_code],
|
|
112
|
+
config[:max_retries],
|
|
113
|
+
config[:wait_for_retry]
|
|
114
|
+
)
|
|
115
|
+
ensure
|
|
116
|
+
# Retrieval is best-effort: a file we could not fetch must not
|
|
117
|
+
# fail an otherwise successful converge, and must never replace
|
|
118
|
+
# an error already in flight from the run command. A transport
|
|
119
|
+
# that cannot download at all is a bug, not a missing file, so
|
|
120
|
+
# it still raises when there is no converge error to protect.
|
|
121
|
+
run_error = $!
|
|
122
|
+
begin
|
|
123
|
+
info("Downloading files from #{instance.to_str}")
|
|
124
|
+
config[:downloads].to_h.each do |remotes, local|
|
|
125
|
+
debug("Downloading #{Array(remotes).join(", ")} to #{local}")
|
|
126
|
+
conn.download(remotes, local)
|
|
127
|
+
end
|
|
128
|
+
debug("Download complete")
|
|
129
|
+
rescue => ex
|
|
130
|
+
raise unless run_error || ex.is_a?(Kitchen::Transport::TransportFailed)
|
|
131
|
+
|
|
132
|
+
warn("Failed to download files from #{instance.to_str}: #{ex.message}")
|
|
133
|
+
end
|
|
118
134
|
end
|
|
119
|
-
debug("Download complete")
|
|
120
135
|
end
|
|
121
136
|
rescue Kitchen::Transport::TransportFailed => ex
|
|
122
137
|
raise ActionFailed, ex.message
|
|
@@ -339,13 +354,8 @@ module Kitchen
|
|
|
339
354
|
|
|
340
355
|
# Replace $env:TEMP with the actual Windows temp directory based on the transport username
|
|
341
356
|
if resolved_path.include?("$env:TEMP")
|
|
342
|
-
# Try to get username from transport configuration
|
|
343
357
|
# For Windows systems, fallback to "Administrator" if not found
|
|
344
|
-
username =
|
|
345
|
-
instance.transport[:username]
|
|
346
|
-
rescue
|
|
347
|
-
nil
|
|
348
|
-
end
|
|
358
|
+
username = instance.transport[:username] if instance.transport.respond_to?(:[])
|
|
349
359
|
username ||= "Administrator"
|
|
350
360
|
|
|
351
361
|
temp_path = "C:/Users/#{username}/AppData/Local/Temp"
|