Skip to content

Commit

Permalink
support non-cloud providers and backends
Browse files Browse the repository at this point in the history
* decouple backend detection from plugins
* expander backend detection that doesn't evaluate ERB
* adjust default max retries for backend re-init to 1
  • Loading branch information
tongueroo committed Dec 27, 2021
1 parent c511389 commit 4a90761
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 21 deletions.
1 change: 1 addition & 0 deletions lib/terraspace/compiler/backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def create
klass = backend_interface(backend_name)
return unless klass # in case auto-creation is not supported for specific backend

# IE: TerraspacePluginAws::Interfaces::Backend.new
interface = klass.new(backend_info)
interface.call
end
Expand Down
30 changes: 11 additions & 19 deletions lib/terraspace/compiler/expander.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
module Terraspace::Compiler
class Expander
extend Memoist
delegate :expand, :expansion, to: :expander

attr_reader :expander
def initialize(mod, name)
@mod, @name = mod, name
@expander = expander_class.new(@mod)
end

def expander
expander_class.new(@mod)
end
memoize :expander

def expander_class
# IE: TerraspacePluginAws::Interfaces::Expander
klass_name = Terraspace::Plugin.klass("Expander", backend: @name)
klass_name.constantize if klass_name
klass_name ? klass_name.constantize : Terraspace::Plugin::Expander::Generic
rescue NameError
Terraspace::Plugin::Expander::Generic
end
Expand All @@ -20,27 +24,15 @@ class << self
extend Memoist

def autodetect(mod, opts={})
backend = opts[:backend]
unless backend
plugin = find_plugin
backend = plugin[:backend]
end
backend = opts[:backend] || find_backend(mod)
new(mod, backend)
end
memoize :autodetect

def find_plugin
plugins = Terraspace::Plugin.meta
if plugins.size == 1
plugins.first[1]
else
precedence = %w[aws azurerm google]
plugin = precedence.find do |provider|
plugins[provider]
end
plugins[plugin]
end
def find_backend(mod)
Backend.new(mod).detect
end
memoize :find_backend
end
end
end
43 changes: 43 additions & 0 deletions lib/terraspace/compiler/expander/backend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Simpler than Terraspace::Compiler::Backend::Parser because
# Terraspace::Compiler::Expander autodetect backend super early on.
# It's so early that don't want helper methods like <%= expansion(...) %> to be called.
# Calling the expansion helper itself results in Terraspace autodetecting a concrete
# Terraspace Plugin Expander, which creates an infinite loop.
# This simple detection class avoids calling ERB and avoids the infinite loop.
class Terraspace::Compiler::Expander
class Backend
extend Memoist

def initialize(mod)
@mod = mod
end

COMMENT = /^\s+#/
# Works for both backend.rb DSL and backend.tf ERB
def detect
lines = IO.readlines(src_path)
backend_line = lines.find { |l| l.include?("backend") && l !~ COMMENT }
md = backend_line.match(/['"](.*)['"]/)
md[1] if md
end

private
# Use original unrendered source as wont know the
# @mod.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
# Until the concrete Terraspace Plugin Expander has been autodetected.
# Follow same precedence rules as rest of Terraspace.
def src_path
exprs = [
"app/stacks/#{@mod.build_dir}/backend.*",
"app/modules/#{@mod.build_dir}/backend.*",
"vendor/stacks/#{@mod.build_dir}/backend.*",
"vendor/modules/#{@mod.build_dir}/backend.*",
"config/terraform/backend.*",
]
path = nil
exprs.find { |expr| path = Dir.glob(expr).first }
path
end
memoize :src_path
end
end
13 changes: 12 additions & 1 deletion lib/terraspace/plugin/expander/interface.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ def expand_string?(string)
#
def strip(string)
string.sub(/^-+/,'').sub(/-+$/,'') # remove leading and trailing -
.sub(%r{/+$},'') # only remove trailing / or else /home/ec2-user => home/ec2-user
.sub(%r{/+$},'') # only remove trailing / or else /home/ec2-user => home/ec2-user
.sub(/:\/\//, 'TMP_KEEP_HTTP') # so we can keep ://. IE: https:// or http://
.gsub(%r{/+},'/') # remove double slashes are more. IE: // -> / Useful of region is '' in generic expander
.sub('TMP_KEEP_HTTP', '://') # restore :// IE: https:// or http://
end

def var_value(name)
Expand Down Expand Up @@ -102,5 +105,13 @@ def instance
def cache_root
Terraspace.cache_root
end

# So default config works:
# config.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
# For when folks configure it with the http backend for non-cloud providers
# The double slash // will be replace with a single slash in expander/interface.rb
def region
''
end
end
end
2 changes: 1 addition & 1 deletion lib/terraspace/terraform/runner/retryer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def initialize(mod, options, command_name, exception)
end

def retry?
max_retries = ENV['TS_MAX_RETRIES'] ? ENV['TS_MAX_RETRIES'].to_i : 3
max_retries = ENV['TS_MAX_RETRIES'] ? ENV['TS_MAX_RETRIES'].to_i : 1
if @retries <= max_retries && !@stop_retrying
true # will retry
else
Expand Down

0 comments on commit 4a90761

Please sign in to comment.