rake-terraform 0.0.8 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +19 -0
- data/.rspec +5 -0
- data/.rubocop.yml +25 -0
- data/.travis.yml +1 -0
- data/README.md +93 -1
- data/Rakefile +22 -3
- data/lib/{rake_terraform.rb → rake-terraform.rb} +1 -0
- data/lib/rake-terraform/apply_task/config.rb +47 -0
- data/lib/rake-terraform/{tasks/applytask.rb → apply_task/task.rb} +21 -33
- data/lib/rake-terraform/applytask.rb +11 -0
- data/lib/rake-terraform/{tasks/basetask.rb → basetask.rb} +2 -1
- data/lib/rake-terraform/default_tasks.rb +5 -2
- data/lib/rake-terraform/dsl.rb +2 -2
- data/lib/rake-terraform/env_process.rb +142 -0
- data/lib/rake-terraform/errors.rb +4 -0
- data/lib/rake-terraform/plan_task/config.rb +61 -0
- data/lib/rake-terraform/plan_task/task.rb +51 -0
- data/lib/rake-terraform/plantask.rb +13 -0
- data/lib/rake-terraform/terraformcmd.rb +56 -0
- data/lib/rake-terraform/version.rb +1 -1
- data/rake-terraform.gemspec +3 -0
- data/spec/fixtures/envprocess_uniq_state_dir_var_invalid.env +3 -0
- data/spec/fixtures/envprocess_uniq_state_dir_var_valid.env +4 -0
- data/spec/fixtures/envprocess_uniq_state_false.env +2 -0
- data/spec/fixtures/envprocess_uniq_state_false_file_valid.env +3 -0
- data/spec/fixtures/envprocess_uniq_state_invalid_state_file_str.env +3 -0
- data/spec/fixtures/envprocess_uniq_state_missing_dir_var.env +4 -0
- data/spec/fixtures/envprocess_uniq_state_true.env +5 -0
- data/spec/fixtures/envprocess_uniq_state_true_both.env +6 -0
- data/spec/fixtures/envprocess_uniq_state_true_file_valid.env +3 -0
- data/spec/fixtures/set_all_variables_nil.env +8 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/unit/applytask_spec.rb +112 -0
- data/spec/unit/basetask_spec.rb +10 -0
- data/spec/unit/envprocess_spec.rb +263 -0
- data/spec/unit/plantask_spec.rb +118 -0
- data/spec/unit/terraformcmd_spec.rb +174 -0
- metadata +90 -7
- data/lib/rake-terraform/tasks/plantask.rb +0 -87
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NWE5MWZmZDg3OGZlNWE4YmNkNmVhY2U3NTFkZGFmODhiMGMzOWE1MA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NjA1MWMyZjY1YjljN2U0NjM3MTY3OTM2Y2I0YzlmNTQ4NzhhOTAyNA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YTFkNjY4MjY4MDkxNjNmZWNhYTQ1YTVmYWY4NWFhODkxYWY2YjJjZWE0YjM0
|
10
|
+
ZjEwMjE3M2YzMjc1NDU4ZjU0N2Y5YjQ3NDAzYTc2ODUwOWU0OGI4NGE2ZjE2
|
11
|
+
YmQzMWEwZWJkOWQwMmIxMTQyYmE4NmM5ODY0MDM3MWNiOWM2ZjE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NDJmZDc5YjE2YTQwMTVmMTU0NjJiYTQ4Y2ZjZGUxOWNlMWY2YTZjMWEwNDY5
|
14
|
+
YmYwZmU2ZjEzNjNmMmU5YzQyNmJiMzIwMzllYmY0N2M0MTE1MWI0MDY0NmZm
|
15
|
+
N2NkYWMxZDE5ZmQ1YzZmYmFlMTU0ZjYzNWJiOGQ1YWY5MjFmZjc=
|
data/.gitignore
CHANGED
@@ -15,3 +15,22 @@ mkmf.log
|
|
15
15
|
terraform/
|
16
16
|
.idea/
|
17
17
|
output/
|
18
|
+
|
19
|
+
# ignore bundlers vendor dir
|
20
|
+
/vendor/bundle/
|
21
|
+
|
22
|
+
# Default ignores for vim editor
|
23
|
+
.*.sw[a-z]
|
24
|
+
*.un~
|
25
|
+
Session.vim
|
26
|
+
.netrwhist
|
27
|
+
# Default ignores for emacs editor
|
28
|
+
*~
|
29
|
+
\#*\#
|
30
|
+
/.emacs.desktop
|
31
|
+
/.emacs.desktop.lock
|
32
|
+
.elc
|
33
|
+
auto-save-list
|
34
|
+
tramp
|
35
|
+
.\#*
|
36
|
+
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'spec/spec_helper.rb'
|
4
|
+
- 'vendor/**/*'
|
5
|
+
Style/FileName:
|
6
|
+
Exclude:
|
7
|
+
# usability - module name should match the gem name
|
8
|
+
- 'lib/rake-terraform.rb'
|
9
|
+
Metrics/AbcSize:
|
10
|
+
Exclude:
|
11
|
+
# TODO - fix this
|
12
|
+
- 'lib/rake-terraform/plan_task/task.rb'
|
13
|
+
Metrics/MethodLength:
|
14
|
+
Max: 12
|
15
|
+
Metrics/ModuleLength:
|
16
|
+
Exclude:
|
17
|
+
- 'spec/unit/*_spec.rb'
|
18
|
+
Metrics/CyclomaticComplexity:
|
19
|
+
Exclude:
|
20
|
+
# TODO: fix tf_plan method to support splat arguments and break
|
21
|
+
# down into one or more command constructor methods
|
22
|
+
- 'lib/rake-terraform/terraformcmd.rb'
|
23
|
+
Metrics/PerceivedComplexity:
|
24
|
+
Exclude:
|
25
|
+
- 'lib/rake-terraform/terraformcmd.rb'
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -52,7 +52,7 @@ You can set the following configuration for the task:
|
|
52
52
|
* `t.execution_path`: The path from which to execute the plan (default: `./terraform`)
|
53
53
|
* This is useful if you are referencing cloud-config files using relative paths
|
54
54
|
|
55
|
-
To use these tasks, you should `require '
|
55
|
+
To use these tasks, you should `require 'rake-terraform'` at the top of your Rakefile.
|
56
56
|
|
57
57
|
### Default Tasks
|
58
58
|
|
@@ -96,6 +96,98 @@ The following environment variables can be set to tweak `default_task`'s behavio
|
|
96
96
|
* `ENV['TERRAFORM_ENVIRONMENT_GLOB']` - Dir glob used to discover terraform environments (default: `terraform/**/*.tf`)
|
97
97
|
* `ENV['TERRAFORM_OUTPUT_BASE']` - Directory to which plan files are saved/read. The environment name is appended to this automatically (default: `output/terraform`)
|
98
98
|
* `ENV['TERRAFORM_CREDENTIAL_FILE']` - The path to your AWS credentials file (default: `~/.aws/credentials`)
|
99
|
+
* `ENV['TERRAFORM_UNIQUE_STATE']` - Whether to use a unique state for this run. Requires `TERRAFORM_STATE_FILE` OR `TERRAFORM_STATE_DIR_VAR`. Can be any truthy or falsey looking string from [this list][wannabe_bool_string] (e.g `TRUE` or `FALSE`)
|
100
|
+
* `ENV['TERRAFORM_STATE_FILE']` - The full path to a state file to use for this run. Only used when `TERRAFORM_UNIQUE_STATE` is true, and cannot be used in conjunction with `TERRAFORM_STATE_DIR_VAR`.
|
101
|
+
* `ENV['TERRAFORM_STATE_DIR_VAR']` - The name of an environment variable that holds a variable that will be used to reference a directory in which to store state files in for this run. This directory will be a subdirectory within the terraform environment. Only used when `TERRAFORM_STATE_DIR` is true, and cannot be used in conjunction with `TERRAFORM_STATE_FILE`
|
102
|
+
|
103
|
+
[wannabe_bool_string]: https://github.com/prodis/wannabe_bool#string
|
104
|
+
|
105
|
+
#### Unique States
|
106
|
+
|
107
|
+
Bu default, `rake-terraform` stores state within a given environment directory.
|
108
|
+
|
109
|
+
Sometimes, you will have several infrastructure environments ("infrastructure
|
110
|
+
environment" in this block here taken to mean e.g "staging" or "production"
|
111
|
+
rather than the broader "terraform environment" used more generally in this
|
112
|
+
doc) that are relatively homogeneous in terms of resources, where all changes
|
113
|
+
are rolled out through those infrastructure environments in a cascading manner.
|
114
|
+
Through application of [variable interpolation][tf_doc_var_interpol] and other
|
115
|
+
methods, you can provide differing configuration for each of your resources to
|
116
|
+
match those infrastructure environments. The issue with this is that Terraform
|
117
|
+
does not support resource names as variables, so when you come to apply the
|
118
|
+
same resource layout with differing configuration to the next infrastructure
|
119
|
+
environment, Terraform will see those configuration changes as needing to be
|
120
|
+
applied to the existing deployed resources.
|
121
|
+
|
122
|
+
One solution to this problem is to keep each of your infrastructure
|
123
|
+
environments in separate directories ("terraform environments"), each with
|
124
|
+
their own state file. An issue with this solution is that it does not confirm
|
125
|
+
to DRY principles, and also depends on you manually diffing changes between
|
126
|
+
files etc, rather than relying on `git diff` or similar. Another solution
|
127
|
+
might be to use separate divergent git branches, and cherry-pick relevant
|
128
|
+
commits between them. Again, depends on clean commit hygiene and easy to mess
|
129
|
+
up manual steps.
|
130
|
+
|
131
|
+
By using a unique state file for each of your infrastructure environments,
|
132
|
+
whilst utilising a single terraform environment, you can avoid repeating
|
133
|
+
yourself and manage roll out changes to each of your infrastructure
|
134
|
+
environments better.
|
135
|
+
|
136
|
+
To enable unique state files, you need to set the environment variable
|
137
|
+
`TERRAFORM_UNIQUE_STATE` to a [truthy value][wannabe_bool_string], then you
|
138
|
+
need to EITHER set `TERRAFORM_STATE_FILE` to the full path of your chosen state
|
139
|
+
file, OR set `TERRAFORM_STATE_DIR_VAR` to the name of another environment
|
140
|
+
variable containing the name of your infrastructure environment.
|
141
|
+
|
142
|
+
[tf_doc_var_interpol]: https://www.terraform.io/docs/configuration/interpolation.html
|
143
|
+
|
144
|
+
##### Examples
|
145
|
+
|
146
|
+
Use a specific state file
|
147
|
+
|
148
|
+
$ export TERRAFORM_UNIQUE_STATE="TRUE"
|
149
|
+
$ export TERRAFORM_STATE_FILE="/home/dave/.tf_states/staging/web_tier.tfstate"
|
150
|
+
$ bundle exec rake terraform:plan_web_tier
|
151
|
+
...
|
152
|
+
|
153
|
+
Use a variable to lookup the state file directory
|
154
|
+
|
155
|
+
$ export TF_VAR_infra_env="staging"
|
156
|
+
$ export TERRAFORM_UNIQUE_STATE="TRUE"
|
157
|
+
$ export TERRAFORM_STATE_DIR_VAR="TF_VAR_infra_env"
|
158
|
+
$ bundle exec rake terraform:plan_web_tier
|
159
|
+
...
|
160
|
+
|
161
|
+
This would result in a directory layout resembling the following:
|
162
|
+
|
163
|
+
terraform
|
164
|
+
web_tier
|
165
|
+
main.tf
|
166
|
+
variables.tf
|
167
|
+
output.tf
|
168
|
+
state
|
169
|
+
staging
|
170
|
+
terraform.tfstate
|
171
|
+
terraform.tfstate.backup
|
172
|
+
production
|
173
|
+
terraform.tfstate
|
174
|
+
terraform.tfstate.backup
|
175
|
+
app_tier
|
176
|
+
main.tf
|
177
|
+
variables.tf
|
178
|
+
output.tf
|
179
|
+
state
|
180
|
+
staging
|
181
|
+
terraform.tfstate
|
182
|
+
terraform.tfstate.backup
|
183
|
+
production
|
184
|
+
terraform.tfstate
|
185
|
+
terraform.tfstate.backup
|
186
|
+
|
187
|
+
## Testing
|
188
|
+
|
189
|
+
There is currently a basic rspec-based test harness in place. The default task
|
190
|
+
runs unit tests and rubocop tests.
|
99
191
|
|
100
192
|
## Contributing
|
101
193
|
|
data/Rakefile
CHANGED
@@ -1,7 +1,26 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
|
-
require 'rake-terraform/default_tasks'
|
3
2
|
require 'rubocop/rake_task'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'rake-terraform'
|
5
|
+
# include project rake tasks
|
6
|
+
require 'rake-terraform/default_tasks'
|
7
|
+
|
8
|
+
namespace :test do
|
9
|
+
# default unit tests
|
10
|
+
desc 'Run all unit tests in default spec suite'
|
11
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
12
|
+
task.pattern = 'spec/(unit|rake-terraform)/*_spec.rb'
|
13
|
+
end
|
14
|
+
# add rubocop tasks to test namespace
|
15
|
+
RuboCop::RakeTask.new
|
16
|
+
# run all non-integration/default tests
|
17
|
+
desc 'Run all default test suites'
|
18
|
+
task default: [:unit, :rubocop]
|
19
|
+
end
|
4
20
|
|
5
|
-
task default
|
21
|
+
# default task is to run all the default test suites
|
22
|
+
task default: ['test:default']
|
6
23
|
|
7
|
-
|
24
|
+
# keep a rubocop alias in place for backwards compatibility
|
25
|
+
desc 'Alias for test:rubocop'
|
26
|
+
task rubocop: ['test:rubocop']
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rake-terraform/env_process'
|
2
|
+
|
3
|
+
module RakeTerraform
|
4
|
+
module ApplyTask
|
5
|
+
# Configuration data for terraform apply task
|
6
|
+
class Config
|
7
|
+
prepend RakeTerraform::EnvProcess
|
8
|
+
|
9
|
+
attr_writer :plan
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
# initialize RakeTerraform::EnvProcess
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def execution_path
|
17
|
+
@execution_path ||= File.expand_path 'terraform'
|
18
|
+
end
|
19
|
+
|
20
|
+
# setter method for execution_path triggers setters for tf_environment and
|
21
|
+
# state_file so that these are dynamically updated on change (but only if
|
22
|
+
# we are using directory state, and not explicit path to a state file)
|
23
|
+
def execution_path=(dir)
|
24
|
+
@tf_environment = dir
|
25
|
+
@state_file = tf_state_file if @state_dir
|
26
|
+
@execution_path = dir
|
27
|
+
end
|
28
|
+
|
29
|
+
def plan
|
30
|
+
@plan ||= File.expand_path(default_plan)
|
31
|
+
end
|
32
|
+
|
33
|
+
def opts
|
34
|
+
Map.new(plan: plan,
|
35
|
+
execution_path: execution_path,
|
36
|
+
unique_state: unique_state,
|
37
|
+
state_file: state_file)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def default_plan
|
43
|
+
File.join('output', 'terraform', 'plan.tf')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,53 +1,41 @@
|
|
1
|
+
require 'highline/import'
|
2
|
+
require 'rake-terraform/basetask'
|
3
|
+
require 'rake-terraform/terraformcmd'
|
4
|
+
|
1
5
|
module RakeTerraform
|
2
6
|
module ApplyTask
|
3
|
-
# Configuration data for terraform apply task
|
4
|
-
class Config
|
5
|
-
attr_accessor :plan
|
6
|
-
attr_accessor :execution_path
|
7
|
-
def initialize
|
8
|
-
@plan = File.expand_path(default_plan)
|
9
|
-
@execution_path = File.expand_path 'terraform'
|
10
|
-
end
|
11
|
-
|
12
|
-
def opts
|
13
|
-
Map.new(plan: @plan,
|
14
|
-
execution_path: @execution_path)
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def default_plan
|
20
|
-
File.join('output', 'terraform', 'plan.tf')
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
7
|
# Custom rake task to run `terraform apply`
|
25
8
|
class Task < BaseTask
|
9
|
+
include RakeTerraform::TerraformCmd
|
10
|
+
|
26
11
|
def initialize(opts)
|
27
12
|
@opts = opts
|
28
13
|
end
|
29
14
|
|
30
15
|
def execute
|
31
|
-
require 'highline/import'
|
32
|
-
|
33
16
|
plan = @opts.get(:plan)
|
34
|
-
|
35
|
-
ensure_plan_exists plan
|
36
|
-
|
37
|
-
system "terraform show --module-depth=2 #{plan}"
|
38
|
-
|
39
|
-
say 'The above changes will be applied to your environment.'
|
40
|
-
exit unless agree 'Are you sure you want to execute this plan? (y/n)'
|
41
|
-
|
17
|
+
pre_execute_checks(plan)
|
42
18
|
Dir.chdir(@opts.get(:execution_path)) do
|
43
|
-
|
19
|
+
if @opts[:unique_state]
|
20
|
+
tf_apply(plan, @opts[:state_file])
|
21
|
+
else
|
22
|
+
tf_apply(plan)
|
23
|
+
end
|
44
24
|
end
|
45
25
|
end
|
46
26
|
|
47
27
|
private
|
48
28
|
|
29
|
+
# run pre execution checks
|
30
|
+
def pre_execute_checks(plan = @opts.get(:plan))
|
31
|
+
validate_terraform_installed
|
32
|
+
ensure_plan_exists plan
|
33
|
+
tf_show(plan)
|
34
|
+
say 'The above changes will be applied to your environment.'
|
35
|
+
exit unless agree 'Are you sure you want to execute this plan? (y/n)'
|
36
|
+
end
|
37
|
+
|
49
38
|
def ensure_plan_exists(plan)
|
50
|
-
require 'fileutils'
|
51
39
|
fail "Plan #{plan} does not exist! Aborting!" unless File.exist? plan
|
52
40
|
end
|
53
41
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rake/task'
|
2
|
+
require 'fileutils'
|
2
3
|
require 'iniparse'
|
3
4
|
require 'English'
|
4
5
|
|
@@ -7,7 +8,7 @@ module RakeTerraform
|
|
7
8
|
class BaseTask < Rake::Task
|
8
9
|
def validate_terraform_installed
|
9
10
|
error = 'Please ensure you have terraform installed and on your path!'
|
10
|
-
fail error unless terraform_installed?
|
11
|
+
fail TerraformNotInstalled, error unless terraform_installed?
|
11
12
|
end
|
12
13
|
|
13
14
|
def terraform_installed?
|
@@ -1,7 +1,11 @@
|
|
1
|
-
require '
|
1
|
+
require 'rake-terraform'
|
2
2
|
require 'pathname'
|
3
3
|
|
4
4
|
namespace :terraform do
|
5
|
+
# TODO: refactor all environment variable processing into
|
6
|
+
# RakeTerraform::EnvProcess, include in this task and pass to the
|
7
|
+
# relevant Config classes, rather than including directly in the Config
|
8
|
+
# classes
|
5
9
|
env_glob = ENV['TERRAFORM_ENVIRONMENT_GLOB'] || 'terraform/**/*.tf'
|
6
10
|
output_base = ENV['TERRAFORM_OUTPUT_BASE'] || 'output/terraform'
|
7
11
|
credential_file = ENV['TERRAFORM_CREDENTIAL_FILE']
|
@@ -25,7 +29,6 @@ namespace :terraform do
|
|
25
29
|
|
26
30
|
short_name = abs_relative_path.to_s.tr('/', '_')
|
27
31
|
plan_path = File.expand_path File.join(output_base, "#{short_name}.tf")
|
28
|
-
|
29
32
|
desc "Plan migration of #{short_name}" if hide_tasks == 'false'
|
30
33
|
terraform_plan "plan_#{short_name}" do |t|
|
31
34
|
t.input_dir = env
|
data/lib/rake-terraform/dsl.rb
CHANGED
@@ -7,7 +7,7 @@ module RakeTerraform
|
|
7
7
|
# Definitions of methods for custom rake tasks
|
8
8
|
module DSL
|
9
9
|
def terraform_plan(*args)
|
10
|
-
require 'rake-terraform/
|
10
|
+
require 'rake-terraform/plantask'
|
11
11
|
Rake::Task.define_task(*args) do
|
12
12
|
c = RakeTerraform::PlanTask::Config.new
|
13
13
|
yield c
|
@@ -16,7 +16,7 @@ module RakeTerraform
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def terraform_apply(*args)
|
19
|
-
require 'rake-terraform/
|
19
|
+
require 'rake-terraform/applytask'
|
20
20
|
Rake::Task.define_task(*args) do
|
21
21
|
c = RakeTerraform::ApplyTask::Config.new
|
22
22
|
yield c
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'wannabe_bool'
|
2
|
+
|
3
|
+
module RakeTerraform
|
4
|
+
# == RakeTerraform::EnvProcess
|
5
|
+
#
|
6
|
+
# Mixin for processing environment variables
|
7
|
+
#
|
8
|
+
# TODO: refactor all non accessor methods as private methods
|
9
|
+
#
|
10
|
+
module EnvProcess
|
11
|
+
attr_reader :unique_state, :state_file, :state_dir_var, :state_dir,
|
12
|
+
:tf_environment
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@unique_state, @state_file, @state_dir_var, @state_dir = nil
|
16
|
+
@tf_environment = nil
|
17
|
+
tf_unique_state_valid? && @unique_state = tf_unique_state
|
18
|
+
tf_state_dir_var_valid? && @state_dir_var = tf_state_dir_var
|
19
|
+
# tf_state_file represents the full path to the calculated file within
|
20
|
+
# tf_state_dir if given
|
21
|
+
if tf_state_dir_valid?
|
22
|
+
@state_dir = tf_state_dir
|
23
|
+
@state_file = tf_state_file
|
24
|
+
end
|
25
|
+
tf_state_file_valid? && @state_file = tf_state_file
|
26
|
+
end
|
27
|
+
|
28
|
+
# whether or not unique states are enabled and required args are also given
|
29
|
+
def tf_unique_state
|
30
|
+
state_var = ENV['TERRAFORM_UNIQUE_STATE'].to_b
|
31
|
+
return false if state_var == false
|
32
|
+
unless tf_unique_state_valid?
|
33
|
+
fail(
|
34
|
+
ArgumentError,
|
35
|
+
'Both or neither of TERRAFORM_STATE_FILE or TERRAFORM_STATE_DIR_VAR' \
|
36
|
+
' given, or missing target for TERRAFORM_STATE_DIR_VAR'
|
37
|
+
)
|
38
|
+
end
|
39
|
+
ENV['TERRAFORM_UNIQUE_STATE'].to_b
|
40
|
+
end
|
41
|
+
|
42
|
+
# if we are using tf_state_dir_var and that is valid, then return the full
|
43
|
+
# path to the calculated state file. Otherwise return the value of a valid
|
44
|
+
# TERRAFORM_STATE_FILE variable
|
45
|
+
def tf_state_file
|
46
|
+
return state_dir_full_path if tf_state_dir_valid?
|
47
|
+
return nil if ENV['TERRAFORM_STATE_FILE'].nil?
|
48
|
+
unless tf_state_file_valid?
|
49
|
+
fail(
|
50
|
+
ArgumentError,
|
51
|
+
'Argument for TERRAFORM_STATE_FILE is invalid'
|
52
|
+
)
|
53
|
+
end
|
54
|
+
ENV['TERRAFORM_STATE_FILE']
|
55
|
+
end
|
56
|
+
|
57
|
+
# return the value if tf_state_dir_var
|
58
|
+
# see also: tf_state_dir
|
59
|
+
def tf_state_dir_var
|
60
|
+
return nil if ENV['TERRAFORM_STATE_DIR_VAR'].nil?
|
61
|
+
unless tf_state_dir_var_valid?
|
62
|
+
fail(
|
63
|
+
ArgumentError,
|
64
|
+
'Argument for TERRAFORM_STATE_DIR_VAR is invalid'
|
65
|
+
)
|
66
|
+
end
|
67
|
+
ENV['TERRAFORM_STATE_DIR_VAR']
|
68
|
+
end
|
69
|
+
|
70
|
+
# return the target of tf_state_dir_var
|
71
|
+
# see also: tf_state_dir_var
|
72
|
+
def tf_state_dir
|
73
|
+
return nil if ENV['TERRAFORM_STATE_DIR_VAR'].nil?
|
74
|
+
unless tf_state_dir_valid?
|
75
|
+
fail(
|
76
|
+
ArgumentError,
|
77
|
+
'Argument for TERRAFORM_STATE_DIR_VAR is invalid'
|
78
|
+
)
|
79
|
+
end
|
80
|
+
dir_var = ENV['TERRAFORM_STATE_DIR_VAR']
|
81
|
+
"#{tf_env_string}state/#{ENV[dir_var]}"
|
82
|
+
end
|
83
|
+
|
84
|
+
# calculate the full path to a state file within tf_state_dir
|
85
|
+
def state_dir_full_path(dir = tf_state_dir)
|
86
|
+
File.expand_path(
|
87
|
+
File.join(dir, default_state_file_name)
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
# if @tf_environment is set then return that, postfixed by a '/' -
|
92
|
+
# otherwise return 'terraform/'
|
93
|
+
def tf_env_string
|
94
|
+
if @tf_environment
|
95
|
+
"#{@tf_environment}/"
|
96
|
+
else
|
97
|
+
'terraform/'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# validate tf_unique_state
|
102
|
+
def tf_unique_state_valid?
|
103
|
+
state_var = ENV['TERRAFORM_UNIQUE_STATE'].to_b
|
104
|
+
return true if state_var == false
|
105
|
+
if tf_state_file_valid? && tf_state_dir_var_valid?
|
106
|
+
return false
|
107
|
+
else
|
108
|
+
tf_state_file_valid? || tf_state_dir_var_valid?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# validate tf_state_file_valid?
|
113
|
+
# returns false if no environment set, or the file does not have a single
|
114
|
+
# a-z0-9 char
|
115
|
+
# TODO: improve regex?
|
116
|
+
def tf_state_file_valid?
|
117
|
+
return false if ENV['TERRAFORM_STATE_FILE'].nil?
|
118
|
+
ENV['TERRAFORM_STATE_FILE'] =~ /[a-z0-9]/i
|
119
|
+
end
|
120
|
+
|
121
|
+
# validate tf_state_dir_var (and corresponding target) is valid
|
122
|
+
# returns false if
|
123
|
+
# * TERRAFORM_STATE_DIR_VAR is nil
|
124
|
+
# * We cannot find the variable referenced by TERRAFORM_STATE_DIR_VAR
|
125
|
+
# * The variable referenced contains something other than a-z0-9_ chars
|
126
|
+
def tf_state_dir_var_valid?
|
127
|
+
return false if ENV['TERRAFORM_STATE_DIR_VAR'].nil?
|
128
|
+
dir_var = ENV['TERRAFORM_STATE_DIR_VAR']
|
129
|
+
return false unless dir_var =~ /^[a-z0-9_]+$/i
|
130
|
+
value = ENV[dir_var]
|
131
|
+
return false if value.nil?
|
132
|
+
value =~ /^[a-z0-9_]+$/i
|
133
|
+
end
|
134
|
+
|
135
|
+
alias_method :tf_state_dir_valid?, :tf_state_dir_var_valid?
|
136
|
+
|
137
|
+
# name of the default state file
|
138
|
+
def default_state_file_name
|
139
|
+
'terraform.tfstate'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|