terradactyl 0.13.2 → 0.15.0
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +80 -12
- data/examples/multi-tf-version/stacks/tfv11/terradactyl.yaml +1 -1
- data/examples/multi-tf-version/stacks/tfv12/example.tf +3 -1
- data/examples/multi-tf-version/stacks/tfv12/versions.tf +3 -0
- data/examples/multi-tf-version/stacks/tfv13/versions.tf +8 -0
- data/examples/multi-tf-version/stacks/tfv14/example.tf +1 -0
- data/examples/multi-tf-version/stacks/tfv14/versions.tf +8 -0
- data/examples/multi-tf-version/stacks/tfv15/example.tf +1 -0
- data/examples/multi-tf-version/stacks/tfv15/versions.tf +8 -0
- data/examples/multi-tf-version/terradactyl.yaml +1 -1
- data/lib/terradactyl/cli.rb +86 -10
- data/lib/terradactyl/commands.rb +128 -14
- data/lib/terradactyl/config.rb +45 -0
- data/lib/terradactyl/stack.rb +4 -0
- data/lib/terradactyl/version.rb +1 -1
- data/terradactyl.gemspec +1 -2
- metadata +11 -7
- data/examples/multi-tf-version/stacks/tfv12/terradactyl.yaml +0 -3
- data/examples/multi-tf-version/stacks/tfv13/terradactyl.yaml +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2a88b521150fa75bede628b6a89642b308b873439b8ab1c321c5c0c4f223670
|
4
|
+
data.tar.gz: ac90f280fec5f7f3ce98b734c407f335b158863df5c324b577dce98e34878f91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 525638ac61294ee05b8cbc0618b467fb4b32910c09bb5c6f8269e690ae2f70ae9764543bc2923fa3d1629591a5b9d952019fbfee0326202f39514bdf234c087a
|
7
|
+
data.tar.gz: ff919fb3c9b2bc11227d0c1d6668aa270d05e273af136a96d85d7afe67139c26979d1e375f51a69792101c50d8acf400f2e3f6629b009b928491f07c43213aa6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 0.15.0 (2021-04-27)
|
4
|
+
|
5
|
+
NEW FEATURES:
|
6
|
+
|
7
|
+
* add support for Terraform version `0.14.x`
|
8
|
+
* add support for Terraform version `0.15.x`
|
9
|
+
* add new subcommand `install`
|
10
|
+
* generic component installation; presently only supports `terraform`
|
11
|
+
- permits on-demand installation of any available Terraform binary
|
12
|
+
* add new subcommand `upgrade`
|
13
|
+
* performs a Terraform upgrade of the target stack
|
14
|
+
* add support for native HCL Terraform contraints
|
15
|
+
* terradactyl will now search for Terraform version contraints in the following files: `settings.tf`, `versions.tf` and `backend.tf`
|
16
|
+
* update version expression parsing to match Terraform's own
|
17
|
+
* terradactyl version expression parsing should now operate the same way Terraform's own does, including support for version ranges
|
18
|
+
|
3
19
|
## 0.13.2 (2020-12-09)
|
4
20
|
|
5
21
|
BUG FIXES:
|
data/README.md
CHANGED
@@ -19,7 +19,7 @@ Terradactyl simplifies managing large heterogeneous Terraform monorepos by intro
|
|
19
19
|
|
20
20
|
Requires Ruby 2.5 or greater.
|
21
21
|
|
22
|
-
NOTE: Terraform sub-command operations are only supported between stable versions
|
22
|
+
NOTE: Terraform sub-command operations are only supported between stable versions `>= 0.11.x` to `~> 0.15.x`.
|
23
23
|
|
24
24
|
## Installation
|
25
25
|
|
@@ -83,6 +83,14 @@ The Terradactyl CLI is installed with a symlink so it may be called by its full
|
|
83
83
|
$ terradactyl help
|
84
84
|
$ td help
|
85
85
|
|
86
|
+
#### install terraform
|
87
|
+
|
88
|
+
##### NOTE: You do not need to explicitly install Terraform, it will be downloaded and installed automatically, if your stack is configured to do so -- this is just to demonstrate on-demand installs ...
|
89
|
+
|
90
|
+
This is optional!
|
91
|
+
|
92
|
+
$ terradactyl install terraform --version=0.15.1
|
93
|
+
|
86
94
|
#### quickplan a single stack
|
87
95
|
|
88
96
|
You can specify the relative path to the stack OR the just the stack name. These two commands are equivalent:
|
@@ -110,6 +118,18 @@ When complete, you should have a JSON report that you can pass to other processe
|
|
110
118
|
|
111
119
|
$ terradactyl smartapply
|
112
120
|
|
121
|
+
#### upgrade a legacy stack
|
122
|
+
|
123
|
+
Running this one time will upgrade it to next minor revision of Terraform ...
|
124
|
+
|
125
|
+
# Take me to Terraform v12
|
126
|
+
$ terradactyl upgrade stacks/tfv11
|
127
|
+
|
128
|
+
Running it again will bump it again!
|
129
|
+
|
130
|
+
# Take me to Terraform v13
|
131
|
+
$ terradactyl upgrade stacks/tfv11
|
132
|
+
|
113
133
|
#### clean all the stacks
|
114
134
|
|
115
135
|
$ terradactyl clean-all
|
@@ -122,7 +142,7 @@ See the [Configuration](#configuration) section for more info on how to control
|
|
122
142
|
|
123
143
|
## Operation
|
124
144
|
|
125
|
-
NOTE: `terradactyl` (symlinked as `td`) ONLY operates in the root of your monorepo. In order to execute any
|
145
|
+
NOTE: `terradactyl` (symlinked as `td`) ONLY operates in the root of your monorepo. In order to execute any subcommands, your working directory must contain your project-level configuration file, otherwise you will receive this:
|
126
146
|
|
127
147
|
FATAL: Could not load project file: `terradactyl.yaml`, No such file or directory @ rb_sysopen - terradactyl.yaml
|
128
148
|
|
@@ -135,9 +155,9 @@ Generally speaking, Terradactyl operates on the principle of **plan file** (`*.t
|
|
135
155
|
|
136
156
|
In some cases, this might seem onerous, but it pays dividends in team workflow and CI/CD contexts.
|
137
157
|
|
138
|
-
### Supported
|
158
|
+
### Supported subcommands
|
139
159
|
|
140
|
-
Terradactyl was created to facilitate the using Terraform in a CI environment. As such, some of the more exotic ad hoc user-focused
|
160
|
+
Terradactyl was created to facilitate the using Terraform in a CI environment. As such, some of the more exotic ad hoc user-focused subcommands have not received any effort in integration. The following is a list of the supported Terraform subcommands:
|
141
161
|
|
142
162
|
* apply
|
143
163
|
* destroy
|
@@ -147,6 +167,32 @@ Terradactyl was created to facilitate the using Terraform in a CI environment. A
|
|
147
167
|
* refresh
|
148
168
|
* validate
|
149
169
|
|
170
|
+
### Special utility subcommands
|
171
|
+
|
172
|
+
Terradactyl add some unique utility commands that permit you to more readily manage your Terraform stacks.
|
173
|
+
|
174
|
+
#### install
|
175
|
+
|
176
|
+
Installs supporting components, namely Terraform itself...
|
177
|
+
|
178
|
+
# Install the latest terraform binary
|
179
|
+
terradactly install terraform
|
180
|
+
|
181
|
+
# Install pessimistic version
|
182
|
+
terradactyl install terraform --version="~> 0.13.0"
|
183
|
+
|
184
|
+
# Install ranged version
|
185
|
+
terradactyl install terraform --version=">= 0.14.5, <= 0.14.7"
|
186
|
+
|
187
|
+
# Install explicit version
|
188
|
+
terradactyl install terraform --version=0.15.0-beta2
|
189
|
+
|
190
|
+
#### upgrade
|
191
|
+
|
192
|
+
Upgrade abstracts the various Terraform subcommands related to upgrading individual stacks (`0.12upgrade` and `0.13upgrade`).
|
193
|
+
|
194
|
+
terradactyl upgrade <stack>
|
195
|
+
|
150
196
|
### Meta-commands
|
151
197
|
|
152
198
|
Terradactyl provides a few useful meta-commands that can help you avoid repetitive multi-phase Terraform operations. Here are a few ...
|
@@ -166,7 +212,7 @@ Apply or Refresh _ANY_ stack containing a plan file.
|
|
166
212
|
|
167
213
|
### Getting Help
|
168
214
|
|
169
|
-
For a list of available
|
215
|
+
For a list of available subcommands do:
|
170
216
|
|
171
217
|
$ terradactyl help
|
172
218
|
|
@@ -195,7 +241,7 @@ You can dump the compiled configuration for your project using the `defaults` su
|
|
195
241
|
```yaml
|
196
242
|
terradactyl: <Object, Terradactyl config>
|
197
243
|
base_folder: <String, the sub-directory for all your Terraform stacks, default=stacks>
|
198
|
-
terraform: <Object, configuration to Terraform
|
244
|
+
terraform: <Object, configuration to Terraform subcommands and binaries>
|
199
245
|
binary: <String, path to the Terraform binary you wish to use, default=nil>
|
200
246
|
version: <String, explicit or implict Terraform version, default=nil>
|
201
247
|
autoinstall: <Bool, perform automatic Terraform installations, default=true>
|
@@ -228,7 +274,7 @@ terradactyl: <Object, Terradactyl config>
|
|
228
274
|
|
229
275
|
### Terraform sub-command arguments
|
230
276
|
|
231
|
-
Note that the config above contains config for Terraform
|
277
|
+
Note that the config above contains config for Terraform subcommands. for example:
|
232
278
|
|
233
279
|
```yaml
|
234
280
|
terradactyl:
|
@@ -243,12 +289,12 @@ Each of the keys in the `plan` object correspond to an argument passed to the `t
|
|
243
289
|
|
244
290
|
terraform -lock=false -parallelism=5 -detailed-exitcode
|
245
291
|
|
246
|
-
There are two conventions to keep in mind when configuring
|
292
|
+
There are two conventions to keep in mind when configuring subcommands:
|
247
293
|
|
248
294
|
1. any sub-command option which toggles behaviour (i.e. `-detailed-exitcode`) requires a specific Boolean value of `true` OR `false`
|
249
295
|
2. any sub-command option that is hyphenated (i.e. `-detailed-exitcode`) is set in the config using an **underscore** (i.e `detailed_exitcode`)
|
250
296
|
|
251
|
-
If you need to tweak or augment any of the default arguments passed to any of the supported Terraform
|
297
|
+
If you need to tweak or augment any of the default arguments passed to any of the supported Terraform subcommands, you can do so by adding them to the config.
|
252
298
|
|
253
299
|
Example:
|
254
300
|
|
@@ -260,7 +306,7 @@ terradactyl:
|
|
260
306
|
backup: /tmp/tfbackup
|
261
307
|
```
|
262
308
|
|
263
|
-
In addition, you can override the `echo` and `quiet` settings for any of the Terraform
|
309
|
+
In addition, you can override the `echo` and `quiet` settings for any of the Terraform subcommands:
|
264
310
|
|
265
311
|
```yaml
|
266
312
|
terradactyl:
|
@@ -279,9 +325,29 @@ This can assist in debugging.
|
|
279
325
|
|
280
326
|
### Terraform version management
|
281
327
|
|
328
|
+
Terradactyl gives you some powerful ways to manage which versions of Terraform you support and where.
|
329
|
+
|
330
|
+
You may set **project-wide** OR **stack-explicit** versions, by using a config file (`terradactyl.yaml`, see [Configuration](#configuration)).
|
331
|
+
|
332
|
+
In addition, Terradactyl will also, search for a stack's desired Terraform version from one of **your HCL files**.
|
333
|
+
|
334
|
+
terraform {
|
335
|
+
required_version = "~> 0.13.0"
|
336
|
+
}
|
337
|
+
|
338
|
+
If a configuration like the one above is discovered in your stack's ...
|
339
|
+
|
340
|
+
* `settings.tf`
|
341
|
+
* `versions.tf`
|
342
|
+
* `backend.tf`
|
343
|
+
|
344
|
+
... file, Terradactyl will download and use that version as required.
|
345
|
+
|
346
|
+
NOTE: These files are searched in the order you see above. If you specify `required_version` multiple times, the last one discovered is used.
|
347
|
+
|
282
348
|
#### Explicit versions
|
283
349
|
|
284
|
-
By default, Terradactyl will always use the **latest** stable version of Terraform.
|
350
|
+
By default, Terradactyl will always use the **latest** stable version of Terraform. So, if you don't specify a version, you will always get the latest stable version of Terraform available.
|
285
351
|
|
286
352
|
But, as part of Terradactyl's configuration, you can specify a **project** Terraform version, making it the default for _your_ monorepo:
|
287
353
|
|
@@ -291,7 +357,9 @@ terradactyl:
|
|
291
357
|
version: 0.12.29
|
292
358
|
```
|
293
359
|
|
294
|
-
Still, because Terradactyl's configuration is hierarchic,
|
360
|
+
Still, because Terradactyl's configuration is hierarchic, you can also specify a version at the project level ...
|
361
|
+
|
362
|
+
Yes! **Each stack may use a different version of Terradactyl independent of any other.**
|
295
363
|
|
296
364
|
See [examples/multi-tf-version](examples/multi-tf-version) for this setup.
|
297
365
|
|
@@ -0,0 +1 @@
|
|
1
|
+
resource "null_resource" "baz" {}
|
@@ -0,0 +1 @@
|
|
1
|
+
resource "null_resource" "baz" {}
|
data/lib/terradactyl/cli.rb
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Fix for https://github.com/erikhuda/thor/issues/398
|
4
|
+
class Thor
|
5
|
+
module Shell
|
6
|
+
class Basic
|
7
|
+
def print_wrapped(message, options = {})
|
8
|
+
indent = (options[:indent] || 0).to_i
|
9
|
+
if indent.zero?
|
10
|
+
stdout.puts message
|
11
|
+
else
|
12
|
+
message.each_line do |message_line|
|
13
|
+
stdout.print ' ' * indent
|
14
|
+
stdout.puts message_line.chomp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
3
22
|
module Terradactyl
|
4
23
|
# rubocop:disable Metrics/ClassLength
|
5
24
|
class CLI < Thor
|
@@ -14,6 +33,7 @@ module Terradactyl
|
|
14
33
|
super
|
15
34
|
end
|
16
35
|
|
36
|
+
# rubocop:disable Metrics/BlockLength
|
17
37
|
no_commands do
|
18
38
|
# Monkey-patch Thor internal method to break out of nested calls
|
19
39
|
def invoke_command(command, *args)
|
@@ -43,7 +63,12 @@ module Terradactyl
|
|
43
63
|
File.write data_file, JSON.pretty_generate(report)
|
44
64
|
print_ok 'Done!'
|
45
65
|
end
|
66
|
+
|
67
|
+
def terraform_latest
|
68
|
+
Terradactyl::Terraform::VersionManager.latest
|
69
|
+
end
|
46
70
|
end
|
71
|
+
# rubocop:enable Metrics/BlockLength
|
47
72
|
|
48
73
|
#################################################################
|
49
74
|
# GENERIC TASKS
|
@@ -247,7 +272,7 @@ module Terradactyl
|
|
247
272
|
when 1
|
248
273
|
Stacks.error!(@stack)
|
249
274
|
print_crit "Plan failed: #{@stack.name}"
|
250
|
-
@stack.
|
275
|
+
@stack.print_error
|
251
276
|
throw :error
|
252
277
|
when 2
|
253
278
|
Stacks.dirty!(@stack)
|
@@ -289,13 +314,7 @@ module Terradactyl
|
|
289
314
|
print_ok "Cleaned: #{@stack.name}"
|
290
315
|
end
|
291
316
|
|
292
|
-
|
293
|
-
# HIDDEN TARGETED STACK TASKS
|
294
|
-
# * These tasks are destructive in nature and do not require
|
295
|
-
# regular use.
|
296
|
-
#################################################################
|
297
|
-
|
298
|
-
desc 'apply NAME', 'Apply an individual stack, by name', hide: true
|
317
|
+
desc 'apply NAME', 'Apply an individual stack, by name'
|
299
318
|
def apply(name)
|
300
319
|
@stack ||= Stack.new(name)
|
301
320
|
print_warning "Applying: #{@stack.name}"
|
@@ -307,7 +326,7 @@ module Terradactyl
|
|
307
326
|
end
|
308
327
|
end
|
309
328
|
|
310
|
-
desc 'refresh NAME', 'Refresh state on an individual stack, by name'
|
329
|
+
desc 'refresh NAME', 'Refresh state on an individual stack, by name'
|
311
330
|
def refresh(name)
|
312
331
|
@stack ||= Stack.new(name)
|
313
332
|
print_crit "Refreshing: #{@stack.name}"
|
@@ -319,7 +338,7 @@ module Terradactyl
|
|
319
338
|
end
|
320
339
|
end
|
321
340
|
|
322
|
-
desc 'destroy NAME', 'Destroy an individual stack, by name'
|
341
|
+
desc 'destroy NAME', 'Destroy an individual stack, by name'
|
323
342
|
def destroy(name)
|
324
343
|
@stack ||= Stack.new(name)
|
325
344
|
print_crit "Destroying: #{@stack.name}"
|
@@ -330,6 +349,63 @@ module Terradactyl
|
|
330
349
|
print_crit "Failed to apply changes: #{@stack.name}"
|
331
350
|
end
|
332
351
|
end
|
352
|
+
|
353
|
+
#################################################################
|
354
|
+
# PROJECT-LEVEL UTILITY TASKS
|
355
|
+
# * These tasks are managing project-wide characteristics or
|
356
|
+
# invoking useful commands.
|
357
|
+
#################################################################
|
358
|
+
|
359
|
+
desc 'install COMPONENT', 'Installs specified component'
|
360
|
+
long_desc <<~LONGDESC
|
361
|
+
The `terradactyl install COMPONENT` subcommand perfoms installations of
|
362
|
+
prerequisties. At present, only Terraform binaries are supported.
|
363
|
+
Here are a few examples:
|
364
|
+
# Install latest
|
365
|
+
`terradactyl install terraform`
|
366
|
+
# Install pessimistic version
|
367
|
+
`terradactyl install terraform --version="~> 0.13.0"`
|
368
|
+
# Install ranged version
|
369
|
+
`terradactyl install terraform --version=">= 0.14.5, <= 0.14.7"`
|
370
|
+
# Install explicit version
|
371
|
+
`terradactyl install terraform --version=0.15.0-beta2`
|
372
|
+
|
373
|
+
LONGDESC
|
374
|
+
option :version, type: :string, default: 'latest'
|
375
|
+
# rubocop:disable Metrics/AbcSize
|
376
|
+
def install(component)
|
377
|
+
case component.to_sym
|
378
|
+
when :terraform
|
379
|
+
print_warning "Installing: #{component}, version: #{options[:version]}"
|
380
|
+
version = options[:version] == 'latest' ? terraform_latest : options[:version]
|
381
|
+
Terradactyl::Terraform::VersionManager.reset!
|
382
|
+
Terradactyl::Terraform::VersionManager.version = version
|
383
|
+
Terradactyl::Terraform::VersionManager.install
|
384
|
+
if Terradactyl::Terraform::VersionManager.binary
|
385
|
+
print_ok "Installed: #{Terradactyl::Terraform::VersionManager.binary}"
|
386
|
+
end
|
387
|
+
else
|
388
|
+
msg = %(Operation not supported -- I don't know how to install: #{component})
|
389
|
+
print_crit msg
|
390
|
+
exit 1
|
391
|
+
end
|
392
|
+
end
|
393
|
+
# rubocop:enable Metrics/AbcSize
|
394
|
+
|
395
|
+
desc 'upgrade NAME', 'Upgrade an individual stack, by name'
|
396
|
+
def upgrade(name)
|
397
|
+
@stack ||= Stack.new(name)
|
398
|
+
print_warning "Upgrading: #{@stack.name}"
|
399
|
+
if @stack.upgrade.zero?
|
400
|
+
print_ok "Upgraded: #{@stack.name}"
|
401
|
+
else
|
402
|
+
Stacks.error!(@stack)
|
403
|
+
print_crit "Failed to upgrade: #{@stack.name}"
|
404
|
+
end
|
405
|
+
rescue Terradactyl::Terraform::Commands::UnsupportedCommandError => e
|
406
|
+
print_crit "Error: #{e.message}"
|
407
|
+
exit 1
|
408
|
+
end
|
333
409
|
end
|
334
410
|
# rubocop:enable Metrics/ClassLength
|
335
411
|
end
|
data/lib/terradactyl/commands.rb
CHANGED
@@ -1,6 +1,70 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Terradactyl
|
4
|
+
module Terraform
|
5
|
+
module Subcommands
|
6
|
+
module Upgrade
|
7
|
+
def defaults
|
8
|
+
{
|
9
|
+
'yes' => false
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def switches
|
14
|
+
%w[
|
15
|
+
yes
|
16
|
+
]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Commands
|
22
|
+
class UnsupportedCommandError < RuntimeError
|
23
|
+
def initialize(msg)
|
24
|
+
super(msg)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
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
|
36
|
+
|
37
|
+
class << self
|
38
|
+
def error_unsupported
|
39
|
+
raise UnsupportedCommandError, ERROR_UNSUPPORTED
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def version
|
44
|
+
@version ||= calculate_upgrade(super)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
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")
|
53
|
+
VersionManager.version = resolution
|
54
|
+
VersionManager.install
|
55
|
+
VersionManager.version
|
56
|
+
end
|
57
|
+
|
58
|
+
def subcmd
|
59
|
+
pre = version.slice(/\d+\.\d+/)
|
60
|
+
sig = self.class.name.split('::').last.downcase
|
61
|
+
sig == 'base' ? '' : "#{pre}#{sig}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# rubocop:disable Metrics/ModuleLength
|
4
68
|
module Commands
|
5
69
|
class << self
|
6
70
|
def extend_by_revision(tf_version, object)
|
@@ -63,18 +127,17 @@ module Terradactyl
|
|
63
127
|
options: options,
|
64
128
|
capture: true)
|
65
129
|
|
66
|
-
|
67
|
-
when 0
|
68
|
-
'No changes. Infrastructure is up-to-date.'
|
69
|
-
when 1
|
70
|
-
captured.stderr
|
71
|
-
when 2
|
72
|
-
captured.stdout
|
73
|
-
end
|
130
|
+
@plan_file_obj = load_plan_file
|
74
131
|
|
75
|
-
|
76
|
-
|
77
|
-
|
132
|
+
case captured.exitstatus
|
133
|
+
when 0
|
134
|
+
'No changes. Infrastructure is up-to-date.'
|
135
|
+
when 1
|
136
|
+
@plan_file_obj.error_output = captured.stderr
|
137
|
+
when 2
|
138
|
+
@plan_file_obj.plan_output = captured.stdout
|
139
|
+
@plan_file_obj.save
|
140
|
+
end
|
78
141
|
|
79
142
|
captured.exitstatus
|
80
143
|
end
|
@@ -118,8 +181,30 @@ module Terradactyl
|
|
118
181
|
end
|
119
182
|
# rubocop:enable Metrics/AbcSize
|
120
183
|
|
184
|
+
def upgrade
|
185
|
+
Upgrade.error_unsupported
|
186
|
+
end
|
187
|
+
|
121
188
|
private
|
122
189
|
|
190
|
+
def perform_upgrade
|
191
|
+
options = command_options.tap { |dat| dat.yes = true }
|
192
|
+
upgrade = Upgrade.new(dir_or_plan: nil, options: options)
|
193
|
+
req_ver = /((?:\n\s)*required_version\s=\s)".*"/m
|
194
|
+
result = upgrade.execute
|
195
|
+
|
196
|
+
if result.zero?
|
197
|
+
settings = File.read('versions.tf').lstrip
|
198
|
+
settings.sub!(req_ver, %(#{Regexp.last_match(1)}"~> #{upgrade.version}"))
|
199
|
+
|
200
|
+
if File.write('versions.tf', settings)
|
201
|
+
FileUtils.rm_rf('terradactyl.yaml') if File.exist?('terradactyl.yaml')
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
result
|
206
|
+
end
|
207
|
+
|
123
208
|
def load_plan_file
|
124
209
|
Terraform::PlanFile.new(plan_path: plan_file, parser: parser)
|
125
210
|
end
|
@@ -127,8 +212,8 @@ module Terradactyl
|
|
127
212
|
module Rev011
|
128
213
|
include Terraform::Commands
|
129
214
|
|
130
|
-
def
|
131
|
-
|
215
|
+
def upgrade
|
216
|
+
perform_upgrade
|
132
217
|
end
|
133
218
|
|
134
219
|
private
|
@@ -141,6 +226,10 @@ module Terradactyl
|
|
141
226
|
module Rev012
|
142
227
|
include Terraform::Commands
|
143
228
|
|
229
|
+
def upgrade
|
230
|
+
perform_upgrade
|
231
|
+
end
|
232
|
+
|
144
233
|
private
|
145
234
|
|
146
235
|
def parser
|
@@ -151,11 +240,36 @@ module Terradactyl
|
|
151
240
|
module Rev013
|
152
241
|
include Terraform::Commands
|
153
242
|
|
243
|
+
def upgrade
|
244
|
+
perform_upgrade
|
245
|
+
end
|
246
|
+
|
154
247
|
private
|
155
248
|
|
156
249
|
def parser
|
157
|
-
Terraform::
|
250
|
+
Terraform::Rev013::PlanFileParser
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
module Rev014
|
255
|
+
include Terraform::Commands
|
256
|
+
|
257
|
+
private
|
258
|
+
|
259
|
+
def parser
|
260
|
+
Terraform::Rev014::PlanFileParser
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
module Rev015
|
265
|
+
include Terraform::Commands
|
266
|
+
|
267
|
+
private
|
268
|
+
|
269
|
+
def parser
|
270
|
+
Terraform::Rev015::PlanFileParser
|
158
271
|
end
|
159
272
|
end
|
160
273
|
end
|
274
|
+
# rubocop:enable Metrics/ModuleLength
|
161
275
|
end
|
data/lib/terradactyl/config.rb
CHANGED
@@ -132,6 +132,12 @@ module Terradactyl
|
|
132
132
|
end
|
133
133
|
|
134
134
|
class ConfigStack < ConfigApplication
|
135
|
+
TERRAFORM_SETTINGS_FILES = %w[
|
136
|
+
settings.tf
|
137
|
+
versions.tf
|
138
|
+
backend.tf
|
139
|
+
].freeze
|
140
|
+
|
135
141
|
attr_reader :stack_name, :stack_path, :base_folder
|
136
142
|
|
137
143
|
def initialize(stack_name)
|
@@ -163,5 +169,44 @@ module Terradactyl
|
|
163
169
|
def plan_path
|
164
170
|
"#{stack_path}/#{plan_file}"
|
165
171
|
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def terraform_required_version
|
176
|
+
matches = TERRAFORM_SETTINGS_FILES.map do |file|
|
177
|
+
path = File.join(stack_path, file)
|
178
|
+
if File.exist?(path)
|
179
|
+
File.read(path).match(terraform_required_version_re)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
return {} unless matches.compact!.any?
|
184
|
+
|
185
|
+
{
|
186
|
+
'terradactyl' => {
|
187
|
+
'terraform' => {
|
188
|
+
'version' => matches.last[:version]
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
end
|
193
|
+
|
194
|
+
def load_overlay(config_file)
|
195
|
+
overlay = super(config_file)
|
196
|
+
|
197
|
+
unless overlay_specifies_version?(overlay)
|
198
|
+
overlay.merge!(terraform_required_version)
|
199
|
+
end
|
200
|
+
|
201
|
+
overlay
|
202
|
+
end
|
203
|
+
|
204
|
+
def overlay_specifies_version?(overlay)
|
205
|
+
overlay['terradactyl']&.fetch('terraform', {})&.fetch('version', nil)
|
206
|
+
end
|
207
|
+
|
208
|
+
def terraform_required_version_re
|
209
|
+
/(?:\s*terraform\s*{(?:\n|\s)*.+required_version\s*=\s*)"(?<version>.*)"(?:(?:\n|\s)*.+})/m
|
210
|
+
end
|
166
211
|
end
|
167
212
|
end
|
data/lib/terradactyl/stack.rb
CHANGED
data/lib/terradactyl/version.rb
CHANGED
data/terradactyl.gemspec
CHANGED
@@ -33,11 +33,10 @@ 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.
|
36
|
+
spec.add_dependency 'terradactyl-terraform', '>= 0.15.0'
|
37
37
|
|
38
38
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
39
39
|
spec.add_development_dependency 'pry', '~> 0.12'
|
40
40
|
spec.add_development_dependency 'pry-remote', '~> 0.1.8'
|
41
41
|
spec.add_development_dependency 'rubocop', '~> 0.71.0'
|
42
42
|
end
|
43
|
-
|
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.
|
4
|
+
version: 0.15.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:
|
11
|
+
date: 2021-04-28 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.
|
103
|
+
version: 0.15.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.
|
110
|
+
version: 0.15.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rspec
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -186,9 +186,13 @@ files:
|
|
186
186
|
- examples/multi-tf-version/stacks/tfv11/example.tf
|
187
187
|
- examples/multi-tf-version/stacks/tfv11/terradactyl.yaml
|
188
188
|
- examples/multi-tf-version/stacks/tfv12/example.tf
|
189
|
-
- examples/multi-tf-version/stacks/tfv12/
|
189
|
+
- examples/multi-tf-version/stacks/tfv12/versions.tf
|
190
190
|
- examples/multi-tf-version/stacks/tfv13/example.tf
|
191
|
-
- examples/multi-tf-version/stacks/tfv13/
|
191
|
+
- examples/multi-tf-version/stacks/tfv13/versions.tf
|
192
|
+
- examples/multi-tf-version/stacks/tfv14/example.tf
|
193
|
+
- examples/multi-tf-version/stacks/tfv14/versions.tf
|
194
|
+
- examples/multi-tf-version/stacks/tfv15/example.tf
|
195
|
+
- examples/multi-tf-version/stacks/tfv15/versions.tf
|
192
196
|
- examples/multi-tf-version/terradactyl.yaml
|
193
197
|
- examples/simple/stacks/demo/example.tf
|
194
198
|
- examples/simple/terradactyl.yaml
|
@@ -227,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
227
231
|
- !ruby/object:Gem::Version
|
228
232
|
version: '0'
|
229
233
|
requirements: []
|
230
|
-
rubygems_version: 3.1.
|
234
|
+
rubygems_version: 3.1.6
|
231
235
|
signing_key:
|
232
236
|
specification_version: 4
|
233
237
|
summary: Manage a Terraform monorepo
|