cem_acpt 0.7.3 → 0.8.0

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: 251ddea81d792241accdd3e63fb1b33ce655e458c08939f6da6a043cb2eeeeef
4
- data.tar.gz: 7cf6e742a5375c190bba491e607b742263e40e15b82e68d1c383d9ca634e7b4f
3
+ metadata.gz: 853cc9a89c0feaf798bb5efdfc0c8af47d2664121cddd3794b65a61d5dc80851
4
+ data.tar.gz: 6d0d5c67e27918d7897ea567a4134249c8a81e23ea95e6a3850a65585ebdd3e0
5
5
  SHA512:
6
- metadata.gz: 79709f1e861e2eea1b31be633076271fefa027656dcfb8e78c252d0492286cf6376547d8756772447b28c1fe6a625cf0fee289f4a84d7e5b7e9bbfa2ef182f71
7
- data.tar.gz: 7fc8c5351bce46273f5d57e743e1865c6d844f89fd702da451082042921cf9aae01473f90b11a3a53e810c6e2f53132de9e75d7d8d0b97c08db105c2abe172f5
6
+ metadata.gz: 244c701ba966fa878c399efba4953db7be8f5977c906501f9d2da8410583ebf2c2c505c687dc03e8cd97b325f362b28472f68c089065cda21f83d01d16c15d22
7
+ data.tar.gz: ae7ca222e4264ed32ed47df2745d76c8347c1b5eab94cd2f0278af581c7c7108fb006232c5bbb4d37b2455559c0826a5630498cd620d4fd85a8948b8a0856c22
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ require:
3
3
  - rubocop-performance
4
4
  - rubocop-rspec
5
5
  AllCops:
6
- NewCops: enable
6
+ NewCops: disable
7
7
  SuggestExtensions: false
8
8
  DisplayCopNames: true
9
9
  TargetRubyVersion: '3.2'
@@ -414,6 +414,8 @@ Style/HashAsLastArrayItem:
414
414
  Enabled: false
415
415
  Style/HashLikeCase:
416
416
  Enabled: false
417
+ Style/HashSyntax:
418
+ Enabled: false
417
419
  Style/HashTransformKeys:
418
420
  Enabled: false
419
421
  Style/HashTransformValues:
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_acpt (0.7.3)
4
+ cem_acpt (0.8.0)
5
5
  async-http (>= 0.60, < 0.70)
6
6
  bcrypt_pbkdf (>= 1.0, < 2.0)
7
7
  deep_merge (>= 1.2, < 2.0)
8
8
  ed25519 (>= 1.2, < 2.0)
9
9
  puppet-modulebuilder (>= 0.0.1)
10
- ruby-terraform (~> 1.7)
10
+ winrm (>= 2.3, < 3.0)
11
11
 
12
12
  GEM
13
13
  remote: https://rubygems.org/
@@ -30,25 +30,32 @@ GEM
30
30
  async-pool (0.4.0)
31
31
  async (>= 1.25)
32
32
  bcrypt_pbkdf (1.1.0)
33
+ builder (3.2.4)
33
34
  coderay (1.1.3)
34
- concurrent-ruby (1.2.2)
35
35
  console (1.16.2)
36
36
  fiber-local
37
37
  deep_merge (1.2.2)
38
38
  diff-lcs (1.5.0)
39
39
  ed25519 (1.3.0)
40
+ erubi (1.12.0)
41
+ ffi (1.15.5)
40
42
  fiber-local (1.0.0)
41
- hamster (3.0.0)
42
- concurrent-ruby (~> 1.0)
43
- immutable-struct (2.4.1)
43
+ gssapi (1.3.1)
44
+ ffi (>= 1.0.1)
45
+ gyoku (1.4.0)
46
+ builder (>= 2.1.2)
47
+ rexml (~> 3.0)
48
+ httpclient (2.8.3)
44
49
  io-event (1.1.7)
45
50
  json (2.6.3)
46
- lino (3.1.0)
47
- hamster (~> 3.0)
48
- open4 (~> 1.3)
51
+ little-plugger (1.1.4)
52
+ logging (2.3.1)
53
+ little-plugger (~> 1.1)
54
+ multi_json (~> 1.14)
49
55
  method_source (1.0.0)
