class Reference

The simplest resource class. Eventually it will function as the base class for all resource-like behaviour.

Public Class Methods

from_pson(pson) click to toggle source
# File lib/puppet/resource.rb, line 30
def self.from_pson(pson)
  raise ArgumentError, "No resource type provided in pson data" unless type = pson['type']
  raise ArgumentError, "No resource title provided in pson data" unless title = pson['title']

  resource = new(type, title)

  if params = pson['parameters']
    params.each { |param, value| resource[param] = value }
  end

  if tags = pson['tags']
    tags.each { |tag| resource.tag(tag) }
  end

  ATTRIBUTES.each do |a|
    if value = pson[a.to_s]
      resource.send(a.to_s + "=", value)
    end
  end

  resource.exported ||= false

  resource
end
new(type, title = nil, attributes = {}) click to toggle source

Create our resource.

# File lib/puppet/resource.rb, line 188
def initialize(type, title = nil, attributes = {})
  @parameters = {}

  # Set things like strictness first.
  attributes.each do |attr, value|
    next if attr == :parameters
    send(attr.to_s + "=", value)
  end

  @type, @title = extract_type_and_title(type, title)

  @type = munge_type_name(@type)

  if self.class?
    @title = :main if @title == ""
    @title = munge_type_name(@title)
  end

  if params = attributes[:parameters]
    extract_parameters(params)
  end

  tag(self.type)
  tag(self.title) if valid_tag?(self.title)

  @reference = self # for serialization compatibility with 0.25.x
  if strict? and ! resource_type
    if self.class?
      raise ArgumentError, "Could not find declared class #{title}"
    else
      raise ArgumentError, "Invalid resource type #{type}"
    end
  end
end
value_to_pson_data(value) click to toggle source
# File lib/puppet/resource.rb, line 83
def self.value_to_pson_data(value)
  if value.is_a? Array
    value.map{|v| value_to_pson_data(v) }
  elsif value.is_a? Puppet::Resource
    value.to_s
  else
    value
  end
end

Public Instance Methods

==(other) click to toggle source
# File lib/puppet/resource.rb, line 130
def ==(other)
  return false unless other.respond_to?(:title) and self.type == other.type and self.title == other.title

  return false unless to_hash == other.to_hash
  true
end
[](param) click to toggle source

Return a given parameter’s value. Converts all passed names to lower-case symbols.

# File lib/puppet/resource.rb, line 126
def [](param)
  parameters[parameter_name(param)]
end
[]=(param, value) click to toggle source

Set a given parameter. Converts all passed names to lower-case symbols.

# File lib/puppet/resource.rb, line 119
def []=(param, value)
  validate_parameter(param) if validate_parameters
  parameters[parameter_name(param)] = value
end
builtin?() click to toggle source

Compatibility method.

# File lib/puppet/resource.rb, line 138
def builtin?
  builtin_type?
end
builtin_type?() click to toggle source

Is this a builtin resource type?

# File lib/puppet/resource.rb, line 143
def builtin_type?
  resource_type.is_a?(Class)
end
class?() click to toggle source
# File lib/puppet/resource.rb, line 179
def class?
  @is_class ||= @type == "Class"
end
each() { |p, v| ... } click to toggle source

Iterate over each param/value pair, as required for Enumerable.

# File lib/puppet/resource.rb, line 148
def each
  parameters.each { |p,v| yield p, v }
end
environment() click to toggle source

These two methods are extracted into a Helper module, but file load order prevents me from including them in the class, and I had weird behaviour (i.e., sometimes it didn’t work) when I directly extended each resource with the helper.

# File lib/puppet/resource.rb, line 161
def environment
  Puppet::Node::Environment.new(@environment)
end
environment=(env) click to toggle source
# File lib/puppet/resource.rb, line 165
def environment=(env)
  if env.is_a?(String) or env.is_a?(Symbol)
    @environment = env
  else
    @environment = env.name
  end
end
include?(parameter) click to toggle source
Calls superclass method
# File lib/puppet/resource.rb, line 152
def include?(parameter)
  super || parameters.keys.include?( parameter_name(parameter) )
end
inspect() click to toggle source
# File lib/puppet/resource.rb, line 55
def inspect
  "#{@type}[#{@title}]#{to_hash.inspect}"
end
key_attributes() click to toggle source
# File lib/puppet/resource.rb, line 258
def key_attributes
  resource_type.respond_to?(:key_attributes) ? resource_type.key_attributes : [:name]
end
name() click to toggle source
# File lib/puppet/resource.rb, line 296
def name
  # this is potential namespace conflict
  # between the notion of an "indirector name"
  # and a "resource name"
  [ type, title ].join('/')
