cem_acpt 0.3.3-universal-java-17 → 0.3.5-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: 50d9f549fee6436b9f857dbdf313dcab94b223e988c2cbfeadd8999d86f436f0
4
- data.tar.gz: 62a556754fe568b9d3bbc28b7381b3657c7aa0db872e5405bb392a1b9cef061d
3
+ metadata.gz: b62e59f800597758c9a69bc1ede3d3f97a9a68c6c38f0d4705201ac2613feab9
4
+ data.tar.gz: 4d4a0ad559702df7cff661726a962b0bbc278d2cb0ecba48241a67a55345dac6
5
5
  SHA512:
6
- metadata.gz: bf027699bcf399a68a6b845ef4191b4b912736f6eb52708e35a0393e78fce74f3c0299ee627bbfe80ec06a8ef9be0e5b030db6a1ab99a678943c8ebdf21112f6
7
- data.tar.gz: eb7448394e6be3719a735cf30adedae0aefb0ea8a6144523300c2e57da61bdbb3dfbf76a394b3c2014cc78a8283a6c565f2f311481951d09f1211454f22add74
6
+ metadata.gz: ee72270cae3121c03597e12f91c3fd6134da4ab40ef342cc3f694ea0a5ee2dcaf37363e9430b2610539120e0cf5ea733caf191d916a926e2d29dc17ac8bc7cfb
7
+ data.tar.gz: 79a40b4e74935a7842bffd7b9252aa63d277cc31e49c0a3a10200f647117a1c3e51d4183a3e2e16aa9cc0e1fd185d0ee375177fdc876ca4097e8828884b55f36
@@ -0,0 +1,36 @@
1
+ name: Unit Tests
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ pull_request:
6
+ types:
7
+ - opened
8
+ - synchronize
9
+ branches:
10
+ - main
11
+ tags:
12
+ - v.*
13
+
14
+ jobs:
15
+ tests:
16
+ name: RSpec tests
17
+ runs-on: ubuntu-20.04
18
+ steps:
19
+ - name: Checkout Source
20
+ uses: actions/checkout@v3
21
+
22
+ - name: Set up Java 17
23
+ uses: actions/setup-java@v3
24
+ with:
25
+ distribution: 'adopt-hotspot'
26
+ java-version: '17'
27
+
28
+ - name: Set up JRuby
29
+ uses: ruby/setup-ruby@v1
30
+ with:
31
+ ruby-version: jruby-9.3.3.0
32
+ bundler-cache: true
33
+
34
+ - name: Run RSpec
35
+ run: |
36
+ bundle exec rake spec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_acpt (0.3.3-universal-java-17)
4
+ cem_acpt (0.3.5-universal-java-17)
5
5
  concurrent-ruby (>= 1.1, < 2.0)
6
6
  deep_merge (>= 1.2, < 2.0)
7
7
  ed25519 (>= 1.2, < 2.0)
@@ -13,10 +13,13 @@ GEM
13
13
  remote: https://rubygems.org/
14
14
  specs:
15
15
  ast (2.4.2)
16
+ coderay (1.1.3)
16
17
  concurrent-ruby (1.1.10)
17
18
  deep_merge (1.2.2)
18
19
  diff-lcs (1.5.0)
19
20
  ed25519 (1.3.0-java)
21
+ ffi (1.15.5-java)
22
+ method_source (1.0.0)
20
23
  minitar (0.9)
21
24
  multi_json (1.15.0)
22
25
  net-scp (4.0.0)
@@ -27,6 +30,10 @@ GEM
27
30
  parser (3.1.2.0)
28
31
  ast (~> 2.4.1)
29
32
  pathspec (1.0.0)
33
+ pry (0.14.2-java)
34
+ coderay (~> 1.1)
35
+ method_source (~> 1.0)
36
+ spoon (~> 0.0)
30
37
  puppet-modulebuilder (0.3.0)
31
38
  minitar (~> 0.9)
32
39
  pathspec (>= 0.2.1, < 2.0.0)
@@ -73,6 +80,8 @@ GEM
73
80
  net-ssh (>= 2.7)
74
81
  net-telnet (= 0.1.1)
75
82
  sfl
83
+ spoon (0.0.6)
84
+ ffi
76
85
  unicode-display_width (2.2.0)
77
86
 
78
87
  PLATFORMS
@@ -80,9 +89,10 @@ PLATFORMS
80
89
 
81
90
  DEPENDENCIES
82
91
  cem_acpt!
92
+ pry
83
93
  rake (>= 12.0)
84
94
  rspec (>= 3.0)
