mux_tf 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 924f8b4cc0e90b4c636e3ffcc806c0e48036380ac81ee83b1dc21a437950e76e
4
- data.tar.gz: 3bea784dc0db5091efa2dcba48c653b812d618b88c8dc04b997b59cc8e810e0c
3
+ metadata.gz: ab68c9969748e0246a48cb2bf53876b0b2f47993b021017e1e9bb31782a7e4b4
4
+ data.tar.gz: 63fb2194ba923f3c30c9480f50946c550e85ea9e7e1988fdcc1764cbe7666f6a
5
5
  SHA512:
6
- metadata.gz: 3dbd88ebf68ae0bb27116ce5b553a04668a746cfdd89ed1e646fc6f75961cf8c61d66f2a4ba46d0baaa17c6fdaa3b99704485632a5787a492037e75707e06b1a
7
- data.tar.gz: bd9bf482078f080477f1871b02c256ad06b7bcb4e323adb8ee35fe056b9f8fd34bec4993c6b1611fac161b09b80db11c3d36395fdb42bef0d174e3ec666f8745
6
+ metadata.gz: e8d1442c6cff1c7c0828347176b1cc0a49fa28fb5a27e0212e730e3bf176fc4a072ba247e9cbf6d248c488fb1c62ffc6a71181dbde47e0b35a759b798ded6886
7
+ data.tar.gz: 3d85fc7be2b58bd815060145c33bccf7dc5814a5ee3a052f5adc6a4c7512792e290f0b1bb26faa07d4f950aab81036bcf9c09b91c2a3a20878fcd70601bd2044
@@ -4,7 +4,7 @@ require "bundler"
4
4
 
5
5
  module MuxTf
6
6
  module Cli
7
- module Current
7
+ module Current # rubocop:disable Metrics/ModuleLength
8
8
  extend TerraformHelpers
9
9
  extend PiotrbCliUtils::Util
10
10
  extend PiotrbCliUtils::CriCommandSupport
@@ -32,19 +32,16 @@ module MuxTf
32
32
  return launch_cmd_loop(:error) unless upgrade_status == :ok
33
33
  end
34
34
 
35
- plan_status, @plan_meta = create_plan(plan_filename)
35
+ plan_status = run_plan
36
36
 
37
37
  case plan_status
38
38
  when :ok
39
- log "no changes, exiting", depth: 1
39
+ log "exiting", depth: 1
40
40
  when :error
41
- log "something went wrong", depth: 1
42
41
  launch_cmd_loop(plan_status)
43
- when :changes
44
- log "Printing Plan Summary ...", depth: 1
45
- pretty_plan_summary(plan_filename)
42
+ when :changes # rubocop:disable Lint/DuplicateBranch
46
43
  launch_cmd_loop(plan_status)
47
- when :unknown
44
+ when :unknown # rubocop:disable Lint/DuplicateBranch
48
45
  launch_cmd_loop(plan_status)
49
46
  end
50
47
  end
@@ -68,28 +65,45 @@ module MuxTf
68
65
 
69
66
  def run_validate
70
67
  remedies = PlanFormatter.process_validation(validate)
71
- process_remedies(remedies)
68
+ status, _results = process_remedies(remedies)
69
+ status
72
70
  end
73
71
 
74
- def process_remedies(remedies)
72
+ def process_remedies(remedies, retry_count: 0) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
73
+ results = {}
74
+ if retry_count > 5
75
+ log "giving up because retry_count: #{retry_count}", depth: 1
76
+ log "unprocessed remedies: #{remedies.to_a}", depth: 1
77
+ return [false, results]
78
+ end
75
79
  if remedies.delete? :init
76
- log "Running terraform init ...", depth: 2
80
+ log "[remedy] Running terraform init ...", depth: 2
77
81
  remedies = PlanFormatter.init_status_to_remedies(*PlanFormatter.run_tf_init)
78
- if process_remedies(remedies)
82
+ status, r_results = process_remedies(remedies)
83
+ results.merge!(r_results)
84
+ if status
79
85
  remedies = PlanFormatter.process_validation(validate)
