terraspace 0.3.2 → 0.3.3

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: 471e59d4e8478c78dd4de1190397e89548e68646fa6fcec02748442ecf9b282e
4
- data.tar.gz: 65250fbef38cef2731688e9c75877747a2a567ecd0d9ba40ce30b2c86c5c73e6
3
+ metadata.gz: e4501185815eeebafbdadd49e8afac52af4fc1c6b8d6d297269614482a38df47
4
+ data.tar.gz: b532e32f8c4a2a34e14b528649ff313041610adb7fc89349f7f97336a4c767d0
5
5
  SHA512:
6
- metadata.gz: 400b78be5d433399119713533a7b56fd7b143b253cae7e96d344273d74784ba9fe877a2a92293f237cec9f0642694256bd04c0b0ad0bef73050d205603884f92
7
- data.tar.gz: eac5b2042f655964d08454d7b5ea3ba40012145fed1c560bf116757c91857479ef7430cd1b7a2be661e828dbaf12a7cd0323014fb847a13299ef8fdc01cc8125
6
+ metadata.gz: b8e949cadb19e163b961bebc40cc8e31bfba8e6ccefb07e28cdabb88a6cf0696a7a8a62b7f4c5f73ab1ae420c9b1956f38d2916f65ad0bfae3ee4e64ba885de5
7
+ data.tar.gz: 0f0ef1edc6432743dc6f3535449c880615057038a4e097ca03227660d7dd39270da8186675c26315f86636344635017d16f4c60fef580dfb6188bd0c785e92ab
@@ -3,6 +3,9 @@
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.3.3]
7
+ * #41 fix `terraspace build` and `terraspace seed` when bucket doesnt exist yet and there are dependenices defined.
8
+
6
9
  ## [0.3.2]
7
10
  * #40 fix backend auto creation
8
11
 