85
95
  rubocop
86
96
 
87
97
  BUNDLED WITH
88
- 2.3.25
98
+ 2.3.15
data/cem_acpt.gemspec CHANGED
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
34
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
+ spec.add_development_dependency 'pry'
37
38
  end
@@ -4,6 +4,7 @@ module CemAcpt::Platform::Gcp
4
4
  require 'json'
5
5
  require 'open3'
6
6
  require_relative File.join(__dir__, '..', 'base', 'cmd.rb')
7
+ require_relative File.join(__dir__, '..', 'utils', 'linux.rb')
7
8
 
8
9
  # This class provides methods to run gcloud commands. It allows for default values to be
9
10
  # set for the project, zone, and user and can also find these values from the local config.
@@ -59,6 +60,10 @@ module CemAcpt::Platform::Gcp
59
60
  @local_port ||= rand(49_512..65_535)
60
61
  end
61
62
 
63
+ def os_release
64
+ @os_release || :not_set
65
+ end
66
+
62
67
  def ssh_key
63
68
  return @ssh_key unless @ssh_key.nil?
64
69
 
@@ -108,6 +113,9 @@ module CemAcpt::Platform::Gcp
108
113
 
109
114
  # Deletes a GCP VM instance.
110
115
  def delete_instance(instance_name)
116
+ ssh_all_known_hosts.each do |kh_file|
117
+ CemAcpt::Platform::Utils::Linux::SSHelper.remove_known_host(vm_alias(instance_name), kh_file)
118
+ end
111
119
  local_exec("compute instances delete #{instance_name} --quiet")
112
120
  rescue StandardError
113
121
  # Ignore errors when deleting instances.
@@ -173,12 +181,38 @@ module CemAcpt::Platform::Gcp
173
181
  logger.debug('Restarting SSH service')
174
182
  gcloud_ssh(instance_name, 'sudo systemctl restart sshd', ignore_command_errors: true)
175
183
  logger.info("SSH connection to #{instance_name} is ready")
184
+ logger.debug('Getting OS release')
185
+ osr = gcloud_ssh(instance_name, 'sudo cat /etc/os-release')
186
+ @os_release = CemAcpt::Platform::Utils::Linux::OSRelease.new(osr)
187
+ logger.debug("OS release: #{@os_release.to_h}")
176
188
  true
177
189
  rescue StandardError => e
178
190
  logger.debug("SSH connection to #{instance_name} failed: #{e}")
179
191
  false
180
192
  end
181
193
 
194
+ def dnf_automatic_success?(instance_name, opts: {})
195
+ ssh_options = ssh_opts(instance_name: instance_name, opts: opts)
196
+ logger.debug("Checking dnf-automatic success on #{instance_name} with options #{ssh_options}")
197
+ gcloud_ssh(instance_name, 'sudo systemctl restart dnf-automatic.timer')
198
+ true
199
+ rescue StandardError => e
200
+ logger.error("DNF automatic updates on #{instance_name} failed: #{e}")
201
+ false
202
+ end
203
+
204
+ def rpm_db_check_success?(instance_name, pkgmgr, opts: {})
205
+ ssh_options = ssh_opts(instance_name: instance_name, opts: opts)
206
+ logger.debug("Checking #{pkgmgr} rpm db on #{instance_name} with options #{ssh_options}")
207
+ gcloud_ssh(instance_name, "sudo #{pkgmgr} upgrade -y rpm glibc")
208
+ gcloud_ssh(instance_name, "sudo rm -f /var/lib/rpm/.rpm.lock")
209
+ gcloud_ssh(instance_name, "sudo #{pkgmgr} upgrade -y #{pkgmgr}")
210
+ true
211
+ rescue StandardError => e
212
+ logger.error("#{pkgmgr} rpm db check on #{instance_name} failed: #{e}")
213
+ false
214
+ end
215
+
182
216
  # This function spawns a background thread to run a GCP IAP tunnel, run the given
183
217
  # code block, then kill the thread. The code block will be yielded ssh_opts that
184
218
  # are used to configure SSH connections over the IAP tunnel. The IAP tunnel is
@@ -287,6 +321,14 @@ module CemAcpt::Platform::Gcp
287
321
  "compute.#{vm_describe(vm)['id']}"
288
322
  end
289
323
 
324
+ def ssh_all_known_hosts
325
+ [
326
+ File.join(ENV['HOME'], '.ssh', 'acpt_test_known_hosts'),
327
+ File.join(ENV['HOME'], '.ssh', 'known_hosts'),
328
+ File.join(ENV['HOME'], '.ssh', 'google_compute_known_hosts'),
329
+ ]
330
+ end
331
+
290
332
  # Default options for Net::SSH
