cem_acpt 0.2.7-universal-java-17 → 0.2.10-universal-java-17

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: 4d851a1f582f7ae5bbb404a443f5a9182a9870c14cf95eb91b579f7bc23ec464
4
- data.tar.gz: b99a67c2106017b09ad3fd8ae06f32e50abc5da5c0384c60d2896f86708be7b0
3
+ metadata.gz: 5d59f3f4432694cd766fc5ca304ade0cad8cb681849181256d8c1ced3ba68438
4
+ data.tar.gz: eff162b600769222a8d0670e2a528cc389eae0407e35a1d6671c1518248c0480
5
5
  SHA512:
6
- metadata.gz: 92c834d242c437434dc4fac8b60f196f8458f0e1b03b26fff8e23ca1d9d79e726b44386f327bdecbdb94b2048401299fdfbfdf626f02b26792aa7f77388116d7
7
- data.tar.gz: 724db71afd7efae7d8b7cb6aa572cef672ee9c705b86c293215568ec334ce706e44284054b88c972e2746a3550ea7b5d398bfe2d217a7e4b9f24aadac78297b7
6
+ metadata.gz: a8124eec84379d5737fc4e04327ded0de1da8cb43c724a51cfd892c150823b58b14f9f6f99ec24adff5a7bc69302595e79de34501326c1c6e85fe1b0fa3c99cc
7
+ data.tar.gz: c6ea839545a9c00779aec17f331a9769a743baf7e05654f25d9efaa0e7edd8490dc528342ba75cdef171dc79328ad0431b204310c53d736f0b8bd2faf71ac6b4
data/Gemfile CHANGED
@@ -1,7 +1,8 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+ source 'https://rubygems.org'
2
3
 
3
4
  # Specify your gem's dependencies in cem_acpt.gemspec
4
5
  gemspec
5
6
 
6
- gem "rake", "~> 12.0"
7
- gem "rspec", "~> 3.0"
7
+ gem 'rake', '>= 12.0'
8
+ gem 'rspec', '>= 3.0'
data/Gemfile.lock CHANGED
@@ -1,12 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_acpt (0.2.7-universal-java-17)
5
- concurrent-ruby (~> 1.1.9)
6
- deep_merge (~> 1.2.2)
4
+ cem_acpt (0.2.10-universal-java-17)
5
+ concurrent-ruby (>= 1.1, < 2.0)
6
+ deep_merge (>= 1.2, < 2.0)
7
7
  ed25519 (>= 1.2, < 2.0)
8
- net-ssh (~> 7.0.0.beta1)
9
- puppet-modulebuilder (> 0.0.1)
8
+ net-ssh (>= 7.0, < 8.0)
9
+ puppet-modulebuilder (>= 0.0.1)
10
10
  serverspec-cem-acpt
11
11
 
12
12
  GEM
@@ -31,7 +31,7 @@ GEM
31
31
  minitar (~> 0.9)
32
32
  pathspec (>= 0.2.1, < 2.0.0)
33
33
  rainbow (3.1.1)
34
- rake (12.3.3)
34
+ rake (13.0.6)
35
35
  regexp_parser (2.5.0)
36
36
  rexml (3.2.5)
37
37
  rspec (3.11.0)
@@ -80,8 +80,8 @@ PLATFORMS
80
80
 
81
81
  DEPENDENCIES
82
82
  cem_acpt!
83
- rake (~> 12.0)
84
- rspec (~> 3.0)
83
+ rake (>= 12.0)
84
+ rspec (>= 3.0)
85
85
  rubocop
86
86
 
87
87
  BUNDLED WITH
data/cem_acpt.gemspec CHANGED
@@ -27,11 +27,11 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
  spec.platform = Gem::Platform.local
30
- spec.add_runtime_dependency 'concurrent-ruby', '~> 1.1.9'
31
- spec.add_runtime_dependency 'deep_merge', '~> 1.2.2'
30
+ spec.add_runtime_dependency 'concurrent-ruby', '>= 1.1', '< 2.0'
31
+ spec.add_runtime_dependency 'deep_merge', '>= 1.2', '< 2.0'
32
32
  spec.add_runtime_dependency 'ed25519', '>= 1.2', '< 2.0'
33
- spec.add_runtime_dependency 'net-ssh', '~> 7.0.0.beta1'
34
- spec.add_runtime_dependency 'puppet-modulebuilder', '> 0.0.1'
33
+ spec.add_runtime_dependency 'net-ssh', '>= 7.0', '< 8.0'
34
+ spec.add_runtime_dependency 'puppet-modulebuilder', '>= 0.0.1'
35
35
  spec.add_runtime_dependency 'serverspec-cem-acpt'
