class Puppet::Resource

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

@api public

Constants

ATTRIBUTES
CLASS_STRING
COMPILABLE_TYPE_STRING
DEFINED_TYPE_STRING
EMPTY_ARRAY
EMPTY_HASH
PCORE_TYPE_KEY
TYPE_CLASS
TYPE_NODE
UNKNOWN_TYPE_STRING
VALUE_KEY

Attributes

catalog[RW]
exported[RW]
file[RW]
kind[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
45 def self.from_data_hash(data)
46   resource = self.allocate
47   resource.initialize_from_hash(data)
48   resource
49 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
260 def initialize(type, title = nil, attributes = EMPTY_HASH)
261   @parameters = {}
262   @sensitive_parameters = []
263   if type.is_a?(Puppet::Resource)
264     # Copy constructor. Let's avoid munging, extracting, tagging, etc
265     src = type
266     self.file = src.file
267     self.line = src.line
268     self.kind = src.kind
269     self.exported = src.exported
270     self.virtual = src.virtual
271     self.set_tags(src)
272     self.environment = src.environment
273     @rstype = src.resource_type
274     @type = src.type
275     @title = src.title
276 
277     src.to_hash.each do |p, v|
278       if v.is_a?(Puppet::Resource)
279         v = v.copy_as_resource
280       elsif v.is_a?(Array)
281         # flatten resource references arrays
282         v = v.flatten if v.flatten.find { |av| av.is_a?(Puppet::Resource) }
283         v = v.collect do |av|
284           av = av.copy_as_resource if av.is_a?(Puppet::Resource)
285           av
286         end
287       end
288 
289       self[p] = v
290     end
291     @sensitive_parameters.replace(type.sensitive_parameters)
292   else
293     if type.is_a?(Hash)
294       #TRANSLATORS 'Puppet::Resource.new' should not be translated
295       raise ArgumentError, _("Puppet::Resource.new does not take a hash as the first argument.") + ' ' +
296         _("Did you mean (%{type}, %{title}) ?") %
297             { type: (type[:type] || type["type"]).inspect, title: (type[:title] || type["title"]).inspect }
298     end
299 
300     # In order to avoid an expensive search of 'known_resource_types" and
301     # to obey/preserve the implementation of the resource's type - if the
302     # given type is a resource type implementation (one of):
303     #   * a "classic" 3.x ruby plugin
304     #   * a compatible implementation (e.g. loading from pcore metadata)
305     #   * a resolved user defined type
306     #
307     # ...then, modify the parameters to the "old" (agent side compatible) way
308     # of describing the type/title with string/symbols.
309     #
310     # TODO: Further optimizations should be possible as the "type juggling" is
311     # not needed when the type implementation is known.
312     #
313     if type.is_a?(Puppet::CompilableResourceType) || type.is_a?(Puppet::Resource::Type)
314       # set the resource type implementation
315       self.resource_type = type
316       # set the type name to the symbolic name
317       type = type.name
318     end
319     @exported = false
320 
321     # Set things like environment, strictness first.
322     attributes.each do |attr, value|
323       next if attr == :parameters
324       send(attr.to_s + "=", value)
325     end
326 
327     if environment.is_a?(Puppet::Node::Environment) && environment != Puppet::Node::Environment::NONE
328       self.file = environment.externalize_path(attributes[:file])
329     end
330 
331     @type, @title = self.class.type_and_title(type, title)
332 
333     rt = resource_type
334 
335     self.kind = self.class.to_kind(rt) unless kind
336     if strict? && rt.nil?
337       if self.class?
338         raise ArgumentError, _("Could not find declared class %{title}") % { title: title }
339       else
340         raise ArgumentError, _("Invalid resource type %{type}") % { type: type }
341       end
342     end
343 
344     params = attributes[:parameters]
345     unless params.nil? || params.empty?
346       extract_parameters(params)
347       if rt && rt.respond_to?(:deprecate_params)
348         rt.deprecate_params(title, params)
349       end
350     end
351 
352     tag(self.type)
353     tag_if_valid(self.title)
354   end
355 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
376 def self.resource_type(type, title, environment)
377   case type
378   when TYPE_CLASS; environment.known_resource_types.hostclass(title == :main ? "" : title)
379   when TYPE_NODE; environment.known_resource_types.node(title)
380   else
381     result = Puppet::Type.type(type)
382     if !result
383       krt = environment.known_resource_types
384       result = krt.definition(type)
385     end
386     result
387   end
388 end
to_kind(resource_type) click to toggle source
    # File lib/puppet/resource.rb
202 def self.to_kind(resource_type)
203   if resource_type == CLASS_STRING
204     CLASS_STRING
205   elsif resource_type.is_a?(Puppet::Resource::Type) && resource_type.type == :definition
206     DEFINED_TYPE_STRING
207   elsif resource_type.is_a?(Puppet::CompilableResourceType)
208     COMPILABLE_TYPE_STRING
209   else
210     UNKNOWN_TYPE_STRING
211   end
212 end
type_and_title(type, title) click to toggle source

@api private

    # File lib/puppet/resource.rb
568 def self.type_and_title(type, title)
569   type, title = extract_type_and_title(type, title)
570   type = munge_type_name(type)
571   if type == TYPE_CLASS
572     title = title == '' ? :main : munge_type_name(title)
573   end
574   [type, title]
575 end
value_to_json_data(value) click to toggle source
    # File lib/puppet/resource.rb
142 def self.value_to_json_data(value)
143   if value.is_a?(Array)
144     value.map{|v| value_to_json_data(v) }
145   elsif value.is_a?(Hash)
146     result = {}
147     value.each_pair { |k, v| result[value_to_json_data(k)] = value_to_json_data(v) }
148     result
149   elsif value.is_a?(Puppet::Resource)
150     value.to_s
151   elsif value.is_a?(Symbol) && value == :undef
152     nil
153   else
154     value
155   end
156 end

Private Class Methods

extract_type_and_title(argtype, argtitle) click to toggle source
    # File lib/puppet/resource.rb
578 def self.extract_type_and_title(argtype, argtitle)
579   if (argtype.nil? || argtype == :component || argtype == :whit) &&
580         argtitle =~ /^([^\[\]]+)\[(.+)\]$/m                  then [ $1,                 $2            ]
581   elsif argtitle.nil? && argtype.is_a?(String) &&
582         argtype =~ /^([^\[\]]+)\[(.+)\]$/m                   then [ $1,                 $2            ]
583   elsif argtitle                                             then [ argtype,            argtitle      ]
584   elsif argtype.is_a?(Puppet::Type)                          then [ argtype.class.name, argtype.title ]
585   else  raise ArgumentError, _("No title provided and %{type} is not a valid resource reference") % { type: argtype.inspect }
586   end
587 end
munge_type_name(value) click to toggle source
    # File lib/puppet/resource.rb
590 def self.munge_type_name(value)
591   return :main if value == :main
592   return TYPE_CLASS if value == '' || value.nil? || value.to_s.casecmp('component') == 0
593   Puppet::Pops::Types::TypeFormatter.singleton.capitalize_segments(value.to_s)
594 end

Public Instance Methods

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

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

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

Compatibility method.

    # File lib/puppet/resource.rb
191 def builtin?
192   # TODO: should be deprecated (was only used in one place in puppet codebase)
193   builtin_type?
194 end
builtin_type?() click to toggle source

Is this a builtin resource type?

    # File lib/puppet/resource.rb
197 def builtin_type?
198   # Note - old implementation only checked if the resource_type was a Class
199   resource_type.is_a?(Puppet::CompilableResourceType)
200 end
class?() click to toggle source
    # File lib/puppet/resource.rb
229 def class?
230   @is_class ||= @type == TYPE_CLASS
231 end
copy_as_resource() click to toggle source
    # File lib/puppet/resource.rb
531 def copy_as_resource
532   Puppet::Resource.new(self)
533 end
each() { |p, v| ... } click to toggle source

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

    # File lib/puppet/resource.rb
215 def each
216   parameters.each { |p,v| yield p, v }
217 end
environment() click to toggle source
    # File lib/puppet/resource.rb
397 def environment
398   @environment ||= if catalog
399                      catalog.environment_instance
400                    else
401                      Puppet.lookup(:current_environment) { Puppet::Node::Environment::NONE }
402                    end
403 end
environment=(environment) click to toggle source
    # File lib/puppet/resource.rb
405 def environment=(environment)
406   @environment = environment
407 end
include?(parameter) click to toggle source
Calls superclass method
    # File lib/puppet/resource.rb
219 def include?(parameter)
220   super || parameters.keys.include?( parameter_name(parameter) )
221 end
initialize_from_hash(data) click to toggle source
   # File lib/puppet/resource.rb
51 def initialize_from_hash(data)
52   type = data['type']
53   raise ArgumentError, _('No resource type provided in serialized data') unless type
54   title = data['title']
55   raise ArgumentError, _('No resource title provided in serialized data') unless title
56   @type, @title = self.class.type_and_title(type, title)
57 
58   params = data['parameters']
59   if params
60     params = Puppet::Pops::Serialization::FromDataConverter.convert(params)
61     @parameters = {}
62     params.each { |param, value| self[param] = value }
63   else
64     @parameters = EMPTY_HASH
65   end
66 
67   sensitives = data['sensitive_parameters']
68   if sensitives
69     @sensitive_parameters = sensitives.map(&:to_sym)
70   else
71     @sensitive_parameters = EMPTY_ARRAY
72   end
73 
74   tags = data['tags']
75   if tags
76     tag(*tags)
77   end
78 
79   ATTRIBUTES.each do |a|
80     value = data[a.to_s]
81     send("#{a}=", value) unless value.nil?
82   end
83 end
inspect() click to toggle source
   # File lib/puppet/resource.rb
85 def inspect
86   "#{@type}[#{@title}]#{to_hash.inspect}"
87 end
key_attributes() click to toggle source
    # File lib/puppet/resource.rb
429 def key_attributes
430   resource_type.respond_to?(:key_attributes) ? resource_type.key_attributes : [:name]
431 end
name() click to toggle source
    # File lib/puppet/resource.rb
516 def name
517   # this is potential namespace conflict
518   # between the notion of an "indirector name"
519   # and a "resource name"
520   [ type, title ].join('/')
521 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
545 def pos
546   nil
547 end
prune_parameters(options = EMPTY_HASH) click to toggle source
    # File lib/puppet/resource.rb
549 def prune_parameters(options = EMPTY_HASH)
550   properties = resource_type.properties.map(&:name)
551 
552   dup.collect do |attribute, value|
553     if value.to_s.empty? or Array(value).empty?
554       delete(attribute)
555     elsif value.to_s == "absent" and attribute.to_s != "ensure"
556       delete(attribute)
557     end
558 
559     parameters_to_include = resource_type.parameters_to_include
560     parameters_to_include += options[:parameters_to_include] || []
561 
562     delete(attribute) unless properties.include?(attribute) || parameters_to_include.include?(attribute)
563   end
564   self
565 end
ref() click to toggle source
    # File lib/puppet/resource.rb
357 def ref
358   to_s
359 end
resolve() click to toggle source

Find our resource.

    # File lib/puppet/resource.rb
362 def resolve
363   catalog ? catalog.resource(to_s) : nil
364 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
369 def resource_type
370   @rstype ||= self.class.resource_type(type, title, environment)
371 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
393 def resource_type=(type)
394   @rstype = type
395 end
stage?() click to toggle source
    # File lib/puppet/resource.rb
233 def stage?
234   @is_stage ||= @type.to_s.casecmp("stage").zero?
235 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
 96 def to_data_hash
 97   data = {
 98     'type' => type,
 99     'title' => title.to_s,
100     'tags' => tags.to_data_hash
101   }
102   ATTRIBUTES.each do |param|
103     value = send(param)
104     data[param.to_s] = value unless value.nil?
105   end
106 
107   data['exported'] ||= false
108 
109   # To get stringified parameter values the flag :stringify_rich can be set
110   # in the puppet context.
111   #
112   stringify = Puppet.lookup(:stringify_rich) { false }
113   converter = stringify ? Puppet::Pops::Serialization::ToStringifiedConverter.new : nil
114 
115   params = {}
116   self.to_hash.each_pair do |param, value|
117     # Don't duplicate the title as the namevar
118     unless param == namevar && value == title
119       if stringify
120         params[param.to_s] = converter.convert(value)
121       else
122         params[param.to_s] = Puppet::Resource.value_to_json_data(value)
123       end
124     end
125   end
126 
127   unless params.empty?
128     data['parameters'] = Puppet::Pops::Serialization::ToDataConverter.convert(params, {
129       :rich_data => Puppet.lookup(:rich_data),
130       :symbol_as_string => true,
131       :local_reference => false,
132       :type_by_reference => true,
133       :message_prefix => ref,
134       :semantic => self
135     })
136   end
137 
138   data['sensitive_parameters'] = sensitive_parameters.map(&:to_s) unless sensitive_parameters.empty?
139   data
140 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
412 def to_hash
413   parse_title.merge parameters
414 end
to_hiera_hash() click to toggle source

Convert our resource to a hiera hash suitable for serialization.

    # File lib/puppet/resource.rb
456 def to_hiera_hash
457   # to_data_hash converts to safe Data types, e.g. no symbols, unicode replacement character
458   h = to_data_hash
459 
460   params = h['parameters'] || {}
461   value = params.delete('ensure')
462 
463   res = {}
464   res['ensure'] = value if value
465   res.merge!(Hash[params.sort])
466 
467   return { h['title'] => res }
468 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
436 def to_hierayaml
437   # Collect list of attributes to align => and move ensure first
438   attr = parameters.keys
439   attr_max = attr.inject(0) { |max,k| k.to_s.length > max ? k.to_s.length : max }
440 
441   attr.sort!
442   if attr.first != :ensure  && attr.include?(:ensure)
443     attr.delete(:ensure)
444     attr.unshift(:ensure)
445   end
446 
447   attributes = attr.collect { |k|
448     v = parameters[k]
449     "    %-#{attr_max}s: %s\n" % [k, Puppet::Parameter.format_value_for_display(v)]
450   }.join
451 
452   "  %s:\n%s" % [self.title, attributes]
453 end
to_manifest() click to toggle source

Convert our resource to Puppet code.

    # File lib/puppet/resource.rb
471 def to_manifest
472   # Collect list of attributes to align => and move ensure first
473   attr = parameters.keys
474   attr_max = attr.inject(0) { |max,k| k.to_s.length > max ? k.to_s.length : max }
475 
476   attr.sort!
477   if attr.first != :ensure  && attr.include?(:ensure)
478     attr.delete(:ensure)
479     attr.unshift(:ensure)
480   end
481 
482   attributes = attr.collect { |k|
483     v = parameters[k]
484     "  %-#{attr_max}s => %s,\n" % [k, Puppet::Parameter.format_value_for_display(v)]
485   }.join
486 
487   escaped = self.title.gsub(/'/,"\\\\'")
488   "%s { '%s':\n%s}" % [self.type.to_s.downcase, escaped, attributes]
489 end
to_ral() click to toggle source

Convert our resource to a RAL resource instance. Creates component instances for resource types that are not of a compilable_type kind. In case the resource doesn’t exist and it’s compilable_type kind, raise an error. There are certain cases where a resource won't be in a catalog, such as when we create a resource directly by using Puppet::Resource.new(...), so we must check its kind before deciding whether the catalog format is of an older version or not.

    # File lib/puppet/resource.rb
502 def to_ral
503   if self.kind == COMPILABLE_TYPE_STRING
504     typeklass = Puppet::Type.type(self.type)
505   elsif self.catalog && self.catalog.catalog_format >= 2
506     typeklass = Puppet::Type.type(:component)
507   else
508     typeklass =  Puppet::Type.type(self.type) || Puppet::Type.type(:component)
509   end
510 
511   raise(Puppet::Error, "Resource type '#{self.type}' was not found") unless typeklass
512 
513   typeklass.new(self)
514 end
to_ref() click to toggle source
    # File lib/puppet/resource.rb
491 def to_ref
492   ref
493 end
to_s() click to toggle source
    # File lib/puppet/resource.rb
416 def to_s
417   "#{type}[#{title}]"
418 end
uniqueness_key() click to toggle source
    # File lib/puppet/resource.rb
420 def uniqueness_key
421   # Temporary kludge to deal with inconsistent use patterns; ensure we don't return nil for namevar/:name
422   h = self.to_hash
423   name = h[namevar] || h[:name] || self.name
424   h[namevar] ||= name
425   h[:name]   ||= name
426   h.values_at(*key_attributes.sort_by { |k| k.to_s })
427 end
valid_parameter?(name) click to toggle source
    # File lib/puppet/resource.rb
535 def valid_parameter?(name)
536   resource_type.valid_parameter?(name)
537 end
validate_parameter(name) click to toggle source
    # File lib/puppet/resource.rb
539 def validate_parameter(name)
540   raise Puppet::ParseError.new(_("no parameter named '%{name}'") % { name: name }, file, line) unless valid_parameter?(name)
541 end
yaml_property_munge(x) click to toggle source
    # File lib/puppet/resource.rb
158 def yaml_property_munge(x)
159   self.value.to_json_data(x)
160 end

Private Instance Methods

extract_parameters(params) click to toggle source
    # File lib/puppet/resource.rb
618 def extract_parameters(params)
619   params.each do |param, value|
620     validate_parameter(param) if strict?
621     self[param] = value
622   end
623 end
missing_arguments() click to toggle source
    # File lib/puppet/resource.rb
523 def missing_arguments
524   resource_type.arguments.select do |param, default|
525     the_param = parameters[param.to_sym]
526     the_param.nil? || the_param.value.nil? || the_param.value == :undef
527   end
528 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
610 def namevar
611   if builtin_type? && !(t = resource_type).nil? && t.key_attributes.length == 1
612     t.key_attributes.first
613   else
614     :name
615   end
616 end
parameter_name(param) click to toggle source

Produce a canonical method name.

    # File lib/puppet/resource.rb
600 def parameter_name(param)
601   param = param.to_s.downcase.to_sym
602   if param == :name and namevar
603     param = namevar
604   end
605   param
606 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
630 def parse_title
631   h = {}
632   type = resource_type
633   if type.respond_to?(:title_patterns) && !type.title_patterns.nil?
634     type.title_patterns.each do |regexp, symbols_and_lambdas|
635       captures = regexp.match(title.to_s)  
636       if captures
637         symbols_and_lambdas.zip(captures[1..-1]).each do |symbol_and_lambda,capture|
638           symbol, proc = symbol_and_lambda
639           # Many types pass "identity" as the proc; we might as well give
640           # them a shortcut to delivering that without the extra cost.
641           #
642           # Especially because the global type defines title_patterns and
643           # uses the identity patterns.
644           #
645           # This was worth about 8MB of memory allocation saved in my
646           # testing, so is worth the complexity for the API.
647           if proc then
648             h[symbol] = proc.call(capture)
649           else
650             h[symbol] = capture
651           end
652         end
653         return h
654       end
655     end
656     # If we've gotten this far, then none of the provided title patterns
657     # matched. Since there's no way to determine the title then the
658     # resource should fail here.
659     raise Puppet::Error, _("No set of title patterns matched the title \"%{title}\".") % { title: title }
660   else
661     return { :name => title.to_s }
662   end
663 end