end
prune_parameters(options = {}) click to toggle source
# File lib/puppet/resource.rb, line 380
def prune_parameters(options = {})
  properties = resource_type.properties.map(&:name)

  dup.collect do |attribute, value|
    if value.to_s.empty? or Array(value).empty?
      delete(attribute)
    elsif value.to_s == "absent" and attribute.to_s != "ensure"
      delete(attribute)
    end

    parameters_to_include = options[:parameters_to_include] || []
    delete(attribute) unless properties.include?(attribute) || parameters_to_include.include?(attribute)
  end
  self
end
ref() click to toggle source
# File lib/puppet/resource.rb, line 223
def ref
  to_s
end
resolve() click to toggle source

Find our resource.

# File lib/puppet/resource.rb, line 228
def resolve
  catalog ? catalog.resource(to_s) : nil
end
resource_type() click to toggle source
# File lib/puppet/resource.rb, line 232
def resource_type
  @rstype ||= case type
  when "Class"; known_resource_types.hostclass(title == :main ? "" : title)
  when "Node"; known_resource_types.node(title)
  else
    Puppet::Type.type(type) || known_resource_types.definition(type)
  end
end
set_default_parameters(scope) click to toggle source
# File lib/puppet/resource.rb, line 332
def set_default_parameters(scope)
  return [] unless resource_type and resource_type.respond_to?(:arguments)

  unless is_a?(Puppet::Parser::Resource)
    fail Puppet::DevError, "Cannot evaluate default parameters for #{self} - not a parser resource"
  end

  missing_arguments.collect do |param, default|
    external_value = lookup_external_default_for(param, scope)

    if external_value.nil? && default.nil?
      next
    elsif external_value.nil?
      value = default.safeevaluate(scope)
    else
      value = external_value
    end

    self[param.to_sym] = value
    param
  end.compact
end
stage?() click to toggle source
# File lib/puppet/resource.rb, line 183
def stage?
  @is_stage ||= @type.to_s.downcase == "stage"
end
to_hash() click to toggle source

Produce a simple hash of our parameters.

# File lib/puppet/resource.rb, line 242
def to_hash
  parse_title.merge parameters
end
to_manifest() click to toggle source

Convert our resource to Puppet code.

# File lib/puppet/resource.rb, line 263
def to_manifest
  # Collect list of attributes to align => and move ensure first
  attr = parameters.keys
  attr_max = attr.inject(0) { |max,k| k.to_s.length > max ? k.to_s.length : max }

  attr.sort!
  if attr.first != :ensure  && attr.include?(:ensure)
    attr.delete(:ensure)
    attr.unshift(:ensure)
  end

  attributes = attr.collect { |k|
    v = parameters[k]
    "  %-#{attr_max}s => %s,\n" % [k, Puppet::Parameter.format_value_for_display(v)]
  }.join

  "%s { '%s':\n%s}" % [self.type.to_s.downcase, self.title, attributes]
end
to_pson(*args) click to toggle source
# File lib/puppet/resource.rb, line 105
def to_pson(*args)
  to_pson_data_hash.to_pson(*args)
end
to_pson_data_hash() click to toggle source
# File lib/puppet/resource.rb, line 59
def to_pson_data_hash
  data = ([:type, :title, :tags] + ATTRIBUTES).inject({}) do |hash, param|
    next hash unless value = self.send(param)
    hash[param.to_s] = value
    hash
  end

  data["exported"] ||= false

  params = self.to_hash.inject({}) do |hash, ary|
    param, value = ary

    # Don't duplicate the title as the namevar
    next hash if param == namevar and value == title

    hash[param] = Puppet::Resource.value_to_pson_data(value)
    hash
  end

  data["parameters"] = params unless params.empty?

  data
end
to_ral() click to toggle source

Convert our resource to a RAL resource instance. Creates component instances for resource types that don’t exist.

# File lib/puppet/resource.rb, line 288
def to_ral
  if typeklass = Puppet::Type.type(self.type)
    return typeklass.new(self)
  else
    return Puppet::Type::Component.new(self)
  end
end
to_ref() click to toggle source
# File lib/puppet/resource.rb, line 282
def to_ref
  ref
end
to_resource() click to toggle source
# File lib/puppet/resource.rb, line 355
def to_resource
  self
end
to_s() click to toggle source
# File lib/puppet/resource.rb, line 246
def to_s
  "#{type}[#{title}]"
end
uniqueness_key() click to toggle source
# File lib/puppet/resource.rb, line 250
def uniqueness_key
  # Temporary kludge to deal with inconsistant use patters
  h = self.to_hash
  h[namevar] ||= h[:name]
  h[:name]   ||= h[namevar]
  h.values_at(*key_attributes.sort_by { |k| k.to_s })
end
valid_parameter?(name) click to toggle source
# File lib/puppet/resource.rb, line 359
def valid_parameter?(name)
  resource_type.valid_parameter?(name)
end
validate_complete() click to toggle source

Verify that all required arguments are either present or have been provided with defaults. Must be called after ‘set_default_parameters’. We can’t join the methods because Type#set_parameters needs specifically ordered behavior.

