rspec-puppet-facts 2.0.5 → 4.0.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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +10 -1
- data/.github/workflows/release.yml +4 -4
- data/.github/workflows/test.yml +31 -7
- data/.rubocop.yml +16 -0
- data/.rubocop_todo.yml +133 -0
- data/CHANGELOG.md +79 -0
- data/Gemfile +6 -9
- data/README.md +25 -3
- data/Rakefile +17 -11
- data/ext/puppet_agent_components.json +1 -1
- data/lib/rspec-puppet-facts/version.rb +1 -1
- data/lib/rspec-puppet-facts.rb +105 -80
- data/rspec-puppet-facts.gemspec +12 -10
- data/spec/fixtures/metadata.json +5 -5
- data/spec/rspec_puppet_facts_spec.rb +451 -435
- metadata +71 -29
data/lib/rspec-puppet-facts.rb
CHANGED
|
@@ -2,6 +2,7 @@ require 'puppet'
|
|
|
2
2
|
require 'facter'
|
|
3
3
|
require 'facterdb'
|
|
4
4
|
require 'json'
|
|
5
|
+
require 'deep_merge'
|
|
5
6
|
|
|
6
7
|
# The purpose of this module is to simplify the Puppet
|
|
7
8
|
# module's RSpec tests by looping through all supported
|
|
@@ -56,9 +57,8 @@ module RspecPuppetFacts
|
|
|
56
57
|
#
|
|
57
58
|
# @api private
|
|
58
59
|
def on_supported_os_implementation(opts = {})
|
|
59
|
-
unless
|
|
60
|
-
raise ArgumentError, ":facterversion must be in the format 'n.n' or "
|
|
61
|
-
"'n.n.n' (n is numeric), not '#{facterversion}'"
|
|
60
|
+
unless /\A\d+\.\d+(?:\.\d+)*\z/.match?((facterversion = opts[:facterversion]))
|
|
61
|
+
raise ArgumentError, ":facterversion must be in the format 'n.n' or 'n.n.n' (n is numeric), not '#{facterversion}'"
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
filter = []
|
|
@@ -66,81 +66,75 @@ module RspecPuppetFacts
|
|
|
66
66
|
if os_sup['operatingsystemrelease']
|
|
67
67
|
Array(os_sup['operatingsystemrelease']).map do |operatingsystemmajrelease|
|
|
68
68
|
opts[:hardwaremodels].each do |hardwaremodel|
|
|
69
|
-
|
|
70
69
|
os_release_filter = "/^#{Regexp.escape(operatingsystemmajrelease.split(' ')[0])}/"
|
|
71
|
-
|
|
70
|
+
case os_sup['operatingsystem']
|
|
71
|
+
when /BSD/i
|
|
72
72
|
hardwaremodel = 'amd64'
|
|
73
|
-
|
|
73
|
+
when /Solaris/i
|
|
74
74
|
hardwaremodel = 'i86pc'
|
|
75
|
-
|
|
75
|
+
when /AIX/i
|
|
76
76
|
hardwaremodel = '/^IBM,.*/'
|
|
77
77
|
os_release_filter = if operatingsystemmajrelease =~ /\A(\d+)\.(\d+)\Z/
|
|
78
78
|
"/^#{$~[1]}#{$~[2]}00-/"
|
|
79
79
|
else
|
|
80
80
|
"/^#{operatingsystemmajrelease}-/"
|
|
81
81
|
end
|
|
82
|
-
|
|
83
|
-
hardwaremodel =
|
|
82
|
+
when /Windows/i
|
|
83
|
+
hardwaremodel = 'x86_64'
|
|
84
84
|
os_sup['operatingsystem'] = os_sup['operatingsystem'].downcase
|
|
85
85
|
operatingsystemmajrelease = operatingsystemmajrelease[/\A(?:Server )?(.+)/i, 1]
|
|
86
86
|
|
|
87
87
|
# force quoting because windows releases can contain spaces
|
|
88
88
|
os_release_filter = "\"#{operatingsystemmajrelease}\""
|
|
89
|
-
|
|
90
|
-
if operatingsystemmajrelease == '2016' && Puppet::Util::Package.versioncmp(facterversion, '3.4') < 0
|
|
91
|
-
os_release_filter = '/^10\\.0\\./'
|
|
92
|
-
end
|
|
93
|
-
elsif os_sup['operatingsystem'] =~ /Amazon/i
|
|
89
|
+
when /Amazon/i
|
|
94
90
|
# Tighten the regex for Amazon Linux 2 so that we don't pick up Amazon Linux 2016 or 2017 facts
|
|
95
|
-
os_release_filter =
|
|
91
|
+
os_release_filter = '/^2$/' if operatingsystemmajrelease == '2'
|
|
96
92
|
end
|
|
97
93
|
|
|
98
94
|
filter << {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
'os.name' => os_sup['operatingsystem'],
|
|
96
|
+
'os.release.full' => os_release_filter,
|
|
97
|
+
'os.hardware' => hardwaremodel,
|
|
102
98
|
}
|
|
103
99
|
end
|
|
104
100
|
end
|
|
105
101
|
else
|
|
106
102
|
opts[:hardwaremodels].each do |hardwaremodel|
|
|
107
103
|
filter << {
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
'os.name' => os_sup['operatingsystem'],
|
|
105
|
+
'os.hardware' => hardwaremodel,
|
|
110
106
|
}
|
|
111
107
|
end
|
|
112
108
|
end
|
|
113
109
|
end
|
|
114
110
|
|
|
115
|
-
|
|
111
|
+
strict_requirement = RspecPuppetFacts.facter_version_to_strict_requirement(facterversion)
|
|
112
|
+
|
|
113
|
+
loose_requirement = RspecPuppetFacts.facter_version_to_loose_requirement(facterversion)
|
|
114
|
+
received_facts = []
|
|
116
115
|
|
|
117
116
|
# FacterDB may have newer versions of facter data for which it contains a subset of all possible
|
|
118
117
|
# facter data (see FacterDB 0.5.2 for Facter releases 3.8 and 3.9). In this situation we need to
|
|
119
118
|
# cycle through and downgrade Facter versions per platform type until we find matching Facter data.
|
|
120
119
|
filter.each do |filter_spec|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if db.empty?
|
|
125
|
-
if RspecPuppetFacts.spec_facts_strict?
|
|
126
|
-
raise ArgumentError, "No facts were found in the FacterDB for Facter v#{facterversion} on #{filter_spec}, aborting"
|
|
127
|
-
end
|
|
120
|
+
versions = FacterDB.get_facts(filter_spec, symbolize_keys: !RSpec.configuration.facterdb_string_keys).to_h do |facts|
|
|
121
|
+
[Gem::Version.new(facts[:facterversion]), facts]
|
|
122
|
+
end
|
|
128
123
|
|
|
129
|
-
|
|
124
|
+
version, facts = versions.select { |v, _f| strict_requirement =~ v }.max_by { |v, _f| v }
|
|
130
125
|
|
|
126
|
+
unless version
|
|
127
|
+
version, facts = versions.select { |v, _f| loose_requirement =~ v }.max_by { |v, _f| v } if loose_requirement
|
|
131
128
|
next unless version
|
|
132
|
-
version = version.to_s
|
|
133
|
-
facter_version_filter = "/\\A#{Regexp.escape(version)}/"
|
|
134
129
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
raise ArgumentError, "No facts were found in the FacterDB for Facter v#{facterversion} on #{filter_spec}, aborting" if RspecPuppetFacts.spec_facts_strict?
|
|
131
|
+
|
|
132
|
+
RspecPuppetFacts.warning "No facts were found in the FacterDB for Facter v#{facterversion} on #{filter_spec}, using v#{version} instead"
|
|
138
133
|
end
|
|
139
134
|
|
|
140
|
-
|
|
135
|
+
received_facts << facts
|
|
141
136
|
end
|
|
142
137
|
|
|
143
|
-
received_facts = FacterDB::get_facts(filter)
|
|
144
138
|
unless received_facts.any?
|
|
145
139
|
RspecPuppetFacts.warning "No facts were found in the FacterDB for: #{filter.inspect}"
|
|
146
140
|
return {}
|
|
@@ -148,38 +142,25 @@ module RspecPuppetFacts
|
|
|
148
142
|
|
|
149
143
|
os_facts_hash = {}
|
|
150
144
|
received_facts.map do |facts|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
elsif facts[:operatingsystem] == 'OpenBSD'
|
|
156
|
-
operatingsystemmajrelease = facts[:operatingsystemrelease]
|
|
157
|
-
elsif facts[:operatingsystem] == 'windows' && facts[:operatingsystemrelease].start_with?('10.0.')
|
|
158
|
-
operatingsystemmajrelease = '2016'
|
|
159
|
-
elsif facts.dig(:os, 'release', 'major')
|
|
160
|
-
operatingsystemmajrelease = facts[:os]['release']['major']
|
|
161
|
-
elsif facts.dig(:os, 'distro', 'release', 'major')
|
|
162
|
-
operatingsystemmajrelease = facts[:os]['distro']['release']['major']
|
|
163
|
-
else
|
|
164
|
-
if facts[:operatingsystemmajrelease].nil?
|
|
165
|
-
operatingsystemmajrelease = facts[:operatingsystemrelease].split('.')[0]
|
|
166
|
-
else
|
|
167
|
-
operatingsystemmajrelease = facts[:operatingsystemmajrelease]
|
|
168
|
-
end
|
|
145
|
+
os_fact = RSpec.configuration.facterdb_string_keys ? facts['os'] : facts[:os]
|
|
146
|
+
unless os_fact
|
|
147
|
+
RspecPuppetFacts.warning "No os fact was found in FacterDB for: #{facts}"
|
|
148
|
+
next
|
|
169
149
|
end
|
|
170
|
-
|
|
171
|
-
|
|
150
|
+
|
|
151
|
+
os = "#{os_fact['name'].downcase}-#{os_fact['release']['major']}-#{os_fact['hardware']}"
|
|
152
|
+
next if RspecPuppetFacts.spec_facts_os_filter && !os.start_with?(RspecPuppetFacts.spec_facts_os_filter)
|
|
153
|
+
|
|
172
154
|
facts.merge! RspecPuppetFacts.common_facts
|
|
173
155
|
os_facts_hash[os] = RspecPuppetFacts.with_custom_facts(os, facts)
|
|
174
156
|
end
|
|
175
157
|
|
|
176
|
-
return stringify_keys(os_facts_hash) if RSpec.configuration.facterdb_string_keys
|
|
177
|
-
|
|
178
158
|
os_facts_hash
|
|
179
159
|
end
|
|
180
160
|
|
|
161
|
+
# @api private
|
|
181
162
|
def stringify_keys(hash)
|
|
182
|
-
|
|
163
|
+
hash.to_h { |k, v| [k.to_s, v.is_a?(Hash) ? stringify_keys(v) : v] }
|
|
183
164
|
end
|
|
184
165
|
|
|
185
166
|
# Register a custom fact that will be included in the facts hash.
|
|
@@ -210,7 +191,8 @@ module RspecPuppetFacts
|
|
|
210
191
|
# @api private
|
|
211
192
|
def self.register_custom_fact(name, value, options)
|
|
212
193
|
@custom_facts ||= {}
|
|
213
|
-
|
|
194
|
+
name = RSpec.configuration.facterdb_string_keys ? name.to_s : name.to_sym
|
|
195
|
+
@custom_facts[name] = { options: options, value: value }
|
|
214
196
|
end
|
|
215
197
|
|
|
216
198
|
# Adds any custom facts according to the rules defined for the operating
|
|
@@ -226,7 +208,13 @@ module RspecPuppetFacts
|
|
|
226
208
|
next if fact[:options][:confine] && !fact[:options][:confine].include?(os)
|
|
227
209
|
next if fact[:options][:exclude] && fact[:options][:exclude].include?(os)
|
|
228
210
|
|
|
229
|
-
|
|
211
|
+
value = fact[:value].respond_to?(:call) ? fact[:value].call(os, facts) : fact[:value]
|
|
212
|
+
# if merge_facts passed, merge supplied facts into facts hash
|
|
213
|
+
if fact[:options][:merge_facts]
|
|
214
|
+
facts.deep_merge!({ name => value })
|
|
215
|
+
else
|
|
216
|
+
facts[name] = value
|
|
217
|
+
end
|
|
230
218
|
end
|
|
231
219
|
|
|
232
220
|
facts
|
|
@@ -246,7 +234,7 @@ module RspecPuppetFacts
|
|
|
246
234
|
# @return [nil,String]
|
|
247
235
|
# @api private
|
|
248
236
|
def self.spec_facts_os_filter
|
|
249
|
-
ENV
|
|
237
|
+
ENV.fetch('SPEC_FACTS_OS', nil)
|
|
250
238
|
end
|
|
251
239
|
|
|
252
240
|
# If SPEC_FACTS_STRICT is set to `yes`, RspecPuppetFacts will error on missing FacterDB entries, instead of warning & skipping the tests, or using an older facter version.
|
|
@@ -262,10 +250,11 @@ module RspecPuppetFacts
|
|
|
262
250
|
# @return [Hash <Symbol => String>]
|
|
263
251
|
def self.common_facts
|
|
264
252
|
return @common_facts if @common_facts
|
|
253
|
+
|
|
265
254
|
@common_facts = {
|
|
266
|
-
:
|
|
267
|
-
:
|
|
268
|
-
:
|
|
255
|
+
puppetversion: Puppet.version,
|
|
256
|
+
rubysitedir: RbConfig::CONFIG['sitelibdir'],
|
|
257
|
+
rubyversion: RUBY_VERSION,
|
|
269
258
|
}
|
|
270
259
|
|
|
271
260
|
@common_facts[:mco_version] = MCollective::VERSION if mcollective?
|
|
@@ -273,6 +262,7 @@ module RspecPuppetFacts
|
|
|
273
262
|
if augeas?
|
|
274
263
|
@common_facts[:augeasversion] = Augeas.open(nil, nil, Augeas::NO_MODL_AUTOLOAD).get('/augeas/version')
|
|
275
264
|
end
|
|
265
|
+
@common_facts = stringify_keys(@common_facts) if RSpec.configuration.facterdb_string_keys
|
|
276
266
|
|
|
277
267
|
@common_facts
|
|
278
268
|
end
|
|
@@ -309,8 +299,9 @@ module RspecPuppetFacts
|
|
|
309
299
|
# @api private
|
|
310
300
|
def self.meta_supported_os
|
|
311
301
|
unless metadata['operatingsystem_support'].is_a? Array
|
|
312
|
-
|
|
302
|
+
raise StandardError, 'Unknown operatingsystem support in the metadata file!'
|
|
313
303
|
end
|
|
304
|
+
|
|
314
305
|
metadata['operatingsystem_support']
|
|
315
306
|
end
|
|
316
307
|
|
|
@@ -322,8 +313,9 @@ module RspecPuppetFacts
|
|
|
322
313
|
def self.metadata
|
|
323
314
|
return @metadata if @metadata
|
|
324
315
|
unless File.file? metadata_file
|
|
325
|
-
|
|
316
|
+
raise StandardError, "Can't find metadata.json... dunno why"
|
|
326
317
|
end
|
|
318
|
+
|
|
327
319
|
content = File.read metadata_file
|
|
328
320
|
@metadata = JSON.parse content
|
|
329
321
|
end
|
|
@@ -339,7 +331,7 @@ module RspecPuppetFacts
|
|
|
339
331
|
# @param message [String]
|
|
340
332
|
# @api private
|
|
341
333
|
def self.warning(message)
|
|
342
|
-
|
|
334
|
+
warn message
|
|
343
335
|
end
|
|
344
336
|
|
|
345
337
|
# Reset the memoization
|
|
@@ -352,13 +344,47 @@ module RspecPuppetFacts
|
|
|
352
344
|
@metadata = nil
|
|
353
345
|
end
|
|
354
346
|
|
|
355
|
-
#
|
|
356
|
-
# @return [
|
|
357
|
-
# @param version [String] the Facter version
|
|
347
|
+
# Construct the strict facter version requirement
|
|
348
|
+
# @return [Gem::Requirement] The version requirement to match
|
|
358
349
|
# @api private
|
|
359
|
-
def self.
|
|
360
|
-
|
|
361
|
-
|
|
350
|
+
def self.facter_version_to_strict_requirement(version)
|
|
351
|
+
Gem::Requirement.new(facter_version_to_strict_requirement_string(version))
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# Construct the strict facter version requirement string
|
|
355
|
+
# @return [String] The version requirement to match
|
|
356
|
+
# @api private
|
|
357
|
+
def self.facter_version_to_strict_requirement_string(version)
|
|
358
|
+
if /\A[0-9]+(\.[0-9]+)*\Z/.match?(version)
|
|
359
|
+
# Interpret 3 as ~> 3.0
|
|
360
|
+
"~> #{version}.0"
|
|
361
|
+
else
|
|
362
|
+
version
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Construct the loose facter version requirement
|
|
367
|
+
# @return [Optional[Gem::Requirement]] The version requirement to match
|
|
368
|
+
# @api private
|
|
369
|
+
def self.facter_version_to_loose_requirement(version)
|
|
370
|
+
string = facter_version_to_loose_requirement_string(version)
|
|
371
|
+
Gem::Requirement.new(string) if string
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Construct the facter version requirement string
|
|
375
|
+
# @return [String] The version requirement to match
|
|
376
|
+
# @api private
|
|
377
|
+
def self.facter_version_to_loose_requirement_string(version)
|
|
378
|
+
if (m = /\A(?<major>[0-9]+)\.(?<minor>[0-9]+)(?:\.(?<patch>[0-9]+))?\Z/.match(version))
|
|
379
|
+
# Interpret 3.1 as < 3.2 and 3.2.1 as < 3.3
|
|
380
|
+
"< #{m[:major]}.#{m[:minor].to_i + 1}"
|
|
381
|
+
elsif /\A[0-9]+\Z/.match?(version)
|
|
382
|
+
# Interpret 3 as < 4
|
|
383
|
+
"< #{version.to_i + 1}"
|
|
384
|
+
else # rubocop:disable Style/EmptyElse
|
|
385
|
+
# This would be the same as the strict requirement
|
|
386
|
+
nil
|
|
387
|
+
end
|
|
362
388
|
end
|
|
363
389
|
|
|
364
390
|
def self.facter_version_for_puppet_version(puppet_version)
|
|
@@ -373,13 +399,13 @@ module RspecPuppetFacts
|
|
|
373
399
|
fd = File.open(json_path, 'rb:UTF-8')
|
|
374
400
|
data = JSON.parse(fd.read)
|
|
375
401
|
|
|
376
|
-
version_map = data.map
|
|
402
|
+
version_map = data.map do |_, versions|
|
|
377
403
|
if versions['puppet'].nil? || versions['facter'].nil?
|
|
378
404
|
nil
|
|
379
405
|
else
|
|
380
406
|
[Gem::Version.new(versions['puppet']), versions['facter']]
|
|
381
407
|
end
|
|
382
|
-
|
|
408
|
+
end.compact
|
|
383
409
|
|
|
384
410
|
puppet_gem_version = Gem::Version.new(puppet_version)
|
|
385
411
|
applicable_versions = version_map.select { |p, _| puppet_gem_version >= p }
|
|
@@ -388,7 +414,7 @@ module RspecPuppetFacts
|
|
|
388
414
|
return Facter.version
|
|
389
415
|
end
|
|
390
416
|
|
|
391
|
-
applicable_versions.
|
|
417
|
+
applicable_versions.max_by { |p, _| p }.last
|
|
392
418
|
rescue JSON::ParserError
|
|
393
419
|
warning "#{json_path} contains invalid JSON, defaulting to Facter #{Facter.version}"
|
|
394
420
|
Facter.version
|
|
@@ -398,7 +424,6 @@ module RspecPuppetFacts
|
|
|
398
424
|
end
|
|
399
425
|
|
|
400
426
|
RSpec.configure do |c|
|
|
401
|
-
c.add_setting :default_facter_version,
|
|
402
|
-
|
|
403
|
-
c.add_setting :facterdb_string_keys, :default => false
|
|
427
|
+
c.add_setting :default_facter_version, default: RspecPuppetFacts.facter_version_for_puppet_version(Puppet.version)
|
|
428
|
+
c.add_setting :facterdb_string_keys, default: false
|
|
404
429
|
end
|
data/rspec-puppet-facts.gemspec
CHANGED
|
@@ -13,18 +13,20 @@ Gem::Specification.new do |s|
|
|
|
13
13
|
s.description = 'Contains facts from many Facter version on many Operating Systems'
|
|
14
14
|
s.licenses = 'Apache-2.0'
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
s.required_ruby_version = '>= 2.4.0'
|
|
16
|
+
s.required_ruby_version = '>= 2.7.0'
|
|
18
17
|
|
|
19
18
|
s.files = `git ls-files`.split("\n")
|
|
20
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
21
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
|
22
20
|
|
|
23
|
-
s.add_development_dependency 'mime-types'
|
|
24
|
-
s.add_development_dependency 'rake'
|
|
25
|
-
s.add_development_dependency 'rspec'
|
|
26
|
-
s.add_development_dependency 'yard'
|
|
27
|
-
|
|
28
|
-
s.
|
|
29
|
-
|
|
21
|
+
s.add_development_dependency 'mime-types', '~> 3.5', '>= 3.5.2'
|
|
22
|
+
s.add_development_dependency 'rake', '~> 13.1'
|
|
23
|
+
s.add_development_dependency 'rspec', '~> 3.12'
|
|
24
|
+
s.add_development_dependency 'yard', '~> 0.9.34'
|
|
25
|
+
|
|
26
|
+
s.add_development_dependency 'voxpupuli-rubocop', '~> 2.7.0'
|
|
27
|
+
|
|
28
|
+
s.add_runtime_dependency 'deep_merge', '~> 1.2'
|
|
29
|
+
s.add_runtime_dependency 'facter', '< 5'
|
|
30
|
+
s.add_runtime_dependency 'facterdb', '~> 2.1'
|
|
31
|
+
s.add_runtime_dependency 'puppet', '>= 7', '< 9'
|
|
30
32
|
end
|
data/spec/fixtures/metadata.json
CHANGED
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
{
|
|
16
16
|
"operatingsystem": "Debian",
|
|
17
17
|
"operatingsystemrelease": [
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"11",
|
|
19
|
+
"12"
|
|
20
20
|
]
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"operatingsystem": "RedHat",
|
|
24
24
|
"operatingsystemrelease": [
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
25
|
+
"7",
|
|
26
|
+
"8",
|
|
27
|
+
"9"
|
|
28
28
|
]
|
|
29
29
|
}
|
|
30
30
|
],
|