36
36
  spec.add_development_dependency 'rubocop'
37
37
  end
@@ -36,10 +36,8 @@ module CemAcpt
36
36
  # Creates a SSH key and a SSH known hosts file for the acceptance test suite
37
37
  def new_test_ssh_key
38
38
  log('Creating ephemeral SSH key and known hosts file for acceptance test suites...')
39
- @ssh_priv_key, @ssh_pub_key = CemAcpt::Utils::SSH.ephemeral_ssh_key
40
- @ssh_known_hosts = CemAcpt::Utils::SSH.acpt_known_hosts
41
- CemAcpt::Utils::SSH.set_ssh_file_permissions(@ssh_priv_key, @ssh_pub_key, @ssh_known_hosts)
42
- log('Successfully created SSH files...')
39
+ @ssh_priv_key, @ssh_pub_key, @ssh_known_hosts = CemAcpt::Utils::SSH::Ephemeral.create
40
+ log('Successfully created SSH files.')
43
41
  log("SSH private key: #{@ssh_priv_key}", :debug)
44
42
  log("SSH public key: #{@ssh_pub_key}", :debug)
45
43
  log("SSH known hosts: #{@ssh_known_hosts}", :debug)
@@ -48,7 +46,9 @@ module CemAcpt
48
46
  # Deletes acceptance test suite SSH files
49
47
  def clean_test_ssh_key
50
48
  log('Deleting ephemeral ssh keys and acpt_known_hosts if they exist...')
51
- [@ssh_priv_key, @ssh_pub_key, @ssh_known_hosts].map { |f| File.delete(f) if File.exist?(f) }
49
+ cleaned = CemAcpt::Utils::SSH::Ephemeral.clean
50
+ log('Successfully cleaned ephemeral ssh files.')
51
+ log("Deleted: #{cleaned}", :debug)
52
52
  end
53
53
 
54
54
  # Prints a period to the terminal every 5 seconds in a single line to keep the terminal
@@ -62,8 +62,8 @@ module CemAcpt
62
62
  end
63
63
 
64
64
  def clean_up_test_suite(opts)
65
- @ctx.node_inventory.clear!
66
- @ctx.node_inventory.clean_local_files
65
+ @ctx&.node_inventory&.clear!
66
+ @ctx&.node_inventory&.clean_local_files
67
67
  clean_test_ssh_key unless opts[:no_ephemeral_ssh_key]
68
68
  @run_handler&.destroy_test_nodes
69
69
  @keep_terminal_alive&.kill
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CemAcpt
4
+ module Logging
5
+ module Formatter
6
+ class << self
7
+ def for(log_format)
8
+ all.find { |f| f.log_format == log_format.downcase.to_sym }.get
9
+ end
10
+
11
+ private
12
+
13
+ def all
14
+ @all ||= [FileFormatter.new, JSONFormatter.new, TextFormatter.new, GithubActionFormatter.new]
15
+ end
16
+ end
17
+
18
+ class FileFormatter
19
+ attr_reader :log_format
20
+
21
+ def initialize
22
+ @log_format = :file
23
+ end
24
+
25
+ def get
26
+ proc do |severity, datetime, progname, msg|
27
+ format(severity, datetime, progname, msg)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def format(severity, datetime, _progname, msg)
34
+ "[#{datetime}] #{severity}: #{msg}\n"
35
+ end
36
+ end
37
+
38
+ class JSONFormatter < FileFormatter
39
+ def initialize
40
+ super
41
+ @log_format = :json
42
+ end
43
+
44
+ private
45
+
46
+ def format(severity, datetime, progname, msg)
47
+ require 'json'
48
+ {
49
+ timestamp: datetime,
50
+ progname: progname,
51
+ severity: severity,
52
+ message: msg,
53
+ }.to_json + "\n"
54
+ end
55
+ end
56
+
57
+ class TextFormatter < FileFormatter
58
+ def initialize
59
+ super
60
+ @log_format = :text
61
+ end
62
+
63
+ private
64
+
65
+ def format(severity, _datetime, _progname, msg)
66
+ "#{severity} - #{msg}\n"
67
+ end
68
+ end
69
+
70
+ class GithubActionFormatter < FileFormatter
71
+ SEV_MAP = {
72
+ 'DEBUG' => '::debug',
73
+ 'INFO' => '::notice',
74
+ 'WARN' => '::warning',
75
+ 'ERROR' => '::error',
76
+ 'FATAL' => '::error',
77
+ }.freeze
78
+
79
+ def initialize
80
+ super
81
+ @log_format = :github_action
82
+ end
83
+
84
+ private
85
+
86
+ def format(severity, _datetime, _progname, msg)
87
+ if severity == 'DEBUG'
88
+ "#{SEV_MAP[severity]}::{#{msg}}\n"
89
+ else
90
+ "#{SEV_MAP[severity]} #{msg}\n"
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'logger'
4
+ require 'cem_acpt/logging/formatter'
4
5
 
