1
1
require 'puppet/util/docs'
2
2
require 'puppet/indirector/envelope'
3
3
require 'puppet/indirector/request'
4
require 'puppet/util/cacher'
5
6
# The class that connects functional classes with their different collection
6
7
# back-ends. Each indirection has a set of associated terminus classes,
7
8
# each of which is a subclass of Puppet::Indirector::Terminus.
8
9
class Puppet::Indirector::Indirection
10
include Puppet::Util::Cacher
9
11
include Puppet::Util::Docs
11
13
@@indirections = []
13
# Clear all cached termini from all indirections.
15
@@indirections.each { |ind| ind.clear_cache }
18
15
# Find an indirection by name. This is provided so that Terminus classes
19
16
# can specifically hook up with the indirections they are associated with.
20
17
def self.instance(name)
27
24
@@indirections.collect { |i| i.name }
30
27
# Find an indirected model by name. This is provided so that Terminus classes
31
28
# can specifically hook up with the indirections they are associated with.
32
29
def self.model(name)
33
30
return nil unless match = @@indirections.find { |i| i.name == name }
37
34
attr_accessor :name, :model
39
36
# Create and return our cache terminus.
50
47
attr_reader :cache_class
51
48
# Define a terminus class to be used for caching.
52
49
def cache_class=(class_name)
53
validate_terminus_class(class_name)
50
validate_terminus_class(class_name) if class_name
54
51
@cache_class = class_name
57
# Clear our cached list of termini, and reset the cache name
58
# so it's looked up again.
59
# This is only used for testing.
64
54
# This is only used for testing.
66
56
@@indirections.delete(self) if @@indirections.include?(self)
137
126
unless terminus_name ||= terminus_class
138
127
raise Puppet::DevError, "No terminus specified for %s; cannot redirect" % self.name
141
return @termini[terminus_name] ||= make_terminus(terminus_name)
130
return termini[terminus_name] ||= make_terminus(terminus_name)
144
133
# This can be used to select the terminus class.
196
185
request = request(:find, key, *args)
197
186
terminus = prepare(request)
199
# See if our instance is in the cache and up to date.
200
if cache? and cached = cache.find(request)
202
Puppet.info "Not using expired %s for %s from cache; expired at %s" % [self.name, request.key, cached.expiration]
204
Puppet.debug "Using cached %s for %s" % [self.name, request.key]
189
if result = find_in_cache(request)
193
puts detail.backtrace if Puppet[:trace]
194
Puppet.err "Cached %s for %s failed: %s" % [self.name, request.key, detail]
209
197
# Otherwise, return the result from the terminus, caching if appropriate.
210
if result = terminus.find(request)
198
if ! request.ignore_terminus? and result = terminus.find(request)
211
199
result.expiration ||= self.expiration
200
if cache? and request.use_cache?
213
201
Puppet.info "Caching %s for %s" % [self.name, request.key]
214
202
cache.save request(:save, result, *args)
205
return terminus.respond_to?(:filter) ? terminus.filter(result) : result
211
def find_in_cache(request)
212
# See if our instance is in the cache and up to date.
213
return nil unless cache? and ! request.ignore_cache? and cached = cache.find(request)
215
Puppet.info "Not using expired %s for %s from cache; expired at %s" % [self.name, request.key, cached.expiration]
219
Puppet.debug "Using cached %s for %s" % [self.name, request.key]
223
223
# Remove something via the terminus.
224
224
def destroy(key, *args)
225
225
request = request(:destroy, key, *args)
255
255
request = request(:save, instance, *args)
256
256
terminus = prepare(request)
258
result = terminus.save(request)
258
260
# If caching is enabled, save our document there
259
261
cache.save(request) if cache?
260
terminus.save(request)
273
276
return unless terminus.respond_to?(:authorized?)
275
278
unless terminus.authorized?(request)
276
raise ArgumentError, "Not authorized to call %s on %s with %s" % [request.method, request.key, request.options.inspect]
279
msg = "Not authorized to call %s on %s" % [request.method, request.to_s]
280
unless request.options.empty?
281
msg += " with %s" % request.options.inspect
283
raise ArgumentError, msg
281
288
def prepare(request)
282
289
# Pick our terminus.
283
290
if respond_to?(:select_terminus)
284
terminus_name = select_terminus(request)
291
unless terminus_name = select_terminus(request)
292
raise ArgumentError, "Could not determine appropriate terminus for %s" % request
286
295
terminus_name = terminus_class
289
check_authorization(request, terminus(terminus_name))
298
dest_terminus = terminus(terminus_name)
299
check_authorization(request, dest_terminus)
291
return terminus(terminus_name)
294
304
# Create a new terminus instance.