cem_acpt 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -1
  3. data/Gemfile.lock +42 -14
  4. data/README.md +8 -0
  5. data/cem_acpt.gemspec +3 -1
  6. data/exe/cem_acpt_image +0 -0
  7. data/lib/cem_acpt/action_result.rb +85 -0
  8. data/lib/cem_acpt/cli.rb +46 -22
  9. data/lib/cem_acpt/config/base.rb +27 -4
  10. data/lib/cem_acpt/config/cem_acpt.rb +0 -17
  11. data/lib/cem_acpt/config/cem_acpt_image.rb +2 -17
  12. data/lib/cem_acpt/goss/api.rb +8 -2
  13. data/lib/cem_acpt/image_builder.rb +82 -64
  14. data/lib/cem_acpt/logging.rb +41 -30
  15. data/lib/cem_acpt/platform.rb +4 -5
  16. data/lib/cem_acpt/provision/terraform/linux.rb +17 -1
  17. data/lib/cem_acpt/provision/terraform/terraform_cmd.rb +181 -0
  18. data/lib/cem_acpt/provision/terraform/windows.rb +9 -0
  19. data/lib/cem_acpt/provision/terraform.rb +34 -47
  20. data/lib/cem_acpt/provision.rb +1 -1
  21. data/lib/cem_acpt/puppet_helpers.rb +1 -1
  22. data/lib/cem_acpt/test_data.rb +3 -3
  23. data/lib/cem_acpt/test_runner/log_formatter/error_formatter.rb +33 -0
  24. data/lib/cem_acpt/test_runner/log_formatter.rb +10 -1
  25. data/lib/cem_acpt/test_runner.rb +151 -52
  26. data/lib/cem_acpt/utils/ssh.rb +2 -2
  27. data/lib/cem_acpt/utils/terminal.rb +1 -5
  28. data/lib/cem_acpt/utils/winrm_runner.rb +160 -0
  29. data/lib/cem_acpt/utils.rb +41 -1
  30. data/lib/cem_acpt/version.rb +1 -1
  31. data/lib/cem_acpt.rb +51 -21
  32. data/lib/terraform/gcp/linux/goss/puppet_idempotent.yaml +2 -2
  33. data/lib/terraform/gcp/linux/goss/puppet_noop.yaml +1 -1
  34. data/lib/terraform/gcp/windows/goss/puppet_idempotent.yaml +9 -0
  35. data/lib/terraform/gcp/windows/goss/puppet_noop.yaml +12 -0
  36. data/lib/terraform/gcp/windows/main.tf +115 -0
  37. metadata +49 -8
@@ -2,11 +2,11 @@
2
2
 
3
3
  require 'fileutils'
4
4
  require 'json'
5
- require 'ruby-terraform'
6
5
  require_relative 'logging'
7
6
  require_relative 'platform'
8
7
  require_relative 'utils'
9
8
  require_relative 'version'
9
+ require_relative 'provision/terraform/terraform_cmd'
10
10
  require_relative 'image_builder/exec'
11
11
  require_relative 'image_builder/provision_commands'
12
12
 
@@ -14,7 +14,17 @@ module CemAcpt
14
14
  # This module contains the classes and methods for building test node images
15
15
  module ImageBuilder
16
16
  def self.build_images(config)
17
- TerraformBuilder.new(config).run
17
+ include CemAcpt::Logging
18
+
19
+ builder = TerraformBuilder.new(config)
20
+ builder.run
21
+ logger.info('CemAcpt::ImageBuilder') { "Image builder finished after #{builder.duration} seconds" }
22
+ if builder.exit_code.zero?
23
+ logger.info('CemAcpt::ImageBuilder') { 'Image builder finished successfully' }
24
+ else
25
+ logger.error('CemAcpt::ImageBuilder') { "Image builder finished with exit code #{builder.exit_code}" }
26
+ end
27
+ exit builder.exit_code
18
28
  end
19
29
 
20
30
  # This class builds test node images using Terraform