5
6
  module CemAcpt
6
7
  # Logging for CemAcpt
@@ -92,41 +93,7 @@ module CemAcpt
92
93
  # @param f [Symbol] the log format style to set
93
94
  # @return [Proc] the proc to be passed to Logger#formatter=
94
95
  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
96
+ CemAcpt::Logging::Formatter.for(f)
130
97
  end
131
98
 
132
99
  # Returns the current log config if set, or the default if not.
@@ -12,13 +12,17 @@ module CemAcpt
12
12
  class BundlerNotFoundError < StandardError; end
13
13
  class RSpecNotFoundError < StandardError; end
14
14
 
15
- # Holds and formats a RSpec command
16
- class Command
17
- include CemAcpt::LoggingAsync
18
- attr_reader :debug, :format, :test_path, :use_bundler, :pty_pid
15
+ # Holds RSpec options used by Command
16
+ class Options
17
+ OPTIONS = %i[test_path bundle rspec use_bundler bundle_install format debug quiet env].freeze
19
18
 
19
+ attr_accessor(*OPTIONS)
20
+
21
+ # @param config [CemAcpt::Config] A config object
20
22
  # @param opts [Hash] options hash for the RSpec command
21
23
  # @option opts [String] :test_path The path (or glob path) to the test file(s) to run. If blank, runs all.
24
+ # @option opts [String] :bundle The path to the `bundle` binary.
25
+ # @option opts [String] :rspec The path to the `rspec` binary.
22
26
  # @option opts [Hash] :format Format options for rspec where the key is the format (documentation, json, etc)
23
27
  # and the value is the out-file path. If you do not want to save the results of a format to a file, the
24
28
  # value should be `nil`.
@@ -30,56 +34,97 @@ module CemAcpt
30
34
  # Default is `true`.
31
35
  # @option opts [Boolean] :bundle_install Whether or not to run `bundle install` before the RSpec command
32
36
  # if `use_bundler` is `true`.
33
- # @option opts [Boolean] :use_shell Whether or not to add `$SHELL` as a prefix to the command
34
37
  # @option opts [Hash] :env Environment variables to prepend to the command
35
- def initialize(opts = {})
36
- @test_path = opts[:test_path]&.shellescape
37
- @format = opts.fetch(:format, {})
38
- @debug = opts.fetch(:debug, false)
39
- @quiet = @debug ? false : opts.fetch(:quiet, false)
40
- @use_bundler = opts.fetch(:use_bundler, false)
41
- @bundle_install = opts.fetch(:bundle_install, false)
42
- @env = opts.fetch(:env, {})
43
- @pty_pid = nil
44
- validate_and_set_bin_paths(opts)
38
+ def initialize(config, **opts)
39
+ @config = config
40
+ @opts = opts
41
+ define_option_instance_vars
42
+ end
43
+
44
+ # Finds and sets the paths to the `bundle` and `rspec` binaries. The paths can
45
+ # be either passed in as options in the `opts` Hash or interrogated from the
46
+ # system.
47
+ # @raise [CemAcpt::RSpecUtils::BundlerNotFoundError] if `@use_bundler` is true and
48
+ # `bundle` binary is not found.
49
+ # @raise [CemAcpt::RSpecUtils::RSpecNotFoundError] if `rspec` binary is not found.
50
+ def resolve_bin_paths
51
+ %i[bundle rspec].each do |bin|
52
+ bin_path = instance_variable_get("@#{bin}") || `#{ENV['SHELL']} -c 'command -v #{bin}'`.strip
53
+ bin_not_found(bin, bin_path) unless bin_path && File.exist?(bin_path)
54
+ instance_variable_set("@#{bin}", bin_path)
55
+ end
56
+ end
57
+
58
+ # Detects if the current Ruby context is JRuby
59
+ def jruby?
60
+ Object.const_defined?('JRUBY_VERSION')
45
61
  end
