rake-terraform 0.0.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|