Class: Terraspace::All::Runner

Inherits:
Base
  • Object
show all
Extended by:
Memoist
Includes:
Util
Defined in:
lib/terraspace/all/runner.rb

Instance Method Summary collapse

Methods included from Util::Pretty

#pretty_path, #pretty_time

Methods included from Util::Sure

#sure?

Methods included from Util::Logging

#logger

Constructor Details

#initialize(command, options = {}) ⇒ Runner

Returns a new instance of Runner.



6
7
8
9
# File 'lib/terraspace/all/runner.rb', line 6

def initialize(command, options={})
  @command, @options = command, options
  super(options)
end

Instance Method Details

#are_you_sure?Boolean

Returns:

  • (Boolean)


177
178
179
180
# File 'lib/terraspace/all/runner.rb', line 177

def are_you_sure?
  return true unless sure_command?
  sure? # from Util
end

#build_batchesObject



24
25
26
27
28
# File 'lib/terraspace/all/runner.rb', line 24

def build_batches
  @batches = Terraspace::Dependency::Resolver.new(@options).resolve
  @batches.reverse! if @command == "down"
  @batches
end

#build_modulesObject



65
66
67
68
# File 'lib/terraspace/all/runner.rb', line 65

def build_modules
  builder = Terraspace::Builder.new(@options.merge(mod: "placeholder", clean: true, quiet: true, include_stacks: :none))
  builder.build(modules: true)
end

#build_stack(name) ⇒ Object



70
71
72
73
74
# File 'lib/terraspace/all/runner.rb', line 70

def build_stack(name)
  include_stacks = @command == "down" ? :root_with_children : :root_only
  builder = Terraspace::Builder.new(@options.merge(mod: name, clean: false, quiet: true, include_stacks: include_stacks))
  builder.build(modules: false)
end

#command_map(name) ⇒ Object



169
170
171
172
173
174
175
# File 'lib/terraspace/all/runner.rb', line 169

def command_map(name)
  map = {
    up:   "apply",
    down: "destroy",
  }.stringify_keys
  map[name] || name
end

#deploy_batch(batch) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/terraspace/all/runner.rb', line 39

def deploy_batch(batch)
  @pids = {} # stores child processes pids. map of pid to mod_name, reset this list on each batch run
  concurrency = Terraspace.config.all.concurrency
  batch.sort_by(&:name).each_slice(concurrency) do |slice|
    slice.each do |node|
      if fork?
        pid = fork do
          deploy_stack(node)
        end
        @pids[pid] = node.name # store mod_name mapping
      else
        deploy_stack(node)
      end
    end
  end
  return unless fork?
  wait_for_child_proccess
  summarize     # also reports lower-level error info
  report_errors # reports finall errors and possibly exit
end

#deploy_batchesObject



30
31
32
33
34
35
36
37
# File 'lib/terraspace/all/runner.rb', line 30

def deploy_batches
  truncate_logs if ENV['TS_TRUNCATE_LOGS']
  build_modules
  @batches.each_with_index do |batch,i|
    logger.info "Batch Run #{i+1}:"
    deploy_batch(batch)
  end
end

#deploy_stack(node) ⇒ Object



60
61
62
63
# File 'lib/terraspace/all/runner.rb', line 60

def deploy_stack(node)
  build_stack(node.name)
  run_terraspace(node.name)
end

#exit_on_fail?Boolean

Precendence:

  1. env var

  2. cli

  3. config/app.rb setting

Returns:

  • (Boolean)


100
101
102
103
104
105
106
107
# File 'lib/terraspace/all/runner.rb', line 100

def exit_on_fail?
  return false if ENV['TS_EXIT_ON_FAIL'] == '0'
  if @options[:exit_on_fail].nil?
    Terraspace.config.all.exit_on_fail[@command]
  else
    @options[:exit_on_fail]
  end
end

#fork?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/terraspace/all/runner.rb', line 138

def fork?
  Terraspace.config.all.concurrency > 1
end

#log_path(mod_name) ⇒ Object