@@ -27,6 +37,8 @@ module CemAcpt
27
37
  DEFAULT_VARS_FILE = 'imagevars.json'
28
38
  include CemAcpt::Logging
29
39
 
40
+ attr_reader :exit_code, :duration
41
+
30
42
  def initialize(config)
31
43
  @config = config
32
44
  @image_terraform_dir = File.join(config.get('terraform.dir'), 'image', config.get('platform.name'))
@@ -36,43 +48,56 @@ module CemAcpt
36
48
  @linux_tfvars = { node_data: {} }
37
49
  @windows_tfvars = { node_data: {} }
38
50
  @duration = 0
39
- @exit_code = 0
51
+ @exit_code = 1
40
52
  @private_key = nil
41
53
  @public_key = nil
42
54
  end
43
55
 
44
56
  def run
45
57
  @start_time = Time.now
46
- logger.with_ci_group("CemAcptImage v#{CemAcpt::VERSION} run started at #{@start_time}") do
47
- @all_tfvars = new_tfvars(@config)
48
- @linux_tfvars, @windows_tfvars = divide_tfvars_by_os(@all_tfvars)
49
- image_types = []
50
- image_types << [@linux_tfvars, 'linux'] unless no_linux?
51
- image_types << [@windows_tfvars, 'windows'] unless no_windows?
52
- return dry_run(image_types) if @config.get('dry_run')
53
-
54
- @working_dir = new_working_dir
55
- logger.info('CemAcptImage') { "Using working directory: #{@working_dir}..." }
56
- keep_terminal_alive
57
- save_vars_to_file!('linux', @linux_tfvars)
58
- save_vars_to_file!('windows', @windows_tfvars)
59
- terraform_init
60
- image_types.each do |tfvars, os_str|
61
- terraform_plan(os_str, tfvars, DEFAULT_PLAN_NAME)
62
- begin
63
- terraform_apply(os_str, DEFAULT_PLAN_NAME)
64
- output = JSON.parse(terraform_output(os_str, 'node-data', json: true))
65
- output.each do |instance_name, data|
66
- logger.info('CemAcptImage') { "Stopping instance #{instance_name}..." }
67
- @exec.run('compute', 'instances', 'stop', instance_name)
58
+ logger.start_ci_group("CemAcptImage v#{CemAcpt::VERSION} run started at #{@start_time}")
59
+ @all_tfvars = new_tfvars(@config)
60
+ @linux_tfvars, @windows_tfvars = divide_tfvars_by_os(@all_tfvars)
61
+ image_types = []
62
+ image_types << [@linux_tfvars, 'linux'] unless no_linux?
63
+ image_types << [@windows_tfvars, 'windows'] unless no_windows?
64
+ return dry_run(image_types) if @config.get('dry_run')
65
+
66
+ @working_dir = new_working_dir
67
+ logger.info('CemAcpt::ImageBuilder') { "Using working directory: #{@working_dir}..." }
68
+ keep_terminal_alive
69
+ save_vars_to_file!('linux', @linux_tfvars)
70
+ save_vars_to_file!('windows', @windows_tfvars)
71
+ terraform_init
72
+ image_types.each do |tfvars, os_str|
73
+ terraform_plan(os_str, tfvars, DEFAULT_PLAN_NAME)
74
+ begin
75
+ terraform_apply(os_str, DEFAULT_PLAN_NAME)
76
+ output = JSON.parse(terraform_output(os_str, 'node-data', json: true))
77
+ output.each do |instance_name, data|
78
+ logger.info('CemAcpt::ImageBuilder') { "Stopping instance #{instance_name}..." }
79
+ @exec.run('compute', 'instances', 'stop', instance_name)
80
+ unless @config.get('no_build_images')
68
81
  deprecate_old_images_in_family(data['image_family'])
69
82
  create_image_from_disk(data['disk_link'], image_name_from_image_family(data['image_family']), data['image_family'])
70
83
  end
