terradactyl 0.15.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +44 -0
- data/README.md +1 -1
- data/lib/terradactyl/cli.rb +6 -3
- data/lib/terradactyl/commands.rb +161 -61
- data/lib/terradactyl/common.rb +8 -0
- data/lib/terradactyl/config.rb +16 -10
- data/lib/terradactyl/version.rb +1 -1
- data/terradactyl.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49fe1966595f9b6757978cdb175659deb41290b3f24ef7c410a03c03c72172d2
|
4
|
+
data.tar.gz: 232ab09501fe09d0f8ac3163065269f43f9200dcb7ea3d68c0b0dfff057fafdc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e22c6c6159ba55bafcc83e0a919b2730647568f158853e9047e3ce08574047f5dcfd539fb3eadfffddc8f94d6c3476d61a892b7875181f40b54e32f0a407521
|
7
|
+
data.tar.gz: 5ca0d7097d609e041c974a6067829e564731e155dbb3cfdbc67a8965f47292f1d89067932285cdfd4d581b84e0da4d30e282cf1307f5521e25ff9e00fe2dfbda
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,49 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 1.1.0 (2021-12-09)
|
4
|
+
|
5
|
+
NEW FEATURES:
|
6
|
+
|
7
|
+
* add support for Terraform version '~> 1.1.0`
|
8
|
+
|
9
|
+
DEPENDENCIES:
|
10
|
+
|
11
|
+
* update depends on terradactyl-terraform to '>= 1.1.0'
|
12
|
+
|
13
|
+
UPGRADEABLE:
|
14
|
+
|
15
|
+
* set '~> 1.0.0` as upgradeable
|
16
|
+
|
17
|
+
## 1.0.0 (2021-06-09)
|
18
|
+
|
19
|
+
NEW FEATURES:
|
20
|
+
|
21
|
+
* add support for Terraform version `~> 1.0.0`
|
22
|
+
|
23
|
+
BUG FIXES:
|
24
|
+
|
25
|
+
* fix bad test matrix
|
26
|
+
|
27
|
+
## 0.15.3 (2021-05-14)
|
28
|
+
|
29
|
+
BUG FIXES:
|
30
|
+
|
31
|
+
* fix `auto-approve` on `destroy` subcommand for Terraform version 0.15
|
32
|
+
* update all tests to use latest minor rev
|
33
|
+
|
34
|
+
## 0.15.2 (2021-05-02)
|
35
|
+
|
36
|
+
NEW FEATURES:
|
37
|
+
|
38
|
+
* make all stacks upgradeable, regardless of binary version
|
39
|
+
* add warning after upgrading to Terrafrom version 0.13
|
40
|
+
* expanded testing
|
41
|
+
|
42
|
+
BUG FIXES:
|
43
|
+
|
44
|
+
* do not init backend during upgrade
|
45
|
+
* fix edge case on stacks with no `versions.tf` file
|
46
|
+
|
3
47
|
## 0.15.1 (2021-04-28)
|
4
48
|
|
5
49
|
BUG FIXES:
|
data/README.md
CHANGED
@@ -189,7 +189,7 @@ Installs supporting components, namely Terraform itself...
|
|
189
189
|
|
190
190
|
#### upgrade
|
191
191
|
|
192
|
-
Upgrade abstracts the various Terraform subcommands related to upgrading individual stacks
|
192
|
+
Upgrade abstracts the various Terraform subcommands related to upgrading individual stacks.
|
193
193
|
|
194
194
|
terradactyl upgrade <stack>
|
195
195
|
|
data/lib/terradactyl/cli.rb
CHANGED
@@ -76,8 +76,9 @@ module Terradactyl
|
|
76
76
|
else
|
77
77
|
Stacks.error!(@stack)
|
78
78
|
print_crit "Failed to upgrade: #{@stack.name}"
|
79
|
+
throw :error
|
79
80
|
end
|
80
|
-
rescue Terradactyl::Terraform::
|
81
|
+
rescue Terradactyl::Terraform::VersionManager::VersionManagerError => e
|
81
82
|
print_crit "Error: #{e.message}"
|
82
83
|
exit 1
|
83
84
|
end
|
@@ -170,7 +171,7 @@ module Terradactyl
|
|
170
171
|
desc 'upgrade NAME', 'Cleans, inits, upgrades and formats an individual stack, by name'
|
171
172
|
def upgrade(name)
|
172
173
|
clean(name)
|
173
|
-
init(name)
|
174
|
+
init(name, backend: false)
|
174
175
|
upgrade_stack(name)
|
175
176
|
fmt(name)
|
176
177
|
end
|
@@ -271,8 +272,10 @@ module Terradactyl
|
|
271
272
|
end
|
272
273
|
|
273
274
|
desc 'init NAME', 'Init an individual stack, by name'
|
274
|
-
def init(name)
|
275
|
+
def init(name, backend: true)
|
275
276
|
@stack ||= Stack.new(name)
|
277
|
+
@stack.config.terraform.init.backend = backend
|
278
|
+
|
276
279
|
print_ok "Initializing: #{@stack.name}"
|
277
280
|
if @stack.init.zero?
|
278
281
|
print_ok "Initialized: #{@stack.name}"
|
data/lib/terradactyl/commands.rb
CHANGED
@@ -19,39 +19,28 @@ module Terradactyl
|
|
19
19
|
end
|
20
20
|
|
21
21
|
module Commands
|
22
|
-
class UnsupportedCommandError < RuntimeError
|
23
|
-
def initialize(msg)
|
24
|
-
super(msg)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
22
|
class Upgrade < Base
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
This stack may already be upgraded. Check the stack's specified
|
33
|
-
Terraform version and consult its builtin help for further
|
34
|
-
details.
|
35
|
-
ERROR
|
23
|
+
def execute
|
24
|
+
VersionManager.install
|
25
|
+
return 0 unless revision.upgradeable?
|
36
26
|
|
37
|
-
|
38
|
-
def error_unsupported
|
39
|
-
raise UnsupportedCommandError, ERROR_UNSUPPORTED
|
40
|
-
end
|
27
|
+
super
|
41
28
|
end
|
42
29
|
|
43
|
-
def
|
44
|
-
@
|
30
|
+
def next_version
|
31
|
+
@next_version ||= compute_upgrade
|
45
32
|
end
|
46
33
|
|
47
34
|
private
|
48
35
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
36
|
+
def revision
|
37
|
+
Terradactyl::Stack.revision
|
38
|
+
end
|
39
|
+
|
40
|
+
def compute_upgrade
|
41
|
+
maj, min, _rev = version.split('.')
|
42
|
+
resolution = VersionManager.resolve("~> #{maj}.#{min.to_i + 1}.0")
|
53
43
|
VersionManager.version = resolution
|
54
|
-
VersionManager.install
|
55
44
|
VersionManager.version
|
56
45
|
end
|
57
46
|
|
@@ -69,9 +58,13 @@ module Terradactyl
|
|
69
58
|
class << self
|
70
59
|
def extend_by_revision(tf_version, object)
|
71
60
|
anon_module = revision_module
|
61
|
+
revision = revision_constant(tf_version)
|
72
62
|
|
73
63
|
anon_module.include(self)
|
74
|
-
anon_module.prepend(
|
64
|
+
anon_module.prepend(revision)
|
65
|
+
|
66
|
+
object.class.define_singleton_method(:revision) { revision }
|
67
|
+
object.define_singleton_method(:revision) { revision }
|
75
68
|
|
76
69
|
object.extend(anon_module)
|
77
70
|
end
|
@@ -105,8 +98,8 @@ module Terradactyl
|
|
105
98
|
end
|
106
99
|
|
107
100
|
def revision_constant(tf_version)
|
108
|
-
|
109
|
-
const_get(
|
101
|
+
revision = Terradactyl::Terraform.calc_revision(tf_version)
|
102
|
+
const_get(revision)
|
110
103
|
end
|
111
104
|
end
|
112
105
|
|
@@ -182,34 +175,69 @@ module Terradactyl
|
|
182
175
|
# rubocop:enable Metrics/AbcSize
|
183
176
|
|
184
177
|
def upgrade
|
185
|
-
|
178
|
+
perform_upgrade
|
186
179
|
end
|
187
180
|
|
188
181
|
private
|
189
182
|
|
183
|
+
def versions_file
|
184
|
+
'versions.tf'
|
185
|
+
end
|
186
|
+
|
190
187
|
def settings_files
|
191
|
-
|
192
|
-
File.
|
188
|
+
Dir.glob('*.tf').each_with_object([]) do |file, memo|
|
189
|
+
File.open(file, 'r').each_line do |line|
|
190
|
+
if line.match(Common.required_versions_re)
|
191
|
+
memo << file
|
192
|
+
break
|
193
|
+
end
|
194
|
+
end
|
193
195
|
end
|
194
196
|
end
|
195
197
|
|
196
|
-
def
|
197
|
-
replace_me = /(?<assignment>(?:\n\s)*required_version\s+=\s+)(?<value>".*?")/m
|
198
|
-
|
198
|
+
def sanitize_terraform_settings
|
199
199
|
settings_files.each do |file|
|
200
|
-
|
201
|
-
substitution = nil.to_s
|
200
|
+
next if file == versions_file
|
202
201
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
end
|
202
|
+
write_stream = Tempfile.new(Common.tag)
|
203
|
+
File.open(file, 'r').each_line do |line|
|
204
|
+
write_stream.puts line unless line.match(Common.required_versions_re)
|
207
205
|
end
|
206
|
+
write_stream.close
|
207
|
+
FileUtils.mv(write_stream.path, file)
|
208
|
+
end
|
209
|
+
end
|
208
210
|
|
209
|
-
|
210
|
-
|
211
|
-
File.
|
211
|
+
def update_required_version(upgrade_version)
|
212
|
+
if File.exist?(versions_file)
|
213
|
+
settings = File.read(versions_file)
|
214
|
+
if (req_version = settings.match(Common.required_versions_re))
|
215
|
+
substitution = %(#{req_version[:assignment]}"~> #{upgrade_version}")
|
216
|
+
settings.sub!(Common.required_versions_re, substitution)
|
217
|
+
end
|
218
|
+
else
|
219
|
+
# This is ugly, so let's explain ...
|
220
|
+
#
|
221
|
+
# When the versions.tf is present, but the stack is ~> 0.11.0, the
|
222
|
+
# `terraform 0.12upgrade` subcommand will FAIL because it uses the
|
223
|
+
# presence of this file as the sole gauge as to whether or not
|
224
|
+
# the stack can be upgraded. So, why not just use `-force`? Haha yes ...
|
225
|
+
#
|
226
|
+
# When the `versions.tf` file exists and the `-force` flag is passed,
|
227
|
+
# it will create a `versions-1.tf` file ... FML :facepalm:
|
228
|
+
#
|
229
|
+
# So, make the creation of a de facto versions.tf contingent upon the
|
230
|
+
# Terraform upgrade_version. Yay.
|
231
|
+
unless upgrade_version =~ /0\.12/
|
232
|
+
settings = <<~VERSIONS
|
233
|
+
terraform {
|
234
|
+
required_version = "~> #{upgrade_version}"
|
235
|
+
}
|
236
|
+
VERSIONS
|
237
|
+
end
|
212
238
|
end
|
239
|
+
|
240
|
+
File.write(versions_file, settings) if settings
|
213
241
|
end
|
214
242
|
|
215
243
|
def upgrade_notice
|
@@ -220,51 +248,75 @@ module Terradactyl
|
|
220
248
|
This stack has been upgraded to version the described below and its
|
221
249
|
Terradactly config file (if it existed) has been removed.
|
222
250
|
|
223
|
-
|
251
|
+
#{insert}
|
224
252
|
|
225
|
-
|
253
|
+
NOTES:
|
226
254
|
|
227
255
|
• ALL Terraform version constraints are now specified in `versions.tf` using
|
228
256
|
the `required_version` directive.
|
229
257
|
|
230
|
-
• If your stack already
|
258
|
+
• If your stack already contained one or more `required_version` directives,
|
231
259
|
they have been consolidated into a single directive in `versions.tf`.
|
232
260
|
|
233
261
|
• Terraform provider version contraints ARE NOT upgraded automatically. You
|
234
262
|
will need to edit these MANUALLY.
|
235
263
|
|
236
264
|
• Before proceeding. please perform a `terradactyl quickplan` on your stack
|
237
|
-
to ensure the upgraded stack functions.
|
265
|
+
to ensure the upgraded stack functions as intended.
|
238
266
|
NOTICE
|
239
267
|
end
|
240
268
|
|
269
|
+
def upgrade_notice_rev013
|
270
|
+
<<~NOTICE
|
271
|
+
STOP UPGRADING!
|
272
|
+
|
273
|
+
Upgrading from Terraform 0.12 to 0.13 requires an apply to be performed
|
274
|
+
before continuing ...
|
275
|
+
|
276
|
+
DO NOT attempt to upgrade any further without first committing the existing
|
277
|
+
changes and seeing they are applied.
|
278
|
+
|
279
|
+
See the documentation here if you require more infomation ...
|
280
|
+
|
281
|
+
https://www.terraform.io/upgrade-guides/0-13.html
|
282
|
+
NOTICE
|
283
|
+
end
|
284
|
+
|
285
|
+
# rubocop:disable Metrics/AbcSize
|
241
286
|
def perform_upgrade
|
242
287
|
options = command_options.tap { |dat| dat.yes = true }
|
243
288
|
upgrade = Upgrade.new(dir_or_plan: nil, options: options)
|
244
289
|
|
245
|
-
|
290
|
+
sanitize_terraform_settings
|
291
|
+
|
292
|
+
update_required_version(upgrade.next_version)
|
246
293
|
|
247
294
|
if (result = upgrade.execute).zero?
|
248
|
-
update_required_version(upgrade.
|
295
|
+
update_required_version(upgrade.next_version)
|
249
296
|
FileUtils.rm_rf('terradactyl.yaml') if File.exist?('terradactyl.yaml')
|
250
297
|
end
|
251
298
|
|
252
|
-
print_content(upgrade_notice)
|
299
|
+
print_content(upgrade_notice) if result.zero?
|
300
|
+
|
301
|
+
print_crit(upgrade_notice_rev013) if upgrade.next_version =~ /0\.13/
|
253
302
|
|
254
303
|
result
|
255
304
|
end
|
305
|
+
# rubocop:enable Metrics/AbcSize
|
256
306
|
|
257
307
|
def load_plan_file
|
258
308
|
Terraform::PlanFile.new(plan_path: plan_file, parser: parser)
|
259
309
|
end
|
260
310
|
|
261
311
|
module Rev011
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
312
|
+
class << self
|
313
|
+
def upgradeable?
|
314
|
+
true
|
315
|
+
end
|
266
316
|
end
|
267
317
|
|
318
|
+
include Terraform::Commands
|
319
|
+
|
268
320
|
private
|
269
321
|
|
270
322
|
def parser
|
@@ -273,12 +325,14 @@ module Terradactyl
|
|
273
325
|
end
|
274
326
|
|
275
327
|
module Rev012
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
328
|
+
class << self
|
329
|
+
def upgradeable?
|
330
|
+
true
|
331
|
+
end
|
280
332
|
end
|
281
333
|
|
334
|
+
include Terraform::Commands
|
335
|
+
|
282
336
|
private
|
283
337
|
|
284
338
|
def parser
|
@@ -287,12 +341,14 @@ module Terradactyl
|
|
287
341
|
end
|
288
342
|
|
289
343
|
module Rev013
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
344
|
+
class << self
|
345
|
+
def upgradeable?
|
346
|
+
false
|
347
|
+
end
|
294
348
|
end
|
295
349
|
|
350
|
+
include Terraform::Commands
|
351
|
+
|
296
352
|
private
|
297
353
|
|
298
354
|
def parser
|
@@ -301,6 +357,12 @@ module Terradactyl
|
|
301
357
|
end
|
302
358
|
|
303
359
|
module Rev014
|
360
|
+
class << self
|
361
|
+
def upgradeable?
|
362
|
+
false
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
304
366
|
include Terraform::Commands
|
305
367
|
|
306
368
|
private
|
@@ -311,6 +373,12 @@ module Terradactyl
|
|
311
373
|
end
|
312
374
|
|
313
375
|
module Rev015
|
376
|
+
class << self
|
377
|
+
def upgradeable?
|
378
|
+
false
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
314
382
|
include Terraform::Commands
|
315
383
|
|
316
384
|
private
|
@@ -319,6 +387,38 @@ module Terradactyl
|
|
319
387
|
Terraform::Rev015::PlanFileParser
|
320
388
|
end
|
321
389
|
end
|
390
|
+
|
391
|
+
module Rev1_00
|
392
|
+
class << self
|
393
|
+
def upgradeable?
|
394
|
+
false
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
include Terraform::Commands
|
399
|
+
|
400
|
+
private
|
401
|
+
|
402
|
+
def parser
|
403
|
+
Terraform::Rev1_00::PlanFileParser
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
module Rev1_01
|
408
|
+
class << self
|
409
|
+
def upgradeable?
|
410
|
+
false
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
include Terraform::Commands
|
415
|
+
|
416
|
+
private
|
417
|
+
|
418
|
+
def parser
|
419
|
+
Terraform::Rev1_01::PlanFileParser
|
420
|
+
end
|
421
|
+
end
|
322
422
|
end
|
323
423
|
# rubocop:enable Metrics/ModuleLength
|
324
424
|
end
|
data/lib/terradactyl/common.rb
CHANGED
@@ -7,6 +7,14 @@ module Terradactyl
|
|
7
7
|
|
8
8
|
module_function
|
9
9
|
|
10
|
+
def required_versions_re
|
11
|
+
/(?<assignment>(?:\n\s)*required_version\s+=\s+)(?<value>".*?")/m
|
12
|
+
end
|
13
|
+
|
14
|
+
def supported_revisions
|
15
|
+
Terradactyl::Commands.constants.select { |c| c =~ /Rev/ }.sort
|
16
|
+
end
|
17
|
+
|
10
18
|
def config
|
11
19
|
@config ||= ConfigProject.instance
|
12
20
|
end
|
data/lib/terradactyl/config.rb
CHANGED
@@ -26,7 +26,7 @@ module Terradactyl
|
|
26
26
|
input: false
|
27
27
|
destroy:
|
28
28
|
parallelism: 5
|
29
|
-
|
29
|
+
auto_approve: true
|
30
30
|
environment:
|
31
31
|
TF_PLUGIN_CACHE_DIR: ~/.terraform.d/plugins
|
32
32
|
misc:
|
@@ -170,22 +170,32 @@ module Terradactyl
|
|
170
170
|
"#{stack_path}/#{plan_file}"
|
171
171
|
end
|
172
172
|
|
173
|
+
def versions_file
|
174
|
+
"#{stack_path}/versions.tf"
|
175
|
+
end
|
176
|
+
|
173
177
|
private
|
174
178
|
|
175
179
|
def terraform_required_version
|
176
|
-
matches = TERRAFORM_SETTINGS_FILES.
|
180
|
+
matches = TERRAFORM_SETTINGS_FILES.each_with_object([]) do |file, memo|
|
177
181
|
path = File.join(stack_path, file)
|
178
|
-
|
179
|
-
|
182
|
+
next unless File.exist?(path)
|
183
|
+
|
184
|
+
File.readlines(path).each do |line|
|
185
|
+
next if line =~ /(?:\s*#\s*)/
|
186
|
+
|
187
|
+
if (match = line.match(Common.required_versions_re))
|
188
|
+
memo << match
|
189
|
+
end
|
180
190
|
end
|
181
191
|
end
|
182
192
|
|
183
|
-
return {} unless matches.
|
193
|
+
return {} unless matches.any?
|
184
194
|
|
185
195
|
{
|
186
196
|
'terradactyl' => {
|
187
197
|
'terraform' => {
|
188
|
-
'version' => matches.last[:
|
198
|
+
'version' => matches.last[:value].delete('"')
|
189
199
|
}
|
190
200
|
}
|
191
201
|
}
|
@@ -204,9 +214,5 @@ module Terradactyl
|
|
204
214
|
def overlay_specifies_version?(overlay)
|
205
215
|
overlay['terradactyl']&.fetch('terraform', {})&.fetch('version', nil)
|
206
216
|
end
|
207
|
-
|
208
|
-
def terraform_required_version_re
|
209
|
-
/(?:\s*terraform\s*{(?:\n|\s)*.+required_version\s*=\s*)"(?<version>.*)"(?:(?:\n|\s)*.+})/m
|
210
|
-
end
|
211
217
|
end
|
212
218
|
end
|
data/lib/terradactyl/version.rb
CHANGED
data/terradactyl.gemspec
CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_dependency 'deep_merge', '~> 1.2'
|
34
34
|
spec.add_dependency 'bundler', '>= 1.16'
|
35
35
|
spec.add_dependency 'rake', '>= 10.0'
|
36
|
-
spec.add_dependency 'terradactyl-terraform', '>=
|
36
|
+
spec.add_dependency 'terradactyl-terraform', '>= 1.1.0'
|
37
37
|
|
38
38
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
39
39
|
spec.add_development_dependency 'pry', '~> 0.12'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terradactyl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Warsing
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: 1.1.0
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: 1.1.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rspec
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|