terradactyl 0.15.1 → 0.15.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0bc592a89bdefefae6460b67cf305a20c9a204f7960d8f7adc060e6b45352d20
4
- data.tar.gz: c2f4083336586251254b15970c97c00f63dd0d07c5354e14f00b2c9ee6fb840c
3
+ metadata.gz: a988ff3b16d74047633cd66e066673cd2fdf761557939a24bc7a234b0bb26920
4
+ data.tar.gz: ab15b45df02d228d06a1ede2330048b613b4fb602436020c073d48e2da778b1a
5
5
  SHA512:
6
- metadata.gz: 48283e55d2f375e71b4aef40e831cb4f973f98a42382972db7a2b099735725f633348995fd1cc8e4a9075799add4a1ce8ac0b41ad755fee08e5bcdd6e709499a
7
- data.tar.gz: 3eb7984c57b37fc6a72dd350a8deeed2b77b228cf5f7e0ace79cde86b5c3004fb4bc9f78d651a059b0a769ba2572a06db93a58b2c75ace1c7140b3091a930f95
6
+ metadata.gz: dfd2683371ff4d31f7ba907f6ea497fda420cd8ab5644b32a5efacc2cf6176bfca30c138c679f94e221e30fb8f76c6f06c59b4a7e027762835688894a5d75323
7
+ data.tar.gz: 36d4db1bc332ed25196a1cf43c31b933397be36764d44bb6521e87fbfd2f173334f5c438046eddb08cdb1923b9cf3b2c92a015f4efd0b1645e2e0cdc29307a63
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.15.2 (2021-05-02)
4
+
5
+ NEW FEATURES:
6
+
7
+ * make all stacks upgradeable, regardless of binary version
8
+ * add warning after upgrading to Terrafrom version 0.13
9
+ * expanded testing
10
+
11
+ BUG FIXES:
12
+
13
+ * do not init backend during upgrade
14
+ * fix edge case on stacks with no `versions.tf` file
15
+
3
16
  ## 0.15.1 (2021-04-28)
4
17
 
5
18
  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
@@ -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
@@ -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
@@ -170,13 +170,17 @@ 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
180
  matches = TERRAFORM_SETTINGS_FILES.map do |file|
177
181
  path = File.join(stack_path, file)
178
182
  if File.exist?(path)
179
- File.read(path).match(terraform_required_version_re)
183
+ File.read(path).match(Common.required_versions_re)
180
184
  end
181
185
  end
182
186
 
@@ -185,7 +189,7 @@ module Terradactyl
185
189
  {
186
190
  'terradactyl' => {
187
191
  'terraform' => {
188
- 'version' => matches.last[:version]
192
+ 'version' => matches.last[:value].delete('"')
189
193
  }
190
194
  }
191
195
  }
@@ -204,9 +208,5 @@ module Terradactyl
204
208
  def overlay_specifies_version?(overlay)
205
209
  overlay['terradactyl']&.fetch('terraform', {})&.fetch('version', nil)
206
210
  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
211
  end
212
212
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Terradactyl
4
- VERSION = '0.15.1'
4
+ VERSION = '0.15.2'
5
5
  end
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: 0.15.2
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-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor