terradactyl 0.13.2 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|