# 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

cache_class[R]
model[RW]
name[RW]
termini[R]
terminus_setting[RW]

This can be used to select the terminus class.

### 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, line 27
    def self.instance(name)
      @@indirections.find { |i| i.name == name }
    end

instances() click to toggle source

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

    # File lib/puppet/indirector/indirection.rb, line 33
    def self.instances
      @@indirections.collect { |i| i.name }
    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, line 39
    def self.model(name)
      return nil unless match = @@indirections.find { |i| i.name == name }
      match.model
    end

new(model, name, options = {}) click to toggle source

    # File lib/puppet/indirector/indirection.rb, line 96
    def initialize(model, name, options = {})
      @model = model
      @name = name
      @termini = {}

      @cache_class = nil
      @terminus_class = nil

      raise(ArgumentError, "Indirection #{@name} is already defined") if @@indirections.find { |i| i.name == @name }
      @@indirections << self

      if mod = options[:extend]
        extend(mod)
        options.delete(:extend)
      end

      # This is currently only used for cache_class and terminus_class.
      set_options(options)
    end

### Public Instance Methods

cache() click to toggle source

Create and return our cache terminus.

    # File lib/puppet/indirector/indirection.rb, line 45
    def cache
      raise(Puppet::DevError, "Tried to cache when no cache class was set") unless cache_class
      terminus(cache_class)
    end

cache?() click to toggle source

Should we use a cache?

    # File lib/puppet/indirector/indirection.rb, line 51
    def cache?
      cache_class ? true : false
    end

cache_class=(class_name) click to toggle source

Define a terminus class to be used for caching.

    # File lib/puppet/indirector/indirection.rb, line 57
    def cache_class=(class_name)
      validate_terminus_class(class_name) if class_name
      @cache_class = class_name
    end

delete() click to toggle source

This is only used for testing.

    # File lib/puppet/indirector/indirection.rb, line 63
    def delete
      @@indirections.delete(self) if @@indirections.include?(self)
    end

destroy(key, options={}) click to toggle source

Remove something via the terminus.

    # File lib/puppet/indirector/indirection.rb, line 231
    def destroy(key, options={})
      request = request(:destroy, key, nil, options)
      terminus = prepare(request)

      result = terminus.destroy(request)

      if cache? and cached = cache.find(request(:find, key, nil, options))
        # Reuse the existing request, since it's equivalent.
        cache.destroy(request)
      end

      result
    end

doc() click to toggle source

Generate the full doc string.

    # File lib/puppet/indirector/indirection.rb, line 84
    def doc
      text = ""

      text += scrub(@doc) + "\n\n" if @doc

      if s = terminus_setting
        text += "* **Terminus Setting**: #{terminus_setting}"
      end

      text
    end

expiration() click to toggle source

Calculate the expiration date for a returned instance.

    # File lib/puppet/indirector/indirection.rb, line 79
    def expiration
      Time.now + ttl
    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, line 165
    def expire(key, options={})
      request = request(:expire, key, nil, options)

      return nil unless cache?

      return nil unless instance = cache.find(request(:find, key, nil, options))

      Puppet.info "Expiring the #{self.name} cache of #{instance.name}"

      # Set an expiration date in the past
      instance.expiration = Time.now - 60

      cache.save(request(:save, nil, instance, options))
    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, line 182
    def find(key, options={})
      request = request(:find, key, nil, options)
      terminus = prepare(request)

      if result = find_in_cache(request)
        return result
      end

      # Otherwise, return the result from the terminus, caching if appropriate.
      if ! request.ignore_terminus? and result = terminus.find(request)
        result.expiration ||= self.expiration if result.respond_to?(:expiration)
        if cache? and request.use_cache?
          Puppet.info "Caching #{self.name} for #{request.key}"
          cache.save request(:save, key, result, options)
        end

        return terminus.respond_to?(:filter) ? terminus.filter(result) : result
      end

      nil
    end

