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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09ac4834cd477fb90ceb545d7dc08fdbacbb42231d51c6e0b27698c37ddc2946'
4
- data.tar.gz: 29a223281b24965c0f33096b180f7a49e5f62e7bd74718e71f16e5fdd072ba1c
3
+ metadata.gz: bae908fcf2dc448dc5b0d2bba463eedd9487c428a296b74955975b66e2faa7c3
4
+ data.tar.gz: bef0979ecaeab8eca50387da95a119719696a759ecff7de55659ff0d8cbac322
5
5
  SHA512:
6
- metadata.gz: 4436cab7ed69ab13e3bda23349c49b3f9e6d3a2fba04b160aba229593aa764f8a7f411c617c1f8892581f4a453a2dcc7c9eb427a976722f40489f518642c0c4a
7
- data.tar.gz: b2f7aded9d6ba98b290d35e02629cb0119eb30a31a22baaa25f44aef94d11fa7a724b534dd9df9d4e918f142d0990743f67e1f49a3412d1df2caf5f08a6819a6
6
+ metadata.gz: 882b9a94cf48af9399a66540385dcd7dbcdbb8118df046c6af833e053f265e57dfeb0a3692f32e315b6a13bb59334c51cfc856db0fc68a067cee4800bc1a3a32
7
+ data.tar.gz: 720aa71881469e415445a1ff83e853c1ece6d71873830111eb1de59c121e9408e478ddaabdd30e6c29e2d48d39b1ec1c96c739e16ca682b3e13e129253594d44
@@ -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/}): 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/cli/): Configurable [CLI Hooks](https://terraspace.cloud/docs/cli/hooks/) and [CLI Args](https://terraspace.cloud/docs/cli/args/) allow you to adjust the underlying terraform command.
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
 
@@ -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
- class InitRequiredError < Error; end
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
@@ -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
 
@@ -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
- @error_messages << err # aggregate all error lines
37
- @known_error ||= known_error_type(err)
38
- unless @known_error
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 @known_error == :reinit_required
80
- raise InitRequiredError.new(@error_messages)
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 => e
29
- logger.info "Terraform reinitialization required detected. Will run `terraform init` and try again."
30
- logger.debug "Retry attempt: #{@retries}"
31
- logger.debug "#{e.class}"
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
- logger.info "ERROR: #{e.message}"
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
@@ -1,3 +1,3 @@
1
1
  module Terraspace
2
- VERSION = "0.4.3"
2
+ VERSION = "0.4.4"
3
3
  end
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.3
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-10-23 00:00:00.000000000 Z
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