46
62
 
47
- # Sets debug mode to `true`
48
- def set_debug
49
- @debug = true
50
- if @quiet
51
- async_debug('Setting :quiet to false because :debug is now true.')
52
- @quiet = false
63
+ private
64
+
65
+ def defaults
66
+ @defaults ||= { use_bundler: false,
67
+ bundle_install: false,
68
+ format: { documentation: nil },
69
+ debug: false,
70
+ quiet: false,
71
+ env: {} }
72
+ end
73
+
74
+ def define_option_instance_vars
75
+ OPTIONS.each do |o|
76
+ val = @config.get("rspec.#{o}") || @opts[o] || defaults[o] || nil
77
+ instance_variable_set("@#{o}", val)
53
78
  end
54
79
  end
55
80
 
56
- # Sets debug mode to `false`
57
- def unset_debug
58
- @debug = false
81
+ # Handles binary paths which are not found
82
+ # @param bin [Symbol] The binary that was not found, either :bundle or :rspec.
83
+ # @param bin_path [String] The path to the binary that was checked.
84
+ # @raise [CemAcpt::RSpecUtils::BundlerNotFoundError] if `@use_bundler` is true and
85
+ # `bundle` binary is not found.
86
+ # @raise [CemAcpt::RSpecUtils::RSpecNotFoundError] if `rspec` binary is not found.
87
+ # @raise [RuntimeError] if `bin` is not :bundle or :rspec.
88
+ def bin_not_found(bin, bin_path)
89
+ msg_base = "#{bin} not found."
90
+ msg = bin_path.nil? ? "#{msg_base} Path is nil." : "#{msg_base} Path: #{bin_path}"
91
+ case bin
92
+ when :bundle
93
+ raise BundlerNotFoundError, msg if opts.use_bundler
94
+ when :rspec
95
+ raise RSpecNotFoundError, msg
96
+ else
97
+ raise "bin #{bin} not recognized!"
98
+ end
59
99
  end
100
+ end
101
+
102
+ # Holds and formats a RSpec command
103
+ class Command
104
+ include CemAcpt::LoggingAsync
105
+ attr_reader :opts, :pty_pid
106
+
107
+ def initialize(opts = Options.new)
108
+ raise 'opts must be instance of CemAcpt::RSpecUtils::Options' unless opts.is_a?(CemAcpt::RSpecUtils::Options)
60
109
 
61
- def quiet
62
- @quiet && !debug
110
+ @opts = opts
111
+ @opts.resolve_bin_paths
112
+ @opts.env = @opts.env.merge({ 'RSPEC_DEBUG' => 'true' }) if @opts.debug
113
+ @pty_pid = nil
63
114
  end
64
115
 
65
116
  # Adds a new format to the RSpec command
66
117
  # @param fmt [String] The name of the format (i.e. "documentation", "json", etc.)
67
118
  # @param out [String] If specified, saves the specified format to a file at this path
68
119
  def with_format(fmt, out: nil)
69
- @format[fmt.to_sym] = out
70
- end
71
-
72
- # Environment variables that will be used for the RSpec command
73
- # @return [Hash] A Hash of environment variables with each key pair being: <var name> => <var value>
74
- def env
75
- @debug ? @env.merge({ 'RSPEC_DEBUG' => 'true' }) : @env
120
+ opts.format[fmt.to_sym] = out
76
121
  end
77
122
 
78
123
  # Returns an array representation of the RSpec command
79
124
  def to_a
80
125
  cmd = cmd_base.dup
81
- cmd << test_path if test_path
82
- format.each do |fmt, out|
126
+ cmd << opts.test_path if opts.test_path
127
+ opts.format.each do |fmt, out|
83
128
  cmd += ['--format', fmt.to_s.shellescape]
84
129
  cmd += ['--out', out.to_s.shellescape] if out
85
130
  end
@@ -112,12 +157,12 @@ module CemAcpt
112
157
  # @return [Integer] The exit code of the RSpec command
113
158
  def execute_pty(log_prefix: 'RSPEC')
114
159
  async_debug("Executing RSpec command '#{self}' in PTY...", log_prefix)
115
- PTY.spawn(env, ENV['SHELL']) do |r, w, pid|
160
+ PTY.spawn(opts.env, ENV['SHELL']) do |r, w, pid|
116
161
  @pty_pid = pid