71
- ensure
72
- terraform_destroy(os_str, tfvars)
84
+ @exit_code = 0
73
85
  end
86
+ ensure
87
+ terraform_destroy(os_str, tfvars) unless @config.get('no_destroy_nodes')
74
88
  end
75
89
  end
90
+ rescue StandardError => e
91
+ logger.error('CemAcpt::ImageBuilder') { "Image builder failed with error: #{e}" }
92
+ logger.verbose('CemAcpt::ImageBuilder') { e.backtrace.join("\n") }
93
+ @exit_code = 1
94
+ ensure
95
+ if @start_time
96
+ @duration = Time.now - @start_time
97
+ else
98
+ @duration = 0
99
+ end
100
+ logger.end_ci_group
76
101
  end
77
102
 
78
103
  private
@@ -84,21 +109,21 @@ module CemAcpt
84
109
  end
85
110
 
86
111
  def deprecate_old_images_in_family(image_family)
87
- logger.info('CemAcptImage') { "Deprecating old images in family #{image_family}..." }
112
+ logger.info('CemAcpt::ImageBuilder') { "Deprecating old images in family #{image_family}..." }
88
113
  images = @exec.run('compute', 'images', 'list', '--project', @config.get('platform.project'), '--filter', "family:#{image_family}")
89
114
  images.each do |image|
90
115
  next unless image['status'] == 'READY'
91
116
 
92
- logger.info('CemAcptImage') { "Deprecating image #{image['name']}..." }
117
+ logger.info('CemAcpt::ImageBuilder') { "Deprecating image #{image['name']}..." }
93
118
  @exec.run('compute', 'images', 'deprecate', image['name'], '--state', 'DEPRECATED', '--delete-in', '1d', '--project', @config.get('platform.project'))
94
119
  end
95
120
  end
96
121
 
97
122
  def create_image_from_disk(disk_link, image_name, image_family)
98
- logger.info('CemAcptImage') { "Creating image from disk #{disk_link}..." }
123
+ logger.info('CemAcpt::ImageBuilder') { "Creating image from disk #{disk_link}..." }
99
124
  @exec.run('compute', 'images', 'create', image_name, '--family', image_family,
100
125
  '--source-disk', disk_link, '--project', @config.get('platform.project'))
101
- logger.info('CemAcptImage') { "Image #{image_name} created for family #{image_family}"}
126
+ logger.info('CemAcpt::ImageBuilder') { "Image #{image_name} created for family #{image_family}"}
102
127
  end
103
128
 
104
129
  def no_windows?
@@ -110,29 +135,22 @@ module CemAcpt
110
135
  end
111
136
 
112
137
  def dry_run(image_types)
113
- logger.info('CemAcptImage') { 'Dry run mode enabled. No images will be built.' }
138
+ logger.info('CemAcpt::ImageBuilder') { 'Dry run mode enabled. No images will be built.' }
114
139
  image_types.each do |tfvars, os_str|
115
- logger.info('CemAcptImage') { "Dry run for #{os_str}..." }
116
- logger.info('CemAcptImage') { "Terraform vars:\n#{JSON.pretty_generate(tfvars)}" }
140
+ logger.info('CemAcpt::ImageBuilder') { "Dry run for #{os_str}..." }
141
+ logger.info('CemAcpt::ImageBuilder') { "Terraform vars:\n#{JSON.pretty_generate(tfvars)}" }
117
142
  end
143
+ @exit_code = 0
118
144
  end
119
145
 
120
146
  def terraform
121
- return @terraform if defined?(@terraform)
122
-
123
- RubyTerraform.configure do |c|
124
- c.logger = logger
125
- c.stdout = logger
126
- c.stderr = logger
127
- end
128
- @terraform = RubyTerraform
129
- @terraform
147
+ @terraform ||= CemAcpt::Provision::TerraformCmd.new(@image_terraform_dir, @environment)
130
148
  end
131
149
 
132
150
  def new_environment(config)
