Class: Puppet::Resource

Inherits:
Object show all
Extended by:
Indirector
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: Catalog, Ral, Status, StoreConfigs, Type, TypeCollection

Constant Summary collapse

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 Indirector

configure_routes, indirects

Methods included from Util::Tagging

#merge_into, #merge_tags, #raw_tagged?, #set_tags, #tag, #tag_if_valid, #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”`.



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
259
260
261
262
263
264
265
266
# File 'lib/puppet/resource.rb', line 192

def initialize(type, title = nil, attributes = {})
  @parameters = {}
  if type.is_a?(Puppet::Resource)
    # Copy constructor. Let's avoid munging, extracting, tagging, etc
    src = type
    self.file = src.file
    self.line = src.line
    self.exported = src.exported
    self.virtual = src.virtual
    self.set_tags(src)
    self.environment = src.environment
    @rstype = src.resource_type
    @type = src.type
    @title = src.title

    src.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

      self[p] = v
    end
  else
    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_if_valid(self.title)
  end

  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



14
15
16
# File 'lib/puppet/resource.rb', line 14

def catalog
  @catalog
end

#exportedObject



14
15
16
# File 'lib/puppet/resource.rb', line 14

def exported
  @exported
end

#fileObject



14
15
16
# File 'lib/puppet/resource.rb', line 14

def file
  @file
end

#lineObject



14
15
16
# File 'lib/puppet/resource.rb', line 14

def line
  @line
end

#strictObject



14
15
16
# File 'lib/puppet/resource.rb', line 14

def strict
  @strict
end

#titleObject (readonly)



15
16
17
# File 'lib/puppet/resource.rb', line 15

def title
  @title
end

#typeObject (readonly)



15
16
17
# File 'lib/puppet/resource.rb', line 15

def type
  @type
end

#validate_parametersObject



14
15
16
# File 'lib/puppet/resource.rb', line 14

def validate_parameters
  @validate_parameters
end

#virtualObject



14
15
16
# File 'lib/puppet/resource.rb', line 14

def virtual
  @virtual
end

Class Method Details

.from_data_hash(data) ⇒ Object

Raises:

  • (ArgumentError)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/puppet/resource.rb', line 23

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

.value_to_pson_data(value) ⇒ Object



74
75
76
77
78
79
80
81
82
# File 'lib/puppet/resource.rb', line 74

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



129
130
131
132
133
134
# File 'lib/puppet/resource.rb', line 129

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.



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

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

#[]=(param, value) ⇒ Object

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



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

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

#builtin?Boolean

Compatibility method.

Returns:

  • (Boolean)


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

def builtin?
  builtin_type?
end

#builtin_type?Boolean

Is this a builtin resource type?

Returns:

  • (Boolean)


142
143
144
# File 'lib/puppet/resource.rb', line 142

def builtin_type?
  resource_type.is_a?(Class)
end

#class?Boolean

Returns:

  • (Boolean)


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

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

#copy_as_resourceObject



486
487
488
# File 'lib/puppet/resource.rb', line 486

def copy_as_resource
  Puppet::Resource.new(self)
end

#eachObject

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



147
148
149
# File 'lib/puppet/resource.rb', line 147

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

#environmentObject



296
297
298
299
300
301
302
# File 'lib/puppet/resource.rb', line 296

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

#environment=(environment) ⇒ Object



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

def environment=(environment)
  @environment = environment
end

#include?(parameter) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#inspectObject



46
47
48
# File 'lib/puppet/resource.rb', line 46

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

#key_attributesObject



326
327
328
# File 'lib/puppet/resource.rb', line 326

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

#nameObject



381
382
383
384
385
386
# File 'lib/puppet/resource.rb', line 381

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



523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
# File 'lib/puppet/resource.rb', line 523

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



268
269
270
# File 'lib/puppet/resource.rb', line 268

def ref
  to_s
end

#resolveObject

Find our resource.



273
274
275
# File 'lib/puppet/resource.rb', line 273

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



280
281
282
283
284
285
286
287
# File 'lib/puppet/resource.rb', line 280

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:



292
293
294
# File 'lib/puppet/resource.rb', line 292

def resource_type=(type)
  @rstype = type
end

#search(*search_functions) ⇒ Object



416
417
418
419
# File 'lib/puppet/resource.rb', line 416

def search(*search_functions)
  search_functions.each {|f| x = f.call(); return x unless x.nil? }
  nil
end

#set_default_parameters(scope) ⇒ Object



463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# File 'lib/puppet/resource.rb', line 463

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)


165
166
167
# File 'lib/puppet/resource.rb', line 165

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

#to_data_hashObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/puppet/resource.rb', line 50

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.



309
310
311
# File 'lib/puppet/resource.rb', line 309

def to_hash
  parse_title.merge parameters
end

#to_hierayamlObject

Convert our resource to yaml for Hiera purposes.



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/puppet/resource.rb', line 331

def to_hierayaml
  # 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:\n%s" % [self.title, attributes]
end

#to_manifestObject

Convert our resource to Puppet code.



351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'lib/puppet/resource.rb', line 351

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_ralObject

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



376
377
378
379
# File 'lib/puppet/resource.rb', line 376

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

#to_refObject



370
371
372
# File 'lib/puppet/resource.rb', line 370

def to_ref
  ref
end

#to_sObject



313
314
315
# File 'lib/puppet/resource.rb', line 313

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.



104
105
106
# File 'lib/puppet/resource.rb', line 104

def to_yaml_properties
  YAML_ATTRIBUTES & super
end

#uniqueness_keyObject



317
318
319
320
321
322
323
324
# File 'lib/puppet/resource.rb', line 317

def uniqueness_key
  # Temporary kludge to deal with inconsistent use patterns; ensure we don't return nil for namevar/:name
  h = self.to_hash
  name = h[namevar] || h[:name] || self.name
  h[namevar] ||= name
  h[:name]   ||= name
  h.values_at(*key_attributes.sort_by { |k| k.to_s })
end

#valid_parameter?(name) ⇒ Boolean

Returns:

  • (Boolean)


490
491
492
# File 'lib/puppet/resource.rb', line 490

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.



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

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

#validate_parameter(name) ⇒ Object

Raises:

  • (ArgumentError)


519
520
521
# File 'lib/puppet/resource.rb', line 519

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

#yaml_property_munge(x) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/puppet/resource.rb', line 84

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