tfwrapper 0.4.1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- 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: [![
|
3
|
+
Build of master branch: [![TravisCI](https://api.travis-ci.org/manheim/tfwrapper.svg?branch=master)](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
|
|