133
151
  env = (config.get('terraform.environment') || {})
134
152
  env['CLOUDSDK_PYTHON_SITEPACKAGES'] = '1' # This is needed for gcloud to use numpy
135
- logger.verbose('ImageBuilder') { "Using environment:\n#{JSON.pretty_generate(env)}" }
153
+ logger.verbose('CemAcpt::ImageBuilder') { "Using environment:\n#{JSON.pretty_generate(env)}" }
136
154
  env
137
155
  end
138
156
 
@@ -177,7 +195,7 @@ module CemAcpt
177
195
  return unless block_given?
178
196
 
179
197
  if no_os_str?(os_str)
180
- logger.debug('ImageBuilder') { "Skipping #{os_str} because no_#{os_str} is true" }
198
+ logger.debug('CemAcpt::ImageBuilder') { "Skipping #{os_str} because no_#{os_str} is true" }
181
199
  return
182
200
  end
183
201
 
@@ -190,7 +208,7 @@ module CemAcpt
190
208
  def terraform_init
191
209
  raise 'Cannot initialize Terraform, both no_linux and no_windows are true' if no_linux? && no_windows?
192
210
 
193
- logger.debug('ImageBuilder') { 'Initializing Terraform' }
211
+ logger.debug('CemAcpt::ImageBuilder') { 'Initializing Terraform' }
194
212
  in_os_dir('linux') do
195
213
  terraform.init({ input: false, no_color: true })
196
214
  end
@@ -201,37 +219,37 @@ module CemAcpt
201
219
 
202
220
  def terraform_plan(os_dir, tfvars, plan_name)
203
221
  in_os_dir(os_dir) do
204
- logger.debug('ImageBuilder') { "Creating Terraform plan #{plan_name} for #{os_dir}" }
205
- logger.verbose('ImageBuilder') { "Using vars:\n#{JSON.pretty_generate(tfvars)}" }
222
+ logger.debug('CemAcpt::ImageBuilder') { "Creating Terraform plan #{plan_name} for #{os_dir}" }
223
+ logger.verbose('CemAcpt::ImageBuilder') { "Using vars:\n#{JSON.pretty_generate(tfvars)}" }
206
224
  terraform.plan({ input: false, no_color: true, plan: plan_name, vars: tfvars }, { environment: environment })
207
225
  end
208
226
  end
209
227
 
210
228
  def terraform_apply(os_dir, plan_name)
211
229
  in_os_dir(os_dir) do
212
- logger.debug('ImageBuilder') { "Applying Terraform plan #{plan_name} for #{os_dir}" }
230
+ logger.debug('CemAcpt::ImageBuilder') { "Applying Terraform plan #{plan_name} for #{os_dir}" }
213
231
  terraform.apply({ input: false, no_color: true, plan: plan_name }, { environment: environment })
214
232
  end
215
233
  end
216
234
 
217
235
  def terraform_output(os_dir, output_name, json: true)
218
236
  in_os_dir(os_dir) do
219
- logger.debug('ImageBuilder') { "Getting Terraform output #{output_name} for #{os_dir}" }
237
+ logger.debug('CemAcpt::ImageBuilder') { "Getting Terraform output #{output_name} for #{os_dir}" }
220
238
  terraform.output({ no_color: true, json: json, name: output_name }, { environment: environment })
221
239
  end
222
240
  end
223
241
 
224
242
  def terraform_destroy(os_dir, tfvars)
225
243
  in_os_dir(os_dir) do
226
- logger.debug('ImageBuilder') { "Destroying Terraform resources for #{os_dir}" }
227
- logger.verbose('ImageBuilder') { "Using vars:\n#{JSON.pretty_generate(tfvars)}" }
244
+ logger.debug('CemAcpt::ImageBuilder') { "Destroying Terraform resources for #{os_dir}" }
245
+ logger.verbose('CemAcpt::ImageBuilder') { "Using vars:\n#{JSON.pretty_generate(tfvars)}" }
228
246
  terraform.destroy({ auto_approve: true, input: false, no_color: true, vars: tfvars }, { environment: environment })
