terraspace 1.0.4 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/templates/base/project/.gitignore +1 -0
- data/lib/templates/base/project/config/app.rb +1 -1
- data/lib/terraspace/all/grapher.rb +11 -3
- data/lib/terraspace/all/runner.rb +17 -10
- data/lib/terraspace/app/callable_option/concern.rb +12 -0
- data/lib/terraspace/app/callable_option.rb +58 -0
- data/lib/terraspace/app.rb +16 -3
- data/lib/terraspace/autodetect.rb +3 -7
- data/lib/terraspace/builder/allow/base.rb +59 -0
- data/lib/terraspace/builder/allow/env.rb +17 -0
- data/lib/terraspace/builder/allow/region.rb +31 -0
- data/lib/terraspace/builder/allow/stack.rb +17 -0
- data/lib/terraspace/builder/allow.rb +3 -33
- data/lib/terraspace/builder/children.rb +42 -0
- data/lib/terraspace/builder.rb +34 -32
- data/lib/terraspace/cli/all.rb +2 -0
- data/lib/terraspace/cli/build/placeholder.rb +3 -1
- data/lib/terraspace/cli/help/all/plan.md +11 -1
- data/lib/terraspace/cli/help/all/up.md +10 -0
- data/lib/terraspace/cli/help/plan.md +9 -1
- data/lib/terraspace/cli/help/up.md +9 -1
- data/lib/terraspace/cli/init.rb +1 -1
- data/lib/terraspace/cli.rb +3 -2
- data/lib/terraspace/compiler/dirs_concern.rb +6 -1
- data/lib/terraspace/compiler/expander/backend.rb +1 -1
- data/lib/terraspace/compiler/expander.rb +38 -14
- data/lib/terraspace/compiler/{builder → perform}/skip.rb +1 -1
- data/lib/terraspace/compiler/{builder.rb → perform.rb} +21 -20
- data/lib/terraspace/compiler/select.rb +32 -42
- data/lib/terraspace/compiler/strategy/tfvar.rb +2 -1
- data/lib/terraspace/dependency/resolver.rb +20 -0
- data/lib/terraspace/mod.rb +1 -0
- data/lib/terraspace/plugin/summary/interface.rb +1 -1
- data/lib/terraspace/terraform/args/expand.rb +25 -0
- data/lib/terraspace/terraform/args/thor.rb +14 -11
- data/lib/terraspace/terraform/ihooks/after/plan.rb +2 -2
- data/lib/terraspace/terraform/ihooks/base.rb +5 -0
- data/lib/terraspace/terraform/ihooks/before/plan.rb +3 -5
- data/lib/terraspace/terraform/remote_state/fetcher.rb +12 -5
- data/lib/terraspace/terraform/remote_state/marker/output.rb +1 -1
- data/lib/terraspace/version.rb +1 -1
- data/spec/terraspace/all/runner_spec.rb +1 -0
- data/spec/terraspace/compiler/erb/render_spec.rb +5 -1
- data/terraspace.gemspec +1 -1
- metadata +14 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c07e843df9e61e62be834feba56f4d5fa058f3dbb130ed7e15edca66ef23e22d
|
4
|
+
data.tar.gz: a7d7c3946e2485ccb369a5d76d413118aed14592750880a48990ca83cdca5bca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 026aa5128ce2bea7deb3e5b0fdb6e99c7cf50297c20f5292bbe6896dabb0ba995e62ecd14526ea2ea7e8e1a4be3895e29021620a89b26df49ad34ee0b95ffd1d
|
7
|
+
data.tar.gz: c2df058d2fe9848834fc4e166c1382ccb0e782170fb52f8fd264e4e948a1032916cc9d77662eac1969f4d2101e66b3655e07d944b217e5749581ac0d3ec04916
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,20 @@
|
|
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
|
+
## [1.1.1] - 2022-02-02
|
7
|
+
- [#199](https://github.com/boltops-tools/terraspace/pull/199) build required dependent stacks as part of terraspace up
|
8
|
+
|
9
|
+
## [1.1.0] - 2022-01-30
|
10
|
+
- [#196](https://github.com/boltops-tools/terraspace/pull/196) terraspace all: build modules in batches and only each specific stack
|
11
|
+
- [#197](https://github.com/boltops-tools/terraspace/pull/197) all plan --output and all up --plan options
|
12
|
+
- simplify starter config/app.rb
|
13
|
+
|
14
|
+
## [1.0.6] - 2022-01-24
|
15
|
+
- [#195](https://github.com/boltops-tools/terraspace/pull/195) improve autodetection for plugin expander for backend like remote
|
16
|
+
|
17
|
+
## [1.0.5] - 2022-01-23
|
18
|
+
- [#194](https://github.com/boltops-tools/terraspace/pull/194) ability to allow and deny envs, regions, and stacks
|
19
|
+
|
6
20
|
## [1.0.4] - 2022-01-21
|
7
21
|
- [#193](https://github.com/boltops-tools/terraspace/pull/193) improve all include_stacks and exclude_stacks option
|
8
22
|
|
@@ -3,14 +3,13 @@ require "tty-tree"
|
|
3
3
|
|
4
4
|
module Terraspace::All
|
5
5
|
class Grapher < Base
|
6
|
+
include Terraspace::Compiler::DirsConcern
|
6
7
|
include Terraspace::Util::Logging
|
7
8
|
|
8
9
|
def run
|
9
10
|
check_graphviz!
|
10
11
|
logger.info "Building graph..."
|
11
|
-
|
12
|
-
builder.run
|
13
|
-
graph = builder.graph
|
12
|
+
graph = build_graph
|
14
13
|
if @options[:format] == "text"
|
15
14
|
text(graph.top_nodes)
|
16
15
|
else
|
@@ -18,6 +17,15 @@ module Terraspace::All
|
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
20
|
+
def build_graph
|
21
|
+
resolver = Terraspace::Dependency::Resolver.new(@options.merge(quiet: true, draw_full_graph: draw_full_graph))
|
22
|
+
resolver.resolve
|
23
|
+
dependencies = Terraspace::Dependency::Registry.data # populated after build_unresolved
|
24
|
+
graph = Terraspace::Dependency::Graph.new(stack_names, dependencies, @options)
|
25
|
+
graph.build
|
26
|
+
graph
|
27
|
+
end
|
28
|
+
|
21
29
|
def text(nodes)
|
22
30
|
Rainbow.enabled = false unless @options[:full]
|
23
31
|
data = build_tree_data(nodes)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Terraspace::All
|
2
2
|
class Runner < Base
|
3
3
|
include Terraspace::Util
|
4
|
+
extend Memoist
|
4
5
|
|
5
6
|
def initialize(command, options={})
|
6
7
|
@command, @options = command, options
|
@@ -21,32 +22,27 @@ module Terraspace::All
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def build_batches
|
24
|
-
@batches =
|
25
|
+
@batches = Terraspace::Dependency::Resolver.new(@options).resolve
|
25
26
|
@batches.reverse! if @command == "down"
|
26
27
|
@batches
|
27
28
|
end
|
28
29
|
|
29
30
|
def deploy_batches
|
30
31
|
truncate_logs if ENV['TS_TRUNCATE_LOGS']
|
32
|
+
build_modules
|
31
33
|
@batches.each_with_index do |batch,i|
|
32
34
|
logger.info "Batch Run #{i+1}:"
|
33
|
-
run_builder unless i == 0 # already handled by build_batches the first time
|
34
35
|
deploy_batch(batch)
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
|
-
# Should run after each batch run. run_builder also calls replace_outputs.
|
39
|
-
# Important: rebuild from source so placeholders are in place.
|
40
|
-
def run_builder(quiet: true)
|
41
|
-
Terraspace::Builder.new(@options.merge(mod: "placeholder", quiet: quiet)).run
|
42
|
-
end
|
43
|
-
|
44
39
|
def deploy_batch(batch)
|
45
40
|
@pids = {} # stores child processes pids. map of pid to mod_name, reset this list on each batch run
|
46
41
|
concurrency = Terraspace.config.all.concurrency
|
47
42
|
batch.sort_by(&:name).each_slice(concurrency) do |slice|
|
48
43
|
slice.each do |node|
|
49
44
|
pid = fork do
|
45
|
+
build_stack(node.name)
|
50
46
|
run_terraspace(node.name)
|
51
47
|
end
|
52
48
|
@pids[pid] = node.name # store mod_name mapping
|
@@ -57,6 +53,16 @@ module Terraspace::All
|
|
57
53
|
report_errors # reports finall errors and possibly exit
|
58
54
|
end
|
59
55
|
|
56
|
+
def build_modules
|
57
|
+
builder = Terraspace::Builder.new(@options.merge(mod: "placeholder", clean: true, quiet: true, include_stacks: :none))
|
58
|
+
builder.build(modules: true)
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_stack(name)
|
62
|
+
builder = Terraspace::Builder.new(@options.merge(mod: name, clean: false, quiet: true, include_stacks: :root_only))
|
63
|
+
builder.build(modules: false)
|
64
|
+
end
|
65
|
+
|
60
66
|
def wait_for_child_proccess
|
61
67
|
@errors = [] # stores child processes pids that errored
|
62
68
|
@pids.each do |pid, _|
|
@@ -70,7 +76,7 @@ module Terraspace::All
|
|
70
76
|
@errors.each do |pid|
|
71
77
|
mod_name = @pids[pid]
|
72
78
|
terraspace_command = terraspace_command(mod_name)
|
73
|
-
logger.error "Error running: #{terraspace_command}.
|
79
|
+
logger.error "Error running: #{terraspace_command}. Fix the error above or check logs for the error.".color(:red)
|
74
80
|
end
|
75
81
|
unless @errors.empty?
|
76
82
|
exit 2 if exit_on_fail?
|
@@ -97,7 +103,8 @@ module Terraspace::All
|
|
97
103
|
log_path: log_path(mod_name),
|
98
104
|
terraspace_command: terraspace_command(mod_name),
|
99
105
|
}
|
100
|
-
|
106
|
+
# Its possible for log file to not get created if RemoteState::Fetcher#validate! fails
|
107
|
+
Summary.new(data).run if File.exist?(data[:log_path])
|
101
108
|
end
|
102
109
|
end
|
103
110
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Terraspace::App::CallableOption
|
2
|
+
module Concern
|
3
|
+
def callable_option(options={})
|
4
|
+
callable_option = Terraspace::App::CallableOption.new(
|
5
|
+
config_name: options[:config_name],
|
6
|
+
config_value: options[:config_value],
|
7
|
+
passed_args: options[:passed_args],
|
8
|
+
)
|
9
|
+
callable_option.object
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Class represents a terraspace option that is possibly callable. Examples:
|
2
|
+
#
|
3
|
+
# config.allow.envs
|
4
|
+
# config.allow.regions
|
5
|
+
# config.deny.envs
|
6
|
+
# config.deny.regions
|
7
|
+
# config.all.include_stacks
|
8
|
+
# config.all.exclude_stacks
|
9
|
+
#
|
10
|
+
# Abstraction is definitely obtuse. Using it to get rid of duplication.
|
11
|
+
#
|
12
|
+
class Terraspace::App
|
13
|
+
class CallableOption
|
14
|
+
include Terraspace::Util::Logging
|
15
|
+
|
16
|
+
def initialize(options={})
|
17
|
+
@options = options
|
18
|
+
# Example:
|
19
|
+
# config_name: config.allow.envs
|
20
|
+
# config_value: ["dev"]
|
21
|
+
# args: [@stack_name] # passed to object.call
|
22
|
+
@config_name = options[:config_name]
|
23
|
+
@config_value = options[:config_value]
|
24
|
+
@passed_args = options[:passed_args]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns either an Array or nil
|
28
|
+
def object
|
29
|
+
case @config_value
|
30
|
+
when nil
|
31
|
+
return nil
|
32
|
+
when Array
|
33
|
+
return @config_value
|
34
|
+
when -> (c) { c.respond_to?(:public_instance_methods) && c.public_instance_methods.include?(:call) }
|
35
|
+
object= @config_value.new
|
36
|
+
when -> (c) { c.respond_to?(:call) }
|
37
|
+
object = @config_value
|
38
|
+
else
|
39
|
+
raise "Invalid option for #{@config_name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
if object
|
43
|
+
result = @passed_args.empty? ? object.call : object.call(*@passed_args)
|
44
|
+
unless result.is_a?(Array) || result.is_a?(NilClass)
|
45
|
+
message = "ERROR: The #{@config_name} needs to return an Array or nil"
|
46
|
+
logger.info message.color(:yellow)
|
47
|
+
logger.info <<~EOL
|
48
|
+
The #{@config_name} when assigned a class, object, or proc must implement
|
49
|
+
the call method and return an Array or nil.
|
50
|
+
The current return value is a #{result.class}
|
51
|
+
EOL
|
52
|
+
raise message
|
53
|
+
end
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/terraspace/app.rb
CHANGED
@@ -12,17 +12,30 @@ module Terraspace
|
|
12
12
|
|
13
13
|
def defaults
|
14
14
|
config = ActiveSupport::OrderedOptions.new
|
15
|
+
|
15
16
|
config.all = ActiveSupport::OrderedOptions.new
|
16
17
|
config.all.concurrency = 5
|
17
18
|
config.all.exit_on_fail = ActiveSupport::OrderedOptions.new
|
18
|
-
config.all.exit_on_fail.down =
|
19
|
+
config.all.exit_on_fail.down = false
|
20
|
+
config.all.exit_on_fail.plan = true
|
19
21
|
config.all.exit_on_fail.up = true
|
20
|
-
|
21
|
-
config.all.include_stacks = nil
|
22
|
+
|
22
23
|
config.allow = ActiveSupport::OrderedOptions.new
|
23
24
|
config.allow.envs = nil
|
24
25
|
config.allow.regions = nil
|
26
|
+
config.allow.stacks = nil
|
27
|
+
config.deny = ActiveSupport::OrderedOptions.new
|
28
|
+
config.deny.envs = nil
|
29
|
+
config.deny.regions = nil
|
30
|
+
config.deny.stacks = nil
|
31
|
+
|
32
|
+
config.all.exclude_stacks = nil
|
33
|
+
config.all.include_stacks = nil
|
34
|
+
config.all.consider_allow_deny_stacks = true
|
35
|
+
|
25
36
|
config.auto_create_backend = true
|
37
|
+
config.autodetect = ActiveSupport::OrderedOptions.new
|
38
|
+
config.autodetect.expander = nil
|
26
39
|
config.build = ActiveSupport::OrderedOptions.new
|
27
40
|
config.build.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
|
28
41
|
config.build.cache_root = nil # defaults to /full/path/to/.terraspace-cache
|
@@ -2,13 +2,9 @@ module Terraspace
|
|
2
2
|
class Autodetect
|
3
3
|
def plugin
|
4
4
|
plugins = Terraspace::Plugin.meta.keys
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
precedence = %w[aws azurerm google]
|
9
|
-
precedence.find do |p|
|
10
|
-
plugins.include?(p)
|
11
|
-
end
|
5
|
+
precedence = %w[aws azurerm google]
|
6
|
+
precedence.find do |p|
|
7
|
+
plugins.include?(p)
|
12
8
|
end
|
13
9
|
end
|
14
10
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class Terraspace::Builder::Allow
|
2
|
+
class Base
|
3
|
+
include Terraspace::App::CallableOption::Concern
|
4
|
+
|
5
|
+
def initialize(mod)
|
6
|
+
@mod = mod # Only Region subclass uses @mod but keeping interface same for Env for simplicity
|
7
|
+
@stack_name = mod.name
|
8
|
+
end
|
9
|
+
|
10
|
+
def check!
|
11
|
+
messages = []
|
12
|
+
unless allowed?
|
13
|
+
messages << message # message is interface method
|
14
|
+
end
|
15
|
+
unless messages.empty?
|
16
|
+
puts "ERROR: The configs do not allow this.".color(:red)
|
17
|
+
puts messages
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def allowed?
|
23
|
+
if allows.nil? && denys.nil?
|
24
|
+
true
|
25
|
+
elsif denys.nil?
|
26
|
+
allows.include?(check_value)
|
27
|
+
elsif allows.nil?
|
28
|
+
!denys.include?(check_value)
|
29
|
+
else
|
30
|
+
allows.include?(check_value) && !denys.include?(check_value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def allows
|
35
|
+
callable_option(
|
36
|
+
config_name: "config.allow.#{config_name}",
|
37
|
+
config_value: config.dig(:allow, config_name),
|
38
|
+
passed_args: [@stack_name],
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def denys
|
43
|
+
callable_option(
|
44
|
+
config_name: "config.deny.#{config_name}",
|
45
|
+
config_value: config.dig(:deny, config_name),
|
46
|
+
passed_args: [@stack_name],
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def config
|
52
|
+
Terraspace.config
|
53
|
+
end
|
54
|
+
|
55
|
+
def config_name
|
56
|
+
self.class.to_s.split('::').last.underscore.pluralize.to_sym # ActiveSuport::HashWithIndifferentAccess#dig requires symbol
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Terraspace::Builder::Allow
|
2
|
+
class Env < Base
|
3
|
+
# interface method
|
4
|
+
def message
|
5
|
+
messages = []
|
6
|
+
messages << "This env is not allowed to be used: TS_ENV=#{Terraspace.env}"
|
7
|
+
messages << "Allow envs: #{allows.join(', ')}" if allows
|
8
|
+
messages << "Deny envs: #{denys.join(', ')}" if denys
|
9
|
+
messages.join("\n")
|
10
|
+
end
|
11
|
+
|
12
|
+
# interface method
|
13
|
+
def check_value
|
14
|
+
Terraspace.env
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Terraspace::Builder::Allow
|
2
|
+
class Region < Base
|
3
|
+
# interface method
|
4
|
+
def message
|
5
|
+
messages = []
|
6
|
+
word = config_name.to_s # IE: regions or locations
|
7
|
+
messages << "This #{word.singularize} is not allowed to be used: Detected current #{word.singularize}=#{current_region}"
|
8
|
+
messages << "Allow #{word}: #{allows.join(', ')}" if allows
|
9
|
+
messages << "Deny #{word}: #{denys.join(', ')}" if denys
|
10
|
+
messages.join("\n")
|
11
|
+
end
|
12
|
+
|
13
|
+
# interface method
|
14
|
+
def check_value
|
15
|
+
current_region
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_region
|
19
|
+
expander = Terraspace::Compiler::Expander.autodetect(@mod).expander
|
20
|
+
expander.region
|
21
|
+
end
|
22
|
+
|
23
|
+
def config_name
|
24
|
+
if config.allow.locations || config.deny.locations
|
25
|
+
:locations # ActiveSuport::HashWithIndifferentAccess#dig requires symbol
|
26
|
+
else
|
27
|
+
super # :regions
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Terraspace::Builder::Allow
|
2
|
+
class Stack < Base
|
3
|
+
# interface method
|
4
|
+
def message
|
5
|
+
messages = []
|
6
|
+
messages << "This stack is not allowed to be used for TS_ENV=#{Terraspace.env}"
|
7
|
+
messages << "Allow stacks: #{allows.join(', ')}" if allows
|
8
|
+
messages << "Deny stacks: #{denys.join(', ')}" if denys
|
9
|
+
messages.join("\n")
|
10
|
+
end
|
11
|
+
|
12
|
+
# interface method
|
13
|
+
def check_value
|
14
|
+
@mod.name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -5,39 +5,9 @@ class Terraspace::Builder
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def check!
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
messages << "Allowed envs: #{config.allow.envs.join(', ')}"
|
12
|
-
end
|
13
|
-
unless region_allowed?
|
14
|
-
messages << "This region is not allowed to be used: Detected current region=#{current_region}"
|
15
|
-
messages << "Allowed regions: #{config.allow.regions.join(', ')}"
|
16
|
-
end
|
17
|
-
unless messages.empty?
|
18
|
-
puts "ERROR: The configs do not allow this.".color(:red)
|
19
|
-
puts messages
|
20
|
-
exit 1
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def env_allowed?
|
25
|
-
return true unless config.allow.envs
|
26
|
-
config.allow.envs.include?(Terraspace.env)
|
27
|
-
end
|
28
|
-
|
29
|
-
def region_allowed?
|
30
|
-
return true unless config.allow.regions
|
31
|
-
config.allow.regions.include?(current_region)
|
32
|
-
end
|
33
|
-
|
34
|
-
def current_region
|
35
|
-
expander = Terraspace::Compiler::Expander.autodetect(@mod).expander
|
36
|
-
expander.region
|
37
|
-
end
|
38
|
-
|
39
|
-
def config
|
40
|
-
Terraspace.config
|
8
|
+
Env.new(@mod).check!
|
9
|
+
Stack.new(@mod).check!
|
10
|
+
Region.new(@mod).check!
|
41
11
|
end
|
42
12
|
end
|
43
13
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Terraspace::Builder
|
2
|
+
class Children
|
3
|
+
include Terraspace::Util::Logging
|
4
|
+
|
5
|
+
def initialize(mod, options={})
|
6
|
+
@mod, @options = mod, options
|
7
|
+
@queue = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def build
|
11
|
+
dependencies = Terraspace::Dependency::Registry.data
|
12
|
+
# Find out if current deploy stack contains dependency
|
13
|
+
found = dependencies.find do |parent_child|
|
14
|
+
parent, _ = parent_child.split(':')
|
15
|
+
parent == @mod.name
|
16
|
+
end
|
17
|
+
return unless found
|
18
|
+
|
19
|
+
# Go down graph children, which are the dependencies to build a queue
|
20
|
+
parent, _ = found.split(':')
|
21
|
+
node = Terraspace::Dependency::Node.find_by(name: parent)
|
22
|
+
build_queue(node)
|
23
|
+
|
24
|
+
logger.debug "Terraspace::Builder::Children @queue #{@queue}"
|
25
|
+
|
26
|
+
# Process queue in reverse order to build leaf nodes first
|
27
|
+
@queue.reverse.each do |node|
|
28
|
+
mod = Terraspace::Mod.new(node.name, @options)
|
29
|
+
Terraspace::Compiler::Perform.new(mod).compile
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Use depth first traversal to build queue
|
34
|
+
def build_queue(node)
|
35
|
+
node.children.each do |child|
|
36
|
+
@queue << child
|
37
|
+
build_queue(child)
|
38
|
+
end
|
39
|
+
@queue
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/terraspace/builder.rb
CHANGED
@@ -4,64 +4,66 @@ module Terraspace
|
|
4
4
|
include Compiler::DirsConcern
|
5
5
|
include Hooks::Concern
|
6
6
|
|
7
|
-
|
7
|
+
# @include_stacks can be 3 values: root_with_children, none, root_only
|
8
|
+
#
|
9
|
+
# none: dont build any stacks at all. used by `terraspace all up`
|
10
|
+
# root_only: only build root stack. used by `terraspace all up`
|
11
|
+
# root_with_children: build all parent stacks as well as the root stack. normal `terraspace up`
|
12
|
+
#
|
13
|
+
def initialize(options={})
|
14
|
+
super
|
15
|
+
@include_stacks = @options[:include_stacks] || :root_with_children
|
16
|
+
end
|
8
17
|
|
9
18
|
def run
|
10
19
|
return if @options[:build] == false
|
11
20
|
Terraspace::CLI::Setup::Check.check!
|
21
|
+
check_allow!
|
12
22
|
@mod.root_module = true
|
13
23
|
clean
|
24
|
+
resolve_dependencies if @include_stacks == :root_with_children
|
25
|
+
build
|
26
|
+
end
|
27
|
+
|
28
|
+
def resolve_dependencies
|
29
|
+
resolver = Terraspace::Dependency::Resolver.new(@options.merge(quiet: true))
|
30
|
+
resolver.resolve # returns batches
|
31
|
+
end
|
32
|
+
|
33
|
+
def build(modules: true)
|
14
34
|
build_dir = Util.pretty_path(@mod.cache_dir)
|
15
35
|
placeholder_stack_message
|
16
36
|
logger.info "Building #{build_dir}" unless @options[:quiet] # from terraspace all
|
17
|
-
|
18
|
-
batches = nil
|
19
37
|
FileUtils.mkdir_p(@mod.cache_dir) # so terraspace before build hooks work
|
20
38
|
run_hooks("terraspace.rb", "build") do
|
21
|
-
|
22
|
-
|
23
|
-
batches = build_batches
|
24
|
-
build_all
|
39
|
+
build_dir("modules") if modules
|
40
|
+
build_stacks
|
25
41
|
logger.info "Built in #{build_dir}" unless @options[:quiet] # from terraspace all
|
26
42
|
end
|
27
|
-
batches
|
28
43
|
end
|
29
44
|
|
30
45
|
def check_allow!
|
31
46
|
Allow.new(@mod).check!
|
32
47
|
end
|
33
48
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@graph.build
|
39
|
-
end
|
40
|
-
|
41
|
-
def build_all
|
42
|
-
# At this point dependencies have been resolved.
|
43
|
-
Terraspace::Terraform::RemoteState::Fetcher.flush!
|
44
|
-
@resolved = true
|
45
|
-
build_unresolved
|
46
|
-
end
|
47
|
-
|
48
|
-
def build_unresolved
|
49
|
-
build_dir("modules")
|
50
|
-
build_dir("stacks")
|
51
|
-
build_root_module
|
49
|
+
def build_stacks
|
50
|
+
return if @include_stacks == :none
|
51
|
+
build_children_stacks if @include_stacks == :root_with_children
|
52
|
+
Compiler::Perform.new(@mod).compile # @include_stacks :root or :root_with_children
|
52
53
|
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
# Build stacks that are part of the dependency graph. Because .terraspace-cache folders
|
56
|
+
# need to exist so `terraform state pull` works to get the state info.
|
57
|
+
def build_children_stacks
|
58
|
+
children = Children.new(@mod, @options)
|
59
|
+
children.build
|
57
60
|
end
|
58
61
|
|
59
62
|
def build_dir(type_dir)
|
60
63
|
with_each_mod(type_dir) do |mod|
|
61
|
-
mod.resolved = @resolved
|
62
64
|
is_root_module = mod.cache_dir == @mod.cache_dir
|
63
|
-
next if is_root_module # handled by
|
64
|
-
Compiler::
|
65
|
+
next if is_root_module # handled by build_stacks
|
66
|
+
Compiler::Perform.new(mod).compile
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
data/lib/terraspace/cli/all.rb
CHANGED
@@ -38,6 +38,7 @@ class Terraspace::CLI
|
|
38
38
|
|
39
39
|
desc "plan", "Run plan for all or multiple stacks."
|
40
40
|
long_desc Help.text("all/plan")
|
41
|
+
option :out, aliases: :o, desc: "Output path. Can be a pattern like :MOD_NAME.plan"
|
41
42
|
def plan(*stacks)
|
42
43
|
Terraspace::All::Runner.new("plan", @options.merge(stacks: stacks)).run
|
43
44
|
end
|
@@ -56,6 +57,7 @@ class Terraspace::CLI
|
|
56
57
|
|
57
58
|
desc "up", "Deploy all or multiple stacks."
|
58
59
|
long_desc Help.text("all/up")
|
60
|
+
option :plan, desc: "Plan path. Can be a pattern like :MOD_NAME.plan"
|
59
61
|
def up(*stacks)
|
60
62
|
Terraspace::All::Runner.new("up", @options.merge(stacks: stacks)).run
|
61
63
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# It's useful for the summary command.
|
4
4
|
module Terraspace::CLI::Build
|
5
5
|
class Placeholder
|
6
|
+
include Terraspace::Compiler::DirsConcern
|
6
7
|
include Terraspace::Util::Logging
|
7
8
|
|
8
9
|
def initialize(options={})
|
@@ -28,7 +29,8 @@ module Terraspace::CLI::Build
|
|
28
29
|
def find_stack
|
29
30
|
stack_paths = Dir.glob("{app,vendor}/stacks/*")
|
30
31
|
stack_paths.select! do |path|
|
31
|
-
|
32
|
+
stack_name = extract_stack_name(path)
|
33
|
+
select = Terraspace::Compiler::Select.new(stack_name)
|
32
34
|
select.selected?
|
33
35
|
end
|
34
36
|
mod_path = stack_paths.last
|
@@ -22,4 +22,14 @@
|
|
22
22
|
terraspace plan a1: Plan: 2 to add, 0 to change, 0 to destroy.
|
23
23
|
terraspace plan a1: Changes to Outputs:
|
24
24
|
Time took: 11s
|
25
|
-
$
|
25
|
+
$
|
26
|
+
|
27
|
+
## Using Plan Outputs
|
28
|
+
|
29
|
+
Using plan output path. You can specify an output path for the plan that contains pattern for expansion. Example:
|
30
|
+
|
31
|
+
$ terraspace all plan --out ":MOD_NAME.plan"
|
32
|
+
|
33
|
+
You can then use this later in terraspace up:
|
34
|
+
|
35
|
+
$ terraspace all up --plan ":MOD_NAME.plan"
|
@@ -25,3 +25,13 @@ Once you confirm, Terraspace deploys the batches in parallel. Essentially, Terra
|
|
25
25
|
Time took: 25s
|
26
26
|
|
27
27
|
Terraspace provides a reduced-noise summary of the runs. The full logs are also written for further inspection and debugging. The [terraspace log](https://terraspace.cloud/reference/terraspace-log/) command is useful for viewing the logs.
|
28
|
+
|
29
|
+
## Using Plans
|
30
|
+
|
31
|
+
Using plan output path. You can specify an output path for the plan that contains pattern for expansion. Example:
|
32
|
+
|
33
|
+
$ terraspace all plan --out ":MOD_NAME.plan"
|
34
|
+
|
35
|
+
You can then use this later in terraspace up:
|
36
|
+
|
37
|
+
$ terraspace all up --plan ":MOD_NAME.plan"
|