117
162
  async_debug("Spawned RSpec PTY with PID #{@pty_pid}", log_prefix)
118
163
  export_envs(w)
119
164
  w.puts "#{self}; exit $?"
120
- quiet ? wait_io(r) : read_io(r, log_prefix: log_prefix)
165
+ handle_io(r, log_prefix: log_prefix)
121
166
  end
122
167
  $CHILD_STATUS
123
168
  end
@@ -130,9 +175,9 @@ module CemAcpt
130
175
  def execute_no_pty(log_prefix: 'RSPEC')
131
176
  async_info("Executing RSpec command '#{self}' with Open3.popen2e()...", log_prefix)
132
177
  exit_status = nil
133
- Open3.popen2e(env, to_s) do |stdin, std_out_err, wait_thr|
178
+ Open3.popen2e(opts.env, to_s) do |stdin, std_out_err, wait_thr|
134
179
  stdin.close
135
- quiet ? wait_io(std_out_err) : read_io(std_out_err, log_prefix: log_prefix)
180
+ handle_io(std_out_err, log_prefix: log_prefix)
136
181
  exit_status = wait_thr.value
137
182
  end
138
183
  exit_status
@@ -147,26 +192,21 @@ module CemAcpt
147
192
 
148
193
  private
149
194
 
150
- # Detects if the current Ruby context is JRuby
151
- def jruby?
152
- File.basename(RbConfig.ruby) == 'jruby'
153
- end
154
-
155
195
  # The base RSpec command
156
196
  def cmd_base
157
- use_bundler ? cmd_base_bundler : cmd_base_rspec
197
+ opts.use_bundler ? cmd_base_bundler : cmd_base_rspec
158
198
  end
159
199
 
160
200
  # The base RSpec command if `:use_bundler` is `true`.
161
201
  def cmd_base_bundler
162
- base = [@bundle, 'exec', 'rspec']
163
- base.unshift("#{@bundle} install;") if @bundle_install
202
+ base = [opts.bundle, 'exec', 'rspec']
203
+ base.unshift("#{opts.bundle} install;") if opts.bundle_install
164
204
  base
165
205
  end
166
206
 
167
207
  # The base RSpec command if `:use_bundler` is `false`
168
208
  def cmd_base_rspec
169
- [@rspec]
209
+ [opts.rspec]
170
210
  end
171
211
 
172
212
  # Puts export statements for each key-value pair in `env` to the given writer.
@@ -174,46 +214,14 @@ module CemAcpt
174
214
  # pass the statements to a shell.
175
215
  # @param writer [IO] An IO object that supprts `puts` and can send statements to a shell
176
216
  def export_envs(writer)
177
- env.each do |key, val|
217
+ @opts.env.each do |key, val|
178
218
  writer.puts "export #{key}=#{val}"
179
219
  end
180
220
  end
181
221
 
182
- # Finds and sets the paths to the `bundle` and `rspec` binaries. The paths can
183
- # be either passed in as options in the `opts` Hash or interrogated from the
184
- # system.
185
- # @param opts [Hash] The options hash
186
- # @option opts [String] :bundle An absolute path on the system to the `bundle` binary.
187
- # @option opts [String] :rspec An absolute path on the system to the `rspec` binary.
188
- # @raise [CemAcpt::RSpecUtils::BundlerNotFoundError] if `@use_bundler` is true and
189
- # `bundle` binary is not found.
190
- # @raise [CemAcpt::RSpecUtils::RSpecNotFoundError] if `rspec` binary is not found.
191
- def validate_and_set_bin_paths(opts = {})
192
- %i[bundle rspec].each do |bin|
193
- bin_path = opts[bin] || `command -v #{bin}`.strip
194
- bin_not_found(bin, bin_path) unless bin_path && File.exist?(bin_path)
195
- instance_variable_set("@#{bin}", bin_path)
196
- end
197
- end
198
-
199
- # Handles binary paths which are not found
200
- # @param bin [Symbol] The binary that was not found, either :bundle or :rspec.
201
- # @param bin_path [String] The path to the binary that was checked.
202
- # @raise [CemAcpt::RSpecUtils::BundlerNotFoundError] if `@use_bundler` is true and
203
- # `bundle` binary is not found.
204
- # @raise [CemAcpt::RSpecUtils::RSpecNotFoundError] if `rspec` binary is not found.
205
- # @raise [RuntimeError] if `bin` is not :bundle or :rspec.
206
- def bin_not_found(bin, bin_path)
207
- msg_base = "#{bin} not found."
208
- msg = bin_path.nil? ? "#{msg_base} Path is nil." : "#{msg_base} Path: #{bin_path}"
209
- case bin
210
- when :bundle
211
- raise BundlerNotFoundError, msg if @use_bundler
212
- when :rspec
213
- raise RSpecNotFoundError, msg
214
- else
215
- raise "bin #{bin} not recognized!"
216
- end
222
+ # Handles IO output
223
+ def handle_io(io_stream, **kwargs)
224
+ opts.quiet ? wait_io(io_stream) : read_io(io_stream, log_prefix: kwargs[:log_prefix])
217
225
  end
