terraspace 0.6.23 → 1.0.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/.cody/README.md +2 -0
- data/.cody/azurerm/bin/az/configure.sh +5 -1
- data/.cody/azurerm/project.rb +4 -0
- data/.cody/azurerm/role.rb +0 -1
- data/.cody/google/bin/gcloud/configure.sh +2 -1
- data/.cody/google/project.rb +4 -0
- data/.cody/google/role.rb +0 -1
- data/.cody/none/bin/build.sh +15 -0
- data/.cody/none/buildspec.yml +10 -0
- data/.cody/none/project.rb +2 -0
- data/.cody/none/role.rb +4 -0
- data/.cody/shared/script/install/terraform.sh +14 -6
- data/.cody/unit/buildspec.yml +1 -0
- data/.pipedream/pipeline.rb +1 -0
- data/CHANGELOG.md +63 -0
- data/Gemfile +6 -0
- data/README.md +8 -4
- data/lib/templates/examples/hcl/module/main.tf +3 -0
- data/lib/templates/examples/hcl/module/outputs.tf +4 -0
- data/lib/templates/examples/hcl/module/variables.tf +5 -0
- data/lib/templates/examples/hcl/stack/main.tf +4 -0
- data/lib/templates/examples/hcl/stack/outputs.tf +4 -0
- data/lib/templates/examples/hcl/stack/variables.tf +5 -0
- data/lib/templates/examples/ruby/module/main.rb +3 -0
- data/lib/templates/examples/ruby/module/outputs.rb +4 -0
- data/lib/templates/examples/ruby/module/variables.rb +5 -0
- data/lib/templates/examples/ruby/stack/main.rb +4 -0
- data/lib/templates/examples/ruby/stack/outputs.rb +4 -0
- data/lib/templates/examples/ruby/stack/variables.rb +5 -0
- data/lib/templates/hcl/project/config/terraform/backend.tf.tt +5 -13
- data/lib/templates/hcl/project/config/terraform/provider.tf +4 -14
- data/lib/terraspace/autodetect.rb +15 -0
- data/lib/terraspace/autoloader.rb +6 -1
- data/lib/terraspace/builder.rb +1 -9
- data/lib/terraspace/bundle.rb +54 -0
- data/lib/terraspace/cli/concern.rb +113 -0
- data/lib/terraspace/cli/help/new/example.md +7 -1
- data/lib/terraspace/cli/help.rb +7 -8
- data/lib/terraspace/cli/new/example.rb +36 -0
- data/lib/terraspace/cli/new/helpers/plugin_gem.rb +2 -14
- data/lib/terraspace/cli/new/helpers.rb +1 -1
- data/lib/terraspace/cli/new/module.rb +1 -1
- data/lib/terraspace/cli/new/plugin/helper.rb +1 -1
- data/lib/terraspace/cli/new/plugin.rb +1 -1
- data/lib/terraspace/cli/new/project.rb +11 -17
- data/lib/terraspace/cli/new/sequence.rb +1 -1
- data/lib/terraspace/cli/new/source/core.rb +7 -6
- data/lib/terraspace/cli/new/source/plugin.rb +2 -2
- data/lib/terraspace/cli/new/stack.rb +3 -2
- data/lib/terraspace/cli/new/test.rb +12 -2
- data/lib/terraspace/cli/new.rb +4 -0
- data/lib/terraspace/cli/{check_setup.rb → setup/check.rb} +5 -3
- data/lib/terraspace/cli/setup.rb +9 -0
- data/lib/terraspace/cli/tfc_concern.rb +1 -1
- data/lib/terraspace/cli.rb +34 -27
- data/lib/terraspace/command.rb +3 -2
- data/lib/terraspace/compiler/commands_concern.rb +0 -8
- data/lib/terraspace/compiler/expander/backend.rb +44 -0
- data/lib/terraspace/compiler/expander.rb +11 -19
- data/lib/terraspace/core.rb +10 -0
- data/lib/terraspace/plugin/expander/friendly.rb +1 -0
- data/lib/terraspace/plugin/expander/interface.rb +19 -4
- data/lib/terraspace/terraform/api/client.rb +1 -1
- data/lib/terraspace/terraform/args/custom.rb +11 -6
- data/lib/terraspace/terraform/args/pass.rb +110 -0
- data/lib/terraspace/terraform/args/{default.rb → thor.rb} +1 -3
- data/lib/terraspace/{compiler → terraform/runner}/backend/parser.rb +1 -1
- data/lib/terraspace/{compiler → terraform/runner}/backend.rb +14 -1
- data/lib/terraspace/terraform/runner/retryer.rb +1 -1
- data/lib/terraspace/terraform/runner.rb +25 -15
- data/lib/terraspace/terraform/tfc/sync.rb +1 -1
- data/lib/terraspace/version.rb +1 -1
- data/spec/terraspace/terraform/args/custom_spec.rb +4 -4
- data/spec/terraspace/terraform/args/pass_spec.rb +101 -0
- data/terraspace.gemspec +2 -4
- metadata +46 -50
data/lib/terraspace/cli/help.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
class Terraspace::CLI
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
IO.read(path) if File.exist?(path)
|
8
|
-
end
|
2
|
+
module Help
|
3
|
+
def text(namespaced_command)
|
4
|
+
path = namespaced_command.to_s.gsub(':','/')
|
5
|
+
path = File.expand_path("../help/#{path}.md", __FILE__)
|
6
|
+
IO.read(path) if File.exist?(path)
|
9
7
|
end
|
8
|
+
extend self
|
10
9
|
end
|
11
|
-
end
|
10
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Terraspace::CLI::New
|
2
|
+
class Example < Thor::Group
|
3
|
+
include Thor::Actions
|
4
|
+
|
5
|
+
# only stack name is configurable
|
6
|
+
argument :name, default: "demo"
|
7
|
+
|
8
|
+
def self.options
|
9
|
+
# default is nil for autodetection
|
10
|
+
[
|
11
|
+
[:force, aliases: %w[f], type: :boolean, desc: "Force overwrite"],
|
12
|
+
[:lang, default: "hcl", desc: "Language to use: HCL/ERB or Ruby DSL"],
|
13
|
+
[:plugin, aliases: %w[p], default: nil, type: :string],
|
14
|
+
]
|
15
|
+
end
|
16
|
+
options.each { |args| class_option(*args) }
|
17
|
+
|
18
|
+
def create
|
19
|
+
Module.start(["example", "--examples"] + cli_args)
|
20
|
+
Stack.start([name, "--examples"] + cli_args)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def cli_args
|
25
|
+
plugin = @options[:plugin] || Terraspace::Autodetect.new.plugin
|
26
|
+
args = if plugin
|
27
|
+
['--plugin', plugin]
|
28
|
+
else
|
29
|
+
['--plugin', 'none'] # override default of aws
|
30
|
+
end
|
31
|
+
args << "--force" if @options[:force]
|
32
|
+
args += ["--lang", @options[:lang]] if @options[:lang]
|
33
|
+
args
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -5,20 +5,8 @@ module Terraspace::CLI::New::Helpers
|
|
5
5
|
if @options[:plugin_gem]
|
6
6
|
@options[:plugin_gem]
|
7
7
|
else
|
8
|
-
plugin = @options[:plugin] ||
|
9
|
-
"terraspace_plugin_#{plugin}"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def autodetect_provider
|
14
|
-
providers = Terraspace::Plugin.meta.keys
|
15
|
-
if providers.size == 1
|
16
|
-
providers.first
|
17
|
-
else
|
18
|
-
precedence = %w[aws azurerm google]
|
19
|
-
precedence.find do |p|
|
20
|
-
providers.include?(p)
|
21
|
-
end
|
8
|
+
plugin = @options[:plugin] || Terraspace::Autodetect.new.plugin
|
9
|
+
"terraspace_plugin_#{plugin}" if plugin and plugin != "none"
|
22
10
|
end
|
23
11
|
end
|
24
12
|
end
|
@@ -5,7 +5,7 @@ class Terraspace::CLI::New
|
|
5
5
|
argument :name
|
6
6
|
|
7
7
|
def create_module
|
8
|
-
puts "=> Creating
|
8
|
+
puts "=> Creating new module called #{name}"
|
9
9
|
plugin_template_source(@options[:lang], "module") # IE: plugin_template_source("hcl", "module")
|
10
10
|
dest = "app/modules/#{name}"
|
11
11
|
dest = "#{@options[:project_name]}/#{dest}" if @options[:project_name]
|
@@ -6,7 +6,6 @@ class Terraspace::CLI::New
|
|
6
6
|
[:config, type: :boolean, default: true, desc: "Whether or not to generate config files."],
|
7
7
|
[:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files."],
|
8
8
|
[:quiet, type: :boolean, desc: "Quiet output."],
|
9
|
-
[:test_structure, type: :boolean, desc: "Create project bootstrap test structure."],
|
10
9
|
]
|
11
10
|
end
|
12
11
|
|
@@ -20,7 +19,7 @@ class Terraspace::CLI::New
|
|
20
19
|
|
21
20
|
public
|
22
21
|
def creating_messaging
|
23
|
-
log "=> Creating new project called #{name}
|
22
|
+
log "=> Creating new project called #{name}"
|
24
23
|
end
|
25
24
|
|
26
25
|
def create_base
|
@@ -28,6 +27,16 @@ class Terraspace::CLI::New
|
|
28
27
|
directory ".", "#{name}"
|
29
28
|
end
|
30
29
|
|
30
|
+
def bundle_install
|
31
|
+
return if @options[:bundle] == false
|
32
|
+
log "=> Installing dependencies with: bundle install"
|
33
|
+
Bundler.with_unbundled_env do
|
34
|
+
bundle = "BUNDLE_IGNORE_CONFIG=1 bundle install"
|
35
|
+
bundle << " > /dev/null 2>&1" if @options[:quiet]
|
36
|
+
system(bundle, chdir: name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
31
40
|
# Will generate config folder from
|
32
41
|
#
|
33
42
|
# 1. terraspace code lang templates or
|
@@ -60,21 +69,6 @@ class Terraspace::CLI::New
|
|
60
69
|
Stack.start(component_args("demo", name))
|
61
70
|
end
|
62
71
|
|
63
|
-
def create_test
|
64
|
-
return unless @options[:test_structure]
|
65
|
-
Test::Bootstrap.start(["--dir", name])
|
66
|
-
end
|
67
|
-
|
68
|
-
def bundle_install
|
69
|
-
return if @options[:bundle] == false
|
70
|
-
log "=> Installing dependencies with: bundle install"
|
71
|
-
Bundler.with_unbundled_env do
|
72
|
-
bundle = "BUNDLE_IGNORE_CONFIG=1 bundle install"
|
73
|
-
bundle << " > /dev/null 2>&1" if @options[:quiet]
|
74
|
-
system(bundle, chdir: name)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
72
|
def welcome_message_examples
|
79
73
|
return unless options[:examples]
|
80
74
|
log <<~EOL
|
@@ -9,7 +9,8 @@ module Terraspace::CLI::New::Source
|
|
9
9
|
|
10
10
|
def set_core_source(template, type=nil)
|
11
11
|
template_name = template_name(template, type)
|
12
|
-
|
12
|
+
folder = @options[:examples] && type != "project" ? "examples/#{template_name}" : template_name
|
13
|
+
template_path = File.expand_path("../../../../templates/#{folder}", __dir__)
|
13
14
|
override_source_paths(template_path)
|
14
15
|
end
|
15
16
|
|
@@ -18,11 +19,14 @@ module Terraspace::CLI::New::Source
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def require_gem(name)
|
22
|
+
return unless name # can be passed in name=nil with rspec test harness
|
21
23
|
begin
|
24
|
+
# Need to clear gem paths since installing plugins like terraspace_plugin_aws as part of terraspace new project
|
25
|
+
Gem.clear_paths
|
22
26
|
require name # require plugin for the templates, this registers the plugin
|
23
27
|
rescue LoadError => e
|
24
28
|
puts "#{e.class}: #{e.message}".color(:red)
|
25
|
-
logger.error "ERROR: Unable to require plugin #{name}
|
29
|
+
logger.error "ERROR: Unable to require plugin #{name}".color(:red)
|
26
30
|
puts "Are you sure you the plugin exists and you specified the right plugin option."
|
27
31
|
puts "You specified --plugin #{@options[:plugin]}"
|
28
32
|
exit 1
|
@@ -32,10 +36,7 @@ module Terraspace::CLI::New::Source
|
|
32
36
|
def set_plugin_gem_source(template, type)
|
33
37
|
require_gem(plugin_gem_name)
|
34
38
|
plugin = Terraspace::Plugin.find_with(plugin: @options[:plugin])
|
35
|
-
unless plugin
|
36
|
-
puts "ERROR: Unable to a find plugin for #{@options[:plugin]}. Are you sure the gem for the plugin is correct?".color(:red)
|
37
|
-
exit 1
|
38
|
-
end
|
39
|
+
return unless plugin # can be passed in name=nil with rspec test harness
|
39
40
|
template_name = template_name(template, type)
|
40
41
|
template_path = File.expand_path("#{plugin.root}/lib/templates/#{template_name}")
|
41
42
|
override_source_paths(template_path)
|
@@ -9,12 +9,12 @@ module Terraspace::CLI::New::Source
|
|
9
9
|
# project always uses the examples from the provider gem for configs
|
10
10
|
# base always uses terraspace core templates
|
11
11
|
# examples option always use examples from provider gems
|
12
|
-
if (type == "project" || @options[:examples]) && template != "base"
|
12
|
+
if (type == "project" || @options[:examples]) && template != "base" &&
|
13
|
+
(@options[:plugin] != "none" && !@options[:plugin].nil?)
|
13
14
|
set_plugin_gem_source(template, type) # provider gems has examples
|
14
15
|
else
|
15
16
|
set_core_source(template, type) # terraspace core has empty starter files
|
16
17
|
end
|
17
18
|
end
|
18
|
-
|
19
19
|
end
|
20
20
|
end
|
@@ -2,10 +2,11 @@ class Terraspace::CLI::New
|
|
2
2
|
class Stack < Sequence
|
3
3
|
component_options.each { |args| class_option(*args) }
|
4
4
|
|
5
|
-
|
5
|
+
# default so terraspace new example works without a Thor warning
|
6
|
+
argument :name, default: "demo"
|
6
7
|
|
7
8
|
def create_stack
|
8
|
-
puts "=> Creating new stack called #{name}
|
9
|
+
puts "=> Creating new stack called #{name}"
|
9
10
|
plugin_template_source(@options[:lang], "stack") # IE: plugin_template_source("hcl", "stack")
|
10
11
|
dest = "app/stacks/#{name}"
|
11
12
|
dest = "#{@options[:project_name]}/#{dest}" if @options[:project_name]
|
@@ -3,13 +3,13 @@ class Terraspace::CLI::New
|
|
3
3
|
include Thor::Actions
|
4
4
|
include Terraspace::CLI::New::Helpers
|
5
5
|
|
6
|
-
argument :name
|
6
|
+
argument :name, required: false
|
7
7
|
|
8
8
|
def self.options
|
9
9
|
[
|
10
10
|
[:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
11
11
|
[:test_name, desc: "Test name. Defaults to the project, module or stack name"],
|
12
|
-
[:type, default: "
|
12
|
+
[:type, default: "stack", desc: "project, stack or module"],
|
13
13
|
]
|
14
14
|
end
|
15
15
|
options.each { |args| class_option(*args) }
|
@@ -42,9 +42,19 @@ class Terraspace::CLI::New
|
|
42
42
|
public
|
43
43
|
|
44
44
|
def create
|
45
|
+
if type != 'project' && name.nil?
|
46
|
+
puts "ERROR: require NAME for type stack and module".color(:red)
|
47
|
+
exit 1
|
48
|
+
end
|
45
49
|
test_template_source(@options[:lang], type)
|
46
50
|
puts "=> Creating #{type} test: #{name}"
|
47
51
|
directory ".", dest
|
48
52
|
end
|
53
|
+
|
54
|
+
# Used in ERB template
|
55
|
+
# rspec-terraspace/lib/templates/stack/test/spec/fixtures/config/terraform/provider.tf.tt
|
56
|
+
def autodetect_provider
|
57
|
+
Terraspace::Autodetect.new.plugin
|
58
|
+
end
|
49
59
|
end
|
50
60
|
end
|
data/lib/terraspace/cli/new.rb
CHANGED
@@ -42,5 +42,9 @@ class Terraspace::CLI
|
|
42
42
|
long_desc Help.text("new/test")
|
43
43
|
Test.options.each { |args| option(*args) }
|
44
44
|
register(Test, "test", "test NAME", "Generates new test.")
|
45
|
+
|
46
|
+
long_desc Help.text("new/example")
|
47
|
+
Example.options.each { |args| option(*args) }
|
48
|
+
register(Example, "example", "example [NAME]", "Generates new example.")
|
45
49
|
end
|
46
50
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
class Terraspace::CLI
|
2
|
-
class
|
1
|
+
class Terraspace::CLI::Setup
|
2
|
+
class Check
|
3
3
|
extend Memoist
|
4
4
|
|
5
5
|
# Terraspace requires at least this version of terraform
|
@@ -83,7 +83,9 @@ class Terraspace::CLI
|
|
83
83
|
#
|
84
84
|
# Note: The -json option is only available in v0.13+
|
85
85
|
def terraform_version_message
|
86
|
-
`terraform --version
|
86
|
+
out = `terraform --version`
|
87
|
+
version = out.split("\n").find { |l| l =~ /^Terraform / }
|
88
|
+
version.strip if version
|
87
89
|
end
|
88
90
|
memoize :terraform_version_message
|
89
91
|
|
data/lib/terraspace/cli.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
module Terraspace
|
2
2
|
class CLI < Command
|
3
|
+
include Concern
|
4
|
+
|
3
5
|
class_option :verbose, type: :boolean
|
4
6
|
class_option :noop, type: :boolean
|
5
7
|
|
6
8
|
yes_option = Proc.new {
|
7
9
|
option :yes, aliases: :y, type: :boolean, desc: "-auto-approve the terraform apply"
|
8
10
|
}
|
9
|
-
format_option = Proc.new {
|
10
|
-
option :format, desc: "output formats: json, text"
|
11
|
-
}
|
12
11
|
out_option = Proc.new {
|
13
12
|
option :out, aliases: :o, desc: "Write the output to path"
|
14
13
|
}
|
@@ -43,6 +42,10 @@ module Terraspace
|
|
43
42
|
long_desc Help.text(:new)
|
44
43
|
subcommand "new", New
|
45
44
|
|
45
|
+
desc "setup SUBCOMMAND", "setup subcommands"
|
46
|
+
long_desc Help.text(:setup)
|
47
|
+
subcommand "setup", Setup
|
48
|
+
|
46
49
|
desc "tfc SUBCOMMAND", "tfc subcommands"
|
47
50
|
long_desc Help.text(:tfc)
|
48
51
|
subcommand "tfc", Tfc
|
@@ -62,17 +65,23 @@ module Terraspace
|
|
62
65
|
Bundle.new(options.merge(args: args)).run
|
63
66
|
end
|
64
67
|
|
65
|
-
desc "check_setup", "Check setup."
|
68
|
+
desc "check_setup", "Check setup.", hide: true
|
66
69
|
long_desc Help.text(:check_setup)
|
67
70
|
def check_setup
|
68
|
-
|
71
|
+
puts <<~EOL
|
72
|
+
DEPRECATED: The terraspace check_setup command is deprecated. Instead use:
|
73
|
+
|
74
|
+
terraspace setup check
|
75
|
+
|
76
|
+
EOL
|
77
|
+
Setup::Check.new(options).run
|
69
78
|
end
|
70
79
|
|
71
80
|
desc "console STACK", "Run console in built terraform project."
|
72
81
|
long_desc Help.text(:console)
|
73
82
|
instance_option.call
|
74
|
-
def console(mod)
|
75
|
-
Commander.new("console", options.merge(mod: mod, shell: "system")).run
|
83
|
+
def console(mod, *args)
|
84
|
+
Commander.new("console", options.merge(mod: mod, args: args, shell: "system")).run
|
76
85
|
end
|
77
86
|
|
78
87
|
desc "down STACK", "Destroy infrastructure stack."
|
@@ -81,8 +90,8 @@ module Terraspace
|
|
81
90
|
yes_option.call
|
82
91
|
reconfigure_option.call
|
83
92
|
option :destroy_workspace, type: :boolean, desc: "Also destroy the Cloud workspace. Only applies when using Terraform Cloud remote backend."
|
84
|
-
def down(mod)
|
85
|
-
Down.new(options.merge(mod: mod)).run
|
93
|
+
def down(mod, *args)
|
94
|
+
Down.new(options.merge(mod: mod, args: args)).run
|
86
95
|
end
|
87
96
|
|
88
97
|
desc "force_unlock", "Calls terrform force-unlock"
|
@@ -111,8 +120,8 @@ module Terraspace
|
|
111
120
|
desc "init STACK", "Run init in built terraform project."
|
112
121
|
long_desc Help.text(:init)
|
113
122
|
instance_option.call
|
114
|
-
def init(mod)
|
115
|
-
Commander.new("init", options.merge(mod: mod, quiet: false)).run
|
123
|
+
def init(mod, *args)
|
124
|
+
Commander.new("init", options.merge(mod: mod, args: args, quiet: false)).run
|
116
125
|
end
|
117
126
|
|
118
127
|
desc "list", "List stacks and modules."
|
@@ -141,22 +150,22 @@ module Terraspace
|
|
141
150
|
out_option.call
|
142
151
|
reconfigure_option.call
|
143
152
|
option :copy_to_root, type: :boolean, default: true, desc: "Copy plan file generated in the cache folder back to project root"
|
144
|
-
def plan(mod)
|
145
|
-
Commander.new("plan", options.merge(mod: mod)).run
|
153
|
+
def plan(mod, *args)
|
154
|
+
Commander.new("plan", options.merge(mod: mod, args: args)).run
|
146
155
|
end
|
147
156
|
|
148
157
|
desc "providers STACK", "Show providers."
|
149
158
|
long_desc Help.text(:providers)
|
150
159
|
instance_option.call
|
151
|
-
def providers(mod)
|
152
|
-
Commander.new("providers", options.merge(mod: mod)).run
|
160
|
+
def providers(mod, *args)
|
161
|
+
Commander.new("providers", options.merge(mod: mod, args: args)).run
|
153
162
|
end
|
154
163
|
|
155
164
|
desc "refresh STACK", "Run refresh."
|
156
165
|
long_desc Help.text(:refresh)
|
157
166
|
instance_option.call
|
158
|
-
def refresh(mod)
|
159
|
-
Commander.new("refresh", options.merge(mod: mod)).run
|
167
|
+
def refresh(mod, *args)
|
168
|
+
Commander.new("refresh", options.merge(mod: mod, args: args)).run
|
160
169
|
end
|
161
170
|
|
162
171
|
desc "seed STACK", "Build starer seed tfvars file."
|
@@ -182,9 +191,8 @@ module Terraspace
|
|
182
191
|
long_desc Help.text(:show)
|
183
192
|
instance_option.call
|
184
193
|
option :plan, desc: "path to created.plan"
|
185
|
-
|
186
|
-
|
187
|
-
Commander.new("show", options.merge(mod: mod)).run
|
194
|
+
def show(mod, *args)
|
195
|
+
Commander.new("show", options.merge(mod: mod, args: args)).run
|
188
196
|
end
|
189
197
|
|
190
198
|
desc "state SUBCOMMAND STACK", "Run state."
|
@@ -201,11 +209,10 @@ module Terraspace
|
|
201
209
|
|
202
210
|
desc "output STACK", "Run output."
|
203
211
|
long_desc Help.text(:output)
|
204
|
-
format_option.call
|
205
212
|
instance_option.call
|
206
213
|
out_option.call
|
207
|
-
def output(mod)
|
208
|
-
Commander.new("output", options.merge(mod: mod)).run
|
214
|
+
def output(mod, *args)
|
215
|
+
Commander.new("output", options.merge(mod: mod, args: args)).run
|
209
216
|
end
|
210
217
|
|
211
218
|
desc "up STACK", "Deploy infrastructure stack."
|
@@ -218,15 +225,15 @@ module Terraspace
|
|
218
225
|
reconfigure_option.call
|
219
226
|
option :plan, desc: "Execution plan that can be used to only execute a pre-determined set of actions."
|
220
227
|
option :var_files, type: :array, desc: "list of var files"
|
221
|
-
def up(mod)
|
222
|
-
Up.new(options.merge(mod: mod)).run
|
228
|
+
def up(mod, *args)
|
229
|
+
Up.new(options.merge(mod: mod, args: args)).run
|
223
230
|
end
|
224
231
|
|
225
232
|
desc "validate STACK", "Validate stack."
|
226
233
|
long_desc Help.text(:validate)
|
227
234
|
instance_option.call
|
228
|
-
def validate(mod)
|
229
|
-
Commander.new("validate", options.merge(mod: mod)).run
|
235
|
+
def validate(mod, *args)
|
236
|
+
Commander.new("validate", options.merge(mod: mod, args: args)).run
|
230
237
|
end
|
231
238
|
|
232
239
|
desc "completion *PARAMS", "Prints words for auto-completion."
|
data/lib/terraspace/command.rb
CHANGED
@@ -71,7 +71,7 @@ module Terraspace
|
|
71
71
|
version_manager = "rvm" if rvm?
|
72
72
|
version_manager = "rbenv" if rbenv?
|
73
73
|
if rbenv? || rvm?
|
74
|
-
puts <<~EOL.color(:yellow)
|
74
|
+
$stderr.puts <<~EOL.color(:yellow)
|
75
75
|
WARN: It looks like a standalone Terraspace install and #{version_manager} is also in use.
|
76
76
|
Different gems from the standalone Terraspace install and #{version_manager} can cause all kinds of trouble.
|
77
77
|
Please install Terraspace as a gem instead and remove the standalone Terraspace /opt/terraspace installation.
|
@@ -102,8 +102,9 @@ module Terraspace
|
|
102
102
|
return if subcommand?
|
103
103
|
return if command_name.nil?
|
104
104
|
return if help_flags.include?(Terraspace.argv.last) # IE: -h help
|
105
|
-
return if %w[-h -v check_setup completion completion_script help new test version].include?(command_name)
|
105
|
+
return if %w[-h -v --version check_setup completion completion_script help new setup test version].include?(command_name)
|
106
106
|
return if File.exist?("#{Terraspace.root}/config/app.rb")
|
107
|
+
return unless Terraspace.check_project
|
107
108
|
logger.error "ERROR: It doesnt look like this is a terraspace project. Are you sure you are in a terraspace project?".color(:red)
|
108
109
|
ENV['TS_TEST'] ? raise : exit(1)
|
109
110
|
end
|
@@ -1,13 +1,5 @@
|
|
1
1
|
module Terraspace::Compiler
|
2
2
|
module CommandsConcern
|
3
|
-
def requires_backend?
|
4
|
-
command_is?(requires_backend_commands)
|
5
|
-
end
|
6
|
-
|
7
|
-
def requires_backend_commands
|
8
|
-
%w[down init output plan providers refresh show up validate]
|
9
|
-
end
|
10
|
-
|
11
3
|
def command_is?(*commands)
|
12
4
|
commands.flatten!
|
13
5
|
commands.map!(&:to_s)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Simpler than Terraspace::Terraform::Runner::Backend::Parser because
|
2
|
+
# Terraspace::Compiler::Expander autodetect backend super early on.
|
3
|
+
# It's so early that don't want helper methods like <%= expansion(...) %> to be called.
|
4
|
+
# Calling the expansion helper itself results in Terraspace autodetecting a concrete
|
5
|
+
# Terraspace Plugin Expander, which creates an infinite loop.
|
6
|
+
# This simple detection class avoids calling ERB and avoids the infinite loop.
|
7
|
+
class Terraspace::Compiler::Expander
|
8
|
+
class Backend
|
9
|
+
extend Memoist
|
10
|
+
|
11
|
+
def initialize(mod)
|
12
|
+
@mod = mod
|
13
|
+
end
|
14
|
+
|
15
|
+
COMMENT = /^\s+#/
|
16
|
+
# Works for both backend.rb DSL and backend.tf ERB
|
17
|
+
def detect
|
18
|
+
return nil unless src_path # no backend file. returning nil means a local backend
|
19
|
+
lines = IO.readlines(src_path)
|
20
|
+
backend_line = lines.find { |l| l.include?("backend") && l !~ COMMENT }
|
21
|
+
md = backend_line.match(/['"](.*)['"]/)
|
22
|
+
md[1] if md
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
# Use original unrendered source as wont know the
|
27
|
+
# @mod.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
|
28
|
+
# Until the concrete Terraspace Plugin Expander has been autodetected.
|
29
|
+
# Follow same precedence rules as rest of Terraspace.
|
30
|
+
def src_path
|
31
|
+
exprs = [
|
32
|
+
"app/stacks/#{@mod.build_dir}/backend.*",
|
33
|
+
"app/modules/#{@mod.build_dir}/backend.*",
|
34
|
+
"vendor/stacks/#{@mod.build_dir}/backend.*",
|
35
|
+
"vendor/modules/#{@mod.build_dir}/backend.*",
|
36
|
+
"config/terraform/backend.*",
|
37
|
+
]
|
38
|
+
path = nil
|
39
|
+
exprs.find { |expr| path = Dir.glob(expr).first }
|
40
|
+
path
|
41
|
+
end
|
42
|
+
memoize :src_path
|
43
|
+
end
|
44
|
+
end
|
@@ -1,17 +1,21 @@
|
|
1
1
|
module Terraspace::Compiler
|
2
2
|
class Expander
|
3
|
+
extend Memoist
|
3
4
|
delegate :expand, :expansion, to: :expander
|
4
5
|
|
5
|
-
attr_reader :expander
|
6
6
|
def initialize(mod, name)
|
7
7
|
@mod, @name = mod, name
|
8
|
-
@expander = expander_class.new(@mod)
|
9
8
|
end
|
10
9
|
|
10
|
+
def expander
|
11
|
+
expander_class.new(@mod)
|
12
|
+
end
|
13
|
+
memoize :expander
|
14
|
+
|
11
15
|
def expander_class
|
12
16
|
# IE: TerraspacePluginAws::Interfaces::Expander
|
13
17
|
klass_name = Terraspace::Plugin.klass("Expander", backend: @name)
|
14
|
-
klass_name.constantize
|
18
|
+
klass_name ? klass_name.constantize : Terraspace::Plugin::Expander::Generic
|
15
19
|
rescue NameError
|
16
20
|
Terraspace::Plugin::Expander::Generic
|
17
21
|
end
|
@@ -20,27 +24,15 @@ module Terraspace::Compiler
|
|
20
24
|
extend Memoist
|
21
25
|
|
22
26
|
def autodetect(mod, opts={})
|
23
|
-
backend = opts[:backend]
|
24
|
-
unless backend
|
25
|
-
plugin = find_plugin
|
26
|
-
backend = plugin[:backend]
|
27
|
-
end
|
27
|
+
backend = opts[:backend] || find_backend(mod)
|
28
28
|
new(mod, backend)
|
29
29
|
end
|
30
30
|
memoize :autodetect
|
31
31
|
|
32
|
-
def
|
33
|
-
|
34
|
-
if plugins.size == 1
|
35
|
-
plugins.first[1]
|
36
|
-
else
|
37
|
-
precedence = %w[aws azurerm google]
|
38
|
-
plugin = precedence.find do |provider|
|
39
|
-
plugins[provider]
|
40
|
-
end
|
41
|
-
plugins[plugin]
|
42
|
-
end
|
32
|
+
def find_backend(mod)
|
33
|
+
Backend.new(mod).detect
|
43
34
|
end
|
35
|
+
memoize :find_backend
|
44
36
|
end
|
45
37
|
end
|
46
38
|
end
|
data/lib/terraspace/core.rb
CHANGED