class Puppet::Indirector::Indirection

The class that connects functional classes with their different collection back-ends. Each indirection has a set of associated terminus classes, each of which is a subclass of Puppet::Indirector::Terminus.

Attributes

model[RW]
name[RW]
termini[R]

Public Class Methods

instance(name) click to toggle source

Find an indirection by name. This is provided so that Terminus classes can specifically hook up with the indirections they are associated with.

   # File lib/puppet/indirector/indirection.rb
21 def self.instance(name)
22   @@indirections.find { |i| i.name == name }
23 end
instances() click to toggle source

Return a list of all known indirections. Used to generate the reference.

   # File lib/puppet/indirector/indirection.rb
27 def self.instances
28   @@indirections.collect { |i| i.name }
29 end
model(name) click to toggle source

Find an indirected model by name. This is provided so that Terminus classes can specifically hook up with the indirections they are associated with.

   # File lib/puppet/indirector/indirection.rb
33 def self.model(name)
34   match = @@indirections.find { |i| i.name == name }
35   return nil unless match
36   match.model
37 end
new(model, name, doc: nil, indirected_class: nil, cache_class: nil, terminus_class: nil, terminus_setting: nil, extend: nil) click to toggle source
    # File lib/puppet/indirector/indirection.rb
 96 def initialize(model, name, doc: nil, indirected_class: nil, cache_class: nil, terminus_class: nil, terminus_setting: nil, extend: nil)
 97   @model = model
 98   @name = name
 99   @termini = {}
100 
101   @doc = doc
102 
103   raise(ArgumentError, _("Indirection %{name} is already defined") % { name: @name }) if @@indirections.find { |i| i.name == @name }
104   @@indirections << self
105 
106   @indirected_class = indirected_class
107   self.extend(extend) if extend
108 
109   # Setting these depend on the indirection already being installed so they have to be at the end
110   set_global_setting(:cache_class, cache_class)
111   set_global_setting(:terminus_class, terminus_class)
112   set_global_setting(:terminus_setting, terminus_setting)
113 end

Public Instance Methods

allow_remote_requests?() click to toggle source
    # File lib/puppet/indirector/indirection.rb
206 def allow_remote_requests?
207   terminus.allow_remote_requests?
208 end
cache() click to toggle source

Create and return our cache terminus.

   # File lib/puppet/indirector/indirection.rb
40 def cache
41   raise Puppet::DevError, _("Tried to cache when no cache class was set") unless cache_class
42   terminus(cache_class)
43 end
cache?() click to toggle source

Should we use a cache?

   # File lib/puppet/indirector/indirection.rb
46 def cache?
47   cache_class ? true : false
48 end
cache_class() click to toggle source
   # File lib/puppet/indirector/indirection.rb
50 def cache_class
51   @cache_class.value
52 end
cache_class=(class_name) click to toggle source

Define a terminus class to be used for caching.

   # File lib/puppet/indirector/indirection.rb
55 def cache_class=(class_name)
56   validate_terminus_class(class_name) if class_name
57   @cache_class.value = class_name
58 end
delete() click to toggle source

This is only used for testing.

   # File lib/puppet/indirector/indirection.rb
61 def delete
62   @@indirections.delete(self) if @@indirections.include?(self)
63 end
destroy(key, options={}) click to toggle source

Remove something via the terminus.

    # File lib/puppet/indirector/indirection.rb
281 def destroy(key, options={})
282   request = request(:destroy, key, nil, options)
283   terminus = prepare(request)
284 
285   result = terminus.destroy(request)
286 
287   if cache? and cache.find(request(:find, key, nil, options))
288     # Reuse the existing request, since it's equivalent.
289     cache.destroy(request)
290   end
291 
292   result
293 end
doc() click to toggle source

Generate the full doc string.

   # File lib/puppet/indirector/indirection.rb
83 def doc
84   text = String.new
85 
86   text << scrub(@doc) << "\n\n" if @doc
87 
88   text << "* **Indirected Class**: `#{@indirected_class}`\n";
89   if terminus_setting
90     text << "* **Terminus Setting**: #{terminus_setting}\n"
91   end
92 
93   text
94 end
expiration() click to toggle source

Calculate the expiration date for a returned instance.

   # File lib/puppet/indirector/indirection.rb
78 def expiration
79   Time.now + ttl
80 end
expire(key, options={}) click to toggle source

Expire a cached object, if one is cached. Note that we don't actually remove it, we expire it and write it back out to disk. This way people can still use the expired object if they want.

    # File lib/puppet/indirector/indirection.rb
