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