~lynxman/ubuntu/precise/puppet/puppetlabsfixbug12844

« back to all changes in this revision

Viewing changes to .pc/debian-changes-2.6.1-0ubuntu1/lib/puppet/type.rb

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2010-09-21 13:53:10 UTC
  • Revision ID: james.westby@ubuntu.com-20100921135310-y942hx46cq2lo375
Tags: 2.6.1-0ubuntu2
debian/puppetmaster-passenger.postinst: Use cacrl instead of hostcrl to
set the location of the CRL in apache2 configuration. Fix apache2 
configuration on upgrade as well (LP: #641001).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
require 'puppet'
2
 
require 'puppet/util/log'
3
 
require 'puppet/util/metric'
4
 
require 'puppet/property'
5
 
require 'puppet/parameter'
6
 
require 'puppet/util'
7
 
require 'puppet/util/autoload'
8
 
require 'puppet/metatype/manager'
9
 
require 'puppet/util/errors'
10
 
require 'puppet/util/log_paths'
11
 
require 'puppet/util/logging'
12
 
require 'puppet/util/cacher'
13
 
require 'puppet/file_collection/lookup'
14
 
require 'puppet/util/tagging'
15
 
 
16
 
# see the bottom of the file for the rest of the inclusions
17
 
 
18
 
module Puppet
19
 
class Type
20
 
  include Puppet::Util
21
 
  include Puppet::Util::Errors
22
 
  include Puppet::Util::LogPaths
23
 
  include Puppet::Util::Logging
24
 
  include Puppet::Util::Cacher
25
 
  include Puppet::FileCollection::Lookup
26
 
  include Puppet::Util::Tagging
27
 
 
28
 
  ###############################
29
 
  # Code related to resource type attributes.
30
 
  class << self
31
 
    include Puppet::Util::ClassGen
32
 
    include Puppet::Util::Warnings
33
 
    attr_reader :properties
34
 
  end
35
 
 
36
 
  def self.states
37
 
    warnonce "The states method is deprecated; use properties"
38
 
    properties
39
 
  end
40
 
 
41
 
  # All parameters, in the appropriate order.  The key_attributes come first, then
42
 
  # the provider, then the properties, and finally the params and metaparams
43
 
  # in the order they were specified in the files.
44
 
  def self.allattrs
45
 
    key_attributes | (parameters & [:provider]) | properties.collect { |property| property.name } | parameters | metaparams
46
 
  end
47
 
 
48
 
  # Retrieve an attribute alias, if there is one.
49
 
  def self.attr_alias(param)
50
 
    @attr_aliases[symbolize(param)]
51
 
  end
52
 
 
53
 
  # Create an alias to an existing attribute.  This will cause the aliased
54
 
  # attribute to be valid when setting and retrieving values on the instance.
55
 
  def self.set_attr_alias(hash)
56
 
    hash.each do |new, old|
57
 
      @attr_aliases[symbolize(new)] = symbolize(old)
58
 
    end
59
 
  end
60
 
 
61
 
  # Find the class associated with any given attribute.
62
 
  def self.attrclass(name)
63
 
    @attrclasses ||= {}
64
 
 
65
 
    # We cache the value, since this method gets called such a huge number
66
 
    # of times (as in, hundreds of thousands in a given run).
67
 
    unless @attrclasses.include?(name)
68
 
      @attrclasses[name] = case self.attrtype(name)
69
 
      when :property; @validproperties[name]
70
 
      when :meta; @@metaparamhash[name]
71
 
      when :param; @paramhash[name]
72
 
      end
73
 
    end
74
 
    @attrclasses[name]
75
 
  end
76
 
 
77
 
  # What type of parameter are we dealing with? Cache the results, because
78
 
  # this method gets called so many times.
79
 
  def self.attrtype(attr)
80
 
    @attrtypes ||= {}
81
 
    unless @attrtypes.include?(attr)
82
 
      @attrtypes[attr] = case
83
 
        when @validproperties.include?(attr); :property
84
 
        when @paramhash.include?(attr); :param
85
 
        when @@metaparamhash.include?(attr); :meta
86
 
        end
87
 
    end
88
 
 
89
 
    @attrtypes[attr]
90
 
  end
91
 
 
92
 
  def self.eachmetaparam
93
 
    @@metaparams.each { |p| yield p.name }
94
 
  end
95
 
 
96
 
  # Create the 'ensure' class.  This is a separate method so other types
97
 
  # can easily call it and create their own 'ensure' values.
98
 
  def self.ensurable(&block)
99
 
    if block_given?
100
 
      self.newproperty(:ensure, :parent => Puppet::Property::Ensure, &block)
101
 
    else
102
 
      self.newproperty(:ensure, :parent => Puppet::Property::Ensure) do
103
 
        self.defaultvalues
104
 
      end
105
 
    end
106
 
  end
107
 
 
108
 
  # Should we add the 'ensure' property to this class?
109
 
  def self.ensurable?
110
 
    # If the class has all three of these methods defined, then it's
111
 
    # ensurable.
112
 
    ens = [:exists?, :create, :destroy].inject { |set, method|
113
 
      set &&= self.public_method_defined?(method)
114
 
    }
115
 
 
116
 
    ens
117
 
  end
118
 
 
119
 
  # Deal with any options passed into parameters.
120
 
  def self.handle_param_options(name, options)
121
 
    # If it's a boolean parameter, create a method to test the value easily
122
 
    if options[:boolean]
123
 
      define_method(name.to_s + "?") do
124
 
        val = self[name]
125
 
        if val == :true or val == true
126
 
          return true
127
 
        end
128
 
      end
129
 
    end
130
 
  end
131
 
 
132
 
  # Is the parameter in question a meta-parameter?
133
 
  def self.metaparam?(param)
134
 
    @@metaparamhash.include?(symbolize(param))
135
 
  end
136
 
 
137
 
  # Find the metaparameter class associated with a given metaparameter name.
138
 
  def self.metaparamclass(name)
139
 
    @@metaparamhash[symbolize(name)]
140
 
  end
141
 
 
142
 
  def self.metaparams
143
 
    @@metaparams.collect { |param| param.name }
144
 
  end
145
 
 
146
 
  def self.metaparamdoc(metaparam)
147
 
    @@metaparamhash[metaparam].doc
148
 
  end
149
 
 
150
 
  # Create a new metaparam.  Requires a block and a name, stores it in the
151
 
  # @parameters array, and does some basic checking on it.
152
 
  def self.newmetaparam(name, options = {}, &block)
153
 
    @@metaparams ||= []
154
 
    @@metaparamhash ||= {}
155
 
    name = symbolize(name)
156
 
 
157
 
 
158
 
      param = genclass(
159
 
        name,
160
 
      :parent => options[:parent] || Puppet::Parameter,
161
 
      :prefix => "MetaParam",
162
 
      :hash => @@metaparamhash,
163
 
      :array => @@metaparams,
164
 
      :attributes => options[:attributes],
165
 
 
166
 
      &block
167
 
    )
168
 
 
169
 
    # Grr.
170
 
    param.required_features = options[:required_features] if options[:required_features]
171
 
 
172
 
    handle_param_options(name, options)
173
 
 
174
 
    param.metaparam = true
175
 
 
176
 
    param
177
 
  end
178
 
 
179
 
  def self.key_attribute_parameters
180
 
    @key_attribute_parameters ||= (
181
 
      params = @parameters.find_all { |param|
182
 
        param.isnamevar? or param.name == :name
183
 
      }
184
 
    )
185
 
  end
186
 
 
187
 
  def self.key_attributes
188
 
    key_attribute_parameters.collect { |p| p.name }
189
 
  end
190
 
 
191
 
  def self.title_patterns
192
 
    case key_attributes.length
193
 
    when 0; []
194
 
    when 1;
195
 
      identity = lambda {|x| x}
196
 
      [ [ /(.*)/m, [ [key_attributes.first, identity ] ] ] ]
197
 
    else
198
 
      raise Puppet::DevError,"you must specify title patterns when there are two or more key attributes"
199
 
    end
200
 
  end
201
 
 
202
 
  def uniqueness_key
203
 
    to_resource.uniqueness_key
204
 
  end
205
 
 
206
 
  # Create a new parameter.  Requires a block and a name, stores it in the
207
 
  # @parameters array, and does some basic checking on it.
208
 
  def self.newparam(name, options = {}, &block)
209
 
    options[:attributes] ||= {}
210
 
 
211
 
      param = genclass(
212
 
        name,
213
 
      :parent => options[:parent] || Puppet::Parameter,
214
 
      :attributes => options[:attributes],
215
 
      :block => block,
216
 
      :prefix => "Parameter",
217
 
      :array => @parameters,
218
 
 
219
 
      :hash => @paramhash
220
 
    )
221
 
 
222
 
    handle_param_options(name, options)
223
 
 
224
 
    # Grr.
225
 
    param.required_features = options[:required_features] if options[:required_features]
226
 
 
227
 
    param.isnamevar if options[:namevar]
228
 
 
229
 
    param
230
 
  end
231
 
 
232
 
  def self.newstate(name, options = {}, &block)
233
 
    Puppet.warning "newstate() has been deprecrated; use newproperty(#{name})"
234
 
    newproperty(name, options, &block)
235
 
  end
236
 
 
237
 
  # Create a new property. The first parameter must be the name of the property;
238
 
  # this is how users will refer to the property when creating new instances.
239
 
  # The second parameter is a hash of options; the options are:
240
 
  # * <tt>:parent</tt>: The parent class for the property.  Defaults to Puppet::Property.
241
 
  # * <tt>:retrieve</tt>: The method to call on the provider or @parent object (if
242
 
  #   the provider is not set) to retrieve the current value.
243
 
  def self.newproperty(name, options = {}, &block)
244
 
    name = symbolize(name)
245
 
 
246
 
    # This is here for types that might still have the old method of defining
247
 
    # a parent class.
248
 
    unless options.is_a? Hash
249
 
      raise Puppet::DevError,
250
 
        "Options must be a hash, not #{options.inspect}"
251
 
    end
252
 
 
253
 
    raise Puppet::DevError, "Class #{self.name} already has a property named #{name}" if @validproperties.include?(name)
254
 
 
255
 
    if parent = options[:parent]
256
 
      options.delete(:parent)
257
 
    else
258
 
      parent = Puppet::Property
259
 
    end
260
 
 
261
 
    # We have to create our own, new block here because we want to define
262
 
    # an initial :retrieve method, if told to, and then eval the passed
263
 
    # block if available.
264
 
    prop = genclass(name, :parent => parent, :hash => @validproperties, :attributes => options) do
265
 
      # If they've passed a retrieve method, then override the retrieve
266
 
      # method on the class.
267
 
      if options[:retrieve]
268
 
        define_method(:retrieve) do
269
 
          provider.send(options[:retrieve])
270
 
        end
271
 
      end
272
 
 
273
 
      class_eval(&block) if block
274
 
    end
275
 
 
276
 
    # If it's the 'ensure' property, always put it first.
277
 
    if name == :ensure
278
 
      @properties.unshift prop
279
 
    else
280
 
      @properties << prop
281
 
    end
282
 
 
283
 
    prop
284
 
  end
285
 
 
286
 
  def self.paramdoc(param)
287
 
    @paramhash[param].doc
288
 
  end
289
 
 
290
 
  # Return the parameter names
291
 
  def self.parameters
292
 
    return [] unless defined?(@parameters)
293
 
    @parameters.collect { |klass| klass.name }
294
 
  end
295
 
 
296
 
  # Find the parameter class associated with a given parameter name.
297
 
  def self.paramclass(name)
298
 
    @paramhash[name]
299
 
  end
300
 
 
301
 
  # Return the property class associated with a name
302
 
  def self.propertybyname(name)
303
 
    @validproperties[name]
304
 
  end
305
 
 
306
 
  def self.validattr?(name)
307
 
    name = symbolize(name)
308
 
    return true if name == :name
309
 
    @validattrs ||= {}
310
 
 
311
 
    unless @validattrs.include?(name)
312
 
      @validattrs[name] = !!(self.validproperty?(name) or self.validparameter?(name) or self.metaparam?(name))
313
 
    end
314
 
 
315
 
    @validattrs[name]
316
 
  end
317
 
 
318
 
  # does the name reflect a valid property?
319
 
  def self.validproperty?(name)
320
 
    name = symbolize(name)
321
 
    @validproperties.include?(name) && @validproperties[name]
322
 
  end
323
 
 
324
 
  # Return the list of validproperties
325
 
  def self.validproperties
326
 
    return {} unless defined?(@parameters)
327
 
 
328
 
    @validproperties.keys
329
 
  end
330
 
 
331
 
  # does the name reflect a valid parameter?
332
 
  def self.validparameter?(name)
333
 
    raise Puppet::DevError, "Class #{self} has not defined parameters" unless defined?(@parameters)
334
 
    !!(@paramhash.include?(name) or @@metaparamhash.include?(name))
335
 
  end
336
 
 
337
 
  # This is a forward-compatibility method - it's the validity interface we'll use in Puppet::Resource.
338
 
  def self.valid_parameter?(name)
339
 
    validattr?(name)
340
 
  end
341
 
 
342
 
  # Return either the attribute alias or the attribute.
343
 
  def attr_alias(name)
344
 
    name = symbolize(name)
345
 
    if synonym = self.class.attr_alias(name)
346
 
      return synonym
347
 
    else
348
 
      return name
349
 
    end
350
 
  end
351
 
 
352
 
  # Are we deleting this resource?
353
 
  def deleting?
354
 
    obj = @parameters[:ensure] and obj.should == :absent
355
 
  end
356
 
 
357
 
  # Create a new property if it is valid but doesn't exist
358
 
  # Returns: true if a new parameter was added, false otherwise
359
 
  def add_property_parameter(prop_name)
360
 
    if self.class.validproperty?(prop_name) && !@parameters[prop_name]
361
 
      self.newattr(prop_name)
362
 
      return true
363
 
    end
364
 
    false
365
 
  end
366
 
 
367
 
  #
368
 
  # The name_var is the key_attribute in the case that there is only one.
369
 
  #
370
 
  def name_var
371
 
    key_attributes = self.class.key_attributes
372
 
    (key_attributes.length == 1) && key_attributes.first
373
 
  end
374
 
 
375
 
  # abstract accessing parameters and properties, and normalize
376
 
  # access to always be symbols, not strings
377
 
  # This returns a value, not an object.  It returns the 'is'
378
 
  # value, but you can also specifically return 'is' and 'should'
379
 
  # values using 'object.is(:property)' or 'object.should(:property)'.
380
 
  def [](name)
381
 
    name = attr_alias(name)
382
 
 
383
 
    fail("Invalid parameter #{name}(#{name.inspect})") unless self.class.validattr?(name)
384
 
 
385
 
    if name == :name
386
 
      name = name_var
387
 
    end
388
 
 
389
 
    if obj = @parameters[name]
390
 
      # Note that if this is a property, then the value is the "should" value,
391
 
      # not the current value.
392
 
      obj.value
393
 
    else
394
 
      return nil
395
 
    end
396
 
  end
397
 
 
398
 
  # Abstract setting parameters and properties, and normalize
399
 
  # access to always be symbols, not strings.  This sets the 'should'
400
 
  # value on properties, and otherwise just sets the appropriate parameter.
401
 
  def []=(name,value)
402
 
    name = attr_alias(name)
403
 
 
404
 
    fail("Invalid parameter #{name}") unless self.class.validattr?(name)
405
 
 
406
 
    if name == :name
407
 
      name = name_var
408
 
    end
409
 
    raise Puppet::Error.new("Got nil value for #{name}") if value.nil?
410
 
 
411
 
    property = self.newattr(name)
412
 
 
413
 
    begin
414
 
      # make sure the parameter doesn't have any errors
415
 
      property.value = value
416
 
    rescue => detail
417
 
      error = Puppet::Error.new("Parameter #{name} failed: #{detail}")
418
 
      error.set_backtrace(detail.backtrace)
419
 
      raise error
420
 
    end
421
 
 
422
 
    nil
423
 
  end
424
 
 
425
 
  # remove a property from the object; useful in testing or in cleanup
426
 
  # when an error has been encountered
427
 
  def delete(attr)
428
 
    attr = symbolize(attr)
429
 
    if @parameters.has_key?(attr)
430
 
      @parameters.delete(attr)
431
 
    else
432
 
      raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
433
 
    end
434
 
  end
435
 
 
436
 
  # iterate across the existing properties
437
 
  def eachproperty
438
 
    # properties is a private method
439
 
    properties.each { |property|
440
 
      yield property
441
 
    }
442
 
  end
443
 
 
444
 
  # Create a transaction event.  Called by Transaction or by
445
 
  # a property.
446
 
  def event(options = {})
447
 
    Puppet::Transaction::Event.new({:resource => self, :file => file, :line => line, :tags => tags, :version => version}.merge(options))
448
 
  end
449
 
 
450
 
  # Let the catalog determine whether a given cached value is
451
 
  # still valid or has expired.
452
 
  def expirer
453
 
    catalog
454
 
  end
455
 
 
456
 
  # retrieve the 'should' value for a specified property
457
 
  def should(name)
458
 
    name = attr_alias(name)
459
 
    (prop = @parameters[name] and prop.is_a?(Puppet::Property)) ? prop.should : nil
460
 
  end
461
 
 
462
 
  # Create the actual attribute instance.  Requires either the attribute
463
 
  # name or class as the first argument, then an optional hash of
464
 
  # attributes to set during initialization.
465
 
  def newattr(name)
466
 
    if name.is_a?(Class)
467
 
      klass = name
468
 
      name = klass.name
469
 
    end
470
 
 
471
 
    unless klass = self.class.attrclass(name)
472
 
      raise Puppet::Error, "Resource type #{self.class.name} does not support parameter #{name}"
473
 
    end
474
 
 
475
 
    return @parameters[name] if @parameters.include?(name)
476
 
 
477
 
    @parameters[name] = klass.new(:resource => self)
478
 
  end
479
 
 
480
 
  # return the value of a parameter
481
 
  def parameter(name)
482
 
    @parameters[name.to_sym]
483
 
  end
484
 
 
485
 
  def parameters
486
 
    @parameters.dup
487
 
  end
488
 
 
489
 
  # Is the named property defined?
490
 
  def propertydefined?(name)
491
 
    name = name.intern unless name.is_a? Symbol
492
 
    @parameters.include?(name)
493
 
  end
494
 
 
495
 
  # Return an actual property instance by name; to return the value, use 'resource[param]'
496
 
  # LAK:NOTE(20081028) Since the 'parameter' method is now a superset of this method,
497
 
  # this one should probably go away at some point.
498
 
  def property(name)
499
 
    (obj = @parameters[symbolize(name)] and obj.is_a?(Puppet::Property)) ? obj : nil
500
 
  end
501
 
 
502
 
  # For any parameters or properties that have defaults and have not yet been
503
 
  # set, set them now.  This method can be handed a list of attributes,
504
 
  # and if so it will only set defaults for those attributes.
505
 
  def set_default(attr)
506
 
    return unless klass = self.class.attrclass(attr)
507
 
    return unless klass.method_defined?(:default)
508
 
    return if @parameters.include?(klass.name)
509
 
 
510
 
    return unless parameter = newattr(klass.name)
511
 
 
512
 
    if value = parameter.default and ! value.nil?
513
 
      parameter.value = value
514
 
    else
515
 
      @parameters.delete(parameter.name)
516
 
    end
517
 
  end
518
 
 
519
 
  # Convert our object to a hash.  This just includes properties.
520
 
  def to_hash
521
 
    rethash = {}
522
 
 
523
 
    @parameters.each do |name, obj|
524
 
      rethash[name] = obj.value
525
 
    end
526
 
 
527
 
    rethash
528
 
  end
529
 
 
530
 
  def type
531
 
    self.class.name
532
 
  end
533
 
 
534
 
  # Return a specific value for an attribute.
535
 
  def value(name)
536
 
    name = attr_alias(name)
537
 
 
538
 
    (obj = @parameters[name] and obj.respond_to?(:value)) ? obj.value : nil
539
 
  end
540
 
 
541
 
  def version
542
 
    return 0 unless catalog
543
 
    catalog.version
544
 
  end
545
 
 
546
 
  # Return all of the property objects, in the order specified in the
547
 
  # class.
548
 
  def properties
549
 
    self.class.properties.collect { |prop| @parameters[prop.name] }.compact
550
 
  end
551
 
 
552
 
  # Is this type's name isomorphic with the object?  That is, if the
553
 
  # name conflicts, does it necessarily mean that the objects conflict?
554
 
  # Defaults to true.
555
 
  def self.isomorphic?
556
 
    if defined?(@isomorphic)
557
 
      return @isomorphic
558
 
    else
559
 
      return true
560
 
    end
561
 
  end
562
 
 
563
 
  def isomorphic?
564
 
    self.class.isomorphic?
565
 
  end
566
 
 
567
 
  # is the instance a managed instance?  A 'yes' here means that
568
 
  # the instance was created from the language, vs. being created
569
 
  # in order resolve other questions, such as finding a package
570
 
  # in a list
571
 
  def managed?
572
 
    # Once an object is managed, it always stays managed; but an object
573
 
    # that is listed as unmanaged might become managed later in the process,
574
 
    # so we have to check that every time
575
 
    if @managed
576
 
      return @managed
577
 
    else
578
 
      @managed = false
579
 
      properties.each { |property|
580
 
        s = property.should
581
 
        if s and ! property.class.unmanaged
582
 
          @managed = true
583
 
          break
584
 
        end
585
 
      }
586
 
      return @managed
587
 
    end
588
 
  end
589
 
 
590
 
  ###############################
591
 
  # Code related to the container behaviour.
592
 
 
593
 
  # this is a retarded hack method to get around the difference between
594
 
  # component children and file children
595
 
  def self.depthfirst?
596
 
    @depthfirst
597
 
  end
598
 
 
599
 
  def depthfirst?
600
 
    self.class.depthfirst?
601
 
  end
602
 
 
603
 
  # Remove an object.  The argument determines whether the object's
604
 
  # subscriptions get eliminated, too.
605
 
  def remove(rmdeps = true)
606
 
    # This is hackish (mmm, cut and paste), but it works for now, and it's
607
 
    # better than warnings.
608
 
    @parameters.each do |name, obj|
609
 
      obj.remove
610
 
    end
611
 
    @parameters.clear
612
 
 
613
 
    @parent = nil
614
 
 
615
 
    # Remove the reference to the provider.
616
 
    if self.provider
617
 
      @provider.clear
618
 
      @provider = nil
619
 
    end
620
 
  end
621
 
 
622
 
  ###############################
623
 
  # Code related to evaluating the resources.
624
 
 
625
 
  # Flush the provider, if it supports it.  This is called by the
626
 
  # transaction.
627
 
  def flush
628
 
    self.provider.flush if self.provider and self.provider.respond_to?(:flush)
629
 
  end
630
 
 
631
 
  # if all contained objects are in sync, then we're in sync
632
 
  # FIXME I don't think this is used on the type instances any more,
633
 
  # it's really only used for testing
634
 
  def insync?(is)
635
 
    insync = true
636
 
 
637
 
    if property = @parameters[:ensure]
638
 
      unless is.include? property
639
 
        raise Puppet::DevError,
640
 
          "The is value is not in the is array for '#{property.name}'"
641
 
      end
642
 
      ensureis = is[property]
643
 
      if property.insync?(ensureis) and property.should == :absent
644
 
        return true
645
 
      end
646
 
    end
647
 
 
648
 
    properties.each { |property|
649
 
      unless is.include? property
650
 
        raise Puppet::DevError,
651
 
          "The is value is not in the is array for '#{property.name}'"
652
 
      end
653
 
 
654
 
      propis = is[property]
655
 
      unless property.insync?(propis)
656
 
        property.debug("Not in sync: #{propis.inspect} vs #{property.should.inspect}")
657
 
        insync = false
658
 
      #else
659
 
      #    property.debug("In sync")
660
 
      end
661
 
    }
662
 
 
663
 
    #self.debug("#{self} sync status is #{insync}")
664
 
    insync
665
 
  end
666
 
 
667
 
  # retrieve the current value of all contained properties
668
 
  def retrieve
669
 
    fail "Provider #{provider.class.name} is not functional on this host" if self.provider.is_a?(Puppet::Provider) and ! provider.class.suitable?
670
 
 
671
 
    result = Puppet::Resource.new(type, title)
672
 
 
673
 
    # Provide the name, so we know we'll always refer to a real thing
674
 
    result[:name] = self[:name] unless self[:name] == title
675
 
 
676
 
    if ensure_prop = property(:ensure) or (self.class.validattr?(:ensure) and ensure_prop = newattr(:ensure))
677
 
      result[:ensure] = ensure_state = ensure_prop.retrieve
678
 
    else
679
 
      ensure_state = nil
680
 
    end
681
 
 
682
 
    properties.each do |property|
683
 
      next if property.name == :ensure
684
 
      if ensure_state == :absent
685
 
        result[property] = :absent
686
 
      else
687
 
        result[property] = property.retrieve
688
 
      end
689
 
    end
690
 
 
691
 
    result
692
 
  end
693
 
 
694
 
  def retrieve_resource
695
 
    resource = retrieve
696
 
    resource = Resource.new(type, title, :parameters => resource) if resource.is_a? Hash
697
 
    resource
698
 
  end
699
 
 
700
 
  # Get a hash of the current properties.  Returns a hash with
701
 
  # the actual property instance as the key and the current value
702
 
  # as the, um, value.
703
 
  def currentpropvalues
704
 
    # It's important to use the 'properties' method here, as it follows the order
705
 
    # in which they're defined in the class.  It also guarantees that 'ensure'
706
 
    # is the first property, which is important for skipping 'retrieve' on
707
 
    # all the properties if the resource is absent.
708
 
    ensure_state = false
709
 
    return properties.inject({}) do | prophash, property|
710
 
      if property.name == :ensure
711
 
        ensure_state = property.retrieve
712
 
        prophash[property] = ensure_state
713
 
      else
714
 
        if ensure_state == :absent
715
 
          prophash[property] = :absent
716
 
        else
717
 
          prophash[property] = property.retrieve
718
 
        end
719
 
      end
720
 
      prophash
721
 
    end
722
 
  end
723
 
 
724
 
  # Are we running in noop mode?
725
 
  def noop?
726
 
    # If we're not a host_config, we're almost certainly part of
727
 
    # Settings, and we want to ignore 'noop'
728
 
    return false if catalog and ! catalog.host_config?
729
 
 
730
 
    if defined?(@noop)
731
 
      @noop
732
 
    else
733
 
      Puppet[:noop]
734
 
    end
735
 
  end
736
 
 
737
 
  def noop
738
 
    noop?
739
 
  end
740
 
 
741
 
  ###############################
742
 
  # Code related to managing resource instances.
743
 
  require 'puppet/transportable'
744
 
 
745
 
  # retrieve a named instance of the current type
746
 
  def self.[](name)
747
 
    raise "Global resource access is deprecated"
748
 
    @objects[name] || @aliases[name]
749
 
  end
750
 
 
751
 
  # add an instance by name to the class list of instances
752
 
  def self.[]=(name,object)
753
 
    raise "Global resource storage is deprecated"
754
 
    newobj = nil
755
 
    if object.is_a?(Puppet::Type)
756
 
      newobj = object
757
 
    else
758
 
      raise Puppet::DevError, "must pass a Puppet::Type object"
759
 
    end
760
 
 
761
 
    if exobj = @objects[name] and self.isomorphic?
762
 
      msg = "Object '#{newobj.class.name}[#{name}]' already exists"
763
 
 
764
 
      msg += ("in file #{object.file} at line #{object.line}") if exobj.file and exobj.line
765
 
      msg += ("and cannot be redefined in file #{object.file} at line #{object.line}") if object.file and object.line
766
 
      error = Puppet::Error.new(msg)
767
 
      raise error
768
 
    else
769
 
      #Puppet.info("adding %s of type %s to class list" %
770
 
      #    [name,object.class])
771
 
      @objects[name] = newobj
772
 
    end
773
 
  end
774
 
 
775
 
  # Create an alias.  We keep these in a separate hash so that we don't encounter
776
 
  # the objects multiple times when iterating over them.
777
 
  def self.alias(name, obj)
778
 
    raise "Global resource aliasing is deprecated"
779
 
    if @objects.include?(name)
780
 
      unless @objects[name] == obj
781
 
        raise Puppet::Error.new(
782
 
          "Cannot create alias #{name}: object already exists"
783
 
        )
784
 
      end
785
 
    end
786
 
 
787
 
    if @aliases.include?(name)
788
 
      unless @aliases[name] == obj
789
 
        raise Puppet::Error.new(
790
 
          "Object #{@aliases[name].name} already has alias #{name}"
791
 
        )
792
 
      end
793
 
    end
794
 
 
795
 
    @aliases[name] = obj
796
 
  end
797
 
 
798
 
  # remove all of the instances of a single type
799
 
  def self.clear
800
 
    raise "Global resource removal is deprecated"
801
 
    if defined?(@objects)
802
 
      @objects.each do |name, obj|
803
 
        obj.remove(true)
804
 
      end
805
 
      @objects.clear
806
 
    end
807
 
    @aliases.clear if defined?(@aliases)
808
 
  end
809
 
 
810
 
  # Force users to call this, so that we can merge objects if
811
 
  # necessary.
812
 
  def self.create(args)
813
 
    # LAK:DEP Deprecation notice added 12/17/2008
814
 
    Puppet.warning "Puppet::Type.create is deprecated; use Puppet::Type.new"
815
 
    new(args)
816
 
  end
817
 
 
818
 
  # remove a specified object
819
 
  def self.delete(resource)
820
 
    raise "Global resource removal is deprecated"
821
 
    return unless defined?(@objects)
822
 
    @objects.delete(resource.title) if @objects.include?(resource.title)
823
 
    @aliases.delete(resource.title) if @aliases.include?(resource.title)
824
 
    if @aliases.has_value?(resource)
825
 
      names = []
826
 
      @aliases.each do |name, otherres|
827
 
        if otherres == resource
828
 
          names << name
829
 
        end
830
 
      end
831
 
      names.each { |name| @aliases.delete(name) }
832
 
    end
833
 
  end
834
 
 
835
 
  # iterate across each of the type's instances
836
 
  def self.each
837
 
    raise "Global resource iteration is deprecated"
838
 
    return unless defined?(@objects)
839
 
    @objects.each { |name,instance|
840
 
      yield instance
841
 
    }
842
 
  end
843
 
 
844
 
  # does the type have an object with the given name?
845
 
  def self.has_key?(name)
846
 
    raise "Global resource access is deprecated"
847
 
    @objects.has_key?(name)
848
 
  end
849
 
 
850
 
  # Retrieve all known instances.  Either requires providers or must be overridden.
851
 
  def self.instances
852
 
    raise Puppet::DevError, "#{self.name} has no providers and has not overridden 'instances'" if provider_hash.empty?
853
 
 
854
 
    # Put the default provider first, then the rest of the suitable providers.
855
 
    provider_instances = {}
856
 
    providers_by_source.collect do |provider|
857
 
      provider.instances.collect do |instance|
858
 
        # We always want to use the "first" provider instance we find, unless the resource
859
 
        # is already managed and has a different provider set
860
 
        if other = provider_instances[instance.name]
861
 
          Puppet.warning "%s %s found in both %s and %s; skipping the %s version" %
862
 
            [self.name.to_s.capitalize, instance.name, other.class.name, instance.class.name, instance.class.name]
863
 
          next
864
 
        end
865
 
        provider_instances[instance.name] = instance
866
 
 
867
 
        new(:name => instance.name, :provider => instance, :audit => :all)
868
 
      end
869
 
    end.flatten.compact
870
 
  end
871
 
 
872
 
  # Return a list of one suitable provider per source, with the default provider first.
873
 
  def self.providers_by_source
874
 
    # Put the default provider first, then the rest of the suitable providers.
875
 
    sources = []
876
 
    [defaultprovider, suitableprovider].flatten.uniq.collect do |provider|
877
 
      next if sources.include?(provider.source)
878
 
 
879
 
      sources << provider.source
880
 
      provider
881
 
    end.compact
882
 
  end
883
 
 
884
 
  # Convert a simple hash into a Resource instance.
885
 
  def self.hash2resource(hash)
886
 
    hash = hash.inject({}) { |result, ary| result[ary[0].to_sym] = ary[1]; result }
887
 
 
888
 
    title = hash.delete(:title)
889
 
    title ||= hash[:name]
890
 
    title ||= hash[key_attributes.first] if key_attributes.length == 1
891
 
 
892
 
    raise Puppet::Error, "Title or name must be provided" unless title
893
 
 
894
 
    # Now create our resource.
895
 
    resource = Puppet::Resource.new(self.name, title)
896
 
    [:catalog].each do |attribute|
897
 
      if value = hash[attribute]
898
 
        hash.delete(attribute)
899
 
        resource.send(attribute.to_s + "=", value)
900
 
      end
901
 
    end
902
 
 
903
 
    hash.each do |param, value|
904
 
      resource[param] = value
905
 
    end
906
 
    resource
907
 
  end
908
 
 
909
 
  # Create the path for logging and such.
910
 
  def pathbuilder
911
 
    if p = parent
912
 
      [p.pathbuilder, self.ref].flatten
913
 
    else
914
 
      [self.ref]
915
 
    end
916
 
  end
917
 
 
918
 
  ###############################
919
 
  # Add all of the meta parameters.
920
 
  newmetaparam(:noop) do
921
 
    desc "Boolean flag indicating whether work should actually
922
 
      be done."
923
 
 
924
 
    newvalues(:true, :false)
925
 
    munge do |value|
926
 
      case value
927
 
      when true, :true, "true"; @resource.noop = true
928
 
      when false, :false, "false"; @resource.noop = false
929
 
      end
930
 
    end
931
 
  end
932
 
 
933
 
  newmetaparam(:schedule) do
934
 
    desc "On what schedule the object should be managed.  You must create a
935
 
      schedule object, and then reference the name of that object to use
936
 
      that for your schedule:
937
 
 
938
 
          schedule { daily:
939
 
            period => daily,
940
 
            range => \"2-4\"
941
 
          }
942
 
 
943
 
          exec { \"/usr/bin/apt-get update\":
944
 
            schedule => daily
945
 
          }
946
 
 
947
 
      The creation of the schedule object does not need to appear in the
948
 
      configuration before objects that use it."
949
 
  end
950
 
 
951
 
  newmetaparam(:audit) do
952
 
    desc "Audit specified attributes of resources over time, and report if any have changed.
953
 
      This attribute can be used to track changes to any resource over time, and can
954
 
      provide an audit trail of every change that happens on any given machine.
955
 
 
956
 
      Note that you cannot both audit and manage an attribute - managing it guarantees
957
 
      the value, and any changes already get logged."
958
 
 
959
 
    validate do |list|
960
 
      list = Array(list)
961
 
      unless list == [:all]
962
 
        list.each do |param|
963
 
          next if @resource.class.validattr?(param)
964
 
          fail "Cannot audit #{param}: not a valid attribute for #{resource}"
965
 
        end
966
 
      end
967
 
    end
968
 
 
969
 
    munge do |args|
970
 
      properties_to_audit(args).each do |param|
971
 
        next unless resource.class.validproperty?(param)
972
 
        resource.newattr(param)
973
 
      end
974
 
    end
975
 
 
976
 
    def all_properties
977
 
      resource.class.properties.find_all do |property|
978
 
        resource.provider.nil? or resource.provider.class.supports_parameter?(property)
979
 
      end.collect do |property|
980
 
        property.name
981
 
      end
982
 
    end
983
 
 
984
 
    def properties_to_audit(list)
985
 
      if list == :all
986
 
        list = all_properties if list == :all
987
 
      else
988
 
        list = Array(list).collect { |p| p.to_sym }
989
 
      end
990
 
    end
991
 
  end
992
 
 
993
 
  newmetaparam(:check) do
994
 
    desc "Audit specified attributes of resources over time, and report if any have changed.
995
 
      This parameter has been deprecated in favor of 'audit'."
996
 
 
997
 
    munge do |args|
998
 
      resource.warning "'check' attribute is deprecated; use 'audit' instead"
999
 
      resource[:audit] = args
1000
 
    end
1001
 
  end
1002
 
 
1003
 
  newmetaparam(:loglevel) do
1004
 
    desc "Sets the level that information will be logged.
1005
 
      The log levels have the biggest impact when logs are sent to
1006
 
      syslog (which is currently the default)."
1007
 
    defaultto :notice
1008
 
 
1009
 
    newvalues(*Puppet::Util::Log.levels)
1010
 
    newvalues(:verbose)
1011
 
 
1012
 
    munge do |loglevel|
1013
 
      val = super(loglevel)
1014
 
      if val == :verbose
1015
 
        val = :info
1016
 
      end
1017
 
      val
1018
 
    end
1019
 
  end
1020
 
 
1021
 
  newmetaparam(:alias) do
1022
 
    desc "Creates an alias for the object.  Puppet uses this internally when you
1023
 
      provide a symbolic name:
1024
 
 
1025
 
          file { sshdconfig:
1026
 
            path => $operatingsystem ? {
1027
 
              solaris => \"/usr/local/etc/ssh/sshd_config\",
1028
 
              default => \"/etc/ssh/sshd_config\"
1029
 
            },
1030
 
            source => \"...\"
1031
 
          }
1032
 
 
1033
 
          service { sshd:
1034
 
            subscribe => File[sshdconfig]
1035
 
          }
1036
 
 
1037
 
      When you use this feature, the parser sets `sshdconfig` as the name,
1038
 
      and the library sets that as an alias for the file so the dependency
1039
 
      lookup for `sshd` works.  You can use this parameter yourself,
1040
 
      but note that only the library can use these aliases; for instance,
1041
 
      the following code will not work:
1042
 
 
1043
 
          file { \"/etc/ssh/sshd_config\":
1044
 
            owner => root,
1045
 
            group => root,
1046
 
            alias => sshdconfig
1047
 
          }
1048
 
 
1049
 
          file { sshdconfig:
1050
 
            mode => 644
1051
 
          }
1052
 
 
1053
 
      There's no way here for the Puppet parser to know that these two stanzas
1054
 
      should be affecting the same file.
1055
 
 
1056
 
      See the [Language Tutorial](http://docs.puppetlabs.com/guides/language_tutorial.html) for more information.
1057
 
 
1058
 
      "
1059
 
 
1060
 
    munge do |aliases|
1061
 
      aliases = [aliases] unless aliases.is_a?(Array)
1062
 
 
1063
 
      raise(ArgumentError, "Cannot add aliases without a catalog") unless @resource.catalog
1064
 
 
1065
 
      aliases.each do |other|
1066
 
        if obj = @resource.catalog.resource(@resource.class.name, other)
1067
 
          unless obj.object_id == @resource.object_id
1068
 
            self.fail("#{@resource.title} can not create alias #{other}: object already exists")
1069
 
          end
1070
 
          next
1071
 
        end
1072
 
 
1073
 
        # Newschool, add it to the catalog.
1074
 
        @resource.catalog.alias(@resource, other)
1075
 
      end
1076
 
    end
1077
 
  end
1078
 
 
1079
 
  newmetaparam(:tag) do
1080
 
    desc "Add the specified tags to the associated resource.  While all resources
1081
 
      are automatically tagged with as much information as possible
1082
 
      (e.g., each class and definition containing the resource), it can
1083
 
      be useful to add your own tags to a given resource.
1084
 
 
1085
 
      Tags are currently useful for things like applying a subset of a
1086
 
      host's configuration:
1087
 
 
1088
 
          puppet agent --test --tags mytag
1089
 
 
1090
 
      This way, when you're testing a configuration you can run just the
1091
 
      portion you're testing."
1092
 
 
1093
 
    munge do |tags|
1094
 
      tags = [tags] unless tags.is_a? Array
1095
 
 
1096
 
      tags.each do |tag|
1097
 
        @resource.tag(tag)
1098
 
      end
1099
 
    end
1100
 
  end
1101
 
 
1102
 
  class RelationshipMetaparam < Puppet::Parameter
1103
 
    class << self
1104
 
      attr_accessor :direction, :events, :callback, :subclasses
1105
 
    end
1106
 
 
1107
 
    @subclasses = []
1108
 
 
1109
 
    def self.inherited(sub)
1110
 
      @subclasses << sub
1111
 
    end
1112
 
 
1113
 
    def munge(references)
1114
 
      references = [references] unless references.is_a?(Array)
1115
 
      references.collect do |ref|
1116
 
        if ref.is_a?(Puppet::Resource)
1117
 
          ref
1118
 
        else
1119
 
          Puppet::Resource.new(ref)
1120
 
        end
1121
 
      end
1122
 
    end
1123
 
 
1124
 
    def validate_relationship
1125
 
      @value.each do |ref|
1126
 
        unless @resource.catalog.resource(ref.to_s)
1127
 
          description = self.class.direction == :in ? "dependency" : "dependent"
1128
 
          fail "Could not find #{description} #{ref} for #{resource.ref}"
1129
 
        end
1130
 
      end
1131
 
    end
1132
 
 
1133
 
    # Create edges from each of our relationships.    :in
1134
 
    # relationships are specified by the event-receivers, and :out
1135
 
    # relationships are specified by the event generator.  This
1136
 
    # way 'source' and 'target' are consistent terms in both edges
1137
 
    # and events -- that is, an event targets edges whose source matches
1138
 
    # the event's source.  The direction of the relationship determines
1139
 
    # which resource is applied first and which resource is considered
1140
 
    # to be the event generator.
1141
 
    def to_edges
1142
 
      @value.collect do |reference|
1143
 
        reference.catalog = resource.catalog
1144
 
 
1145
 
        # Either of the two retrieval attempts could have returned
1146
 
        # nil.
1147
 
        unless related_resource = reference.resolve
1148
 
          self.fail "Could not retrieve dependency '#{reference}' of #{@resource.ref}"
1149
 
        end
1150
 
 
1151
 
        # Are we requiring them, or vice versa?  See the method docs
1152
 
        # for futher info on this.
1153
 
        if self.class.direction == :in
1154
 
          source = related_resource
1155
 
          target = @resource
1156
 
        else
1157
 
          source = @resource
1158
 
          target = related_resource
1159
 
        end
1160
 
 
1161
 
        if method = self.class.callback
1162
 
          subargs = {
1163
 
            :event => self.class.events,
1164
 
            :callback => method
1165
 
          }
1166
 
          self.debug("subscribes to #{related_resource.ref}")
1167
 
        else
1168
 
          # If there's no callback, there's no point in even adding
1169
 
          # a label.
1170
 
          subargs = nil
1171
 
          self.debug("requires #{related_resource.ref}")
1172
 
        end
1173
 
 
1174
 
        rel = Puppet::Relationship.new(source, target, subargs)
1175
 
      end
1176
 
    end
1177
 
  end
1178
 
 
1179
 
  def self.relationship_params
1180
 
    RelationshipMetaparam.subclasses
1181
 
  end
1182
 
 
1183
 
 
1184
 
  # Note that the order in which the relationships params is defined
1185
 
  # matters.  The labelled params (notify and subcribe) must be later,
1186
 
  # so that if both params are used, those ones win.  It's a hackish
1187
 
  # solution, but it works.
1188
 
 
1189
 
  newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do
1190
 
    desc "One or more objects that this object depends on.
1191
 
      This is used purely for guaranteeing that changes to required objects
1192
 
      happen before the dependent object.  For instance:
1193
 
 
1194
 
          # Create the destination directory before you copy things down
1195
 
          file { \"/usr/local/scripts\":
1196
 
            ensure => directory
1197
 
          }
1198
 
 
1199
 
          file { \"/usr/local/scripts/myscript\":
1200
 
            source => \"puppet://server/module/myscript\",
1201
 
            mode => 755,
1202
 
            require => File[\"/usr/local/scripts\"]
1203
 
          }
1204
 
 
1205
 
      Multiple dependencies can be specified by providing a comma-seperated list
1206
 
      of resources, enclosed in square brackets:
1207
 
 
1208
 
          require => [ File[\"/usr/local\"], File[\"/usr/local/scripts\"] ]
1209
 
 
1210
 
      Note that Puppet will autorequire everything that it can, and
1211
 
      there are hooks in place so that it's easy for resources to add new
1212
 
      ways to autorequire objects, so if you think Puppet could be
1213
 
      smarter here, let us know.
1214
 
 
1215
 
      In fact, the above code was redundant -- Puppet will autorequire
1216
 
      any parent directories that are being managed; it will
1217
 
      automatically realize that the parent directory should be created
1218
 
      before the script is pulled down.
1219
 
 
1220
 
      Currently, exec resources will autorequire their CWD (if it is
1221
 
      specified) plus any fully qualified paths that appear in the
1222
 
      command.   For instance, if you had an `exec` command that ran
1223
 
      the `myscript` mentioned above, the above code that pulls the
1224
 
      file down would be automatically listed as a requirement to the
1225
 
      `exec` code, so that you would always be running againts the
1226
 
      most recent version.
1227
 
      "
1228
 
  end
1229
 
 
1230
 
  newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do
1231
 
    desc "One or more objects that this object depends on.  Changes in the
1232
 
      subscribed to objects result in the dependent objects being
1233
 
      refreshed (e.g., a service will get restarted).  For instance:
1234
 
 
1235
 
          class nagios {
1236
 
            file { \"/etc/nagios/nagios.conf\":
1237
 
              source => \"puppet://server/module/nagios.conf\",
1238
 
              alias => nagconf # just to make things easier for me
1239
 
            }
1240
 
            service { nagios:
1241
 
              ensure => running,
1242
 
              subscribe => File[nagconf]
1243
 
            }
1244
 
          }
1245
 
 
1246
 
      Currently the `exec`, `mount` and `service` type support
1247
 
      refreshing.
1248
 
      "
1249
 
  end
1250
 
 
1251
 
  newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do
1252
 
    desc %{This parameter is the opposite of **require** -- it guarantees
1253
 
      that the specified object is applied later than the specifying
1254
 
      object:
1255
 
 
1256
 
          file { "/var/nagios/configuration":
1257
 
            source  => "...",
1258
 
            recurse => true,
1259
 
            before => Exec["nagios-rebuid"]
1260
 
          }
1261
 
 
1262
 
          exec { "nagios-rebuild":
1263
 
            command => "/usr/bin/make",
1264
 
            cwd => "/var/nagios/configuration"
1265
 
          }
1266
 
 
1267
 
      This will make sure all of the files are up to date before the
1268
 
      make command is run.}
1269
 
  end
1270
 
 
1271
 
  newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do
1272
 
    desc %{This parameter is the opposite of **subscribe** -- it sends events
1273
 
      to the specified object:
1274
 
 
1275
 
          file { "/etc/sshd_config":
1276
 
            source => "....",
1277
 
            notify => Service[sshd]
1278
 
          }
1279
 
 
1280
 
          service { sshd:
1281
 
            ensure => running
1282
 
          }
1283
 
 
1284
 
      This will restart the sshd service if the sshd config file changes.}
1285
 
  end
1286
 
 
1287
 
  newmetaparam(:stage) do
1288
 
    desc %{Which run stage a given resource should reside in.  This just creates
1289
 
      a dependency on or from the named milestone.  For instance, saying that
1290
 
      this is in the 'bootstrap' stage creates a dependency on the 'bootstrap'
1291
 
      milestone.
1292
 
 
1293
 
      By default, all classes get directly added to the
1294
 
      'main' stage.  You can create new stages as resources:
1295
 
 
1296
 
          stage { [pre, post]: }
1297
 
 
1298
 
      To order stages, use standard relationships:
1299
 
 
1300
 
          stage { pre: before => Stage[main] }
1301
 
 
1302
 
      Or use the new relationship syntax:
1303
 
 
1304
 
          Stage[pre] -> Stage[main] -> Stage[post]
1305
 
 
1306
 
      Then use the new class parameters to specify a stage:
1307
 
 
1308
 
          class { foo: stage => pre }
1309
 
 
1310
 
      Stages can only be set on classes, not individual resources.  This will
1311
 
      fail:
1312
 
 
1313
 
          file { '/foo': stage => pre, ensure => file }
1314
 
    }
1315
 
  end
1316
 
 
1317
 
  ###############################
1318
 
  # All of the provider plumbing for the resource types.
1319
 
  require 'puppet/provider'
1320
 
  require 'puppet/util/provider_features'
1321
 
 
1322
 
  # Add the feature handling module.
1323
 
  extend Puppet::Util::ProviderFeatures
1324
 
 
1325
 
  attr_reader :provider
1326
 
 
1327
 
  # the Type class attribute accessors
1328
 
  class << self
1329
 
    attr_accessor :providerloader
1330
 
    attr_writer :defaultprovider
1331
 
  end
1332
 
 
1333
 
  # Find the default provider.
1334
 
  def self.defaultprovider
1335
 
    unless @defaultprovider
1336
 
      suitable = suitableprovider
1337
 
 
1338
 
      # Find which providers are a default for this system.
1339
 
      defaults = suitable.find_all { |provider| provider.default? }
1340
 
 
1341
 
      # If we don't have any default we use suitable providers
1342
 
      defaults = suitable if defaults.empty?
1343
 
      max = defaults.collect { |provider| provider.specificity }.max
1344
 
      defaults = defaults.find_all { |provider| provider.specificity == max }
1345
 
 
1346
 
      retval = nil
1347
 
      if defaults.length > 1
1348
 
        Puppet.warning(
1349
 
          "Found multiple default providers for #{self.name}: #{defaults.collect { |i| i.name.to_s }.join(", ")}; using #{defaults[0].name}"
1350
 
        )
1351
 
        retval = defaults.shift
1352
 
      elsif defaults.length == 1
1353
 
        retval = defaults.shift
1354
 
      else
1355
 
        raise Puppet::DevError, "Could not find a default provider for #{self.name}"
1356
 
      end
1357
 
 
1358
 
      @defaultprovider = retval
1359
 
    end
1360
 
 
1361
 
    @defaultprovider
1362
 
  end
1363
 
 
1364
 
  def self.provider_hash_by_type(type)
1365
 
    @provider_hashes ||= {}
1366
 
    @provider_hashes[type] ||= {}
1367
 
  end
1368
 
 
1369
 
  def self.provider_hash
1370
 
    Puppet::Type.provider_hash_by_type(self.name)
1371
 
  end
1372
 
 
1373
 
  # Retrieve a provider by name.
1374
 
  def self.provider(name)
1375
 
    name = Puppet::Util.symbolize(name)
1376
 
 
1377
 
    # If we don't have it yet, try loading it.
1378
 
    @providerloader.load(name) unless provider_hash.has_key?(name)
1379
 
    provider_hash[name]
1380
 
  end
1381
 
 
1382
 
  # Just list all of the providers.
1383
 
  def self.providers
1384
 
    provider_hash.keys
1385
 
  end
1386
 
 
1387
 
  def self.validprovider?(name)
1388
 
    name = Puppet::Util.symbolize(name)
1389
 
 
1390
 
    (provider_hash.has_key?(name) && provider_hash[name].suitable?)
1391
 
  end
1392
 
 
1393
 
  # Create a new provider of a type.  This method must be called
1394
 
  # directly on the type that it's implementing.
1395
 
  def self.provide(name, options = {}, &block)
1396
 
    name = Puppet::Util.symbolize(name)
1397
 
 
1398
 
    if obj = provider_hash[name]
1399
 
      Puppet.debug "Reloading #{name} #{self.name} provider"
1400
 
      unprovide(name)
1401
 
    end
1402
 
 
1403
 
    parent = if pname = options[:parent]
1404
 
      options.delete(:parent)
1405
 
      if pname.is_a? Class
1406
 
        pname
1407
 
      else
1408
 
        if provider = self.provider(pname)
1409
 
          provider
1410
 
        else
1411
 
          raise Puppet::DevError,
1412
 
            "Could not find parent provider #{pname} of #{name}"
1413
 
        end
1414
 
      end
1415
 
    else
1416
 
      Puppet::Provider
1417
 
    end
1418
 
 
1419
 
    options[:resource_type] ||= self
1420
 
 
1421
 
    self.providify
1422
 
 
1423
 
 
1424
 
      provider = genclass(
1425
 
        name,
1426
 
      :parent => parent,
1427
 
      :hash => provider_hash,
1428
 
      :prefix => "Provider",
1429
 
      :block => block,
1430
 
      :include => feature_module,
1431
 
      :extend => feature_module,
1432
 
 
1433
 
      :attributes => options
1434
 
    )
1435
 
 
1436
 
    provider
1437
 
  end
1438
 
 
1439
 
  # Make sure we have a :provider parameter defined.  Only gets called if there
1440
 
  # are providers.
1441
 
  def self.providify
1442
 
    return if @paramhash.has_key? :provider
1443
 
 
1444
 
    newparam(:provider) do
1445
 
      desc "The specific backend for #{self.name.to_s} to use. You will
1446
 
        seldom need to specify this -- Puppet will usually discover the
1447
 
        appropriate provider for your platform."
1448
 
 
1449
 
      # This is so we can refer back to the type to get a list of
1450
 
      # providers for documentation.
1451
 
      class << self
1452
 
        attr_accessor :parenttype
1453
 
      end
1454
 
 
1455
 
      # We need to add documentation for each provider.
1456
 
      def self.doc
1457
 
        @doc + "  Available providers are:\n\n" + parenttype.providers.sort { |a,b|
1458
 
          a.to_s <=> b.to_s
1459
 
        }.collect { |i|
1460
 
          "* **#{i}**: #{parenttype().provider(i).doc}"
1461
 
        }.join("\n")
1462
 
      end
1463
 
 
1464
 
      defaultto {
1465
 
        @resource.class.defaultprovider.name
1466
 
      }
1467
 
 
1468
 
      validate do |provider_class|
1469
 
        provider_class = provider_class[0] if provider_class.is_a? Array
1470
 
        provider_class = provider_class.class.name if provider_class.is_a?(Puppet::Provider)
1471
 
 
1472
 
        unless provider = @resource.class.provider(provider_class)
1473
 
          raise ArgumentError, "Invalid #{@resource.class.name} provider '#{provider_class}'"
1474
 
        end
1475
 
      end
1476
 
 
1477
 
      munge do |provider|
1478
 
        provider = provider[0] if provider.is_a? Array
1479
 
        provider = provider.intern if provider.is_a? String
1480
 
        @resource.provider = provider
1481
 
 
1482
 
        if provider.is_a?(Puppet::Provider)
1483
 
          provider.class.name
1484
 
        else
1485
 
          provider
1486
 
        end
1487
 
      end
1488
 
    end.parenttype = self
1489
 
  end
1490
 
 
1491
 
  def self.unprovide(name)
1492
 
    if provider_hash.has_key? name
1493
 
 
1494
 
      rmclass(
1495
 
        name,
1496
 
        :hash => provider_hash,
1497
 
 
1498
 
        :prefix => "Provider"
1499
 
      )
1500
 
      if @defaultprovider and @defaultprovider.name == name
1501
 
        @defaultprovider = nil
1502
 
      end
1503
 
    end
1504
 
  end
1505
 
 
1506
 
  # Return an array of all of the suitable providers.
1507
 
  def self.suitableprovider
1508
 
    providerloader.loadall if provider_hash.empty?
1509
 
    provider_hash.find_all { |name, provider|
1510
 
      provider.suitable?
1511
 
    }.collect { |name, provider|
1512
 
      provider
1513
 
    }.reject { |p| p.name == :fake } # For testing
1514
 
  end
1515
 
 
1516
 
  def provider=(name)
1517
 
    if name.is_a?(Puppet::Provider)
1518
 
      @provider = name
1519
 
      @provider.resource = self
1520
 
    elsif klass = self.class.provider(name)
1521
 
      @provider = klass.new(self)
1522
 
    else
1523
 
      raise ArgumentError, "Could not find #{name} provider of #{self.class.name}"
1524
 
    end
1525
 
  end
1526
 
 
1527
 
  ###############################
1528
 
  # All of the relationship code.
1529
 
 
1530
 
  # Specify a block for generating a list of objects to autorequire.  This
1531
 
  # makes it so that you don't have to manually specify things that you clearly
1532
 
  # require.
1533
 
  def self.autorequire(name, &block)
1534
 
    @autorequires ||= {}
1535
 
    @autorequires[name] = block
1536
 
  end
1537
 
 
1538
 
  # Yield each of those autorequires in turn, yo.
1539
 
  def self.eachautorequire
1540
 
    @autorequires ||= {}
1541
 
    @autorequires.each { |type, block|
1542
 
      yield(type, block)
1543
 
    }
1544
 
  end
1545
 
 
1546
 
  # Figure out of there are any objects we can automatically add as
1547
 
  # dependencies.
1548
 
  def autorequire(rel_catalog = nil)
1549
 
    rel_catalog ||= catalog
1550
 
    raise(Puppet::DevError, "You cannot add relationships without a catalog") unless rel_catalog
1551
 
 
1552
 
    reqs = []
1553
 
    self.class.eachautorequire { |type, block|
1554
 
      # Ignore any types we can't find, although that would be a bit odd.
1555
 
      next unless typeobj = Puppet::Type.type(type)
1556
 
 
1557
 
      # Retrieve the list of names from the block.
1558
 
      next unless list = self.instance_eval(&block)
1559
 
      list = [list] unless list.is_a?(Array)
1560
 
 
1561
 
      # Collect the current prereqs
1562
 
      list.each { |dep|
1563
 
        obj = nil
1564
 
        # Support them passing objects directly, to save some effort.
1565
 
        unless dep.is_a? Puppet::Type
1566
 
          # Skip autorequires that we aren't managing
1567
 
          unless dep = rel_catalog.resource(type, dep)
1568
 
            next
1569
 
          end
1570
 
        end
1571
 
 
1572
 
        reqs << Puppet::Relationship.new(dep, self)
1573
 
      }
1574
 
    }
1575
 
 
1576
 
    reqs
1577
 
  end
1578
 
 
1579
 
  # Build the dependencies associated with an individual object.
1580
 
  def builddepends
1581
 
    # Handle the requires
1582
 
    self.class.relationship_params.collect do |klass|
1583
 
      if param = @parameters[klass.name]
1584
 
        param.to_edges
1585
 
      end
1586
 
    end.flatten.reject { |r| r.nil? }
1587
 
  end
1588
 
 
1589
 
  # Define the initial list of tags.
1590
 
  def tags=(list)
1591
 
    tag(self.class.name)
1592
 
    tag(*list)
1593
 
  end
1594
 
 
1595
 
  # Types (which map to resources in the languages) are entirely composed of
1596
 
  # attribute value pairs.  Generally, Puppet calls any of these things an
1597
 
  # 'attribute', but these attributes always take one of three specific
1598
 
  # forms:  parameters, metaparams, or properties.
1599
 
 
1600
 
  # In naming methods, I have tried to consistently name the method so
1601
 
  # that it is clear whether it operates on all attributes (thus has 'attr' in
1602
 
  # the method name, or whether it operates on a specific type of attributes.
1603
 
  attr_writer :title
1604
 
  attr_writer :noop
1605
 
 
1606
 
  include Enumerable
1607
 
 
1608
 
  # class methods dealing with Type management
1609
 
 
1610
 
  public
1611
 
 
1612
 
  # the Type class attribute accessors
1613
 
  class << self
1614
 
    attr_reader :name
1615
 
    attr_accessor :self_refresh
1616
 
    include Enumerable, Puppet::Util::ClassGen
1617
 
    include Puppet::MetaType::Manager
1618
 
 
1619
 
    include Puppet::Util
1620
 
    include Puppet::Util::Logging
1621
 
  end
1622
 
 
1623
 
  # all of the variables that must be initialized for each subclass
1624
 
  def self.initvars
1625
 
    # all of the instances of this class
1626
 
    @objects = Hash.new
1627
 
    @aliases = Hash.new
1628
 
 
1629
 
    @defaults = {}
1630
 
 
1631
 
    @parameters ||= []
1632
 
 
1633
 
    @validproperties = {}
1634
 
    @properties = []
1635
 
    @parameters = []
1636
 
    @paramhash = {}
1637
 
 
1638
 
    @attr_aliases = {}
1639
 
 
1640
 
    @paramdoc = Hash.new { |hash,key|
1641
 
      key = key.intern if key.is_a?(String)
1642
 
      if hash.include?(key)
1643
 
        hash[key]
1644
 
      else
1645
 
        "Param Documentation for #{key} not found"
1646
 
      end
1647
 
    }
1648
 
 
1649
 
    @doc ||= ""
1650
 
 
1651
 
  end
1652
 
 
1653
 
  def self.to_s
1654
 
    if defined?(@name)
1655
 
      "Puppet::Type::#{@name.to_s.capitalize}"
1656
 
    else
1657
 
      super
1658
 
    end
1659
 
  end
1660
 
 
1661
 
  # Create a block to validate that our object is set up entirely.  This will
1662
 
  # be run before the object is operated on.
1663
 
  def self.validate(&block)
1664
 
    define_method(:validate, &block)
1665
 
    #@validate = block
1666
 
  end
1667
 
 
1668
 
  # The catalog that this resource is stored in.
1669
 
  attr_accessor :catalog
1670
 
 
1671
 
  # is the resource exported
1672
 
  attr_accessor :exported
1673
 
 
1674
 
  # is the resource virtual (it should not :-))
1675
 
  attr_accessor :virtual
1676
 
 
1677
 
  # create a log at specified level
1678
 
  def log(msg)
1679
 
 
1680
 
    Puppet::Util::Log.create(
1681
 
 
1682
 
      :level => @parameters[:loglevel].value,
1683
 
      :message => msg,
1684
 
 
1685
 
      :source => self
1686
 
    )
1687
 
  end
1688
 
 
1689
 
 
1690
 
  # instance methods related to instance intrinsics
1691
 
  # e.g., initialize and name
1692
 
 
1693
 
  public
1694
 
 
1695
 
  attr_reader :original_parameters
1696
 
 
1697
 
  # initialize the type instance
1698
 
  def initialize(resource)
1699
 
    raise Puppet::DevError, "Got TransObject instead of Resource or hash" if resource.is_a?(Puppet::TransObject)
1700
 
    resource = self.class.hash2resource(resource) unless resource.is_a?(Puppet::Resource)
1701
 
 
1702
 
    # The list of parameter/property instances.
1703
 
    @parameters = {}
1704
 
 
1705
 
    # Set the title first, so any failures print correctly.
1706
 
    if resource.type.to_s.downcase.to_sym == self.class.name
1707
 
      self.title = resource.title
1708
 
    else
1709
 
      # This should only ever happen for components
1710
 
      self.title = resource.ref
1711
 
    end
1712
 
 
1713
 
    [:file, :line, :catalog, :exported, :virtual].each do |getter|
1714
 
      setter = getter.to_s + "="
1715
 
      if val = resource.send(getter)
1716
 
        self.send(setter, val)
1717
 
      end
1718
 
    end
1719
 
 
1720
 
    @tags = resource.tags
1721
 
 
1722
 
    @original_parameters = resource.to_hash
1723
 
 
1724
 
    set_name(@original_parameters)
1725
 
 
1726
 
    set_default(:provider)
1727
 
 
1728
 
    set_parameters(@original_parameters)
1729
 
 
1730
 
    self.validate if self.respond_to?(:validate)
1731
 
  end
1732
 
 
1733
 
  private
1734
 
 
1735
 
  # Set our resource's name.
1736
 
  def set_name(hash)
1737
 
    self[name_var] = hash.delete(name_var) if name_var
1738
 
  end
1739
 
 
1740
 
  # Set all of the parameters from a hash, in the appropriate order.
1741
 
  def set_parameters(hash)
1742
 
    # Use the order provided by allattrs, but add in any
1743
 
    # extra attributes from the resource so we get failures
1744
 
    # on invalid attributes.
1745
 
    no_values = []
1746
 
    (self.class.allattrs + hash.keys).uniq.each do |attr|
1747
 
      begin
1748
 
        # Set any defaults immediately.  This is mostly done so
1749
 
        # that the default provider is available for any other
1750
 
        # property validation.
1751
 
        if hash.has_key?(attr)
1752
 
          self[attr] = hash[attr]
1753
 
        else
1754
 
          no_values << attr
1755
 
        end
1756
 
      rescue ArgumentError, Puppet::Error, TypeError
1757
 
        raise
1758
 
      rescue => detail
1759
 
        error = Puppet::DevError.new( "Could not set #{attr} on #{self.class.name}: #{detail}")
1760
 
        error.set_backtrace(detail.backtrace)
1761
 
        raise error
1762
 
      end
1763
 
    end
1764
 
    no_values.each do |attr|
1765
 
      set_default(attr)
1766
 
    end
1767
 
  end
1768
 
 
1769
 
  public
1770
 
 
1771
 
  # Set up all of our autorequires.
1772
 
  def finish
1773
 
    # Make sure all of our relationships are valid.  Again, must be done
1774
 
    # when the entire catalog is instantiated.
1775
 
    self.class.relationship_params.collect do |klass|
1776
 
      if param = @parameters[klass.name]
1777
 
        param.validate_relationship
1778
 
      end
1779
 
    end.flatten.reject { |r| r.nil? }
1780
 
  end
1781
 
 
1782
 
  # For now, leave the 'name' method functioning like it used to.  Once 'title'
1783
 
  # works everywhere, I'll switch it.
1784
 
  def name
1785
 
    self[:name]
1786
 
  end
1787
 
 
1788
 
  # Look up our parent in the catalog, if we have one.
1789
 
  def parent
1790
 
    return nil unless catalog
1791
 
 
1792
 
    unless defined?(@parent)
1793
 
      if parents = catalog.adjacent(self, :direction => :in)
1794
 
        # We should never have more than one parent, so let's just ignore
1795
 
        # it if we happen to.
1796
 
        @parent = parents.shift
1797
 
      else
1798
 
        @parent = nil
1799
 
      end
1800
 
    end
1801
 
    @parent
1802
 
  end
1803
 
 
1804
 
  # Return the "type[name]" style reference.
1805
 
  def ref
1806
 
    "#{self.class.name.to_s.capitalize}[#{self.title}]"
1807
 
  end
1808
 
 
1809
 
  def self_refresh?
1810
 
    self.class.self_refresh
1811
 
  end
1812
 
 
1813
 
  # Mark that we're purging.
1814
 
  def purging
1815
 
    @purging = true
1816
 
  end
1817
 
 
1818
 
  # Is this resource being purged?  Used by transactions to forbid
1819
 
  # deletion when there are dependencies.
1820
 
  def purging?
1821
 
    if defined?(@purging)
1822
 
      @purging
1823
 
    else
1824
 
      false
1825
 
    end
1826
 
  end
1827
 
 
1828
 
  # Retrieve the title of an object.  If no title was set separately,
1829
 
  # then use the object's name.
1830
 
  def title
1831
 
    unless @title
1832
 
      if self.class.validparameter?(name_var)
1833
 
        @title = self[:name]
1834
 
      elsif self.class.validproperty?(name_var)
1835
 
        @title = self.should(name_var)
1836
 
      else
1837
 
        self.devfail "Could not find namevar #{name_var} for #{self.class.name}"
1838
 
      end
1839
 
    end
1840
 
 
1841
 
    @title
1842
 
  end
1843
 
 
1844
 
  # convert to a string
1845
 
  def to_s
1846
 
    self.ref
1847
 
  end
1848
 
 
1849
 
  # Convert to a transportable object
1850
 
  def to_trans(ret = true)
1851
 
    trans = TransObject.new(self.title, self.class.name)
1852
 
 
1853
 
    values = retrieve_resource
1854
 
    values.each do |name, value|
1855
 
      name = name.name if name.respond_to? :name
1856
 
      trans[name] = value
1857
 
    end
1858
 
 
1859
 
    @parameters.each do |name, param|
1860
 
      # Avoid adding each instance name twice
1861
 
      next if param.class.isnamevar? and param.value == self.title
1862
 
 
1863
 
      # We've already got property values
1864
 
      next if param.is_a?(Puppet::Property)
1865
 
      trans[name] = param.value
1866
 
    end
1867
 
 
1868
 
    trans.tags = self.tags
1869
 
 
1870
 
    # FIXME I'm currently ignoring 'parent' and 'path'
1871
 
 
1872
 
    trans
1873
 
  end
1874
 
 
1875
 
  def to_resource
1876
 
    # this 'type instance' versus 'resource' distinction seems artificial
1877
 
    # I'd like to see it collapsed someday ~JW
1878
 
    self.to_trans.to_resource
1879
 
  end
1880
 
 
1881
 
  def virtual?;  !!@virtual;  end
1882
 
  def exported?; !!@exported; end
1883
 
end
1884
 
end
1885
 
 
1886
 
require 'puppet/provider'
1887
 
 
1888
 
# Always load these types.
1889
 
require 'puppet/type/component'