291
333
  def default_ssh_opts
292
334
  {
@@ -236,6 +236,7 @@ module CemAcpt::Platform::Gcp
236
236
  node_data: data,
237
237
  transport: :ssh,
238
238
  ssh_opts: opts,
239
+ os_release: os_release.to_h,
239
240
  }
240
241
  end
241
242
 
@@ -260,6 +261,29 @@ module CemAcpt::Platform::Gcp
260
261
  false
261
262
  end
262
263
 
264
+ def dnf_automatic_success?
265
+ if os_release.name.match?(%r{^Red Hat.*}) && os_release.version.match?(%r{^(8|9).*})
266
+ logger.debug("Checking dnf-automatic on #{name} with platform #{info[:os_release][:platform]}")
267
+ @cmd.dnf_automatic_success?(name)
268
+ else
269
+ true
270
+ end
271
+ end
272
+
273
+ def rpm_db_check_success?
274
+ if os_release.name.match?(%r{^Red Hat.*})
275
+ logger.debug("Checking rpmdb on #{name} with platform #{info[:os_release][:platform]}")
276
+ pkgmgr = os_release.version.match?(%r{^(8|9).*}) ? 'dnf' : 'yum'
277
+ @cmd.rpm_db_check_success?(name, pkgmgr)
278
+ else
279
+ true
280
+ end
281
+ end
282
+
283
+ def os_release
284
+ @cmd.os_release
285
+ end
286
+
263
287
  def destroy
264
288
  @cmd.delete_instance(name)
265
289
  end
@@ -35,6 +35,18 @@ module Platform
35
35
  @instance.ready?
36
36
  end
37
37
 
38
+ # Returns true if dnf_automatic ran successfully on the GCP instance
39
+ def dnf_automatic_success?
40
+ logger.debug("Checking if dnf_automatic ran successfully on #{node_name}...")
41
+ @instance.dnf_automatic_success?
42
+ end
43
+
44
+ # Returns true if rpm_db_check ran successfully on the GCP instance
45
+ def rpm_db_check_success?
46
+ logger.debug("Checking if rpm_db_check ran successfully on #{node_name}...")
47
+ @instance.rpm_db_check_success?
48
+ end
49
+
38
50
  # Runs the test suite against the GCP instance. Must be given a block.
39
51
  # If necessary, can pass information into the block to be used in the test suite.