50
56
  minitar (0.9)
51
- open4 (1.3.4)
57
+ multi_json (1.15.0)
58
+ nori (2.6.0)
52
59
  parallel (1.22.1)
53
60
  parser (3.2.1.1)
54
61
  ast (~> 2.4.1)
@@ -95,15 +102,34 @@ GEM
95
102
  unicode-display_width (>= 2.4.0, < 3.0)
96
103
  rubocop-ast (1.28.0)
97
104
  parser (>= 3.2.1.0)
105
+ rubocop-capybara (2.18.0)
106
+ rubocop (~> 1.41)
107
+ rubocop-factory_bot (2.23.1)
108
+ rubocop (~> 1.33)
109
+ rubocop-performance (1.19.0)
110
+ rubocop (>= 1.7.0, < 2.0)
111
+ rubocop-ast (>= 0.4.0)
112
+ rubocop-rspec (2.23.2)
113
+ rubocop (~> 1.33)
114
+ rubocop-capybara (~> 2.17)
115
+ rubocop-factory_bot (~> 2.22)
98
116
  ruby-progressbar (1.13.0)
99
- ruby-terraform (1.7.0)
100
- immutable-struct (~> 2.4)
101
- lino (~> 3.0)
117
+ rubyntlm (0.6.3)
102
118
  timers (4.3.5)
103
119
  traces (0.9.1)
104
120
  unicode-display_width (2.4.2)
121
+ winrm (2.3.6)
122
+ builder (>= 2.1.2)
123
+ erubi (~> 1.8)
124
+ gssapi (~> 1.2)
125
+ gyoku (~> 1.0)
126
+ httpclient (~> 2.2, >= 2.2.0.2)
127
+ logging (>= 1.6.1, < 3.0)
128
+ nori (~> 2.0)
129
+ rubyntlm (~> 0.6.0, >= 0.6.3)
105
130
 
106
131
  PLATFORMS
132
+ arm64-darwin-22
107
133
  x86_64-darwin-20
108
134
  x86_64-linux
109
135
 
@@ -113,6 +139,8 @@ DEPENDENCIES
113
139
  rake (>= 12.0)
114
140
  rspec (>= 3.0)
115
141
  rubocop
142
+ rubocop-performance
143
+ rubocop-rspec
116
144
 
117
145
  BUNDLED WITH
118
- 2.4.6
146
+ 2.4.18
data/README.md CHANGED
@@ -89,6 +89,10 @@ Options set in the user-specific config file will be overridden by options set i
89
89
 
90
90
  CemAcpt can be configured using command-line options. These options are specified using the `--<option>` syntax. For a full list of options, run `cem_acpt -h`. Options specified on the command-line will override options specified in the config file and environment variables.
91
91
 