190 def expire(key, options={})
191   request = request(:expire, key, nil, options)
192 
193   return nil unless cache? && !request.ignore_cache_save?
194 
195   instance = cache.find(request(:find, key, nil, options))
196   return nil unless instance
197 
198   Puppet.info _("Expiring the %{cache} cache of %{instance}") % { cache: self.name, instance: instance.name }
199 
200   # Set an expiration date in the past
201   instance.expiration = Time.now - 60
202 
203   cache.save(request(:save, nil, instance, options))
204 end
find(key, options={}) click to toggle source

Search for an instance in the appropriate terminus, caching the results if caching is configured..

    # File lib/puppet/indirector/indirection.rb
212 def find(key, options={})
213   request = request(:find, key, nil, options)
214   terminus = prepare(request)
215 
216   result = find_in_cache(request)
217   if not result.nil?
218     result
219   elsif request.ignore_terminus?
220     nil
221   else
222     # Otherwise, return the result from the terminus, caching if
223     # appropriate.
224     result = terminus.find(request)
225     if not result.nil?
226       result.expiration ||= self.expiration if result.respond_to?(:expiration)
227       if cache? && !request.ignore_cache_save?
228         Puppet.info _("Caching %{indirection} for %{request}") % { indirection: self.name, request: request.key }
229         begin
230           cache.save request(:save, key, result, options)
231         rescue => detail
232           Puppet.log_exception(detail)
233           raise detail
234         end
235       end
236 
237       filtered = result
238       if terminus.respond_to?(:filter)
239         Puppet::Util::Profiler.profile(_("Filtered result for %{indirection} %{request}") % { indirection: self.name, request: request.key }, [:indirector, :filter, self.name, request.key]) do
240           begin
241             filtered = terminus.filter(result)
242           rescue Puppet::Error => detail
243             Puppet.log_exception(detail)
244             raise detail
245           end
246         end
247       end
248       filtered
249     end
250   end
251 end
find_in_cache(request) click to toggle source
    # File lib/puppet/indirector/indirection.rb
264 def find_in_cache(request)
265   # See if our instance is in the cache and up to date.
266   cached = cache.find(request) if cache? && ! request.ignore_cache?
267   return nil unless cached
268   if cached.expired?
269     Puppet.info _("Not using expired %{indirection} for %{request} from cache; expired at %{expiration}") % { indirection: self.name, request: request.key, expiration: cached.expiration }
270     return nil
271   end
272 
273   Puppet.debug { "Using cached #{self.name} for #{request.key}" }
274   cached
275 rescue => detail
276   Puppet.log_exception(detail, _("Cached %{indirection} for %{request} failed: %{detail}") % { indirection: self.name, request: request.key, detail: detail })
277   nil
278 end
head(key, options={}) click to toggle source

Search for an instance in the appropriate terminus, and return a boolean indicating whether the instance was found.

    # File lib/puppet/indirector/indirection.rb
255 def head(key, options={})
256   request = request(:head, key, nil, options)
257   terminus = prepare(request)
258 
259   # Look in the cache first, then in the terminus.  Force the result
260   # to be a boolean.
261   !!(find_in_cache(request) || terminus.head(request))
262 end
request(*args) click to toggle source

Set up our request object.

    # File lib/puppet/indirector/indirection.rb
132 def request(*args)
133   Puppet::Indirector::Request.new(self.name, *args)
134 end
reset_terminus_class() click to toggle source
    # File lib/puppet/indirector/indirection.rb
166 def reset_terminus_class
167   @terminus_class.value = nil
168 end
save(instance, key = nil, options={}) click to toggle source

Save the instance in the appropriate terminus. This method is normally an instance method on the indirected class.

    # File lib/puppet/indirector/indirection.rb
313 def save(instance, key = nil, options={})
314   request = request(:save, key, instance, options)
315   terminus = prepare(request)
316 
317   result = terminus.save(request) if !request.ignore_terminus?
318 
319   # If caching is enabled, save our document there
320   cache.save(request) if cache? && !request.ignore_cache_save?
321 
322   result
323 end
set_global_setting(setting, value) click to toggle source

Use this to set indirector settings globally across threads.

    # File lib/puppet/indirector/indirection.rb
116 def set_global_setting(setting, value)
117   case setting
118   when :cache_class
119     validate_terminus_class(value) if !value.nil?
120     @cache_class = Puppet::ThreadLocal.new(value)
121   when :terminus_class
122     validate_terminus_class(value) if !value.nil?
123     @terminus_class = Puppet::ThreadLocal.new(value)
124   when :terminus_setting
125     @terminus_setting = Puppet::ThreadLocal.new(value)
126   else
127     raise(ArgumentError, _("The setting %{setting} is not a valid indirection setting.") % {setting: setting})
128   end
129 end
terminus(terminus_name = nil) click to toggle source

