Class: Puppet::Resource

Inherits:
Object show all
Extended by:
Indirector, Util::Pson
Includes:
Enumerable, Util::Tagging
Defined in:
lib/puppet/resource.rb,
lib/puppet/resource/status.rb

Overview

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

Direct Known Subclasses

Parser::Resource

Defined Under Namespace

Modules: TypeCollectionHelper, Validator Classes: ActiveRecord, Catalog, Ral, Rest, Status, StoreConfigs, Type, TypeCollection

Constant Summary collapse

Reference =

This stub class is only needed for serialization compatibility with 0.25.x. Specifically, it exists to provide a compatibility API when using YAML serialized objects loaded from StoreConfigs.

Puppet::Resource
ATTRIBUTES =
[:file, :line, :exported]
YAML_ATTRIBUTES =
[:@file, :@line, :@exported, :@type, :@title, :@tags, :@parameters]

Constants included from Indirector

Indirector::BadNameRegexp

Constants included from Util::Tagging

Util::Tagging::ValidTagRegex

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::Pson

pson_create

Methods included from Indirector

configure_routes, indirects

Methods included from Util::Tagging

#raw_tagged?, #tag, #tagged?, #tags, #tags=

Constructor Details

#initialize(type, title = nil, attributes = {}) ⇒ Resource

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 Node::Environment#known_resource_types in order to resolve `String` and `Symbol` Types to actual Ruby classes.

Parameters:

  • type (Symbol, String)

    The name of the Puppet Type, as a string or symbol. The actual Type will be looked up using Node::Environment#known_resource_types. This lookup is expensive.

  • type (String)

    The full resource name in the form of ‘“Type”`. This method of calling should only be used when `title` is `nil`.

  • type (nil)

    If a ‘nil` is passed, the title argument must be a string of the form `“Type”`.

  • type (Class)

    A class that inherits from ‘Puppet::Type`. This method of construction is much more efficient as it skips calls to Node::Environment#known_resource_types.

  • title (String, :main, nil) (defaults to: nil)

    The title of the resource. If type is ‘nil`, may also be the full resource name in the form of `“Type”`.



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/puppet/resource.rb', line 212

def initialize(type, title = nil, attributes = {})
  @parameters = {}
  environment = attributes[:environment]
  if type.is_a?(Class) && type < Puppet::Type
    # Set the resource type to avoid an expensive `known_resource_types`
    # lookup.
    self.resource_type = type
    # From this point on, the constructor behaves the same as if `type` had
    # been passed as a symbol.
    type = type.name
  end

  # 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

  if resource_type && resource_type.respond_to?(:deprecate_params)
      resource_type.deprecate_params(title, attributes[:parameters])
  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

Instance Attribute Details

#catalogObject



20
21
22
# File 'lib/puppet/resource.rb', line 20

def catalog
  @catalog
end

#exportedObject



20
21
22
# File 'lib/puppet/resource.rb', line 20

def exported
  @exported
end

#fileObject



20
21
22
# File 'lib/puppet/resource.rb', line 20

def file
  @file
end

#lineObject



20
21
22
# File 'lib/puppet/resource.rb', line 20

def line
  @line
end

#strictObject



20
21
22
# File 'lib/puppet/resource.rb', line 20

def strict
  @strict
end

#titleObject (readonly)



21
22
23
# File 'lib/puppet/resource.rb', line 21

def title
  @title
end

#typeObject (readonly)



21
22
23
# File 'lib/puppet/resource.rb', line 21

def type
  @type
end

#validate_parametersObject



20
21
22
# File 'lib/puppet/resource.rb', line 20

def validate_parameters
  @validate_parameters
end

#virtualObject



20
21
22
# File 'lib/puppet/resource.rb', line 20

def virtual
  @virtual
end

Class Method Details

.from_data_hash(data) ⇒ Object

Raises:

  • (ArgumentError)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/puppet/resource.rb', line 29

def self.from_data_hash(data)
  raise ArgumentError, "No resource type provided in serialized data" unless type = data['type']
  raise ArgumentError, "No resource title provided in serialized data" unless title = data['title']

  resource = new(type, title)

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

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

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

  resource
end

.from_pson(pson) ⇒ Object



