class Puppet::Resource::Catalog

This class models a node catalog. It is the thing meant to be passed from server to client, and it contains all of the information in the catalog, including the resources and the relationships between them.

@api public

Attributes

client_version[RW]

Some metadata to help us compile and generally respond to the current state.

environment[RW]

A String representing the environment for this catalog

environment_instance[RW]

The actual environment instance that was used during compilation

from_cache[RW]

Whether this catalog was retrieved from the cache, which affects whether it is written back out again.

host_config[RW]

Whether this is a host catalog, which behaves very differently. In particular, reports are sent, graphs are made, and state is stored in the state database. If this is set incorrectly, then you often end up in infinite loops, because catalogs are used to make things that the host catalog needs.

name[RW]

The host name this is a catalog for.

retrieval_duration[RW]

How long this catalog took to retrieve. Used for reporting stats.

server_version[RW]

Some metadata to help us compile and generally respond to the current state.

version[RW]

The catalog version. Used for testing whether a catalog is up to date.

Public Instance Methods

add_class(*classes) click to toggle source

Add classes to our class list.

# File lib/puppet/resource/catalog.rb, line 56
def add_class(*classes)
  classes.each do |klass|
    @classes << klass
  end

  # Add the class names as tags, too.
  tag(*classes)
end
add_resource(*resources) click to toggle source
# File lib/puppet/resource/catalog.rb, line 70
def add_resource(*resources)
  resources.each do |resource|
    add_one_resource(resource)
  end
end
alias(resource, key) click to toggle source

Create an alias for a resource.

