terraspace 0.2.1 → 0.3.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 +31 -0
- data/README.md +34 -13
- data/lib/templates/base/git_hook/hook.sh +1 -1
- data/lib/templates/base/project/.gitignore +1 -0
- data/lib/templates/base/project/README.md +17 -0
- data/lib/terraspace.rb +4 -0
- data/lib/terraspace/all/base.rb +8 -0
- data/lib/terraspace/all/grapher.rb +129 -0
- data/lib/terraspace/all/preview.rb +43 -0
- data/lib/terraspace/all/runner.rb +169 -0
- data/lib/terraspace/all/summary.rb +99 -0
- data/lib/terraspace/app.rb +31 -8
- data/lib/terraspace/booter.rb +9 -0
- data/lib/terraspace/builder.rb +65 -20
- data/lib/terraspace/cli.rb +39 -12
- data/lib/terraspace/cli/all.rb +63 -0
- data/lib/terraspace/cli/build/placeholder.rb +2 -5
- data/lib/terraspace/cli/bundle.rb +1 -1
- data/lib/terraspace/cli/check_setup.rb +17 -5
- data/lib/terraspace/cli/cloud.rb +19 -3
- data/lib/terraspace/cli/cloud/runs.rb +24 -0
- data/lib/terraspace/cli/commander.rb +1 -8
- data/lib/terraspace/cli/down.rb +20 -0
- data/lib/terraspace/cli/help/cloud/runs/list.md +36 -0
- data/lib/terraspace/cli/help/cloud/runs/prune.md +25 -0
- data/lib/terraspace/cli/help/cloud/sync.md +19 -0
- data/lib/terraspace/cli/help/log.md +42 -0
- data/lib/terraspace/cli/init.rb +35 -7
- data/lib/terraspace/cli/list.rb +14 -1
- data/lib/terraspace/cli/log.rb +112 -0
- data/lib/terraspace/cli/log/concern.rb +24 -0
- data/lib/terraspace/cli/logs.rb +15 -0
- data/lib/terraspace/cli/logs/tasks.rb +32 -0
- data/lib/terraspace/cli/new/git_hook.rb +1 -1
- data/lib/terraspace/cli/tfc_concern.rb +14 -0
- data/lib/terraspace/cli/up.rb +32 -0
- data/lib/terraspace/compiler/builder.rb +3 -3
- data/lib/terraspace/compiler/cleaner.rb +1 -1
- data/lib/terraspace/compiler/cleaner/backend_change.rb +21 -7
- data/lib/terraspace/compiler/dirs_concern.rb +47 -0
- data/lib/terraspace/compiler/dsl/syntax/helpers/common.rb +26 -1
- data/lib/terraspace/core.rb +11 -2
- data/lib/terraspace/dependency/graph.rb +139 -0
- data/lib/terraspace/dependency/node.rb +38 -0
- data/lib/terraspace/dependency/registry.rb +11 -0
- data/lib/terraspace/logger.rb +6 -18
- data/lib/terraspace/logger/formatter.rb +13 -0
- data/lib/terraspace/mod.rb +7 -1
- data/lib/terraspace/seeder/where.rb +6 -2
- data/lib/terraspace/shell.rb +79 -0
- data/lib/terraspace/terraform/api.rb +7 -40
- data/lib/terraspace/terraform/api/base.rb +7 -0
- data/lib/terraspace/terraform/api/client.rb +23 -3
- data/lib/terraspace/terraform/api/http.rb +14 -34
- data/lib/terraspace/terraform/api/http/concern.rb +10 -0
- data/lib/terraspace/terraform/api/runs.rb +28 -0
- data/lib/terraspace/terraform/api/token.rb +65 -0
- data/lib/terraspace/terraform/api/var.rb +20 -6
- data/lib/terraspace/terraform/api/vars.rb +2 -1
- data/lib/terraspace/terraform/api/workspace.rb +98 -0
- data/lib/terraspace/terraform/args/default.rb +48 -21
- data/lib/terraspace/terraform/cloud/runs.rb +13 -0
- data/lib/terraspace/terraform/cloud/runs/base.rb +33 -0
- data/lib/terraspace/terraform/cloud/runs/item_presenter.rb +37 -0
- data/lib/terraspace/terraform/cloud/runs/lister.rb +22 -0
- data/lib/terraspace/terraform/cloud/runs/pruner.rb +109 -0
- data/lib/terraspace/terraform/cloud/sync.rb +41 -0
- data/lib/terraspace/terraform/cloud/syncer.rb +52 -0
- data/lib/terraspace/terraform/cloud/workspace.rb +10 -21
- data/lib/terraspace/terraform/hooks/builder.rb +1 -1
- data/lib/terraspace/terraform/remote_state/fetcher.rb +122 -0
- data/lib/terraspace/terraform/remote_state/marker/output.rb +39 -0
- data/lib/terraspace/terraform/remote_state/marker/pretty_tracer.rb +37 -0
- data/lib/terraspace/terraform/remote_state/output_proxy.rb +29 -0
- data/lib/terraspace/terraform/runner.rb +24 -14
- data/lib/terraspace/util.rb +1 -5
- data/lib/terraspace/util/pretty.rb +18 -0
- data/lib/terraspace/version.rb +1 -1
- data/spec/fixtures/fetcher/c1.json +37 -0
- data/spec/fixtures/parser/cache_dirs/all/01-test.auto.tfvars +5 -0
- data/spec/fixtures/parser/cache_dirs/depends_on/01-test.auto.tfvars +2 -0
- data/spec/fixtures/parser/cache_dirs/output/01-test.auto.tfvars +2 -0
- data/spec/fixtures/summary/down.log +12 -0
- data/spec/fixtures/summary/output.log +5 -0
- data/spec/fixtures/summary/plan/error.log +20 -0
- data/spec/fixtures/summary/plan/success.log +17 -0
- data/spec/fixtures/summary/show.log +22 -0
- data/spec/fixtures/summary/up/error.log +13 -0
- data/spec/fixtures/summary/up/success.log +63 -0
- data/spec/fixtures/summary/validate/error.log +13 -0
- data/spec/fixtures/summary/validate/success.log +5 -0
- data/spec/terraspace/all/grapher_spec.rb +38 -0
- data/spec/terraspace/all/runner_spec.rb +48 -0
- data/spec/terraspace/all/summary_spec.rb +93 -0
- data/spec/terraspace/dependency/graph_spec.rb +162 -0
- data/spec/terraspace/seeder_spec.rb +0 -1
- data/spec/terraspace/terraform/remote_state/fetcher_spec.rb +52 -0
- data/terraspace.gemspec +5 -1
- metadata +137 -5
- data/lib/terraspace/terraform/cloud.rb +0 -25
- data/lib/terraspace/util/sh.rb +0 -19
@@ -0,0 +1,41 @@
|
|
1
|
+
module Terraspace::Terraform::Cloud
|
2
|
+
class Sync < Terraspace::CLI::Base
|
3
|
+
extend Memoist
|
4
|
+
include Terraspace::Terraform::Api::Client
|
5
|
+
|
6
|
+
# Note about why workspace.create is called:
|
7
|
+
#
|
8
|
+
# CLI::Init#run
|
9
|
+
# init => runs `terraform init`
|
10
|
+
# build_remote_dependencies
|
11
|
+
# sync_cloud => leads to create_workspace
|
12
|
+
#
|
13
|
+
# The `terraform init` will auto-create the TFC workspace
|
14
|
+
# If there is a .terraform folder the config.init.mode == "auto" though,
|
15
|
+
# then the workspace won't be created.
|
16
|
+
# So we check and create the workspace if necessary.
|
17
|
+
def run
|
18
|
+
# Note: workspace still gets created by `terraform init` However, variables wont be sync if returns early
|
19
|
+
return unless Terraspace.config.cloud.auto_sync || @options[:override_auto_sync]
|
20
|
+
return unless workspaces_backend?
|
21
|
+
logger.info "Syncing to Terraform Cloud: #{@mod.name} => #{workspace_name}"
|
22
|
+
@api = Terraspace::Terraform::Api.new(@mod, remote)
|
23
|
+
workspace.create_or_update
|
24
|
+
workspace.set_working_dir
|
25
|
+
workspace.set_env_vars
|
26
|
+
end
|
27
|
+
|
28
|
+
def workspace
|
29
|
+
@api.workspace
|
30
|
+
end
|
31
|
+
|
32
|
+
def workspaces_backend?
|
33
|
+
remote && remote['workspaces']
|
34
|
+
end
|
35
|
+
|
36
|
+
# already memoized in Api::Client
|
37
|
+
def backend
|
38
|
+
Terraspace::Compiler::Backend::Parser.new(@mod).result
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Terraspace::Terraform::Cloud
|
2
|
+
class Syncer < Terraspace::CLI::Base
|
3
|
+
extend Memoist
|
4
|
+
include Terraspace::Compiler::DirsConcern
|
5
|
+
include Terraspace::Util::Sure
|
6
|
+
|
7
|
+
def run
|
8
|
+
are_you_sure?
|
9
|
+
mods.each do |mod|
|
10
|
+
run_sync(mod)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def mods
|
15
|
+
mod = @options[:mod]
|
16
|
+
mod ? [mod] : stack_names
|
17
|
+
end
|
18
|
+
|
19
|
+
def run_sync(mod)
|
20
|
+
sync(mod).run
|
21
|
+
end
|
22
|
+
|
23
|
+
def sync(mod)
|
24
|
+
Sync.new(@options.merge(mod: mod))
|
25
|
+
end
|
26
|
+
memoize :sync
|
27
|
+
|
28
|
+
def are_you_sure?
|
29
|
+
message =<<~EOL
|
30
|
+
About to sync these project stacks with Terraform Cloud workspaces:
|
31
|
+
|
32
|
+
Stack => Workspace
|
33
|
+
EOL
|
34
|
+
|
35
|
+
mods.each do |mod|
|
36
|
+
sync = sync(mod)
|
37
|
+
message << " #{mod} => #{sync.workspace_name}\n"
|
38
|
+
end
|
39
|
+
message << <<~EOL
|
40
|
+
|
41
|
+
A sync does the following for each workspace:
|
42
|
+
|
43
|
+
1. Create or update workspace, including the VCS settings.
|
44
|
+
2. Set the working dir.
|
45
|
+
3. Set env and terraform variables.
|
46
|
+
|
47
|
+
Are you sure?
|
48
|
+
EOL
|
49
|
+
sure?(message.chop)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,8 +1,9 @@
|
|
1
|
-
|
1
|
+
module Terraspace::Terraform::Cloud
|
2
2
|
class Workspace < Terraspace::CLI::Base
|
3
3
|
extend Memoist
|
4
4
|
include Terraspace::Util::Logging
|
5
5
|
include Terraspace::Terraform::Api::Client
|
6
|
+
include Terraspace::Terraform::Api::Http::Concern
|
6
7
|
|
7
8
|
# List will not have @mod set.
|
8
9
|
def list
|
@@ -32,10 +33,15 @@ class Terraspace::Terraform::Cloud
|
|
32
33
|
Terraspace::CLI::Init.new(@options.merge(calling_command: "cloud-setup")).run
|
33
34
|
end
|
34
35
|
|
36
|
+
def create
|
37
|
+
build
|
38
|
+
return unless api
|
39
|
+
api.workspace.create
|
40
|
+
end
|
41
|
+
|
35
42
|
def destroy
|
36
43
|
build
|
37
|
-
return unless
|
38
|
-
api = Terraspace::Terraform::Api.new(@mod, remote)
|
44
|
+
return unless api
|
39
45
|
workspace = api.workspace(exit_on_fail: false)
|
40
46
|
unless workspace
|
41
47
|
logger.info "Workspace #{workspace_name} not found for #{@mod.type}: #{@mod.name}"
|
@@ -43,25 +49,8 @@ class Terraspace::Terraform::Cloud
|
|
43
49
|
end
|
44
50
|
sure?
|
45
51
|
logger.info "Destroying workspace #{workspace_name}"
|
46
|
-
api.
|
47
|
-
end
|
48
|
-
|
49
|
-
def build
|
50
|
-
Terraspace::Builder.new(@options).run
|
51
|
-
end
|
52
|
-
|
53
|
-
def workspace_name
|
54
|
-
remote['workspaces']['name']
|
55
|
-
end
|
56
|
-
|
57
|
-
def remote
|
58
|
-
backend["remote"]
|
59
|
-
end
|
60
|
-
|
61
|
-
def backend
|
62
|
-
Terraspace::Compiler::Backend::Parser.new(@mod).result
|
52
|
+
api.workspace.destroy
|
63
53
|
end
|
64
|
-
memoize :backend
|
65
54
|
|
66
55
|
def sure?
|
67
56
|
message = <<~EOL.chop + " " # chop to remove newline
|
@@ -34,7 +34,7 @@ module Terraspace::Terraform::Hooks
|
|
34
34
|
exit_on_fail = exit_on_fail.nil? ? true : exit_on_fail
|
35
35
|
|
36
36
|
logger.info "Running #{type} hook"
|
37
|
-
|
37
|
+
Terraspace::Shell.new(@mod, execute, exit_on_fail: exit_on_fail).run
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Terraspace::Terraform::RemoteState
|
2
|
+
class Fetcher
|
3
|
+
extend Memoist
|
4
|
+
include Terraspace::Util::Logging
|
5
|
+
|
6
|
+
def initialize(parent, identifier, options={})
|
7
|
+
@parent, @identifier, @options = parent, identifier, options
|
8
|
+
child_name, @output_key = identifier.split('.')
|
9
|
+
@child = Terraspace::Mod.new(child_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
validate!
|
14
|
+
pull
|
15
|
+
load
|
16
|
+
end
|
17
|
+
|
18
|
+
def output
|
19
|
+
run
|
20
|
+
if pull_success?
|
21
|
+
value = output_value
|
22
|
+
error = output_error(:key_not_found) unless @outputs.key?(@output_key)
|
23
|
+
OutputProxy.new(value, @options.merge(error: error))
|
24
|
+
else
|
25
|
+
error = output_error(:state_not_found)
|
26
|
+
OutputProxy.new(nil, @options.merge(error: error))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def output_value
|
31
|
+
return unless @outputs.key?(@output_key)
|
32
|
+
result = @outputs.dig(@output_key)
|
33
|
+
result.dig("value") if result
|
34
|
+
end
|
35
|
+
|
36
|
+
def output_error(type)
|
37
|
+
msg = case type
|
38
|
+
when :key_not_found
|
39
|
+
"Output #{@output_key} was not found for the #{@parent.name} tfvars file. Either #{@child.name} stack has not been deployed yet or it does not have this output: #{@output_key}"
|
40
|
+
when :state_not_found
|
41
|
+
"Output #{@output_key} could not be looked up for the #{@parent.name} tfvars file. #{@child.name} stack needs to be deployed"
|
42
|
+
end
|
43
|
+
msg = "(#{msg})"
|
44
|
+
log_message(msg)
|
45
|
+
msg
|
46
|
+
end
|
47
|
+
|
48
|
+
@@pull_successes = {}
|
49
|
+
@@download_shown = false
|
50
|
+
def pull
|
51
|
+
return if @@pull_successes[cache_key]
|
52
|
+
logger.info "Downloading tfstate files for dependencies defined in tfvars..." unless @@download_shown || @options[:quiet]
|
53
|
+
@@download_shown = true
|
54
|
+
logger.debug "Downloading tfstate for stack: #{@child.name}"
|
55
|
+
Terraspace::CLI::Init.new(mod: @child.name, calling_command: "apply", quiet: true).init # init not run, so only init
|
56
|
+
FileUtils.mkdir_p(File.dirname(state_path))
|
57
|
+
command = "cd #{@child.cache_dir} && terraform state pull > #{state_path}"
|
58
|
+
logger.debug "=> #{command}"
|
59
|
+
success = system(command)
|
60
|
+
# Can error if using a old terraform version and the statefile was created with a newer version of terraform
|
61
|
+
# IE: Failed to refresh state: state snapshot was created by Terraform v0.13.2, which is newer than current v0.12.29;
|
62
|
+
# upgrade to Terraform v0.13.2 or greater to work with this state
|
63
|
+
unless success
|
64
|
+
logger.info "Error running: #{command}".color(:red)
|
65
|
+
logger.info "Please fix the error before continuing"
|
66
|
+
end
|
67
|
+
@@pull_successes[cache_key] = success
|
68
|
+
end
|
69
|
+
|
70
|
+
def load
|
71
|
+
return self unless pull_success?
|
72
|
+
|
73
|
+
# use or set cache
|
74
|
+
if @@cache[cache_key]
|
75
|
+
@outputs = @@cache[cache_key]
|
76
|
+
else
|
77
|
+
@outputs = @@cache[cache_key] = read_statefile_outputs
|
78
|
+
end
|
79
|
+
|
80
|
+
self
|
81
|
+
end
|
82
|
+
memoize :load
|
83
|
+
|
84
|
+
def cache_key
|
85
|
+
@child.name
|
86
|
+
end
|
87
|
+
|
88
|
+
def read_statefile_outputs
|
89
|
+
data = JSON.load(IO.read(state_path))
|
90
|
+
data ? data['outputs'] : {}
|
91
|
+
end
|
92
|
+
|
93
|
+
def pull_success?
|
94
|
+
@@pull_successes[cache_key]
|
95
|
+
end
|
96
|
+
|
97
|
+
def state_path
|
98
|
+
"#{Terraspace.tmp_root}/remote_state/#{@child.build_dir}/state.json"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Note we already validate mod exist at the terraform_output helper. This is just in case that logic changes.
|
102
|
+
def validate!
|
103
|
+
return if @child.exist?
|
104
|
+
logger.error "ERROR: stack #{@child.name} not found".color(:red)
|
105
|
+
exit 1
|
106
|
+
end
|
107
|
+
|
108
|
+
# Using debug level because all the tfvar files always get evaluated.
|
109
|
+
# So dont want these messages to show up and be noisy unless debugging.
|
110
|
+
def log_message(msg)
|
111
|
+
logger.debug "DEBUG: #{msg}".color(:yellow)
|
112
|
+
end
|
113
|
+
|
114
|
+
cattr_accessor :cache, default: {}
|
115
|
+
class << self
|
116
|
+
def flush!
|
117
|
+
@@pull_successes = {}
|
118
|
+
@@cache = {}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Terraspace::Terraform::RemoteState::Marker
|
2
|
+
class Output
|
3
|
+
include Terraspace::Util::Logging
|
4
|
+
|
5
|
+
def initialize(mod, identifier, options={})
|
6
|
+
@mod, @identifier, @options = mod, identifier, options
|
7
|
+
@parent_name = @mod.name
|
8
|
+
@child_name, @output_key = @identifier.split('.')
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
if valid?
|
13
|
+
Terraspace::Dependency::Registry.register(@parent_name, @child_name)
|
14
|
+
else
|
15
|
+
warning
|
16
|
+
end
|
17
|
+
# MARKER for debugging. Only appears on 1st pass. Will not see unless changing Terraspace code for debugging.
|
18
|
+
marker = "MARKER:terraform_output('#{@identifier}')"
|
19
|
+
Terraspace::Terraform::RemoteState::OutputProxy.new(marker, @options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid?
|
23
|
+
self.class.stack_names.include?(@child_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def warning
|
27
|
+
logger.warn "WARN: The #{@child_name} stack does not exist".color(:yellow)
|
28
|
+
caller_line = caller.find { |l| l.include?('.tfvars') }
|
29
|
+
source_code = PrettyTracer.new(caller_line).source_code
|
30
|
+
logger.info source_code
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
extend Memoist
|
35
|
+
# Marker::Output uses DirsConcern stack_names to check if stacks are valid
|
36
|
+
include Terraspace::Compiler::DirsConcern
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Terraspace::Terraform::RemoteState::Marker
|
2
|
+
class PrettyTracer
|
3
|
+
def initialize(caller_line)
|
4
|
+
@caller_line = caller_line
|
5
|
+
end
|
6
|
+
|
7
|
+
# /full/path/to/app/stacks/a1/tfvars/dev.tfvars:4:in `__tilt_5560'
|
8
|
+
def source_code
|
9
|
+
line = @caller_line.sub(/:in `.*/,'')
|
10
|
+
path, error_line_number = line.split(':')
|
11
|
+
pretty_trace(path, error_line_number.to_i)
|
12
|
+
end
|
13
|
+
|
14
|
+
def pretty_trace(path, error_line_number)
|
15
|
+
io = StringIO.new
|
16
|
+
context = 5 # lines of context
|
17
|
+
top, bottom = [error_line_number-context-1, 0].max, error_line_number+context-1
|
18
|
+
|
19
|
+
io.puts "Here's the line in #{Terraspace::Util.pretty_path(path)} with the error:\n\n"
|
20
|
+
|
21
|
+
lines = IO.read(path).split("\n")
|
22
|
+
context = 5 # lines of context
|
23
|
+
top, bottom = [error_line_number-context-1, 0].max, error_line_number+context-1
|
24
|
+
spacing = lines.size.to_s.size
|
25
|
+
lines[top..bottom].each_with_index do |line_content, index|
|
26
|
+
line_number = top+index+1
|
27
|
+
if line_number == error_line_number
|
28
|
+
io.printf("%#{spacing}d %s\n".color(:red), line_number, line_content)
|
29
|
+
else
|
30
|
+
io.printf("%#{spacing}d %s\n", line_number, line_content)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
io.string
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Terraspace::Terraform::RemoteState
|
2
|
+
class OutputProxy
|
3
|
+
# raw: can be anything: String, Array, Hash, etc
|
4
|
+
# options: original options passed by user with terraform_output
|
5
|
+
attr_reader :raw, :options
|
6
|
+
def initialize(raw, options={})
|
7
|
+
@raw, @options = raw, options
|
8
|
+
@format = @options[:format]
|
9
|
+
end
|
10
|
+
|
11
|
+
# Should always return a String
|
12
|
+
def to_s
|
13
|
+
case @format
|
14
|
+
when "string"
|
15
|
+
content.to_s
|
16
|
+
else # "json"
|
17
|
+
content.to_json
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def content
|
22
|
+
if @raw.nil?
|
23
|
+
@options[:mock] || @options[:error]
|
24
|
+
else
|
25
|
+
@raw
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -7,6 +7,7 @@ module Terraspace::Terraform
|
|
7
7
|
def initialize(name, options={})
|
8
8
|
@name = name
|
9
9
|
super(options)
|
10
|
+
@retries = 1
|
10
11
|
end
|
11
12
|
|
12
13
|
def run
|
@@ -21,17 +22,37 @@ module Terraspace::Terraform
|
|
21
22
|
params = args.flatten.join(' ')
|
22
23
|
command = "terraform #{name} #{params}"
|
23
24
|
run_hooks(name) do
|
24
|
-
|
25
|
+
Terraspace::Shell.new(@mod, command, @options.merge(env: custom.env_vars)).run
|
26
|
+
end
|
27
|
+
rescue Terraspace::InitRequiredError => e
|
28
|
+
logger.info "Terraform reinitialization required detected. Will run `terraform init` and try again."
|
29
|
+
logger.debug "Retry attempt: #{@retries}"
|
30
|
+
logger.debug "#{e.class}"
|
31
|
+
Runner.new("init", @options).run
|
32
|
+
if @retries <= 3
|
33
|
+
backoff = 2 ** @retries # 2, 4, 8
|
34
|
+
logger.debug "Waiting #{backoff}s before retrying"
|
35
|
+
sleep(backoff)
|
36
|
+
@retries += 1
|
37
|
+
retry
|
38
|
+
else
|
39
|
+
logger.info "ERROR: #{e.message}"
|
40
|
+
exit 1
|
25
41
|
end
|
26
42
|
end
|
27
43
|
|
28
44
|
@@current_dir_message_shown = false
|
29
45
|
def current_dir_message
|
30
46
|
return if @@current_dir_message_shown
|
31
|
-
|
47
|
+
log "Current directory: #{Terraspace::Util.pretty_path(@mod.cache_dir)}"
|
32
48
|
@@current_dir_message_shown = true
|
33
49
|
end
|
34
50
|
|
51
|
+
def log(msg)
|
52
|
+
# quiet useful for RemoteState::Fetcher
|
53
|
+
@options[:quiet] ? logger.debug(msg) : logger.info(msg)
|
54
|
+
end
|
55
|
+
|
35
56
|
def run_hooks(name, &block)
|
36
57
|
hooks = Hooks::Builder.new(@mod, name)
|
37
58
|
hooks.build # build hooks
|
@@ -59,18 +80,7 @@ module Terraspace::Terraform
|
|
59
80
|
yield
|
60
81
|
t2 = Time.now
|
61
82
|
if %w[apply destroy].include?(@name)
|
62
|
-
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# http://stackoverflow.com/questions/4175733/convert-duration-to-hoursminutesseconds-or-similar-in-rails-3-or-ruby
|
67
|
-
def pretty_time(total_seconds)
|
68
|
-
minutes = (total_seconds / 60) % 60
|
69
|
-
seconds = total_seconds % 60
|
70
|
-
if total_seconds < 60
|
71
|
-
"#{seconds.to_i}s"
|
72
|
-
else
|
73
|
-
"#{minutes.to_i}m #{seconds.to_i}s"
|
83
|
+
logger.info "Time took: #{pretty_time(t2-t1)}"
|
74
84
|
end
|
75
85
|
end
|
76
86
|
end
|