52
53
54
55
# File 'lib/puppet/resource.rb', line 52

def self.from_pson(pson)
  Puppet.deprecation_warning("from_pson is being removed in favour of from_data_hash.")
  self.from_data_hash(pson)
end

.value_to_pson_data(value) ⇒ Object



90
91
92
93
94
95
96
97
98
# File 'lib/puppet/resource.rb', line 90

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

Instance Method Details

#==(other) ⇒ Object



149
150
151
152
153
154
# File 'lib/puppet/resource.rb', line 149

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) ⇒ Object

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



145
146
147
# File 'lib/puppet/resource.rb', line 145

def [](param)
  parameters[parameter_name(param)]
end

#[]=(param, value) ⇒ Object

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



138
139
140
141
# File 'lib/puppet/resource.rb', line 138

def []=(param, value)
  validate_parameter(param) if validate_parameters
  parameters[parameter_name(param)] = value
end

#builtin?Boolean

Compatibility method.

Returns:

  • (Boolean)


157
158
159
# File 'lib/puppet/resource.rb', line 157

def builtin?
  builtin_type?
end

#builtin_type?Boolean

Is this a builtin resource type?

Returns:

  • (Boolean)


162
163
164
# File 'lib/puppet/resource.rb', line 162

def builtin_type?
  resource_type.is_a?(Class)
end

#class?Boolean

Returns:

  • (Boolean)


181
182
183
# File 'lib/puppet/resource.rb', line 181

def class?
  @is_class ||= @type == "Class"
end

#copy_as_resourceObject



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
# File 'lib/puppet/resource.rb', line 422

def copy_as_resource
  result = Puppet::Resource.new(type, title)

  result.file = self.file
  result.line = self.line
  result.exported = self.exported
  result.virtual = self.virtual
  result.tag(*self.tags)
  result.environment = environment
  result.instance_variable_set(:@rstype, resource_type)

  to_hash.each do |p, v|
    if v.is_a?(Puppet::Resource)
      v = Puppet::Resource.new(v.type, v.title)
    elsif v.is_a?(Array)
      # flatten resource references arrays
      v = v.flatten if v.flatten.find { |av| av.is_a?(Puppet::Resource) }
      v = v.collect do |av|
        av = Puppet::Resource.new(av.type, av.title) if av.is_a?(Puppet::Resource)
        av
      end
    end

    if !Puppet.future_parser?
      # If the value is an array with only one value, then
      # convert it to a single value.  This is largely so that
      # the database interaction doesn't have to worry about
      # whether it returns an array or a string.
      #
      # This behavior is not done in the future parser, but we can't issue a
      # deprecation warning either since there isn't anything that a user can
      # do about it.
      result[p] = if v.is_a?(Array) and v.length == 1
                    v[0]
                  else
                    v
                  end
    else
      result[p] = v
    end
  end

  result
end

#eachObject

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



167
168
169
# File 'lib/puppet/resource.rb', line 167

def each
  parameters.each { |p,v| yield p, v }
end

#environmentObject



288
289
290
291
292
293
294
# File 'lib/puppet/resource.rb', line 288

def environment
  @environment ||= if catalog
                     catalog.environment_instance
                   else
                     Puppet.lookup(:current_environment) { Puppet::Node::Environment::NONE }
                   end
end

#environment=(environment) ⇒ Object



296
297
298
# File 'lib/puppet/resource.rb', line 296

def environment=(environment)
  @environment = environment
end

#include?(parameter) ⇒ Boolean

Returns:

  • (Boolean)


171
172
173
# File 'lib/puppet/resource.rb', line 171

def include?(parameter)
  super || parameters.keys.include?( parameter_name(parameter) )
end

#inspectObject



57
58
59
# File 'lib/puppet/resource.rb', line 57

def inspect
  "#{@type}[#{@title}]#{to_hash.inspect}"
end

#key_attributesObject



317
318
319
# File 'lib/puppet/resource.rb', line 317

def key_attributes
  resource_type.respond_to?(:key_attributes) ? resource_type.key_attributes : [:name]
end

#nameObject



352
353
354
355
356
357
# File 'lib/puppet/resource.rb', line 352

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 = {}) ⇒ Object



503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
# File 'lib/puppet/resource.rb', line 503

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

