Skip to content

Commit 1392ffb

Browse files
committed
Merge branch '1.6.x'
2 parents 6d77e7d + 0cf84e5 commit 1392ffb

File tree

13 files changed

+270
-105
lines changed

13 files changed

+270
-105
lines changed

Rakefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,30 @@ end
1414
require 'rspec/core/rake_task'
1515

1616
RSpec::Core::RakeTask.new(:spec) do |t|
17-
Rake::Task[:spec_prep].invoke
1817
# thanks to the fixtures/modules/ symlinks this needs to exclude fixture modules explicitely
1918
excludes = ['fixtures/**/*.rb,fixtures/modules/*/**/*.rb']
2019
if RUBY_PLATFORM == 'java'
2120
excludes += ['acceptance/**/*.rb', 'integration/**/*.rb', 'puppet/resource_api/*_context_spec.rb', 'puppet/util/network_device/simple/device_spec.rb']
2221
t.rspec_opts = '--tag ~agent_test'
22+
t.rspec_opts << ' --tag ~j17_exclude' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0')
2323
end
2424
t.exclude_pattern = "spec/{#{excludes.join ','}}"
2525
end
2626

27+
task :spec => :spec_prep
28+
2729
namespace :spec do
2830
desc 'Run RSpec code examples with coverage collection'
2931
task :coverage do
3032
ENV['SIMPLECOV'] = 'yes'
3133
Rake::Task['spec'].execute
3234
end
35+
36+
RSpec::Core::RakeTask.new(:unit) do |t|
37+
t.pattern = "spec/puppet/**/*_spec.rb,spec/integration/**/*_spec.rb"
38+
end
39+
40+
task :unit => :spec_prep
3341
end
3442

3543
#### LICENSE_FINDER ####

lib/puppet/resource_api.rb

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def type_definition
6666
apply_to_device
6767
end
6868

69-
define_method(:initialize) do |attributes|
69+
def initialize(attributes)
7070
# $stderr.puts "A: #{attributes.inspect}"
7171
if attributes.is_a? Puppet::Resource
7272
@title = attributes.title
@@ -94,7 +94,7 @@ def type_definition
9494
# the `Puppet::Resource::Ral.find` method, when `instances` does not return a match, uses a Hash with a `:name` key to create
9595
# an "absent" resource. This is often hit by `puppet resource`. This needs to work, even if the namevar is not called `name`.
9696
# This bit here relies on the default `title_patterns` (see below) to match the title back to the first (and often only) namevar
97-
if definition[:attributes][:name].nil? && attributes[:title].nil?
97+
if type_definition.attributes[:name].nil? && attributes[:title].nil?
9898
attributes[:title] = attributes.delete(:name)
9999
if attributes[:title].nil? && !type_definition.namevars.empty?
100100
attributes[:title] = @title
@@ -108,11 +108,25 @@ def name
108108
title
109109
end
110110

111+
def self.build_title(type_definition, resource_hash)
112+
if type_definition.namevars.size > 1
113+
# use a MonkeyHash to allow searching in Puppet's RAL
114+
Puppet::ResourceApi::MonkeyHash[type_definition.namevars.map { |attr| [attr, resource_hash[attr]] }]
115+
else
116+
resource_hash[type_definition.namevars[0]]
117+
end
118+
end
119+
120+
def rsapi_title
121+
@rsapi_title ||= self.class.build_title(type_definition, self)
122+
@rsapi_title
123+
end
124+
111125
def to_resource
112126
to_resource_shim(super)
113127
end
114128

115-
define_method(:to_resource_shim) do |resource|
129+
def to_resource_shim(resource)
116130
resource_hash = Hash[resource.keys.map { |k| [k, resource[k]] }]
117131
resource_hash[:title] = resource.title
118132
ResourceShim.new(resource_hash, type_definition.name, type_definition.namevars, type_definition.attributes, catalog)
@@ -213,7 +227,7 @@ def to_resource
213227
end
214228
end
215229