218
226
 
219
227
  # Blocking wait on an IO stream. Wait stops once the IO stream has reached
@@ -9,6 +9,7 @@ require_relative 'runner_result'
9
9
  module CemAcpt
10
10
  module TestRunner
11
11
  class RunnerError < StandardError; end
12
+
12
13
  # Error used to wrap fatal errors raised in Runner steps
13
14
  class RunnerStepError < StandardError
14
15
  attr_reader :step
@@ -19,6 +20,7 @@ module CemAcpt
19
20
  set_backtrace err.backtrace if err.respond_to?(:backtrace)
20
21
  end
21
22
  end
23
+
22
24
  class RunnerProvisionError < RunnerStepError; end
23
25
 
24
26
  # Runner is a class that runs a single acceptance test suite on a single node.
@@ -143,12 +145,12 @@ module CemAcpt
143
145
  async_info("Running test #{@node.test_data[:test_name]} on node #{@node.node_name}...", log_prefix('RSPEC'))
144
146
  @node.run_tests do |cmd_env|
145
147
  cmd_opts = rspec_opts
146
- cmd_opts[:env].merge!(cmd_env) if cmd_env
148
+ cmd_opts.env = cmd_opts.env.merge(cmd_env) if cmd_env
147
149
  # Documentation format gets logged in real time, JSON file is read after the fact
148
150
  begin
149
151
  @rspec_cmd = CemAcpt::RSpecUtils::Command.new(cmd_opts)
150
- @rspec_cmd.execute(log_prefix: log_prefix('RSPEC'))
151
- @run_result.from_json_file(cmd_opts[:format][:json])
152
+ @rspec_cmd.execute(pty: false, log_prefix: log_prefix('RSPEC'))
153
+ @run_result.from_json_file(cmd_opts.format[:json])
152
154
  rescue Errno::EIO => e
153
155
  async_error("failed to run rspec: #{@node.test_data[:test_name]}: #{$ERROR_INFO}", log_prefix('RSPEC'))
154
156
  @run_result.from_error(e)
@@ -189,21 +191,21 @@ module CemAcpt
189
191
 
190
192
  # Options used with RSpec
191
193
  def rspec_opts
192
- opts = {
193
- test_path: @node.test_data[:test_file],
194
- use_bundler: false,
195
- bundle_install: false,
196
- format: {
197
- json: "results_#{@node.test_data[:test_name]}.json",
198
- },
199
- debug: (@debug_mode && @context.config.get('verbose')),
200
- quiet: @context.config.get('quiet'),
201
- env: {
202
- 'TARGET_HOST' => @node.node_name,
203
- }
204
- }
205
- opts[:format][:documentation] = nil unless @context.config.get('verbose')
206
- opts
194
+ opts_test_path = @node.test_data[:test_file]
195
+ opts_env = { 'TARGET_HOST' => @node.node_name }
196
+ opts_debug = (@debug_mode && @context.config.get('verbose'))
197
+ opts_quiet = @context.config.get('quiet')
198
+ opts_format = if @context.config.get('verbose')
199
+ { json: "results_#{@node.test_data[:test_name]}.json", documentation: nil }
200
+ else
201
+ { json: "results_#{@node.test_data[:test_name]}.json" }
202
+ end
203
+ CemAcpt::RSpecUtils::Options.new(@context.config,
204
+ test_path: opts_test_path,
205
+ env: opts_env,
206
+ debug: opts_debug,
207
+ quiet: opts_quiet,
208
+ format: opts_format)
207
209
  end
208
210
  end
209
211
  end
@@ -81,6 +81,40 @@ module CemAcpt
81
81
 
82
82
  # SSH-related utilities
83
83
  module SSH
