puppet 0.9.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (182) hide show
  1. data/CHANGELOG +0 -0
  2. data/COPYING +340 -0
  3. data/LICENSE +17 -0
  4. data/README +24 -0
  5. data/Rakefile +294 -0
  6. data/TODO +4 -0
  7. data/bin/cf2puppet +186 -0
  8. data/bin/puppet +176 -0
  9. data/bin/puppetca +213 -0
  10. data/bin/puppetd +246 -0
  11. data/bin/puppetdoc +184 -0
  12. data/bin/puppetmasterd +258 -0
  13. data/examples/code/allatonce +13 -0
  14. data/examples/code/assignments +11 -0
  15. data/examples/code/classing +35 -0
  16. data/examples/code/components +73 -0
  17. data/examples/code/execs +16 -0
  18. data/examples/code/failers/badclassnoparam +10 -0
  19. data/examples/code/failers/badclassparam +10 -0
  20. data/examples/code/failers/badcompnoparam +9 -0
  21. data/examples/code/failers/badcompparam +9 -0
  22. data/examples/code/failers/badtypeparam +3 -0
  23. data/examples/code/file.bl +11 -0
  24. data/examples/code/filedefaults +10 -0
  25. data/examples/code/fileparsing +116 -0
  26. data/examples/code/filerecursion +15 -0
  27. data/examples/code/functions +3 -0
  28. data/examples/code/groups +7 -0
  29. data/examples/code/head +30 -0
  30. data/examples/code/importing +8 -0
  31. data/examples/code/nodes +20 -0
  32. data/examples/code/one +8 -0
  33. data/examples/code/relationships +34 -0
  34. data/examples/code/selectors +28 -0
  35. data/examples/code/simpletests +11 -0
  36. data/examples/code/snippets/argumentdefaults +14 -0
  37. data/examples/code/snippets/casestatement +39 -0
  38. data/examples/code/snippets/classheirarchy.pp +15 -0
  39. data/examples/code/snippets/classincludes.pp +17 -0
  40. data/examples/code/snippets/classpathtest +11 -0
  41. data/examples/code/snippets/dirchmod +19 -0
  42. data/examples/code/snippets/failmissingexecpath.pp +13 -0
  43. data/examples/code/snippets/falsevalues.pp +3 -0
  44. data/examples/code/snippets/filecreate +11 -0
  45. data/examples/code/snippets/implicititeration +15 -0
  46. data/examples/code/snippets/multipleinstances +7 -0
  47. data/examples/code/snippets/namevartest +9 -0
  48. data/examples/code/snippets/scopetest +13 -0
  49. data/examples/code/snippets/selectorvalues.pp +22 -0
  50. data/examples/code/snippets/simpledefaults +5 -0
  51. data/examples/code/snippets/simpleselector +38 -0
  52. data/examples/code/svncommit +13 -0
  53. data/examples/root/bin/sleeper +69 -0
  54. data/examples/root/etc/configfile +0 -0
  55. data/examples/root/etc/debian-passwd +29 -0
  56. data/examples/root/etc/debian-syslog.conf +71 -0
  57. data/examples/root/etc/init.d/sleeper +65 -0
  58. data/examples/root/etc/otherfile +0 -0
  59. data/examples/root/etc/puppet/fileserver.conf +3 -0
  60. data/examples/root/etc/puppet/puppetmasterd.conf +10 -0
  61. data/ext/module:puppet +195 -0
  62. data/install.rb +270 -0
  63. data/lib/puppet.rb +249 -0
  64. data/lib/puppet/base64.rb +19 -0
  65. data/lib/puppet/client.rb +519 -0
  66. data/lib/puppet/config.rb +49 -0
  67. data/lib/puppet/daemon.rb +208 -0
  68. data/lib/puppet/element.rb +71 -0
  69. data/lib/puppet/event.rb +259 -0
  70. data/lib/puppet/log.rb +321 -0
  71. data/lib/puppet/metric.rb +250 -0
  72. data/lib/puppet/parsedfile.rb +38 -0
  73. data/lib/puppet/parser/ast.rb +1560 -0
  74. data/lib/puppet/parser/interpreter.rb +150 -0
  75. data/lib/puppet/parser/lexer.rb +226 -0
  76. data/lib/puppet/parser/parser.rb +1354 -0
  77. data/lib/puppet/parser/scope.rb +755 -0
  78. data/lib/puppet/server.rb +170 -0
  79. data/lib/puppet/server/authstore.rb +227 -0
  80. data/lib/puppet/server/ca.rb +140 -0
  81. data/lib/puppet/server/filebucket.rb +147 -0
  82. data/lib/puppet/server/fileserver.rb +477 -0
  83. data/lib/puppet/server/logger.rb +43 -0
  84. data/lib/puppet/server/master.rb +103 -0
  85. data/lib/puppet/server/servlet.rb +247 -0
  86. data/lib/puppet/sslcertificates.rb +737 -0
  87. data/lib/puppet/statechange.rb +150 -0
  88. data/lib/puppet/storage.rb +95 -0
  89. data/lib/puppet/transaction.rb +179 -0
  90. data/lib/puppet/transportable.rb +151 -0
  91. data/lib/puppet/type.rb +1354 -0
  92. data/lib/puppet/type/component.rb +141 -0
  93. data/lib/puppet/type/cron.rb +543 -0
  94. data/lib/puppet/type/exec.rb +316 -0
  95. data/lib/puppet/type/group.rb +152 -0
  96. data/lib/puppet/type/nameservice.rb +3 -0
  97. data/lib/puppet/type/nameservice/netinfo.rb +173 -0
  98. data/lib/puppet/type/nameservice/objectadd.rb +146 -0
  99. data/lib/puppet/type/nameservice/posix.rb +200 -0
  100. data/lib/puppet/type/package.rb +420 -0
  101. data/lib/puppet/type/package/apt.rb +70 -0
  102. data/lib/puppet/type/package/dpkg.rb +108 -0
  103. data/lib/puppet/type/package/rpm.rb +81 -0
  104. data/lib/puppet/type/package/sun.rb +117 -0
  105. data/lib/puppet/type/package/yum.rb +58 -0
  106. data/lib/puppet/type/pfile.rb +569 -0
  107. data/lib/puppet/type/pfile/checksum.rb +219 -0
  108. data/lib/puppet/type/pfile/create.rb +108 -0
  109. data/lib/puppet/type/pfile/group.rb +129 -0
  110. data/lib/puppet/type/pfile/mode.rb +131 -0
  111. data/lib/puppet/type/pfile/source.rb +264 -0
  112. data/lib/puppet/type/pfile/type.rb +31 -0
  113. data/lib/puppet/type/pfile/uid.rb +166 -0
  114. data/lib/puppet/type/pfilebucket.rb +80 -0
  115. data/lib/puppet/type/pprocess.rb +97 -0
  116. data/lib/puppet/type/service.rb +347 -0
  117. data/lib/puppet/type/service/base.rb +17 -0
  118. data/lib/puppet/type/service/debian.rb +50 -0
  119. data/lib/puppet/type/service/init.rb +145 -0
  120. data/lib/puppet/type/service/smf.rb +29 -0
  121. data/lib/puppet/type/state.rb +182 -0
  122. data/lib/puppet/type/symlink.rb +183 -0
  123. data/lib/puppet/type/tidy.rb +183 -0
  124. data/lib/puppet/type/typegen.rb +149 -0
  125. data/lib/puppet/type/typegen/filerecord.rb +243 -0
  126. data/lib/puppet/type/typegen/filetype.rb +316 -0
  127. data/lib/puppet/type/user.rb +290 -0
  128. data/lib/puppet/util.rb +138 -0
  129. data/test/certmgr/certmgr.rb +265 -0
  130. data/test/client/client.rb +203 -0
  131. data/test/executables/puppetbin.rb +53 -0
  132. data/test/executables/puppetca.rb +79 -0
  133. data/test/executables/puppetd.rb +71 -0
  134. data/test/executables/puppetmasterd.rb +153 -0
  135. data/test/executables/puppetmodule.rb +60 -0
  136. data/test/language/ast.rb +412 -0
  137. data/test/language/interpreter.rb +71 -0
  138. data/test/language/scope.rb +412 -0
  139. data/test/language/snippets.rb +445 -0
  140. data/test/other/events.rb +111 -0
  141. data/test/other/log.rb +195 -0
  142. data/test/other/metrics.rb +92 -0
  143. data/test/other/overrides.rb +115 -0
  144. data/test/other/parsedfile.rb +31 -0
  145. data/test/other/relationships.rb +113 -0
  146. data/test/other/state.rb +106 -0
  147. data/test/other/storage.rb +39 -0
  148. data/test/other/transactions.rb +235 -0
  149. data/test/parser/lexer.rb +120 -0
  150. data/test/parser/parser.rb +180 -0
  151. data/test/puppet/conffiles.rb +104 -0
  152. data/test/puppet/defaults.rb +100 -0
  153. data/test/puppet/error.rb +23 -0
  154. data/test/puppet/utiltest.rb +120 -0
  155. data/test/puppettest.rb +774 -0
  156. data/test/server/authstore.rb +209 -0
  157. data/test/server/bucket.rb +227 -0
  158. data/test/server/ca.rb +201 -0
  159. data/test/server/fileserver.rb +710 -0
  160. data/test/server/logger.rb +175 -0
  161. data/test/server/master.rb +150 -0
  162. data/test/server/server.rb +130 -0
  163. data/test/tagging/tagging.rb +80 -0
  164. data/test/test +51 -0
  165. data/test/types/basic.rb +119 -0
  166. data/test/types/component.rb +272 -0
  167. data/test/types/cron.rb +261 -0
  168. data/test/types/exec.rb +273 -0
  169. data/test/types/file.rb +616 -0
  170. data/test/types/filebucket.rb +167 -0
  171. data/test/types/fileignoresource.rb +287 -0
  172. data/test/types/filesources.rb +587 -0
  173. data/test/types/filetype.rb +162 -0
  174. data/test/types/group.rb +271 -0
  175. data/test/types/package.rb +205 -0
  176. data/test/types/query.rb +101 -0
  177. data/test/types/service.rb +100 -0
  178. data/test/types/symlink.rb +93 -0
  179. data/test/types/tidy.rb +124 -0
  180. data/test/types/type.rb +135 -0
  181. data/test/types/user.rb +371 -0
  182. metadata +243 -0
