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
Public Class Methods
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
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
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
# 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
# File lib/puppet/indirector/indirection.rb 206 def allow_remote_requests? 207 terminus.allow_remote_requests? 208 end
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
Should we use a cache?
# File lib/puppet/indirector/indirection.rb 46 def cache? 47 cache_class ? true : false 48 end
# File lib/puppet/indirector/indirection.rb 50 def cache_class 51 @cache_class.value 52 end
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
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
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
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
Calculate the expiration date for a returned instance.
# File lib/puppet/indirector/indirection.rb 78 def expiration 79 Time.now + ttl 80 end
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
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
# 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
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
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
# File lib/puppet/indirector/indirection.rb 166 def reset_terminus_class 167 @terminus_class.value = nil 168 end
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
Search for more than one instance. Should always return an array.
# File lib/puppet/indirector/indirection.rb 296 def search(key, options={}) 297 request = request(:search, key, nil, options) 298 terminus = prepare(request) 299 300 result = terminus.search(request) 301 if result 302 raise Puppet::DevError, _("Search results from terminus %{terminus_name} are not an array") % { terminus_name: terminus.name } unless result.is_a?(Array) 303 result.each do |instance| 304 next unless instance.respond_to? :expiration 305 instance.expiration ||= self.expiration 306 end 307 return result 308 end 309 end
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
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
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
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
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
# File lib/puppet/indirector/indirection.rb 149 def terminus_setting=(setting) 150 @terminus_setting.value = setting 151 end
Default to the runinterval for the ttl.
# File lib/puppet/indirector/indirection.rb 73 def ttl 74 @ttl ||= Puppet[:runinterval] 75 end
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
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
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
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