# File lib/puppet/resource.rb, line 367
def validate_complete
  return unless resource_type and resource_type.respond_to?(:arguments)

  resource_type.arguments.each do |param, default|
    param = param.to_sym
    fail Puppet::ParseError, "Must pass #{param} to #{self}" unless parameters.include?(param)
  end
end
validate_parameter(name) click to toggle source
# File lib/puppet/resource.rb, line 376
def validate_parameter(name)
  raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name)
end
yaml_property_munge(x) click to toggle source
# File lib/puppet/resource.rb, line 93
def yaml_property_munge(x)
  case x
  when Hash
    x.inject({}) { |h,kv|
      k,v = kv
      h[k] = self.class.value_to_pson_data(v)
      h
    }
  else self.class.value_to_pson_data(x)
  end
end

Private Instance Methods

extract_parameters(params) click to toggle source
# File lib/puppet/resource.rb, line 417
def extract_parameters(params)
  params.each do |param, value|
    validate_parameter(param) if strict?
    self[param] = value
  end
end
extract_type_and_title(argtype, argtitle) click to toggle source
# File lib/puppet/resource.rb, line 424
def extract_type_and_title(argtype, argtitle)
  if    (argtitle || argtype) =~ /^([^\[\]]+)\[(.+)\]$/ then [ $1,                 $2            ]
  elsif argtitle                                         then [ argtype,            argtitle      ]
  elsif argtype.is_a?(Puppet::Type)                      then [ argtype.class.name, argtype.title ]
  elsif argtype.is_a?(Hash)                              then
    raise ArgumentError, "Puppet::Resource.new does not take a hash as the first argument. "+
      "Did you mean (#{(argtype[:type] || argtype["type"]).inspect}, #{(argtype[:title] || argtype["title"]).inspect }) ?"
  else raise ArgumentError, "No title provided and #{argtype.inspect} is not a valid resource reference"
  end
end
lookup_external_default_for(param, scope) click to toggle source

Consult external data bindings for class parameter values which must be namespaced in the backend.

Example:

class foo($port){ ... }

We make a request to the backend for the key ‘foo::port’ not ‘foo’

# File lib/puppet/resource.rb, line 320
def lookup_external_default_for(param, scope)
  if resource_type.type == :hostclass
    Puppet::DataBinding.indirection.find(
      "#{resource_type.name}::#{param}",
      :environment => scope.environment.to_s,
      :variables => Puppet::DataBinding::Variables.new(scope))
  else
    nil
  end
end
missing_arguments() click to toggle source
# File lib/puppet/resource.rb, line 303
def missing_arguments
  resource_type.arguments.select do |param, default|
    param = param.to_sym
    parameters[param].nil? || parameters[param].value == :undef
  end
end
munge_type_name(value) click to toggle source
# File lib/puppet/resource.rb, line 435
def munge_type_name(value)
  return :main if value == :main
  return "Class" if value == "" or value.nil? or value.to_s.downcase == "component"

  value.to_s.split("::").collect { |s| s.capitalize }.join("::")
end
namevar() click to toggle source

The namevar for our resource type. If the type doesn’t exist, always use :name.

# File lib/puppet/resource.rb, line 409
def namevar
  if builtin_type? and t = resource_type and t.key_attributes.length == 1
    t.key_attributes.first
  else
    :name
  end
end
parameter_name(param) click to toggle source

Produce a canonical method name.

# File lib/puppet/resource.rb, line 399
def parameter_name(param)
  param = param.to_s.downcase.to_sym
  if param == :name and n = namevar
    param = namevar
  end
  param
end
parameters() click to toggle source
# File lib/puppet/resource.rb, line 476
def parameters
  # @parameters could have been loaded from YAML, causing it to be nil (by
  # bypassing initialize).
  @parameters ||= {}
end
parse_title() click to toggle source
# File lib/puppet/resource.rb, line 442
def parse_title
  h = {}
  type = resource_type
  if type.respond_to? :title_patterns
    type.title_patterns.each { |regexp, symbols_and_lambdas|
      if captures = regexp.match(title.to_s)
        symbols_and_lambdas.zip(captures[1..-1]).each do |symbol_and_lambda,capture|
          symbol, proc = symbol_and_lambda
          # Many types pass "identity" as the proc; we might as well give
          # them a shortcut to delivering that without the extra cost.
          #
          # Especially because the global type defines title_patterns and
          # uses the identity patterns.
          #
          # This was worth about 8MB of memory allocation saved in my
          # testing, so is worth the complexity for the API.
          if proc then
            h[symbol] = proc.call(capture)
          else
            h[symbol] = capture
          end
        end
        return h
      end
    }
    # If we've gotten this far, then none of the provided title patterns
    # matched. Since there's no way to determine the title then the
    # resource should fail here.
    raise Puppet::Error, "No set of title patterns matched the title \"#{title}\"."
  else
    return { :name => title.to_s }
  end
end