55require 'puppet/resource_api/glue'
66require 'puppet/resource_api/parameter'
77require 'puppet/resource_api/property'
8+ require 'puppet/resource_api/provider_get_cache'
89require 'puppet/resource_api/puppet_context' unless RUBY_PLATFORM == 'java'
910require 'puppet/resource_api/read_only_parameter'
1011require 'puppet/resource_api/transport'
@@ -69,6 +70,15 @@ def type_definition
6970 apply_to_device
7071 end
7172
73+ define_singleton_method ( :rsapi_provider_get_cache ) do
74+ # This gives a new cache per resource provider on each Puppet run:
75+ @rsapi_provider_get_cache ||= Puppet ::ResourceApi ::ProviderGetCache . new
76+ end
77+
78+ def rsapi_provider_get_cache
79+ self . class . rsapi_provider_get_cache
80+ end
81+
7282 def initialize ( attributes )
7383 # $stderr.puts "A: #{attributes.inspect}"
7484 if attributes . is_a? Puppet ::Resource
@@ -154,8 +164,17 @@ def generate
154164 end
155165
156166 def rsapi_current_state
157- refresh_current_state unless @rsapi_current_state
158- @rsapi_current_state
167+ return @rsapi_current_state if @rsapi_current_state
168+ # If the current state is not set, then check the cache and, if a value is
169+ # found, ensure it passes strict_check before allowing it to be used:
170+ cached_value = rsapi_provider_get_cache . get ( rsapi_title )
171+ strict_check ( cached_value ) if cached_value
172+ @rsapi_current_state = cached_value
173+ end
174+
175+ def rsapi_current_state = ( value )
176+ rsapi_provider_get_cache . add ( rsapi_title , value )
177+ @rsapi_current_state = value
159178 end
160179
161180 def to_resource
@@ -242,57 +261,77 @@ def to_resource_shim(resource)
242261 type_definition . create_attribute_in ( self , name , param_or_property , parent , options )
243262 end
244263
264+ def self . rsapi_provider_get ( names = nil )
265+ # If the cache has been marked as having all instances, then just return the
266+ # full contents:
267+ return rsapi_provider_get_cache . all if rsapi_provider_get_cache . cached_all? && names . nil?
268+
269+ fetched = if type_definition . feature? ( 'simple_get_filter' )
270+ my_provider . get ( context , names )
271+ else
272+ my_provider . get ( context )
273+ end
274+
275+ fetched . each do |resource_hash |
276+ type_definition . check_schema ( resource_hash )
277+ rsapi_provider_get_cache . add ( build_title ( type_definition , resource_hash ) , resource_hash )
278+ end
279+
280+ if names . nil? && !type_definition . feature? ( 'simple_get_filter' )
281+ # Mark the cache as having all possible instances:
282+ rsapi_provider_get_cache . cached_all
283+ end
284+
285+ fetched
286+ end
287+
245288 def self . instances
246289 # puts 'instances'
247290 # force autoloading of the provider
248291 provider ( type_definition . name )
249292
250- initial_fetch = if type_definition . feature? ( 'simple_get_filter' )
251- my_provider . get ( context , nil )
252- else
253- my_provider . get ( context )
254- end
255-
256- initial_fetch . map do |resource_hash |
257- type_definition . check_schema ( resource_hash )
293+ rsapi_provider_get . map do |resource_hash |
258294 # allow a :title from the provider to override the default
259295 result = if resource_hash . key? :title
260296 new ( title : resource_hash [ :title ] )
261297 else
262298 new ( title : build_title ( type_definition , resource_hash ) )
263299 end
300+ # Cache the state in the generated resource, but unfortunately
301+ # this only benefits "puppet resource", not apply runs:
264302 result . cache_current_state ( resource_hash )
265303 result
266304 end
267305 end
268306
269307 def refresh_current_state
270- @rsapi_current_state = if type_definition . feature? ( 'simple_get_filter' )
271- my_provider . get ( context , [ rsapi_title ] ) . find { |h | namevar_match? ( h ) }
272- else
273- my_provider . get ( context ) . find { |h | namevar_match? ( h ) }
274- end
275-
276- if @rsapi_current_state
277- type_definition . check_schema ( @rsapi_current_state )
278- strict_check ( @rsapi_current_state )
308+ current_state = self . class . rsapi_provider_get ( [ rsapi_title ] ) . find { |h | namevar_match? ( h ) }
309+
310+ if current_state
311+ strict_check ( current_state )
279312 else
280- @rsapi_current_state = if rsapi_title . is_a? Hash
281- rsapi_title . dup
282- else
283- { title : rsapi_title }
284- end
285- @rsapi_current_state [ :ensure ] = :absent if type_definition . ensurable?
313+ current_state = if rsapi_title . is_a? Hash
314+ rsapi_title . dup
315+ else
316+ { title : rsapi_title }
317+ end
318+ current_state [ :ensure ] = :absent if type_definition . ensurable?
286319 end
320+ self . rsapi_current_state = current_state
287321 end
288322
289- # Use this to set the current state from the `instances` method
323+ # Use this to set the current state from the `instances` method. "puppet resources"
324+ # needs this to minimize provider get() calls, but during a Puppet apply run
325+ # the instances() method is only used by resource generation, and resource
326+ # generators use and then discard the resources created by `instances``, so this
327+ # does not help with that:
290328 def cache_current_state ( resource_hash )
291- @ rsapi_current_state = resource_hash
292- strict_check ( @rsapi_current_state )
329+ self . rsapi_current_state = resource_hash
330+ strict_check ( resource_hash )
293331 end
294332
295333 def retrieve
334+ refresh_current_state unless rsapi_current_state
296335 Puppet . debug ( "Current State: #{ rsapi_current_state . inspect } " )
297336
298337 result = Puppet ::Resource . new ( self . class , title , parameters : rsapi_current_state )
@@ -316,17 +355,17 @@ def flush
316355 # puts 'flush'
317356 target_state = rsapi_canonicalized_target_state
318357
319- retrieve unless @ rsapi_current_state
358+ retrieve unless rsapi_current_state
320359
321- return if @ rsapi_current_state == target_state
360+ return if rsapi_current_state == target_state
322361
323362 Puppet . debug ( "Target State: #{ target_state . inspect } " )
324363
325364 # enforce init_only attributes
326- if Puppet . settings [ :strict ] != :off && @ rsapi_current_state && ( @ rsapi_current_state[ :ensure ] == 'present' && target_state [ :ensure ] == 'present' )
365+ if Puppet . settings [ :strict ] != :off && rsapi_current_state && ( rsapi_current_state [ :ensure ] == 'present' && target_state [ :ensure ] == 'present' )
327366 target_state . each do |name , value |
328- next unless type_definition . attributes [ name ] [ :behaviour ] == :init_only && value != @ rsapi_current_state[ name ]
329- message = "Attempting to change `#{ name } ` init_only attribute value from `#{ @ rsapi_current_state[ name ] } ` to `#{ value } `"
367+ next unless type_definition . attributes [ name ] [ :behaviour ] == :init_only && value != rsapi_current_state [ name ]
368+ message = "Attempting to change `#{ name } ` init_only attribute value from `#{ rsapi_current_state [ name ] } ` to `#{ value } `"
330369 case Puppet . settings [ :strict ]
331370 when :warning
332371 Puppet . warning ( message )
@@ -337,17 +376,17 @@ def flush
337376 end
338377
339378 if type_definition . feature? ( 'supports_noop' )
340- my_provider . set ( context , { rsapi_title => { is : @ rsapi_current_state, should : target_state } } , noop : noop? )
379+ my_provider . set ( context , { rsapi_title => { is : rsapi_current_state , should : target_state } } , noop : noop? )
341380 else
342- my_provider . set ( context , rsapi_title => { is : @ rsapi_current_state, should : target_state } ) unless noop?
381+ my_provider . set ( context , rsapi_title => { is : rsapi_current_state , should : target_state } ) unless noop?
343382 end
344383 if context . failed?
345384 context . reset_failed
346385 raise 'Execution encountered an error'
347386 end
348387
349388 # remember that we have successfully reached our desired state
350- @ rsapi_current_state = target_state
389+ self . rsapi_current_state = target_state
351390 end
352391
353392 def raise_missing_attrs
0 commit comments