#refObject



260
261
262
# File 'lib/puppet/resource.rb', line 260

def ref
  to_s
end

#resolveObject

Find our resource.



265
266
267
# File 'lib/puppet/resource.rb', line 265

def resolve
  catalog ? catalog.resource(to_s) : nil
end

#resource_typePuppet::Type, Puppet::Resource::Type

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The resource’s type implementation



272
273
274
275
276
277
278
279
# File 'lib/puppet/resource.rb', line 272

def resource_type
  @rstype ||= case type
  when "Class"; environment.known_resource_types.hostclass(title == :main ? "" : title)
  when "Node"; environment.known_resource_types.node(title)
  else
    Puppet::Type.type(type) || environment.known_resource_types.definition(type)
  end
end

#resource_type=(type) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set the resource’s type implementation

Parameters:



284
285
286
# File 'lib/puppet/resource.rb', line 284

def resource_type=(type)
  @rstype = type
end

#set_default_parameters(scope) ⇒ Object



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'lib/puppet/resource.rb', line 399

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?Boolean

Returns:

  • (Boolean)


185
186
187
# File 'lib/puppet/resource.rb', line 185

def stage?
  @is_stage ||= @type.to_s.downcase == "stage"
end

#to_data_hashObject



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/puppet/resource.rb', line 61

def to_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_hashObject

Produce a simple hash of our parameters.



301
302
303
# File 'lib/puppet/resource.rb', line 301

def to_hash
  parse_title.merge parameters
end

#to_manifestObject

Convert our resource to Puppet code.



322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/puppet/resource.rb', line 322

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) ⇒ Object



124
125
126
# File 'lib/puppet/resource.rb', line 124

def to_pson(*args)
  to_data_hash.to_pson(*args)
end

#to_pson_data_hashObject

This doesn’t include document type as it is part of a catalog



86
87
88
# File 'lib/puppet/resource.rb', line 86

def to_pson_data_hash
  to_data_hash
end

#to_ralObject

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



347
348
349
350
# File 'lib/puppet/resource.rb', line 347

def to_ral
  typeklass = Puppet::Type.type(self.type) || Puppet::Type.type(:component)
  typeklass.new(self)
end

#to_refObject



341
342
343
# File 'lib/puppet/resource.rb', line 341

def to_ref
  ref
end

#to_sObject



305
306
307
# File 'lib/puppet/resource.rb', line 305

def to_s
  "#{type}[#{title}]"
end

#to_yaml_propertiesArray<Symbol>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Explicitly list the instance variables that should be serialized when converting to YAML.

Returns:

  • (Array<Symbol>)

    The intersection of our explicit variable list and all of the instance variables defined on this class.



120
121
122
# File 'lib/puppet/resource.rb', line 120

def to_yaml_properties
  YAML_ATTRIBUTES & super
end

#uniqueness_keyObject



309
310
311
312
313
314
315
# File 'lib/puppet/resource.rb', line 309

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) ⇒ Boolean

Returns:

  • (Boolean)


467
468
469
# File 'lib/puppet/resource.rb', line 467

def valid_parameter?(name)
  resource_type.valid_parameter?(name)
end

#validate_completeObject

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.



475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'lib/puppet/resource.rb', line 475

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

  # Perform optional type checking
  if Puppet.future_parser?
    # Perform type checking
    arg_types = resource_type.argument_types
    # Parameters is a map from name, to parameter, and the parameter again has name and value
    parameters.each do |name, value|
      next unless t = arg_types[name.to_s]  # untyped, and parameters are symbols here (aargh, strings in the type)
      unless Puppet::Pops::Types::TypeCalculator.instance?(t, value.value)
        inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(value.value)
        actual = Puppet::Pops::Types::TypeCalculator.generalize!(inferred_type)
        fail Puppet::ParseError, "Expected parameter '#{name}' of '#{self}' to have type #{t.to_s}, got #{actual.to_s}"
      end
    end
  end
end

#validate_parameter(name) ⇒ Object

Raises:

  • (ArgumentError)


499
500
501
# File 'lib/puppet/resource.rb', line 499

def validate_parameter(name)
  raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name)
end

#yaml_property_munge(x) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/puppet/resource.rb', line 100

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