cem_acpt 0.2.6-universal-java-17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/CODEOWNERS +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +93 -0
- data/README.md +150 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/cem_acpt.gemspec +39 -0
- data/exe/cem_acpt +84 -0
- data/lib/cem_acpt/bootstrap/bootstrapper.rb +206 -0
- data/lib/cem_acpt/bootstrap/operating_system/rhel_family.rb +129 -0
- data/lib/cem_acpt/bootstrap/operating_system.rb +17 -0
- data/lib/cem_acpt/bootstrap.rb +12 -0
- data/lib/cem_acpt/context.rb +153 -0
- data/lib/cem_acpt/core_extensions.rb +108 -0
- data/lib/cem_acpt/image_name_builder.rb +104 -0
- data/lib/cem_acpt/logging.rb +351 -0
- data/lib/cem_acpt/platform/base/cmd.rb +71 -0
- data/lib/cem_acpt/platform/base.rb +78 -0
- data/lib/cem_acpt/platform/gcp/cmd.rb +345 -0
- data/lib/cem_acpt/platform/gcp/compute.rb +332 -0
- data/lib/cem_acpt/platform/gcp.rb +85 -0
- data/lib/cem_acpt/platform/vmpooler.rb +24 -0
- data/lib/cem_acpt/platform.rb +103 -0
- data/lib/cem_acpt/puppet_helpers.rb +39 -0
- data/lib/cem_acpt/rspec_utils.rb +242 -0
- data/lib/cem_acpt/shared_objects.rb +537 -0
- data/lib/cem_acpt/spec_helper_acceptance.rb +184 -0
- data/lib/cem_acpt/test_data.rb +146 -0
- data/lib/cem_acpt/test_runner/run_handler.rb +187 -0
- data/lib/cem_acpt/test_runner/runner.rb +210 -0
- data/lib/cem_acpt/test_runner/runner_result.rb +103 -0
- data/lib/cem_acpt/test_runner.rb +10 -0
- data/lib/cem_acpt/utils.rb +144 -0
- data/lib/cem_acpt/version.rb +5 -0
- data/lib/cem_acpt.rb +34 -0
- data/sample_config.yaml +58 -0
- metadata +218 -0
@@ -0,0 +1,351 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module CemAcpt
|
6
|
+
# Logging for CemAcpt
|
7
|
+
module Logging
|
8
|
+
LEVEL_MAP = {
|
9
|
+
'debug' => Logger::DEBUG,
|
10
|
+
'info' => Logger::INFO,
|
11
|
+
'warn' => Logger::WARN,
|
12
|
+
'error' => Logger::ERROR,
|
13
|
+
'fatal' => Logger::FATAL,
|
14
|
+
'unknown' => Logger::UNKNOWN,
|
15
|
+
}
|
16
|
+
|
17
|
+
# Delegator class for when you want to log to multiple devices
|
18
|
+
# at the same time, such as STDOUT and a file.
|
19
|
+
# @param loggers [::Logger] one or more instances of Logger
|
20
|
+
class MultiLogger
|
21
|
+
def initialize(*loggers)
|
22
|
+
@loggers = loggers
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(m, *args, &block)
|
26
|
+
if @loggers.all? { |l| l.respond_to?(m) }
|
27
|
+
@loggers.map { |l| l.send(m, *args, &block) }
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def respond_to_missing?(m, include_private = false)
|
34
|
+
@loggers.all? { |l| l.respond_to?(m) } || super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
def new_logger(*logdevs, **configs)
|
40
|
+
new_configs = current_log_config.merge(configs.reject { |_, v| v.nil? })
|
41
|
+
if new_configs.key?(:level) && !LEVEL_MAP.values.include?(new_configs[:level])
|
42
|
+
new_configs[:level] = LEVEL_MAP[new_configs[:level].downcase]
|
43
|
+
end
|
44
|
+
loggers = logdevs.map do |dev|
|
45
|
+
logdev = dev.is_a?(String) ? $stdout : dev
|
46
|
+
logger = Logger.new(
|
47
|
+
logdev,
|
48
|
+
new_configs[:shift_age],
|
49
|
+
new_configs[:shift_size],
|
50
|
+
**new_configs.reject { |k, _| %i[logdev shift_age shift_size].include?(k) },
|
51
|
+
)
|
52
|
+
logger.reopen(dev) if dev.is_a?(String)
|
53
|
+
logger
|
54
|
+
end
|
55
|
+
@logger = CemAcpt::Logging::MultiLogger.new(*loggers)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Exposes a logger instance. Will either use the currently set logger or
|
59
|
+
# create a new one.
|
60
|
+
# @return [Logger]
|
61
|
+
def logger
|
62
|
+
@logger ||= Logger.new(
|
63
|
+
current_log_config[:logdev],
|
64
|
+
current_log_config[:shift_age],
|
65
|
+
current_log_config[:shift_size],
|
66
|
+
**current_log_config.reject { |k, _| %i[logdev shift_age shift_size].include?(k) }
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Shortcut method for logger.level
|
71
|
+
# @return [Logger::Severity]
|
72
|
+
def current_log_level
|
73
|
+
logger.level
|
74
|
+
end
|
75
|
+
|
76
|
+
# Shortcut method to set logger.level
|
77
|
+
# @param level [String] the log level to set
|
78
|
+
def new_log_level(level)
|
79
|
+
raise ArgumentError, 'Log level not recognized' unless LEVEL_MAP[level.downcase]
|
80
|
+
|
81
|
+
@logger.level = LEVEL_MAP[level.downcase]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Shows the current log format style if set, or the default if not.
|
85
|
+
# @return [Symbol] the current log format style
|
86
|
+
def current_log_format
|
87
|
+
@current_log_format ||= :text
|
88
|
+
end
|
89
|
+
|
90
|
+
# Sets the current log format style and returns a proc to be passed to
|
91
|
+
# Logger#formatter=
|
92
|
+
# @param f [Symbol] the log format style to set
|
93
|
+
# @return [Proc] the proc to be passed to Logger#formatter=
|
94
|
+
def new_log_formatter(f)
|
95
|
+
case f.downcase.to_sym
|
96
|
+
when :json
|
97
|
+
require 'json'
|
98
|
+
@current_log_format = :json
|
99
|
+
proc do |severity, datetime, progname, msg|
|
100
|
+
{
|
101
|
+
timestamp: datetime,
|
102
|
+
progname: progname,
|
103
|
+
severity: severity,
|
104
|
+
message: msg,
|
105
|
+
}.to_json + "\n"
|
106
|
+
end
|
107
|
+
when :text
|
108
|
+
@current_log_format = :text
|
109
|
+
proc do |severity, _datetime, _progname, msg|
|
110
|
+
"#{severity} - #{msg}\n"
|
111
|
+
end
|
112
|
+
when :github_action
|
113
|
+
@current_log_format = :github_action
|
114
|
+
sev_map = {
|
115
|
+
'DEBUG' => '::debug::',
|
116
|
+
'INFO' => '::notice::',
|
117
|
+
'WARN' => '::warning::',
|
118
|
+
'ERROR' => '::error::',
|
119
|
+
'FATAL' => '::error::',
|
120
|
+
}
|
121
|
+
proc do |severity, _datetime, _progname, msg|
|
122
|
+
"#{sev_map[severity]}{#{msg}}\n"
|
123
|
+
end
|
124
|
+
else
|
125
|
+
@current_log_format = :file
|
126
|
+
proc do |severity, datetime, _progname, msg|
|
127
|
+
"[#{datetime}] #{severity}: #{msg}\n"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns the current log config if set, or the default if not.
|
133
|
+
# @return [Hash] the current log config
|
134
|
+
def current_log_config
|
135
|
+
return @log_config if @log_config
|
136
|
+
|
137
|
+
formatter = new_log_formatter(current_log_format)
|
138
|
+
@log_config = {
|
139
|
+
logdev: $stdout,
|
140
|
+
shift_age: 'o',
|
141
|
+
shift_size: 1_048_576,
|
142
|
+
level: Logger::INFO,
|
143
|
+
progname: 'CemAcpt',
|
144
|
+
datetime_format: '%Y%m%dT%H%M%S%z',
|
145
|
+
formatter: formatter,
|
146
|
+
}
|
147
|
+
@log_config
|
148
|
+
end
|
149
|
+
|
150
|
+
# Creates a new log config hash and a new Logger instance using that config and sets
|
151
|
+
# the new Logger instance as the current logger. NO DEFAULT VALUES ARE SET.
|
152
|
+
# @param logdev [String, IO] the log device to use. If 'stdout' or 'stderr' are passed,
|
153
|
+
# the respective IO object will be used. Otherwise, Strings will be treated as file paths.
|
154
|
+
# If an IO object is passed, it will be used directly.
|
155
|
+
# If no logdev is passed, or an invalid logdev is passed, the default is $stdout.
|
156
|
+
# @param shift_age [String] the log rotation age
|
157
|
+
# @param shift_size [Integer] the log rotation size
|
158
|
+
# @param level [Logger::Severity] the log level
|
159
|
+
# @param formatter [Proc] the log formatter
|
160
|
+
# @param datetime_format [String] the datetime format
|
161
|
+
def new_log_config(logdev: nil, shift_age: nil, shift_size: nil, level: nil, formatter: nil, datetime_format: nil)
|
162
|
+
@log_config[:shift_age] = shift_age if shift_age
|
163
|
+
@log_config[:shift_size] = shift_size if shift_size
|
164
|
+
@log_config[:level] = level if level
|
165
|
+
@log_config[:formatter] = formatter if formatter
|
166
|
+
@log_config[:datetime_format] = datetime_format if datetime_format
|
167
|
+
case logdev
|
168
|
+
when 'stdout'
|
169
|
+
@log_config[:logdev] = $stdout
|
170
|
+
when 'stderr'
|
171
|
+
@log_config[:logdev] = $stderr
|
172
|
+
when String
|
173
|
+
@log_config[:logdev] = target
|
174
|
+
when IO
|
175
|
+
@log_config[:logdev] = logdev
|
176
|
+
else
|
177
|
+
@log_config[:logdev] = $stdout
|
178
|
+
logger.warn("Unknown log target: #{logdev.inspect}, using STDOUT")
|
179
|
+
end
|
180
|
+
@logger = Logger.new(
|
181
|
+
@log_config[:logdev],
|
182
|
+
@log_config[:shift_age],
|
183
|
+
@log_config[:shift_size],
|
184
|
+
**@log_config.reject { |k, _| %i[logdev shift_age shift_size].include?(k) },
|
185
|
+
)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Provides class method wrappers for logging methods
|
190
|
+
def self.included(base)
|
191
|
+
class << base
|
192
|
+
def new_logger(*logdevs, **configs)
|
193
|
+
CemAcpt::Logging.new_logger(*logdevs, **configs)
|
194
|
+
end
|
195
|
+
|
196
|
+
def logger
|
197
|
+
CemAcpt::Logging.logger
|
198
|
+
end
|
199
|
+
|
200
|
+
def current_log_level
|
201
|
+
CemAcpt::Logging.current_log_level
|
202
|
+
end
|
203
|
+
|
204
|
+
def new_log_level(level)
|
205
|
+
CemAcpt::Logging.new_log_level(level)
|
206
|
+
end
|
207
|
+
|
208
|
+
def current_log_format
|
209
|
+
CemAcpt::Logging.current_log_format
|
210
|
+
end
|
211
|
+
|
212
|
+
def new_log_formatter(f)
|
213
|
+
CemAcpt::Logging.new_log_formatter(f)
|
214
|
+
end
|
215
|
+
|
216
|
+
def current_log_config
|
217
|
+
CemAcpt::Logging.current_log_config
|
218
|
+
end
|
219
|
+
|
220
|
+
def new_log_config(logdev: nil, shift_age: nil, shift_size: nil, level: nil, formatter: nil, datetime_format: nil)
|
221
|
+
CemAcpt::Logging.new_log_config(logdev: logdev, shift_age: shift_age, shift_size: shift_size, level: level, formatter: formatter, datetime_format: datetime_format)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def new_logger(*logdevs, **configs)
|
227
|
+
CemAcpt::Logging.new_logger(*logdevs, **configs)
|
228
|
+
end
|
229
|
+
|
230
|
+
# Exposes the logger instance
|
231
|
+
def logger
|
232
|
+
CemAcpt::Logging.logger
|
233
|
+
end
|
234
|
+
|
235
|
+
# Exposes the current log level
|
236
|
+
def current_log_level
|
237
|
+
CemAcpt::Logging.current_log_level
|
238
|
+
end
|
239
|
+
|
240
|
+
# Exposes setting the log level
|
241
|
+
def new_log_level(level)
|
242
|
+
CemAcpt::Logging.new_log_level(level)
|
243
|
+
end
|
244
|
+
|
245
|
+
def current_log_format
|
246
|
+
CemAcpt::Logging.current_log_format
|
247
|
+
end
|
248
|
+
|
249
|
+
def new_log_formatter(f)
|
250
|
+
CemAcpt::Logging.new_log_formatter(f)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Exposes the current log config
|
254
|
+
def current_log_config
|
255
|
+
CemAcpt::Logging.current_log_config
|
256
|
+
end
|
257
|
+
|
258
|
+
# Exposes setting a new log config
|
259
|
+
def new_log_config(logdev: nil, shift_age: nil, shift_size: nil, level: nil, formatter: nil, datetime_format: nil)
|
260
|
+
CemAcpt::Logging.new_log_config(logdev: logdev, shift_age: shift_age, shift_size: shift_size, level: level, formatter: formatter, datetime_format: datetime_format)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
module LoggingAsync
|
265
|
+
require 'concurrent-ruby'
|
266
|
+
|
267
|
+
class << self
|
268
|
+
def log_write_thread
|
269
|
+
@log_write_thread ||= Concurrent::SingleThreadExecutor.new
|
270
|
+
end
|
271
|
+
|
272
|
+
def async_debug(message, prefix = nil)
|
273
|
+
msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
|
274
|
+
CemAcpt::Logging.logger.debug(msg)
|
275
|
+
end
|
276
|
+
|
277
|
+
def async_info(message, prefix = nil)
|
278
|
+
msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
|
279
|
+
CemAcpt::Logging.logger.info(msg)
|
280
|
+
end
|
281
|
+
|
282
|
+
def async_warn(message, prefix = nil)
|
283
|
+
msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
|
284
|
+
CemAcpt::Logging.logger.warn(msg)
|
285
|
+
end
|
286
|
+
|
287
|
+
def async_error(message, prefix = nil)
|
288
|
+
msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
|
289
|
+
CemAcpt::Logging.logger.error(msg)
|
290
|
+
end
|
291
|
+
|
292
|
+
def async_fatal(message, prefix = nil)
|
293
|
+
msg = prefix.nil? || prefix.empty? ? message : "#{prefix} #{message}"
|
294
|
+
CemAcpt::Logging.logger.fatal(msg)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# Provides class method wrappers for logging methods
|
299
|
+
def self.included(base)
|
300
|
+
class << base
|
301
|
+
def log_write_thread
|
302
|
+
CemAcpt::LoggingAsync.log_write_thread
|
303
|
+
end
|
304
|
+
|
305
|
+
def async_debug(message, prefix = nil)
|
306
|
+
CemAcpt::LoggingAsync.async_debug(message, prefix)
|
307
|
+
end
|
308
|
+
|
309
|
+
def async_info(message, prefix = nil)
|
310
|
+
CemAcpt::LoggingAsync.async_info(message, prefix)
|
311
|
+
end
|
312
|
+
|
313
|
+
def async_warn(message, prefix = nil)
|
314
|
+
CemAcpt::LoggingAsync.async_warn(message, prefix)
|
315
|
+
end
|
316
|
+
|
317
|
+
def async_error(message, prefix = nil)
|
318
|
+
CemAcpt::LoggingAsync.async_error(message, prefix)
|
319
|
+
end
|
320
|
+
|
321
|
+
def async_fatal(message, prefix = nil)
|
322
|
+
CemAcpt::LoggingAsync.async_fatal(message, prefix)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
def log_write_thread
|
328
|
+
CemAcpt::LoggingAsync.log_write_thread
|
329
|
+
end
|
330
|
+
|
331
|
+
def async_debug(message, prefix = nil)
|
332
|
+
CemAcpt::LoggingAsync.async_debug(message, prefix)
|
333
|
+
end
|
334
|
+
|
335
|
+
def async_info(message, prefix = nil)
|
336
|
+
CemAcpt::LoggingAsync.async_info(message, prefix)
|
337
|
+
end
|
338
|
+
|
339
|
+
def async_warn(message, prefix = nil)
|
340
|
+
CemAcpt::LoggingAsync.async_warn(message, prefix)
|
341
|
+
end
|
342
|
+
|
343
|
+
def async_error(message, prefix = nil)
|
344
|
+
CemAcpt::LoggingAsync.async_error(message, prefix)
|
345
|
+
end
|
346
|
+
|
347
|
+
def async_fatal(message, prefix = nil)
|
348
|
+
CemAcpt::LoggingAsync.async_fatal(message, prefix)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CemAcpt::Platform
|
4
|
+
require_relative File.join(__dir__, '..', '..', 'logging.rb')
|
5
|
+
|
6
|
+
class CmdError < StandardError; end
|
7
|
+
|
8
|
+
# Base class for command providers. Provides an API for subclasses to implement.
|
9
|
+
class CmdBase
|
10
|
+
include CemAcpt::Logging
|
11
|
+
|
12
|
+
attr_reader :env
|
13
|
+
|
14
|
+
def initialize(*_args, env: {}, **_kwargs)
|
15
|
+
@env = env
|
16
|
+
end
|
17
|
+
|
18
|
+
def local_exec(*_args, **_kwargs)
|
19
|
+
raise NotImplementedError, '#local_exec must be implemented by a subclass'
|
20
|
+
end
|
21
|
+
|
22
|
+
def ssh(_instance_name, _command, _ignore_command_errors: false, _opts: {})
|
23
|
+
raise NotImplementedError, '#ssh must be implemented by a subclass'
|
24
|
+
end
|
25
|
+
|
26
|
+
def scp_upload(_instance_name, _local, _remote, _scp_opts: {}, _opts: {})
|
27
|
+
raise NotImplementedError, '#scp_upload must be implemented by a subclass'
|
28
|
+
end
|
29
|
+
|
30
|
+
def scp_download(_instance_name, _local, _remote, _scp_opts: {}, _opts: {})
|
31
|
+
raise NotImplementedError, '#scp_download must be implemented by a subclass'
|
32
|
+
end
|
33
|
+
|
34
|
+
def ssh_ready?(_instance_name, _timeout = 300, _opts: {})
|
35
|
+
raise NotImplementedError, '#ssh_ready? must be implemented by a subclass'
|
36
|
+
end
|
37
|
+
|
38
|
+
def apply_manifest(_instance_name, _manifest, _opts: {})
|
39
|
+
raise NotImplementedError, '#create_manifest_on_node must be implemented by a subclass'
|
40
|
+
end
|
41
|
+
|
42
|
+
def run_shell(_instance_name, _command, _opts: {})
|
43
|
+
raise NotImplementedError, '#run_shell must be implemented by a subclass'
|
44
|
+
end
|
45
|
+
|
46
|
+
def trim_output(output)
|
47
|
+
if output.include?("\n")
|
48
|
+
output.split("\n").map(&:strip).reject(&:empty?).join("\n")
|
49
|
+
else
|
50
|
+
output.strip
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def with_timed_retry(timeout = 300)
|
55
|
+
return unless block_given?
|
56
|
+
|
57
|
+
last_error = nil
|
58
|
+
start_time = Time.now
|
59
|
+
while Time.now - start_time < timeout
|
60
|
+
begin
|
61
|
+
output = yield
|
62
|
+
return output
|
63
|
+
rescue StandardError => e
|
64
|
+
last_error = e
|
65
|
+
sleep(10)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
raise last_error
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require_relative File.join(__dir__, '..', 'image_name_builder')
|
5
|
+
require_relative File.join(__dir__, '..', 'logging')
|
6
|
+
|
7
|
+
module CemAcpt::Platform
|
8
|
+
# Base class for all platform classes. This class provides an API for
|
9
|
+
# interacting with the underlying platform.
|
10
|
+
class Base
|
11
|
+
include CemAcpt::Logging
|
12
|
+
|
13
|
+
attr_reader :config, :test_data, :local_port, :node_name, :image_name
|
14
|
+
|
15
|
+
# @param conf [CemAcpt::Config] the config object.
|
16
|
+
# @param single_test_data [Hash] the test data for the current test.
|
17
|
+
# @param local_port [Integer] the local port to use for the test.
|
18
|
+
def initialize(conf, single_test_data, local_port)
|
19
|
+
raise ArgumentError, 'single_test_data must be a Hash' unless single_test_data.is_a?(Hash)
|
20
|
+
|
21
|
+
@config = conf.get('node_data')
|
22
|
+
@test_data = single_test_data
|
23
|
+
@local_port = local_port
|
24
|
+
@node_name = @test_data[:node_name] || random_node_name
|
25
|
+
@image_name = conf.has?('image_name_builder') ? image_name_builder(conf, single_test_data) : @test_data[:image_name]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Node should return a hash of all data about a created node.
|
29
|
+
def node
|
30
|
+
raise NotImplementedError, '#node must be implemented by subclass'
|
31
|
+
end
|
32
|
+
|
33
|
+
# Provision a node. Will be called asynchronously.
|
34
|
+
def provision
|
35
|
+
raise NotImplementedError, '#provision must be implemented by subclass'
|
36
|
+
end
|
37
|
+
|
38
|
+
# Destroy a node. Will be called asynchronously.
|
39
|
+
def destroy
|
40
|
+
raise NotImplementedError, '#destroy must be implemented by subclass'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Tests to see if a node is ready to accept connections from the test suite.
|
44
|
+
def ready?
|
45
|
+
raise NotImplementedError, '#ready? must be implemented by subclass'
|
46
|
+
end
|
47
|
+
|
48
|
+
# Upload and install a Puppet module package on the node. Blocking call.
|
49
|
+
def install_puppet_module_package(_module_pkg_path, _remote_path)
|
50
|
+
raise NotImplementedError, '#install_puppet_module_package must be implemented by subclass'
|
51
|
+
end
|
52
|
+
|
53
|
+
# Generates a random node name.
|
54
|
+
def random_node_name
|
55
|
+
"acpt-test-#{SecureRandom.hex(10)}"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Builds an image name if the config specifies to use the image name builder.
|
59
|
+
def image_name_builder(conf, tdata)
|
60
|
+
@image_name_builder ||= CemAcpt::ImageNameBuilder.new(conf).build(tdata)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns a command provider specified by the Platform module of the specific platform.
|
64
|
+
def self.command_provider
|
65
|
+
raise NotImplementedError, '#command_provider must be implemented by subclass'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Applies a Puppet manifest on the given node.
|
69
|
+
def self.apply_manifest(_instance_name, _manifest, _opts = {})
|
70
|
+
raise NotImplementedError, '#apply_manifest must be implemented by subclass'
|
71
|
+
end
|
72
|
+
|
73
|
+
# Runs a shell command on the given node.
|
74
|
+
def self.run_shell(_instance_name, _cmd, _opts = {})
|
75
|
+
raise NotImplementedError, '#run_shell must be implemented by subclass'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|