# File lib/puppet/resource/catalog.rb, line 117
def alias(resource, key)
  resource.ref =~ /^(.+)\[/
  class_name = $1 || resource.class.name

  newref = [class_name, key].flatten

  if key.is_a? String
    ref_string = "#{class_name}[#{key}]"
    return if ref_string == resource.ref
  end

  # LAK:NOTE It's important that we directly compare the references,
  # because sometimes an alias is created before the resource is
  # added to the catalog, so comparing inside the below if block
  # isn't sufficient.
  if existing = @resource_table[newref]
    return if existing == resource
    resource_declaration = " at #{resource.file}:#{resource.line}" if resource.file and resource.line
    existing_declaration = " at #{existing.file}:#{existing.line}" if existing.file and existing.line
    msg = "Cannot alias #{resource.ref} to #{key.inspect}#{resource_declaration}; resource #{newref.inspect} already declared#{existing_declaration}"
    raise ArgumentError, msg
  end
  @resource_table[newref] = resource
  @aliases[resource.ref] ||= []
  @aliases[resource.ref] << newref
end
apply(options = {}) { |transaction| ... } click to toggle source

Apply our catalog to the local host. @param options [Hash{Symbol => Object}] a hash of options @option options [Puppet::Transaction::Report] :report

The report object to log this transaction to. This is optional,
and the resulting transaction will create a report if not
supplied.

@option options [Array] :tags

Tags used to filter the transaction. If supplied then only
resources tagged with any of these tags will be evaluated.

@option options [Boolean] :ignoreschedules

Ignore schedules when evaluating resources

@option options [Boolean] :for_network_device

Whether this catalog is for a network device

@return [Puppet::Transaction] the transaction created for this

application

@api public

# File lib/puppet/resource/catalog.rb, line 162
def apply(options = {})
  Puppet::Util::Storage.load if host_config?

  transaction = create_transaction(options)

  begin
    transaction.report.as_logging_destination do
      transaction.evaluate
    end
  ensure
    # Don't try to store state unless we're a host config
    # too recursive.
    Puppet::Util::Storage.store if host_config?
  end

  yield transaction if block_given?

  transaction
end
classes() click to toggle source
# File lib/puppet/resource/catalog.rb, line 211
def classes
  @classes.dup
end
clear(remove_resources = true) click to toggle source
# File lib/puppet/resource/catalog.rb, line 198
def clear(remove_resources = true)
  super()
  # We have to do this so that the resources clean themselves up.
  @resource_table.values.each { |resource| resource.remove } if remove_resources
  @resource_table.clear
  @resources = []

  if @relationship_graph
    @relationship_graph.clear
    @relationship_graph = nil
  end
end
container_of(resource) click to toggle source

@param resource [A Resource] a resource in the catalog @return [A Resource, nil] the resource that contains the given resource @api public

# File lib/puppet/resource/catalog.rb, line 79
def container_of(resource)
  adjacent(resource, :direction => :in)[0]
end
create_resource(type, options) click to toggle source

Create a new resource and register it in the catalog.

# File lib/puppet/resource/catalog.rb, line 216
def create_resource(type, options)
  unless klass = Puppet::Type.type(type)
    raise ArgumentError, "Unknown resource type #{type}"
  end
  return unless resource = klass.new(options)

  add_resource(resource)
  resource
end
filter(&block) click to toggle source

filter out the catalog, applying block to each resource. If the block result is false, the resource will be kept otherwise it will be skipped

# File lib/puppet/resource/catalog.rb, line 415
def filter(&block)
  # to_catalog must take place in a context where current_environment is set to the same env as the
  # environment set in the catalog (if it is set)
  # See PUP-3755
  if environment_instance
    Puppet.override({:current_environment => environment_instance}) do
      to_catalog :to_resource, &block
    end
  else
    # If catalog has no environment_instance, hope that the caller has made sure the context has the
    # correct current_environment
    to_catalog :to_resource, &block
  end
end
finalize() click to toggle source

Make sure all of our resources are “finished”.

# File lib/puppet/resource/catalog.rb, line 227
def finalize
  make_default_resources

  @resource_table.values.each { |resource| resource.finish }

  write_graph(:resources)
end
host_config?() click to toggle source
# File lib/puppet/resource/catalog.rb, line 235
def host_config?
  host_config
end
make_default_resources() click to toggle source

Make the default objects necessary for function.

# File lib/puppet/resource/catalog.rb, line 260
def make_default_resources
  # We have to add the resources to the catalog, or else they won't get cleaned up after
  # the transaction.

  # First create the default scheduling objects
  Puppet::Type.type(:schedule).mkdefaultschedules.each { |res| add_resource(res) unless resource(res.ref) }

  # And filebuckets
  if bucket = Puppet::Type.type(:filebucket).mkdefaultbucket
    add_resource(bucket) unless resource(bucket.ref)
  end
end
relationship_graph(given_prioritizer = nil) click to toggle source

The #relationship_graph form of the catalog. This contains all of the dependency edges that are used for determining order.

@param given_prioritizer [Puppet::Graph::Prioritizer] The prioritization

strategy to use when constructing the relationship graph. Defaults the
being determined by the `ordering` setting.

@return [Puppet::Graph::RelationshipGraph] @api public

# File lib/puppet/resource/catalog.rb, line 190
def relationship_graph(given_prioritizer = nil)
  if @relationship_graph.nil?
    @relationship_graph = Puppet::Graph::RelationshipGraph.new(given_prioritizer || prioritizer)
    @relationship_graph.populate_from(self)
  end
  @relationship_graph
end
remove_resource(*resources) click to toggle source

Remove the resource from our catalog. Notice that we also call ‘remove’ on the resource, at least until resource classes no longer maintain references to the resource instances.

# File lib/puppet/resource/catalog.rb, line 276
def remove_resource(*resources)
  resources.each do |resource|
    title_key = title_key_for_ref(resource.ref)
    @resource_table.delete(title_key)
    if aliases = @aliases[resource.ref]
      aliases.each { |res_alias| @resource_table.delete(res_alias) }
      @aliases.delete(resource.ref)
    end
    remove_vertex!(resource) if vertex?(resource)
    @relationship_graph.remove_vertex!(resource) if @relationship_graph and @relationship_graph.vertex?(resource)
    @resources.delete(title_key)
    resource.remove
  end
end
resource(type, title = nil) click to toggle source

Look a resource up by its reference (e.g., File).

# File lib/puppet/resource/catalog.rb, line 292
def resource(type, title = nil)
  # Always create a resource reference, so that it always
  # canonicalizes how we are referring to them.
  attributes = { :environment => environment_instance }
  if title
    res = Puppet::Resource.new(type, title, attributes)
  else
    # If they didn't provide a title, then we expect the first
    # argument to be of the form 'Class[name]', which our
    # Reference class canonicalizes for us.
    res = Puppet::Resource.new(nil, type, attributes)
  end
  res.catalog = self
  title_key      = [res.type, res.title.to_s]
  uniqueness_key = [res.type, res.uniqueness_key].flatten
  @resource_table[title_key] || @resource_table[uniqueness_key]
end
resource_keys() click to toggle source
# File lib/puppet/resource/catalog.rb, line 314
def resource_keys
  @resource_table.keys
end
resource_refs() click to toggle source
# File lib/puppet/resource/catalog.rb, line 310
def resource_refs
  resource_keys.collect{ |type, name| name.is_a?( String ) ? "#{type}[#{name}]" : nil}.compact
end
resources() click to toggle source
# File lib/puppet/resource/catalog.rb, line 318
def resources
  @resources.collect do |key|
    @resource_table[key]
  end
end
title_key_for_ref( ref ) click to toggle source
# File lib/puppet/resource/catalog.rb, line 65
def title_key_for_ref( ref )
  ref =~ /^([-\w:]+)\[(.*)\]$/
  [$1, $2]
end
to_data_hash() click to toggle source
# File lib/puppet/resource/catalog.rb, line 375
def to_data_hash
  {
    'tags'      => tags,
    'name'      => name,
    'version'   => version,
    'environment' => environment.to_s,
    'resources' => @resources.collect { |v| @resource_table[v].to_pson_data_hash },
    'edges'     => edges.   collect { |e| e.to_pson_data_hash },
    'classes'   => classes
  }
end
to_pson(*args) click to toggle source
# File lib/puppet/resource/catalog.rb, line 398
def to_pson(*args)
  to_pson_data_hash.to_pson(*args)
end
to_pson_data_hash() click to toggle source
# File lib/puppet/resource/catalog.rb, line 388
def to_pson_data_hash
  {
    'document_type' => 'Catalog',
    'data'       => to_data_hash,
    'metadata' => {
      'api_version' => 1
      }
  }
end
to_ral() click to toggle source

Convert our catalog into a RAL catalog.

# File lib/puppet/resource/catalog.rb, line 403
def to_ral
  to_catalog :to_ral
end
to_resource() click to toggle source

Convert our catalog into a catalog of Puppet::Resource instances.

# File lib/puppet/resource/catalog.rb, line 408
def to_resource
  to_catalog :to_resource
end
write_class_file() click to toggle source

Store the classes in the classfile.

# File lib/puppet/resource/catalog.rb, line 431
def write_class_file
  ::File.open(Puppet[:classfile], "w") do |f|
    f.puts classes.join("\n")
  end
rescue => detail
  Puppet.err "Could not create class file #{Puppet[:classfile]}: #{detail}"
end
write_graph(name) click to toggle source

Produce the graph files if requested.

# File lib/puppet/resource/catalog.rb, line 457
def write_graph(name)
  # We only want to graph the main host catalog.
  return unless host_config?

  super
end
write_resource_file() click to toggle source

Store the list of resources we manage

# File lib/puppet/resource/catalog.rb, line 440
def write_resource_file
  ::File.open(Puppet[:resourcefile], "w") do |f|
    to_print = resources.map do |resource|
      next unless resource.managed?
      if resource.name_var
        "#{resource.type}[#{resource[resource.name_var]}]"
      else
        "#{resource.ref.downcase}"
      end
    end.compact
    f.puts to_print.join("\n")
  end
rescue => detail
  Puppet.err "Could not create resource file #{Puppet[:resourcefile]}: #{detail}"
end

Public Class Methods

from_data_hash(data) click to toggle source
# File lib/puppet/resource/catalog.rb, line 324
def self.from_data_hash(data)
  result = new(data['name'], Puppet::Node::Environment::NONE)

  if tags = data['tags']
    result.tag(*tags)
  end

  if version = data['version']
    result.version = version
  end

  if environment = data['environment']
    result.environment = environment
    result.environment_instance = Puppet::Node::Environment.remote(environment.to_sym)
  end

  if resources = data['resources']
    result.add_resource(*resources.collect do |res|
      Puppet::Resource.from_data_hash(res)
    end)
  end

  if edges = data['edges']
    edges.each do |edge_hash|
      edge = Puppet::Relationship.from_data_hash(edge_hash)
      unless source = result.resource(edge.source)
        raise ArgumentError, "Could not intern from data: Could not find relationship source #{edge.source.inspect}"
      end
      edge.source = source

      unless target = result.resource(edge.target)
        raise ArgumentError, "Could not intern from data: Could not find relationship target #{edge.target.inspect}"
      end
      edge.target = target

      result.add_edge(edge)
    end
  end

  if classes = data['classes']
    result.add_class(*classes)
  end

  result
end
from_pson(data) click to toggle source
# File lib/puppet/resource/catalog.rb, line 370
def self.from_pson(data)
  Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
  self.from_data_hash(data)
end
new(name = nil, environment = Puppet::Node::Environment::NONE) { |self| ... } click to toggle source
# File lib/puppet/resource/catalog.rb, line 239
def initialize(name = nil, environment = Puppet::Node::Environment::NONE)
  super()
  @name = name
  @classes = []
  @resource_table = {}
  @resources = []
  @relationship_graph = nil

  @host_config = true
  @environment_instance = environment
  @environment = environment.to_s

  @aliases = {}

  if block_given?
    yield(self)
    finalize
  end
end