229
247
  end
230
248
  end
231
249
 
232
250
  def terraform_show(os_dir)
233
251
  in_os_dir(os_dir) do
234
- logger.debug('ImageBuilder') { "Showing Terraform state for #{os_dir}" }
252
+ logger.debug('CemAcpt::ImageBuilder') { "Showing Terraform state for #{os_dir}" }
235
253
  terraform.show({ no_color: true }, { environment: environment })
236
254
  end
237
255
  end
@@ -262,7 +280,7 @@ module CemAcpt
262
280
  windows_image: windows_image?(image[:os]),
263
281
  )
264
282
  end
265
- logger.verbose('ImageBuilder') { "All Terraform variables:\n#{JSON.pretty_generate(tfvars)}" }
283
+ logger.verbose('CemAcpt::ImageBuilder') { "All Terraform variables:\n#{JSON.pretty_generate(tfvars)}" }
266
284
  tfvars
267
285
  end
268
286
 
@@ -273,8 +291,8 @@ module CemAcpt
273
291
  linux_tfvars[:node_data] = linux_node_data
274
292
  windows_tfvars = tfvars.dup
275
293
  windows_tfvars[:node_data] = windows_node_data
276
- logger.verbose('ImageBuilder') { "Linux Terraform variables:\n#{JSON.pretty_generate(linux_tfvars)}" }
277
- logger.verbose('ImageBuilder') { "Windows Terraform variables:\n#{JSON.pretty_generate(windows_tfvars)}" }
294
+ logger.verbose('CemAcpt::ImageBuilder') { "Linux Terraform variables:\n#{JSON.pretty_generate(linux_tfvars)}" }
295
+ logger.verbose('CemAcpt::ImageBuilder') { "Windows Terraform variables:\n#{JSON.pretty_generate(windows_tfvars)}" }
278
296
  [linux_tfvars, windows_tfvars]
279
297
  end
280
298
 
@@ -283,10 +301,10 @@ module CemAcpt
283
301
  end
284
302
 
285
303
  def save_vars_to_file!(prefix, vars)
