terraspace 1.0.3 → 1.1.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 +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 +15 -2
- 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.rb +11 -33
- 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 +61 -15
- data/lib/terraspace/compiler/strategy/tfvar.rb +2 -1
- data/lib/terraspace/dependency/resolver.rb +19 -0
- 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 +10 -3
- 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/terraspace.gemspec +1 -1
- metadata +13 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6c8809128dbbbf51d0f654c92784a879c88cab49d31e15e2a1d827c4b40d051
|
4
|
+
data.tar.gz: c557bd4692fddd9a1bf859a986566780cb6ccd6024dcdb3e7979138a42f1e00e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b28d7d1b8565fa0f646fda57163b6d21486db7e7f704ebe657a219335e66504206769e487cec9dc3f30da06ac793e28d81b1709ebd4c32a39a70a5d8668be05
|
7
|
+
data.tar.gz: 1a09efc8d460c9267371aca9dbb130e4dbb1c9268ea870e19d6a9734aa48e0134b3cee09aedfe894acfd2c7e956a1fed4bf7b38cad9cf9b13b935802bd2fa4a7
|
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.0] - 2022-01-30
|
7
|
+
- [#196](https://github.com/boltops-tools/terraspace/pull/196) terraspace all: build modules in batches and only each specific stack
|
8
|
+
- [#197](https://github.com/boltops-tools/terraspace/pull/197) all plan --output and all up --plan options
|
9
|
+
- simplify starter config/app.rb
|
10
|
+
|
11
|
+
## [1.0.6] - 2022-01-24
|
12
|
+
- [#195](https://github.com/boltops-tools/terraspace/pull/195) improve autodetection for plugin expander for backend like remote
|
13
|
+
|
14
|
+
## [1.0.5] - 2022-01-23
|
15
|
+
- [#194](https://github.com/boltops-tools/terraspace/pull/194) ability to allow and deny envs, regions, and stacks
|
16
|
+
|
17
|
+
## [1.0.4] - 2022-01-21
|
18
|
+
- [#193](https://github.com/boltops-tools/terraspace/pull/193) improve all include_stacks and exclude_stacks option
|
19
|
+
|
6
20
|
## [1.0.3] - 2022-01-20
|
7
21
|
- [#192](https://github.com/boltops-tools/terraspace/pull/192) run super-early boot hooks before dotenv load
|
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", quiet: true, clean: true))
|
58
|
+
builder.build(modules: true, stack: false)
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_stack(name)
|
62
|
+
builder = Terraspace::Builder.new(@options.merge(mod: name, quiet: true, clean: false))
|
63
|
+
builder.build(modules: false, stack: true)
|
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
19
|
config.all.exit_on_fail.down = true
|
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
|
data/lib/terraspace/builder.rb
CHANGED
@@ -4,64 +4,42 @@ module Terraspace
|
|
4
4
|
include Compiler::DirsConcern
|
5
5
|
include Hooks::Concern
|
6
6
|
|
7
|
-
attr_reader :graph
|
8
|
-
|
9
7
|
def run
|
10
8
|
return if @options[:build] == false
|
11
9
|
Terraspace::CLI::Setup::Check.check!
|
10
|
+
check_allow!
|
12
11
|
@mod.root_module = true
|
13
12
|
clean
|
13
|
+
build
|
14
|
+
end
|
15
|
+
|
16
|
+
def build(modules: true, stack: true)
|
14
17
|
build_dir = Util.pretty_path(@mod.cache_dir)
|
15
18
|
placeholder_stack_message
|
16
19
|
logger.info "Building #{build_dir}" unless @options[:quiet] # from terraspace all
|
17
|
-
|
18
|
-
batches = nil
|
19
20
|
FileUtils.mkdir_p(@mod.cache_dir) # so terraspace before build hooks work
|
20
21
|
run_hooks("terraspace.rb", "build") do
|
21
|
-
|
22
|
-
|
23
|
-
batches = build_batches
|
24
|
-
build_all
|
22
|
+
build_dir("modules") if modules
|
23
|
+
build_root_module if stack
|
25
24
|
logger.info "Built in #{build_dir}" unless @options[:quiet] # from terraspace all
|
26
25
|
end
|
27
|
-
batches
|
28
26
|
end
|
29
27
|
|
30
28
|
def check_allow!
|
31
29
|
Allow.new(@mod).check!
|
32
30
|
end
|
33
31
|
|
34
|
-
# Builds dependency graph and returns the batches to run
|
35
|
-
def build_batches
|
36
|
-
dependencies = Terraspace::Dependency::Registry.data # populated after build_unresolved
|
37
|
-
@graph = Terraspace::Dependency::Graph.new(stack_names, dependencies, @options)
|
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
|
52
|
-
end
|
53
|
-
|
54
32
|
def build_root_module
|
55
|
-
@mod.resolved =
|
56
|
-
Compiler::
|
33
|
+
@mod.resolved = true
|
34
|
+
Compiler::Perform.new(@mod).compile
|
57
35
|
end
|
58
36
|
|
59
37
|
def build_dir(type_dir)
|
60
38
|
with_each_mod(type_dir) do |mod|
|
61
|
-
mod.resolved =
|
39
|
+
mod.resolved = true
|
62
40
|
is_root_module = mod.cache_dir == @mod.cache_dir
|
63
41
|
next if is_root_module # handled by build_root_module
|
64
|
-
Compiler::
|
42
|
+
Compiler::Perform.new(mod).compile
|
65
43
|
end
|
66
44
|
end
|
67
45
|
|
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"
|
@@ -26,4 +26,12 @@
|
|
26
26
|
can't guarantee that exactly these actions will be performed if
|
27
27
|
"terraform apply" is subsequently run.
|
28
28
|
|
29
|
-
$
|
29
|
+
$
|
30
|
+
|
31
|
+
Using plan output path. You can specify an output path for the plan. Example:
|
32
|
+
|
33
|
+
$ terraspace plan demo --out "my.plan"
|
34
|
+
|
35
|
+
You can then use this later in terraspace up:
|
36
|
+
|
37
|
+
$ terraspace up demo --plan "my.plan"
|
@@ -27,4 +27,12 @@
|
|
27
27
|
|
28
28
|
bucket_name = bucket-trusty-marmoset
|
29
29
|
Time took: 39s
|
30
|
-
$
|
30
|
+
$
|
31
|
+
|
32
|
+
Using plan output path. You can specify an output path for the plan. Example:
|
33
|
+
|
34
|
+
$ terraspace plan demo --out "my.plan"
|
35
|
+
|
36
|
+
You can then use this later in terraspace up:
|
37
|
+
|
38
|
+
$ terraspace up demo --plan "my.plan"
|
data/lib/terraspace/cli/init.rb
CHANGED
@@ -52,7 +52,7 @@ class Terraspace::CLI
|
|
52
52
|
return if meta['Dir'] == '.' # root is already built
|
53
53
|
|
54
54
|
remote_mod = Terraspace::Mod::Remote.new(meta, @mod)
|
55
|
-
Terraspace::Compiler::
|
55
|
+
Terraspace::Compiler::Perform.new(remote_mod).build
|
56
56
|
end
|
57
57
|
|
58
58
|
def auto?
|
data/lib/terraspace/cli.rb
CHANGED
@@ -9,7 +9,7 @@ module Terraspace
|
|
9
9
|
option :yes, aliases: :y, type: :boolean, desc: "-auto-approve the terraform apply"
|
10
10
|
}
|
11
11
|
out_option = Proc.new {
|
12
|
-
option :out, aliases: :o, desc: "
|
12
|
+
option :out, aliases: :o, desc: "Output path. Can be a pattern like :MOD_NAME.plan"
|
13
13
|
}
|
14
14
|
input_option = Proc.new {
|
15
15
|
option :input, type: :boolean, desc: "Ask for input for variables if not directly set."
|
@@ -55,6 +55,7 @@ module Terraspace
|
|
55
55
|
option :quiet, type: :boolean, desc: "quiet output"
|
56
56
|
instance_option.call
|
57
57
|
yes_option.call
|
58
|
+
option :clean, type: :boolean, default: nil, desc: "Whether or not clean out .terraspace-cache folder first", hide: true
|
58
59
|
def build(mod="placeholder")
|
59
60
|
Terraspace::Builder.new(options.merge(mod: mod)).run # building any stack builds them all
|
60
61
|
end
|
@@ -190,7 +191,7 @@ module Terraspace
|
|
190
191
|
desc "show STACK", "Run show."
|
191
192
|
long_desc Help.text(:show)
|
192
193
|
instance_option.call
|
193
|
-
option :plan, desc: "path
|
194
|
+
option :plan, desc: "Plan path. Can be a pattern like :MOD_NAME.plan"
|
194
195
|
def show(mod, *args)
|
195
196
|
Commander.new("show", options.merge(mod: mod, args: args)).run
|
196
197
|
end
|
@@ -37,10 +37,15 @@ module Terraspace::Compiler
|
|
37
37
|
# path /home/ec2-user/environment/downloads/infra/app/stacks/demo
|
38
38
|
def select_stack?(type_dir, path)
|
39
39
|
return true unless type_dir == "stacks"
|
40
|
-
|
40
|
+
stack_name = extract_stack_name(path)
|
41
|
+
select = Terraspace::Compiler::Select.new(stack_name)
|
41
42
|
select.selected?
|
42
43
|
end
|
43
44
|
|
45
|
+
def extract_stack_name(path)
|
46
|
+
path.sub(%r{.*(app|vendor)/stacks/}, '')
|
47
|
+
end
|
48
|
+
|
44
49
|
def local_paths(type_dir)
|
45
50
|
dirs("app/#{type_dir}/*") + dirs("vendor/#{type_dir}/*")
|
46
51
|
end
|
@@ -3,8 +3,8 @@ module Terraspace::Compiler
|
|
3
3
|
extend Memoist
|
4
4
|
delegate :expand, :expansion, to: :expander
|
5
5
|
|
6
|
-
def initialize(mod,
|
7
|
-
@mod, @
|
6
|
+
def initialize(mod, backend=nil)
|
7
|
+
@mod, @backend = mod, backend
|
8
8
|
end
|
9
9
|
|
10
10
|
def expander
|
@@ -12,27 +12,51 @@ module Terraspace::Compiler
|
|
12
12
|
end
|
13
13
|
memoize :expander
|
14
14
|
|
15
|
+
# IE: TerraspacePluginAws::Interfaces::Expander
|
15
16
|
def expander_class
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
class_name = expander_class_name
|
18
|
+
class_name ? class_name.constantize : Terraspace::Plugin::Expander::Generic
|
19
|
+
rescue NameError => e
|
20
|
+
logger.debug "#{e.class}: #{e.message}"
|
20
21
|
Terraspace::Plugin::Expander::Generic
|
21
22
|
end
|
22
23
|
|
24
|
+
def expander_class_name
|
25
|
+
plugin = Terraspace.config.autodetect.expander # contains plugin name. IE: aws, azurerm, google
|
26
|
+
if plugin
|
27
|
+
# early return for user override of autodetection
|
28
|
+
return Terraspace::Plugin.klass("Expander", plugin: plugin) # can return nil
|
29
|
+
end
|
30
|
+
|
31
|
+
backend = @backend || parse_backend
|
32
|
+
class_name = Terraspace::Plugin.klass("Expander", backend: backend) # can return nil
|
33
|
+
unless class_name
|
34
|
+
backend = plugin_backend
|
35
|
+
class_name = Terraspace::Plugin.klass("Expander", backend: backend) # can return nil
|
36
|
+
end
|
37
|
+
class_name
|
38
|
+
end
|
39
|
+
|
40
|
+
# autodetect by parsing backend.tf or backend.rb
|
41
|
+
def parse_backend
|
42
|
+
Backend.new(@mod).detect
|
43
|
+
end
|
44
|
+
|
45
|
+
# autodetect by looking up loaded plugins
|
46
|
+
def plugin_backend
|
47
|
+
plugin = Terraspace::Autodetect.new.plugin # IE: aws, azurerm, google
|
48
|
+
if plugin
|
49
|
+
data = Terraspace::Plugin.meta[plugin]
|
50
|
+
data[:backend] # IE: s3, azurerm, gcs
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
23
54
|
class << self
|
24
55
|
extend Memoist
|
25
|
-
|
26
56
|
def autodetect(mod, opts={})
|
27
|
-
|
28
|
-
new(mod, backend)
|
57
|
+
new(mod, opts)
|
29
58
|
end
|
30
59
|
memoize :autodetect
|
31
|
-
|
32
|
-
def find_backend(mod)
|
33
|
-
Backend.new(mod).detect
|
34
|
-
end
|
35
|
-
memoize :find_backend
|
36
60
|
end
|
37
61
|
end
|
38
62
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Terraspace::Compiler
|
2
|
-
class
|
2
|
+
class Perform
|
3
3
|
include CommandsConcern
|
4
4
|
include Basename
|
5
5
|
|
@@ -7,44 +7,45 @@ module Terraspace::Compiler
|
|
7
7
|
@mod = mod
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def compile
|
11
|
+
compile_config
|
12
|
+
compile_module if @mod.resolved
|
13
|
+
compile_tfvars
|
14
14
|
end
|
15
15
|
|
16
|
-
#
|
17
|
-
def
|
18
|
-
return unless
|
19
|
-
|
16
|
+
# compile common config files: provider and backend for the root module
|
17
|
+
def compile_config
|
18
|
+
return unless compile?
|
19
|
+
compile_config_terraform
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def compile_module
|
23
23
|
with_mod_file do |src_path|
|
24
|
-
|
24
|
+
compile_mod_file(src_path)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
return unless
|
30
|
-
|
28
|
+
def compile_tfvars(write: true)
|
29
|
+
return unless compile?
|
30
|
+
return if command_is?(:seed) # avoid dependencies being built and erroring when backend bucket doesnt exist
|
31
|
+
Strategy::Tfvar.new(@mod).run(write: write) # writer within Strategy to control file ordering
|
31
32
|
end
|
32
33
|
|
33
34
|
private
|
34
|
-
def
|
35
|
+
def compile?
|
35
36
|
@mod.type == "stack" || @mod.root_module?
|
36
37
|
end
|
37
38
|
|
38
|
-
def
|
39
|
+
def compile_config_terraform
|
39
40
|
expr = "#{Terraspace.root}/config/terraform/**/*"
|
40
41
|
search(expr).each do |path|
|
41
42
|
next unless File.file?(path)
|
42
43
|
next if path.include?('config/terraform/tfvars')
|
43
|
-
|
44
|
+
compile_config_file(basename(path))
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
|
-
def
|
48
|
+
def compile_config_file(file)
|
48
49
|
existing = search("#{@mod.root}/#{file}").first
|
49
50
|
return if existing && existing.ends_with?(".tf") # do not overwrite existing backend.tf, provider.tf, etc
|
50
51
|
|
@@ -52,10 +53,10 @@ module Terraspace::Compiler
|
|
52
53
|
src_path = search("#{@mod.root}/#{basename(file)}").first # existing source. IE: backend.rb in module folder
|
53
54
|
end
|
54
55
|
src_path ||= search("#{Terraspace.root}/config/terraform/#{file}").first
|
55
|
-
|
56
|
+
compile_mod_file(src_path) if src_path
|
56
57
|
end
|
57
58
|
|
58
|
-
def
|
59
|
+
def compile_mod_file(src_path)
|
59
60
|
content = Strategy::Mod.new(@mod, src_path).run
|
60
61
|
Writer.new(@mod, src_path: src_path).write(content)
|
61
62
|
end
|
@@ -1,28 +1,74 @@
|
|
1
1
|
module Terraspace::Compiler
|
2
2
|
class Select
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
include Terraspace::App::CallableOption::Concern
|
4
|
+
include Terraspace::Util::Logging
|
5
|
+
|
6
|
+
def initialize(stack_name)
|
7
|
+
@stack_name = stack_name
|
6
8
|
end
|
7
9
|
|
8
10
|
def selected?
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
if all.include_stacks.nil?
|
17
|
-
!ignore_stacks.include?(@stack_name)
|
11
|
+
ignore_stacks_deprecation_warning
|
12
|
+
if include_stacks.nil? && exclude_stacks.nil?
|
13
|
+
true
|
14
|
+
elsif include_stacks.nil?
|
15
|
+
!exclude_stacks.include?(@stack_name)
|
16
|
+
elsif exclude_stacks.nil?
|
17
|
+
include_stacks.include?(@stack_name)
|
18
18
|
else
|
19
|
-
stacks = include_stacks -
|
19
|
+
stacks = include_stacks - exclude_stacks
|
20
20
|
stacks.include?(@stack_name)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
|
24
|
+
def include_stacks
|
25
|
+
if config.all.include_stacks
|
26
|
+
config_name = "config.all.include_stacks"
|
27
|
+
config_value = config.dig(:all, :include_stacks)
|
28
|
+
elsif config.all.consider_allow_deny_stacks
|
29
|
+
config_name = "config.allow.stacks"
|
30
|
+
config_value = config.dig(:allow, :stacks)
|
31
|
+
else
|
32
|
+
return
|
33
|
+
end
|
34
|
+
callable_option(
|
35
|
+
config_name: config_name,
|
36
|
+
config_value: config_value,
|
37
|
+
passed_args: [@stack_name],
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def exclude_stacks
|
42
|
+
if config.all.exclude_stacks
|
43
|
+
config_name = "config.all.exclude_stacks"
|
44
|
+
config_value = config.dig(:all, :exclude_stacks)
|
45
|
+
elsif config.all.consider_allow_deny_stacks
|
46
|
+
config_name = "config.deny.stacks"
|
47
|
+
config_value = config.dig(:deny, :stacks)
|
48
|
+
else
|
49
|
+
return
|
50
|
+
end
|
51
|
+
callable_option(
|
52
|
+
config_name: config_name,
|
53
|
+
config_value: config_value,
|
54
|
+
passed_args: [@stack_name],
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def config
|
60
|
+
Terraspace.config
|
61
|
+
end
|
62
|
+
|
63
|
+
@@ignore_stacks_deprecation_warning = nil
|
64
|
+
def ignore_stacks_deprecation_warning
|
65
|
+
return unless config.all.ignore_stacks
|
66
|
+
return if @@ignore_stacks_deprecation_warning
|
67
|
+
puts <<~EOL.color(:yellow)
|
68
|
+
DEPRECATED: config.all.ignore_stacks
|
69
|
+
Instead use: config.all.exclude_stacks
|
70
|
+
EOL
|
71
|
+
@@ignore_stacks_deprecation_warning = true
|
26
72
|
end
|
27
73
|
end
|
28
74
|
end
|
@@ -5,7 +5,7 @@ module Terraspace::Compiler::Strategy
|
|
5
5
|
@order = 0
|
6
6
|
end
|
7
7
|
|
8
|
-
def run
|
8
|
+
def run(write: true)
|
9
9
|
layer_paths.each do |layer_path|
|
10
10
|
ext = File.extname(layer_path).sub('.','')
|
11
11
|
klass = strategy_class(ext)
|
@@ -14,6 +14,7 @@ module Terraspace::Compiler::Strategy
|
|
14
14
|
strategy = klass.new(@mod, layer_path)
|
15
15
|
content = strategy.run
|
16
16
|
|
17
|
+
next unless write
|
17
18
|
dest_name = ordered_name(layer_path)
|
18
19
|
writer = Terraspace::Compiler::Writer.new(@mod, dest_name: dest_name)
|
19
20
|
writer.write(content)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Terraspace::Dependency
|
2
|
+
class Resolver
|
3
|
+
include Terraspace::Compiler::DirsConcern
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def resolve
|
10
|
+
with_each_mod("stacks") do |mod|
|
11
|
+
Terraspace::Compiler::Perform.new(mod).compile_tfvars(write: false)
|
12
|
+
end
|
13
|
+
|
14
|
+
dependencies = Terraspace::Dependency::Registry.data # populated dependencies resolved
|
15
|
+
@graph = Terraspace::Dependency::Graph.new(stack_names, dependencies, @options)
|
16
|
+
@graph.build # Returns batches to run
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Terraspace::Terraform::Args
|
2
|
+
class Expand
|
3
|
+
class << self
|
4
|
+
def option_method(*names)
|
5
|
+
names.compact.each do |name|
|
6
|
+
option_method_each(name)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def option_method_each(name)
|
11
|
+
define_method name do
|
12
|
+
return unless @options[name]
|
13
|
+
expander = Terraspace::Compiler::Expander.autodetect(@mod)
|
14
|
+
expander.expansion(@options[name]) # pattern is a String that contains placeholders for substitutions
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(mod, options={})
|
20
|
+
@mod, @options = mod, options
|
21
|
+
end
|
22
|
+
|
23
|
+
option_method :plan, :out
|
24
|
+
end
|
25
|
+
end
|
@@ -2,6 +2,8 @@ require "tempfile"
|
|
2
2
|
|
3
3
|
module Terraspace::Terraform::Args
|
4
4
|
class Thor
|
5
|
+
extend Memoist
|
6
|
+
|
5
7
|
def initialize(mod, name, options={})
|
6
8
|
@mod, @name, @options = mod, name.underscore, options
|
7
9
|
@quiet = @options[:quiet].nil? ? true : @options[:quiet]
|
@@ -48,7 +50,7 @@ module Terraspace::Terraform::Args
|
|
48
50
|
args << input_option
|
49
51
|
|
50
52
|
# must be at the end
|
51
|
-
plan =
|
53
|
+
plan = expand.plan
|
52
54
|
if plan
|
53
55
|
copy_to_cache(plan)
|
54
56
|
args << " #{plan}"
|
@@ -81,7 +83,7 @@ module Terraspace::Terraform::Args
|
|
81
83
|
|
82
84
|
def output_args
|
83
85
|
args = []
|
84
|
-
args << "> #{
|
86
|
+
args << "> #{expand.out}" if expand.out
|
85
87
|
args
|
86
88
|
end
|
87
89
|
|
@@ -89,26 +91,22 @@ module Terraspace::Terraform::Args
|
|
89
91
|
args = []
|
90
92
|
args << input_option
|
91
93
|
args << "-destroy" if @options[:destroy]
|
92
|
-
args << "-out #{
|
93
|
-
# Note: based on the
|
94
|
+
args << "-out #{expand.out}" if expand.out
|
95
|
+
# Note: based on the expand.out will run an internal hook to copy plan
|
94
96
|
# file back up to the root project folder for use. Think this is convenient and expected behavior.
|
95
97
|
args
|
96
98
|
end
|
97
99
|
|
98
100
|
def show_args
|
99
101
|
args = []
|
100
|
-
plan =
|
102
|
+
plan = expand.plan
|
101
103
|
if plan
|
102
|
-
copy_to_cache(
|
103
|
-
args << " #{
|
104
|
+
copy_to_cache(expand.plan)
|
105
|
+
args << " #{expand.plan}" # terraform show /path/to/plan
|
104
106
|
end
|
105
107
|
args
|
106
108
|
end
|
107
109
|
|
108
|
-
def expanded_out
|
109
|
-
@options[:out]
|
110
|
-
end
|
111
|
-
|
112
110
|
def destroy_args
|
113
111
|
auto_approve_arg
|
114
112
|
end
|
@@ -147,5 +145,10 @@ module Terraspace::Terraform::Args
|
|
147
145
|
FileUtils.mkdir_p(File.dirname(dest))
|
148
146
|
FileUtils.cp(src, dest) unless same_file?(src, dest)
|
149
147
|
end
|
148
|
+
|
149
|
+
def expand
|
150
|
+
Terraspace::Terraform::Args::Expand.new(@mod, @options)
|
151
|
+
end
|
152
|
+
memoize :expand
|
150
153
|
end
|
151
154
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Terraspace::Terraform::Ihooks::After
|
2
2
|
class Plan < Terraspace::Terraform::Ihooks::Base
|
3
3
|
def run
|
4
|
-
return if
|
5
|
-
copy_to_root(
|
4
|
+
return if !out_option || @options[:copy_to_root] == false
|
5
|
+
copy_to_root(out_option)
|
6
6
|
end
|
7
7
|
|
8
8
|
def copy_to_root(file)
|
@@ -1,12 +1,10 @@
|
|
1
1
|
module Terraspace::Terraform::Ihooks::Before
|
2
2
|
class Plan < Terraspace::Terraform::Ihooks::Base
|
3
3
|
def run
|
4
|
-
|
5
|
-
return
|
6
|
-
return if out =~ %r{^/} # not need to create parent dir for copy with absolute path
|
4
|
+
return unless out_option
|
5
|
+
return if out_option =~ %r{^/} # not need to create parent dir for copy with absolute path
|
7
6
|
|
8
|
-
|
9
|
-
name = out.sub("#{Terraspace.root}/",'')
|
7
|
+
name = out_option.sub("#{Terraspace.root}/",'')
|
10
8
|
dest = "#{@mod.cache_dir}/#{name}"
|
11
9
|
FileUtils.mkdir_p(File.dirname(dest))
|
12
10
|
end
|
@@ -2,6 +2,7 @@ module Terraspace::Terraform::RemoteState
|
|
2
2
|
class Fetcher
|
3
3
|
extend Memoist
|
4
4
|
include Terraspace::Compiler::CommandsConcern
|
5
|
+
include Terraspace::Compiler::DirsConcern
|
5
6
|
include Terraspace::Util::Logging
|
6
7
|
|
7
8
|
def initialize(parent, identifier, options={})
|
@@ -130,9 +131,15 @@ module Terraspace::Terraform::RemoteState
|
|
130
131
|
|
131
132
|
# Note we already validate mod exist at the terraform_output helper. This is just in case that logic changes.
|
132
133
|
def validate!
|
133
|
-
|
134
|
-
|
135
|
-
|
134
|
+
unless @child.exist?
|
135
|
+
logger.error "ERROR: stack #{@child.name} not found".color(:red)
|
136
|
+
exit 1
|
137
|
+
end
|
138
|
+
select = Terraspace::Compiler::Select.new(@child.name)
|
139
|
+
unless select.selected?
|
140
|
+
logger.error "ERROR: stack #{@child.name} is configured to not be included. IE: config.all.include_stacks or config.all.exclude_stacks".color(:red)
|
141
|
+
exit 1
|
142
|
+
end
|
136
143
|
end
|
137
144
|
|
138
145
|
# Using debug level because all the tfvar files always get evaluated.
|
@@ -25,7 +25,7 @@ module Terraspace::Terraform::RemoteState::Marker
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def warning
|
28
|
-
logger.warn "WARN: The #{@child_name} stack does not exist".color(:yellow)
|
28
|
+
logger.warn "WARN: The #{@child_name} stack does not exist or is configured to be not included. IE: config.all.include_stacks or config.all.exclude_stacks".color(:yellow)
|
29
29
|
caller_line = caller.find { |l| l.include?('.tfvars') }
|
30
30
|
return unless caller_line # specs dont have a tfvars file
|
31
31
|
source_code = PrettyTracer.new(caller_line).source_code
|
data/lib/terraspace/version.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
describe Terraspace::All::Runner do
|
2
2
|
let(:runner) do
|
3
3
|
runner = described_class.new(command: "up", yes: true)
|
4
|
+
allow(runner).to receive(:build_modules)
|
4
5
|
allow(runner).to receive(:build_batches).and_return(batches)
|
5
6
|
allow(runner).to receive(:preview)
|
6
7
|
# Just test to the point of the run_builder and deploy_batch
|
data/terraspace.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Tung Nguyen"]
|
10
10
|
spec.email = ["tung@boltops.com"]
|
11
11
|
spec.summary = "Terraspace: The Terraspace Framework"
|
12
|
-
spec.homepage = "https://
|
12
|
+
spec.homepage = "https://terraspace.cloud"
|
13
13
|
spec.license = "Apache-2.0"
|
14
14
|
|
15
15
|
spec.files = File.directory?('.git') ? `git ls-files`.split($/) : Dir.glob("**/*")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terraspace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tung Nguyen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-01-
|
11
|
+
date: 2022-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -478,12 +478,18 @@ files:
|
|
478
478
|
- lib/terraspace/all/runner.rb
|
479
479
|
- lib/terraspace/all/summary.rb
|
480
480
|
- lib/terraspace/app.rb
|
481
|
+
- lib/terraspace/app/callable_option.rb
|
482
|
+
- lib/terraspace/app/callable_option/concern.rb
|
481
483
|
- lib/terraspace/app/inits.rb
|
482
484
|
- lib/terraspace/autodetect.rb
|
483
485
|
- lib/terraspace/autoloader.rb
|
484
486
|
- lib/terraspace/booter.rb
|
485
487
|
- lib/terraspace/builder.rb
|
486
488
|
- lib/terraspace/builder/allow.rb
|
489
|
+
- lib/terraspace/builder/allow/base.rb
|
490
|
+
- lib/terraspace/builder/allow/env.rb
|
491
|
+
- lib/terraspace/builder/allow/region.rb
|
492
|
+
- lib/terraspace/builder/allow/stack.rb
|
487
493
|
- lib/terraspace/bundle.rb
|
488
494
|
- lib/terraspace/cli.rb
|
489
495
|
- lib/terraspace/cli/all.rb
|
@@ -596,8 +602,6 @@ files:
|
|
596
602
|
- lib/terraspace/cli/up.rb
|
597
603
|
- lib/terraspace/command.rb
|
598
604
|
- lib/terraspace/compiler/basename.rb
|
599
|
-
- lib/terraspace/compiler/builder.rb
|
600
|
-
- lib/terraspace/compiler/builder/skip.rb
|
601
605
|
- lib/terraspace/compiler/cleaner.rb
|
602
606
|
- lib/terraspace/compiler/cleaner/backend_change.rb
|
603
607
|
- lib/terraspace/compiler/commands_concern.rb
|
@@ -627,6 +631,8 @@ files:
|
|
627
631
|
- lib/terraspace/compiler/expander.rb
|
628
632
|
- lib/terraspace/compiler/expander/backend.rb
|
629
633
|
- lib/terraspace/compiler/helper_extender.rb
|
634
|
+
- lib/terraspace/compiler/perform.rb
|
635
|
+
- lib/terraspace/compiler/perform/skip.rb
|
630
636
|
- lib/terraspace/compiler/select.rb
|
631
637
|
- lib/terraspace/compiler/strategy/abstract_base.rb
|
632
638
|
- lib/terraspace/compiler/strategy/mod.rb
|
@@ -649,6 +655,7 @@ files:
|
|
649
655
|
- lib/terraspace/dependency/helper/output.rb
|
650
656
|
- lib/terraspace/dependency/node.rb
|
651
657
|
- lib/terraspace/dependency/registry.rb
|
658
|
+
- lib/terraspace/dependency/resolver.rb
|
652
659
|
- lib/terraspace/dotenv.rb
|
653
660
|
- lib/terraspace/ext.rb
|
654
661
|
- lib/terraspace/ext/bundler.rb
|
@@ -697,6 +704,7 @@ files:
|
|
697
704
|
- lib/terraspace/terraform/api/workspace.rb
|
698
705
|
- lib/terraspace/terraform/args/custom.rb
|
699
706
|
- lib/terraspace/terraform/args/dsl.rb
|
707
|
+
- lib/terraspace/terraform/args/expand.rb
|
700
708
|
- lib/terraspace/terraform/args/pass.rb
|
701
709
|
- lib/terraspace/terraform/args/shorthands.rb
|
702
710
|
- lib/terraspace/terraform/args/thor.rb
|
@@ -858,7 +866,7 @@ files:
|
|
858
866
|
- spec/terraspace/terraform/remote_state/marker/output_spec.rb
|
859
867
|
- spec/terraspace/terraform/remote_state/output_proxy_spec.rb
|
860
868
|
- terraspace.gemspec
|
861
|
-
homepage: https://
|
869
|
+
homepage: https://terraspace.cloud
|
862
870
|
licenses:
|
863
871
|
- Apache-2.0
|
864
872
|
metadata: {}
|