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
@!attribute [rw] sensitive_parameters
@api private @return [Array<Symbol>] A list of parameters to be treated as sensitive
@deprecated
Public Class Methods
# 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
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
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
# 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
@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
# 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
# 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
# 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
# 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
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
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
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
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
# File lib/puppet/resource.rb 229 def class? 230 @is_class ||= @type == TYPE_CLASS 231 end
# File lib/puppet/resource.rb 531 def copy_as_resource 532 Puppet::Resource.new(self) 533 end
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
# 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
# File lib/puppet/resource.rb 405 def environment=(environment) 406 @environment = environment 407 end
# File lib/puppet/resource.rb 219 def include?(parameter) 220 super || parameters.keys.include?( parameter_name(parameter) ) 221 end
# 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
# File lib/puppet/resource.rb 85 def inspect 86 "#{@type}[#{@title}]#{to_hash.inspect}" 87 end
# File lib/puppet/resource.rb 429 def key_attributes 430 resource_type.respond_to?(:key_attributes) ? resource_type.key_attributes : [:name] 431 end
# 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
# 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
# File lib/puppet/resource.rb 357 def ref 358 to_s 359 end
Find our resource.
# File lib/puppet/resource.rb 362 def resolve 363 catalog ? catalog.resource(to_s) : nil 364 end
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
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
# File lib/puppet/resource.rb 233 def stage? 234 @is_stage ||= @type.to_s.casecmp("stage").zero? 235 end
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
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
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
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
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
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
# File lib/puppet/resource.rb 491 def to_ref 492 ref 493 end
# File lib/puppet/resource.rb 416 def to_s 417 "#{type}[#{title}]" 418 end
# 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
# File lib/puppet/resource.rb 535 def valid_parameter?(name) 536 resource_type.valid_parameter?(name) 537 end
# 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
# File lib/puppet/resource.rb 158 def yaml_property_munge(x) 159 self.value.to_json_data(x) 160 end
Private Instance Methods
# 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
# 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
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
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
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