terraspace 0.3.4 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/README.md +56 -29
- data/lib/templates/base/project/README.md +1 -1
- data/lib/terraspace/all/preview.rb +1 -1
- data/lib/terraspace/all/runner.rb +1 -0
- data/lib/terraspace/all/summary.rb +8 -1
- data/lib/terraspace/app.rb +9 -5
- data/lib/terraspace/builder.rb +10 -6
- data/lib/terraspace/cli.rb +11 -16
- data/lib/terraspace/cli/all.rb +6 -0
- data/lib/terraspace/cli/bundle.rb +2 -1
- data/lib/terraspace/cli/clean.rb +18 -6
- data/lib/terraspace/cli/clean/all.rb +18 -0
- data/lib/terraspace/cli/clean/base.rb +15 -0
- data/lib/terraspace/cli/clean/cache.rb +25 -0
- data/lib/terraspace/cli/{logs/tasks.rb → clean/logs.rb} +16 -5
- data/lib/terraspace/cli/help/all/init.md +33 -0
- data/lib/terraspace/cli/help/clean/all.md +10 -0
- data/lib/terraspace/cli/help/clean/cache.md +12 -0
- data/lib/terraspace/cli/help/clean/logs.md +17 -0
- data/lib/terraspace/cli/help/logs.md +48 -0
- data/lib/terraspace/cli/init.rb +3 -7
- data/lib/terraspace/cli/list.rb +2 -1
- data/lib/terraspace/cli/logs.rb +106 -9
- data/lib/terraspace/cli/{log → logs}/concern.rb +2 -1
- data/lib/terraspace/cli/new/helper.rb +9 -2
- data/lib/terraspace/compiler/dependencies/helpers.rb +34 -0
- data/lib/terraspace/compiler/dsl/syntax/helpers/common.rb +0 -26
- data/lib/terraspace/compiler/dsl/syntax/tfvar.rb +1 -0
- data/lib/terraspace/compiler/erb/context.rb +1 -1
- data/lib/terraspace/compiler/erb/helpers.rb +6 -0
- data/lib/terraspace/dependency/helper/base.rb +7 -0
- data/lib/terraspace/dependency/helper/depends_on.rb +12 -0
- data/lib/terraspace/dependency/helper/output.rb +11 -0
- data/lib/terraspace/hooks/builder.rb +52 -0
- data/lib/terraspace/hooks/concern.rb +9 -0
- data/lib/terraspace/{terraform/hooks → hooks}/dsl.rb +3 -2
- data/lib/terraspace/hooks/runner.rb +23 -0
- data/lib/terraspace/mod.rb +11 -2
- data/lib/terraspace/plugin/summary/interface.rb +3 -1
- data/lib/terraspace/shell.rb +15 -10
- data/lib/terraspace/terraform/args/custom.rb +1 -1
- data/lib/terraspace/terraform/args/default.rb +9 -19
- data/lib/terraspace/terraform/remote_state/fetcher.rb +13 -4
- data/lib/terraspace/terraform/remote_state/marker/output.rb +3 -1
- data/lib/terraspace/terraform/remote_state/output_proxy.rb +18 -14
- data/lib/terraspace/terraform/remote_state/unresolved.rb +40 -0
- data/lib/terraspace/terraform/runner.rb +3 -8
- data/lib/terraspace/version.rb +1 -1
- data/spec/fixtures/dependencies/app/stacks/a1/tfvars/dev.tfvars +1 -0
- data/spec/fixtures/fetcher/c1.json +4 -0
- data/spec/terraspace/compiler/erb/render_spec.rb +15 -0
- data/spec/terraspace/dependency/helper/depends_on_spec.rb +27 -0
- data/spec/terraspace/dependency/helper/output_spec.rb +29 -0
- data/spec/terraspace/{terraform/hooks → hooks}/builder_spec.rb +4 -5
- data/spec/terraspace/terraform/remote_state/fetcher_spec.rb +108 -27
- data/spec/terraspace/terraform/remote_state/marker/output_spec.rb +36 -0
- data/spec/terraspace/terraform/remote_state/output_proxy_spec.rb +69 -0
- data/terraspace.gemspec +1 -1
- metadata +38 -13
- data/lib/terraspace/cli/help/clean.md +0 -5
- data/lib/terraspace/cli/help/log.md +0 -48
- data/lib/terraspace/cli/log.rb +0 -112
- data/lib/terraspace/terraform/hooks/builder.rb +0 -40
@@ -0,0 +1,25 @@
|
|
1
|
+
class Terraspace::CLI::Clean
|
2
|
+
class Cache < Base
|
3
|
+
def run
|
4
|
+
Terraspace.check_project!
|
5
|
+
paths = [Terraspace.cache_root, Terraspace.tmp_root]
|
6
|
+
are_you_sure?(paths)
|
7
|
+
paths.each do |path|
|
8
|
+
FileUtils.rm_rf(path)
|
9
|
+
puts "Removed #{pretty(path)}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def are_you_sure?(paths)
|
14
|
+
pretty_paths = paths.map { |p| " #{pretty(p)}" }.join("\n")
|
15
|
+
message = <<~EOL.chomp
|
16
|
+
Will remove these folders and all their files:
|
17
|
+
|
18
|
+
#{pretty_paths}
|
19
|
+
|
20
|
+
Are you sure?
|
21
|
+
EOL
|
22
|
+
sure?(message) # from Util::Sure
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,11 +1,13 @@
|
|
1
|
-
class Terraspace::CLI::
|
2
|
-
class
|
3
|
-
def
|
4
|
-
@options
|
1
|
+
class Terraspace::CLI::Clean
|
2
|
+
class Logs < Base
|
3
|
+
def run
|
4
|
+
action = @options[:truncate] ? "truncate" : "remove"
|
5
|
+
are_you_sure?(action)
|
6
|
+
@options[:truncate] ? truncate : remove
|
7
|
+
logger.info "Logs #{action}d" # IE: Logs truncated or Logs removed
|
5
8
|
end
|
6
9
|
|
7
10
|
def truncate
|
8
|
-
puts "Truncating log files in #{pretty_log_root}/" unless @options[:mute]
|
9
11
|
log_files.each do |path|
|
10
12
|
File.open(path, "w").close # truncates files
|
11
13
|
end
|
@@ -28,5 +30,14 @@ class Terraspace::CLI::Logs
|
|
28
30
|
def log_root
|
29
31
|
Terraspace.config.log.root
|
30
32
|
end
|
33
|
+
|
34
|
+
def are_you_sure?(action)
|
35
|
+
message = <<~EOL.chomp
|
36
|
+
Will #{action} all the log files in #{pretty_log_root}/ folder
|
37
|
+
Are you sure?
|
38
|
+
EOL
|
39
|
+
sure?(message) # from Util::Sure
|
40
|
+
end
|
31
41
|
end
|
32
42
|
end
|
43
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
## Example
|
2
|
+
|
3
|
+
$ terraspace all init
|
4
|
+
Building one stack to build all stacks
|
5
|
+
Building .terraspace-cache/us-west-2/dev/stacks/c1
|
6
|
+
Downloading tfstate files for dependencies defined in tfvars...
|
7
|
+
Built in .terraspace-cache/us-west-2/dev/stacks/c1
|
8
|
+
Running:
|
9
|
+
terraspace init c1 # batch 1
|
10
|
+
terraspace init b1 # batch 2
|
11
|
+
terraspace init b2 # batch 2
|
12
|
+
terraspace init a1 # batch 3
|
13
|
+
Batch Run 1:
|
14
|
+
Running: terraspace init c1 Logs: log/init/c1.log
|
15
|
+
terraspace init c1: Terraform has been successfully initialized!
|
16
|
+
Batch Run 2:
|
17
|
+
Running: terraspace init b1 Logs: log/init/b1.log
|
18
|
+
Running: terraspace init b2 Logs: log/init/b2.log
|
19
|
+
terraspace init b1: Terraform has been successfully initialized!
|
20
|
+
terraspace init b2: Terraform has been successfully initialized!
|
21
|
+
Batch Run 3:
|
22
|
+
Running: terraspace init a1 Logs: log/init/a1.log
|
23
|
+
terraspace init a1: Terraform has been successfully initialized!
|
24
|
+
Time took: 6s
|
25
|
+
$
|
26
|
+
|
27
|
+
If Terraform is having trouble initializing, clearing the cache may help:
|
28
|
+
|
29
|
+
$ terraspace clean cache -y
|
30
|
+
Removed .terraspace-cache
|
31
|
+
Removed /tmp/terraspace
|
32
|
+
|
33
|
+
Also consider disabling the [terraform.plugin_cache.enabled](https://terraspace.cloud/docs/config/reference/).
|
@@ -0,0 +1,17 @@
|
|
1
|
+
## Examples
|
2
|
+
|
3
|
+
Remove logs completely:
|
4
|
+
|
5
|
+
$ terraspace clean logs
|
6
|
+
Will remove all the log files in log/ folder
|
7
|
+
Are you sure? (y/N) y
|
8
|
+
Removing all files in log/
|
9
|
+
Logs removed
|
10
|
+
|
11
|
+
Truncate logs. IE: Keeps the files but removes contents and zero bytes the files.
|
12
|
+
|
13
|
+
$ terraspace clean logs --truncate
|
14
|
+
Will truncate all the log files in log/ folder
|
15
|
+
Are you sure? (y/N) y
|
16
|
+
Logs truncated
|
17
|
+
$
|
@@ -0,0 +1,48 @@
|
|
1
|
+
The log commands will filter out the logs for the last ran terraspace command. It does this by filtering for the last found PID in the log files.
|
2
|
+
|
3
|
+
## Quick Start
|
4
|
+
|
5
|
+
Follow all the logs as you're running `terraspace all up`:
|
6
|
+
|
7
|
+
terraspace logs -f
|
8
|
+
|
9
|
+
Note, Terraspace automatically checks every second for new logs and adds them to be followed.
|
10
|
+
|
11
|
+
## View Logs
|
12
|
+
|
13
|
+
View last 10 lines of each log file.
|
14
|
+
|
15
|
+
terraspace logs up network # view up log on a specific stack
|
16
|
+
terraspace logs up # view all up logs
|
17
|
+
terraspace logs down # view all down logs
|
18
|
+
terraspace logs # view all logs: up, down, etc
|
19
|
+
|
20
|
+
By default, the logs command shows the last 10 lines for each log file. You can use the `-n` option to adjust this.
|
21
|
+
|
22
|
+
terraspace logs -n 2 # view last 2 lines of all logs: up, down, etc
|
23
|
+
|
24
|
+
To show all logs, use the `-a` option.
|
25
|
+
|
26
|
+
terraspace logs up -a
|
27
|
+
|
28
|
+
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`.
|
29
|
+
|
30
|
+
## Tail Logs
|
31
|
+
|
32
|
+
To tail logs, use the `-f` option.
|
33
|
+
|
34
|
+
terraspace logs up network -f # view up log on a specific stack
|
35
|
+
terraspace logs up -f # view all up logs
|
36
|
+
terraspace logs down -f # view all down logs
|
37
|
+
terraspace logs -f # view all logs: up, down, etc
|
38
|
+
|
39
|
+
## Timestamps
|
40
|
+
|
41
|
+
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, the timestamps are not shown.
|
42
|
+
|
43
|
+
terraspace logs up # timestamps will be shown in this case
|
44
|
+
terraspace logs up network # timestamps not be shown in this case
|
45
|
+
|
46
|
+
To show timestamps:
|
47
|
+
|
48
|
+
terraspace logs up network --timestamps
|
data/lib/terraspace/cli/init.rb
CHANGED
@@ -67,7 +67,7 @@ class Terraspace::CLI
|
|
67
67
|
mode = ENV['TS_INIT_MODE'] || Terraspace.config.init.mode
|
68
68
|
case mode.to_sym
|
69
69
|
when :auto
|
70
|
-
!
|
70
|
+
!already_init?
|
71
71
|
when :always
|
72
72
|
true
|
73
73
|
when :never
|
@@ -80,16 +80,12 @@ class Terraspace::CLI
|
|
80
80
|
# Traverse symlink dirs also: linux_amd64 is a symlink
|
81
81
|
# plugins/registry.terraform.io/hashicorp/google/3.39.0/linux_amd64/terraform-provider-google_v3.39.0_x5
|
82
82
|
#
|
83
|
-
|
84
|
-
# So init happens again during the second pass.
|
85
|
-
#
|
86
|
-
def already_initialized?
|
83
|
+
def already_init?
|
87
84
|
terraform = "#{@mod.cache_dir}/.terraform"
|
88
85
|
provider = Dir.glob("#{terraform}/**{,/*/**}/*").find do |path|
|
89
86
|
path.include?("terraform-provider-")
|
90
87
|
end
|
91
|
-
|
92
|
-
!!(provider && modules)
|
88
|
+
!!provider
|
93
89
|
end
|
94
90
|
end
|
95
91
|
end
|
data/lib/terraspace/cli/list.rb
CHANGED
@@ -6,7 +6,8 @@ class Terraspace::CLI
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def run
|
9
|
-
Dir.glob("{app,vendor}/{modules,stacks}/*").
|
9
|
+
dirs = Dir.glob("{app,vendor}/{modules,stacks}/*").select { |p| File.directory?(p) }
|
10
|
+
dirs.sort.each do |path|
|
10
11
|
if @type_dir
|
11
12
|
puts path if path.include?("/#{@type_dir}/")
|
12
13
|
else
|
data/lib/terraspace/cli/logs.rb
CHANGED
@@ -1,15 +1,112 @@
|
|
1
|
+
require "eventmachine"
|
2
|
+
require "eventmachine-tail"
|
3
|
+
|
1
4
|
class Terraspace::CLI
|
2
|
-
class Logs <
|
3
|
-
|
4
|
-
|
5
|
-
def
|
6
|
-
|
5
|
+
class Logs < Base
|
6
|
+
include Concern
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
super
|
10
|
+
@action, @stack = options[:action], options[:stack]
|
11
|
+
@action ||= '**'
|
12
|
+
@stack ||= '*'
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
check_logs!
|
17
|
+
if @options[:follow]
|
18
|
+
follow_logs
|
19
|
+
else
|
20
|
+
all_log_paths.each { |path| show_log(path) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def follow_logs
|
25
|
+
glob_path = "#{Terraspace.log_root}/#{@action}/#{@stack}.log"
|
26
|
+
Dir.glob(glob_path).each do |path|
|
27
|
+
puts "Following #{pretty(path)}".color(:purple)
|
28
|
+
end
|
29
|
+
EventMachine.run do
|
30
|
+
interval = Integer(ENV['TS_LOG_GLOB_INTERNAL'] || 1)
|
31
|
+
EventMachine::FileGlobWatchTail.new(glob_path, nil, interval) do |filetail, line|
|
32
|
+
puts line # always show timestamp in follow mode
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def show_log(path)
|
38
|
+
report_log(path)
|
39
|
+
lines = readlines(path)
|
40
|
+
lines = apply_limit(lines)
|
41
|
+
lines.each do |line|
|
42
|
+
puts format(line)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def report_log(path)
|
47
|
+
pretty_path = pretty(path)
|
48
|
+
if File.exist?(path)
|
49
|
+
puts "Showing: #{pretty_path}".color(:purple)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def format(line)
|
54
|
+
if timestamps
|
55
|
+
line
|
56
|
+
else
|
57
|
+
line.sub(/.*\]: /,'')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def all_log_paths
|
62
|
+
Dir.glob("#{Terraspace.log_root}/#{@action}/#{@stack}.log")
|
7
63
|
end
|
8
64
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
65
|
+
def check_logs!
|
66
|
+
return unless all_log_paths.empty?
|
67
|
+
puts "WARN: No logs found".color(:yellow)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Only need to check if both action and stack are provided. Otherwise the Dir.globs are used to discover the files
|
71
|
+
def check_log!
|
72
|
+
return unless single_log?
|
73
|
+
path = "#{Terraspace.log_root}/#{@action}/#{@stack}.log"
|
74
|
+
return if File.exist?(path)
|
75
|
+
puts "ERROR: Log file was not found: #{pretty(path)}".color(:red)
|
76
|
+
exit 1
|
77
|
+
end
|
78
|
+
|
79
|
+
def single_log?
|
80
|
+
@action != '**' && @stack != '*'
|
81
|
+
end
|
82
|
+
|
83
|
+
def apply_limit(lines)
|
84
|
+
return lines if all
|
85
|
+
left = limit * -1
|
86
|
+
lines[left..-1] || []
|
87
|
+
end
|
88
|
+
|
89
|
+
def all
|
90
|
+
if single_log?
|
91
|
+
@options[:all].nil? ? true : @options[:all]
|
92
|
+
else # multiple
|
93
|
+
@options[:all].nil? ? false : @options[:all]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def limit
|
98
|
+
@options[:limit].nil? ? 10 : @options[:limit]
|
99
|
+
end
|
100
|
+
|
101
|
+
def timestamps
|
102
|
+
if single_log?
|
103
|
+
@options[:timestamps].nil? ? false : @options[:timestamps]
|
104
|
+
else
|
105
|
+
@options[:timestamps].nil? ? true : @options[:timestamps]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
def pretty(path)
|
109
|
+
Terraspace::Util.pretty_path(path)
|
13
110
|
end
|
14
111
|
end
|
15
112
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Terraspace::CLI::
|
1
|
+
class Terraspace::CLI::Logs
|
2
2
|
module Concern
|
3
3
|
# Filters for lines that belong to the last ran process pid
|
4
4
|
def readlines(path)
|
@@ -17,6 +17,7 @@ class Terraspace::CLI::Log
|
|
17
17
|
|
18
18
|
# [2020-09-06T21:58:25 #11313 terraspace up b1]:
|
19
19
|
def pid(line)
|
20
|
+
return @options[:pid] if @options && @options[:pid] # Terraspace::All::Summary: doesnt have @options set
|
20
21
|
md = line.match(/:\d{2} #(\d+) /)
|
21
22
|
md[1] if md
|
22
23
|
end
|
@@ -6,10 +6,17 @@ class Terraspace::CLI::New
|
|
6
6
|
def build_gemfile(*list)
|
7
7
|
lines = []
|
8
8
|
list.each do |name|
|
9
|
-
|
10
|
-
lines << line
|
9
|
+
lines << gem_line(name)
|
11
10
|
end
|
12
11
|
lines.join("\n")
|
13
12
|
end
|
13
|
+
|
14
|
+
def gem_line(name)
|
15
|
+
if name == "terraspace"
|
16
|
+
%Q|gem "#{name}", '~> #{Terraspace::VERSION}'|
|
17
|
+
else
|
18
|
+
%Q|gem "#{name}"|
|
19
|
+
end
|
20
|
+
end
|
14
21
|
end
|
15
22
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Terraspace::Compiler::Dependencies
|
2
|
+
# This is a separate module specifically because the DSL also has an output method.
|
3
|
+
# The module allows us to include dependency related methods only within tfvars context for the DSL.
|
4
|
+
#
|
5
|
+
# 1. Only include this module to DSL tfvars context.
|
6
|
+
# So the output method works in tfvars .rb files works.
|
7
|
+
# At the same time, the DSL usage of output also works for normal main.tf files.
|
8
|
+
# Passing specs prove this.
|
9
|
+
# 2. For ERB, there's currently only one ERB context. So this module is included in all contexts.
|
10
|
+
# The builder only processes dependencies from tfvars, so these helpers are only respected there.
|
11
|
+
#
|
12
|
+
# Where the module is included in the code:
|
13
|
+
#
|
14
|
+
# 1. lib/terraspace/compiler/dsl/syntax/tfvar.rb
|
15
|
+
# 2. lib/terraspace/compiler/erb/helpers.rb
|
16
|
+
#
|
17
|
+
module Helpers
|
18
|
+
def output(identifier, options={})
|
19
|
+
Terraspace::Dependency::Helper::Output.new(@mod, identifier, options).result
|
20
|
+
end
|
21
|
+
alias_method :terraform_output, :output # backwards compatibility
|
22
|
+
|
23
|
+
def depends_on(*child_names, **options)
|
24
|
+
child_names.flatten!
|
25
|
+
child_names.map do |child_name|
|
26
|
+
each_depends_on(child_name, options)
|
27
|
+
end.join("\n")
|
28
|
+
end
|
29
|
+
|
30
|
+
def each_depends_on(child_name, options={})
|
31
|
+
Terraspace::Dependency::Helper::DependsOn.new(@mod, child_name, options).result
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Terraspace::Compiler::Dsl::Syntax::Helpers
|
2
2
|
module Common
|
3
3
|
extend Memoist
|
4
|
-
Fetcher = Terraspace::Terraform::RemoteState::Fetcher
|
5
|
-
Marker = Terraspace::Terraform::RemoteState::Marker
|
6
4
|
Meta = Terraspace::Compiler::Dsl::Meta
|
7
5
|
|
8
6
|
def var
|
@@ -25,29 +23,5 @@ module Terraspace::Compiler::Dsl::Syntax::Helpers
|
|
25
23
|
command = ["terraspace"] + args
|
26
24
|
command.join(separator)
|
27
25
|
end
|
28
|
-
|
29
|
-
def terraform_output(identifier, options={})
|
30
|
-
if @mod.resolved # dependencies have been resolved
|
31
|
-
Fetcher.new(@mod, identifier, options).output
|
32
|
-
else
|
33
|
-
Marker::Output.new(@mod, identifier, options).build
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def depends_on(*child_names, **options)
|
38
|
-
child_names.flatten!
|
39
|
-
child_names.map do |child_name|
|
40
|
-
each_depends_on(child_name, options)
|
41
|
-
end.join("\n")
|
42
|
-
end
|
43
|
-
|
44
|
-
def each_depends_on(child_name, options={})
|
45
|
-
if @mod.resolved # dependencies have been resolved
|
46
|
-
# Note: A generated line is not really needed. Dependencies are stored in memory. Added to assist users with debugging
|
47
|
-
"# #{@mod.name} depends on #{child_name}"
|
48
|
-
else
|
49
|
-
Marker::Output.new(@mod, child_name, options).build
|
50
|
-
end
|
51
|
-
end
|
52
26
|
end
|
53
27
|
end
|