156
157
158
# File 'lib/terraspace/all/runner.rb', line 156

def log_path(mod_name)
  "#{Terraspace.config.log.root}/#{@command}/#{mod_name}.log"
end

#previewObject



20
21
22
# File 'lib/terraspace/all/runner.rb', line 20

def preview
  Preview.new(@command, @batches, @options).show
end

#report_errorsObject



85
86
87
88
89
90
91
92
93
94
# File 'lib/terraspace/all/runner.rb', line 85

def report_errors
  @errors.each do |pid|
    mod_name = @pids[pid]
    terraspace_command = terraspace_command(mod_name)
    logger.error "Error running: #{terraspace_command}. Fix the error above or check logs for the error.".color(:red)
  end
  unless @errors.empty?
    exit 2 if exit_on_fail?
  end
end

#runObject



11
12
13
14
15
16
17
18
# File 'lib/terraspace/all/runner.rb', line 11

def run
  time_took do
    @batches = build_batches
    preview
    are_you_sure?
    deploy_batches
  end
end

#run_terraspace(mod_name) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/terraspace/all/runner.rb', line 121

def run_terraspace(mod_name)
  set_log_path!(mod_name) if fork?
  name = command_map(@command)
  o = @options.merge(mod: mod_name, yes: true, build: false, input: false, log_to_stderr: true)
  o.merge!(quiet: false) if @command == "init" # noisy so can filter and summarize output
  case @command
  when "up"
    Terraspace::CLI::Up.new(o).run
  when "down"
    Terraspace::CLI::Down.new(o).run
  when "plan"
    Terraspace::CLI::Plan.new(o).run
  else
    Terraspace::CLI::Commander.new(name, o).run
  end
end

#set_log_path!(mod_name) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/terraspace/all/runner.rb', line 142

def set_log_path!(mod_name)
  command = terraspace_command(mod_name)
  path = log_path(mod_name)
  pretty_path = Terraspace::Util.pretty_path(path)
  logger.info "Running: #{command.bright} Logs: #{pretty_path}"

  FileUtils.mkdir_p(File.dirname(path))
  logger = Terraspace::Logger.new(path)
  logger.level = Terraspace.config.logger.level # match the level that user configured
  logger.formatter = Terraspace.config.logger.formatter # match the level that user configured
  logger.progname = command
  Terraspace.logger = logger
end

#summarizeObject



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/terraspace/all/runner.rb', line 109

def summarize
  @pids.each do |_, mod_name|
    data = {
      command: @command,
      log_path: log_path(mod_name),
      terraspace_command: terraspace_command(mod_name),
    }
    # Its possible for log file to not get created if RemoteState::Fetcher#validate! fails
    Summary.new(data).run if File.exist?(data[:log_path])
  end
end

#sure_command?Boolean

Returns:

  • (Boolean)


182
183
184
# File 'lib/terraspace/all/runner.rb', line 182

def sure_command?
  %w[up down].include?(@command)
end

#terraspace_command(name) ⇒ Object



165
166
167
# File 'lib/terraspace/all/runner.rb', line 165

def terraspace_command(name)
  "terraspace #{@command} #{name}"
end

#time_tookObject



186
187
188
189
190
191
# File 'lib/terraspace/all/runner.rb', line 186

def time_took
  t1 = Time.now
  yield
  t2 = Time.now
  logger.info "Time took: #{pretty_time(t2-t1)}"
end

#truncate_logsObject



160
161
162
163
# File 'lib/terraspace/all/runner.rb', line 160

def truncate_logs
  logs = Terraspace::CLI::Log::Tasks.new(mute: true)
  logs.truncate
end

#wait_for_child_proccessObject



76
77
78
79
80
81
82
83
# File 'lib/terraspace/all/runner.rb', line 76

def wait_for_child_proccess
  @errors = [] # stores child processes pids that errored
  @pids.each do |pid, _|
    pid, status = Process.wait2(pid)
    success = status.exitstatus == 0
    @errors << pid unless success
  end
end