terraspace 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +2 -2
- data/lib/terraspace.rb +3 -1
- data/lib/terraspace/cli/cloud.rb +2 -0
- data/lib/terraspace/shell.rb +5 -33
- data/lib/terraspace/shell/error.rb +46 -0
- data/lib/terraspace/terraform/runner.rb +5 -13
- data/lib/terraspace/terraform/runner/retryer.rb +65 -0
- data/lib/terraspace/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bae908fcf2dc448dc5b0d2bba463eedd9487c428a296b74955975b66e2faa7c3
|
4
|
+
data.tar.gz: bef0979ecaeab8eca50387da95a119719696a759ecff7de55659ff0d8cbac322
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 882b9a94cf48af9399a66540385dcd7dbcdbb8118df046c6af833e053f265e57dfeb0a3692f32e315b6a13bb59334c51cfc856db0fc68a067cee4800bc1a3a32
|
7
|
+
data.tar.gz: 720aa71881469e415445a1ff83e853c1ece6d71873830111eb1de59c121e9408e478ddaabdd30e6c29e2d48d39b1ec1c96c739e16ca682b3e13e129253594d44
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,10 @@
|
|
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
|
+
## [0.4.4]
|
7
|
+
- #50 retry logic for shared cache error
|
8
|
+
- #51 fix cloud sync: call build first
|
9
|
+
|
6
10
|
## [0.4.3]
|
7
11
|
* #49 add info --path option
|
8
12
|
|
data/README.md
CHANGED
@@ -107,8 +107,8 @@ To install modules:
|
|
107
107
|
* [Generators](https://terraspace.cloud/docs/generators/): Built-in generators to quickly create the starter module. Focus on code instead of boilerplate structure.
|
108
108
|
* [Tfvars](https://terraspace.cloud/docs/tfvars/) & [Layering](https://terraspace.cloud/docs/tfvars/layering/): Use the same code with different tfvars to create multiple environments. Terraspace conventionally loads tfvars from the `tfvars` folder. Rich layering support allows you to build different environments like dev and prod with the same code. Examples are in [Full Layering](https://terraspace.cloud/docs/tfvars/full-layering/).
|
109
109
|
* [Deploy Multiple Stacks](https://terraspace.cloud/docs/intro/deploy-all/): The ability to deploy multiple stacks with a single command. Terraspace calculates the [dependency graph](https://terraspace.cloud/docs/dependencies/) and deploys stacks in the right order. You can also target specific stacks and deploy [subgraphs](https://terraspace.cloud/docs/dependencies/subgraphs/).
|
110
|
-
* [Terrafile](https://terraspace.cloud/docs/terrafile/
|
111
|
-
* [Configurable CLI](https://terraspace.cloud/docs/
|
110
|
+
* [Terrafile](https://terraspace.cloud/docs/terrafile/): Terraspace makes it easy to use Terraform modules sourced from your own git repositories, other git repositories, or the Terraform Registry. The git repos can be private or public. This is an incredibly powerful feature of Terraspace because it opens up a world of modules for you to use. Use any module you want.
|
111
|
+
* [Configurable CLI](https://terraspace.cloud/docs/config/args/): Configurable [CLI Hooks](https://terraspace.cloud/docs/config/hooks/) and [CLI Args](https://terraspace.cloud/docs/config/args/) allow you to adjust the underlying terraform command.
|
112
112
|
* [Testing](https://terraspace.cloud/docs/testing/): A testing framework that allows you to create test harnesses, deploy real-resources, and have higher confidence that your code works.
|
113
113
|
* [Terraform Cloud and Terraform Enterprise Support](https://terraspace.cloud/docs/cloud/): TFC and TFE are both supported. Terraspace adds additional conveniences to make working with Terraform Cloud Workspaces easier.
|
114
114
|
|
data/lib/terraspace.rb
CHANGED
@@ -26,8 +26,10 @@ DslEvaluator.backtrace_reject = "lib/terraspace"
|
|
26
26
|
module Terraspace
|
27
27
|
extend Core # for Terraspace.root
|
28
28
|
class Error < StandardError; end
|
29
|
-
|
29
|
+
|
30
30
|
class BucketNotFoundError < Error; end
|
31
|
+
class InitRequiredError < Error; end
|
32
|
+
class SharedCacheError < Error; end
|
31
33
|
end
|
32
34
|
|
33
35
|
Terraspace::Booter.boot
|
data/lib/terraspace/cli/cloud.rb
CHANGED
@@ -16,6 +16,7 @@ class Terraspace::CLI
|
|
16
16
|
|
17
17
|
desc "destroy STACK", "Destroy workspace by specifying the stack"
|
18
18
|
long_desc Help.text("cloud:destroy")
|
19
|
+
yes_option.call
|
19
20
|
def destroy(mod)
|
20
21
|
Workspace.new(options.merge(mod: mod)).destroy
|
21
22
|
end
|
@@ -24,6 +25,7 @@ class Terraspace::CLI
|
|
24
25
|
long_desc Help.text("cloud:sync")
|
25
26
|
yes_option.call
|
26
27
|
def sync(*stacks)
|
28
|
+
Terraspace::CLI::Build::Placeholder.new(options).build
|
27
29
|
Syncer.new(options.merge(stacks: stacks, override_auto_sync: true)).run
|
28
30
|
end
|
29
31
|
|
data/lib/terraspace/shell.rb
CHANGED
@@ -6,8 +6,6 @@ module Terraspace
|
|
6
6
|
|
7
7
|
def initialize(mod, command, options={})
|
8
8
|
@mod, @command, @options = mod, command, options
|
9
|
-
# error_messages holds aggregation of all error lines
|
10
|
-
@known_error, @error_messages = nil, ''
|
11
9
|
end
|
12
10
|
|
13
11
|
# requires @mod to be set
|
@@ -33,9 +31,9 @@ module Terraspace
|
|
33
31
|
Open3.popen3(env, @command, chdir: @mod.cache_dir) do |stdin, stdout, stderr, wait_thread|
|
34
32
|
mimic_terraform_input(stdin, stdout)
|
35
33
|
while err = stderr.gets
|
36
|
-
@
|
37
|
-
@
|
38
|
-
unless @
|
34
|
+
@error ||= Error.new
|
35
|
+
@error.lines << err # aggregate all error lines
|
36
|
+
unless @error.known?
|
39
37
|
# Sometimes may print a "\e[31m\n" which like during dependencies fetcher init
|
40
38
|
# suppress it so dont get a bunch of annoying "newlines"
|
41
39
|
next if err == "\e[31m\n" && @options[:suppress_error_color]
|
@@ -48,38 +46,12 @@ module Terraspace
|
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
|
-
def known_error_type(err)
|
52
|
-
if reinit_required?(err)
|
53
|
-
:reinit_required
|
54
|
-
elsif bucket_not_found?(err)
|
55
|
-
:bucket_not_found
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def bucket_not_found?(err)
|
60
|
-
# Message is included in aws, azurerm, and google. See: https://bit.ly/3iOKDri
|
61
|
-
err.include?("Failed to get existing workspaces")
|
62
|
-
end
|
63
|
-
|
64
|
-
def reinit_required?(err)
|
65
|
-
# Example error: https://gist.github.com/tongueroo/f7e0a44b64f0a2e533089b18f331c21e
|
66
|
-
squeezed = @error_messages.gsub("\n", ' ').squeeze(' ') # remove double whitespaces and newlines
|
67
|
-
general_check = squeezed.include?("terraform init") && squeezed.include?("Error:")
|
68
|
-
|
69
|
-
general_check ||
|
70
|
-
err.include?("reinitialization required") ||
|
71
|
-
err.include?("terraform init") ||
|
72
|
-
err.include?("require reinitialization")
|
73
|
-
end
|
74
|
-
|
75
49
|
def exit_status(status)
|
76
50
|
return if status == 0
|
77
51
|
|
78
52
|
exit_on_fail = @options[:exit_on_fail].nil? ? true : @options[:exit_on_fail]
|
79
|
-
if @
|
80
|
-
raise
|
81
|
-
elsif @known_error == :bucket_not_found
|
82
|
-
raise BucketNotFoundError.new(@error_messages)
|
53
|
+
if @error && @error.known?
|
54
|
+
raise @error.instance
|
83
55
|
elsif exit_on_fail
|
84
56
|
logger.error "Error running command: #{@command}".color(:red)
|
85
57
|
exit status
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Terraspace::Shell
|
2
|
+
class Error
|
3
|
+
attr_accessor :lines
|
4
|
+
def initialize
|
5
|
+
@lines = '' # holds aggregation of all error lines
|
6
|
+
end
|
7
|
+
|
8
|
+
def known?
|
9
|
+
!!instance
|
10
|
+
end
|
11
|
+
|
12
|
+
def instance
|
13
|
+
if reinit_required?
|
14
|
+
Terraspace::InitRequiredError.new(@lines)
|
15
|
+
elsif bucket_not_found?
|
16
|
+
Terraspace::BucketNotFound.new(@lines)
|
17
|
+
elsif shared_cache_error?
|
18
|
+
Terraspace::SharedCacheError.new(@lines)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def bucket_not_found?
|
23
|
+
# Message is included in aws, azurerm, and google. See: https://bit.ly/3iOKDri
|
24
|
+
message.include?("Failed to get existing workspaces")
|
25
|
+
end
|
26
|
+
|
27
|
+
def reinit_required?
|
28
|
+
# Example error: https://gist.github.com/tongueroo/f7e0a44b64f0a2e533089b18f331c21e
|
29
|
+
general_check = message.include?("terraform init") && message.include?("Error:")
|
30
|
+
general_check ||
|
31
|
+
message.include?("reinitialization required") ||
|
32
|
+
message.include?("terraform init") ||
|
33
|
+
message.include?("require reinitialization")
|
34
|
+
end
|
35
|
+
|
36
|
+
def message
|
37
|
+
@lines.gsub("\n", ' ').squeeze(' ') # remove double whitespaces and newlines
|
38
|
+
end
|
39
|
+
|
40
|
+
def shared_cache_error?
|
41
|
+
# Example: https://gist.github.com/tongueroo/4f2c925709d21f5810229ce9ca482560
|
42
|
+
message.include?("Failed to install provider from shared cache") ||
|
43
|
+
message.include?("Failed to validate installed provider")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -8,7 +8,6 @@ module Terraspace::Terraform
|
|
8
8
|
def initialize(name, options={})
|
9
9
|
@name = name
|
10
10
|
super(options)
|
11
|
-
@retries = 1
|
12
11
|
end
|
13
12
|
|
14
13
|
def run
|
@@ -25,20 +24,13 @@ module Terraspace::Terraform
|
|
25
24
|
run_hooks("terraform.rb", name) do
|
26
25
|
Terraspace::Shell.new(@mod, command, @options.merge(env: custom.env_vars)).run
|
27
26
|
end
|
28
|
-
rescue Terraspace::InitRequiredError
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
Runner.new("init", @options).run
|
33
|
-
if @retries <= 3
|
34
|
-
backoff = 2 ** @retries # 2, 4, 8
|
35
|
-
logger.debug "Waiting #{backoff}s before retrying"
|
36
|
-
sleep(backoff)
|
37
|
-
@retries += 1
|
27
|
+
rescue Terraspace::SharedCacheError, Terraspace::InitRequiredError
|
28
|
+
@retryer ||= Retryer.new(@mod, @options, name, $!)
|
29
|
+
if @retryer.retry?
|
30
|
+
@retryer.run
|
38
31
|
retry
|
39
32
|
else
|
40
|
-
|
41
|
-
exit 1
|
33
|
+
exit(1)
|
42
34
|
end
|
43
35
|
end
|
44
36
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class Terraspace::Terraform::Runner
|
2
|
+
class Retryer
|
3
|
+
include Terraspace::Util::Logging
|
4
|
+
include Terraspace::Util::Pretty
|
5
|
+
|
6
|
+
def initialize(mod, options, command_name, exception)
|
7
|
+
@mod, @options, @command_name, @exception = mod, options, command_name, exception
|
8
|
+
@retries = 1
|
9
|
+
end
|
10
|
+
|
11
|
+
def retry?
|
12
|
+
if @retries <= 3
|
13
|
+
true # will retry
|
14
|
+
else
|
15
|
+
logger.info "ERROR: #{@exception.message}"
|
16
|
+
false # will not retry
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
backoff = 2 ** @retries # 2, 4, 8
|
22
|
+
logger.debug "Waiting #{backoff}s before retrying"
|
23
|
+
sleep(backoff)
|
24
|
+
@retries += 1
|
25
|
+
|
26
|
+
case @exception
|
27
|
+
when Terraspace::SharedCacheError
|
28
|
+
shared_cache_error
|
29
|
+
when Terraspace::InitRequiredError
|
30
|
+
init_required_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def shared_cache_error
|
35
|
+
logger.info "Terraform Shared Cache error detected. Will purge caches and run `terraform init` to try again."
|
36
|
+
logger.debug "Retry attempt: #{@retries}"
|
37
|
+
logger.debug "#{@exception.class}"
|
38
|
+
logger.debug "#{@exception.message}"
|
39
|
+
purge_caches # Purging the cache "fixes" this terraform bug
|
40
|
+
reinit
|
41
|
+
end
|
42
|
+
|
43
|
+
def init_required_error
|
44
|
+
logger.info "Terraform reinitialization required detected. Will run `terraform init` and try again."
|
45
|
+
logger.debug "Retry attempt: #{@retries}"
|
46
|
+
logger.debug "#{@exception.class}"
|
47
|
+
reinit
|
48
|
+
end
|
49
|
+
|
50
|
+
def reinit
|
51
|
+
Terraspace::Terraform::Runner.new("init", @options).run unless @command_name == "init"
|
52
|
+
end
|
53
|
+
|
54
|
+
def purge_caches
|
55
|
+
dir = "#{@mod.cache_dir}/.terraform"
|
56
|
+
logger.info "Purging #{pretty_path(dir)}"
|
57
|
+
FileUtils.rm_rf(dir)
|
58
|
+
|
59
|
+
dir = "#{Terraspace.config.terraform.plugin_cache.dir}"
|
60
|
+
logger.info "Purging #{pretty_path(dir)}"
|
61
|
+
FileUtils.rm_rf(dir)
|
62
|
+
FileUtils.mkdir_p(dir) # need /tmp/terraspace/plugin_cache dir to exist
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/terraspace/version.rb
CHANGED
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: 0.4.
|
4
|
+
version: 0.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tung Nguyen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -639,6 +639,7 @@ files:
|
|
639
639
|
- lib/terraspace/seeder/content.rb
|
640
640
|
- lib/terraspace/seeder/where.rb
|
641
641
|
- lib/terraspace/shell.rb
|
642
|
+
- lib/terraspace/shell/error.rb
|
642
643
|
- lib/terraspace/terraform/api.rb
|
643
644
|
- lib/terraspace/terraform/api/base.rb
|
644
645
|
- lib/terraspace/terraform/api/client.rb
|
@@ -670,6 +671,7 @@ files:
|
|
670
671
|
- lib/terraspace/terraform/remote_state/output_proxy.rb
|
671
672
|
- lib/terraspace/terraform/remote_state/unresolved.rb
|
672
673
|
- lib/terraspace/terraform/runner.rb
|
674
|
+
- lib/terraspace/terraform/runner/retryer.rb
|
673
675
|
- lib/terraspace/tester.rb
|
674
676
|
- lib/terraspace/tester/finder.rb
|
675
677
|
- lib/terraspace/tester/meta.rb
|