80
- return false unless process_remedies(remedies)
86
+ return [false, results] unless process_remedies(remedies)
81
87
  end
82
88
  end
89
+ if remedies.delete?(:plan)
90
+ log "[remedy] Running terraform plan ...", depth: 2
91
+ plan_status = run_plan(retry_count: retry_count)
92
+ results[:plan_status] = plan_status
93
+ return [false, results] unless [:ok, :changes].include?(plan_status)
94
+ end
83
95
  if remedies.delete? :reconfigure
84
- log "Running terraform init ...", depth: 2
96
+ log "[remedy] Running terraform init ...", depth: 2
85
97
  remedies = PlanFormatter.init_status_to_remedies(*PlanFormatter.run_tf_init(reconfigure: true))
86
- return false unless process_remedies(remedies)
98
+ status, r_results = process_remedies(remedies)
99
+ results.merge!(r_results)
100
+ return [false, results] unless status
87
101
  end
88
102
  unless remedies.empty?
89
103
  log "unprocessed remedies: #{remedies.to_a}", depth: 1
90
- return false
104
+ return [false, results]
91
105
  end
92
- true
106
+ [true, results]
93
107
  end
94
108
 
95
109
  def validate
@@ -268,20 +282,68 @@ module MuxTf
268
282
  end
269
283
  end
270
284
 
271
- def run_plan(targets: [])
285
+ def print_errors_and_warnings # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
286
+ message = []
287
+ message << Paint["#{@plan_meta[:warnings].length} Warnings", :yellow] if @plan_meta[:warnings]
288
+ message << Paint["#{@plan_meta[:errors].length} Errors", :red] if @plan_meta[:errors]
289
+ if message.length.positive?
290
+ log ""
291
+ log "Encountered: #{message.join(' and ')}"
292
+ log ""
293
+ end
294
+
295
+ @plan_meta[:warnings]&.each do |warning|
296
+ log "-" * 20
297
+ log Paint["Warning: #{warning[:message]}", :yellow]
298
+ warning[:body]&.each do |line|
299
+ log Paint[line, :yellow], depth: 1
300
+ end
301
+ log ""
302
+ end
303
+
304
+ @plan_meta[:errors]&.each do |error|
305
+ log "-" * 20
306
+ log Paint["Error: #{error[:message]}", :red]
307
+ error[:body]&.each do |line|
308
+ log Paint[line, :red], depth: 1
309
+ end
310
+ log ""
311
+ end
312
+
313
+ return unless message.length.positive?
314
+
315
+ log ""
316
+ end
317
+
318
+ def detect_remedies_from_plan
319
+ remedies = Set.new
320
+ @plan_meta[:errors]&.each do |error|
321
+ remedies << :plan if error[:message].include?("timeout while waiting for plugin to start")
322
+ end
323
+ remedies
324
+ end
325
+
326
+ def run_plan(targets: [], retry_count: 0)
272
327
  plan_status, @plan_meta = create_plan(plan_filename, targets: targets)
273
328
 
274
329
  case plan_status
275
330
  when :ok
276
331
  log "no changes", depth: 1
277
332
  when :error
278
- log "something went wrong", depth: 1
333
+ # log "something went wrong", depth: 1
334
+ print_errors_and_warnings
335
+ remedies = detect_remedies_from_plan
336
+ status, results = process_remedies(remedies, retry_count: retry_count)
337
+ plan_status = results[:plan_status] if status
279
338
  when :changes
280
339
  log "Printing Plan Summary ...", depth: 1
281
340
  pretty_plan_summary(plan_filename)
282
341
  when :unknown
283
342
  # nothing
284
343
  end
344
+
345
+ print_errors_and_warnings
346
+
285
347
  plan_status
286
348
  end
287
349
 
@@ -292,8 +354,6 @@ module MuxTf
292
354
  [:ok, meta]
293
355
  when 1
294
356
  [:error, meta]
295
- # when 2
296
- # [:changes, meta]
297
357
  else
298
358
  log Paint["terraform init upgrade exited with an unknown exit code: #{exit_code}", :yellow]
