class Puppet::Resource

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

@api public

Constants

ATTRIBUTES
EMPTY_ARRAY
EMPTY_HASH
PCORE_TYPE_KEY
TYPE_CLASS
TYPE_NODE
VALUE_KEY

Attributes

catalog[RW]
exported[RW]
file[RW]
line[RW]
parameters[R]
sensitive_parameters[RW]

@!attribute [rw] sensitive_parameters

@api private
@return [Array<Symbol>] A list of parameters to be treated as sensitive
strict[RW]
title[R]
type[R]
validate_parameters[RW]

@deprecated

virtual[RW]

Public Class Methods

from_data_hash(data) click to toggle source
   # File lib/puppet/resource.rb
39 def self.from_data_hash(data)
40   resource = self.allocate
41   resource.initialize_from_hash(data)
42   resource
43 end
new(type, title = nil, attributes = EMPTY_HASH) click to toggle source

Construct a resource from data.

Constructs a resource instance with the given `type` and `title`. Multiple type signatures are possible for these arguments and most will result in an expensive call to {Puppet::Node::Environment#known_resource_types} in order to resolve `String` and `Symbol` Types to actual Ruby classes.

@param type [Symbol, String] The name of the Puppet Type, as a string or

symbol. The actual Type will be looked up using
{Puppet::Node::Environment#known_resource_types}. This lookup is expensive.

@param type [String] The full resource name in the form of

`"Type[Title]"`. This method of calling should only be used when
`title` is `nil`.

@param type [nil] If a `nil` is passed, the title argument must be a string

of the form `"Type[Title]"`.

@param type [Class] A class that inherits from `Puppet::Type`. This method

of construction is much more efficient as it skips calls to
{Puppet::Node::Environment#known_resource_types}.

@param title [String, :main, nil] The title of the resource. If type is `nil`, may also

be the full resource name in the form of `"Type[Title]"`.

@api public

    # File lib/puppet/resource.rb
242 def initialize(type, title = nil, attributes = EMPTY_HASH)
243   @parameters = {}
244   @sensitive_parameters = []
245   if type.is_a?(Puppet::Resource)
246     # Copy constructor. Let's avoid munging, extracting, tagging, etc
247     src = type
248     self.file = src.file
249     self.line = src.line
250     self.exported = src.exported
251     self.virtual = src.virtual
252     self.set_tags(src)
253     self.environment = src.environment
254     @rstype = src.resource_type
255     @type = src.type
256     @title = src.title
257 
258     src.to_hash.each do |p, v|
259       if v.is_a?(Puppet::Resource)
260         v = v.copy_as_resource
261       elsif v.is_a?(Array)
262         # flatten resource references arrays
263         v = v.flatten if v.flatten.find { |av| av.is_a?(Puppet::Resource) }
264         v = v.collect do |av|
265           av = av.copy_as_resource if av.is_a?(Puppet::Resource)
266           av
267         end
268       end
269 
270       self[p] = v
271     end
272     @sensitive_parameters.replace(type.sensitive_parameters)
273   else
274     if type.is_a?(Hash)
275       #TRANSLATORS 'Puppet::Resource.new' should not be translated
276       raise ArgumentError, _("Puppet::Resource.new does not take a hash as the first argument.") + ' ' +
277         _("Did you mean (%{type}, %{title}) ?") %
278             { type: (type[:type] || type["type"]).inspect, title: (type[:title] || type["title"]).inspect }
279     end
280 
281     # In order to avoid an expensive search of 'known_resource_types" and
282     # to obey/preserve the implementation of the resource's type - if the
283     # given type is a resource type implementation (one of):
284     #   * a "classic" 3.x ruby plugin
285     #   * a compatible implementation (e.g. loading from pcore metadata)
286     #   * a resolved user defined type
287     #
288     # ...then, modify the parameters to the "old" (agent side compatible) way
289     # of describing the type/title with string/symbols.
290     #
291     # TODO: Further optimizations should be possible as the "type juggling" is
292     # not needed when the type implementation is known.
293     #
294     if type.is_a?(Puppet::CompilableResourceType) || type.is_a?(Puppet::Resource::Type)
295       # set the resource type implementation
296       self.resource_type = type
297       # set the type name to the symbolic name
298       type = type.name
299     end
300     @exported = false
301 
302     # Set things like environment, strictness first.
303     attributes.each do |attr, value|
304       next if attr == :parameters
305       send(attr.to_s + "=", value)
306     end
307 
308     @type, @title = self.class.type_and_title(type, title)
309 
310     rt = resource_type
311 
312     if strict? && rt.nil?
313       if self.class?
314         raise ArgumentError, _("Could not find declared class %{title}") % { title: title }
315       else
316         raise ArgumentError, _("Invalid resource type %{type}") % { type: type }
317       end
318     end
319 
320     params = attributes[:parameters]
321     unless params.nil? || params.empty?
322       extract_parameters(params)
323       if rt && rt.respond_to?(:deprecate_params)
324         rt.deprecate_params(title, params)
325       end
326     end
327 
328     tag(self.type)
329     tag_if_valid(self.title)
330   end
331 end
resource_type(type, title, environment) click to toggle source

The resource's type implementation @return [Puppet::Type, Puppet::Resource::Type] @api private

    # File lib/puppet/resource.rb
352 def self.resource_type(type, title, environment)
353   case type
354   when TYPE_CLASS; environment.known_resource_types.hostclass(title == :main ? "" : title)
355   when TYPE_NODE; environment.known_resource_types.node(title)
356   else
357     result = Puppet::Type.type(type)
358     if !result
359       krt = environment.known_resource_types
360       result = krt.definition(type)
361     end
362     result
363   end
364 end
type_and_title(type, title) click to toggle source

@api private

    # File lib/puppet/resource.rb
530 def self.type_and_title(type, title)
531   type, title = extract_type_and_title(type, title)
532   type = munge_type_name(type)
533   if type == TYPE_CLASS
534     title = title == '' ? :main : munge_type_name(title)
535   end
536   [type, title]
537 end
value_to_json_data(value) click to toggle source
    # File lib/puppet/resource.rb
136 def self.value_to_json_data(value)
137   if value.is_a?(Array)
138     value.map{|v| value_to_json_data(v) }
139   elsif value.is_a?(Hash)
140     result = {}
141     value.each_pair { |k, v| result[value_to_json_data(k)] = value_to_json_data(v) }
142     result
143   elsif value.is_a?(Puppet::Resource)
144     value.to_s
145   elsif value.is_a?(Symbol) && value == :undef
146     nil
147   else
148     value
149   end
150 end

Private Class Methods

extract_type_and_title(argtype, argtitle) click to toggle source
    # File lib/puppet/resource.rb
540 def self.extract_type_and_title(argtype, argtitle)
541   if (argtype.nil? || argtype == :component || argtype == :whit) &&
542         argtitle =~ /^([^\[\]]+)\[(.+)\]$/m                  then [ $1,                 $2            ]
543   elsif argtitle.nil? && argtype.is_a?(String) &&
544         argtype =~ /^([^\[\]]+)\[(.+)\]$/m                   then [ $1,                 $2            ]
545   elsif argtitle                                             then [ argtype,            argtitle      ]
546   elsif argtype.is_a?(Puppet::Type)                          then [ argtype.class.name, argtype.title ]
547   else  raise ArgumentError, _("No title provided and %{type} is not a valid resource reference") % { type: argtype.inspect }
548   end
549 end
munge_type_name(value) click to toggle source
    # File lib/puppet/resource.rb
552 def self.munge_type_name(value)
553   return :main if value == :main
554   return TYPE_CLASS if value == '' || value.nil? || value.to_s.casecmp('component') == 0
555   Puppet::Pops::Types::TypeFormatter.singleton.capitalize_segments(value.to_s)
556 end

Public Instance Methods

==(other) click to toggle source
    # File lib/puppet/resource.rb
177 def ==(other)
178   return false unless other.respond_to?(:title) and self.type == other.type and self.title == other.title
179 
180   return false unless to_hash == other.to_hash
181   true
182 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
173 def [](param)
174   parameters[parameter_name(param)]
175 end
[]=(param, value) click to toggle source

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

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

Compatibility method.

    # File lib/puppet/resource.rb
185 def builtin?
186   # TODO: should be deprecated (was only used in one place in puppet codebase)
187   builtin_type?
188 end
builtin_type?() click to toggle source

Is this a builtin resource type?

    # File lib/puppet/resource.rb
191 def builtin_type?
192   # Note - old implementation only checked if the resource_type was a Class
193   resource_type.is_a?(Puppet::CompilableResourceType)
194 end
class?() click to toggle source
    # File lib/puppet/resource.rb
211 def class?
212   @is_class ||= @type == TYPE_CLASS
213 end
copy_as_resource() click to toggle source
    # File lib/puppet/resource.rb
493 def copy_as_resource
494   Puppet::Resource.new(self)
495 end
each() { |p, v| ... } click to toggle source

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

    # File lib/puppet/resource.rb
197 def each
198   parameters.each { |p,v| yield p, v }
199 end
environment() click to toggle source
    # File lib/puppet/resource.rb
373 def environment
374   @environment ||= if catalog
375                      catalog.environment_instance
376                    else
377                      Puppet.lookup(:current_environment) { Puppet::Node::Environment::NONE }
378                    end
379 end
environment=(environment) click to toggle source
    # File lib/puppet/resource.rb
381 def environment=(environment)
382   @environment = environment
383 end
include?(parameter) click to toggle source
Calls superclass method
    # File lib/puppet/resource.rb
201 def include?(parameter)
202   super || parameters.keys.include?( parameter_name(parameter) )
203 end
initialize_from_hash(data) click to toggle source
   # File lib/puppet/resource.rb
45 def initialize_from_hash(data)
46   type = data['type']
47   raise ArgumentError, _('No resource type provided in serialized data') unless type
48   title = data['title']
49   raise ArgumentError, _('No resource title provided in serialized data') unless title
50   @type, @title = self.class.type_and_title(type, title)
51 
52   params = data['parameters']
53   if params
54     params = Puppet::Pops::Serialization::FromDataConverter.convert(params)
55     @parameters = {}
56     params.each { |param, value| self[param] = value }
57   else
58     @parameters = EMPTY_HASH
59   end
60 
61   sensitives = data['sensitive_parameters']
62   if sensitives
63     @sensitive_parameters = sensitives.map(&:to_sym)
64   else
65     @sensitive_parameters = EMPTY_ARRAY
66   end
67 
68   tags = data['tags']
69   if tags
70     tag(*tags)
71   end
72 
73   ATTRIBUTES.each do |a|
74     value = data[a.to_s]
75     send("#{a}=", value) unless value.nil?
76   end
77 end
inspect() click to toggle source
   # File lib/puppet/resource.rb
79 def inspect
80   "#{@type}[#{@title}]#{to_hash.inspect}"
81 end
key_attributes() click to toggle source
    # File lib/puppet/resource.rb
405 def key_attributes
406   resource_type.respond_to?(:key_attributes) ? resource_type.key_attributes : [:name]
407 end
name() click to toggle source
    # File lib/puppet/resource.rb
478 def name
479   # this is potential namespace conflict
480   # between the notion of an "indirector name"
481   # and a "resource name"
482   [ type, title ].join('/')
483 end
pos() click to toggle source

This method, together with file and line, makes it possible for a Resource to be a 'source_pos' in a reported issue. @return [Integer] Instances of this class will always return `nil`.

    # File lib/puppet/resource.rb
507 def pos
508   nil
509 end
prune_parameters(options = EMPTY_HASH) click to toggle source
    # File lib/puppet/resource.rb
511 def prune_parameters(options = EMPTY_HASH)
512   properties = resource_type.properties.map(&:name)
513 
514   dup.collect do |attribute, value|
515     if value.to_s.empty? or Array(value).empty?
516       delete(attribute)
517     elsif value.to_s == "absent" and attribute.to_s != "ensure"
518       delete(attribute)
519     end
520 
521     parameters_to_include = resource_type.parameters_to_include
522     parameters_to_include += options[:parameters_to_include] || []
523 
524     delete(attribute) unless properties.include?(attribute) || parameters_to_include.include?(attribute)
525   end
526   self
527 end
ref() click to toggle source
    # File lib/puppet/resource.rb
333 def ref
334   to_s
335 end
resolve() click to toggle source

Find our resource.

    # File lib/puppet/resource.rb
338 def resolve
339   catalog ? catalog.resource(to_s) : nil
340 end
resource_type() click to toggle source

The resource's type implementation @return [Puppet::Type, Puppet::Resource::Type] @api private

    # File lib/puppet/resource.rb
345 def resource_type
346   @rstype ||= self.class.resource_type(type, title, environment)
347 end
resource_type=(type) click to toggle source

Set the resource's type implementation @param type [Puppet::Type, Puppet::Resource::Type] @api private

    # File lib/puppet/resource.rb
369 def resource_type=(type)
370   @rstype = type
371 end
stage?() click to toggle source
    # File lib/puppet/resource.rb
215 def stage?
216   @is_stage ||= @type.to_s.casecmp("stage").zero?
217 end
to_data_hash() click to toggle source

Produces a Data compliant hash of the resource. The result depends on the –rich_data setting, and the context value for Puppet.lookup(:stringify_rich), that if it is `true` will use the ToStringifiedConverter to produce the value per parameter. (Note that the ToStringifiedConverter output is lossy and should not be used when producing a catalog serialization).

    # File lib/puppet/resource.rb
 90 def to_data_hash
 91   data = {
 92     'type' => type,
 93     'title' => title.to_s,
 94     'tags' => tags.to_data_hash
 95   }
 96   ATTRIBUTES.each do |param|
 97     value = send(param)
 98     data[param.to_s] = value unless value.nil?
 99   end
100 
101   data['exported'] ||= false
102 
103   # To get stringified parameter values the flag :stringify_rich can be set
104   # in the puppet context.
105   #
106   stringify = Puppet.lookup(:stringify_rich) { false }
107   converter = stringify ? Puppet::Pops::Serialization::ToStringifiedConverter.new : nil
108 
109   params = {}
110   self.to_hash.each_pair do |param, value|
111     # Don't duplicate the title as the namevar
112     unless param == namevar && value == title
113       if stringify
114         params[param.to_s] = converter.convert(value)
115       else
116         params[param.to_s] = Puppet::Resource.value_to_json_data(value)
117       end
118     end
119   end
120 
121   unless params.empty?
122     data['parameters'] = Puppet::Pops::Serialization::ToDataConverter.convert(params, {
123       :rich_data => Puppet.lookup(:rich_data),
124       :symbol_as_string => true,
125       :local_reference => false,
126       :type_by_reference => true,
127       :message_prefix => ref,
128       :semantic => self
129     })
130   end
131 
132   data['sensitive_parameters'] = sensitive_parameters.map(&:to_s) unless sensitive_parameters.empty?
133   data
134 end
to_hash() click to toggle source

Produces a hash of attribute to value mappings where the title parsed into its components acts as the default values overridden by any parameter values explicitly given as parameters.

    # File lib/puppet/resource.rb
388 def to_hash
389   parse_title.merge parameters
390 end
to_hiera_hash() click to toggle source

Convert our resource to a hiera hash suitable for serialization.

    # File lib/puppet/resource.rb
432 def to_hiera_hash
433   # to_data_hash converts to safe Data types, e.g. no symbols, unicode replacement character
434   h = to_data_hash
435 
436   params = h['parameters'] || {}
437   value = params.delete('ensure')
438 
439   res = {}
440   res['ensure'] = value if value
441   res.merge!(Hash[params.sort])
442 
443   return { h['title'] => res }
444 end
to_hierayaml() click to toggle source

Convert our resource to yaml for Hiera purposes.

@deprecated Use {to_hiera_hash} instead.

    # File lib/puppet/resource.rb
412 def to_hierayaml
413   # Collect list of attributes to align => and move ensure first
414   attr = parameters.keys
415   attr_max = attr.inject(0) { |max,k| k.to_s.length > max ? k.to_s.length : max }
416 
417   attr.sort!
418   if attr.first != :ensure  && attr.include?(:ensure)
419     attr.delete(:ensure)
420     attr.unshift(:ensure)
421   end
422 
423   attributes = attr.collect { |k|
424     v = parameters[k]
425     "    %-#{attr_max}s: %s\n" % [k, Puppet::Parameter.format_value_for_display(v)]
426   }.join
427 
428   "  %s:\n%s" % [self.title, attributes]
429 end
to_manifest() click to toggle source

Convert our resource to Puppet code.

    # File lib/puppet/resource.rb
447 def to_manifest
448   # Collect list of attributes to align => and move ensure first
449   attr = parameters.keys
450   attr_max = attr.inject(0) { |max,k| k.to_s.length > max ? k.to_s.length : max }
451 
452   attr.sort!
453   if attr.first != :ensure  && attr.include?(:ensure)
454     attr.delete(:ensure)
455     attr.unshift(:ensure)
456   end
457 
458   attributes = attr.collect { |k|
459     v = parameters[k]
460     "  %-#{attr_max}s => %s,\n" % [k, Puppet::Parameter.format_value_for_display(v)]
461   }.join
462 
463   escaped = self.title.gsub(/'/,"\\\\'")
464   "%s { '%s':\n%s}" % [self.type.to_s.downcase, escaped, attributes]
465 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
473 def to_ral
474   typeklass = Puppet::Type.type(self.type) || Puppet::Type.type(:component)
475   typeklass.new(self)
476 end
to_ref() click to toggle source
    # File lib/puppet/resource.rb
467 def to_ref
468   ref
469 end
to_s() click to toggle source
    # File lib/puppet/resource.rb
392 def to_s
393   "#{type}[#{title}]"
394 end
uniqueness_key() click to toggle source
    # File lib/puppet/resource.rb
396 def uniqueness_key
397   # Temporary kludge to deal with inconsistent use patterns; ensure we don't return nil for namevar/:name
398   h = self.to_hash
399   name = h[namevar] || h[:name] || self.name
400   h[namevar] ||= name
401   h[:name]   ||= name
402   h.values_at(*key_attributes.sort_by { |k| k.to_s })
403 end
valid_parameter?(name) click to toggle source
    # File lib/puppet/resource.rb
497 def valid_parameter?(name)
498   resource_type.valid_parameter?(name)
499 end
validate_parameter(name) click to toggle source
    # File lib/puppet/resource.rb
501 def validate_parameter(name)
502   raise Puppet::ParseError.new(_("no parameter named '%{name}'") % { name: name }, file, line) unless valid_parameter?(name)
503 end
yaml_property_munge(x) click to toggle source
    # File lib/puppet/resource.rb
152 def yaml_property_munge(x)
153   self.value.to_json_data(x)
154 end

Private Instance Methods

extract_parameters(params) click to toggle source
    # File lib/puppet/resource.rb
580 def extract_parameters(params)
581   params.each do |param, value|
582     validate_parameter(param) if strict?
583     self[param] = value
584   end
585 end
missing_arguments() click to toggle source
    # File lib/puppet/resource.rb
485 def missing_arguments
486   resource_type.arguments.select do |param, default|
487     the_param = parameters[param.to_sym]
488     the_param.nil? || the_param.value.nil? || the_param.value == :undef
489   end
490 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
572 def namevar
573   if builtin_type? && !(t = resource_type).nil? && t.key_attributes.length == 1
574     t.key_attributes.first
575   else
576     :name
577   end
578 end
parameter_name(param) click to toggle source

Produce a canonical method name.

    # File lib/puppet/resource.rb
562 def parameter_name(param)
563   param = param.to_s.downcase.to_sym
564   if param == :name and namevar
565     param = namevar
566   end
567   param
568 end
parse_title() click to toggle source

Produces a hash with { :key => part_of_title } for each entry in title_patterns for the resource type. A typical result for a title of 'example' is {:name => 'example'}. A resource type with a complex title to attribute mapping returns one entry in the hash per part.

    # File lib/puppet/resource.rb
592 def parse_title
593   h = {}
594   type = resource_type
595   if type.respond_to?(:title_patterns) && !type.title_patterns.nil?
596     type.title_patterns.each do |regexp, symbols_and_lambdas|
597       captures = regexp.match(title.to_s)  
598       if captures
599         symbols_and_lambdas.zip(captures[1..-1]).each do |symbol_and_lambda,capture|
600           symbol, proc = symbol_and_lambda
601           # Many types pass "identity" as the proc; we might as well give
602           # them a shortcut to delivering that without the extra cost.
603           #
604           # Especially because the global type defines title_patterns and
605           # uses the identity patterns.
606           #
607           # This was worth about 8MB of memory allocation saved in my
608           # testing, so is worth the complexity for the API.
609           if proc then
610             h[symbol] = proc.call(capture)
611           else
612             h[symbol] = capture
613           end
614         end
615         return h
616       end
617     end
618     # If we've gotten this far, then none of the provided title patterns
619     # matched. Since there's no way to determine the title then the
620     # resource should fail here.
621     raise Puppet::Error, _("No set of title patterns matched the title \"%{title}\".") % { title: title }
622   else
623     return { :name => title.to_s }
624   end
625 end