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,755 @@
1
+ # The scope class, which handles storing and retrieving variables and types and
2
+ # such.
3
+
4
+ require 'puppet/transportable'
5
+
6
+ module Puppet
7
+ module Parser
8
+ class Scope
9
+ include Enumerable
10
+ attr_accessor :parent, :level, :interp
11
+ attr_accessor :name, :type, :topscope, :base
12
+
13
+ # This is probably not all that good of an idea, but...
14
+ # This way a parent can share its tables with all of its children.
15
+ attr_writer :nodetable, :classtable, :definedtable
16
+
17
+ # Whether we behave declaratively. Note that it's a class variable,
18
+ # so all scopes behave the same.
19
+ @@declarative = true
20
+
21
+ # Retrieve and set the declarative setting.
22
+ def Scope.declarative
23
+ return @@declarative
24
+ end
25
+
26
+ def Scope.declarative=(val)
27
+ @@declarative = val
28
+ end
29
+
30
+ # Add a single object's tags to the global list of tags for
31
+ # that object.
32
+ def addtags(obj)
33
+ unless defined? @tagtable
34
+ raise Puppet::DevError, "Told to add tags, but no tag table"
35
+ end
36
+ list = @tagtable[obj.type][obj.name]
37
+
38
+ obj.tags.each { |tag|
39
+ unless list.include?(tag)
40
+ if tag.nil? or tag == ""
41
+ Puppet.warning "Got tag %s from %s(%s)" %
42
+ [tag.inspect, obj.type, obj.name]
43
+ else
44
+ list << tag
45
+ end
46
+ end
47
+ }
48
+ end
49
+
50
+ # Log the existing tags. At some point this should be in a better
51
+ # place, but eh.
52
+ def logtags
53
+ @tagtable.sort { |a, b|
54
+ a[0] <=> b[0]
55
+ }.each { |type, names|
56
+ names.sort { |a, b|
57
+ a[0] <=> b[0]
58
+ }.each { |name, tags|
59
+ Puppet.info "%s(%s): '%s'" % [type, name, tags.join("' '")]
60
+ }
61
+ }
62
+ end
63
+
64
+ # Create a new child scope.
65
+ def child=(scope)
66
+ @children.push(scope)
67
+
68
+ if defined? @nodetable
69
+ scope.nodetable = @nodetable
70
+ else
71
+ raise Puppet::DevError, "No nodetable has been defined"
72
+ end
73
+
74
+ if defined? @classtable
75
+ scope.classtable = @classtable
76
+ else
77
+ raise Puppet::DevError, "No classtable has been defined"
78
+ end
79
+
80
+ if defined? @definedtable
81
+ scope.definedtable = @definedtable
82
+ else
83
+ raise Puppet::DevError, "No definedtable has been defined"
84
+ end
85
+ end
86
+
87
+ # Test whether a given scope is declarative. Even though it's
88
+ # a global value, the calling objects don't need to know that.
89
+ def declarative?
90
+ @@declarative
91
+ end
92
+
93
+ # Remove a specific child.
94
+ def delete(child)
95
+ @children.delete(child)
96
+ end
97
+
98
+ # Verify that no nodescopes are hanging around.
99
+ def nodeclean
100
+ @children.find_all { |child|
101
+ if child.is_a?(Scope)
102
+ child.nodescope?
103
+ else
104
+ false
105
+ end
106
+ }.each { |child|
107
+ @children.delete(child)
108
+ }
109
+
110
+ @children.each { |child|
111
+ if child.is_a?(Scope)
112
+ child.nodeclean
113
+ end
114
+ }
115
+ end
116
+
117
+ # Is this scope associated with being a node? The answer determines
118
+ # whether we store class instances here
119
+ def nodescope?
120
+ @nodescope
121
+ end
122
+
123
+ # Mark that we are a nodescope.
124
+ def isnodescope
125
+ @nodescope = true
126
+
127
+ # Also, create the extra tables associated with being a node
128
+ # scope.
129
+ # The table for storing class singletons.
130
+ @classtable = Hash.new(nil)
131
+
132
+ # Also, create the object checking map
133
+ @definedtable = Hash.new { |types, type|
134
+ types[type] = {}
135
+ }
136
+ end
137
+
138
+ # Has a given object been defined anywhere in the scope tree?
139
+ def objectdefined?(name, type)
140
+ unless defined? @definedtable
141
+ raise Puppet::DevError, "Scope did not receive definedtable"
142
+ end
143
+
144
+ return @definedtable[type][name]
145
+ end
146
+
147
+ # Are we the top scope?
148
+ def topscope?
149
+ @level == 1
150
+ end
151
+
152
+ # Yield each child scope in turn
153
+ def each
154
+ @children.reject { |child|
155
+ yield child
156
+ }
157
+ end
158
+
159
+ # Evaluate a specific node's code. This method will normally be called
160
+ # on the top-level scope, but it actually evaluates the node at the
161
+ # appropriate scope.
162
+ def evalnode(names, facts)
163
+ scope = code = nil
164
+
165
+ # Find a node that matches one of our names
166
+ names.each { |node|
167
+ if hash = @nodetable[node]
168
+ code = hash[:node]
169
+ scope = hash[:scope]
170
+ break
171
+ end
172
+ }
173
+
174
+ # And fail if we don't find one.
175
+ unless scope and code
176
+ raise Puppet::Error, "Could not find configuration for %s" %
177
+ names.join(" or ")
178
+ end
179
+
180
+ # First make sure there aren't any other node scopes lying around
181
+ self.nodeclean
182
+
183
+ # We need to do a little skullduggery here. We want a
184
+ # temporary scope, because we don't want this scope to
185
+ # show up permanently in the scope tree -- otherwise we could
186
+ # not evaluate the node multiple times. We could conceivably
187
+ # cache the results, but it's not worth it at this stage.
188
+
189
+ # Note that we evaluate the node code with its containing
190
+ # scope, not with the top scope.
191
+ code.safeevaluate(scope, facts)
192
+
193
+ # We don't need to worry about removing the Node code because
194
+ # it will be removed during translation.
195
+
196
+ # And now return the whole thing
197
+ #return self.to_trans
198
+ objects = self.to_trans
199
+
200
+ # I should do something to add the node as an object with tags
201
+ # but that will possibly end up with far too many tags.
202
+ #self.logtags
203
+ return objects
204
+ end
205
+
206
+ # Retrieve a specific node. This is used in ast.rb to find a
207
+ # parent node and in findnode to retrieve and evaluate a node.
208
+ def node(name)
209
+ @nodetable[name]
210
+ end
211
+
212
+ # Store a host in the site node table.
213
+ def setnode(name,code)
214
+ unless defined? @nodetable
215
+ raise Puppet::DevError, "No node table defined"
216
+ end
217
+ if @nodetable.include?(name)
218
+ raise Puppet::ParseError, "Host %s is already defined" % name
219
+ else
220
+ #Puppet.warning "Setting node %s at level %s" % [name, @level]
221
+
222
+ # We have to store both the scope that's setting the node and
223
+ # the node itself, so that the node gets evaluated in the correct
224
+ # scope.
225
+ @nodetable[name] = {
226
+ :scope => self,
227
+ :node => code
228
+ }
229
+ end
230
+ end
231
+
232
+ # Evaluate normally, with no node definitions. This is a bit of a
233
+ # silly method, in that it just calls evaluate on the passed-in
234
+ # objects, and then calls to_trans on itself. It just conceals
235
+ # a paltry amount of info from whomever's using the scope object.
236
+ def evaluate(objects, facts = {}, classes = [])
237
+ facts.each { |var, value|
238
+ self.setvar(var, value)
239
+ }
240
+
241
+ objects.safeevaluate(self)
242
+
243
+ # These classes would be passed in manually, via something like
244
+ # a cfengine module
245
+ classes.each { |klass|
246
+ if code = self.lookuptype(klass)
247
+ code.safeevaluate(self, {}, klass, klass)
248
+ end
249
+ }
250
+
251
+ return self.to_trans
252
+ end
253
+
254
+ # Initialize our new scope. Defaults to having no parent and to
255
+ # being declarative.
256
+ def initialize(parent = nil, declarative = true)
257
+ @parent = parent
258
+ @nodescope = false
259
+
260
+ @tags = []
261
+
262
+ if @parent.nil?
263
+ # the level is mostly used for debugging
264
+ @level = 1
265
+
266
+ @@declarative = declarative
267
+
268
+ # The table for storing class singletons. This will only actually
269
+ # be used by top scopes and node scopes.
270
+ @classtable = Hash.new(nil)
271
+
272
+ # The table for all defined objects. This will only be
273
+ # used in the top scope if we don't have any nodescopes.
274
+ @definedtable = Hash.new { |types, type|
275
+ types[type] = {}
276
+ }
277
+
278
+ # A table for storing nodes.
279
+ @nodetable = Hash.new(nil)
280
+
281
+ # Eventually, if we support sites, this will allow definitions
282
+ # of nodes with the same name in different sites. For now
283
+ # the top-level scope is always the only site scope.
284
+ @sitescope = true
285
+
286
+ # We're the top scope, so record that fact for our children
287
+ @topscope = self
288
+
289
+ # And create a tag table, so we can collect all of the tags
290
+ # associated with any objects created in this scope tree
291
+ @tagtable = Hash.new { |types, type|
292
+ types[type] = Hash.new { |names, name|
293
+ names[name] = []
294
+ }
295
+ }
296
+ else
297
+ @parent.child = self
298
+ @level = @parent.level + 1
299
+ @interp = @parent.interp
300
+ @topscope = @parent.topscope
301
+ end
302
+
303
+ # Our child scopes
304
+ @children = []
305
+
306
+ # The symbol table for this scope
307
+ @symtable = Hash.new(nil)
308
+
309
+ # The type table for this scope
310
+ @typetable = Hash.new(nil)
311
+
312
+ # All of the defaults set for types. It's a hash of hashes,
313
+ # with the first key being the type, then the second key being
314
+ # the parameter.
315
+ @defaultstable = Hash.new { |dhash,type|
316
+ dhash[type] = Hash.new(nil)
317
+ }
318
+
319
+ # The object table is similar, but it is actually a hash of hashes
320
+ # where the innermost objects are TransObject instances.
321
+ @objectable = Hash.new { |typehash,typekey|
322
+ #hash[key] = TransObject.new(key)
323
+ typehash[typekey] = Hash.new { |namehash, namekey|
324
+ #Puppet.debug("Creating iobject with name %s and type %s" %
325
+ # [namekey,typekey])
326
+ namehash[namekey] = TransObject.new(namekey,typekey)
327
+ @children.push namehash[namekey]
328
+
329
+ # this has to be last, because the return value of the
330
+ # block is the actual hash
331
+ namehash[namekey]
332
+ }
333
+ }
334
+
335
+ # Map the names to the tables.
336
+ @map = {
337
+ "variable" => @symtable,
338
+ "type" => @typetable,
339
+ "node" => @nodetable,
340
+ "object" => @objectable,
341
+ "defaults" => @defaultstable
342
+ }
343
+ end
344
+
345
+ # This method abstracts recursive searching. It accepts the type
346
+ # of search being done and then either a literal key to search for or
347
+ # a Proc instance to do the searching.
348
+ def lookup(type,sub)
349
+ table = @map[type]
350
+ if table.nil?
351
+ error = Puppet::ParseError.new(
352
+ "Could not retrieve %s table at level %s" %
353
+ [type,self.level]
354
+ )
355
+ error.stack = caller
356
+ raise error
357
+ end
358
+
359
+ if sub.is_a?(Proc) and obj = sub.call(table)
360
+ return obj
361
+ elsif table.include?(sub)
362
+ return table[sub]
363
+ elsif ! @parent.nil?
364
+ return @parent.lookup(type,sub)
365
+ else
366
+ return :undefined
367
+ end
368
+ end
369
+
370
+ # Look up a given class. This enables us to make sure classes are
371
+ # singletons
372
+ def lookupclass(klass)
373
+ unless defined? @classtable
374
+ raise Puppet::DevError, "Scope did not receive class table"
375
+ end
376
+ return @classtable[klass]
377
+ end
378
+
379
+ # Collect all of the defaults set at any higher scopes.
380
+ # This is a different type of lookup because it's additive --
381
+ # it collects all of the defaults, with defaults in closer scopes
382
+ # overriding those in later scopes.
383
+ def lookupdefaults(type)
384
+ values = {}
385
+
386
+ # first collect the values from the parents
387
+ unless @parent.nil?
388
+ @parent.lookupdefaults(type).each { |var,value|
389
+ values[var] = value
390
+ }
391
+ end
392
+
393
+ # then override them with any current values
394
+ # this should probably be done differently
395
+ if @defaultstable.include?(type)
396
+ @defaultstable[type].each { |var,value|
397
+ values[var] = value
398
+ }
399
+ end
400
+ #Puppet.debug "Got defaults for %s: %s" %
401
+ # [type,values.inspect]
402
+ return values
403
+ end
404
+
405
+ # Look up a node by name
406
+ def lookupnode(name)
407
+ Puppet.debug "Looking up type %s" % name
408
+ value = self.lookup("type",name)
409
+ if value == :undefined
410
+ return nil
411
+ else
412
+ Puppet.debug "Found type %s" % name
413
+ return value
414
+ end
415
+ end
416
+
417
+ # Look up a defined type.
418
+ def lookuptype(name)
419
+ Puppet.debug "Looking up type %s" % name
420
+ value = self.lookup("type",name)
421
+ if value == :undefined
422
+ return nil
423
+ else
424
+ Puppet.debug "Found type %s" % name
425
+ return value
426
+ end
427
+ end
428
+
429
+ # Look up an object by name and type.
430
+ def lookupobject(name,type)
431
+ Puppet.debug "Looking up object %s of type %s in level %s" %
432
+ [name, type, @level]
433
+ sub = proc { |table|
434
+ if table.include?(type)
435
+ if table[type].include?(name)
436
+ table[type][name]
437
+ end
438
+ else
439
+ nil
440
+ end
441
+ }
442
+ value = self.lookup("object",sub)
443
+ if value == :undefined
444
+ return nil
445
+ else
446
+ return value
447
+ end
448
+ end
449
+
450
+ # Look up a variable. The simplest value search we do.
451
+ def lookupvar(name)
452
+ Puppet.debug "Looking up variable %s" % name
453
+ value = self.lookup("variable", name)
454
+ if value == :undefined
455
+ error = Puppet::ParseError.new(
456
+ "Undefined variable '%s'" % name
457
+ )
458
+ error.stack = caller
459
+ raise error
460
+ else
461
+ #Puppet.debug "Value of '%s' is '%s'" % [name,value]
462
+ return value
463
+ end
464
+ end
465
+
466
+ # Create a new scope.
467
+ def newscope
468
+ Puppet.debug "Creating new scope, level %s" % [self.level + 1]
469
+ return Puppet::Parser::Scope.new(self)
470
+ end
471
+
472
+ # Store the fact that we've evaluated a given class.
473
+ # FIXME Shouldn't setclass actually store the code, not just a boolean?
474
+ def setclass(klass)
475
+ if self.nodescope? or self.topscope?
476
+ @classtable[klass] = true
477
+ else
478
+ @parent.setclass(klass)
479
+ end
480
+ end
481
+
482
+ # Set defaults for a type. The typename should already be downcased,
483
+ # so that the syntax is isolated.
484
+ def setdefaults(type,params)
485
+ table = @defaultstable[type]
486
+
487
+ # if we got a single param, it'll be in its own array
488
+ unless params[0].is_a?(Array)
489
+ params = [params]
490
+ end
491
+
492
+ params.each { |ary|
493
+ Puppet.debug "Default for %s is %s => %s" %
494
+ [type,ary[0].inspect,ary[1].inspect]
495
+ if @@declarative
496
+ if table.include?(ary[0])
497
+ error = Puppet::ParseError.new(
498
+ "Default already defined for %s { %s }" %
499
+ [type,ary[0]]
500
+ )
501
+ error.stack = caller
502
+ raise error
503
+ end
504
+ else
505
+ if table.include?(ary[0])
506
+ # we should maybe allow this warning to be turned off...
507
+ Puppet.warning "Replacing default for %s { %s }" %
508
+ [type,ary[0]]
509
+ end
510
+ end
511
+ table[ary[0]] = ary[1]
512
+ }
513
+ end
514
+
515
+ # Define our type.
516
+ def settype(name,ltype)
517
+ @typetable[name] = ltype
518
+ end
519
+
520
+ # Return an interpolated string.
521
+ # FIXME We do not yet support a non-interpolated string.
522
+ def strinterp(string)
523
+ newstring = string.dup
524
+ regex = Regexp.new('\$\{(\w+)\}|\$(\w+)')
525
+ #Puppet.debug("interpreting '%s'" % string)
526
+ while match = regex.match(newstring) do
527
+ if match[1]
528
+ newstring.sub!(regex,self.lookupvar(match[1]).to_s)
529
+ elsif match[2]
530
+ newstring.sub!(regex,self.lookupvar(match[2]).to_s)
531
+ else
532
+ raise Puppet::DevError, "Could not match variable in %s" %
533
+ newstring
534
+ end
535
+ end
536
+ #Puppet.debug("result is '%s'" % newstring)
537
+ return newstring
538
+ end
539
+
540
+ # This method will fail if the named object is already defined anywhere
541
+ # in the scope tree, which is what provides some minimal closure-like
542
+ # behaviour.
543
+ def setobject(type, name, params, file, line)
544
+ # First see if we can look the object up using normal scope
545
+ # rules, i.e., one of our parent classes has defined the
546
+ # object or something
547
+ obj = self.lookupobject(name,type)
548
+
549
+ # If we can't find it...
550
+ if obj == :undefined or obj.nil?
551
+ # Make sure it's not defined elsewhere in the configuration
552
+ if tmp = self.objectdefined?(name, type)
553
+ typeklass = Puppet::Type.type(type)
554
+ if typeklass and ! typeklass.isomorphic?
555
+ Puppet.info "Allowing duplicate %s" % type
556
+ else
557
+ msg = "Duplicate definition: %s[%s] is already defined" %
558
+ [type, name]
559
+ error = Puppet::ParseError.new(msg)
560
+ if tmp.line
561
+ error.line = tmp.line
562
+ end
563
+ if tmp.file
564
+ error.file = tmp.file
565
+ end
566
+ raise error
567
+ end
568
+ end
569
+
570
+ # And if it's not, then create it anew
571
+ obj = @objectable[type][name]
572
+
573
+ # only set these if we've created the object, which is the
574
+ # most common case
575
+ obj.file = file
576
+ obj.line = line
577
+ end
578
+
579
+ # Now add our parameters. This has the function of overriding
580
+ # existing values, which might have been defined in a higher
581
+ # scope.
582
+ params.each { |var,value|
583
+ obj[var] = value
584
+ }
585
+
586
+ # And finally store the fact that we've defined this object.
587
+ @definedtable[type][name] = obj
588
+
589
+ return obj
590
+ end
591
+
592
+ # Set a variable in the current scope. This will override settings
593
+ # in scopes above, but will not allow variables in the current scope
594
+ # to be reassigned if we're declarative (which is the default).
595
+ def setvar(name,value)
596
+ Puppet.debug "Setting %s to '%s' at level %s" %
597
+ [name.inspect,value,self.level]
598
+ if @@declarative and @symtable.include?(name)
599
+ error = Puppet::ParseError.new(
600
+ "Cannot reassign variable %s" % name
601
+ )
602
+ error.stack = caller
603
+ raise error
604
+ else
605
+ if @symtable.include?(name)
606
+ Puppet.warning "Reassigning %s to %s" % [name,value]
607
+ end
608
+ @symtable[name] = value
609
+ end
610
+ end
611
+
612
+ # Add a tag to our current list. These tags will be added to all
613
+ # of the objects contained in this scope.
614
+ def tag(*ary)
615
+ ary.each { |tag|
616
+ if tag.nil? or tag == ""
617
+ Puppet.warning "got told to tag with %s" % tag.inspect
618
+ end
619
+ unless @tags.include?(tag)
620
+ #Puppet.info "Tagging scope %s with %s" % [self.object_id, tag]
621
+ @tags << tag.to_s
622
+ end
623
+ }
624
+ end
625
+
626
+ # Return the tags associated with this scope. It's basically
627
+ # just our parents' tags, plus our type.
628
+ def tags
629
+ tmp = [] + @tags
630
+ unless ! defined? @type or @type.nil? or @type == ""
631
+ tmp << @type.to_s
632
+ end
633
+ if @parent
634
+ @parent.tags.each { |tag|
635
+ if tag.nil? or tag == ""
636
+ Puppet.warning "parent returned tag %s" % tag.inspect
637
+ end
638
+ unless tmp.include?(tag)
639
+ tmp << tag
640
+ end
641
+ }
642
+ end
643
+ return tmp
644
+ end
645
+
646
+ # Convert our scope to a list of Transportable objects.
647
+ def to_trans
648
+ #Puppet.debug "Translating scope %s at level %s" %
649
+ # [self.object_id,self.level]
650
+
651
+ results = []
652
+
653
+ # Iterate across our child scopes and call to_trans on them
654
+ @children.each { |child|
655
+ if child.is_a?(Scope)
656
+ cresult = child.to_trans
657
+ #Puppet.debug "Got %s from scope %s" %
658
+ # [cresult.class,child.object_id]
659
+
660
+ # Scopes normally result in a TransBucket, but they could
661
+ # also result in a normal array; if that happens, get rid
662
+ # of the array.
663
+ unless cresult.is_a?(TransBucket)
664
+ cresult.each { |result|
665
+ results.push(result)
666
+ }
667
+ else
668
+ unless cresult.empty?
669
+ # Otherwise, just add it to our list of results.
670
+ results.push(cresult)
671
+ end
672
+ end
673
+
674
+ # Nodescopes are one-time; once they've been evaluated
675
+ # I need to destroy them. Nodeclean makes sure this is
676
+ # done correctly, but this should catch most of them.
677
+ if child.nodescope?
678
+ @children.delete(child)
679
+ end
680
+ elsif child.is_a?(TransObject)
681
+ if child.empty?
682
+ next
683
+ end
684
+ # Wait until the last minute to set tags, although this
685
+ # probably should not matter
686
+ child.tags = self.tags
687
+
688
+ # Then make sure this child's tags are stored in the
689
+ # central table. This should maybe be in the evaluate
690
+ # methods, but, eh.
691
+ @topscope.addtags(child)
692
+ results.push(child)
693
+ else
694
+ error = Puppet::DevError.new(
695
+ "Puppet::Parse::Scope cannot handle objects of type %s" %
696
+ child.class
697
+ )
698
+ error.stack = caller
699
+ raise error
700
+ end
701
+ }
702
+
703
+ # Get rid of any nil objects.
704
+ results = results.reject { |child|
705
+ child.nil?
706
+ }
707
+
708
+ # If we have a name and type, then make a TransBucket, which
709
+ # becomes a component.
710
+ # Else, just stack all of the objects into the current bucket.
711
+ if defined? @name
712
+ bucket = TransBucket.new
713
+ bucket.name = @name
714
+
715
+ # it'd be nice not to have to do this...
716
+ results.each { |result|
717
+ #Puppet.debug "Result type is %s" % result.class
718
+ bucket.push(result)
719
+ }
720
+ if defined? @type
721
+ bucket.type = @type
722
+ else
723
+ error = Puppet::ParseError.new(
724
+ "No type for scope %s" % @name
725
+ )
726
+ error.stack = caller
727
+ raise error
728
+ end
729
+ #Puppet.debug(
730
+ # "TransBucket with name %s and type %s in scope %s" %
731
+ # [@name,@type,self.object_id]
732
+ #)
733
+
734
+ # now find metaparams
735
+ @symtable.each { |var,value|
736
+ if Puppet::Type.metaparam?(var.intern)
737
+ #Puppet.debug("Adding metaparam %s" % var)
738
+ bucket.param(var,value)
739
+ else
740
+ #Puppet.debug("%s is not a metaparam" % var)
741
+ end
742
+ }
743
+ #Puppet.debug "Returning bucket %s from scope %s" %
744
+ # [bucket.name,self.object_id]
745
+ return bucket
746
+ else
747
+ Puppet.debug "nameless scope; just returning a list"
748
+ return results
749
+ end
750
+ end
751
+ end
752
+ end
753
+ end
754
+
755
+ # $Id: scope.rb 746 2005-11-17 21:03:19Z luke $