data/README.md CHANGED
@@ -88,7 +88,7 @@ When you use the all command, the dependency graph is calculated and the stacks
88
88
  * [Config Structure](https://terraspace.cloud/docs/config/): A common config structure that gets materializes with the deployed module. Configs can be dynamically controlled to keep your code DRY. You can override the settings if needed, like for using existing backends. See: [Existing Backends](https://terraspace.cloud/docs/state/existing/).
89
89
  * [Generators](https://terraspace.cloud/docs/generators/): Built-in generators to quickly create the starter module. Focus on code instead of boilerplate structure.
90
90
  * [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/).
91
- * [Deploy Multiple Stacks](https://terraspace.cloud/docs/dependencies/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/).
91
+ * [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/).
92
92
  * [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.
93
93
  * [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.
94
94
  * [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.
@@ -26,6 +26,7 @@ module Terraspace
26
26
  extend Core # for Terraspace.root
27
27
  class Error < StandardError; end
28
28
  class InitRequiredError < Error; end
29
+ class BucketNotFoundError < Error; end
29
30
  end
30
31
 
31
32
  Terraspace::Booter.boot
@@ -1,6 +1,7 @@
1
1
  module Terraspace
2
2
  class Builder < Terraspace::CLI::Base
3
3
  include Compiler::DirsConcern
4
+ include Compiler::CommandsConcern
4
5
 
5
6
  attr_reader :graph
6
7
 
@@ -58,16 +59,10 @@ module Terraspace
58
59
  # Auto create after build_unresolved since will need to run state pull for dependencies
59
60
  def auto_create_backend
60
61
  return if Terraspace.config.auto_create_backend == false
61
- return unless create_backend?
62
+ return unless requires_backend?
62
63
  Terraspace::Compiler::Backend.new(@mod).create
63
64
  end
64
65
 
65
- def create_backend?
66
- commands = %w[down init output plan providers refresh show up validate]
67
- commands.include?(ARGV[0]) || # IE: terraspace up
68
- ARGV[0] == "all" && commands.include?(ARGV[1]) # IE: terraspace all up
69
- end
70
-
71
66
  def clean
72
67
  Compiler::Cleaner.new(@mod, @options).clean if clean?
73
68
  end
@@ -110,7 +110,7 @@ module Terraspace
110
110
  List.new(options).run
111
111
  end
112
112
 
113
- desc "log [ACTION] [STACK]", "The all log command allows you to view multiple logs."
113
+ desc "log [ACTION] [STACK]", "The log command allows you to view multiple logs."
114
114
  long_desc Help.text("log")
115
115
  option :timestamps, aliases: %w[t], type: :boolean, desc: "Whether or not to show the leading timestamp. Defaults to timestamps for multiple logs, and no timestamp if a single log is specified. Note: In follow mode, timestamp always shown"
116
116
  option :follow, aliases: %w[f], type: :boolean, desc: "Follow the log in live tail fashion. Must specify a stack if using this option."
@@ -1,4 +1,4 @@
1
- This leaves the to most recent run alone. The top run will immediately start planning. Runs that are also in "Needs Confirmation" will be cancelled.
1
+ This leaves the top run alone. The top run usually starts immediately planning once the other runs are pruned. Runs that are also in "Needs Confirmation" will be cancelled.
2
2
 
3
3
  ## Examples
4
4
 
@@ -23,7 +23,7 @@ To show all logs, use the `-a` option.
23
23
 
24
24
  terraspace log up -a
25
25
 
26
- Note, if both an action and stack is specified, then it defaults to showing all logs. If you want to not show all logs in thta case, then you can use `--no-all`.
26
+ Note, if both an action and stack is specified, then it defaults to showing all logs. If you want not to show all logs, use `--no-all`.
27
27
 
28
28
  ## Tail Logs
29
29
 
@@ -36,7 +36,11 @@ To tail logs, use the `-f` option.
36
36
 
37
37
  ## Timestamps
38
38
 
39
- The timestamps are shown by default when you are looking for multiple files. When you specify a both the action and stack for a single log file, then timestamps are not shown.
39
+ The timestamps are shown by default when you are looking for multiple files. When you specify both the action and stack for a single log file, then timestamps are not shown.
40
40
 
41
41
  terraspace log up # timestamps will be shown in this case
42
42
  terraspace log up network # timestamps not be shown in this case
43
+
44
+ To show timestamps:
45
+
46
+ terraspace up up network --timestamps
@@ -6,7 +6,13 @@ module Terraspace::Compiler
6
6
  @mod = mod
7
7
  end
8
8
 
9
+ @@created = {}
9
10
  def create
11
+ return if @@created[cache_key]
12
+ # set immediately, since local storage wont reach bottom.
13
+ # if fail for other backends, there will be an exception anyway
14
+ @@created[cache_key] = true
15
+
10
16
  klass = backend_interface(backend_name)
11
17
  return unless klass # in case auto-creation is not supported for specific backend
12
18
 
@@ -14,6 +20,10 @@ module Terraspace::Compiler
14
20
  interface.call
15
21
  end
16
22
 
23
+ def cache_key
24
+ @mod.build_dir
25
+ end
26
+
17
27
  def backend_name
18
28
  backend.keys.first # IE: s3, gcs, etc
19
29
  end
@@ -1,5 +1,6 @@
1
1
  module Terraspace::Compiler
2
2
  class Builder
3
+ include CommandsConcern
3
4
  include Basename
4
5
 
5
6
  def initialize(mod)
@@ -9,7 +10,7 @@ module Terraspace::Compiler
9
10
  def build
10
11
  build_config
11
12
  build_module if @mod.resolved
12
- build_tfvars
13
+ build_tfvars unless command_is?(:seed) # avoid dependencies being built and erroring when backend bucket doesnt exist
13
14
  end
14
15
 
15
16
  # build common config files: provider and backend for the root module
@@ -0,0 +1,18 @@
1
+ module Terraspace::Compiler
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
+ def command_is?(*commands)
12
+ commands.flatten!
13
+ commands.map!(&:to_s)
14
+ commands.include?(ARGV[0]) || # IE: terraspace up
15
+ ARGV[0] == "all" && commands.include?(ARGV[1]) # IE: terraspace all up
16
+ end
17
+ end
18
+ end
@@ -6,7 +6,7 @@ module Terraspace
6
6
 
7
7
  def initialize(mod, command, options={})
8
8
  @mod, @command, @options = mod, command, options
9
- @init_required, @init_messages = false, ''
9
+ @error_type, @error_messages = nil, ''
10
10
  end
11
11
 
12
12
  # requires @mod to be set
@@ -22,10 +22,13 @@ module Terraspace
22
22
  Open3.popen3(env, @command, chdir: @mod.cache_dir) do |stdin, stdout, stderr, wait_thread|
23
23
  mimic_terraform_input(stdin, stdout)
24
24
  while err = stderr.gets
25
- @init_required ||= reinitialization_required?(err)
26
- if @init_required
27
- @init_messages << err
25
+ @error_type ||= known_error_type(err)
26
+ if @error_type
27
+ @error_messages << err
28
28
  else
29
+ # Sometimes may print a "\e[31m\n" which like during dependencies fetcher init
30
+ # suppress it so dont get a bunch of annoying "newlines"
31
+ next if err == "\e[31m\n" && @options[:suppress_error_color]
29
32
  logger.error(err)
30
33
  end
31
34
  end
@@ -35,24 +38,39 @@ module Terraspace
35
38
  end
36
39
  end
37
40
 
41
+ def known_error_type(err)
42
+ if reinitialization_required?(err)
43
+ :reinitialization_required
44
+ elsif bucket_not_found?(err)
45
+ :bucket_not_found
46
+ end
47
+ end
48
+
49
+ def bucket_not_found?(err)
50
+ # Message is included in aws, azurerm, and google. See: https://bit.ly/3iOKDri
51
+ err.include?("Failed to get existing workspaces")
52
+ end
53
+
54
+ def reinitialization_required?(err)
55
+ err.include?("reinitialization required") ||
56
+ err.include?("terraform init") ||
57
+ err.include?("require reinitialization")
58
+ end
59
+
38
60
  def exit_status(status)
39
61
  return if status == 0
40
62
 
41
63
  exit_on_fail = @options[:exit_on_fail].nil? ? true : @options[:exit_on_fail]
42
- if @init_required
43
- raise InitRequiredError.new(@init_messages)
64
+ if @error_type == :reinitialization_required
65
+ raise InitRequiredError.new(@error_messages)
66
+ elsif @error_type == :bucket_not_found
67
+ raise BucketNotFoundError.new(@error_messages)
44
68
  elsif exit_on_fail
45
69
  logger.error "Error running command: #{@command}".color(:red)
46
70
  exit status
47
71
  end
48
72
  end
49
73
 
50
- def reinitialization_required?(err)
51
- err.include?("reinitialization required") ||
52
- err.include?("terraform init") ||
53
- err.include?("require reinitialization")
54
- end
55
-
56
74
  # Terraform doesnt seem to stream the line that prompts with "Enter a value:" when using Open3.popen3
57
75
  # Hack around it by mimicking the "Enter a value:" prompt
58
76
  #
@@ -1,6 +1,7 @@
1
1
  module Terraspace::Terraform::RemoteState
2
2
  class Fetcher
3
3
  extend Memoist
4
+ include Terraspace::Compiler::CommandsConcern
4
5
  include Terraspace::Util::Logging
5
6
 
6
7
  def initialize(parent, identifier, options={})
@@ -10,7 +11,7 @@ module Terraspace::Terraform::RemoteState
10
11
  end
11
12
 
12
13
  def run
13
- validate!
14
+ validate! # check child stack exists
14
15
  pull
15
16
  load
16
17
  end
@@ -22,7 +23,8 @@ module Terraspace::Terraform::RemoteState
22
23
  error = output_error(:key_not_found) unless @outputs.key?(@output_key)
23
24
  OutputProxy.new(value, @options.merge(error: error))
24
25
  else
25
- error = output_error(:state_not_found)
26
+ @error_type ||= :state_not_found # could be set to :bucket_not_found by bucket_not_found_error
27
+ error = output_error(@error_type)
26
28
  OutputProxy.new(nil, @options.merge(error: error))
27
29
  end
28
30
  end
@@ -39,6 +41,8 @@ module Terraspace::Terraform::RemoteState
39
41
  "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
42
  when :state_not_found
41
43
  "Output #{@output_key} could not be looked up for the #{@parent.name} tfvars file. #{@child.name} stack needs to be deployed"
44
+ when :bucket_not_found
45
+ "The bucket for the backend could not be found"
42
46
  end
43
47
  msg = "(#{msg})"
44
48
  log_message(msg)
@@ -52,7 +56,10 @@ module Terraspace::Terraform::RemoteState
52
56
  logger.info "Downloading tfstate files for dependencies defined in tfvars..." unless @@download_shown || @options[:quiet]
53
57
  @@download_shown = true
54
58
  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
59
+
60
+ success = init # init not yet run. only run .init directly, not .run. init can completely error and early exit.
61
+ return unless success
62
+
56
63
  FileUtils.mkdir_p(File.dirname(state_path))
57
64
  command = "cd #{@child.cache_dir} && terraform state pull > #{state_path}"
58
65
  logger.debug "=> #{command}"
@@ -67,6 +74,20 @@ module Terraspace::Terraform::RemoteState
67
74
  @@pull_successes[cache_key] = success
68
75
  end
69
76
 
77
+ def init
78
+ Terraspace::CLI::Init.new(mod: @child.name, calling_command: "apply", quiet: true, suppress_error_color: true).init
79
+ true
80
+ rescue Terraspace::BucketNotFoundError # from Terraspace::Shell
81
+ bucket_not_found_error
82
+ false
83
+ end
84
+
85
+ # mimic pull error
86
+ def bucket_not_found_error
87
+ @@pull_successes[cache_key] = false
88
+ @error_type = :bucket_not_found
89
+ end
90
+
70
91
  def load
71
92
  return self unless pull_success?
72
93
 
@@ -1,3 +1,3 @@
1
1
  module Terraspace
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terraspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
@@ -520,6 +520,7 @@ files:
520
520
  - lib/terraspace/compiler/builder.rb
521
521
  - lib/terraspace/compiler/cleaner.rb
522
522
  - lib/terraspace/compiler/cleaner/backend_change.rb
523
+ - lib/terraspace/compiler/commands_concern.rb
523
524
  - lib/terraspace/compiler/dirs_concern.rb
524
525
  - lib/terraspace/compiler/dsl/base.rb
525
526
  - lib/terraspace/compiler/dsl/meta/local.rb