terraspace 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/lib/templates/base/git_hook/hook.sh +5 -0
- data/lib/templates/base/project/.gitignore +0 -1
- data/lib/templates/base/shim/terraspace +7 -0
- data/lib/templates/hcl/project/config/terraform/backend.tf.tt +3 -3
- data/lib/templates/plugin/lib/templates/hcl/project/config/terraform/backend.tf.tt +2 -2
- data/lib/terraspace/app.rb +6 -0
- data/lib/terraspace/builder.rb +2 -46
- data/lib/terraspace/cli.rb +34 -18
- data/lib/terraspace/cli/build/placeholder.rb +40 -0
- data/lib/terraspace/cli/cloud.rb +24 -0
- data/lib/terraspace/cli/commander.rb +8 -1
- data/lib/terraspace/cli/init.rb +67 -0
- data/lib/terraspace/cli/list.rb +13 -0
- data/lib/terraspace/cli/new.rb +8 -0
- data/lib/terraspace/cli/new/git_hook.rb +33 -0
- data/lib/terraspace/cli/new/shim.rb +58 -0
- data/lib/terraspace/cli/summary.rb +9 -12
- data/lib/terraspace/compiler/backend.rb +9 -37
- data/lib/terraspace/compiler/backend/parser.rb +42 -0
- data/lib/terraspace/compiler/builder.rb +6 -2
- data/lib/terraspace/compiler/cleaner.rb +19 -2
- data/lib/terraspace/compiler/cleaner/backend_change.rb +1 -1
- data/lib/terraspace/compiler/dsl/syntax/mod.rb +1 -0
- data/lib/terraspace/compiler/dsl/syntax/mod/backend.rb +16 -3
- data/lib/terraspace/compiler/expander.rb +28 -1
- data/lib/terraspace/compiler/writer.rb +1 -1
- data/lib/terraspace/core.rb +7 -1
- data/lib/terraspace/mod.rb +37 -12
- data/lib/terraspace/mod/remote.rb +1 -1
- data/lib/terraspace/plugin/expander/interface.rb +48 -5
- data/lib/terraspace/plugin/infer_provider.rb +15 -0
- data/lib/terraspace/plugin/layer/interface.rb +5 -0
- data/lib/terraspace/seeder.rb +4 -4
- data/lib/terraspace/terraform/api.rb +53 -0
- data/lib/terraspace/terraform/api/client.rb +10 -0
- data/lib/terraspace/terraform/api/http.rb +106 -0
- data/lib/terraspace/terraform/api/var.rb +72 -0
- data/lib/terraspace/terraform/api/vars.rb +38 -0
- data/lib/terraspace/terraform/api/vars/base.rb +7 -0
- data/lib/terraspace/terraform/api/vars/json.rb +14 -0
- data/lib/terraspace/terraform/api/vars/rb.rb +21 -0
- data/lib/terraspace/terraform/args/custom.rb +1 -1
- data/lib/terraspace/terraform/args/default.rb +16 -2
- data/lib/terraspace/terraform/cloud.rb +25 -0
- data/lib/terraspace/terraform/cloud/workspace.rb +95 -0
- data/lib/terraspace/terraform/runner.rb +1 -1
- data/lib/terraspace/util/sh.rb +1 -1
- data/lib/terraspace/version.rb +1 -1
- data/spec/fixtures/{cache_build_dir → cache_dir}/variables.tf +0 -0
- data/spec/fixtures/projects/hcl/aws/config/backend.tf +1 -1
- data/spec/fixtures/projects/hcl/google/config/backend.tf +1 -1
- data/spec/terraspace/seeder_spec.rb +1 -1
- data/spec/terraspace/terraform/hooks/builder_spec.rb +1 -1
- data/terraspace.gemspec +3 -3
- metadata +37 -17
- data/lib/terraspace/cli/build.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6cfa0c4e6aa1aa9871bc8b1902b283f2b91f5392738a066fdc58efb56153bed1
|
4
|
+
data.tar.gz: 2219a5bbbd4dbad228e406d7ce586cf5bfdb8392868478e59e3adbd6dc4adda5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3bb558668074f2e278359a887e369c5182c95fd306973a9cae6c4bd7f95d9be653ce41b923e41e5470350c35234443a0ae3d4e16d5c8b35763feab9393a9c12
|
7
|
+
data.tar.gz: 24acaffec5e568152133e014697404cc9d80a2bd79d54b700584db93a5884ca184508544519d349e833a17f84ac1cc4f2d095a787ed5cdb5216f25b37f04fb50
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,27 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
|
5
5
|
|
6
|
+
## [0.2.0]
|
7
|
+
* #34 Terraform Cloud and Terraform Enterprise support added.
|
8
|
+
* TFC Vars support: JSON and DSL. config.overwrite and config.overwrite_sensitive configs
|
9
|
+
* Build all stacks with config/terraform files. Designed to support the TFC VCS-driven workflow.
|
10
|
+
* Layer Interface module added. All latest provider plugins like terraspace\_plugin_aws make use of this module.
|
11
|
+
* Backend pattern expansion auto-detects the provider bakcend. The `expansion` method replaces the `backend_expand` method. `backend_expand` is deprecated.
|
12
|
+
* New expander variables: TYPE_INSTANCE, INSTANCE, CACHE_ROOT. Also added strip trailing - and / behavior.
|
13
|
+
* Timeout for terraform init. The default timeout is 10m and will then print out the terraform init log.
|
14
|
+
* Terraspace 0.2.x is compatible with terraspace\_plugin_aws 0.2.x, terraspace\_plugin_google 0.2.x, and terraspace\_plugin_azurerm 0.2.x
|
15
|
+
* New commands: terraspace list, terraspace cloud list, terraspace cloud setup, terraspace cloud destroy, terraspace new shim, terraspace new git_hook
|
16
|
+
* terraspace list: list of modules and stacks
|
17
|
+
* terraspace cloud list: shows list of TFC workspaces
|
18
|
+
* terraspace cloud setup: setups up TFC workspace for VCS-driven workflow. This automatically happens for the TFC CLI-driven workflow.
|
19
|
+
* terraspace cloud destroy: destroys the TFC workspace associated with the stack. Can also use the `terraspace down demo --destroy-workspace` option.
|
20
|
+
* terraspace new shim: An quick way to generate a terraspace shim.
|
21
|
+
* terraspace new git_hook: An quick way to set up a git pre-push hook for the TFC VCS-driven workflow.
|
22
|
+
* terraspace down: works even if there's no app/stacks folder. A fake stack is built.
|
23
|
+
* terraspace build: terraspace build placeholder concept.
|
24
|
+
* terraspace build: only builds now. auto bucket backend creation and terraform init is is still automatically called by terraform up, etc.
|
25
|
+
* terraspace up: --reconfigure option. This is useful if upgrading Terraform version.
|
26
|
+
|
6
27
|
## [0.1.2]
|
7
28
|
- #33 rspec-terraspace dependency added
|
8
29
|
|
@@ -3,8 +3,8 @@
|
|
3
3
|
# terraform {
|
4
4
|
# backend "s3" {
|
5
5
|
# bucket = "<%= options[:bucket] || "terraform-state-:ACCOUNT-:REGION-:ENV" %>"
|
6
|
-
# key = "<%%= "
|
7
|
-
# region = "<%%= "
|
6
|
+
# key = "<%%= expansion(":REGION/:ENV/:BUILD_DIR/terraform.tfstate") %> # IE: us-west-2/dev/ec2/modules/vpc/terraform.tfstate
|
7
|
+
# region = "<%%= expansion(":REGION") %>"
|
8
8
|
# encrypt = true
|
9
9
|
# dynamodb_table = "terraform_locks"
|
10
10
|
# }
|
@@ -13,6 +13,6 @@
|
|
13
13
|
# terraform {
|
14
14
|
# backend "gcs" {
|
15
15
|
# bucket = "<%= options[:bucket] || "terraform-state-:PROJECT-:REGION-:ENV" %>"
|
16
|
-
# prefix = "<%%=
|
16
|
+
# prefix = "<%%= expansion(":REGION/:ENV/:BUILD_DIR") %>" # IE: us-central1/dev/modules/vm
|
17
17
|
# }
|
18
18
|
# }
|
@@ -1,6 +1,6 @@
|
|
1
1
|
terraform {
|
2
2
|
backend "PROVIDER_BACKEND" {
|
3
|
-
bucket = "<%%=
|
4
|
-
prefix = "<%%=
|
3
|
+
bucket = "<%%= expansion("terraform-state-REPLACE_ME-REPLACE_ME-:ENV") %>" # expanded by terraspace
|
4
|
+
prefix = "<%%= expansion("REPLACE_ME/:ENV/:BUILD_DIR") %>" # expanded by terraspace
|
5
5
|
}
|
6
6
|
}
|
data/lib/terraspace/app.rb
CHANGED
@@ -14,6 +14,12 @@ module Terraspace
|
|
14
14
|
config.logger = Logger.new($stdout)
|
15
15
|
config.logger.level = :info
|
16
16
|
config.hooks = Hooks.new
|
17
|
+
config.cloud = ActiveSupport::OrderedOptions.new
|
18
|
+
config.cloud.overwrite = true
|
19
|
+
config.cloud.overwrite_sensitive = true
|
20
|
+
config.build = ActiveSupport::OrderedOptions.new
|
21
|
+
config.build.cache_root = nil # defaults to .terraspace-cache
|
22
|
+
config.build.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
|
17
23
|
config
|
18
24
|
end
|
19
25
|
|
data/lib/terraspace/builder.rb
CHANGED
@@ -4,24 +4,15 @@ module Terraspace
|
|
4
4
|
Terraspace::CLI::CheckSetup.check!
|
5
5
|
@mod.root_module = true
|
6
6
|
Compiler::Cleaner.new(@mod, @options).clean
|
7
|
-
build_dir = Util.pretty_path(@mod.
|
7
|
+
build_dir = Util.pretty_path(@mod.cache_dir)
|
8
8
|
logger.info "Building #{build_dir}"
|
9
9
|
|
10
10
|
build_all("modules") # build all modules and stacks as dependencies
|
11
11
|
build_all("stacks")
|
12
|
-
build_root_module
|
13
|
-
|
14
|
-
auto_create_backend
|
15
|
-
Terraform::Runner.new("init", @options).run if !auto? && @options[:init] != false # will run on @options[:init].nil?
|
16
|
-
build_remote_dependencies # runs after terraform init, which downloads remote modules
|
12
|
+
build_root_module
|
17
13
|
logger.info "Built in #{build_dir}"
|
18
14
|
end
|
19
15
|
|
20
|
-
def auto?
|
21
|
-
# command is only passed from CLI in the update specifically for this check
|
22
|
-
@options[:auto] && @options[:command] == "update"
|
23
|
-
end
|
24
|
-
|
25
16
|
def build_root_module
|
26
17
|
Compiler::Builder.new(@mod).build
|
27
18
|
end
|
@@ -35,22 +26,12 @@ module Terraspace
|
|
35
26
|
|
36
27
|
consider_stacks = type_dir == "stacks"
|
37
28
|
mod = Mod.new(mod_name, consider_stacks: consider_stacks)
|
38
|
-
next if root?(mod) # will build root module at the end
|
39
29
|
|
40
30
|
Compiler::Builder.new(mod).build
|
41
31
|
built << mod_name
|
42
32
|
end
|
43
33
|
end
|
44
34
|
|
45
|
-
def root?(mod)
|
46
|
-
mod.name == @mod.name && mod.type == @mod.type
|
47
|
-
end
|
48
|
-
|
49
|
-
def auto_create_backend
|
50
|
-
return unless @options[:command] == "update"
|
51
|
-
Compiler::Backend.new(@mod).create
|
52
|
-
end
|
53
|
-
|
54
35
|
def local_paths(type_dir)
|
55
36
|
dirs("app/#{type_dir}/*") + dirs("vendor/#{type_dir}/*")
|
56
37
|
end
|
@@ -58,30 +39,5 @@ module Terraspace
|
|
58
39
|
def dirs(path)
|
59
40
|
Dir.glob("#{Terraspace.root}/#{path}")
|
60
41
|
end
|
61
|
-
|
62
|
-
# Currently only handles remote modules only one-level deep.
|
63
|
-
def build_remote_dependencies
|
64
|
-
modules_json_path = "#{@mod.cache_build_dir}/.terraform/modules/modules.json"
|
65
|
-
return unless File.exist?(modules_json_path)
|
66
|
-
|
67
|
-
initialized_modules = JSON.load(IO.read(modules_json_path))
|
68
|
-
# For example of structure see spec/fixtures/initialized/modules.json
|
69
|
-
initialized_modules["Modules"].each do |meta|
|
70
|
-
build_remote_mod(meta)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def build_remote_mod(meta)
|
75
|
-
return if local_source?(meta["Source"])
|
76
|
-
return if meta['Dir'] == '.' # root is already built
|
77
|
-
|
78
|
-
remote_mod = Mod::Remote.new(meta, @mod)
|
79
|
-
Compiler::Builder.new(remote_mod).build
|
80
|
-
end
|
81
|
-
|
82
|
-
private
|
83
|
-
def local_source?(s)
|
84
|
-
s =~ %r{^\.} || s =~ %r{^/}
|
85
|
-
end
|
86
42
|
end
|
87
43
|
end
|
data/lib/terraspace/cli.rb
CHANGED
@@ -24,20 +24,25 @@ module Terraspace
|
|
24
24
|
init_option = Proc.new {
|
25
25
|
option :init, type: :boolean, default: true, desc: "Instance of stack"
|
26
26
|
}
|
27
|
+
reconfigure_option = Proc.new {
|
28
|
+
option :reconfigure, type: :boolean, desc: "Add terraform -reconfigure option"
|
29
|
+
}
|
27
30
|
|
28
31
|
desc "new SUBCOMMAND", "new subcommands"
|
29
32
|
long_desc Help.text(:new)
|
30
33
|
subcommand "new", New
|
31
34
|
|
32
|
-
desc "
|
35
|
+
desc "cloud SUBCOMMAND", "cloud subcommands"
|
36
|
+
long_desc Help.text(:cloud)
|
37
|
+
subcommand "cloud", Cloud
|
38
|
+
|
39
|
+
desc "build STACK", "build"
|
33
40
|
long_desc Help.text(:build)
|
34
41
|
option :quiet, type: :boolean, default: true, desc: "quiet output"
|
35
|
-
auto_option.call
|
36
|
-
init_option.call
|
37
|
-
input_option.call
|
38
42
|
instance_option.call
|
43
|
+
yes_option.call
|
39
44
|
def build(mod)
|
40
|
-
|
45
|
+
Terraspace::Builder.new(@options.merge(mod: mod)).run
|
41
46
|
end
|
42
47
|
|
43
48
|
desc "bundle", "bundle"
|
@@ -58,22 +63,25 @@ module Terraspace
|
|
58
63
|
Clean.new(options).run
|
59
64
|
end
|
60
65
|
|
61
|
-
desc "console", "console .terraspace-cache dir"
|
66
|
+
desc "console STACK", "console .terraspace-cache dir"
|
62
67
|
long_desc Help.text(:console)
|
63
68
|
instance_option.call
|
64
69
|
def console(mod)
|
65
70
|
Commander.new("console", options.merge(mod: mod)).run
|
66
71
|
end
|
67
72
|
|
68
|
-
desc "down
|
73
|
+
desc "down STACK", "down"
|
69
74
|
long_desc Help.text(:down)
|
70
75
|
instance_option.call
|
71
76
|
yes_option.call
|
77
|
+
reconfigure_option.call
|
78
|
+
option :destroy_workspace, type: :boolean, desc: "Also destroy the Cloud workspace. Only applies when using Terraform Cloud remote backend."
|
72
79
|
def down(mod)
|
73
|
-
Commander.new("destroy", options.merge(mod: mod)).run
|
80
|
+
Commander.new("destroy", options.merge(mod: mod, command: "down")).run
|
81
|
+
Terraspace::Terraform::Cloud::Workspace.new(options.merge(mod: mod)).destroy if @options[:destroy_workspace]
|
74
82
|
end
|
75
83
|
|
76
|
-
desc "info
|
84
|
+
desc "info STACK", "info"
|
77
85
|
long_desc Help.text(:info)
|
78
86
|
format_option.call
|
79
87
|
instance_option.call
|
@@ -81,31 +89,38 @@ module Terraspace
|
|
81
89
|
Info.new(options.merge(mod: mod)).run
|
82
90
|
end
|
83
91
|
|
84
|
-
desc "
|
92
|
+
desc "list", "list stacks and modules"
|
93
|
+
long_desc Help.text(:list)
|
94
|
+
def list
|
95
|
+
List.new(options).run
|
96
|
+
end
|
97
|
+
|
98
|
+
desc "plan STACK", "plan stack"
|
85
99
|
long_desc Help.text(:plan)
|
86
100
|
auto_option.call
|
87
101
|
input_option.call
|
88
102
|
instance_option.call
|
89
103
|
out_option.call
|
104
|
+
reconfigure_option.call
|
90
105
|
def plan(mod)
|
91
106
|
Commander.new("plan", options.merge(mod: mod)).run
|
92
107
|
end
|
93
108
|
|
94
|
-
desc "providers
|
109
|
+
desc "providers STACK", "providers"
|
95
110
|
long_desc Help.text(:providers)
|
96
111
|
instance_option.call
|
97
112
|
def providers(mod)
|
98
113
|
Commander.new("providers", options.merge(mod: mod)).run
|
99
114
|
end
|
100
115
|
|
101
|
-
desc "refresh", "refresh"
|
116
|
+
desc "refresh STACK", "refresh"
|
102
117
|
long_desc Help.text(:refresh)
|
103
118
|
instance_option.call
|
104
119
|
def refresh(mod)
|
105
120
|
Commander.new("refresh", options.merge(mod: mod)).run
|
106
121
|
end
|
107
122
|
|
108
|
-
desc "seed
|
123
|
+
desc "seed STACK", "seed"
|
109
124
|
long_desc Help.text(:seed)
|
110
125
|
option :yes, aliases: :y, type: :boolean, desc: "bypass prompts and force overwrite files"
|
111
126
|
option :where, desc: "where to create file. either under app or seed folder structure. values: app or stack"
|
@@ -124,7 +139,7 @@ module Terraspace
|
|
124
139
|
Summary.new(options).run
|
125
140
|
end
|
126
141
|
|
127
|
-
desc "show
|
142
|
+
desc "show STACK", "show"
|
128
143
|
long_desc Help.text(:show)
|
129
144
|
instance_option.call
|
130
145
|
def show(mod)
|
@@ -137,7 +152,7 @@ module Terraspace
|
|
137
152
|
Test.new(options).run
|
138
153
|
end
|
139
154
|
|
140
|
-
desc "output
|
155
|
+
desc "output STACK", "output"
|
141
156
|
long_desc Help.text(:output)
|
142
157
|
format_option.call
|
143
158
|
instance_option.call
|
@@ -146,20 +161,21 @@ module Terraspace
|
|
146
161
|
Commander.new("output", options.merge(mod: mod)).run
|
147
162
|
end
|
148
163
|
|
149
|
-
desc "update
|
164
|
+
desc "update STACK", "Update infrasturcture. IE: apply plan"
|
150
165
|
long_desc Help.text(:update)
|
151
166
|
auto_option.call
|
152
167
|
init_option.call
|
153
168
|
input_option.call
|
154
169
|
instance_option.call
|
155
170
|
yes_option.call
|
171
|
+
reconfigure_option.call
|
156
172
|
option :plan, desc: "Execution plan that can be used to only execute a pre-determined set of actions."
|
157
173
|
option :var_files, type: :array, desc: "list of var files"
|
158
174
|
def update(mod)
|
159
|
-
Commander.new("apply", options.merge(mod: mod
|
175
|
+
Commander.new("apply", options.merge(mod: mod)).run
|
160
176
|
end
|
161
177
|
|
162
|
-
desc "validate
|
178
|
+
desc "validate STACK", "validate"
|
163
179
|
long_desc Help.text(:validate)
|
164
180
|
instance_option.call
|
165
181
|
def validate(mod)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# The placeholder stack is a special stack that is useful in case there are no app/stacks.
|
2
|
+
# We build a placeholder back just so we have backend.tf to be used to grab info.
|
3
|
+
# It's useful for the summary command.
|
4
|
+
module Terraspace::CLI::Build
|
5
|
+
class Placeholder
|
6
|
+
include Terraspace::Util::Logging
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
# Grab the last module and build that.
|
13
|
+
# Assume the backend key has the same prefix
|
14
|
+
# Note: Tried building a empty "null" stack but with TFC a null space workspace is created, which is undesired.
|
15
|
+
def build
|
16
|
+
return if ENV['TS_SUMMARY_BUILD'] == '0'
|
17
|
+
|
18
|
+
mod = @options[:mod]
|
19
|
+
if !mod or mod == "placeholder"
|
20
|
+
logger.info "Building one of the modules to get backend.tf info"
|
21
|
+
mod = find_mod
|
22
|
+
end
|
23
|
+
Terraspace::Builder.new(@options.merge(mod: mod, init: false)).run # generate and init
|
24
|
+
Terraspace::Mod.new(mod, @options) # mod metadata
|
25
|
+
end
|
26
|
+
|
27
|
+
# Used by: terraspace build placeholder
|
28
|
+
def find_mod
|
29
|
+
mod_path = Dir.glob("{app,vendor}/{modules,stacks}/*").last
|
30
|
+
unless mod_path
|
31
|
+
logger.info <<~EOL
|
32
|
+
No modules or stacks found.
|
33
|
+
Unable to determine the backend state path without at least one module.
|
34
|
+
EOL
|
35
|
+
exit 0
|
36
|
+
end
|
37
|
+
File.basename(mod_path) # mod name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Terraspace::CLI
|
2
|
+
class Cloud < Terraspace::Command
|
3
|
+
Workspace = Terraspace::Terraform::Cloud::Workspace
|
4
|
+
|
5
|
+
desc "list", "List workspaces"
|
6
|
+
long_desc Help.text("cloud:list")
|
7
|
+
def list
|
8
|
+
Workspace.new(options).list
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "destroy", "Destroy workspace"
|
12
|
+
long_desc Help.text("cloud:destroy")
|
13
|
+
option :yes, aliases: :y, type: :boolean, desc: "bypass are you sure prompt"
|
14
|
+
def destroy(mod)
|
15
|
+
Workspace.new(options.merge(mod: mod)).destroy
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "setup", "Setup workspace"
|
19
|
+
long_desc Help.text("cloud:setup")
|
20
|
+
def setup(mod)
|
21
|
+
Workspace.new(options.merge(mod: mod)).setup
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -7,8 +7,15 @@ class Terraspace::CLI
|
|
7
7
|
|
8
8
|
# Commander always runs Build#run
|
9
9
|
def run
|
10
|
-
|
10
|
+
Terraspace::Builder.new(@options).run # generate and init
|
11
|
+
auto_create_backend
|
12
|
+
Init.new(@options.merge(calling_command: @name)).run
|
11
13
|
Terraspace::Terraform::Runner.new(@name, @options).run
|
12
14
|
end
|
15
|
+
|
16
|
+
def auto_create_backend
|
17
|
+
return unless @name == "apply"
|
18
|
+
Terraspace::Compiler::Backend.new(@mod).create
|
19
|
+
end
|
13
20
|
end
|
14
21
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
3
|
+
class Terraspace::CLI
|
4
|
+
class Init < Base
|
5
|
+
def initialize(options={})
|
6
|
+
# Original calling command. Can be from Commander which is a terraform command. IE: terraform apply
|
7
|
+
# Or can be from terraspace cloud setup. Which will be cloud-setup.
|
8
|
+
@calling_command = options[:calling_command]
|
9
|
+
super(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
init if init?
|
14
|
+
build_remote_dependencies # runs after terraform init, which downloads remote modules
|
15
|
+
sync_cloud
|
16
|
+
end
|
17
|
+
|
18
|
+
# Note the init will always create the Terraform Cloud Workspace
|
19
|
+
def init
|
20
|
+
# default init timeout is pretty generous in case of slow internet to download the provider plugins
|
21
|
+
init_timeout = Integer(ENV['TS_INIT_TIMEOUT'] || 600)
|
22
|
+
Timeout::timeout(init_timeout) do
|
23
|
+
Terraspace::Terraform::Runner.new("init", @options).run if !auto? && @options[:init] != false # will run on @options[:init].nil?
|
24
|
+
end
|
25
|
+
rescue Timeout::Error
|
26
|
+
logger.error "ERROR: It took too long to run terraform init. Here is the output logs of terraform init:".color(:red)
|
27
|
+
logger.error IO.read(Terraspace::Terraform::Args::Default.terraform_init_log)
|
28
|
+
end
|
29
|
+
|
30
|
+
def sync_cloud
|
31
|
+
Terraspace::Terraform::Cloud.new(@options).run if %w[apply plan destroy cloud-setup].include?(@calling_command)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Currently only handles remote modules only one-level deep.
|
35
|
+
def build_remote_dependencies
|
36
|
+
modules_json_path = "#{@mod.cache_dir}/.terraform/modules/modules.json"
|
37
|
+
return unless File.exist?(modules_json_path)
|
38
|
+
|
39
|
+
initialized_modules = JSON.load(IO.read(modules_json_path))
|
40
|
+
# For example of structure see spec/fixtures/initialized/modules.json
|
41
|
+
initialized_modules["Modules"].each do |meta|
|
42
|
+
build_remote_mod(meta)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_remote_mod(meta)
|
47
|
+
return if local_source?(meta["Source"])
|
48
|
+
return if meta['Dir'] == '.' # root is already built
|
49
|
+
|
50
|
+
remote_mod = Mod::Remote.new(meta, @mod)
|
51
|
+
Compiler::Builder.new(remote_mod).build
|
52
|
+
end
|
53
|
+
|
54
|
+
def auto?
|
55
|
+
# command is only passed from CLI in the update specifically for this check
|
56
|
+
@options[:auto] && @calling_command == "apply"
|
57
|
+
end
|
58
|
+
private
|
59
|
+
def local_source?(s)
|
60
|
+
s =~ %r{^\.} || s =~ %r{^/}
|
61
|
+
end
|
62
|
+
|
63
|
+
def init?
|
64
|
+
%w[apply console destroy output plan providers refresh show validate cloud-setup].include?(@calling_command)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|