92
+ #### Tracing
93
+
94
+ To aide in development, you can enable tracing on CemAcpt's Ruby code execution by using the `--trace` flag. Traces are logged only for events executed by CemAcpt code itself, and the logger code is exempt from tracing. **CAUTION** Tracing produces **a lot** of logs and it's advised to only use it when logging to a file. Additionally, the specific trace events that are logged can be specified using the `--trace-events` flag. Tracing is enabled by the [TracePoint](https://ruby-doc.org/core-3.1.0/TracePoint.html) class.
95
+
92
96
  ## Goss
93
97
 
94
98
  [Goss](https://github.com/goss-org/goss/blob/master/docs/manual.md) is the core infrastructure testing tool used by CemAcpt. The `goss.yaml` file is used to specify the tests to run. Please see the [Goss documentation](https://github.com/goss-org/goss/blob/master/docs/manual.md#goss-test-creation) for more information on how to write Goss tests.
@@ -248,3 +252,7 @@ images:
248
252
  ```
249
253
 
250
254
  See [sample_config.yaml](sample_config.yaml) for a more complete example.
255
+
256
+ ### Testing with cem_windows
257
+
258
+ While testing with cem_windows follows pretty much the same outline as cem_linux, there are a few extra step that we have to do when bootstrapping the generated node. Two of the most prominents steps are enabling long path and using NSSM to start the goss service. When we enable long path on Windows, it allows the command `puppet module install` to install dependencies correctly (specifically the dsc modules). As for [NSSM](https://nssm.cc/), stands for Non-sucking service manager, it is necessary for us to use this tool because without it, we will not be able to create services for Goss. Windows services cannot run from an executable but rather through a Windows service project that can be build with Visual Studio. NSSM allows us to bypass having to create Windows service project for Goss and create services directly from the Goss executable.
data/cem_acpt.gemspec CHANGED
@@ -32,7 +32,9 @@ Gem::Specification.new do |spec|
32
32
  spec.add_runtime_dependency 'deep_merge', '>= 1.2', '< 2.0'
33
33
  spec.add_runtime_dependency 'ed25519', '>= 1.2', '< 2.0'
34
34
  spec.add_runtime_dependency 'puppet-modulebuilder', '>= 0.0.1'
35
- spec.add_runtime_dependency 'ruby-terraform', '~> 1.7'
35
+ spec.add_runtime_dependency 'winrm', '>= 2.3', '< 3.0'
36
36
  spec.add_development_dependency 'pry'
37
37
  spec.add_development_dependency 'rubocop'
38
+ spec.add_development_dependency 'rubocop-performance'
39
+ spec.add_development_dependency 'rubocop-rspec'
38
40
  end
data/exe/cem_acpt_image CHANGED
File without changes
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CemAcpt
4
+ # Wrapper class for the result of an action. Provides a common interface for
5
+ # getting reportable data from the result.
6
+ class ActionResult
7
+ def initialize(result)
8
+ @result = if result.instance_of?(CemAcpt::Goss::Api::ActionResponse)
9
+ result
10
+ else
11
+ ErrorActionResult.new(result)
12
+ end
13
+ end
14
+
15
+ def error?
16
+ @result.is_a?(ErrorActionResult)
17
+ end
18
+
19
+ def method_missing(method_name, *args, **kwargs, &block)
20
+ if @result.respond_to?(method_name)
21
+ @result.send(method_name, *args, **kwargs, &block)
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def respond_to_missing?(method_name, include_private = false)
28
+ @result.respond_to?(method_name, include_private) || super
29
+ end
30
+ end
31
+
32
+ # Wrapper class for an error raised during an action.
33
+ class ErrorActionResult
34
+ attr_reader :error
35
+
36
+ def initialize(error)
37
+ @error = error
38
+ end
39
+
40
+ def error?
41
+ true
42
+ end
43
+
44
+ def success?
45
+ false
46
+ end
47
+
48
+ def to_s
49
+ "#<#{@error.class.name}:0x#{@error.object_id.to_s(16)}>"
50
+ end
51
+
52
+ def inspect
53
+ to_s
54
+ end
55
+
56
+ def to_h
57
+ {
58
+ class: @error.class.name,
59
+ message: @error.message,
60
+ backtrace: @error.backtrace,
61
+ }
62
+ end
63
+
64
+ def status
65
+ 1
66
+ end
67
+ alias http_status status
68
+
69
+ def results
70
+ @error.backtrace
71
+ end
72
+
73
+ def results?
74
+ true
75
+ end
76
+
77
+ def summary
78
+ @error.message
79
+ end
80
+
81
+ def summary?
82
+ true
83
+ end
84
+ end
85
+ end
data/lib/cem_acpt/cli.rb CHANGED
@@ -9,7 +9,7 @@ module CemAcpt
9
9
  options = {}
10
10
  parser = OptionParser.new do |opts|
11
11
  opts.banner = "Usage: #{command} [options]"
12
-
12
+
13
13
  opts.on('-h', '--help', 'Show this help message') do
14
14
  puts opts
15
15
  exit 0
@@ -21,17 +21,17 @@ module CemAcpt
21
21
  opts.on('-m', '--module-dir DIR', 'Set module directory. Example: -m "/tmp/module"') do |m|
22
22
  options[:module_dir] = m
23
23
  end
24
-
24
+
25
25
  opts.on('-a', '--only-actions ACTIONS', 'Set actions. Example: -a "acpt,noop"') do |a|
26
26
  options[:actions] ||= {}
27
27
  options[:actions][:only] = a.split(',')
28
28
  end
29
-
29
+
30
30
  opts.on('-A', '--except-actions ACTIONS', 'Set excluded actions. Example: -A "noop,idempotent"') do |a|
31
31
  options[:actions] ||= {}
32
32
  options[:actions][:except] = a.split(',')
33
33
  end
34
-
34
+
35
35
  opts.on('-t', '--tests TESTS', 'Set tests. Example: -t "test1,test2"') do |t|
36
36
  options[:tests] = t.split(',')
37
37
  end
@@ -58,67 +58,87 @@ module CemAcpt
58
58
  options[:image_name_filter] = Regexp.new(f)
59
59
  end
60
60
  end
61
-
61
+
62
62
  opts.on('-D', '--debug', 'Enable debug logging') do
63
63
  options[:log_level] = 'debug'
64
64
  end
65
-
65
+
66
66
  opts.on('-L', '--log-file FILE', 'Log to FILE') do |file|
67
67
  options[:log_file] = file
68
68
  end
69
-
69
+
70
70
  opts.on('-O', '--options OPTS', 'Set options. Example: -P "param1=value1,param2=value2"') do |o|
71
71
  params = o.split(',').map { |s| s.split('=') }.to_h
72
72
  params.transform_keys(&:to_sym).each do |k, v|
73
73
  options[k] = v
74
74
  end
75
75
  end
76
-
76
+
77
77
  opts.on('-p', '--platform PLATFORM', 'Set platform. Example: -p "gcp"') do |p|
78
78
  options[:platform] = p
79
79
  end
80
-
80
+
81
81
  opts.on('-c', '--config-file FILE', 'Set config file. Example: -c "/tmp/config.yaml"') do |c|
82
82
  options[:config_file] = c
83
83
  end
84
-
84
+
85
85
  opts.on('-I', '--CI', 'Run in CI mode (modifies logging for Github Actions output)') do
86
86
  options[:ci_mode] = true
87
87
  options[:log_format] = 'github_action'
88
88
  end
89
-
89
+
90
90
  opts.on('-E', '--no-destroy-nodes', 'Do not destroy nodes') do
91
91
  options[:no_destroy_nodes] = true
92
92
  end
93
-
93
+
94
94
  opts.on('-q', '--quiet', 'Do not log to stdout') do
95
95
  options[:quiet] = true
96
96
  end
97
-
97
+
98
98
  opts.on('-v', '--verbose', 'Enables verbose logging mode') do
99
99
  options[:verbose] = true
100
100
  end
101
-
101
+
102
102
  opts.on('-S', '--no-epehemeral-ssh-key', 'Do not generate an ephemeral SSH key for test suites') do
103
103
  options[:no_ephemeral_ssh_key] = true
104
104
  end
105
-
105
+
106
106
  opts.on('-V', '--version', 'Show the cem_acpt version') do
107
107
  cmd = :version
108
108
  end
109
-
109
+
110
110
  opts.on('-Y', '--print-yaml-config', 'Loads and prints the config as YAML. Other specified options will be added to the config.') do
111
111
  cmd = :print_yaml_config
112
112
  end
113
-
113
+
114
114
  opts.on('-X', '--explain-config', 'Loads and prints the config explanation. Other specified options will be added to the config.') do
115
115
  cmd = :print_explain_config
116
116
  end
117
-
118
- # NOT IMPLEMENTED
119
- # opts.on('-R', '--reuse-nodes', 'Reuses test nodes if compatible node inventory exists') do
120
- # options[:reuse_nodes] = true
121
- # end
117
+
118
+ opts.on('--trace', 'Enables trace output') do
119
+ options[:trace] = true
120
+ end
121
+
122
+ opts.on(
123
+ '--trace-events [EVENTS]',
124
+ [
125
+ 'Comma-separated list of trace events to enable. Example: --trace-events "line,call,b_call,thread_begin,thread_end"',
126
+ 'See here for list of events: https://ruby-doc.org/core-2.5.0/TracePoint.html#class-TracePoint-label-Events.',
127
+ 'Default: line,call,b_call,thread_begin,thread_end',
128
+ ].join(' '),
129
+ ) do |events|
130
+ options[:trace_events] = events.split(',')
131
+ end
132
+
133
+ opts.on('--puppet-no-debug', 'Disables Puppet debug logging') do
134
+ options[:puppet] ||= {}
135
+ options[:puppet][:no_debug] = true
136
+ end
137
+
138
+ opts.on('--puppet-no-verbose', 'Disables Puppet verbose logging') do
139
+ options[:puppet] ||= {}
140
+ options[:puppet][:no_verbose] = true
141
+ end
122
142
  end
123
143
  parser.parse!
124
144
  [cmd, options]
@@ -33,6 +33,7 @@ module CemAcpt
33
33
  no_ephemeral_ssh_key
34
34
  platform
35
35
  provisioner
36
+ puppet
36
37
  quiet
37
38
  terraform
38
39
  user_config
@@ -85,6 +86,7 @@ module CemAcpt
85
86
  add_static_options!(@config)
86
87
  @config.format! # Symbolize keys of all hashes
87
88
  validate_config!
89
+ @dot_key_cache = {}
88
90
  # Freeze the config so it can't be modified
89
91
  # This helps with thread safety and deterministic behavior
90
92
  @config.freeze
@@ -115,14 +117,14 @@ module CemAcpt
115
117
  if key.is_a?(Symbol)
116
118
  @config[key].dup
117
119
  elsif key.is_a?(String)
118
- @config.dget(key).dup
120
+ get(key)
119
121
  else
120
122
  raise ArgumentError, "Invalid key type '#{key.class}'"
121
123
  end
122
124
  end
123
125
 
124
126
  def get(dot_key)
125
- @config.dget(dot_key).dup
127
+ @dot_key_cache[dot_key] ||= @config.dget(dot_key).dup
126
128
  end
127
129
  alias dget get
128
130
 
@@ -5,12 +5,15 @@ require 'async/barrier'
5
5
  require 'async/http/internet'
6
6
  require 'json'
7
7
  require_relative 'api/action_response'
8
+ require_relative '../logging'
8
9
 
9
10
  module CemAcpt
10
11
  module Goss
11
12
  # Holds methods for interacting with the Goss API running on a test node.
12
13
  module Api
13
14
  class << self
15
+ include CemAcpt::Logging
16
+
14
17
  # The actions that can be run against the Goss API. The key is the action
15
18
  # name and the value is the port/endpoint of the action.
16
19
  ACTIONS = {
@@ -40,16 +43,17 @@ module CemAcpt
40
43
  raise ArgumentError, 'results must be a Queue-like object implementing #<<' unless results.respond_to?(:<<)
41
44
  raise ArgumentError, 'only must be an Array' unless except.is_a?(Array)
42
45
  raise ArgumentError, 'except must be an Array' unless except.is_a?(Array)
46
+ logger.info('CemAcpt::Goss::Api') { "Running test actions against #{hosts.size} host(s)..." }
43
47
  only.map!(&:to_sym)
44
48
  except.map!(&:to_sym)
45
49
  only_specified = !only.empty?
46
50
  except_specified = !except.empty?
47
- Async do
51
+ task = Async do
48
52
  internet = Async::HTTP::Internet.new
49
53
  barrier = Async::Barrier.new
50
54
  barrier.async do
51
55
  hosts.each do |host|
52
- ACTIONS.keys.each do |action, _|
56
+ ACTIONS.each_key do |action|
53
57
  next if only_specified && !only.include?(action)
54
58
  next if except_specified && except.include?(action)
55
59
 
@@ -62,6 +66,8 @@ module CemAcpt
62
66
  internet&.close
63
67
  results.close if results.respond_to?(:close)
64
68
  end
69
+ task.wait
70
+ logger.info('CemAcpt::Goss::Api') { 'Finished running test actions, returning results...' }
65
71
  results
66
72
  end
67
73