Return the singleton terminus for this indirection.

    # File lib/puppet/indirector/indirection.rb
137 def terminus(terminus_name = nil)
138   # Get the name of the terminus.
139   raise Puppet::DevError, _("No terminus specified for %{name}; cannot redirect") % { name: self.name } unless terminus_name ||= terminus_class
140 
141   termini[terminus_name] ||= make_terminus(terminus_name)
142 end
terminus_class() click to toggle source

Determine the terminus class.

    # File lib/puppet/indirector/indirection.rb
154 def terminus_class
155   unless @terminus_class.value
156     setting = self.terminus_setting
157     if setting
158       self.terminus_class = Puppet.settings[setting]
159     else
160       raise Puppet::DevError, _("No terminus class nor terminus setting was provided for indirection %{name}") % { name: self.name}
161     end
162   end
163   @terminus_class.value
164 end
terminus_class=(klass) click to toggle source

Specify the terminus class to use.

    # File lib/puppet/indirector/indirection.rb
171 def terminus_class=(klass)
172   validate_terminus_class(klass)
173   @terminus_class.value = klass
174 end
terminus_setting() click to toggle source

These can be used to select the terminus class.

    # File lib/puppet/indirector/indirection.rb
145 def terminus_setting
146   @terminus_setting.value
147 end
terminus_setting=(setting) click to toggle source
    # File lib/puppet/indirector/indirection.rb
149 def terminus_setting=(setting)
150   @terminus_setting.value = setting
151 end
ttl() click to toggle source

Default to the runinterval for the ttl.

   # File lib/puppet/indirector/indirection.rb
73 def ttl
74   @ttl ||= Puppet[:runinterval]
75 end
ttl=(value) click to toggle source

Set the time-to-live for instances created through this indirection.

   # File lib/puppet/indirector/indirection.rb
66 def ttl=(value)
67   #TRANSLATORS "TTL" stands for "time to live" and refers to a duration of time
68   raise ArgumentError, _("Indirection TTL must be an integer") unless value.is_a?(Integer)
69   @ttl = value
70 end
validate_terminus_class(terminus_class) click to toggle source

This is used by terminus_class= and cache=.

    # File lib/puppet/indirector/indirection.rb
177 def validate_terminus_class(terminus_class)
178   unless terminus_class and terminus_class.to_s != ""
179     raise ArgumentError, _("Invalid terminus name %{terminus_class}") % { terminus_class: terminus_class.inspect }
180   end
181   unless Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
182     raise ArgumentError, _("Could not find terminus %{terminus_class} for indirection %{name}") %
183         { terminus_class: terminus_class, name: self.name }
184   end
185 end

Private Instance Methods

check_authorization(request, terminus) click to toggle source

Check authorization if there's a hook available; fail if there is one and it returns false.

    # File lib/puppet/indirector/indirection.rb
329 def check_authorization(request, terminus)
330   # At this point, we're assuming authorization makes no sense without
331   # client information.
332   return unless request.node
333 
334   # This is only to authorize via a terminus-specific authorization hook.
335   return unless terminus.respond_to?(:authorized?)
336 
337   unless terminus.authorized?(request)
338     msg = if request.options.empty?
339             _("Not authorized to call %{method} on %{description}") %
340                 { method: request.method, description: request.description }
341           else
342             _("Not authorized to call %{method} on %{description} with %{option}") %
343                 { method: request.method, description: request.description, option: request.options.inspect }
344           end
345     raise ArgumentError, msg
346   end
347 end
make_terminus(terminus_class) click to toggle source

Create a new terminus instance.

    # File lib/puppet/indirector/indirection.rb
365 def make_terminus(terminus_class)
366   # Load our terminus class.
367   klass = Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
368   unless klass
369     raise ArgumentError, _("Could not find terminus %{terminus_class} for indirection %{indirection}") % { terminus_class: terminus_class, indirection: self.name }
370   end
371   klass.new
372 end
prepare(request) click to toggle source

Pick the appropriate terminus, check the request's authorization, and return it. @param [Puppet::Indirector::Request] request instance @return [Puppet::Indirector::Terminus] terminus instance (usually a subclass

of Puppet::Indirector::Terminus) for this request
    # File lib/puppet/indirector/indirection.rb
353 def prepare(request)
354   # Pick our terminus.
355   terminus_name = terminus_class
356 
357   dest_terminus = terminus(terminus_name)
358   check_authorization(request, dest_terminus)
359   dest_terminus.validate(request)
360 
361   dest_terminus
362 end