@@ -0,0 +1,1354 @@
1
+ require 'puppet'
2
+ require 'puppet/log'
3
+ require 'puppet/element'
4
+ require 'puppet/event'
5
+ require 'puppet/metric'
6
+ require 'puppet/type/state'
7
+ # see the bottom of the file for the rest of the inclusions
8
+
9
+ module Puppet # :nodoc:
10
+ # This class is the abstract base class for the mechanism for organizing
11
+ # work. No work is actually done by this class or its subclasses; rather,
12
+ # the subclasses include states which do the actual work.
13
+ # See state.rb for how work is actually done.
14
+ class Type < Puppet::Element
15
+ attr_accessor :children, :parameters, :parent
16
+ attr_accessor :file, :line, :tags
17
+
18
+ attr_writer :implicit
19
+ def implicit?
20
+ if defined? @implicit and @implicit
21
+ return true
22
+ else
23
+ return false
24
+ end
25
+ end
26
+
27
+ include Enumerable
28
+
29
+ # this is currently unused, but I expect to use it for metrics eventually
30
+ @@retrieved = Hash.new(0)
31
+
32
+ # an array to contain all instances of Type
33
+ # also currently unused
34
+ @@allobjects = Array.new
35
+
36
+ # a little fakery, since Puppet itself isn't a type
37
+ # I don't think this is used any more, now that the language can't
38
+ # call methods
39
+ @name = :puppet
40
+
41
+ # set it to something to silence the tests, but otherwise not used
42
+ @namevar = :notused
43
+
44
+ # again, silence the tests; the :notused has to be there because it's
45
+ # the namevar
46
+ @states = []
47
+ @parameters = [:notused]
48
+
49
+ # @paramdoc = Hash.new
50
+
51
+ # the parameters that all instances will accept
52
+ @@metaparams = [
53
+ :onerror,
54
+ :noop,
55
+ :schedule,
56
+ :check,
57
+ :subscribe,
58
+ :require,
59
+ :loglevel
60
+ ]
61
+
62
+ @@metaparamdoc = Hash.new { |hash,key|
63
+ if key.is_a?(String)
64
+ key = key.intern
65
+ end
66
+ if hash.include?(key)
67
+ hash[key]
68
+ else
69
+ "Metaparam Documentation for %s not found" % key
70
+ end
71
+ }
72
+
73
+ @@metaparamdoc[:onerror] = "How to handle errors -- roll back innermost
74
+ transaction, roll back entire transaction, ignore, etc. Currently
75
+ non-functional."
76
+ @@metaparamdoc[:noop] = "Boolean flag indicating whether work should actually
77
+ be done."
78
+ @@metaparamdoc[:schedule] = "On what schedule the object should be managed.
79
+ Currently non-functional."
80
+ @@metaparamdoc[:check] = "States which should have their values retrieved
81
+ but which should not actually be modified. This is currently used
82
+ internally, but will eventually be used for querying."
83
+ @@metaparamdoc[:require] = "One or more objects that this object depends on.
84
+ This is used purely for guaranteeing that changes to required objects
85
+ happen before the dependent object."
86
+ @@metaparamdoc[:subscribe] = "One or more objects that this object depends on.
87
+ Changes in the subscribed to objects result in the dependent objects being
88
+ refreshed (e.g., a service will get restarted)."
89
+ @@metaparamdoc[:loglevel] = "Sets the level that information will be logged:
90
+ debug, info, verbose, notice, warning, err, alert, emerg or crit"
91
+
92
+ # class methods dealing with Type management
93
+
94
+ public
95
+
96
+ # these objects are used for mapping type names (e.g., 'file')
97
+ # to actual object classes; because Type.inherited is
98
+ # called before the <subclass>.name method is defined, we need
99
+ # to store each class in an array, and then later actually iterate
100
+ # across that array and make a map
101
+ @@typeary = [self] # so that the allowedmethods stuff works
102
+ @@typehash = Hash.new { |hash,key|
103
+ if key.is_a?(String)
104
+ key = key.intern
105
+ end
106
+ if hash.include?(key)
107
+ hash[key]
108
+ else
109
+ raise TypeError.new("Object type %s not found" % key)
110
+ end
111
+ }
112
+
113
+ # the Type class attribute accessors
114
+ class << self
115
+ attr_reader :name, :namevar, :states, :parameters
116
+ end
117
+
118
+ # Create @@typehash from @@typeary. This is meant to be run
119
+ # multiple times -- whenever it is discovered that the two
120
+ # objects have differents lengths.
121
+ def self.buildtypehash
122
+ @@typeary.each { |otype|
123
+ if @@typehash.include?(otype.name)
124
+ if @@typehash[otype.name] != otype
125
+ Puppet.warning("Object type %s is already defined (%s vs %s)" %
126
+ [otype.name,@@typehash[otype.name],otype])
127
+ end
128
+ else
129
+ @@typehash[otype.name] = otype
130
+ end
131
+ }
132
+ end
133
+
134
+ # iterate across all of the subclasses of Type
135
+ def self.eachtype
136
+ @@typeary.each { |type| yield type }
137
+ end
138
+
139
+ # The work that gets done for every subclass of Type
140
+ # this is an implicit method called by Ruby for us
141
+ def self.inherited(sub)
142
+ sub.initvars
143
+
144
+ #debug("subtype %s(%s) just created" % [sub,sub.superclass])
145
+ # add it to the master list
146
+ # unfortunately we can't yet call sub.name, because the #inherited
147
+ # method gets called before any commands in the class definition
148
+ # get executed, which, um, sucks
149
+ @@typeary.push(sub)
150
+ end
151
+
152
+ # all of the variables that must be initialized for each subclass
153
+ def self.initvars
154
+ # all of the instances of this class
155
+ @objects = Hash.new
156
+
157
+ @validstates = {}
158
+
159
+ @paramdoc = Hash.new { |hash,key|
160
+ if key.is_a?(String)
161
+ key = key.intern
162
+ end
163
+ if hash.include?(key)
164
+ hash[key]
165
+ else
166
+ "Param Documentation for %s not found" % key
167
+ end
168
+ }
169
+
170
+ unless defined? @doc
171
+ @doc = ""
172
+ end
173
+
174
+ unless defined? @states
175
+ @states = []
176
+ end
177
+
178
+ end
179
+
180
+ # return a Type instance by name
181
+ def self.type(type)
182
+ unless @@typeary.length == @@typehash.length
183
+ # call bulidtypehash if types have been added since it
184
+ # was last called
185
+ Type.buildtypehash
186
+ end
187
+ @@typehash[type]
188
+ end
189
+
190
+ # class methods dealing with type instance management
191
+
192
+ public
193
+
194
+ # retrieve a named instance of the current type
195
+ def self.[](name)
196
+ if @objects.has_key?(name)
197
+ return @objects[name]
198
+ else
199
+ return nil
200
+ end
201
+ end
202
+
203
+ # add an instance by name to the class list of instances
204
+ def self.[]=(name,object)
205
+ newobj = nil
206
+ if object.is_a?(Puppet::Type)
207
+ newobj = object
208
+ else
209
+ raise Puppet::DevError, "must pass a Puppet::Type object"
210
+ end
211
+
212
+ if @objects.has_key?(newobj.name) and self.isomorphic?
213
+ raise Puppet::Error.new(
214
+ "Object '%s' of type '%s' already exists with id '%s' vs. '%s'" %
215
+ [newobj.name,newobj.class.name,
216
+ @objects[newobj.name].object_id,newobj.object_id]
217
+ )
218
+ else
219
+ #debug("adding %s of type %s to class list" %
220
+ # [object.name,object.class])
221
+ @objects[newobj.name] = newobj
222
+ end
223
+
224
+ # and then add it to the master list
225
+ Puppet::Type.push(object)
226
+ end
227
+
228
+ # remove all type instances; this is mostly only useful for testing
229
+ def self.allclear
230
+ @@allobjects.clear
231
+ Puppet::Event::Subscription.clear
232
+ @@typeary.each { |subtype|
233
+ subtype.clear
234
+ }
235
+ end
236
+
237
+ # remove all of the instances of a single type
238
+ def self.clear
239
+ if defined? @objects
240
+ @objects.clear
241
+ end
242
+ end
243
+
244
+ # remove a specified object
245
+ def self.delete(object)
246
+ if @@allobjects.include?(object)
247
+ @@allobjects.delete(object)
248
+ end
249
+ return unless defined? @objects
250
+ if @objects.include?(object.name)
251
+ @objects.delete(object.name)
252
+ end
253
+ end
254
+
255
+ # iterate across each of the type's instances
256
+ def self.each
257
+ return unless defined? @objects
258
+ @objects.each { |name,instance|
259
+ yield instance
260
+ }
261
+ end
262
+
263
+ # does the type have an object with the given name?
264
+ def self.has_key?(name)
265
+ return @objects.has_key?(name)
266
+ end
267
+
268
+ # Allow an outside party to specify the 'is' value for a state. The
269
+ # arguments are an array because you can't use parens with 'is=' calls.
270
+ # Most classes won't use this.
271
+ def is=(ary)
272
+ param, value = ary
273
+ if param.is_a?(String)
274
+ param = param.intern
275
+ end
276
+ if self.class.validstate?(param)
277
+ unless @states.include?(param)
278
+ self.newstate(param)
279
+ end
280
+ @states[param].is = value
281
+ else
282
+ self[param] = value
283
+ end
284
+ end
285
+
286
+ # add an object to the master list of Type instances
287
+ # I'm pretty sure this is currently basically unused
288
+ def self.push(object)
289
+ @@allobjects.push object
290
+ #debug("adding %s of type %s to master list" %
291
+ # [object.name,object.class])
292
+ end
293
+
294
+ # class and instance methods dealing with parameters and states
295
+
296
+ public
297
+
298
+ # build a per-Type hash, mapping the states to their names
299
+ def self.buildstatehash
300
+ unless defined? @validstates
301
+ @validstates = Hash.new(false)
302
+ end
303
+ @states.each { |stateklass|
304
+ name = stateklass.name
305
+ if @validstates.include?(name)
306
+ if @validstates[name] != stateklass
307
+ raise Puppet::Error.new("Redefining state %s(%s) in %s" %
308
+ [name,stateklass,self])
309
+ else
310
+ # it's already there, so don't bother
311
+ end
312
+ else
313
+ @validstates[name] = stateklass
314
+ end
315
+ }
316
+ end
317
+
318
+ # set the parameters for a type; probably only used by FileRecord
319
+ # objects
320
+ def self.parameters=(params)
321
+ Puppet.debug "setting parameters to [%s]" % params.join(" ")
322
+ @parameters = params.collect { |param|
323
+ if param.class == Symbol
324
+ param
325
+ else
326
+ param.intern
327
+ end
328
+ }
329
+ end
330
+
331
+ # does the name reflect a valid state?
332
+ def self.validstate?(name)
333
+ unless @validstates.length == @states.length
334
+ self.buildstatehash
335
+ end
336
+ if @validstates.include?(name)
337
+ return @validstates[name]
338
+ else
339
+ return false
340
+ end
341
+ end
342
+
343
+ # Return the list of validstates
344
+ def self.validstates
345
+ unless @validstates.length == @states.length
346
+ self.buildstatehash
347
+ end
348
+
349
+ return @validstates.keys
350
+ end
351
+
352
+ # Return the state class associated with a name
353
+ def self.statebyname(name)
354
+ unless @validstates.length == @states.length
355
+ self.buildstatehash
356
+ end
357
+ @validstates[name]
358
+ end
359
+
360
+ # does the name reflect a valid parameter?
361
+ def self.validparameter?(name)
362
+ unless defined? @parameters
363
+ raise Puppet::DevError, "Class %s has not defined parameters" % self
364
+ end
365
+ if @parameters.include?(name) or @@metaparams.include?(name)
366
+ return true
367
+ else
368
+ return false
369
+ end
370
+ end
371
+
372
+ def self.validarg?(name)
373
+ if name.is_a?(String)
374
+ name = name.intern
375
+ end
376
+ if self.validstate?(name) or self.validparameter?(name) or self.metaparam?(name)
377
+ return true
378
+ else
379
+ return false
380
+ end
381
+ end
382
+
383
+ # abstract accessing parameters and states, and normalize
384
+ # access to always be symbols, not strings
385
+ # This returns a value, not an object. It returns the 'is'
386
+ # value, but you can also specifically return 'is' and 'should'
387
+ # values using 'object.is(:state)' or 'object.should(:state)'.
388
+ def [](name)
389
+ if name.is_a?(String)
390
+ name = name.intern
391
+ end
392
+
393
+ if name == :name
394
+ name = self.class.namevar
395
+ end
396
+ if self.class.validstate?(name)
397
+ if @states.include?(name)
398
+ return @states[name].is
399
+ else
400
+ return nil
401
+ end
402
+ elsif Puppet::Type.metaparam?(name)
403
+ if @metaparams.include?(name)
404
+ return @metaparams[name]
405
+ else
406
+ return nil
407
+ end
408
+ elsif self.class.validparameter?(name)
409
+ if @parameters.include?(name)
410
+ return @parameters[name]
411
+ else
412
+ return nil
413
+ end
414
+ else
415
+ raise TypeError.new("Invalid parameter %s" % [name])
416
+ end
417
+ end
418
+
419
+ # Abstract setting parameters and states, and normalize
420
+ # access to always be symbols, not strings. This sets the 'should'
421
+ # value on states, and otherwise just sets the appropriate parameter.
422
+ def []=(name,value)
423
+ if name.is_a?(String)
424
+ name = name.intern
425
+ end
426
+
427
+ if name == :name
428
+ name = self.class.namevar
429
+ end
430
+ if value.nil?
431
+ raise Puppet::Error.new("Got nil value for %s" % name)
432
+ end
433
+ if Puppet::Type.metaparam?(name)
434
+ @parameters[name] = value
435
+ # call the metaparam method
436
+ self.send(("meta" + name.id2name + "="),value)
437
+ elsif stateklass = self.class.validstate?(name)
438
+ if value.is_a?(Puppet::State)
439
+ self.debug "'%s' got handed a state for '%s'" % [self,name]
440
+ @states[name] = value
441
+ else
442
+ if @states.include?(name)
443
+ @states[name].should = value
444
+ else
445
+ # newstate returns true if it successfully created the state,
446
+ # false otherwise; I just don't know what to do with that
447
+ # fact.
448
+ unless newstate(name, :should => value)
449
+ #self.info "%s failed" % name
450
+ end
451
+ end
452
+ end
453
+ elsif self.class.validparameter?(name)
454
+ # if they've got a method to handle the parameter, then do it that way
455
+ method = "param" + name.id2name + "="
456
+ if self.respond_to?(method)
457
+ self.send(method,value)
458
+ else
459
+ # else just set it
460
+ @parameters[name] = value
461
+ end
462
+ else
463
+ raise Puppet::Error, "Invalid parameter %s" % [name]
464
+ end
465
+ end
466
+
467
+ # remove a state from the object; useful in testing or in cleanup
468
+ # when an error has been encountered
469
+ def delete(attr)
470
+ case attr
471
+ when Puppet::Type
472
+ if @children.include?(attr)
473
+ @children.delete(attr)
474
+ end
475
+ else
476
+ if @states.has_key?(attr)
477
+ @states.delete(attr)
478
+ else
479
+ raise Puppet::DevError.new("Undefined state '#{attr}' in #{self}")
480
+ end
481
+ end
482
+ end
483
+
484
+ # iterate across all children, and then iterate across states
485
+ # we do children first so we're sure that all dependent objects
486
+ # are checked first
487
+ # we ignore parameters here, because they only modify how work gets
488
+ # done, they don't ever actually result in work specifically
489
+ def each
490
+ # we want to return the states in the order that each type
491
+ # specifies it, because it may (as in the case of File#create)
492
+ # be important
493
+ if self.class.depthfirst?
494
+ @children.each { |child|
495
+ yield child
496
+ }
497
+ end
498
+ self.eachstate { |state|
499
+ yield state
500
+ }
501
+ unless self.class.depthfirst?
502
+ @children.each { |child|
503
+ yield child
504
+ }
505
+ end
506
+ end
507
+
508
+ # iterate across the existing states
509
+ def eachstate
510
+ # states() is a private method
511
+ states().each { |state|
512
+ yield state
513
+ }
514
+ end
515
+
516
+ # retrieve the 'is' value for a specified state
517
+ def is(state)
518
+ if @states.include?(state)
519
+ return @states[state].is
520
+ else
521
+ return nil
522
+ end
523
+ end
524
+
525
+ # retrieve the 'should' value for a specified state
526
+ def should(state)
527
+ if @states.include?(state)
528
+ return @states[state].should
529
+ else
530
+ return nil
531
+ end
532
+ end
533
+
534
+ # create a log at specified level
535
+ def log(msg)
536
+ Puppet::Log.create(
537
+ :level => @metaparams[:loglevel],
538
+ :message => msg,
539
+ :source => self
540
+ )
541
+ end
542
+
543
+ # is the instance a managed instance? A 'yes' here means that
544
+ # the instance was created from the language, vs. being created
545
+ # in order resolve other questions, such as finding a package
546
+ # in a list
547
+ def managed?
548
+ if defined? @managed
549
+ return @managed
550
+ else
551
+ @managed = false
552
+ states.each { |state|
553
+ if state.should and ! state.class.unmanaged
554
+ @managed = true
555
+ end
556
+ }
557
+ return @managed
558
+ end
559
+ end
560
+
561
+ # create a new state
562
+ def newstate(name, hash = {})
563
+ unless stateklass = self.class.validstate?(name)
564
+ raise Puppet::Error, "Invalid parameter %s" % name
565
+ end
566
+ if @states.include?(name)
567
+ hash.each { |var,value|
568
+ @states[name].send(var.to_s + "=", value)
569
+ }
570
+ else
571
+ #Puppet.warning "Creating state %s for %s" %
572
+ # [stateklass.name,self.name]
573
+ begin
574
+ hash[:parent] = self
575
+ # make sure the state doesn't have any errors
576
+ newstate = stateklass.new(hash)
577
+ @states[name] = newstate
578
+ return true
579
+ rescue Puppet::Error => detail
580
+ # the state failed, so just ignore it
581
+ self.warning "State %s failed: %s" %
582
+ [name, detail]
583
+ return false
584
+ rescue Puppet::DevError => detail
585
+ # the state failed, so just ignore it
586
+ self.err "State %s failed: %s" %
587
+ [name, detail]
588
+ return false
589
+ rescue => detail
590
+ # the state failed, so just ignore it
591
+ self.err "State %s failed: %s (%s)" %
592
+ [name, detail, detail.class]
593
+ return false
594
+ end
595
+ end
596
+ end
597
+
598
+ # return the value of a parameter
599
+ def parameter(name)
600
+ unless name.is_a? Symbol
601
+ name = name.intern
602
+ end
603
+ return @parameters[name]
604
+ end
605
+
606
+ def push(*childs)
607
+ unless defined? @children
608
+ @children = []
609
+ end
610
+ childs.each { |child|
611
+ @children.push(child)
612
+ child.parent = self
613
+ }
614
+ end
615
+
616
+ # Remove an object. The argument determines whether the object's
617
+ # subscriptions get eliminated, too.
618
+ def remove(rmdeps)
619
+ @children.each { |child|
620
+ child.remove
621
+ }
622
+ self.class.delete(self)
623
+
624
+ if rmdeps
625
+ Puppet::Event::Subscription.dependencies(self).each { |dep|
626
+ self.unsubscribe(dep)
627
+ }
628
+ end
629
+
630
+ if defined? @parent and @parent
631
+ @parent.delete(self)
632
+ end
633
+ end
634
+
635
+ # return an actual type by name; to return the value, use 'inst[name]'
636
+ # FIXME this method should go away
637
+ def state(name)
638
+ unless name.is_a? Symbol
639
+ name = name.intern
640
+ end
641
+ return @states[name]
642
+ end
643
+
644
+ private
645
+
646
+ def states
647
+ #debug "%s has %s states" % [self,@states.length]
648
+ tmpstates = []
649
+ self.class.states.each { |state|
650
+ if @states.include?(state.name)
651
+ tmpstates.push(@states[state.name])
652
+ end
653
+ }
654
+ unless tmpstates.length == @states.length
655
+ raise Puppet::DevError,
656
+ "Something went very wrong with tmpstates creation"
657
+ end
658
+ return tmpstates
659
+ end
660
+
661
+
662
+ # instance methods related to instance intrinsics
663
+ # e.g., initialize() and name()
664
+
665
+ public
666
+
667
+ # Force users to call this, so that we can merge objects if
668
+ # necessary. FIXME This method should be responsible for most of the
669
+ # error handling.
670
+ def self.create(hash)
671
+ # Handle this new object being implicit
672
+ implicit = hash[:implicit] || false
673
+ if hash.include?(:implicit)
674
+ hash.delete(:implicit)
675
+ end
676
+
677
+ name = nil
678
+ unless name = hash["name"] || hash[:name] ||
679
+ hash[self.namevar] || hash[self.namevar.to_s]
680
+ raise Puppet::Error, "You must specify a name for objects of type %s" %
681
+ self.to_s
682
+ end
683
+ # if the object already exists
684
+ if self.isomorphic? and retobj = self[name]
685
+ # if only one of our objects is implicit, then it's easy to see
686
+ # who wins -- the non-implicit one.
687
+ if retobj.implicit? and ! implicit
688
+ Puppet.notice "Removing implicit %s" % retobj.name
689
+ # Remove all of the objects, but do not remove their subscriptions.
690
+ retobj.remove(false)
691
+
692
+ # now pass through and create the new object
693
+ elsif implicit
694
+ Puppet.notice "Ignoring implicit %s" % name
695
+
696
+ return retobj
697
+ else
698
+ # We will probably want to support merging of some kind in
699
+ # the future, but for now, just throw an error.
700
+ raise Puppet::Error, "%s %s is already being managed" %
701
+ [self.name, name]
702
+ #retobj.merge(hash)
703
+
704
+ #return retobj
705
+ end
706
+ end
707
+
708
+ # create it anew
709
+ # if there's a failure, destroy the object if it got that far
710
+ begin
711
+ obj = new(hash)
712
+ rescue => detail
713
+ if Puppet[:debug]
714
+ if detail.respond_to?(:stack)
715
+ puts detail.stack
716
+ end
717
+ end
718
+ Puppet.err "Could not create %s: %s" % [name, detail.to_s]
719
+ if obj
720
+ obj.remove(true)
721
+ elsif obj = self[name]
722
+ obj.remove(true)
723
+ end
724
+ return nil
725
+ end
726
+
727
+ if implicit
728
+ obj.implicit = true
729
+ end
730
+
731
+ return obj
732
+ end
733
+
734
+ def self.implicitcreate(hash)
735
+ unless hash.include?(:implicit)
736
+ hash[:implicit] = true
737
+ end
738
+ obj = self.create(hash)
739
+ obj.implicit = true
740
+
741
+ return obj
742
+ end
743
+
744
+ # Is this type's name isomorphic with the object? That is, if the
745
+ # name conflicts, does it necessarily mean that the objects conflict?
746
+ # Defaults to true.
747
+ def self.isomorphic?
748
+ if defined? @isomorphic
749
+ return @isomorphic
750
+ else
751
+ return true
752
+ end
753
+ end
754
+
755
+ # and then make 'new' private
756
+ class << self
757
+ private :new
758
+ end
759
+
760
+ # initialize the type instance
761
+ def initialize(hash)
762
+ @children = []
763
+ @evalcount = 0
764
+
765
+ # callbacks are per object and event
766
+ @callbacks = Hash.new { |chash, key|
767
+ chash[key] = {}
768
+ }
769
+
770
+ # states and parameters are treated equivalently from the outside:
771
+ # as name-value pairs (using [] and []=)
772
+ # internally, however, parameters are merely a hash, while states
773
+ # point to State objects
774
+ # further, the lists of valid states and parameters are defined
775
+ # at the class level
776
+ unless defined? @states
777
+ @states = Hash.new(false)
778
+ end
779
+ unless defined? @parameters
780
+ @parameters = Hash.new(false)
781
+ end
782
+ unless defined? @metaparams
783
+ @metaparams = Hash.new(false)
784
+ end
785
+
786
+ #unless defined? @paramdoc
787
+ # @paramdoc = Hash.new { |hash,key|
788
+ # if key.is_a?(String)
789
+ # key = key.intern
790
+ # end
791
+ # if hash.include?(key)
792
+ # hash[key]
793
+ # else
794
+ # "Param Documentation for %s not found" % key
795
+ # end
796
+ # }
797
+ #end
798
+
799
+ # set defalts
800
+ @noop = false
801
+ @metaparams[:loglevel] = :notice
802
+ # keeping stats for the total number of changes, and how many were
803
+ # completely sync'ed
804
+ # this isn't really sufficient either, because it adds lots of special cases
805
+ # such as failed changes
806
+ # it also doesn't distinguish between changes from the current transaction
807
+ # vs. changes over the process lifetime
808
+ @totalchanges = 0
809
+ @syncedchanges = 0
810
+ @failedchanges = 0
811
+
812
+ # Before anything else, set our parent if it was included
813
+ if hash.include?(:parent)
814
+ @parent = hash[:parent]
815
+ hash.delete(:parent)
816
+ end
817
+
818
+ hash = self.argclean(hash)
819
+
820
+ # now get all of the arguments, in a specific order
821
+ order = [self.class.namevar]
822
+ order << [self.class.states.collect { |state| state.name },
823
+ self.class.parameters,
824
+ self.class.eachmetaparam { |param| param }].flatten.reject { |param|
825
+ # we don't want our namevar in there multiple times
826
+ param == self.class.namevar
827
+ }
828
+
829
+ order.flatten.each { |name|
830
+ if hash.include?(name)
831
+ begin
832
+ self[name] = hash[name]
833
+ rescue => detail
834
+ raise Puppet::DevError.new(
835
+ "Could not set %s on %s: %s" % [name, self.class.name, detail]
836
+ )
837
+ end
838
+ hash.delete name
839
+ end
840
+ }
841
+
842
+ if hash.length > 0
843
+ self.debug hash.inspect
844
+ raise Puppet::Error.new("Class %s does not accept argument(s) %s" %
845
+ [self.class.name, hash.keys.join(" ")])
846
+ end
847
+
848
+ # add this object to the specific class's list of objects
849
+ #puts caller
850
+ self.class[self.name] = self
851
+ end
852
+
853
+ # Merge new information with an existing object, checking for conflicts
854
+ # and such. This allows for two specifications of the same object and
855
+ # the same values, but it's pretty limited right now. The result of merging
856
+ # states is very different from the result of merging parameters or metaparams.
857
+ # This is currently unused.
858
+ def merge(hash)
859
+ hash.each { |param, value|
860
+ if param.is_a?(String)
861
+ param = param.intern
862
+ end
863
+
864
+ # Of course names are the same, duh.
865
+ next if param == :name or param == self.class.namevar
866
+
867
+ unless value.is_a?(Array)
868
+ value = [value]
869
+ end
870
+
871
+ if oldvals = @states[param].shouldorig
872
+ unless oldvals.is_a?(Array)
873
+ oldvals = [oldvals]
874
+ end
875
+ # If the values are exactly the same, order and everything,
876
+ # then it's okay.
877
+ if oldvals == value
878
+ return true
879
+ end
880
+ # take the intersection
881
+ newvals = oldvals & value
882
+ if newvals.empty?
883
+ raise Puppet::Error, "No common values for %s on %s(%s)" %
884
+ [param, self.class.name, self.name]
885
+ elsif newvals.length > 1
886
+ raise Puppet::Error, "Too many values for %s on %s(%s)" %
887
+ [param, self.class.name, self.name]
888
+ else
889
+ self.debug "Reduced old values %s and new values %s to %s" %
890
+ [oldvals.inspect, value.inspect, newvals.inspect]
891
+ @states[param].should = newvals
892
+ #self.should = newvals
893
+ return true
894
+ end
895
+ else
896
+ self[param] = value
897
+ end
898
+ }
899
+ end
900
+
901
+ # derive the instance name based on class.namevar
902
+ def name
903
+ unless defined? @name and @name
904
+ namevar = self.class.namevar
905
+ if self.class.validparameter?(namevar)
906
+ @name = @parameters[namevar]
907
+ elsif self.class.validstate?(namevar)
908
+ @name = self.should(namevar)
909
+ else
910
+ raise Puppet::DevError, "Could not find namevar %s for %s" %
911
+ [namevar, self.class.name]
912
+ end
913
+ end
914
+
915
+ unless @name
916
+ raise Puppet::DevError, "Could not find name %s for %s" %
917
+ [namevar, self.class.name]
918
+ end
919
+
920
+ return @name
921
+ end
922
+
923
+ # fix any namevar => param translations
924
+ def argclean(hash)
925
+ # we have to set the name of our object before anything else,
926
+ # because it might be used in creating the other states
927
+ hash = hash.dup
928
+
929
+ if hash.include?(:parent)
930
+ hash.delete(:parent)
931
+ end
932
+ namevar = self.class.namevar
933
+
934
+ hash.each { |var,value|
935
+ unless var.is_a? Symbol
936
+ hash[var.intern] = value
937
+ hash.delete(var)
938
+ end
939
+ }
940
+
941
+ # if they're not using :name for the namevar but we got :name (probably
942
+ # from the parser)
943
+ if namevar != :name and hash.include?(:name) and ! hash[:name].nil?
944
+ #self[namevar] = hash[:name]
945
+ hash[namevar] = hash[:name]
946
+ hash.delete(:name)
947
+ # else if we got the namevar
948
+ elsif hash.has_key?(namevar) and ! hash[namevar].nil?
949
+ #self[namevar] = hash[namevar]
950
+ #hash.delete(namevar)
951
+ # else something's screwy
952
+ else
953
+ # they didn't specify anything related to names
954
+ end
955
+
956
+ return hash
957
+ end
958
+
959
+ # retrieve the current value of all contained states
960
+ def retrieve
961
+ # it's important to use the method here, as it follows the order
962
+ # in which they're defined in the object
963
+ states.each { |state|
964
+ state.retrieve
965
+ }
966
+ end
967
+
968
+ # sync the changes to disk, and return the events generated by the changes
969
+ # FIXME this method is essentially obviated, but it's still used by tests
970
+ # and i don't feel like fixing it yet
971
+ def sync
972
+ #raise Puppet::DevError, "Type#sync called"
973
+ events = self.collect { |child|
974
+ child.sync
975
+ }.reject { |event|
976
+ ! (event.is_a?(Symbol) or event.is_a?(String))
977
+ }.flatten
978
+
979
+ #Puppet.notice "got events %s" % events.inspect
980
+
981
+ Puppet::Metric.addevents(self.class,self,events)
982
+ return events
983
+ end
984
+
985
+ # convert to a string
986
+ def to_s
987
+ self.name
988
+ end
989
+
990
+ # instance methods dealing with actually doing work
991
+
992
+ public
993
+
994
+ # this is a retarded hack method to get around the difference between
995
+ # component children and file children
996
+ def self.depthfirst?
997
+ if defined? @depthfirst
998
+ return @depthfirst
999
+ else
1000
+ return false
1001
+ end
1002
+ end
1003
+
1004
+ # this method is responsible for collecting state changes
1005
+ # we always descend into the children before we evaluate our current
1006
+ # states
1007
+ # this returns any changes resulting from testing, thus 'collect'
1008
+ # rather than 'each'
1009
+ def evaluate
1010
+ #Puppet.err "Evaluating %s" % self.path.join(":")
1011
+ unless defined? @evalcount
1012
+ self.err "No evalcount defined on '%s' of type '%s'" %
1013
+ [self.name,self.class]
1014
+ @evalcount = 0
1015
+ end
1016
+ @@retrieved[self] += 1
1017
+ # if we're a metaclass and we've already evaluated once...
1018
+ #if self.metaclass and @evalcount > 0
1019
+ # return
1020
+ #end
1021
+ @evalcount += 1
1022
+
1023
+ #changes = @children.collect { |child|
1024
+ # child.evaluate
1025
+ #}
1026
+
1027
+ changes = []
1028
+ # collect all of the changes from children and states
1029
+ #if self.class.depthfirst?
1030
+ # changes << self.collect { |child|
1031
+ # child.evaluate
1032
+ # }
1033
+ #end
1034
+
1035
+ # this only operates on states, not states + children
1036
+ # it's important that we call retrieve() on the type instance,
1037
+ # not directly on the state, because it allows the type to override
1038
+ # the method, like pfile does
1039
+ self.retrieve
1040
+
1041
+ # states() is a private method, returning an ordered list
1042
+ unless self.class.depthfirst?
1043
+ changes << states().find_all { |state|
1044
+ ! state.insync?
1045
+ }.collect { |state|
1046
+ Puppet::StateChange.new(state)
1047
+ }
1048
+ end
1049
+
1050
+ if changes.length > 0
1051
+ # add one to the number of out-of-sync instances
1052
+ Puppet::Metric.add(self.class,self,:outofsync,1)
1053
+ end
1054
+ #end
1055
+
1056
+ changes << @children.collect { |child|
1057
+ child.evaluate
1058
+ }
1059
+ #unless self.class.depthfirst?
1060
+ # changes << self.collect { |child|
1061
+ # child.evaluate
1062
+ # }
1063
+ #end
1064
+ # collect changes and return them
1065
+ # these changes could be from child objects or from contained states
1066
+ #self.collect { |child|
1067
+ # child.evaluate
1068
+ #}
1069
+
1070
+ if self.class.depthfirst?
1071
+ changes << states().find_all { |state|
1072
+ ! state.insync?
1073
+ }.collect { |state|
1074
+ Puppet::StateChange.new(state)
1075
+ }
1076
+ end
1077
+
1078
+ changes.flatten!
1079
+
1080
+ # now record how many changes we've resulted in
1081
+ Puppet::Metric.add(self.class,self,:changes,changes.length)
1082
+ if changes.length > 0
1083
+ self.info "%s change(s)" %
1084
+ [changes.length]
1085
+ #changes.each { |change|
1086
+ # self.debug "change: %s" % change.state.name
1087
+ #}
1088
+ end
1089
+ return changes.flatten
1090
+ end
1091
+
1092
+ # if all contained objects are in sync, then we're in sync
1093
+ # FIXME I don't think this is used on the type instances any more,
1094
+ # it's really only used for testing
1095
+ def insync?
1096
+ insync = true
1097
+
1098
+ states.each { |state|
1099
+ unless state.insync?
1100
+ self.debug("%s is not in sync: %s vs %s" %
1101
+ [state, state.is, state.should])
1102
+ insync = false
1103
+ end
1104
+ }
1105
+
1106
+ #self.debug("%s sync status is %s" % [self,insync])
1107
+ return insync
1108
+ end
1109
+
1110
+ # Meta-parameter methods: These methods deal with the results
1111
+ # of specifying metaparameters
1112
+
1113
+ def self.eachmetaparam
1114
+ @@metaparams.each { |param|
1115
+ yield param
1116
+ }
1117
+ end
1118
+
1119
+ # This just marks states that we definitely want to retrieve values
1120
+ # on. There is currently no way to uncheck a parameter.
1121
+ def metacheck=(args)
1122
+ unless args.is_a?(Array)
1123
+ args = [args]
1124
+ end
1125
+
1126
+ # these are states that we might not have 'should'
1127
+ # values for but we want to retrieve 'is' values for anyway
1128
+ args.each { |state|
1129
+ unless state.is_a?(Symbol)
1130
+ state = state.intern
1131
+ end
1132
+ next if @states.include?(state)
1133
+
1134
+ stateklass = nil
1135
+ self.newstate(state)
1136
+ }
1137
+ end
1138
+
1139
+ # Is the parameter in question a meta-parameter?
1140
+ def self.metaparam?(param)
1141
+ @@metaparams.include?(param)
1142
+ end
1143
+
1144
+ # for each object we require, subscribe to all events that it
1145
+ # generates
1146
+ # we might reduce the level of subscription eventually, but for now...
1147
+ def metarequire=(requires)
1148
+ self.handledepends(requires, :NONE, nil)
1149
+ end
1150
+
1151
+ # for each object we require, subscribe to all events that it
1152
+ # generates
1153
+ # we might reduce the level of subscription eventually, but for now...
1154
+ def metasubscribe=(requires)
1155
+ self.handledepends(requires, :ALL_EVENTS, :refresh)
1156
+ end
1157
+
1158
+ def metanoop=(noop)
1159
+ if noop == "true" or noop == true
1160
+ @noop = true
1161
+ elsif noop == "false" or noop == false
1162
+ @noop = false
1163
+ else
1164
+ raise Puppet::Error.new("Invalid noop value '%s'" % noop)
1165
+ end
1166
+ end
1167
+
1168
+ # Currently nonfunctional
1169
+ def metaonerror=(response)
1170
+ self.debug("Would have called metaonerror")
1171
+ @onerror = response
1172
+ end
1173
+
1174
+ # Currently nonfunctional
1175
+ def metaschedule=(schedule)
1176
+ @schedule = schedule
1177
+ end
1178
+
1179
+ # Determines what our objects log at. Defaults to :notice.
1180
+ def metaloglevel=(loglevel)
1181
+ if loglevel.is_a?(String)
1182
+ loglevel = loglevel.intern
1183
+ end
1184
+ if loglevel == :verbose
1185
+ loglevel = :info
1186
+ end
1187
+
1188
+ if Puppet::Log.validlevel?(loglevel)
1189
+ @metaparams[:loglevel] = loglevel
1190
+ else
1191
+ raise Puppet::Error.new("Invalid loglevel '%s'" % loglevel)
1192
+ end
1193
+ end
1194
+
1195
+ # Subscription and relationship methods
1196
+
1197
+ #def addcallback(object, event, method)
1198
+ # @callbacks[object][event] = method
1199
+ #end
1200
+
1201
+ # return all objects subscribed to the current object
1202
+ def eachdependency
1203
+ Puppet::Event::Subscription.dependencies(self).each { |dep|
1204
+ yield dep.source
1205
+ }
1206
+ end
1207
+
1208
+ # return all objects subscribed to the current object
1209
+ #def eachsubscriber
1210
+ # Puppet::Event::Subscriptions.subscribers?(self).each { |sub|
1211
+ # yield sub.targetobject
1212
+ # }
1213
+ #end
1214
+
1215
+ def handledepends(requires, event, method)
1216
+ # Requires are specified in the form of [type, name], so they're always
1217
+ # an array. But we want them to be an array of arrays.
1218
+ unless requires[0].is_a?(Array)
1219
+ requires = [requires]
1220
+ end
1221
+ requires.each { |rname|
1222
+ # we just have a name and a type, and we need to convert it
1223
+ # to an object...
1224
+ type = nil
1225
+ object = nil
1226
+ tname = rname[0]
1227
+ unless type = Puppet::Type.type(tname)
1228
+ raise Puppet::Error, "Could not find type %s" % tname
1229
+ end
1230
+ name = rname[1]
1231
+ unless object = type[name]
1232
+ raise Puppet::Error, "Could not retrieve object '%s' of type '%s'" %
1233
+ [name,type]
1234
+ end
1235
+ self.debug("subscribes to %s" % [object])
1236
+
1237
+ #unless @dependencies.include?(object)
1238
+ # @dependencies << object
1239
+ #end
1240
+
1241
+ # pure requires don't call methods
1242
+ #next if method.nil?
1243
+
1244
+ # ok, both sides of the connection store some information
1245
+ # we store the method to call when a given subscription is
1246
+ # triggered, but the source object decides whether
1247
+ subargs = {
1248
+ :event => event,
1249
+ :source => object,
1250
+ :target => self
1251
+ }
1252
+ if method and self.respond_to?(method)
1253
+ subargs[:callback] = method
1254
+ end
1255
+ Puppet::Event::Subscription.new(subargs)
1256
+ #if self.respond_to?(method)
1257
+ # self.addcallback(object, event, method)
1258
+ #end
1259
+ #object.addnotify(self)
1260
+ }
1261
+ end
1262
+
1263
+ # Trigger any associated subscriptions, and then pass the event up to our
1264
+ # parent.
1265
+ def propagate(event, transaction)
1266
+ Puppet::Event::Subscription.trigger(self, event, transaction)
1267
+
1268
+ if defined? @parent
1269
+ @parent.propagate(event, transaction)
1270
+ end
1271
+ end
1272
+
1273
+ def subscribe(hash)
1274
+ hash[:source] = self
1275
+ Puppet::Event::Subscription.new(hash)
1276
+
1277
+ # add to the correct area
1278
+ #@subscriptions.push sub
1279
+ end
1280
+
1281
+ # Unsubscribe from a given object, possibly with a specific event.
1282
+ def unsubscribe(object, event = nil)
1283
+ Puppet::Event::Subscription.dependencies(self).find_all { |sub|
1284
+ if event
1285
+ sub.match?(event)
1286
+ else
1287
+ sub.source == object
1288
+ end
1289
+ }.each { |sub|
1290
+ Puppet::Event::Subscription.delete(sub)
1291
+ }
1292
+ end
1293
+
1294
+ # return all of the subscriptions to a given event
1295
+ #def subscribers?(event)
1296
+ # Puppet::Event::Subscription.subscriptions(self).find_all { |sub|
1297
+ # sub.match?(event)
1298
+ # }.collect { |sub|
1299
+ # sub.target
1300
+ # }
1301
+ #end
1302
+
1303
+ # we've received an event
1304
+ # we only support local events right now, so we can pass actual
1305
+ # objects around, including the transaction object
1306
+ # the assumption here is that container objects will pass received
1307
+ # methods on to contained objects
1308
+ # i.e., we don't trigger our children, our refresh() method calls
1309
+ # refresh() on our children
1310
+ def trigger(event, source)
1311
+ trans = event.transaction
1312
+ if @callbacks.include?(source)
1313
+ [:ALL_EVENTS, event.event].each { |eventname|
1314
+ if method = @callbacks[source][eventname]
1315
+ if trans.triggered?(self, method) > 0
1316
+ next
1317
+ end
1318
+ if self.respond_to?(method)
1319
+ self.send(method)
1320
+ end
1321
+
1322
+ trans.triggered(self, method)
1323
+ end
1324
+ }
1325
+ end
1326
+ end
1327
+
1328
+ # Documentation methods
1329
+ def self.paramdoc(param)
1330
+ @paramdoc[param]
1331
+ end
1332
+ def self.metaparamdoc(metaparam)
1333
+ @@metaparamdoc[metaparam]
1334
+ end
1335
+ end # Puppet::Type
1336
+ end
1337
+
1338
+ require 'puppet/statechange'
1339
+ require 'puppet/type/component'
1340
+ require 'puppet/type/cron'
1341
+ require 'puppet/type/exec'
1342
+ require 'puppet/type/group'
1343
+ require 'puppet/type/package'
1344
+ require 'puppet/type/pfile'
1345
+ require 'puppet/type/pfilebucket'
1346
+ require 'puppet/type/service'
1347
+ require 'puppet/type/symlink'
1348
+ require 'puppet/type/user'
1349
+ require 'puppet/type/tidy'
1350
+ #require 'puppet/type/typegen'
1351
+ #require 'puppet/type/typegen/filetype'
1352
+ #require 'puppet/type/typegen/filerecord'
1353
+
1354
+ # $Id: type.rb 742 2005-11-16 17:12:11Z luke $