84
+ module Ephemeral
85
+ PRIV_KEY = 'acpt_test_key'
86
+ CREATE_OPTS = {
87
+ type: 'rsa',
88
+ bits: '4096',
89
+ comment: 'Ephemeral for cem_acpt',
90
+ password: '',
91
+ known_hosts: 'acpt_known_hosts',
92
+ overwrite_known_hosts: true,
93
+ }.freeze
94
+
95
+ class << self
96
+ attr_accessor :ephemeral_keydir
97
+ end
98
+
99
+ def self.create(keydir: CemAcpt::Utils::SSH.default_keydir)
100
+ self.ephemeral_keydir = keydir
101
+ @priv_key, @pub_key, @known_hosts = CemAcpt::Utils::SSH.create(PRIV_KEY, keydir: ephemeral_keydir, **CREATE_OPTS)
102
+ [@priv_key, @pub_key, @known_hosts]
103
+ end
104
+
105
+ def self.clean
106
+ [@priv_key, @pub_key, @known_hosts].each_with_object([]) do |f, arr|
107
+ next unless f
108
+
109
+ path = CemAcpt::Utils::SSH.file_path(f, keydir: ephemeral_keydir)
110
+ if ::File.exist?(path)
111
+ ::File.delete(path)
112
+ arr << path
113
+ end
114
+ end
115
+ end
116
+ end
117
+
84
118
  def self.ssh_keygen
85
119
  bin_path = `#{ENV['SHELL']} -c 'command -v ssh-keygen'`.chomp
86
120
  raise 'Cannot find ssh-keygen! Install it and verify PATH' unless bin_path
@@ -97,26 +131,52 @@ module CemAcpt
97
131
  ssh_dir
98
132
  end
99
133
 
100
- def self.ephemeral_ssh_key(type: 'rsa', bits: '4096', comment: nil, keydir: default_keydir)
101
- raise ArgumentError, 'keydir does not exist' unless ::File.directory?(keydir)
134
+ def self.file_path(file_name, keydir: default_keydir)
135
+ ::File.join(keydir, file_name)
136
+ end
137
+
138
+ # Takes a file name (not path) and optional SSH key directory and returns the paths
139
+ # to the private key and public key based on the file name given.
140
+ # @param file_name [String] The base name for the keys
141
+ # @param keydir [String] An optional SSH key directory
142
+ def self.key_paths(file_name, keydir: default_keydir)
143
+ [file_path(file_name, keydir: keydir), file_path("#{file_name}.pub", keydir: keydir)]
144
+ end
102
145
 
103
- keyfile = ::File.join(keydir, 'acpt_test_key')
104
- keygen_cmd = [ssh_keygen, "-t #{type}", "-b #{bits}", "-f #{keyfile}", '-N ""']
146
+ def self.create(key_name, type: 'rsa', bits: '4096', comment: nil, password: '', known_hosts: nil, overwrite_known_hosts: true, keydir: default_keydir)
147
+ raise ArgumentError, "Key directory #{keydir} does not exist" unless ::File.directory?(keydir)
148
+
149
+ keys = key_paths(key_name, keydir: keydir)
150
+ # If we don't delete an existing key file, generation will fail
151
+ keys.each { |f| ::File.delete(f) if ::File.exist?(f) }
152
+ keygen_cmd = [ssh_keygen, "-t #{type}", "-b #{bits}", "-f #{keys[0]}", "-N '#{password}'"]
105
153
  keygen_cmd << "-C \"#{comment}\"" if comment
106
154
  _, stderr, status = Open3.capture3(keygen_cmd.join(' '))
107
- raise "Failed to generate ephemeral SSH key: #{stderr}" unless status.success?
155
+ raise "Failed to generate ephemeral SSH key: STDOUT: #{stdout}; STDERR: #{stderr}" unless status.success?
108
156
 
109
- [keyfile, "#{keyfile}.pub"]
157
+ keys << create_known_hosts(known_hosts, overwrite: overwrite_known_hosts, keydir: keydir)
158
+ set_ssh_file_permissions(*keys)
159
+ keys
110
160
  end
111
161
 
112
- def self.acpt_known_hosts(keydir: default_keydir, file_name: 'acpt_known_hosts', overwrite: true)
113
- kh_file = ::File.join(keydir, file_name)
162
+ def self.create_known_hosts(known_hosts, overwrite: true, keydir: default_keydir)
163
+ return nil unless known_hosts
164
+
165
+ kh_file = file_path(known_hosts, keydir: keydir)
114
166
  ::File.open(kh_file, 'w') { |f| f.write("\n") } unless ::File.exist?(kh_file) && !overwrite
