mux_tf 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mux_tf.rb +21 -20
- data/lib/mux_tf/cli/current.rb +71 -62
- data/lib/mux_tf/cli/mux.rb +26 -24
- data/lib/mux_tf/cli/plan_summary.rb +20 -246
- data/lib/mux_tf/plan_formatter.rb +36 -36
- data/lib/mux_tf/plan_summary_handler.rb +258 -0
- data/lib/mux_tf/terraform_helpers.rb +28 -28
- data/lib/mux_tf/tmux.rb +18 -11
- data/lib/mux_tf/version.rb +1 -1
- data/lib/mux_tf/version_check.rb +6 -6
- data/lib/mux_tf/yaml_cache.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d3511e5badfa499bd43efb92048717c8d597633229c4e135a51c0d57ea56d84
|
4
|
+
data.tar.gz: 3a2feb35ce3d7a9c4f2781b2ace26eb08ed41da0ba047b33a8b4882363878914
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7559eca291ace43436b5f38ea72823187573c85e7b51029861bf98a4e3b88b9144f0997a915a9ab1e9cb581ddc04807b9a9da569dd233a47207007fae5939b57
|
7
|
+
data.tar.gz: 15d909df002d4ff344e2966eb2a54d3943407f6d9e910daebc84781de233f215bfa282067f7cf3eaf702811553785e785be9c5d8a437908e8b0f30d1efa911b8
|
data/lib/mux_tf.rb
CHANGED
@@ -1,30 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "English"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
5
|
+
require "shellwords"
|
6
|
+
require "optparse"
|
7
|
+
require "json"
|
8
|
+
require "open3"
|
9
9
|
|
10
|
-
require
|
11
|
-
require
|
10
|
+
require "piotrb_cli_utils"
|
11
|
+
require "stateful_parser"
|
12
12
|
|
13
|
-
require
|
13
|
+
require "active_support/core_ext"
|
14
14
|
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
15
|
+
require "paint"
|
16
|
+
require "pastel"
|
17
|
+
require "tty-prompt"
|
18
|
+
require "tty-table"
|
19
|
+
require "dotenv"
|
20
20
|
|
21
|
-
require_relative
|
22
|
-
require_relative
|
23
|
-
require_relative
|
24
|
-
require_relative
|
25
|
-
require_relative
|
26
|
-
require_relative
|
27
|
-
require_relative
|
21
|
+
require_relative "./mux_tf/version"
|
22
|
+
require_relative "./mux_tf/cli"
|
23
|
+
require_relative "./mux_tf/tmux"
|
24
|
+
require_relative "./mux_tf/terraform_helpers"
|
25
|
+
require_relative "./mux_tf/plan_formatter"
|
26
|
+
require_relative "./mux_tf/version_check"
|
27
|
+
require_relative "./mux_tf/yaml_cache"
|
28
|
+
require_relative "./mux_tf/plan_summary_handler"
|
28
29
|
|
29
30
|
module MuxTf
|
30
31
|
end
|
data/lib/mux_tf/cli/current.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bundler"
|
4
|
+
|
3
5
|
module MuxTf
|
4
6
|
module Cli
|
5
7
|
module Current
|
@@ -8,13 +10,13 @@ module MuxTf
|
|
8
10
|
extend PiotrbCliUtils::CriCommandSupport
|
9
11
|
extend PiotrbCliUtils::CmdLoop
|
10
12
|
|
11
|
-
PLAN_FILENAME =
|
13
|
+
PLAN_FILENAME = "foo.tfplan"
|
12
14
|
|
13
15
|
class << self
|
14
16
|
def run(args)
|
15
17
|
version_check
|
16
18
|
|
17
|
-
if args[0] ==
|
19
|
+
if args[0] == "cli"
|
18
20
|
cmd_loop
|
19
21
|
return
|
20
22
|
end
|
@@ -22,12 +24,12 @@ module MuxTf
|
|
22
24
|
folder_name = File.basename(Dir.getwd)
|
23
25
|
log "Processing #{Paint[folder_name, :cyan]} ..."
|
24
26
|
|
25
|
-
ENV[
|
26
|
-
ENV[
|
27
|
+
ENV["TF_IN_AUTOMATION"] = "1"
|
28
|
+
ENV["TF_INPUT"] = "0"
|
27
29
|
|
28
30
|
return launch_cmd_loop(:error) unless run_validate
|
29
31
|
|
30
|
-
if ENV[
|
32
|
+
if ENV["TF_UPGRADE"]
|
31
33
|
upgrade_status, upgrade_meta = run_upgrade
|
32
34
|
return launch_cmd_loop(:error) unless upgrade_status == :ok
|
33
35
|
end
|
@@ -36,37 +38,37 @@ module MuxTf
|
|
36
38
|
|
37
39
|
case plan_status
|
38
40
|
when :ok
|
39
|
-
log
|
41
|
+
log "no changes, exiting", depth: 1
|
40
42
|
when :error
|
41
|
-
log
|
43
|
+
log "something went wrong", depth: 1
|
42
44
|
launch_cmd_loop(plan_status)
|
43
45
|
when :changes
|
44
|
-
log
|
46
|
+
log "Printing Plan Summary ...", depth: 1
|
45
47
|
pretty_plan_summary(PLAN_FILENAME)
|
46
48
|
launch_cmd_loop(plan_status)
|
47
49
|
when :unknown
|
48
50
|
launch_cmd_loop(plan_status)
|
49
51
|
end
|
50
52
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
51
|
-
puts Paint[
|
52
|
-
puts
|
53
|
+
puts Paint["Unhandled Exception!", :red]
|
54
|
+
puts "=" * 20
|
53
55
|
puts e.full_message
|
54
56
|
puts
|
55
|
-
puts
|
57
|
+
puts "< press enter to continue >"
|
56
58
|
gets
|
57
59
|
exit 1
|
58
60
|
end
|
59
61
|
|
60
|
-
|
62
|
+
private
|
61
63
|
|
62
64
|
def version_check
|
63
65
|
if VersionCheck.has_updates?
|
64
|
-
log Paint["="*80, :yellow]
|
66
|
+
log Paint["=" * 80, :yellow]
|
65
67
|
log "New version of #{Paint["mux_tf", :cyan]} is available!"
|
66
68
|
log "You are currently on version: #{Paint[VersionCheck.current_gem_version, :yellow]}"
|
67
69
|
log "Latest version found is: #{Paint[VersionCheck.latest_gem_version, :green]}"
|
68
|
-
log "Run `#{Paint["gem
|
69
|
-
log Paint["="*80, :yellow]
|
70
|
+
log "Run `#{Paint["gem install mux_tf", :green]}` to update!"
|
71
|
+
log Paint["=" * 80, :yellow]
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
@@ -77,7 +79,7 @@ module MuxTf
|
|
77
79
|
|
78
80
|
def process_remedies(remedies)
|
79
81
|
if remedies.delete? :init
|
80
|
-
log
|
82
|
+
log "Running terraform init ...", depth: 2
|
81
83
|
tf_init
|
82
84
|
remedies = PlanFormatter.process_validation(validate)
|
83
85
|
process_remedies(remedies)
|
@@ -90,12 +92,12 @@ module MuxTf
|
|
90
92
|
end
|
91
93
|
|
92
94
|
def validate
|
93
|
-
log
|
95
|
+
log "Validating module ...", depth: 1
|
94
96
|
tf_validate.parsed_output
|
95
97
|
end
|
96
98
|
|
97
99
|
def create_plan(filename)
|
98
|
-
log
|
100
|
+
log "Preparing Plan ...", depth: 1
|
99
101
|
exit_code, meta = PlanFormatter.pretty_plan(filename)
|
100
102
|
case exit_code
|
101
103
|
when 0
|
@@ -111,13 +113,13 @@ module MuxTf
|
|
111
113
|
end
|
112
114
|
|
113
115
|
def launch_cmd_loop(status)
|
114
|
-
return if ENV[
|
116
|
+
return if ENV["NO_CMD"]
|
115
117
|
|
116
118
|
case status
|
117
119
|
when :error, :unknown
|
118
|
-
log Paint[
|
120
|
+
log Paint["Dropping to command line so you can fix the issue!", :red]
|
119
121
|
when :changes
|
120
|
-
log Paint[
|
122
|
+
log Paint["Dropping to command line so you can review the changes.", :yellow]
|
121
123
|
end
|
122
124
|
cmd_loop(status)
|
123
125
|
end
|
@@ -138,7 +140,7 @@ module MuxTf
|
|
138
140
|
end
|
139
141
|
|
140
142
|
run_cmd_loop(prompt) do |cmd|
|
141
|
-
throw(:stop, :no_input) if cmd ==
|
143
|
+
throw(:stop, :no_input) if cmd == ""
|
142
144
|
args = Shellwords.split(cmd)
|
143
145
|
root_cmd.run(args, {}, hard_exit: false)
|
144
146
|
end
|
@@ -159,90 +161,98 @@ module MuxTf
|
|
159
161
|
end
|
160
162
|
|
161
163
|
def plan_cmd
|
162
|
-
define_cmd(
|
164
|
+
define_cmd("plan", summary: "Re-run plan") do |_opts, _args, _cmd|
|
163
165
|
run_validate && run_plan
|
164
166
|
end
|
165
167
|
end
|
166
168
|
|
167
169
|
def apply_cmd
|
168
|
-
define_cmd(
|
170
|
+
define_cmd("apply", summary: "Apply the current plan") do |_opts, _args, _cmd|
|
169
171
|
status = tf_apply(filename: PLAN_FILENAME)
|
170
172
|
if status.success?
|
171
173
|
throw :stop, :done
|
172
174
|
else
|
173
|
-
log
|
175
|
+
log "Apply Failed!"
|
174
176
|
end
|
175
177
|
end
|
176
178
|
end
|
177
179
|
|
178
180
|
def shell_cmd
|
179
|
-
define_cmd(
|
180
|
-
log Paint[
|
181
|
-
log Paint[
|
182
|
-
system ENV[
|
181
|
+
define_cmd("shell", summary: "Open your default terminal in the current folder") do |_opts, _args, _cmd|
|
182
|
+
log Paint["Launching shell ...", :yellow]
|
183
|
+
log Paint["When it exits you will be back at this prompt.", :yellow]
|
184
|
+
system ENV["SHELL"]
|
183
185
|
end
|
184
186
|
end
|
185
187
|
|
186
188
|
def force_unlock_cmd
|
187
|
-
define_cmd(
|
189
|
+
define_cmd("force-unlock", summary: "Force unlock state after encountering a lock error!") do
|
188
190
|
prompt = TTY::Prompt.new(interrupt: :noop)
|
189
191
|
|
190
192
|
table = TTY::Table.new(header: %w[Field Value])
|
191
|
-
table << [
|
192
|
-
table << [
|
193
|
-
table << [
|
194
|
-
table << [
|
193
|
+
table << ["Lock ID", @plan_meta["ID"]]
|
194
|
+
table << ["Operation", @plan_meta["Operation"]]
|
195
|
+
table << ["Who", @plan_meta["Who"]]
|
196
|
+
table << ["Created", @plan_meta["Created"]]
|
195
197
|
|
196
198
|
puts table.render(:unicode, padding: [0, 1])
|
197
199
|
|
198
|
-
if @plan_meta && @plan_meta[
|
199
|
-
done = catch(:abort)
|
200
|
-
if @plan_meta[
|
200
|
+
if @plan_meta && @plan_meta["error"] == "lock"
|
201
|
+
done = catch(:abort) {
|
202
|
+
if @plan_meta["Operation"] != "OperationTypePlan"
|
201
203
|
throw :abort unless prompt.yes?(
|
202
|
-
"Are you sure you want to force unlock a lock for operation: #{@plan_meta[
|
204
|
+
"Are you sure you want to force unlock a lock for operation: #{@plan_meta["Operation"]}",
|
203
205
|
default: false
|
204
206
|
)
|
205
207
|
end
|
206
208
|
|
207
209
|
throw :abort unless prompt.yes?(
|
208
|
-
|
210
|
+
"Are you sure you want to force unlock this lock?",
|
209
211
|
default: false
|
210
212
|
)
|
211
213
|
|
212
|
-
status = tf_force_unlock(id: @plan_meta[
|
214
|
+
status = tf_force_unlock(id: @plan_meta["ID"])
|
213
215
|
if status.success?
|
214
|
-
log
|
216
|
+
log "Done!"
|
215
217
|
else
|
216
218
|
log Paint["Failed with status: #{status}", :red]
|
217
219
|
end
|
218
220
|
|
219
221
|
true
|
220
|
-
|
222
|
+
}
|
221
223
|
|
222
|
-
log Paint[
|
224
|
+
log Paint["Aborted", :yellow] unless done
|
223
225
|
else
|
224
|
-
log Paint[
|
226
|
+
log Paint["No lock error or no plan ran!", :red]
|
225
227
|
end
|
226
228
|
end
|
227
229
|
end
|
228
230
|
|
229
231
|
def upgrade_cmd
|
230
|
-
define_cmd(
|
232
|
+
define_cmd("upgrade", summary: "Upgrade modules/plguins") do |_opts, _args, _cmd|
|
231
233
|
status, meta = run_upgrade
|
232
234
|
if status != :ok
|
233
235
|
log meta.inspect unless meta.empty?
|
234
|
-
log
|
236
|
+
log "Upgrade Failed!"
|
235
237
|
end
|
236
238
|
end
|
237
239
|
end
|
238
240
|
|
239
241
|
def interactive_cmd
|
240
|
-
define_cmd(
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
242
|
+
define_cmd("interactive", summary: "Apply interactively") do |_opts, _args, _cmd|
|
243
|
+
plan = PlanSummaryHandler.from_file(PLAN_FILENAME)
|
244
|
+
begin
|
245
|
+
abort_message = catch :abort do
|
246
|
+
plan.run_interactive
|
247
|
+
end
|
248
|
+
if abort_message
|
249
|
+
log Paint["Aborted: #{abort_message}", :red]
|
250
|
+
else
|
251
|
+
run_plan
|
252
|
+
end
|
253
|
+
rescue Exception => e
|
254
|
+
log e.full_message
|
255
|
+
log "Interactive Apply Failed!"
|
246
256
|
end
|
247
257
|
end
|
248
258
|
end
|
@@ -252,11 +262,11 @@ module MuxTf
|
|
252
262
|
|
253
263
|
case plan_status
|
254
264
|
when :ok
|
255
|
-
log
|
265
|
+
log "no changes", depth: 1
|
256
266
|
when :error
|
257
|
-
log
|
267
|
+
log "something went wrong", depth: 1
|
258
268
|
when :changes
|
259
|
-
log
|
269
|
+
log "Printing Plan Summary ...", depth: 1
|
260
270
|
pretty_plan_summary(PLAN_FILENAME)
|
261
271
|
when :unknown
|
262
272
|
# nothing
|
@@ -278,16 +288,15 @@ module MuxTf
|
|
278
288
|
end
|
279
289
|
end
|
280
290
|
|
281
|
-
def tf_plan_summrary_cmd
|
282
|
-
@tf_plan_summrary_cmd ||= File.expand_path(File.join(__dir__, '..', '..', '..', 'exe', 'tf_plan_summary'))
|
283
|
-
end
|
284
|
-
|
285
291
|
def pretty_plan_summary(filename)
|
286
|
-
|
287
|
-
|
292
|
+
plan = PlanSummaryHandler.from_file(filename)
|
293
|
+
plan.flat_summary.each do |line|
|
294
|
+
log line, depth: 2
|
288
295
|
end
|
296
|
+
log "", depth: 2
|
297
|
+
log plan.summary, depth: 2
|
289
298
|
end
|
299
|
+
end
|
290
300
|
end
|
291
301
|
end
|
292
|
-
end
|
293
302
|
end
|
data/lib/mux_tf/cli/mux.rb
CHANGED
@@ -8,48 +8,50 @@ module MuxTf
|
|
8
8
|
|
9
9
|
class << self
|
10
10
|
def run(_args)
|
11
|
-
Dotenv.load(
|
11
|
+
Dotenv.load(".env.mux")
|
12
12
|
|
13
|
-
log
|
13
|
+
log "Enumerating folders ..."
|
14
14
|
dirs = enumerate_terraform_dirs
|
15
15
|
|
16
|
-
fail_with
|
16
|
+
fail_with "Error: - no subfolders detected! Aborting." if dirs.empty?
|
17
17
|
|
18
|
-
tasks = dirs.map
|
18
|
+
tasks = dirs.map { |dir|
|
19
19
|
{
|
20
20
|
name: dir,
|
21
21
|
cwd: dir,
|
22
|
-
cmd: File.expand_path(File.join(__dir__,
|
22
|
+
cmd: File.expand_path(File.join(__dir__, "..", "..", "..", "exe", "tf_current"))
|
23
23
|
}
|
24
|
-
|
24
|
+
}
|
25
25
|
|
26
26
|
project = File.basename(Dir.getwd)
|
27
27
|
|
28
|
-
if ENV[
|
29
|
-
log
|
30
|
-
words = Shellwords.shellsplit(ENV[
|
31
|
-
result = capture_shell([*words,
|
28
|
+
if ENV["MUX_TF_AUTH_WRAPPER"]
|
29
|
+
log "Warming up AWS connection ..."
|
30
|
+
words = Shellwords.shellsplit(ENV["MUX_TF_AUTH_WRAPPER"])
|
31
|
+
result = capture_shell([*words, "aws", "sts", "get-caller-identity"], raise_on_error: true)
|
32
32
|
p JSON.parse(result)
|
33
33
|
end
|
34
34
|
|
35
35
|
if Tmux.session_running?(project)
|
36
|
-
log
|
36
|
+
log "Killing existing session ..."
|
37
37
|
Tmux.kill_session(project)
|
38
38
|
end
|
39
39
|
|
40
|
-
log
|
40
|
+
log "Starting new session ..."
|
41
41
|
Tmux.new_session project
|
42
|
-
Tmux.select_pane
|
42
|
+
Tmux.select_pane "initial"
|
43
|
+
|
44
|
+
Tmux.set_hook "pane-exited", "select-layout tiled"
|
45
|
+
Tmux.set_hook "window-pane-changed", "select-layout tiled"
|
43
46
|
|
44
|
-
Tmux.
|
45
|
-
Tmux.set_hook 'window-pane-changed', 'select-layout tiled'
|
47
|
+
Tmux.set "mouse", "on"
|
46
48
|
|
47
|
-
Tmux.
|
49
|
+
window_id = Tmux.list_windows.first[:id]
|
48
50
|
|
49
51
|
unless tasks.empty?
|
50
52
|
tasks.each do |task|
|
51
53
|
log "launching task: #{task[:name]} ...", depth: 2
|
52
|
-
Tmux.split_window :horizontal, "#{project}
|
54
|
+
Tmux.split_window :horizontal, "#{project}:#{window_id}", cmd: task[:cmd], cwd: task[:cwd]
|
53
55
|
Tmux.select_pane task[:name]
|
54
56
|
Tmux.tile!
|
55
57
|
task[:commands]&.each do |cmd|
|
@@ -58,17 +60,17 @@ module MuxTf
|
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
61
|
-
log
|
63
|
+
log "Almost done ..."
|
62
64
|
|
63
|
-
initial_pane = Tmux.find_pane(
|
65
|
+
initial_pane = Tmux.find_pane("initial")
|
64
66
|
Tmux.kill_pane initial_pane[:id]
|
65
67
|
Tmux.tile!
|
66
68
|
|
67
69
|
puts "\e]0;tmux: #{project}\007"
|
68
70
|
|
69
|
-
log
|
70
|
-
Tmux.attach(project, cc: !!ENV[
|
71
|
-
log
|
71
|
+
log "Attaching ..."
|
72
|
+
Tmux.attach(project, cc: !!ENV["MUXP_CC_MODE"])
|
73
|
+
log "Done!"
|
72
74
|
end
|
73
75
|
|
74
76
|
private
|
@@ -76,9 +78,9 @@ module MuxTf
|
|
76
78
|
def enumerate_terraform_dirs
|
77
79
|
ignored = []
|
78
80
|
|
79
|
-
ignored += ENV[
|
81
|
+
ignored += ENV["MUX_IGNORE"].split(",") if ENV["MUX_IGNORE"]
|
80
82
|
|
81
|
-
dirs = Dir[
|
83
|
+
dirs = Dir["**/*/.terraform"].map { |n| n.gsub(%r{/\.terraform}, "") }
|
82
84
|
dirs.reject! { |d| d.in?(ignored) }
|
83
85
|
|
84
86
|
dirs
|