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
20 def self.instance(name)
21   @@indirections.find { |i| i.name == name }
22 end
instances() click to toggle source

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

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

Public Instance Methods

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

Create and return our cache terminus.

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

Should we use a cache?

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

Define a terminus class to be used for caching.

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

This is only used for testing.

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

Remove something via the terminus.

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

Generate the full doc string.

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

Calculate the expiration date for a returned instance.

   # File lib/puppet/indirector/indirection.rb
77 def expiration
78   Time.now + ttl
79 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
189 def expire(key, options={})
190   request = request(:expire, key, nil, options)
191 
192   return nil unless cache? && !request.ignore_cache_save?
193 
194   instance = cache.find(request(:find, key, nil, options))
195   return nil unless instance
196 
197   Puppet.info _("Expiring the %{cache} cache of %{instance}") % { cache: self.name, instance: instance.name }
198 
199   # Set an expiration date in the past
200   instance.expiration = Time.now - 60
201 
202   cache.save(request(:save, nil, instance, options))
203 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
211 def find(key, options={})
212   request = request(:find, key, nil, options)
213   terminus = prepare(request)
214 
215   result = find_in_cache(request)
216   if not result.nil?
217     result
218   elsif request.ignore_terminus?
219     nil
220   else
221     # Otherwise, return the result from the terminus, caching if
222     # appropriate.
223     result = terminus.find(request)
224     if not result.nil?
225       result.expiration ||= self.expiration if result.respond_to?(:expiration)
226       if cache? && !request.ignore_cache_save?
227         Puppet.info _("Caching %{indirection} for %{request}") % { indirection: self.name, request: request.key }
228         begin
229           cache.save request(:save, key, result, options)
230         rescue => detail
231           Puppet.log_exception(detail)
232           raise detail
233         end
234       end
235 
236       filtered = result
237       if terminus.respond_to?(:filter)
238         Puppet::Util::Profiler.profile(_("Filtered result for %{indirection} %{request}") % { indirection: self.name, request: request.key }, [:indirector, :filter, self.name, request.key]) do
239           begin
240             filtered = terminus.filter(result)
241           rescue Puppet::Error => detail
242             Puppet.log_exception(detail)
243             raise detail
244           end
245         end
246       end
247       filtered
248     end
249   end
250 end
find_in_cache(request) click to toggle source
    # File lib/puppet/indirector/indirection.rb
263 def find_in_cache(request)
264   # See if our instance is in the cache and up to date.
265   cached = cache.find(request) if cache? && ! request.ignore_cache?
266   return nil unless cached
267   if cached.expired?
268     Puppet.info _("Not using expired %{indirection} for %{request} from cache; expired at %{expiration}") % { indirection: self.name, request: request.key, expiration: cached.expiration }
269     return nil
270   end
271 
272   Puppet.debug { "Using cached #{self.name} for #{request.key}" }
273   cached
274 rescue => detail
275   Puppet.log_exception(detail, _("Cached %{indirection} for %{request} failed: %{detail}") % { indirection: self.name, request: request.key, detail: detail })
276   nil
277 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
254 def head(key, options={})
255   request = request(:head, key, nil, options)
256   terminus = prepare(request)
257 
258   # Look in the cache first, then in the terminus.  Force the result
259   # to be a boolean.
260   !!(find_in_cache(request) || terminus.head(request))
261 end
request(*args) click to toggle source

Set up our request object.

    # File lib/puppet/indirector/indirection.rb
131 def request(*args)
132   Puppet::Indirector::Request.new(self.name, *args)
133 end
reset_terminus_class() click to toggle source
    # File lib/puppet/indirector/indirection.rb
165 def reset_terminus_class
166   @terminus_class.value = nil
167 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
312 def save(instance, key = nil, options={})
313   request = request(:save, key, instance, options)
314   terminus = prepare(request)
315 
316   result = terminus.save(request)
317 
318   # If caching is enabled, save our document there
319   cache.save(request) if cache? && !request.ignore_cache_save?
320 
321   result
322 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
115 def set_global_setting(setting, value)
116   case setting
117   when :cache_class
118     validate_terminus_class(value) if !value.nil?
119     @cache_class = Puppet::ThreadLocal.new(value)
120   when :terminus_class
121     validate_terminus_class(value) if !value.nil?
122     @terminus_class = Puppet::ThreadLocal.new(value)
123   when :terminus_setting
124     @terminus_setting = Puppet::ThreadLocal.new(value)
125   else
126     raise(ArgumentError, _("The setting %{setting} is not a valid indirection setting.") % {setting: setting})
127   end
128 end
terminus(terminus_name = nil) click to toggle source

Return the singleton terminus for this indirection.

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

Determine the terminus class.

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

Specify the terminus class to use.

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

These can be used to select the terminus class.

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

Default to the runinterval for the ttl.

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

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

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

This is used by terminus_class= and cache=.

    # File lib/puppet/indirector/indirection.rb
176 def validate_terminus_class(terminus_class)
177   unless terminus_class and terminus_class.to_s != ""
178     raise ArgumentError, _("Invalid terminus name %{terminus_class}") % { terminus_class: terminus_class.inspect }
179   end
180   unless Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
181     raise ArgumentError, _("Could not find terminus %{terminus_class} for indirection %{name}") %
182         { terminus_class: terminus_class, name: self.name }
183   end
184 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
328 def check_authorization(request, terminus)
329   # At this point, we're assuming authorization makes no sense without
330   # client information.
331   return unless request.node
332 
333   # This is only to authorize via a terminus-specific authorization hook.
334   return unless terminus.respond_to?(:authorized?)
335 
336   unless terminus.authorized?(request)
337     msg = if request.options.empty?
338             _("Not authorized to call %{method} on %{description}") %
339                 { method: request.method, description: request.description }
340           else
341             _("Not authorized to call %{method} on %{description} with %{option}") %
342                 { method: request.method, description: request.description, option: request.options.inspect }
343           end
344     raise ArgumentError, msg
345   end
346 end
make_terminus(terminus_class) click to toggle source

Create a new terminus instance.

    # File lib/puppet/indirector/indirection.rb
364 def make_terminus(terminus_class)
365   # Load our terminus class.
366   klass = Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
367   unless klass
368     raise ArgumentError, _("Could not find terminus %{terminus_class} for indirection %{indirection}") % { terminus_class: terminus_class, indirection: self.name }
369   end
370   klass.new
371 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
352 def prepare(request)
353   # Pick our terminus.
354   terminus_name = terminus_class
355 
356   dest_terminus = terminus(terminus_name)
357   check_authorization(request, dest_terminus)
358   dest_terminus.validate(request)
359 
360   dest_terminus
361 end