299
359
  [:unknown, meta]
data/lib/mux_tf/cli.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  module MuxTf
4
4
  module Cli
5
+ extend PiotrbCliUtils::Util
6
+
5
7
  def self.run(mode, args)
6
8
  case mode
7
9
  when :mux
@@ -13,7 +13,7 @@ module MuxTf
13
13
 
14
14
  parser = StatefulParser.new(normalizer: pastel.method(:strip))
15
15
  parser.state(:info, /^Acquiring state lock/)
16
- parser.state(:error, /(╷|Error locking state|Error:)/, [:none, :blank, :info, :reading])
16
+ parser.state(:error, /(Error locking state|Error:)/, [:none, :blank, :info, :reading])
17
17
  parser.state(:reading, /: (Reading...|Read complete after)/, [:none, :info, :reading])
18
18
  parser.state(:none, /^$/, [:reading])
19
19
  parser.state(:refreshing, /^.+: Refreshing state... \[id=/, [:none, :info, :reading])
@@ -31,10 +31,13 @@ module MuxTf
31
31
  parser.state(:plan_legend, /^Terraform used the selected providers to generate the following execution$/)
32
32
  parser.state(:none, /^$/, [:plan_legend])
33
33
 
34
- parser.state(:error_lock_info, /Lock Info/, [:error])
35
- parser.state(:error, /^$/, [:error_lock_info])
34
+ parser.state(:error_lock_info, /Lock Info/, [:plan_error_error])
36
35
 
37
- parser.state(:plan_error, /^╷|Error: /, [:refreshing, :refresh_done])
36
+ parser.state(:plan_error, /Planning failed. Terraform encountered an error while generating this plan./, [:refreshing, :refresh_done])
37
+ parser.state(:plan_error_block, /^╷/, [:plan_error, :none, :blank, :info, :reading])
38
+ parser.state(:plan_error_warning, /^│ Warning: /, [:plan_error_block])
39
+ parser.state(:plan_error_error, /^│ Error: /, [:plan_error_block])
40
+ parser.state(:plan_error, /^╵/, [:plan_error_warning, :plan_error_error, :plan_error_block, :error_lock_info])
38
41
 
39
42
  last_state = nil
40
43
 
@@ -68,16 +71,54 @@ module MuxTf
68
71
  else
69
72
  p [state, line]
70
73
  end
71
- when :error
72
- meta["error"] = "lock"
73
- log Paint[line, :red], depth: 2
74
+ when :plan_error_block
75
+ meta[:current_error] = {
76
+ type: :unknown,
77
+ body: []
78
+ }
79
+ when :plan_error_warning, :plan_error_error
80
+ clean_line = pastel.strip(line).gsub(/^│ /, "")
81
+ if clean_line =~ /^(Warning|Error): (.+)$/
82
+ meta[:current_error][:type] = $LAST_MATCH_INFO[1].downcase.to_sym
83
+ meta[:current_error][:message] = $LAST_MATCH_INFO[2]
84
+ elsif clean_line == ""
85
+ # skip double empty lines
86
+ meta[:current_error][:body] << clean_line if meta[:current_error][:body].last != ""
87
+ else
88
+ meta[:current_error][:body] ||= []
89
+ meta[:current_error][:body] << clean_line
90
+ end
74
91
  when :plan_error
75
- puts if first_in_state
76
- meta["error"] = "refresh"
77
- log Paint[line, :red], depth: 2
92
+ case pastel.strip(line)
93
+ when "" # closing of an error block
94
+ if meta[:current_error][:type] == :error
95
+ meta[:errors] ||= []
96
+ meta[:errors] << meta[:current_error]
97
+ end
98
+ if meta[:current_error][:type] == :warning
99
+ meta[:warnings] ||= []
100
+ meta[:warnings] << meta[:current_error]
101
+ end
102
+ meta.delete(:current_error)
103
+ when ""
104
+ # skip empty line
105
+ when /Releasing state lock. This may take a few moments"/
106
+ log line, depth: 2
107
+ when /Planning failed./ # rubocop:disable Lint/DuplicateBranch
108
+ log line, depth: 2
109
+ else
110
+ p [state, line]
111
+ end
78
112
  when :error_lock_info
113
+ meta["error"] = "lock"
79
114
  meta[$LAST_MATCH_INFO[1]] = $LAST_MATCH_INFO[2] if line =~ /([A-Z]+\S+)+:\s+(.+)$/
80
- log Paint[line, :red], depth: 2
115
+ clean_line = pastel.strip(line).gsub(/^│ /, "")
116
+ if clean_line == ""
117
+ meta[:current_error][:body] << clean_line if meta[:current_error][:body].last != ""
118
+ else
119
+ meta[:current_error][:body] << clean_line
120
+ end
121
+ # log Paint[line, :red], depth: 2
81
122
  when :refreshing
82
123
  if first_in_state
83
124
  log "Refreshing state ", depth: 2, newline: false
@@ -270,6 +311,8 @@ module MuxTf
270
311
  remedies << :init
271
312
  elsif /there is no package for .+ cached in/.match?(dinfo["summary"]) # rubocop:disable Lint/DuplicateBranch
272
313
  remedies << :init
314
+ elsif dinfo["detail"]&.include?("timeout while waiting for plugin to start") # rubocop:disable Lint/DuplicateBranch
315
+ remedies << :init
273
316
  else
274
317
  log dinfo["detail"], depth: 4 if dinfo["detail"]
275
318
  log format_validation_range(dinfo["range"], color), depth: 4 if dinfo["range"]
@@ -239,7 +239,7 @@ module MuxTf
239
239
  throw :abort, "nothing selected"
240
240
  else
241
241
  log "Re-running apply with the selected resources ..."
242
- run_plan(targets: result)
242
+ MuxTf::Cli::Current.run_plan(targets: result)
243
243
  end
244
244
  end
245
245
 
@@ -263,36 +263,6 @@ module MuxTf
263
263
  end
264
264
  end
265
265
 
266
- def run_plan(targets: [])
267
- plan_filename = MuxTf::Cli::Current.plan_filename
268
- plan_status, @plan_meta = create_plan(plan_filename, targets: targets)
269
-
270
- case plan_status
271
- when :ok
272
- log "no changes", depth: 1
273
- when :error
274
- log "something went wrong", depth: 1
275
- when :changes
276
- log "Printing Plan Summary ...", depth: 1
277
- pretty_plan_summary(plan_filename)
278
- when :unknown
279
- # nothing
280
- end
281
- plan_status
282
- end
283
-
284
- def pretty_plan_summary(filename)
285
- plan = PlanSummaryHandler.from_file(filename)
286
- plan.flat_summary.each do |line|
287
- log line, depth: 2
288
- end
289
- plan.output_summary.each do |line|
290
- log line, depth: 2
291
- end
292
- log "", depth: 2
293
- log plan.summary, depth: 2
294
- end
295
-
296
266
  def prune_unchanged_deps(_parts)
297
267
  valid_addresses = resource_parts.map { |part| part[:address] }
298
268
 
@@ -3,6 +3,7 @@
3
3
  module MuxTf
4
4
  module TerraformHelpers
5
5
  include PiotrbCliUtils::ShellHelpers
6
+ include PiotrbCliUtils::Util
6
7
 
7
8
  ResultStruct = Struct.new("TerraformResponse", :status, :success?, :output, :parsed_output, keyword_init: true)
8
9
 
data/lib/mux_tf/tmux.rb CHANGED
@@ -4,6 +4,8 @@ require "shellwords"
4
4
 
5
5
  module MuxTf
6
6
  module Tmux
7
+ extend PiotrbCliUtils::Util
8
+
7
9
  class << self
8
10
  def session_running?(name)
9
11
  tmux("has-session -t #{name.inspect} 2>/dev/null", raise_on_error: false)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MuxTf
4
- VERSION = "0.12.0"
4
+ VERSION = "0.13.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mux_tf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Banasik
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-12 00:00:00.000000000 Z
11
+ date: 2023-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport