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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0bc592a89bdefefae6460b67cf305a20c9a204f7960d8f7adc060e6b45352d20
4
- data.tar.gz: c2f4083336586251254b15970c97c00f63dd0d07c5354e14f00b2c9ee6fb840c
3
+ metadata.gz: 49fe1966595f9b6757978cdb175659deb41290b3f24ef7c410a03c03c72172d2
4
+ data.tar.gz: 232ab09501fe09d0f8ac3163065269f43f9200dcb7ea3d68c0b0dfff057fafdc
5
5
  SHA512:
6
- metadata.gz: 48283e55d2f375e71b4aef40e831cb4f973f98a42382972db7a2b099735725f633348995fd1cc8e4a9075799add4a1ce8ac0b41ad755fee08e5bcdd6e709499a
7
- data.tar.gz: 3eb7984c57b37fc6a72dd350a8deeed2b77b228cf5f7e0ace79cde86b5c3004fb4bc9f78d651a059b0a769ba2572a06db93a58b2c75ace1c7140b3091a930f95
6
+ metadata.gz: 6e22c6c6159ba55bafcc83e0a919b2730647568f158853e9047e3ce08574047f5dcfd539fb3eadfffddc8f94d6c3476d61a892b7875181f40b54e32f0a407521
7
+ data.tar.gz: 5ca0d7097d609e041c974a6067829e564731e155dbb3cfdbc67a8965f47292f1d89067932285cdfd4d581b84e0da4d30e282cf1307f5521e25ff9e00fe2dfbda
data/.rubocop.yml CHANGED
@@ -10,6 +10,8 @@ Metrics/CyclomaticComplexity:
10
10
  Max: 10
11
11
  Metrics/ClassLength:
12
12
  Max: 115
13
+ Naming/ClassAndModuleCamelCase:
14
+ Enabled: false
13
15
  Naming/UncommunicativeMethodParamName:
14
16
  MinNameLength: 2
15
17
  Style/IfUnlessModifier:
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 (`0.12upgrade` and `0.13upgrade`).
192
+ Upgrade abstracts the various Terraform subcommands related to upgrading individual stacks.
193
193
 
194
194
  terradactyl upgrade <stack>
195
195
 
@@ -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::Commands::UnsupportedCommandError => e
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}"
@@ -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
- ERROR_UNSUPPORTED = <<~ERROR
30
- subcommand `upgrade` is not supported on this stack!
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
- class << self
38
- def error_unsupported
39
- raise UnsupportedCommandError, ERROR_UNSUPPORTED
40
- end
27
+ super
41
28
  end
42
29
 
43
- def version
44
- @version ||= calculate_upgrade(super)
30
+ def next_version
31
+ @next_version ||= compute_upgrade
45
32
  end
46
33
 
47
34
  private
48
35
 
49
- def calculate_upgrade(current_version)
50
- maj, min, _rev = current_version.split('.')
51
- min = min.to_i < 13 ? (min.to_i + 1) : min
52
- resolution = VersionManager.resolve("~> #{maj}.#{min}.0")
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(revision_constant(tf_version))
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
- revision_name = ['Rev', *tf_version.split('.').take(2)].join
109
- const_get(revision_name)
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
- Upgrade.error_unsupported
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
- Terradactyl::ConfigStack::TERRAFORM_SETTINGS_FILES.select do |file|
192
- File.exist?(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 update_required_version(upgrade_version)
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
- settings = File.read(file)
201
- substitution = nil.to_s
200
+ next if file == versions_file
202
201
 
203
- if (req_version = settings.match(replace_me))
204
- if file == 'versions.tf'
205
- substitution = %(#{req_version[:assignment]}"~> #{upgrade_version}")
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
- settings.sub!(replace_me, substitution)
210
-
211
- File.write(file, settings)
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
- #{insert}
251
+ #{insert}
224
252
 
225
- NOTES:
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 containedo one or more `required_version` directives,
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
- update_required_version(upgrade.version)
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.version)
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
- include Terraform::Commands
263
-
264
- def upgrade
265
- perform_upgrade
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
- include Terraform::Commands
277
-
278
- def upgrade
279
- perform_upgrade
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
- include Terraform::Commands
291
-
292
- def upgrade
293
- perform_upgrade
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
@@ -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
@@ -26,7 +26,7 @@ module Terradactyl
26
26
  input: false
27
27
  destroy:
28
28
  parallelism: 5
29
- force: true
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.map do |file|
180
+ matches = TERRAFORM_SETTINGS_FILES.each_with_object([]) do |file, memo|
177
181
  path = File.join(stack_path, file)
178
- if File.exist?(path)
179
- File.read(path).match(terraform_required_version_re)
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.compact!.any?
193
+ return {} unless matches.any?
184
194
 
185
195
  {
186
196
  'terradactyl' => {
187
197
  'terraform' => {
188
- 'version' => matches.last[:version]
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Terradactyl
4
- VERSION = '0.15.1'
4
+ VERSION = '1.1.0'
5
5
  end
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', '>= 0.15.0'
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: 0.15.1
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-04-28 00:00:00.000000000 Z
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: 0.15.0
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: 0.15.0
110
+ version: 1.1.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rspec
113
113
  requirement: !ruby/object:Gem::Requirement