40
52
  def run_tests(&block)
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CemAcpt
4
+ module Platform
5
+ module Utils
6
+ module Linux
7
+ # Module provides SSH helper methods for Linux platforms
8
+ class SSHelper
9
+ def self.ssh_keygen?
10
+ system('command -v ssh-keygen 2>&1 > /dev/null')
11
+ end
12
+
13
+ def self.remove_known_host(host, file = File.join([ENV['HOME'], '.ssh', 'known_hosts']))
14
+ if File.exist?(file)
15
+ if ssh_keygen?
16
+ system("ssh-keygen -R #{host} -f #{file} 2>&1 > /dev/null")
17
+ else
18
+ remove_known_host_no_keygen(host, file)
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.remove_known_host_no_keygen(host, file = File.join([ENV['HOME'], '.ssh', 'known_hosts']))
24
+ require 'fileutils'
25
+ found = false
26
+ File.open("#{file}.cem_acpt_new", 'w') do |f|
27
+ File.readlines(file).each do |line|
28
+ if line.include?(host)
29
+ found = true
30
+ else
31
+ f.puts(line)
32
+ end
33
+ end
34
+ end
35
+ if found
36
+ FileUtils.mv("#{file}.cem_acpt_new", file)
37
+ else
38
+ FileUtils.rm("#{file}.cem_acpt_new")
39
+ end
40
+ end
41
+ end
42
+
43
+ # Class to parse the /etc/os-release file
44
+ class OSRelease
45
+ attr_reader :properties
46
+
47
+ def initialize(os_release)
48
+ @os_release = parse_string(os_release)
49
+ @properties = []
50
+ define_properties(@os_release)
51
+ end
52
+
53
+ def to_h
54
+ @os_release
55
+ end
56
+
57
+ private
58
+
59
+ def parse_string(os_release)
60
+ os_release = os_release.split("\n")
61
+ os_release = os_release.map { |line| line.split('=', 2) }.select { |l| l.length == 2 }
62
+ os_release.map! { |k, v| [k.downcase, v.delete_prefix('"').delete_suffix('"')] }
63
+ os_release.to_h
64
+ end
65
+
66
+ def define_properties(hsh)
67
+ hsh.each do |k, v|
68
+ @properties << k
69
+ self.class.send(:define_method, k) { v }
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../logging'
4
+
5
+ module CemAcpt
6
+ module TestRunner
7
+ # Namespace for TestRunner logging wrapper
8
+ module Logging
9
+ def use_logger(logger, **prefix_parts)
10
+ if logger.nil? || !logger.is_a?(CemAcpt::TestRunner::Logging::Logger)
11
+ CemAcpt::TestRunner::Logging::Logger.new(**prefix_parts)
12
+ else
13
+ this_prefix_parts = logger.prefix_parts.dup.merge(prefix_parts)
14
+ CemAcpt::TestRunner::Logging::Logger.new(**this_prefix_parts)
15
+ end
16
+ end
17
+
18
+ # Class to handle logging for Runner objects
19
+ class Logger
20
+ include CemAcpt::Logging
21
+
22
+ attr_reader :prefix_parts
23
+
24
+ def initialize(**prefix_parts)
25
+ @prefix_parts = prefix_parts
26
+ end
27
+
28
+ def log_prefix
29
+ parts = []
30
+ parts << @prefix_parts[:test] if @prefix_parts.key?(:test)
31
+ parts << @prefix_parts[:node] if @prefix_parts.key?(:node)
32
+ parts << @prefix_parts[:stage] if @prefix_parts.key?(:stage)
33
+ parts << @prefix_parts[:step] if @prefix_parts.key?(:step)
34
+ parts.join(': ')
35
+ end
36
+
37
+ def add_prefix_parts(**parts)
38
+ @prefix_parts.merge!(parts)
39
+ end
40
+
41
+ def debug(msg, no_prefix: false)
42
+ logger.debug(format_msg(msg, no_prefix))
43
+ end
44
+
45
+ def info(msg, no_prefix: false)
46
+ logger.info(format_msg(msg, no_prefix))
47
+ end
48
+
49
+ def warn(msg, no_prefix: false)
50
+ logger.warn(format_msg(msg, no_prefix))
51
+ end
52
+
53
+ def error(msg, no_prefix: false)
54
+ logger.error(format_msg(msg, no_prefix))
55
+ end
56
+
57
+ def fatal(msg, no_prefix: false)
58
+ logger.fatal(format_msg(msg, no_prefix))
59
+ end
60
+
61
+ def <<(msg)
62
+ logger << msg
63
+ end
64
+
65
+ private
66
+
67
+ def format_msg(msg, no_prefix)
68
+ if no_prefix
69
+ msg
70
+ else
71
+ "#{log_prefix}: #{msg}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -3,8 +3,8 @@
3
3
  require 'concurrent-ruby'
4
4
  require 'open3'
5
5
  require_relative '../context'
6
- require_relative '../logging'
7
6
  require_relative '../puppet_helpers'
7
+ require_relative 'logging'
8
8
  require_relative 'runner'
9
9
 
10
10
  module CemAcpt
@@ -19,7 +19,7 @@ module CemAcpt
19
19
  # creating Runner objects, handling input and output, and exception
20
20
  # handling.
21
21
  class RunHandler
22
- include CemAcpt::Logging
22
+ include CemAcpt::TestRunner::Logging
23
23
 
24
24
  attr_accessor :run_context
25
25
 
@@ -29,6 +29,7 @@ module CemAcpt
29
29
  @module_pkg_path = Concurrent::IVar.new
30
30
  @runners = Concurrent::Array.new
31
31
  @thread_pool = Concurrent::SimpleExecutorService.new
32
+ @logger = use_logger(nil, stage: 'RunHandler')
32
33
  end
33
34
 
34
35
  # Gets the overall exit code for all runners
@@ -38,14 +39,14 @@ module CemAcpt
38
39
 
39
40
  # Runs the acceptance test suites.
40
41
  def run
41
- logger.info('RUN HANDLER: Creating and starting test runners...')
42
+ @logger.info('creating and starting test runners...')
42
43
  create_runners
43
- logger.info("RUN HANDLER: Created #{@runners.length} runners...")
44
+ @logger.info("created #{@runners.length} runners...")
44
45
  @runners.map { |r| @thread_pool.post { r.start } }
45
46
  @thread_pool.shutdown
46
47
  @thread_pool.wait_for_termination
47
48
  @thread_pool = Concurrent::SimpleExecutorService.new
48
- logger.info('Test runners have all exited...')
49
+ @logger.info('test runners have all exited...')
49
50
  rescue StandardError => e
