mux_tf 0.15.0 → 0.16.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/lib/mux_tf/cli/current/plan_command.rb +123 -0
- data/lib/mux_tf/cli/current.rb +92 -171
- data/lib/mux_tf/cli/mux.rb +168 -5
- data/lib/mux_tf/cli/plan_summary.rb +12 -21
- data/lib/mux_tf/error_handling_methods.rb +79 -0
- data/lib/mux_tf/handlers/plan_handler.rb +8 -0
- data/lib/mux_tf/handlers.rb +6 -0
- data/lib/mux_tf/plan_formatter.rb +285 -257
- data/lib/mux_tf/plan_summary_handler.rb +36 -29
- data/lib/mux_tf/plan_utils.rb +20 -4
- data/lib/mux_tf/resource_tokenizer.rb +1 -1
- data/lib/mux_tf/stderr_line_handler.rb +145 -0
- data/lib/mux_tf/terraform_helpers.rb +44 -6
- data/lib/mux_tf/tmux.rb +55 -6
- data/lib/mux_tf/version.rb +1 -1
- data/lib/mux_tf/version_check.rb +1 -1
- data/lib/mux_tf.rb +6 -12
- data/mux_tf.gemspec +7 -1
- metadata +69 -8
@@ -6,11 +6,9 @@ module MuxTf
|
|
6
6
|
extend PiotrbCliUtils::Util
|
7
7
|
include Coloring
|
8
8
|
|
9
|
-
|
10
|
-
def log_unhandled_line(state, line, reason: nil)
|
11
|
-
p [state, pastel.strip(line), reason]
|
12
|
-
end
|
9
|
+
extend ErrorHandlingMethods
|
13
10
|
|
11
|
+
class << self
|
14
12
|
def pretty_plan(filename, targets: [])
|
15
13
|
if ENV["JSON_PLAN"]
|
16
14
|
pretty_plan_v2(filename, targets: targets)
|
@@ -44,7 +42,6 @@ module MuxTf
|
|
44
42
|
result
|
45
43
|
end
|
46
44
|
|
47
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
48
45
|
def tf_plan_json(out:, targets: [], &block)
|
49
46
|
emit_line = proc { |result|
|
50
47
|
result[:level] ||= result[:stream] == :stderr ? "error" : "info"
|
@@ -84,11 +81,11 @@ module MuxTf
|
|
84
81
|
status = tf_plan(out: out, detailed_exitcode: true, color: true, compact_warnings: false, json: true, input: false,
|
85
82
|
targets: targets) { |(stream, raw_line)|
|
86
83
|
case stream
|
87
|
-
|
88
|
-
|
84
|
+
when :command
|
85
|
+
log "Running command: #{raw_line.strip} ...", depth: 2
|
89
86
|
when :stdout
|
90
87
|
parsed_line = JSON.parse(raw_line)
|
91
|
-
parsed_line.keys.each do |key|
|
88
|
+
parsed_line.keys.each do |key|
|
92
89
|
if key[0] == "@"
|
93
90
|
parsed_line[key[1..]] = parsed_line[key]
|
94
91
|
parsed_line.delete(key)
|
@@ -129,7 +126,6 @@ module MuxTf
|
|
129
126
|
emit_line.call(last_stderr_line) if last_stderr_line
|
130
127
|
status
|
131
128
|
end
|
132
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
133
129
|
|
134
130
|
def parse_lock_info(detail)
|
135
131
|
# Lock Info:
|
@@ -174,7 +170,7 @@ module MuxTf
|
|
174
170
|
log log_line
|
175
171
|
end
|
176
172
|
|
177
|
-
# rubocop:disable Metrics/AbcSize
|
173
|
+
# rubocop:disable Metrics/AbcSize
|
178
174
|
def pretty_plan_v2(filename, targets: [])
|
179
175
|
meta = {}
|
180
176
|
meta[:seen] = {
|
@@ -350,26 +346,27 @@ module MuxTf
|
|
350
346
|
}
|
351
347
|
[status.status, meta]
|
352
348
|
end
|
353
|
-
# rubocop:enable Metrics/AbcSize
|
354
|
-
|
355
|
-
def pretty_plan_v1(filename, targets: []) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
356
|
-
meta = {}
|
349
|
+
# rubocop:enable Metrics/AbcSize
|
357
350
|
|
358
|
-
|
351
|
+
def setup_plan_v1_parser(parser)
|
359
352
|
parser.state(:info, /^Acquiring state lock/)
|
360
353
|
parser.state(:error, /(Error locking state|Error:)/, [:none, :blank, :info, :reading])
|
361
354
|
parser.state(:reading, /: (Reading...|Read complete after)/, [:none, :info, :reading])
|
362
355
|
parser.state(:none, /^$/, [:reading])
|
363
|
-
parser.state(:refreshing, /^.+: Refreshing state... \[id=/, [:none, :info, :reading])
|
356
|
+
parser.state(:refreshing, /^.+: Refreshing state... \[id=/, [:none, :info, :reading, :import])
|
364
357
|
parser.state(:refreshing, /Refreshing Terraform state in-memory prior to plan.../,
|
365
358
|
[:none, :blank, :info, :reading])
|
366
359
|
parser.state(:none, /^----------+$/, [:refreshing])
|
367
360
|
parser.state(:none, /^$/, [:refreshing])
|
368
361
|
|
362
|
+
parser.state(:import, /".+: Preparing import... \[id=.+\]$/, [:none, :import])
|
363
|
+
parser.state(:none, /^$/, [:import])
|
364
|
+
|
369
365
|
parser.state(:output_info, /^Changes to Outputs:$/, [:none])
|
370
366
|
parser.state(:none, /^$/, [:output_info])
|
371
367
|
|
372
368
|
parser.state(:plan_info, /Terraform will perform the following actions:/, [:none])
|
369
|
+
parser.state(:plan_info, /You can apply this plan to save these new output values to the Terraform/, [:none])
|
373
370
|
parser.state(:plan_summary, /^Plan:/, [:plan_info])
|
374
371
|
|
375
372
|
parser.state(:plan_legend, /^Terraform used the selected providers to generate the following execution$/)
|
@@ -378,94 +375,146 @@ module MuxTf
|
|
378
375
|
parser.state(:plan_info, /Terraform planned the following actions, but then encountered a problem:/, [:none])
|
379
376
|
parser.state(:plan_info, /No changes. Your infrastructure matches the configuration./, [:none])
|
380
377
|
|
381
|
-
parser.state(:plan_error, /Planning failed. Terraform encountered an error while generating this plan./, [:refreshing])
|
378
|
+
parser.state(:plan_error, /Planning failed. Terraform encountered an error while generating this plan./, [:refreshing, :none])
|
382
379
|
|
383
380
|
# this extends the error block to include the lock info
|
384
381
|
parser.state(:error_lock_info, /Lock Info/, [:error_block_error])
|
385
382
|
parser.state(:after_error, /^╵/, [:error_lock_info])
|
383
|
+
end
|
386
384
|
|
387
|
-
|
385
|
+
def handle_plan_v1_line(state, line, meta, first_in_state:, stripped_line:)
|
386
|
+
case state
|
387
|
+
when :none
|
388
|
+
if line.blank?
|
389
|
+
# nothing
|
390
|
+
elsif stripped_line.match(/Error when retrieving token from sso/) || stripped_line.match(/Error loading SSO Token/)
|
391
|
+
meta[:need_auth] = true
|
392
|
+
log pastel.red("authentication problem"), depth: 2
|
393
|
+
else
|
394
|
+
log_unhandled_line(state, line, reason: "unexpected non blank line in :none state")
|
395
|
+
end
|
396
|
+
when :reading
|
397
|
+
if stripped_line.match(/^(.+): Reading...$/)
|
398
|
+
log "Reading: #{$LAST_MATCH_INFO[1]} ...", depth: 2
|
399
|
+
elsif stripped_line.match(/^(.+): Read complete after ([^\[]+)(?: \[(.+)\])?$/)
|
400
|
+
if $LAST_MATCH_INFO[3]
|
401
|
+
log "Reading Complete: #{$LAST_MATCH_INFO[1]} after #{$LAST_MATCH_INFO[2]} [#{$LAST_MATCH_INFO[3]}]", depth: 3
|
402
|
+
else
|
403
|
+
log "Reading Complete: #{$LAST_MATCH_INFO[1]} after #{$LAST_MATCH_INFO[2]}", depth: 3
|
404
|
+
end
|
405
|
+
else
|
406
|
+
log_unhandled_line(state, line, reason: "unexpected line in :reading state")
|
407
|
+
end
|
408
|
+
when :import
|
409
|
+
# github_repository_topics.this[\"tf-k8s-infra-modules\"]: Preparing import... [id=tf-k8s-infra-modules]
|
410
|
+
matches = stripped_line.match(/^(?<resource>.+): Preparing import... \[id=(?<id>.+)\]$/)
|
411
|
+
if matches
|
412
|
+
log "Importing #{pastel.cyan(matches[:resource])} (id=#{pastel.yellow(matches[:id])}) ...", depth: 2
|
413
|
+
else
|
414
|
+
p [:import, "couldn't parse line:", stripped_line]
|
415
|
+
end
|
416
|
+
when :info
|
417
|
+
if /Acquiring state lock. This may take a few moments.../.match?(line)
|
418
|
+
log "Acquiring state lock ...", depth: 2
|
419
|
+
else
|
420
|
+
log_unhandled_line(state, line, reason: "unexpected line in :info state")
|
421
|
+
end
|
422
|
+
when :plan_error
|
423
|
+
case pastel.strip(line)
|
424
|
+
when ""
|
425
|
+
# skip empty line
|
426
|
+
when /Releasing state lock. This may take a few moments"/
|
427
|
+
log line, depth: 2
|
428
|
+
when /Planning failed./ # rubocop:disable Lint/DuplicateBranch
|
429
|
+
log line, depth: 2
|
430
|
+
else
|
431
|
+
log_unhandled_line(state, line, reason: "unexpected line in :plan_error state")
|
432
|
+
end
|
433
|
+
when :error_lock_info
|
434
|
+
meta["error"] = "lock"
|
435
|
+
meta[$LAST_MATCH_INFO[1]] = $LAST_MATCH_INFO[2] if line =~ /([A-Z]+\S+)+:\s+(.+)$/
|
436
|
+
if stripped_line == ""
|
437
|
+
meta[:current_error][:body] << stripped_line if meta[:current_error][:body].last != ""
|
438
|
+
else
|
439
|
+
meta[:current_error][:body] << stripped_line
|
440
|
+
end
|
441
|
+
when :refreshing
|
442
|
+
if first_in_state
|
443
|
+
log "Refreshing state ", depth: 2, newline: false
|
444
|
+
else
|
445
|
+
print "."
|
446
|
+
end
|
447
|
+
when :plan_legend
|
448
|
+
puts if first_in_state
|
449
|
+
log line, depth: 2
|
450
|
+
when :refresh_done
|
451
|
+
puts if first_in_state
|
452
|
+
when :plan_info # rubocop:disable Lint/DuplicateBranch
|
453
|
+
puts if first_in_state
|
454
|
+
log line, depth: 2
|
455
|
+
when :output_info # rubocop:disable Lint/DuplicateBranch
|
456
|
+
puts if first_in_state
|
457
|
+
log line, depth: 2
|
458
|
+
when :plan_summary
|
459
|
+
log line, depth: 2
|
460
|
+
else
|
461
|
+
return false
|
462
|
+
end
|
463
|
+
true
|
464
|
+
end
|
465
|
+
|
466
|
+
def pretty_plan_v1(filename, targets: [])
|
467
|
+
meta = {}
|
468
|
+
init_phase = :none
|
469
|
+
|
470
|
+
parser = StatefulParser.new(normalizer: pastel.method(:strip))
|
471
|
+
|
472
|
+
setup_init_parser(parser)
|
473
|
+
setup_plan_v1_parser(parser)
|
474
|
+
|
475
|
+
setup_error_handling(parser,
|
476
|
+
from_states: [:plan_error, :none, :blank, :info, :reading, :plan_summary, :refreshing] + [:plugins, :modules_init])
|
388
477
|
|
389
478
|
last_state = nil
|
390
479
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
if $LAST_MATCH_INFO[3]
|
411
|
-
log "Reading Complete: #{$LAST_MATCH_INFO[1]} after #{$LAST_MATCH_INFO[2]} [#{$LAST_MATCH_INFO[3]}]", depth: 3
|
412
|
-
else
|
413
|
-
log "Reading Complete: #{$LAST_MATCH_INFO[1]} after #{$LAST_MATCH_INFO[2]}", depth: 3
|
414
|
-
end
|
415
|
-
else
|
416
|
-
log_unhandled_line(state, line, reason: "unexpected line in :reading state")
|
417
|
-
end
|
418
|
-
when :info
|
419
|
-
if /Acquiring state lock. This may take a few moments.../.match?(line)
|
420
|
-
log "Acquiring state lock ...", depth: 2
|
421
|
-
else
|
422
|
-
log_unhandled_line(state, line, reason: "unexpected line in :info state")
|
423
|
-
end
|
424
|
-
when :plan_error
|
425
|
-
case pastel.strip(line)
|
426
|
-
when ""
|
427
|
-
# skip empty line
|
428
|
-
when /Releasing state lock. This may take a few moments"/
|
429
|
-
log line, depth: 2
|
430
|
-
when /Planning failed./ # rubocop:disable Lint/DuplicateBranch
|
431
|
-
log line, depth: 2
|
432
|
-
else
|
433
|
-
log_unhandled_line(state, line, reason: "unexpected line in :plan_error state")
|
434
|
-
end
|
435
|
-
when :error_lock_info
|
436
|
-
meta["error"] = "lock"
|
437
|
-
meta[$LAST_MATCH_INFO[1]] = $LAST_MATCH_INFO[2] if line =~ /([A-Z]+\S+)+:\s+(.+)$/
|
438
|
-
clean_line = pastel.strip(line).gsub(/^│ /, "")
|
439
|
-
if clean_line == ""
|
440
|
-
meta[:current_error][:body] << clean_line if meta[:current_error][:body].last != ""
|
441
|
-
else
|
442
|
-
meta[:current_error][:body] << clean_line
|
443
|
-
end
|
444
|
-
when :refreshing
|
445
|
-
if first_in_state
|
446
|
-
log "Refreshing state ", depth: 2, newline: false
|
480
|
+
stderr_handler = StderrLineHandler.new(operation: :plan)
|
481
|
+
|
482
|
+
status = tf_plan(out: filename, detailed_exitcode: true, compact_warnings: true, targets: targets, split_streams: true) { |(stream, raw_line)|
|
483
|
+
case stream
|
484
|
+
when :command
|
485
|
+
log "Running command: #{raw_line.strip} ...", depth: 2
|
486
|
+
when :stderr
|
487
|
+
stderr_handler.handle(raw_line)
|
488
|
+
when :stdout
|
489
|
+
stripped_line = pastel.strip(raw_line.rstrip)
|
490
|
+
parser.parse(raw_line.rstrip) do |state, line|
|
491
|
+
first_in_state = last_state != state
|
492
|
+
|
493
|
+
if (handled = handle_plan_v1_line(state, line, meta, first_in_state: first_in_state, stripped_line: stripped_line))
|
494
|
+
# great!
|
495
|
+
elsif (handled = handle_init_line(state, line, meta, phase: init_phase, stripped_line: stripped_line))
|
496
|
+
init_phase = handled[:phase]
|
497
|
+
elsif handle_error_states(meta, state, line)
|
498
|
+
# no-op
|
447
499
|
else
|
448
|
-
|
500
|
+
log_unhandled_line(state, line, reason: "unexpected state")
|
449
501
|
end
|
450
|
-
|
451
|
-
|
452
|
-
log line, depth: 2
|
453
|
-
when :refresh_done
|
454
|
-
puts if first_in_state
|
455
|
-
when :plan_info # rubocop:disable Lint/DuplicateBranch
|
456
|
-
puts if first_in_state
|
457
|
-
log line, depth: 2
|
458
|
-
when :output_info # rubocop:disable Lint/DuplicateBranch
|
459
|
-
puts if first_in_state
|
460
|
-
log line, depth: 2
|
461
|
-
when :plan_summary
|
462
|
-
log line, depth: 2
|
463
|
-
else
|
464
|
-
log_unhandled_line(state, line, reason: "unexpected state") unless handle_error_states(meta, state, line)
|
502
|
+
|
503
|
+
last_state = state
|
465
504
|
end
|
466
|
-
last_state = state
|
467
505
|
end
|
468
506
|
}
|
507
|
+
|
508
|
+
stderr_handler.flush
|
509
|
+
stderr_handler.merge_meta_into(meta)
|
510
|
+
|
511
|
+
meta[:errors]&.each do |error|
|
512
|
+
if error[:message] == "Error acquiring the state lock"
|
513
|
+
meta["error"] = "lock"
|
514
|
+
meta.merge!(parse_lock_info(error[:body].join("\n")))
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
469
518
|
[status.status, meta]
|
470
519
|
end
|
471
520
|
|
@@ -475,10 +524,8 @@ module MuxTf
|
|
475
524
|
remedies << :reconfigure if meta[:need_reconfigure]
|
476
525
|
remedies << :auth if meta[:need_auth]
|
477
526
|
log "!! expected meta[:errors] to be set, how did we get here?" unless meta[:errors]
|
478
|
-
|
479
|
-
|
480
|
-
remedies << :add_provider_constraint if error[:body].grep(/Could not retrieve the list of available versions for provider/)
|
481
|
-
end
|
527
|
+
meta[:errors]&.each do |error|
|
528
|
+
remedies << :add_provider_constraint if error[:body].grep(/Could not retrieve the list of available versions for provider/)
|
482
529
|
end
|
483
530
|
if remedies.empty?
|
484
531
|
log "!! don't know how to generate init remedies for this"
|
@@ -491,193 +538,176 @@ module MuxTf
|
|
491
538
|
remedies
|
492
539
|
end
|
493
540
|
|
494
|
-
def
|
495
|
-
parser.state(:
|
496
|
-
parser.state(:
|
497
|
-
parser.state(:
|
498
|
-
parser.state(:
|
541
|
+
def setup_init_parser(parser)
|
542
|
+
parser.state(:modules_init, /^Initializing modules\.\.\./, [:none, :backend])
|
543
|
+
parser.state(:modules_upgrade, /^Upgrading modules\.\.\./)
|
544
|
+
parser.state(:backend, /^Initializing the backend\.\.\./, [:none, :modules_init, :modules_upgrade])
|
545
|
+
parser.state(:plugins, /^Initializing provider plugins\.\.\./, [:backend, :modules_init])
|
546
|
+
|
547
|
+
parser.state(:backend_error, /Error when retrieving token from sso/, [:backend])
|
548
|
+
|
549
|
+
parser.state(:plugin_warnings, /^$/, [:plugins])
|
550
|
+
parser.state(:backend_error, /Error:/, [:backend])
|
499
551
|
end
|
500
552
|
|
501
|
-
def
|
553
|
+
def handle_init_line(state, line, meta, phase:, stripped_line:)
|
502
554
|
case state
|
503
|
-
when :
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
555
|
+
when :modules_init
|
556
|
+
if phase == state
|
557
|
+
case stripped_line
|
558
|
+
when /^Downloading (?<repo>[^ ]+) (?<version>[^ ]+) for (?<module>[^ ]+)\.\.\./
|
559
|
+
print "D"
|
560
|
+
when /^Downloading (?<repo>[^ ]+) for (?<module>[^ ]+)\.\.\./ # rubocop:disable Lint/DuplicateBranch
|
561
|
+
print "D"
|
562
|
+
when /^- (?<module>[^ ]+) in (?<path>.+)$/
|
563
|
+
print "."
|
564
|
+
when ""
|
565
|
+
puts
|
566
|
+
else
|
567
|
+
log_unhandled_line(state, line, reason: "unexpected line in :modules_init state")
|
568
|
+
end
|
516
569
|
else
|
517
|
-
|
518
|
-
|
570
|
+
phase = state
|
571
|
+
log "Initializing modules ", depth: 1
|
519
572
|
end
|
520
|
-
when :
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
573
|
+
when :modules_upgrade
|
574
|
+
if phase == state
|
575
|
+
case stripped_line
|
576
|
+
when /^- (?<module>[^ ]+) in (?<path>.+)$/
|
577
|
+
print "."
|
578
|
+
when /^Downloading (?<repo>[^ ]+) (?<version>[^ ]+) for (?<module>[^ ]+)\.\.\./
|
579
|
+
print "D"
|
580
|
+
when /^Downloading (?<repo>[^ ]+) for (?<module>[^ ]+)\.\.\./ # rubocop:disable Lint/DuplicateBranch
|
581
|
+
print "D"
|
582
|
+
when ""
|
583
|
+
puts
|
584
|
+
else
|
585
|
+
log_unhandled_line(state, line, reason: "unexpected line in :modules_upgrade state")
|
526
586
|
end
|
527
|
-
|
528
|
-
|
529
|
-
|
587
|
+
else
|
588
|
+
# first line
|
589
|
+
phase = state
|
590
|
+
log "Upgrding modules ", depth: 1, newline: false
|
591
|
+
end
|
592
|
+
when :backend
|
593
|
+
if phase == state
|
594
|
+
case stripped_line
|
595
|
+
when /^Successfully configured/
|
596
|
+
log line, depth: 2
|
597
|
+
when /unless the backend/ # rubocop:disable Lint/DuplicateBranch
|
598
|
+
log line, depth: 2
|
599
|
+
when ""
|
600
|
+
puts
|
601
|
+
else
|
602
|
+
log_unhandled_line(state, line, reason: "unexpected line in :backend state")
|
530
603
|
end
|
531
|
-
|
604
|
+
else
|
605
|
+
# first line
|
606
|
+
phase = state
|
607
|
+
log "Initializing the backend ", depth: 1 # , newline: false
|
608
|
+
end
|
609
|
+
when :backend_error
|
610
|
+
if raw_line.match "terraform init -reconfigure"
|
611
|
+
meta[:need_reconfigure] = true
|
612
|
+
log pastel.red("module needs to be reconfigured"), depth: 2
|
532
613
|
end
|
614
|
+
if raw_line.match "Error when retrieving token from sso"
|
615
|
+
meta[:need_auth] = true
|
616
|
+
log pastel.red("authentication problem"), depth: 2
|
617
|
+
end
|
618
|
+
when :plugins
|
619
|
+
if phase == state
|
620
|
+
case stripped_line
|
621
|
+
when /^- Reusing previous version of (?<module>.+) from the dependency lock file$/
|
622
|
+
info = $LAST_MATCH_INFO.named_captures
|
623
|
+
log "- [FROM-LOCK] #{info['module']}", depth: 2
|
624
|
+
when /^- (?<module>.+) is built in to Terraform$/
|
625
|
+
info = $LAST_MATCH_INFO.named_captures
|
626
|
+
log "- [BUILTIN] #{info['module']}", depth: 2
|
627
|
+
when /^- Finding (?<module>[^ ]+) versions matching "(?<version>.+)"\.\.\./
|
628
|
+
info = $LAST_MATCH_INFO.named_captures
|
629
|
+
log "- [FIND] #{info['module']} matching #{info['version'].inspect}", depth: 2
|
630
|
+
when /^- Finding latest version of (?<module>.+)\.\.\.$/
|
631
|
+
info = $LAST_MATCH_INFO.named_captures
|
632
|
+
log "- [FIND] #{info['module']}", depth: 2
|
633
|
+
when /^- Installing (?<module>[^ ]+) v(?<version>.+)\.\.\.$/
|
634
|
+
info = $LAST_MATCH_INFO.named_captures
|
635
|
+
log "- [INSTALLING] #{info['module']} v#{info['version']}", depth: 2
|
636
|
+
when /^- Installed (?<module>[^ ]+) v(?<version>.+) \(signed by(?: a)? (?<signed>.+)\)$/
|
637
|
+
info = $LAST_MATCH_INFO.named_captures
|
638
|
+
log "- [INSTALLED] #{info['module']} v#{info['version']} (#{info['signed']})", depth: 2
|
639
|
+
when /^- Using previously-installed (?<module>[^ ]+) v(?<version>.+)$/
|
640
|
+
info = $LAST_MATCH_INFO.named_captures
|
641
|
+
log "- [USING] #{info['module']} v#{info['version']}", depth: 2
|
642
|
+
when /^- Downloading plugin for provider "(?<provider>[^"]+)" \((?<provider_path>[^)]+)\) (?<version>.+)\.\.\.$/
|
643
|
+
info = $LAST_MATCH_INFO.named_captures
|
644
|
+
log "- #{info['provider']} #{info['version']}", depth: 2
|
645
|
+
when /^- Using (?<provider>[^ ]+) v(?<version>.+) from the shared cache directory$/
|
646
|
+
info = $LAST_MATCH_INFO.named_captures
|
647
|
+
log "- [CACHE HIT] #{info['provider']} #{info['version']}", depth: 2
|
648
|
+
when "- Checking for available provider plugins..."
|
649
|
+
# noop
|
650
|
+
else
|
651
|
+
log_unhandled_line(state, line, reason: "unexpected line in :plugins state")
|
652
|
+
end
|
653
|
+
else
|
654
|
+
# first line
|
655
|
+
phase = state
|
656
|
+
log "Initializing provider plugins ...", depth: 1
|
657
|
+
end
|
658
|
+
when :plugin_warnings
|
659
|
+
if phase == state
|
660
|
+
log pastel.yellow(line), depth: 1
|
661
|
+
else
|
662
|
+
# first line
|
663
|
+
phase = state
|
664
|
+
end
|
665
|
+
when :none
|
666
|
+
log_unhandled_line(state, line, reason: "unexpected line in :none state") if line != ""
|
533
667
|
else
|
534
668
|
return false
|
669
|
+
# log_unhandled_line(state, line, reason: "unexpected state") unless handle_error_states(meta, state, line)
|
535
670
|
end
|
536
|
-
|
671
|
+
|
672
|
+
{ phase: phase }
|
537
673
|
end
|
538
674
|
|
539
|
-
def run_tf_init(upgrade: nil, reconfigure: nil)
|
675
|
+
def run_tf_init(upgrade: nil, reconfigure: nil)
|
540
676
|
phase = :init
|
541
677
|
|
542
678
|
meta = {}
|
543
679
|
|
544
680
|
parser = StatefulParser.new(normalizer: pastel.method(:strip))
|
545
681
|
|
546
|
-
parser
|
547
|
-
parser.state(:modules_upgrade, /^Upgrading modules\.\.\./)
|
548
|
-
parser.state(:backend, /^Initializing the backend\.\.\./, [:none, :modules_init, :modules_upgrade])
|
549
|
-
parser.state(:plugins, /^Initializing provider plugins\.\.\./, [:backend, :modules_init])
|
550
|
-
|
551
|
-
parser.state(:backend_error, /Error when retrieving token from sso/, [:backend])
|
552
|
-
|
553
|
-
parser.state(:plugin_warnings, /^$/, [:plugins])
|
554
|
-
parser.state(:backend_error, /Error:/, [:backend])
|
682
|
+
setup_init_parser(parser)
|
555
683
|
|
556
684
|
setup_error_handling(parser, from_states: [:plugins, :modules_init])
|
557
685
|
|
558
|
-
|
559
|
-
stripped_line = pastel.strip(raw_line.rstrip)
|
686
|
+
stderr_handler = StderrLineHandler.new(operation: :init)
|
560
687
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
when /^- (?<module>[^ ]+) in (?<path>.+)$/
|
575
|
-
print "."
|
576
|
-
when ""
|
577
|
-
puts
|
578
|
-
else
|
579
|
-
log_unhandled_line(state, line, reason: "unexpected line in :modules_init state")
|
580
|
-
end
|
581
|
-
when :modules_upgrade
|
582
|
-
if phase != state
|
583
|
-
# first line
|
584
|
-
phase = state
|
585
|
-
log "Upgrding modules ", depth: 1, newline: false
|
586
|
-
next
|
587
|
-
end
|
588
|
-
case stripped_line
|
589
|
-
when /^- (?<module>[^ ]+) in (?<path>.+)$/
|
590
|
-
print "."
|
591
|
-
when /^Downloading (?<repo>[^ ]+) (?<version>[^ ]+) for (?<module>[^ ]+)\.\.\./
|
592
|
-
print "D"
|
593
|
-
when /^Downloading (?<repo>[^ ]+) for (?<module>[^ ]+)\.\.\./ # rubocop:disable Lint/DuplicateBranch
|
594
|
-
print "D"
|
595
|
-
when ""
|
596
|
-
puts
|
597
|
-
else
|
598
|
-
log_unhandled_line(state, line, reason: "unexpected line in :modules_upgrade state")
|
599
|
-
end
|
600
|
-
when :backend
|
601
|
-
if phase != state
|
602
|
-
# first line
|
603
|
-
phase = state
|
604
|
-
log "Initializing the backend ", depth: 1 # , newline: false
|
605
|
-
next
|
606
|
-
end
|
607
|
-
case stripped_line
|
608
|
-
when /^Successfully configured/
|
609
|
-
log line, depth: 2
|
610
|
-
when /unless the backend/ # rubocop:disable Lint/DuplicateBranch
|
611
|
-
log line, depth: 2
|
612
|
-
when ""
|
613
|
-
puts
|
614
|
-
else
|
615
|
-
log_unhandled_line(state, line, reason: "unexpected line in :backend state")
|
616
|
-
end
|
617
|
-
when :backend_error
|
618
|
-
if raw_line.match "terraform init -reconfigure"
|
619
|
-
meta[:need_reconfigure] = true
|
620
|
-
log pastel.red("module needs to be reconfigured"), depth: 2
|
621
|
-
end
|
622
|
-
if raw_line.match "Error when retrieving token from sso"
|
623
|
-
meta[:need_auth] = true
|
624
|
-
log pastel.red("authentication problem"), depth: 2
|
625
|
-
end
|
626
|
-
when :plugins
|
627
|
-
if phase != state
|
628
|
-
# first line
|
629
|
-
phase = state
|
630
|
-
log "Initializing provider plugins ...", depth: 1
|
631
|
-
next
|
632
|
-
end
|
633
|
-
case stripped_line
|
634
|
-
when /^- Reusing previous version of (?<module>.+) from the dependency lock file$/
|
635
|
-
info = $LAST_MATCH_INFO.named_captures
|
636
|
-
log "- [FROM-LOCK] #{info['module']}", depth: 2
|
637
|
-
when /^- (?<module>.+) is built in to Terraform$/
|
638
|
-
info = $LAST_MATCH_INFO.named_captures
|
639
|
-
log "- [BUILTIN] #{info['module']}", depth: 2
|
640
|
-
when /^- Finding (?<module>[^ ]+) versions matching "(?<version>.+)"\.\.\./
|
641
|
-
info = $LAST_MATCH_INFO.named_captures
|
642
|
-
log "- [FIND] #{info['module']} matching #{info['version'].inspect}", depth: 2
|
643
|
-
when /^- Finding latest version of (?<module>.+)\.\.\.$/
|
644
|
-
info = $LAST_MATCH_INFO.named_captures
|
645
|
-
log "- [FIND] #{info['module']}", depth: 2
|
646
|
-
when /^- Installing (?<module>[^ ]+) v(?<version>.+)\.\.\.$/
|
647
|
-
info = $LAST_MATCH_INFO.named_captures
|
648
|
-
log "- [INSTALLING] #{info['module']} v#{info['version']}", depth: 2
|
649
|
-
when /^- Installed (?<module>[^ ]+) v(?<version>.+) \(signed by(?: a)? (?<signed>.+)\)$/
|
650
|
-
info = $LAST_MATCH_INFO.named_captures
|
651
|
-
log "- [INSTALLED] #{info['module']} v#{info['version']} (#{info['signed']})", depth: 2
|
652
|
-
when /^- Using previously-installed (?<module>[^ ]+) v(?<version>.+)$/
|
653
|
-
info = $LAST_MATCH_INFO.named_captures
|
654
|
-
log "- [USING] #{info['module']} v#{info['version']}", depth: 2
|
655
|
-
when /^- Downloading plugin for provider "(?<provider>[^"]+)" \((?<provider_path>[^)]+)\) (?<version>.+)\.\.\.$/
|
656
|
-
info = $LAST_MATCH_INFO.named_captures
|
657
|
-
log "- #{info['provider']} #{info['version']}", depth: 2
|
658
|
-
when "- Checking for available provider plugins..."
|
659
|
-
# noop
|
688
|
+
status = tf_init(upgrade: upgrade, reconfigure: reconfigure) { |(stream, raw_line)|
|
689
|
+
case stream
|
690
|
+
when :command
|
691
|
+
log "Running command: #{raw_line.strip} ...", depth: 2
|
692
|
+
when :stderr
|
693
|
+
stderr_handler.handle(raw_line)
|
694
|
+
when :stdout
|
695
|
+
stripped_line = pastel.strip(raw_line.rstrip)
|
696
|
+
parser.parse(raw_line.rstrip) do |state, line|
|
697
|
+
if (handled = handle_init_line(state, line, meta, phase: phase, stripped_line: stripped_line))
|
698
|
+
phase = handled[:phase]
|
699
|
+
elsif handle_error_states(meta, state, line)
|
700
|
+
# no-op
|
660
701
|
else
|
661
|
-
log_unhandled_line(state, line, reason: "unexpected
|
702
|
+
log_unhandled_line(state, line, reason: "unexpected state")
|
662
703
|
end
|
663
|
-
when :plugin_warnings
|
664
|
-
if phase != state
|
665
|
-
# first line
|
666
|
-
phase = state
|
667
|
-
next
|
668
|
-
end
|
669
|
-
|
670
|
-
log pastel.yellow(line), depth: 1
|
671
|
-
when :none
|
672
|
-
next if line == ""
|
673
|
-
|
674
|
-
log_unhandled_line(state, line, reason: "unexpected line in :none state")
|
675
|
-
else
|
676
|
-
log_unhandled_line(state, line, reason: "unexpected state") unless handle_error_states(meta, state, line)
|
677
704
|
end
|
678
705
|
end
|
679
706
|
}
|
680
707
|
|
708
|
+
stderr_handler.flush
|
709
|
+
stderr_handler.merge_meta_into(meta)
|
710
|
+
|
681
711
|
[status.status, meta]
|
682
712
|
end
|
683
713
|
|
@@ -693,8 +723,7 @@ module MuxTf
|
|
693
723
|
end
|
694
724
|
end
|
695
725
|
|
696
|
-
|
697
|
-
def process_validation(info) # rubocop:disable Metrics/CyclomaticComplexity
|
726
|
+
def process_validation(info)
|
698
727
|
remedies = Set.new
|
699
728
|
|
700
729
|
if (info["error_count"]).positive? || (info["warning_count"]).positive?
|
@@ -749,11 +778,10 @@ module MuxTf
|
|
749
778
|
|
750
779
|
remedies
|
751
780
|
end
|
752
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
753
781
|
|
754
782
|
private
|
755
783
|
|
756
|
-
def format_validation_range(dinfo, color)
|
784
|
+
def format_validation_range(dinfo, color)
|
757
785
|
range = dinfo["range"]
|
758
786
|
# filename: "../../../modules/pods/jane_pod/main.tf"
|
759
787
|
# start:
|