286
- logger.debug('ImageBuilder') { "Saving vars to file #{File.join(@working_dir, "#{prefix}_#{DEFAULT_VARS_FILE}")}" }
304
+ logger.debug('CemAcpt::ImageBuilder') { "Saving vars to file #{File.join(@working_dir, "#{prefix}_#{DEFAULT_VARS_FILE}")}" }
287
305
  File.write(File.join(@working_dir, "#{prefix}_#{DEFAULT_VARS_FILE}"), vars.to_json)
288
306
  rescue StandardError => e
289
- logger.error('ImageBuilder') { 'Error saving vars to file' }
307
+ logger.error('CemAcpt::ImageBuilder') { 'Error saving vars to file' }
290
308
  raise e
291
309
  end
292
310
 
@@ -294,25 +312,25 @@ module CemAcpt
294
312
  unless Dir.exist?(@image_terraform_dir)
295
313
  raise "Image Terraform directory #{@image_terraform_dir} does not exist"
296
314
  end
297
- logger.debug('ImageBuilder') { "Creating new working directory in #{@image_terraform_dir}" }
315
+ logger.debug('CemAcpt::ImageBuilder') { "Creating new working directory in #{@image_terraform_dir}" }
298
316
  working_dir = File.join(@image_terraform_dir, "image_builder_#{Time.now.to_i}")
299
317
  FileUtils.mkdir_p(working_dir)
300
- logger.verbose('ImageBuilder') { "Created working directory #{working_dir}" }
318
+ logger.verbose('CemAcpt::ImageBuilder') { "Created working directory #{working_dir}" }
301
319
  FileUtils.cp_r(File.join(@image_terraform_dir, 'linux'), working_dir)
302
320
  FileUtils.cp_r(File.join(@image_terraform_dir, 'windows'), working_dir)
303
- logger.verbose('ImageBuilder') { "Copied Terraform files from #{@image_terraform_dir}/(linux|windows) to #{working_dir}" }
321
+ logger.verbose('CemAcpt::ImageBuilder') { "Copied Terraform files from #{@image_terraform_dir}/(linux|windows) to #{working_dir}" }
304
322
  if File.exist?(@all_tfvars[:private_key])
305
323
  FileUtils.cp(@all_tfvars[:private_key], working_dir)
306
324
  @private_key = File.join(working_dir, File.basename(@all_tfvars[:private_key]))
307
- logger.verbose('ImageBuilder') { "Copied private key #{@all_tfvars[:private_key]} to #{working_dir}" }
325
+ logger.verbose('CemAcpt::ImageBuilder') { "Copied private key #{@all_tfvars[:private_key]} to #{working_dir}" }
308
326
  end
309
327
  if File.exist?(@all_tfvars[:public_key])
310
328
  FileUtils.cp(@all_tfvars[:public_key], working_dir)
311
329
  @public_key = File.join(working_dir, File.basename(@all_tfvars[:public_key]))
312
- logger.verbose('ImageBuilder') { "Copied public key #{@all_tfvars[:public_key]} to #{working_dir}" }
330
+ logger.verbose('CemAcpt::ImageBuilder') { "Copied public key #{@all_tfvars[:public_key]} to #{working_dir}" }
313
331
  end
314
332
 
315
- logger.verbose('ImageBuilder') { "Content of #{working_dir}:\n#{Dir.glob(File.join(working_dir, '*')).join("\n")}" }
333
+ logger.verbose('CemAcpt::ImageBuilder') { "Content of #{working_dir}:\n#{Dir.glob(File.join(working_dir, '*')).join("\n")}" }
316
334
  working_dir
317
335
  end
318
336
  end
@@ -13,7 +13,7 @@ module CemAcpt
13
13
  'error' => ::Logger::ERROR,
14
14
  'fatal' => ::Logger::FATAL,
15
15
  'unknown' => ::Logger::UNKNOWN,
16
- }
16
+ }.freeze
17
17
 
18
18
  # Delegator class for when you want to log to multiple devices
19
19
  # at the same time, such as STDOUT and a file.
@@ -28,34 +28,39 @@ module CemAcpt
28
28
  def self.from_logger_configs(configs)
29
29
  return if configs.nil? || configs.empty?
30
30
 
31
- loggers = configs.map do |config|
31
+ logger_instances = configs.map do |config|
32
32
  CemAcpt::Logging::Logger.new(config[:logdev],
33
33
  config[:shift_age],
34
34
  config[:shift_size],
35
35
  **config.reject { |k, _| [:logdev, :shift_age, :shift_size].include?(k) })
36
36
  end
37
- new(*loggers)
37
+ new(*logger_instances)
38
38
  end
39
39
 
40
- def initialize(*loggers)
41
- @loggers = loggers
40
+ def initialize(*logger_instances)
41
+ @loggers = logger_instances
42
42
  end
43
43
 
44
44
  def logger_configs
45
- @loggers.map(&:config_hash)
45
+ loggers.map(&:config_hash)
46
46
  end
47
47
 
48
48
  def method_missing(m, *args, &block)
49
- if @loggers.all? { |l| l.respond_to?(m) }
50
- @loggers.map { |l| l.send(m, *args, &block) }
49
+ if loggers.all? { |l| l.respond_to?(m) }
50
+ loggers.map { |l| l.send(m, *args, &block) }
51
51
  else
52
52
  super
53
53
  end
54
54
  end
55
55
 
56
56
  def respond_to_missing?(m, include_private = false)
57
- @loggers.all? { |l| l.respond_to?(m) } || super
57
+ loggers.all? { |l| l.respond_to?(m) } || super
58
58
  end
59
+
60
+ private
61
+
62
+ # Basically just for making testing easier
63
+ attr_reader :loggers
59
64
  end
