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
@!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 39 def self.from_data_hash(data) 40 resource = self.allocate 41 resource.initialize_from_hash(data) 42 resource 43 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 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
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
@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
# 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
# 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
# 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
# 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
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
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
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
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
# File lib/puppet/resource.rb 211 def class? 212 @is_class ||= @type == TYPE_CLASS 213 end
# File lib/puppet/resource.rb 493 def copy_as_resource 494 Puppet::Resource.new(self) 495 end
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
# 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
# File lib/puppet/resource.rb 381 def environment=(environment) 382 @environment = environment 383 end
# File lib/puppet/resource.rb 201 def include?(parameter) 202 super || parameters.keys.include?( parameter_name(parameter) ) 203 end
# 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
# File lib/puppet/resource.rb 79 def inspect 80 "#{@type}[#{@title}]#{to_hash.inspect}" 81 end
# File lib/puppet/resource.rb 405 def key_attributes 406 resource_type.respond_to?(:key_attributes) ? resource_type.key_attributes : [:name] 407 end
# 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
# 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
# File lib/puppet/resource.rb 333 def ref 334 to_s 335 end
Find our resource.
# File lib/puppet/resource.rb 338 def resolve 339 catalog ? catalog.resource(to_s) : nil 340 end
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
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
# File lib/puppet/resource.rb 215 def stage? 216 @is_stage ||= @type.to_s.casecmp("stage").zero? 217 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 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
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
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
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
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
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
# File lib/puppet/resource.rb 467 def to_ref 468 ref 469 end
# File lib/puppet/resource.rb 392 def to_s 393 "#{type}[#{title}]" 394 end
# 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
# File lib/puppet/resource.rb 497 def valid_parameter?(name) 498 resource_type.valid_parameter?(name) 499 end
# 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
# File lib/puppet/resource.rb 152 def yaml_property_munge(x) 153 self.value.to_json_data(x) 154 end
Private Instance Methods
# 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
# 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
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
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
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