216-
define_singleton_method(:instances) do
230+
def self.instances
217231
# puts 'instances'
218232
# force autoloading of the provider
219233
provider(type_definition.name)
@@ -230,16 +244,16 @@ def to_resource
230244
result = if resource_hash.key? :title
231245
new(title: resource_hash[:title])
232246
else
233-
new(title: resource_hash[type_definition.namevars.first])
247+
new(title: build_title(type_definition, resource_hash))
234248
end
235249
result.cache_current_state(resource_hash)
236250
result
237251
end
238252
end
239253

240-
define_method(:refresh_current_state) do
254+
def refresh_current_state
241255
@rsapi_current_state = if type_definition.feature?('simple_get_filter')
242-
my_provider.get(context, [title]).find { |h| namevar_match?(h) }
256+
my_provider.get(context, [rsapi_title]).find { |h| namevar_match?(h) }
243257
else
244258
my_provider.get(context).find { |h| namevar_match?(h) }
245259
end
@@ -248,7 +262,11 @@ def to_resource
248262
type_definition.check_schema(@rsapi_current_state)
249263
strict_check(@rsapi_current_state) if type_definition.feature?('canonicalize')
250264
else
251-
@rsapi_current_state = { title: title }
265+
@rsapi_current_state = if rsapi_title.is_a? Hash
266+
rsapi_title.dup
267+
else
268+
{ title: rsapi_title }
269+
end
252270
@rsapi_current_state[:ensure] = :absent if type_definition.ensurable?
253271
end
254272
end
@@ -259,7 +277,7 @@ def cache_current_state(resource_hash)
259277
strict_check(@rsapi_current_state) if type_definition.feature?('canonicalize')
260278
end
261279

262-
define_method(:retrieve) do
280+
def retrieve
263281
refresh_current_state unless @rsapi_current_state
264282

265283
Puppet.debug("Current State: #{@rsapi_current_state.inspect}")
@@ -273,13 +291,13 @@ def cache_current_state(resource_hash)
273291
result
274292
end
275293

276-
define_method(:namevar_match?) do |item|
294+
def namevar_match?(item)
277295
context.type.namevars.all? do |namevar|
278296
item[namevar] == @parameters[namevar].value if @parameters[namevar].respond_to? :value
279297
end
280298
end
281299

282-
define_method(:flush) do
300+
def flush
283301
raise_missing_attrs
284302

285303
# puts 'flush'
@@ -297,7 +315,7 @@ def cache_current_state(resource_hash)
297315
# enforce init_only attributes
298316
if Puppet.settings[:strict] != :off && @rsapi_current_state && (@rsapi_current_state[:ensure] == 'present' && target_state[:ensure] == 'present')
299317
target_state.each do |name, value|
300-
next unless definition[:attributes][name][:behaviour] == :init_only && value != @rsapi_current_state[name]
318+
next unless type_definition.attributes[name][:behaviour] == :init_only && value != @rsapi_current_state[name]
301319
message = "Attempting to change `#{name}` init_only attribute value from `#{@rsapi_current_state[name]}` to `#{value}`"
302320
case Puppet.settings[:strict]
303321
when :warning
@@ -309,27 +327,27 @@ def cache_current_state(resource_hash)
309327
end
310328

311329
if type_definition.feature?('supports_noop')
312-
my_provider.set(context, { title => { is: @rsapi_current_state, should: target_state } }, noop: noop?)
330+
my_provider.set(context, { rsapi_title => { is: @rsapi_current_state, should: target_state } }, noop: noop?)
313331
else
314-
my_provider.set(context, title => { is: @rsapi_current_state, should: target_state }) unless noop?
332+
my_provider.set(context, rsapi_title => { is: @rsapi_current_state, should: target_state }) unless noop?
315333
end
316334
raise 'Execution encountered an error' if context.failed?
317335

318336
# remember that we have successfully reached our desired state
319337
@rsapi_current_state = target_state
320338
end
321339

322-
define_method(:raise_missing_attrs) do
340+
def raise_missing_attrs
323341
error_msg = "The following mandatory attributes were not provided:\n * " + @missing_attrs.join(", \n * ")
324342
raise Puppet::ResourceError, error_msg if @missing_attrs.any? && (value(:ensure) != :absent && !value(:ensure).nil?)
325343
end
326344