50
51
  handle_fatal_error(e)
51
52
  ensure
@@ -70,17 +71,17 @@ module CemAcpt
70
71
  end
71
72
 
72
73
  def create_runner(node, platform)
73
- logger.info("RUN HANDLER: Creating runner for #{node.test_data[:test_name]} on node #{node.node_name}...")
74
+ @logger.info("creating runner for #{node.test_data[:test_name]} on node #{node.node_name}...")
74
75
  runner = CemAcpt::TestRunner::Runner.new(node, @run_context, platform)
75
76
  runner || runner_creation_error(node)
76
77
  end
77
78
 
78
79
  def runner_creation_error(node)
79
80
  msg = [
80
- "Failed to create runner object for node #{node.node_name}.",
81
+ "failed to create runner object for node #{node.node_name}!",
81
82
  "Cannot run test #{node.test_data[:test_name]}",
82
83
  ].join(' ')
83
- logger.error(msg)
84
+ @logger.error(msg)
84
85
  nil
85
86
  end
86
87
 
@@ -88,22 +89,22 @@ module CemAcpt
88
89
  def handle_test_results
89
90
  @runners.each do |runner|
90
91
  result = runner.run_result.to_h
91
- logger << "::group::{Results for #{runner.node.test_data[:test_name]}}\n"
92
+ @logger << "::group::{Results for #{runner.node.test_data[:test_name]}}\n"
92
93
  if result.key?('summary_line')
93
- logger.info("SUMMARY: #{result['summary_line']} for test #{runner.node.test_data[:test_name]}")
94
+ @logger.info("SUMMARY: #{result['summary_line']} for test #{runner.node.test_data[:test_name]}", no_prefix: true)
94
95
  else
95
96
  handle_runner_error_results(runner)
96
- logger << "::endgroup::\n"
97
+ @logger << "::endgroup::\n"
97
98
  next
98
99
  end
99
100
  unless runner.test_failures?
100
- logger << "::endgroup::\n"
101
+ @logger << "::endgroup::\n"
101
102
  next
102
103
  end
103
104
 
104
105
  if result.key?('examples') # Log errors outside of examples
105
106
  if result['examples'].empty? && !result['messages'].empty?
106
- logger.error(result['messages'].join("\n"))
107
+ @logger.error(result['messages'].join("\n"), no_prefix: true)
107
108
  else
108
109
  handle_example_error_pending_skipped(runner.node.node_name, result['examples'])
109
110
  end
@@ -111,7 +112,7 @@ module CemAcpt
111
112
  handle_runner_error_results(runner)
112
113
  end
113
114
  #debug_test_results(runner) if logger.debug?
114
- logger << "::endgroup::\n"
115
+ @logger << "::endgroup::\n"
115
116
  end
116
117
  end
117
118
 
@@ -121,18 +122,18 @@ module CemAcpt
121
122
  next if e['status'] == 'passed'
122
123
 
123
124
  if e['status'] == 'pending'
124
- logger.info(test_pending_msg(node_name, e))
125
+ @logger.info(test_pending_msg(node_name, e), no_prefix: true)
125
126
  else
126
- logger.error(test_error_msg(node_name, e))
127
+ @logger.error(test_error_msg(node_name, e), no_prefix: true)
127
128
  end
128
129
  end
129
130
  end
130
131
 
131
132
  # Handles logging the results of the runners that errored.
132
133
  def handle_runner_error_results(runner)
133
- logger.error("SUMMARY: Encountered an error with test #{runner.node.test_data[:test_name]} on node #{runner.node.node_name}")
134
+ @logger.error("SUMMARY: Encountered an error with test #{runner.node.test_data[:test_name]} on node #{runner.node.node_name}", no_prefix: true)
134
135
  runner.run_result.to_h.each do |k, v|
135
- logger.error("#{k.upcase}: #{v}")
136
+ @logger.error("#{k.upcase}: #{v}", no_prefix: true)
136
137
  end
137
138
  end
138
139
 
@@ -202,8 +203,8 @@ module CemAcpt
202
203
  # Gracefully handles a fatal error and exits the program.
203
204
  # @param err [StandardError, Exception] the error that caused the fatal error
204
205
  def handle_fatal_error(err)
205
- logger.fatal("RUN HANDLER: Fatal error: #{err.message}")
206
- logger.debug(err.backtrace.join("\n"))
206
+ @logger.fatal("fatal error: #{err.message}")
207
+ @logger.debug(err.backtrace.join("\n"), no_prefix: true)
207
208
  end
208
209
  end
209
210
  end