60
65
 
61
66
  # Delagator class for the standard Ruby Logger class.
@@ -89,55 +94,63 @@ module CemAcpt
89
94
  end
90
95
 
91
96
  def debug(progname = nil, &block)
92
- return if log_trap_context('debug', progname, &block)
93
- return if log_ci_mode('debug', progname, &block)
97
+ severity = 'debug'
98
+ return log_trap_context(severity, progname, &block) if log_trap_context?(severity)
99
+ return log_ci_mode(severity, progname, &block) if log_ci_mode?(severity)
94
100
 
95
101
  super
96
102
  end
97
103
 
98
104
  def info(progname = nil, &block)
99
- return if log_trap_context('info', progname, &block)
100
- return if log_ci_mode('info', progname, &block)
105
+ severity = 'info'
106
+ return log_trap_context(severity, progname, &block) if log_trap_context?(severity)
107
+ return log_ci_mode(severity, progname, &block) if log_ci_mode?(severity)
101
108
 
102
109
  super
103
110
  end
104
111
 
105
112
  def warn(progname = nil, &block)
106
- return if log_trap_context('warn', progname, &block)
107
- return if log_ci_mode('warn', progname, &block)
113
+ severity = 'warn'
114
+ return log_trap_context(severity, progname, &block) if log_trap_context?(severity)
115
+ return log_ci_mode(severity, progname, &block) if log_ci_mode?(severity)
108
116
 
109
117
  super
110
118
  end
111
119
 
112
120
  def error(progname = nil, &block)
113
- return if log_trap_context('error', progname, &block)
114
- return if log_ci_mode('error', progname, &block)
121
+ severity = 'error'
122
+ return log_trap_context(severity, progname, &block) if log_trap_context?(severity)
123
+ return log_ci_mode(severity, progname, &block) if log_ci_mode?(severity)
115
124
 
116
125
  super
117
126
  end
118
127
 
119
128
  def fatal(progname = nil, &block)
120
- return if log_trap_context('fatal', progname, &block)
121
- return if log_ci_mode('fatal', progname, &block)
129
+ severity = 'fatal'
130
+ return log_trap_context(severity, progname, &block) if log_trap_context?(severity)
131
+ return log_ci_mode(severity, progname, &block) if log_ci_mode?(severity)
122
132
 
123
133
  super
124
134
  end
125
135
 
126
- # Wraps the given block in a Github Actions group if in CI mode
127
- # @param name [String] the name of the group
128
- def with_ci_group(name)
136
+ def start_ci_group(name)
129
137
  if @ci_mode
130
138
  self.<< "::group::#{name}\n"
131
139
  else
132
140
  info(name)
133
141
  end
134
- yield
135
- ensure
142
+ end
143
+
144
+ def end_ci_group
136
145
  self.<< "::endgroup::\n" if @ci_mode
137
146
  end
138
147
 
139
148
  private
140
149
 
150
+ def log_trap_context?(severity)
151
+ @trap_context && level <= LEVEL_MAP[severity]
152
+ end
153
+
141
154
  # Can't use the standard Logger methods when in trap context
142
155
  # because they don't work. So we have to write directly to the
143
156
  # raw logdev. Unlike the standard Logger methods, there is no
@@ -145,8 +158,6 @@ module CemAcpt
145
158
  # This is necessary in the trap context because using a Mutex
146
159
  # lock in a trap context will cause a deadlock.
147
160
  def log_trap_context(severity, progname = nil, &block)
148
- return false unless @trap_context && level <= LEVEL_MAP[severity]
149
-
150
161
  if @raw_logdev.respond_to?(:puts)
151
162
  @raw_logdev.puts(ci_format(severity, false, progname, &block))
152
163
  elsif @raw_logdev.respond_to?(:write)
@@ -155,7 +166,10 @@ module CemAcpt
155
166
  # Default to logging to STDERR
156
167
  $stderr.puts(ci_format(severity, false, progname, &block))
157
168
  end