327-
define_method(:raise_missing_params) do
345+
def raise_missing_params
328346
error_msg = "The following mandatory parameters were not provided:\n * " + @missing_params.join(", \n * ")
329347
raise Puppet::ResourceError, error_msg
330348
end
331349

332-
define_method(:strict_check) do |current_state|
350+
def strict_check(current_state)
333351
return if Puppet.settings[:strict] == :off
334352

335353
# if strict checking is on we must notify if the values are changed by canonicalize
@@ -343,7 +361,7 @@ def cache_current_state(resource_hash)
343361
#:nocov:
344362
# codecov fails to register this multiline as covered, even though simplecov does.
345363
message = <<MESSAGE.strip
346-
#{definition[:name]}[#{@title}]#get has not provided canonicalized values.
364+
#{type_definition.name}[#{@title}]#get has not provided canonicalized values.
347365
Returned values: #{current_state.inspect}
348366
Canonicalized values: #{state_clone.inspect}
349367
MESSAGE
@@ -356,7 +374,7 @@ def cache_current_state(resource_hash)
356374
raise Puppet::DevError, message
357375
end
358376

359-
return nil
377+
nil
360378
end
361379

362380
define_singleton_method(:context) do
@@ -367,9 +385,9 @@ def context
367385
self.class.context
368386
end
369387

370-
define_singleton_method(:title_patterns) do
371-
@title_patterns ||= if definition.key? :title_patterns
372-
parse_title_patterns(definition[:title_patterns])
388+
def self.title_patterns
389+
@title_patterns ||= if type_definition.definition.key? :title_patterns
390+
parse_title_patterns(type_definition.definition[:title_patterns])
373391
else
374392
[[%r{(.*)}m, [[type_definition.namevars.first]]]]
375393
end

lib/puppet/resource_api/glue.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,19 @@ def filtered_keys
5757
values.keys.reject { |k| k == :title || !attr_def[k] || (attr_def[k][:behaviour] == :namevar && @namevars.size == 1) }
5858
end
5959
end
60+
61+
# this hash allows key-value based ordering comparisons between instances of this and instances of this and other classes
62+
# this is required for `lib/puppet/indirector/resource/ral.rb`'s `search` method which expects all titles to be comparable
63+
class MonkeyHash < Hash
64+
def <=>(other)
65+
result = self.class.name <=> other.class.name
66+
if result.zero?
67+
result = keys.sort <=> other.keys.sort
68+
end
69+
if result.zero?
70+
result = keys.sort.map { |k| self[k] } <=> other.keys.sort.map { |k| other[k] }
71+
end
72+
result
73+
end
74+
end
6075
end

lib/puppet/resource_api/simple_provider.rb

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
module Puppet; end # rubocop:disable Style/Documentation
2+
23
module Puppet::ResourceApi
34
# This class provides a default implementation for set(), when your resource does not benefit from batching.
45
# Instead of processing changes yourself, the `create`, `update`, and `delete` functions, are called for you,
@@ -19,12 +20,12 @@ def set(context, changes)
1920

2021
raise 'SimpleProvider cannot be used with a Type that is not ensurable' unless context.type.ensurable?
2122

22-
is = { name: name, ensure: 'absent' } if is.nil?
23-
should = { name: name, ensure: 'absent' } if should.nil?
23+
is = SimpleProvider.create_absent(:name, name) if is.nil?
24+
should = SimpleProvider.create_absent(:name, name) if should.nil?
2425

2526
name_hash = if context.type.namevars.length > 1
2627
# pass a name_hash containing the values of all namevars
27-
name_hash = { title: name }
28+
name_hash = {}
2829
context.type.namevars.each do |namevar|
2930
name_hash[namevar] = change[:should][namevar]
3031
end
@@ -60,5 +61,16 @@ def update(_context, _name, _should)
6061
def delete(_context, _name)
6162
raise "#{self.class} has not implemented `delete`"
6263
end
64+
65+
# @api private
66+
def self.create_absent(namevar, title)
67+
result = if title.is_a? Hash
68+
title.dup
69+
else
70+
{ namevar => title }
71+
end
72+
result[:ensure] = 'absent'
73+
result
74+
end
6375
end
6476
end

0 commit comments

Comments
 (0)