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
# File 'lib/puppet/resource.rb', line 212

def initialize(type, title = nil, attributes = {})
  @parameters = {}
  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



421
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
# File 'lib/puppet/resource.rb', line 421

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[:parser] == 'current'
      # 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



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

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

#environment=(environment) ⇒ Object



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

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



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

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

#nameObject



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

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



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

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



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

def ref
  to_s
end

#resolveObject

Find our resource.



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

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



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

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:



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

def resource_type=(type)
  @rstype = type
end

#set_default_parameters(scope) ⇒ Object



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

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.



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

def to_hash
  parse_title.merge parameters
end

#to_manifestObject

Convert our resource to Puppet code.



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

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.



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

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

#to_refObject



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

def to_ref
  ref
end

#to_sObject



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

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



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

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)


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

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.



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

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[:parser] == 'future'
    # 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(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)


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

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