158
- true
169
+ end
170
+
171
+ def log_ci_mode?(severity)
172
+ @ci_mode && level <= LEVEL_MAP[severity]
159
173
  end
160
174
 
161
175
  # CI mode uses << instead of the standard Logger methods
@@ -164,10 +178,7 @@ module CemAcpt
164
178
  # with a standard Logger, the CI mode messages are still
165
179
  # formatted correctly.
166
180
  def log_ci_mode(severity, progname = nil, &block)
167
- return false unless @ci_mode && level <= LEVEL_MAP[severity]
168
-
169
181
  self.<<(ci_format(severity, true, progname, &block))
170
- true
171
182
  end
172
183
 
173
184
  # Formats the log message for CI mode, translating the severity
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent-ruby'
4
3
  require_relative 'logging'
5
4
 
6
5
  # CemAcpt::Platform manages creating and configring platform specific objects
@@ -25,7 +24,7 @@ module CemAcpt::Platform
25
24
  raise Error, 'run_data must include a :test_data key' unless run_data.key?(:test_data)
26
25
  raise Error, 'run_data[:test_data] must be an Array' unless run_data[:test_data].is_a?(Array)
27
26
 
28
- logger.info "Using #{platform} for #{run_data[:test_data].length} tests..."
27
+ logger.info('CemAcpt::Platform') { "Using #{platform} for #{run_data[:test_data].length} tests..." }
29
28
  run_data[:test_data].dup.each_with_object([]) do |single_test_data, ary|
30
29
  ary << new_test_platform_object(platform, config, single_test_data, **run_data.reject { |k, _| k == :test_data })
31
30
  end
@@ -53,7 +52,7 @@ module CemAcpt::Platform
53
52
  File.basename(file, '.rb') unless file.end_with?('base.rb')
54
53
  end
55
54
  @platforms.compact!
56
- logger.debug "Discovered platform(s): #{@platforms}"
55
+ logger.debug('CemAcpt::Platform') { "Discovered platform(s): #{@platforms}" }
57
56
  @platforms
58
57
  end
59
58
 
@@ -83,7 +82,7 @@ module CemAcpt::Platform
83
82
  require_relative 'platform/base'
84
83
  # If the class has already been defined, we can just use it.
85
84
  if Object.const_defined?(class_name)
86
- logger.debug "Using existing platform class #{class_name}"
85
+ logger.debug('CemAcpt::Platform') { "Using existing platform class #{class_name}" }
87
86
  klass = Object.const_get(class_name)
88
87
  else
89
88
  # Otherwise, we need to create the class. We do this by setting
@@ -110,7 +109,7 @@ module CemAcpt::Platform
110
109
  end,
111
110
  )
112
111
  end
113
- logger.debug "Using platform class: #{klass.inspect}"
112
+ logger.debug('CemAcpt::Platform') { "Using platform class: #{klass.inspect}" }
114
113
  klass
115
114
  end
116
115
  end
@@ -40,7 +40,23 @@ module CemAcpt
40
40
  commands << "sudo systemctl start #{file} && sudo systemctl enable #{file}"
41
41
  end
42
42
  end
43
- commands << "sudo #{puppet_bin_path} apply #{destination_provision_directory}/#{puppet_manifest_file}"
43
+ commands << apply_command
44
+ end
45
+
46
+ private
47
+
48
+ def apply_command
49
+ cmd = [
50
+ 'sudo',
51
+ puppet_bin_path,
52
+ 'apply',
53
+ '--logdest',
54
+ 'console,/opt/cem_acpt/provision_apply.log',
55
+ ]
56
+ cmd << '--debug' if @config.debug? && !@config.get('puppet.no_debug')
57
+ cmd << '--verbose' if @config.verbose? && !@config.get('puppet.no_verbose')
58
+ cmd << "#{destination_provision_directory}/#{puppet_manifest_file}"
59
+ cmd.join(' ')
44
60
  end
45
61
  end
46
62
  end