115
167
  kh_file
116
168
  end
117
169
 
118
- def self.set_ssh_file_permissions(priv_key, pub_key, known_hosts)
119
- CemAcpt::Utils::File.set_permissions(0o600, priv_key, pub_key, known_hosts)
170
+ def self.set_ssh_file_permissions(*files)
171
+ CemAcpt::Utils::File.set_permissions(0o600, *files.uniq.compact)
172
+ end
173
+
174
+ def self.ephemeral_ssh_key(keydir: default_keydir)
175
+ CemAcpt::Utils::SSH::Ephemeral.create(keydir: keydir)
176
+ end
177
+
178
+ def self.clean_ephemeral_keys
179
+ CemAcpt::Utils::SSH::Ephemeral.clean
120
180
  end
121
181
  end
122
182
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CemAcpt
4
- VERSION = '0.2.7'
4
+ VERSION = '0.2.10'
5
5
  end
metadata CHANGED
@@ -1,43 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cem_acpt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.10
5
5
  platform: universal-java-17
6
6
  authors:
7
7
  - puppetlabs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-27 00:00:00.000000000 Z
11
+ date: 2022-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.1'
19
+ - - "<"
17
20
  - !ruby/object:Gem::Version
18
- version: 1.1.9
21
+ version: '2.0'
19
22
  name: concurrent-ruby
20
23
  prerelease: false
21
24
  type: :runtime
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.1'
30
+ - - "<"
25
31
  - !ruby/object:Gem::Version
26
- version: 1.1.9
32
+ version: '2.0'
27
33
  - !ruby/object:Gem::Dependency
28
34
  requirement: !ruby/object:Gem::Requirement
29
35
  requirements:
30
- - - "~>"
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '1.2'
39
+ - - "<"
31
40
  - !ruby/object:Gem::Version
32
- version: 1.2.2
41
+ version: '2.0'
33
42
  name: deep_merge
34
43
  prerelease: false
35
44
  type: :runtime
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - "~>"
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '1.2'
50
+ - - "<"
39
51
  - !ruby/object:Gem::Version
40
- version: 1.2.2
52
+ version: '2.0'
41
53
  - !ruby/object:Gem::Dependency
42
54
  requirement: !ruby/object:Gem::Requirement
43
55
  requirements:
@@ -61,21 +73,27 @@ dependencies:
61
73
  - !ruby/object:Gem::Dependency
62
74
  requirement: !ruby/object:Gem::Requirement
63
75
  requirements:
64
- - - "~>"
76
+ - - ">="
65
77
  - !ruby/object:Gem::Version
66
- version: 7.0.0.beta1
78
+ version: '7.0'
79
+ - - "<"
80
+ - !ruby/object:Gem::Version
81
+ version: '8.0'
67
82
  name: net-ssh
68
83
  prerelease: false
69
84
  type: :runtime
70
85
  version_requirements: !ruby/object:Gem::Requirement
71
86
  requirements:
72
- - - "~>"
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '7.0'
90
+ - - "<"
73
91
  - !ruby/object:Gem::Version
74
- version: 7.0.0.beta1
92
+ version: '8.0'
75
93
  - !ruby/object:Gem::Dependency
76
94
  requirement: !ruby/object:Gem::Requirement
77
95
  requirements:
78
- - - ">"
96
+ - - ">="
79
97
  - !ruby/object:Gem::Version
80
98
  version: 0.0.1
81
99
  name: puppet-modulebuilder
@@ -83,7 +101,7 @@ dependencies:
83
101
  type: :runtime
84
102
  version_requirements: !ruby/object:Gem::Requirement
85
103
  requirements:
86
- - - ">"
104
+ - - ">="
87
105
  - !ruby/object:Gem::Version
88
106
  version: 0.0.1
89
107
  - !ruby/object:Gem::Dependency
@@ -142,6 +160,7 @@ files:
142
160
  - lib/cem_acpt/core_extensions.rb
143
161
  - lib/cem_acpt/image_name_builder.rb
144
162
  - lib/cem_acpt/logging.rb
163
+ - lib/cem_acpt/logging/formatter.rb
145
164
  - lib/cem_acpt/platform.rb
146
165
  - lib/cem_acpt/platform/base.rb
147
166
  - lib/cem_acpt/platform/base/cmd.rb