tfwrapper 0.4.1 → 0.6.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 +5 -5
- data/.gitignore +1 -0
- data/.rubocop.yml +5 -5
- data/.travis.yml +62 -0
- data/ChangeLog.md +31 -0
- data/Gemfile +4 -0
- data/README.md +48 -5
- data/lib/tfwrapper/helpers.rb +25 -3
- data/lib/tfwrapper/raketasks.rb +91 -10
- data/lib/tfwrapper/version.rb +1 -1
- data/spec/acceptance/acceptance_helpers.rb +16 -3
- data/spec/acceptance/acceptance_spec.rb +229 -0
- data/spec/fixtures/landscapeTest/Rakefile +38 -0
- data/spec/fixtures/landscapeTest/failingTerraform/main.tf +28 -0
- data/spec/fixtures/landscapeTest/main.tf +32 -0
- data/spec/fixtures/landscapeTest/state.json +43 -0
- data/spec/fixtures/landscapeTest/with_landscape_default.out +45 -0
- data/spec/fixtures/landscapeTest/with_landscape_dots.out +45 -0
- data/spec/fixtures/landscapeTest/with_landscape_lines.out +70 -0
- data/spec/fixtures/landscapeTest/with_landscape_stream.out +71 -0
- data/spec/fixtures/landscapeTest/without_landscape.out +62 -0
- data/spec/fixtures/testOne.tf +1 -0
- data/spec/fixtures/testThree/bar/testThreeBar.tf +1 -0
- data/spec/fixtures/testThree/baz/testThreeBaz.tf +1 -0
- data/spec/fixtures/testThree/foo/testThreeFoo.tf +1 -0
- data/spec/fixtures/testTwo/foo/bar/testTwo.tf +1 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/unit/helpers_spec.rb +131 -3
- data/spec/unit/raketasks_spec.rb +250 -26
- data/tfwrapper.gemspec +1 -0
- metadata +36 -4
- data/circle.yml +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4a404a81c05bcc07e29ef34eef1d881aa9c47faa1e5ba0ed127a34b8ae1202c5
|
4
|
+
data.tar.gz: f0078c62815fd5d7e49c14d201d9da2154ed91f6c4786a7a7be65914582cd4d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db129accb7e439c570ca8a8eb2d56a259acb98221a5acf5e451cc4aa44516627abd6e29603574abbf4dcd16c968b58607552bbec3a1b50ce7df44de9659968a7
|
7
|
+
data.tar.gz: f9f99bcc2e51e2aa4cedabd0e1179a1954dbc3e3e4d44149ab2d171218cc6e55a940ef2372869c6cd694c77be0282d5230f7a7d142eaea53479794c78550e810
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -2,10 +2,10 @@ AllCops:
|
|
2
2
|
TargetRubyVersion: 2.0
|
3
3
|
|
4
4
|
Metrics/AbcSize:
|
5
|
-
Max:
|
5
|
+
Max: 50
|
6
6
|
|
7
7
|
Metrics/BlockLength:
|
8
|
-
Max:
|
8
|
+
Max: 1500
|
9
9
|
|
10
10
|
Metrics/ClassLength:
|
11
11
|
Max: 500
|
@@ -14,10 +14,10 @@ Metrics/MethodLength:
|
|
14
14
|
Max: 100
|
15
15
|
|
16
16
|
Metrics/PerceivedComplexity:
|
17
|
-
Max:
|
17
|
+
Max: 10
|
18
18
|
|
19
19
|
Metrics/CyclomaticComplexity:
|
20
|
-
Max:
|
20
|
+
Max: 10
|
21
21
|
|
22
22
|
# These are to compensate for some warnings that differ by
|
23
23
|
# rubocop/ruby version
|
@@ -30,7 +30,7 @@ Style/MutableConstant:
|
|
30
30
|
- 'lib/tfwrapper/version.rb'
|
31
31
|
- 'spec/acceptance/acceptance_spec.rb'
|
32
32
|
|
33
|
-
|
33
|
+
Layout/MultilineMethodCallIndentation:
|
34
34
|
Exclude:
|
35
35
|
- 'spec/unit/raketasks_spec.rb'
|
36
36
|
|
data/.travis.yml
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
---
|
2
|
+
dist: xenial
|
3
|
+
language: ruby
|
4
|
+
cache: bundler
|
5
|
+
before_install:
|
6
|
+
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
|
7
|
+
- gem install bundler -v '< 2'
|
8
|
+
install: true
|
9
|
+
matrix:
|
10
|
+
include:
|
11
|
+
- rvm: ruby
|
12
|
+
install: bundle install --without landscape
|
13
|
+
script: ["bundle exec ruby --version", "bundle exec rake spec:unit"]
|
14
|
+
name: "ruby-latest unit"
|
15
|
+
- rvm: ruby
|
16
|
+
install: bundle install --without landscape
|
17
|
+
script: bundle exec rake rubocop
|
18
|
+
name: "ruby-latest rubocop"
|
19
|
+
- rvm: ruby
|
20
|
+
install: bundle install --without landscape
|
21
|
+
script: bundle exec rake yard:generate
|
22
|
+
name: "ruby-latest yard"
|
23
|
+
- rvm: 2.0
|
24
|
+
install: bundle install --without landscape
|
25
|
+
script: bundle exec rake spec:unit
|
26
|
+
name: "ruby-2.0 unit"
|
27
|
+
- rvm: 2.1
|
28
|
+
install: bundle install --without landscape
|
29
|
+
script: bundle exec rake spec:unit
|
30
|
+
name: "ruby-2.1 unit"
|
31
|
+
- rvm: 2.2
|
32
|
+
install: bundle install --without landscape
|
33
|
+
script: bundle exec rake spec:unit
|
34
|
+
name: "ruby-2.2 unit"
|
35
|
+
- rvm: 2.3
|
36
|
+
install: bundle install --without landscape
|
37
|
+
script: bundle exec rake spec:unit
|
38
|
+
name: "ruby-2.3 unit"
|
39
|
+
- rvm: 2.3
|
40
|
+
install: bundle install
|
41
|
+
script: bundle exec rake spec:acceptance TF_VERSION=0.10.0
|
42
|
+
name: "ruby-2.3 acceptance TF 0.10.0"
|
43
|
+
- rvm: 2.3
|
44
|
+
install: bundle install
|
45
|
+
script: bundle exec rake spec:acceptance TF_VERSION=0.10.2
|
46
|
+
name: "ruby-2.3 acceptance TF 0.10.2"
|
47
|
+
- rvm: 2.3
|
48
|
+
install: bundle install
|
49
|
+
script: bundle exec rake spec:acceptance TF_VERSION=0.11.2
|
50
|
+
name: "ruby-2.3 acceptance TF 0.11.2"
|
51
|
+
- rvm: 2.3
|
52
|
+
install: bundle install
|
53
|
+
script: bundle exec rake spec:acceptance TF_VERSION=0.11.14
|
54
|
+
name: "ruby-2.3 acceptance TF 0.11.14"
|
55
|
+
- rvm: 2.4
|
56
|
+
install: bundle install
|
57
|
+
script: bundle exec rake spec:unit
|
58
|
+
name: "ruby-2.4 unit"
|
59
|
+
- rvm: 2.4
|
60
|
+
install: bundle install
|
61
|
+
script: bundle exec rake spec:acceptance TF_VERSION=0.11.14
|
62
|
+
name: "ruby-2.4 acceptance TF 0.11.14"
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,34 @@
|
|
1
|
+
Version 0.6.2
|
2
|
+
|
3
|
+
- Add ``tf_sensitive_vars`` option.
|
4
|
+
|
5
|
+
Version 0.6.1
|
6
|
+
|
7
|
+
- Add ``allowed_empty_vars`` option.
|
8
|
+
- Only support terraform up to 0.11.14.
|
9
|
+
|
10
|
+
Version 0.6.0
|
11
|
+
|
12
|
+
- Include full terraform output when a terraform run fails with output including ``hrottling``, ``status code: 403``, or ``status code: 401``. Previously terraform output was suppressed in these cases, which causes confusion with providers other than "aws" that include these strings in their failure output.
|
13
|
+
- In ``Gemfile``, for testing, pin terraform-landscape gem to 0.2.2 for Ruby 2.x compatibility.
|
14
|
+
- Pin ``rb-inotify`` dependency to 0.9.10 to allow build with Ruby < 2.2
|
15
|
+
- Switch testing from circleci.com to travis-ci.org
|
16
|
+
- Pin terraform_landscape dependency to 0.2.2 for compatibility with ruby < 2.5
|
17
|
+
- Acceptance tests:
|
18
|
+
- Use HashiCorp checkpoint API instead of GitHub Releases API to find latest terraform version, to work around query failures
|
19
|
+
- Pin consul provider versions to 1.0.0 to fix intermittent failures
|
20
|
+
- Switch Ruby versions used in tests to latest TravisCI versions
|
21
|
+
- Stop acceptance testing terraform 0.9.x, as newer versions require pinning the consul provider version but 0.9 doesn't support versioned providers.
|
22
|
+
|
23
|
+
Version 0.5.1
|
24
|
+
|
25
|
+
- Fix bug where terraform plan errors were suppressed if a plan run with landscape support enabled exited non-zero.
|
26
|
+
|
27
|
+
Version 0.5.0
|
28
|
+
|
29
|
+
- Add support for using terraform_landscape gem, if present, to reformat plan output; see README for usage.
|
30
|
+
- Add CircleCI testing under ruby 2.4.1, and acceptance tests for terraform 0.11.2.
|
31
|
+
|
1
32
|
Version 0.4.1
|
2
33
|
|
3
34
|
- Upgrade rubocop, yard and diplomat development dependency versions
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# tfwrapper
|
2
2
|
|
3
|
-
Build of master branch: [](https://travis-ci.org/manheim/tfwrapper)
|
4
4
|
|
5
5
|
Documentation: [http://www.rubydoc.info/gems/tfwrapper/](http://www.rubydoc.info/gems/tfwrapper/)
|
6
6
|
|
7
|
-
tfwrapper provides Rake tasks for working with [Hashicorp Terraform](https://www.terraform.io/) 0.9
|
7
|
+
tfwrapper provides Rake tasks for working with [Hashicorp Terraform](https://www.terraform.io/) 0.9 through 0.11, ensuring proper initialization and passing in variables from the environment or Ruby, as well as optionally pushing some information to Consul. tfwrapper also attempts to detect and retry
|
8
8
|
failed runs due to AWS throttling or access denied errors.
|
9
9
|
|
10
10
|
## Overview
|
@@ -18,7 +18,9 @@ This Gem provides the following Rake tasks:
|
|
18
18
|
one or more optional [resource address](https://www.terraform.io/docs/internals/resource-addressing.html) targets to pass to
|
19
19
|
terraform with the ``-target`` flag as Rake task arguments, i.e. ``bundle exec rake tf:plan[aws_instance.foo[1]]`` or
|
20
20
|
``bundle exec rake tf:plan[aws_instance.foo[1],aws_instance.bar[2]]``; see the
|
21
|
-
[plan documentation](https://www.terraform.io/docs/commands/plan.html) for more information.
|
21
|
+
[plan documentation](https://www.terraform.io/docs/commands/plan.html) for more information. By default this will use
|
22
|
+
[terraform_landscape](https://github.com/coinbase/terraform-landscape/blob/master/README.md) for formatting the plan
|
23
|
+
output if the ``terraform_landscape`` gem is installed; see the [section below](#terraform-landscape) for more information.
|
22
24
|
* __tf:apply__ - run ``terraform apply`` with all variables and configuration, and TF variables written to disk. You can specify
|
23
25
|
one or more optional [resource address](https://www.terraform.io/docs/internals/resource-addressing.html) targets to pass to
|
24
26
|
terraform with the ``-target`` flag as Rake task arguments, i.e. ``bundle exec rake tf:apply[aws_instance.foo[1]]`` or
|
@@ -42,12 +44,29 @@ with 1.9.3 is simply too high to justify.
|
|
42
44
|
Add to your ``Gemfile``:
|
43
45
|
|
44
46
|
```ruby
|
45
|
-
gem 'tfwrapper', '~> 0.
|
47
|
+
gem 'tfwrapper', '~> 0.6.1'
|
46
48
|
```
|
47
49
|
|
48
50
|
### Supported Terraform Versions
|
49
51
|
|
50
|
-
tfwrapper only supports terraform 0.9
|
52
|
+
tfwrapper only supports terraform 0.9-0.11. It is tested against multiple versions from 0.9.2 to 0.11.14.
|
53
|
+
|
54
|
+
### Terraform Landscape
|
55
|
+
|
56
|
+
The [terraform_landscape](https://github.com/coinbase/terraform-landscape/blob/master/README.md) gem provides enhanced formatting of ``terraform plan`` output including colorization of changes and human-friendly diffs (i.e. diffs of JSON rendered with pretty-printing). By default ``plan`` output will be passed through terraform_landscape if the ``terraform_landscape`` gem is available. To enable this, add ``gem 'terraform_landscape', '~> 0.1.17'`` to your ``Gemfile``. __Note__ that we rely on an undocumented internal API of terraform_landscape to achieve this; the formatting code will fall back to unformatted output in case of an error.
|
57
|
+
|
58
|
+
If you wish to disable terraform_landscape output even when the gem is installed, pass ``disable_landscape: true`` as an option to ``install_tasks()``:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
TFWrapper::RakeTasks.install_tasks('.', disable_landscape: true)
|
62
|
+
```
|
63
|
+
|
64
|
+
In previous versions or when terraform_landscape is not installed, the output of all terraform commands is streamed in realtime. Since terraform_landscape requires the full and complete ``plan`` output in order to reformat it, this is no longer the case. By default when terraform_landscape is installed and not disabled the ``plan`` task will not produce any output until complete, at which point it will print the landscape-formatted output all at once. This behavior can be controlled with the ``:landscape_progress`` option of ``install_tasks()``, which takes one of the following values:
|
65
|
+
|
66
|
+
* ``nil``, the default, to not produce any output until the command is complete at which point the landscape-formatted output will be shown.
|
67
|
+
* ``:dots`` to print a dot to STDOUT for every line of ``terraform plan`` output and then print the landscape-formatted output when complete.
|
68
|
+
* ``:lines`` to print a dot followed by a newline to STDOUT for every line of ``terraform plan`` output and then print the landscape-formatted output when complete. This is useful for systems like Jenkins that line-buffer output (and don't display anything until a newline is encountered).
|
69
|
+
* ``:stream`` to stream the ``terraform plan`` output in realtime (as was the previous behavior) and then print the landscape-formatted output when complete. Note that this will result in the output containing the complete unformatted ``terraform plan`` output, followed by the landscape-formatted output.
|
51
70
|
|
52
71
|
## Usage
|
53
72
|
|
@@ -128,6 +147,10 @@ TFWrapper::RakeTasks.install_tasks(
|
|
128
147
|
)
|
129
148
|
```
|
130
149
|
|
150
|
+
These variables are tested to be set in the environment with a non-empty value, and will raise an error if any are
|
151
|
+
missing or empty. If some should be allowed to be missing or empty empty, pass a ``allowed_empty_vars`` list with
|
152
|
+
their environment variable names.
|
153
|
+
|
131
154
|
### Ruby Variables to Terraform Variables
|
132
155
|
|
133
156
|
If you wish to explicitly bind values from your Ruby code to terraform variables, you can do this with
|
@@ -307,6 +330,26 @@ $ consul kv get terraform/inputs/foo
|
|
307
330
|
{"FOO":"one", "BAR":"two"}
|
308
331
|
```
|
309
332
|
|
333
|
+
### Sensitive Environment Variables
|
334
|
+
If you wish for certain variables to be marked as "redacted", use the ``tf_sensitive_vars`` option. This is an array of variables that will not be printed.
|
335
|
+
|
336
|
+
Note: ``aws_access_key`` and ``aws_secret_key`` will always be redacted without requiring configuration.
|
337
|
+
|
338
|
+
|
339
|
+
Example to redact the vaule for ``secret``:
|
340
|
+
|
341
|
+
Rakefile:
|
342
|
+
|
343
|
+
```ruby
|
344
|
+
require 'tfwrapper/raketasks'
|
345
|
+
|
346
|
+
TFWrapper::RakeTasks.install_tasks(
|
347
|
+
'.',
|
348
|
+
tf_vars_from_env: {'foo' => 'FOO', 'bar' => 'BAR', 'secret' => 'abc'},
|
349
|
+
tf_sensitive_vars: ['secret']
|
350
|
+
)
|
351
|
+
```
|
352
|
+
|
310
353
|
## Development
|
311
354
|
|
312
355
|
1. ``bundle install --path vendor``
|
data/lib/tfwrapper/helpers.rb
CHANGED
@@ -31,8 +31,20 @@ module TFWrapper
|
|
31
31
|
#
|
32
32
|
# @param cmd [String] command to run
|
33
33
|
# @param pwd [String] directory/path to run command in
|
34
|
+
# @option opts [Hash] :progress How to handle streaming output. Possible
|
35
|
+
# values are ``:stream`` (default) to stream each line in STDOUT/STDERR
|
36
|
+
# to STDOUT, ``:dots`` to print a dot for each line, ``:lines`` to print
|
37
|
+
# a dot followed by a newline for each line, or ``nil`` to not stream any
|
38
|
+
# output at all.
|
34
39
|
# @return [Array] - out_err [String], exit code [Fixnum]
|
35
|
-
def self.run_cmd_stream_output(cmd, pwd)
|
40
|
+
def self.run_cmd_stream_output(cmd, pwd, opts = {})
|
41
|
+
stream_type = opts.fetch(:progress, :stream)
|
42
|
+
unless [:dots, :lines, :stream, nil].include?(stream_type)
|
43
|
+
raise(
|
44
|
+
ArgumentError,
|
45
|
+
'progress option must be one of: [:dots, :lines, :stream, nil]'
|
46
|
+
)
|
47
|
+
end
|
36
48
|
old_sync = $stdout.sync
|
37
49
|
$stdout.sync = true
|
38
50
|
all_out_err = ''.dup
|
@@ -41,7 +53,13 @@ module TFWrapper
|
|
41
53
|
stdin.close_write
|
42
54
|
begin
|
43
55
|
while (line = stdout_and_err.gets)
|
44
|
-
|
56
|
+
if stream_type == :stream
|
57
|
+
puts line
|
58
|
+
elsif stream_type == :dots
|
59
|
+
STDOUT.print '.'
|
60
|
+
elsif stream_type == :lines
|
61
|
+
puts '.'
|
62
|
+
end
|
45
63
|
all_out_err << line
|
46
64
|
end
|
47
65
|
rescue IOError => e
|
@@ -51,6 +69,7 @@ module TFWrapper
|
|
51
69
|
end
|
52
70
|
# rubocop:disable Style/RedundantReturn
|
53
71
|
$stdout.sync = old_sync
|
72
|
+
puts '' if stream_type == :dots
|
54
73
|
return all_out_err, exit_status
|
55
74
|
# rubocop:enable Style/RedundantReturn
|
56
75
|
end
|
@@ -59,9 +78,12 @@ module TFWrapper
|
|
59
78
|
# non-empty. Raise StandardError if any aren't.
|
60
79
|
#
|
61
80
|
# @param required [Array] list of required environment variables
|
62
|
-
|
81
|
+
# @param allowed_missing [Array] list of environment variables to allow to
|
82
|
+
# be empty or missing.
|
83
|
+
def self.check_env_vars(required, allowed_missing)
|
63
84
|
missing = []
|
64
85
|
required.each do |name|
|
86
|
+
next if allowed_missing.include?(name)
|
65
87
|
if !ENV.include?(name)
|
66
88
|
puts "ERROR: Environment variable '#{name}' must be set."
|
67
89
|
missing << name
|
data/lib/tfwrapper/raketasks.rb
CHANGED
@@ -6,6 +6,15 @@ require 'rake'
|
|
6
6
|
require 'rubygems'
|
7
7
|
require 'tfwrapper/version'
|
8
8
|
|
9
|
+
# :nocov:
|
10
|
+
begin
|
11
|
+
require 'terraform_landscape'
|
12
|
+
HAVE_LANDSCAPE = true
|
13
|
+
rescue LoadError
|
14
|
+
HAVE_LANDSCAPE = false
|
15
|
+
end
|
16
|
+
# :nocov:
|
17
|
+
|
9
18
|
module TFWrapper
|
10
19
|
# Generates Rake tasks for working with Terraform.
|
11
20
|
class RakeTasks
|
@@ -46,8 +55,12 @@ module TFWrapper
|
|
46
55
|
# configurations in the same Rakefile.
|
47
56
|
# @option opts [Hash] :tf_vars_from_env hash of Terraform variables to the
|
48
57
|
# (required) environment variables to populate their values from
|
58
|
+
# @option opts [Hash] :allowed_empty_vars array of environment variable
|
59
|
+
# names (specified in :tf_vars_from_env) to allow to be empty or missing.
|
49
60
|
# @option opts [Hash] :tf_extra_vars hash of Terraform variables to their
|
50
61
|
# values; overrides any same-named keys in ``tf_vars_from_env``
|
62
|
+
# @option opts [Array] :tf_sensitive_vars list of Terraform variables
|
63
|
+
# which should not be printed
|
51
64
|
# @option opts [String] :consul_url URL to access Consul at, for the
|
52
65
|
# ``:consul_env_vars_prefix`` option.
|
53
66
|
# @option opts [String] :consul_env_vars_prefix if specified and not nil,
|
@@ -63,6 +76,22 @@ module TFWrapper
|
|
63
76
|
# the body of each task. Called with two arguments, the String full
|
64
77
|
# (namespaced) name of the task being executed, and ``tf_dir``. This will
|
65
78
|
# not execute if the body of the task fails.
|
79
|
+
# @option opts [Bool] :disable_landscape By default, if the
|
80
|
+
# ``terraform_landscape`` gem can be loaded, it will be used to reformat
|
81
|
+
# the output of ``terraform plan``. If this is not desired, set to
|
82
|
+
# ``true`` to disable landscale. Default: ``false``.
|
83
|
+
# @option opts [Symbol, nil] :landscape_progress The ``terraform_landscape``
|
84
|
+
# code used to reformat plan output requires the full output of the
|
85
|
+
# complete ``plan`` execution. By default, this means that when landscape
|
86
|
+
# is used, no output will appear from the time ``terraform plan`` begins
|
87
|
+
# until the command is complete. If progress output is desired, this option
|
88
|
+
# can be set to one of the following: ``:dots`` to print a dot to STDOUT
|
89
|
+
# for every line of ``terraform plan`` output, ``:lines`` to print a dot
|
90
|
+
# followed by a newline (e.g. for systems like Jenkins that line buffer)
|
91
|
+
# for every line of ``terraform plan`` output, or ``:stream`` to stream
|
92
|
+
# the raw ``terraform plan`` output (which will then be followed by the
|
93
|
+
# reformatted landscape output). Default is ``nil`` to show no progress
|
94
|
+
# output.
|
66
95
|
def initialize(tf_dir, opts = {})
|
67
96
|
# find the directory that contains the Rakefile
|
68
97
|
rakedir = File.realpath(Rake.application.rakefile)
|
@@ -71,9 +100,20 @@ module TFWrapper
|
|
71
100
|
@ns_prefix = opts.fetch(:namespace_prefix, nil)
|
72
101
|
@consul_env_vars_prefix = opts.fetch(:consul_env_vars_prefix, nil)
|
73
102
|
@tf_vars_from_env = opts.fetch(:tf_vars_from_env, {})
|
103
|
+
@allowed_empty_vars = opts.fetch(:allowed_empty_vars, [])
|
104
|
+
@tf_sensitive_vars = opts.fetch(:tf_sensitive_vars, [])
|
74
105
|
@tf_extra_vars = opts.fetch(:tf_extra_vars, {})
|
75
106
|
@backend_config = opts.fetch(:backend_config, {})
|
76
107
|
@consul_url = opts.fetch(:consul_url, nil)
|
108
|
+
@disable_landscape = opts.fetch(:disable_landscape, false)
|
109
|
+
@landscape_progress = opts.fetch(:landscape_progress, nil)
|
110
|
+
unless [:dots, :lines, :stream, nil].include?(@landscape_progress)
|
111
|
+
raise(
|
112
|
+
ArgumentError,
|
113
|
+
'landscape_progress option must be one of: ' \
|
114
|
+
'[:dots, :lines, :stream, nil]'
|
115
|
+
)
|
116
|
+
end
|
77
117
|
@before_proc = opts.fetch(:before_proc, nil)
|
78
118
|
if !@before_proc.nil? && !@before_proc.is_a?(Proc)
|
79
119
|
raise(
|
@@ -128,7 +168,9 @@ module TFWrapper
|
|
128
168
|
desc 'Run terraform init with appropriate arguments'
|
129
169
|
task :init do |t|
|
130
170
|
@before_proc.call(t.name, @tf_dir) unless @before_proc.nil?
|
131
|
-
TFWrapper::Helpers.check_env_vars(
|
171
|
+
TFWrapper::Helpers.check_env_vars(
|
172
|
+
@tf_vars_from_env.values, @allowed_empty_vars
|
173
|
+
)
|
132
174
|
@tf_version = check_tf_version
|
133
175
|
cmd = [
|
134
176
|
'terraform',
|
@@ -160,7 +202,13 @@ module TFWrapper
|
|
160
202
|
args.extras
|
161
203
|
)
|
162
204
|
|
163
|
-
|
205
|
+
stream_type = if HAVE_LANDSCAPE && !@disable_landscape
|
206
|
+
@landscape_progress
|
207
|
+
else
|
208
|
+
:stream
|
209
|
+
end
|
210
|
+
outerr = terraform_runner(cmd, progress: stream_type)
|
211
|
+
landscape_format(outerr) if HAVE_LANDSCAPE && !@disable_landscape
|
164
212
|
@after_proc.call(t.name, @tf_dir) unless @after_proc.nil?
|
165
213
|
end
|
166
214
|
end
|
@@ -274,7 +322,9 @@ module TFWrapper
|
|
274
322
|
tf_vars = terraform_vars
|
275
323
|
puts 'Terraform vars:'
|
276
324
|
tf_vars.sort.map do |k, v|
|
277
|
-
|
325
|
+
redacted_list = (%w[aws_access_key aws_secret_key] +
|
326
|
+
@tf_sensitive_vars)
|
327
|
+
if redacted_list.include?(k)
|
278
328
|
puts "#{k} => (redacted)"
|
279
329
|
else
|
280
330
|
puts "#{k} => #{v}"
|
@@ -296,13 +346,39 @@ module TFWrapper
|
|
296
346
|
res
|
297
347
|
end
|
298
348
|
|
349
|
+
# Given a string of terraform plan output, format it with
|
350
|
+
# terraform_landscape and print the result to STDOUT.
|
351
|
+
def landscape_format(output)
|
352
|
+
p = TerraformLandscape::Printer.new(
|
353
|
+
TerraformLandscape::Output.new(STDOUT)
|
354
|
+
)
|
355
|
+
p.process_string(output)
|
356
|
+
rescue StandardError, ScriptError => ex
|
357
|
+
STDERR.puts 'Exception calling terraform_landscape to reformat ' \
|
358
|
+
"output: #{ex.class.name}: #{ex}"
|
359
|
+
puts output unless @landscape_progress == :stream
|
360
|
+
end
|
361
|
+
|
299
362
|
# Run a Terraform command, providing some useful output and handling AWS
|
300
363
|
# API rate limiting gracefully. Raises StandardError on failure. The command
|
301
364
|
# is run in @tf_dir.
|
302
365
|
#
|
303
366
|
# @param cmd [String] Terraform command to run
|
367
|
+
# @option opts [Hash] :progress How to handle streaming output. Possible
|
368
|
+
# values are ``:stream`` (default) to stream each line in STDOUT/STDERR
|
369
|
+
# to STDOUT, ``:dots`` to print a dot for each line, ``:lines`` to print
|
370
|
+
# a dot followed by a newline for each line, or ``nil`` to not stream any
|
371
|
+
# output at all.
|
372
|
+
# @return [String] combined STDOUT and STDERR
|
304
373
|
# rubocop:disable Metrics/PerceivedComplexity
|
305
|
-
def terraform_runner(cmd)
|
374
|
+
def terraform_runner(cmd, opts = {})
|
375
|
+
stream_type = opts.fetch(:progress, :stream)
|
376
|
+
unless [:dots, :lines, :stream, nil].include?(stream_type)
|
377
|
+
raise(
|
378
|
+
ArgumentError,
|
379
|
+
'progress option must be one of: [:dots, :lines, :stream, nil]'
|
380
|
+
)
|
381
|
+
end
|
306
382
|
require 'retries'
|
307
383
|
STDERR.puts "terraform_runner command: '#{cmd}' (in #{@tf_dir})"
|
308
384
|
out_err = nil
|
@@ -321,25 +397,30 @@ module TFWrapper
|
|
321
397
|
) do
|
322
398
|
# this streams STDOUT and STDERR as a combined stream,
|
323
399
|
# and also captures them as a combined string
|
324
|
-
out_err, status = TFWrapper::Helpers.run_cmd_stream_output(
|
400
|
+
out_err, status = TFWrapper::Helpers.run_cmd_stream_output(
|
401
|
+
cmd, @tf_dir, progress: stream_type
|
402
|
+
)
|
325
403
|
if status != 0 && out_err.include?('hrottling')
|
326
|
-
raise StandardError,
|
404
|
+
raise StandardError, "#{out_err}\nTerraform hit AWS API rate limiting"
|
327
405
|
end
|
328
406
|
if status != 0 && out_err.include?('status code: 403')
|
329
|
-
raise StandardError,
|
330
|
-
'denied or credentials not propagated'
|
407
|
+
raise StandardError, "#{out_err}\nTerraform command got 403 error " \
|
408
|
+
'- access denied or credentials not propagated'
|
331
409
|
end
|
332
410
|
if status != 0 && out_err.include?('status code: 401')
|
333
|
-
raise StandardError,
|
334
|
-
'denied or credentials not propagated'
|
411
|
+
raise StandardError, "#{out_err}\nTerraform command got 401 error " \
|
412
|
+
'- access denied or credentials not propagated'
|
335
413
|
end
|
336
414
|
end
|
337
415
|
# end exponential backoff
|
338
416
|
unless status.zero?
|
417
|
+
# if we weren't streaming output, send it now
|
418
|
+
STDERR.puts out_err unless stream_type == :stream
|
339
419
|
raise StandardError, "Errors have occurred executing: '#{cmd}' " \
|
340
420
|
"(exited #{status})"
|
341
421
|
end
|
342
422
|
STDERR.puts "terraform_runner command '#{cmd}' finished and exited 0"
|
423
|
+
out_err
|
343
424
|
end
|
344
425
|
# rubocop:enable Metrics/PerceivedComplexity
|
345
426
|
|