find_in_cache(request) click to toggle source

    # File lib/puppet/indirector/indirection.rb, line 215
    def find_in_cache(request)
      # See if our instance is in the cache and up to date.
      return nil unless cache? and ! request.ignore_cache? and cached = cache.find(request)
      if cached.expired?
        Puppet.info "Not using expired #{self.name} for #{request.key} from cache; expired at #{cached.expiration}"
        return nil
      end

      Puppet.debug "Using cached #{self.name} for #{request.key}"
      cached
    rescue => detail
      Puppet.log_exception(detail, "Cached #{self.name} for #{request.key} failed: #{detail}")
      nil
    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, line 206
    def head(key, options={})
      request = request(:head, key, nil, options)
      terminus = prepare(request)

      # Look in the cache first, then in the terminus.  Force the result
      # to be a boolean.
      !!(find_in_cache(request) || terminus.head(request))
    end

request(*args) click to toggle source

Set up our request object.

    # File lib/puppet/indirector/indirection.rb, line 117
    def request(*args)
      Puppet::Indirector::Request.new(self.name, *args)
    end

reset_terminus_class() click to toggle source

    # File lib/puppet/indirector/indirection.rb, line 144
    def reset_terminus_class
      @terminus_class = nil
    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, line 262
    def save(instance, key = nil, options={})
      request = request(:save, key, instance, options)
      terminus = prepare(request)

      result = terminus.save(request)

      # If caching is enabled, save our document there
      cache.save(request) if cache?

      result
    end

search(key, options={}) click to toggle source

Search for more than one instance. Should always return an array.

    # File lib/puppet/indirector/indirection.rb, line 246
    def search(key, options={})
      request = request(:search, key, nil, options)
      terminus = prepare(request)

      if result = terminus.search(request)
        raise Puppet::DevError, "Search results from terminus #{terminus.name} are not an array" unless result.is_a?(Array)
        result.each do |instance|
          next unless instance.respond_to? :expiration
          instance.expiration ||= self.expiration
        end
        return result
      end
    end

terminus(terminus_name = nil) click to toggle source

Return the singleton terminus for this indirection.

    # File lib/puppet/indirector/indirection.rb, line 122
    def terminus(terminus_name = nil)
      # Get the name of the terminus.
      raise Puppet::DevError, "No terminus specified for #{self.name}; cannot redirect" unless terminus_name ||= terminus_class

      termini[terminus_name] ||= make_terminus(terminus_name)
    end

terminus_class() click to toggle source

Determine the terminus class.

    # File lib/puppet/indirector/indirection.rb, line 133
    def terminus_class
      unless @terminus_class
        if setting = self.terminus_setting
          self.terminus_class = Puppet.settings[setting]
        else
          raise Puppet::DevError, "No terminus class nor terminus setting was provided for indirection #{self.name}"
        end
      end
      @terminus_class
    end

terminus_class=(klass) click to toggle source

Specify the terminus class to use.

    # File lib/puppet/indirector/indirection.rb, line 149
    def terminus_class=(klass)
      validate_terminus_class(klass)
      @terminus_class = klass
    end

ttl() click to toggle source

Default to the runinterval for the ttl.

    # File lib/puppet/indirector/indirection.rb, line 74
    def ttl
      @ttl ||= Puppet[:runinterval]
    end

ttl=(value) click to toggle source

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

    # File lib/puppet/indirector/indirection.rb, line 68
    def ttl=(value)
      raise ArgumentError, "Indirection TTL must be an integer" unless value.is_a?(Fixnum)
      @ttl = value
    end

validate_terminus_class(terminus_class) click to toggle source

This is used by #terminus_class= and cache=.

    # File lib/puppet/indirector/indirection.rb, line 155
    def validate_terminus_class(terminus_class)
      raise ArgumentError, "Invalid terminus name #{terminus_class.inspect}" unless terminus_class and terminus_class.to_s != ""
      unless Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
        raise ArgumentError, "Could not find terminus #{terminus_class} for indirection #{self.name}"
      end
    end