puppet 0.16.0 → 0.18.4

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 (185) hide show
  1. data/CHANGELOG +98 -0
  2. data/Rakefile +5 -1
  3. data/bin/puppet +1 -1
  4. data/bin/puppetca +25 -11
  5. data/bin/puppetd +189 -66
  6. data/bin/puppetdoc +79 -62
  7. data/bin/puppetmasterd +93 -49
  8. data/bin/puppetrun +385 -0
  9. data/conf/redhat/client.init +5 -2
  10. data/conf/redhat/fileserver.conf +1 -1
  11. data/conf/redhat/lsb-config.patch +51 -0
  12. data/conf/redhat/puppet.spec +45 -18
  13. data/conf/redhat/puppetd.conf +32 -4
  14. data/conf/redhat/server.init +5 -2
  15. data/conf/solaris/pkginfo +7 -0
  16. data/conf/solaris/smf/puppetd.xml +77 -0
  17. data/conf/solaris/smf/puppetmasterd.xml +77 -0
  18. data/conf/solaris/smf/svc-puppetd +66 -0
  19. data/conf/solaris/smf/svc-puppetmasterd +62 -0
  20. data/examples/code/failers/noobjectrvalue +1 -0
  21. data/examples/code/snippets/deepclassheirarchy.pp +23 -0
  22. data/examples/code/snippets/defineoverrides.pp +17 -0
  23. data/examples/code/snippets/emptyexec.pp +3 -0
  24. data/examples/code/snippets/selectorvalues.pp +6 -1
  25. data/examples/code/snippets/tagged.pp +35 -0
  26. data/ext/ldap/puppet.schema +2 -2
  27. data/install.rb +4 -2
  28. data/lib/puppet.rb +206 -15
  29. data/lib/puppet/client.rb +30 -20
  30. data/lib/puppet/client/ca.rb +2 -2
  31. data/lib/puppet/client/dipper.rb +5 -9
  32. data/lib/puppet/client/master.rb +224 -44
  33. data/lib/puppet/client/pelement.rb +54 -9
  34. data/lib/puppet/client/proxy.rb +3 -2
  35. data/lib/puppet/client/reporter.rb +34 -0
  36. data/lib/puppet/client/runner.rb +17 -0
  37. data/lib/puppet/config.rb +136 -55
  38. data/lib/puppet/daemon.rb +59 -37
  39. data/lib/puppet/element.rb +2 -1
  40. data/lib/puppet/event.rb +14 -3
  41. data/lib/puppet/filetype.rb +28 -19
  42. data/lib/puppet/log.rb +297 -132
  43. data/lib/puppet/metric.rb +31 -131
  44. data/lib/puppet/networkclient.rb +73 -46
  45. data/lib/puppet/parameter.rb +49 -1
  46. data/lib/puppet/parsedfile.rb +32 -12
  47. data/lib/puppet/parser/ast.rb +6 -1
  48. data/lib/puppet/parser/ast/astarray.rb +32 -6
  49. data/lib/puppet/parser/ast/collection.rb +91 -0
  50. data/lib/puppet/parser/ast/compdef.rb +2 -2
  51. data/lib/puppet/parser/ast/component.rb +24 -11
  52. data/lib/puppet/parser/ast/function.rb +50 -0
  53. data/lib/puppet/parser/ast/hostclass.rb +70 -22
  54. data/lib/puppet/parser/ast/node.rb +17 -8
  55. data/lib/puppet/parser/ast/nodedef.rb +1 -1
  56. data/lib/puppet/parser/ast/objectdef.rb +28 -10
  57. data/lib/puppet/parser/ast/selector.rb +4 -1
  58. data/lib/puppet/parser/functions.rb +145 -0
  59. data/lib/puppet/parser/interpreter.rb +243 -86
  60. data/lib/puppet/parser/lexer.rb +5 -4
  61. data/lib/puppet/parser/parser.rb +586 -505
  62. data/lib/puppet/parser/scope.rb +337 -187
  63. data/lib/puppet/rails.rb +115 -0
  64. data/lib/puppet/rails/database.rb +40 -0
  65. data/lib/puppet/rails/host.rb +83 -0
  66. data/lib/puppet/rails/rails_object.rb +42 -0
  67. data/lib/puppet/rails/rails_parameter.rb +5 -0
  68. data/lib/puppet/reports/rrdgraph.rb +20 -0
  69. data/lib/puppet/reports/tagmail.rb +94 -0
  70. data/lib/puppet/server.rb +20 -4
  71. data/lib/puppet/server/authconfig.rb +14 -3
  72. data/lib/puppet/server/authstore.rb +2 -2
  73. data/lib/puppet/server/ca.rb +23 -11
  74. data/lib/puppet/server/filebucket.rb +10 -10
  75. data/lib/puppet/server/fileserver.rb +4 -8
  76. data/lib/puppet/server/master.rb +19 -22
  77. data/lib/puppet/server/pelement.rb +28 -16
  78. data/lib/puppet/server/report.rb +184 -0
  79. data/lib/puppet/server/runner.rb +62 -0
  80. data/lib/puppet/server/servlet.rb +23 -9
  81. data/lib/puppet/sslcertificates/ca.rb +25 -1
  82. data/lib/puppet/statechange.rb +34 -53
  83. data/lib/puppet/storage.rb +1 -2
  84. data/lib/puppet/transaction.rb +305 -133
  85. data/lib/puppet/transaction/report.rb +42 -0
  86. data/lib/puppet/transportable.rb +57 -33
  87. data/lib/puppet/type.rb +260 -127
  88. data/lib/puppet/type/component.rb +9 -21
  89. data/lib/puppet/type/cron.rb +367 -116
  90. data/lib/puppet/type/exec.rb +15 -16
  91. data/lib/puppet/type/group.rb +9 -1
  92. data/lib/puppet/type/nameservice.rb +2 -5
  93. data/lib/puppet/type/nameservice/netinfo.rb +3 -0
  94. data/lib/puppet/type/nameservice/objectadd.rb +23 -10
  95. data/lib/puppet/type/nameservice/pw.rb +16 -3
  96. data/lib/puppet/type/package.rb +25 -75
  97. data/lib/puppet/type/package/apple.rb +15 -1
  98. data/lib/puppet/type/package/apt.rb +37 -2
  99. data/lib/puppet/type/package/blastwave.rb +136 -0
  100. data/lib/puppet/type/package/dpkg.rb +4 -4
  101. data/lib/puppet/type/package/gem.rb +119 -0
  102. data/lib/puppet/type/package/openbsd.rb +7 -6
  103. data/lib/puppet/type/package/ports.rb +7 -2
  104. data/lib/puppet/type/package/rpm.rb +1 -1
  105. data/lib/puppet/type/package/sun.rb +23 -9
  106. data/lib/puppet/type/package/sunfreeware.rb +7 -0
  107. data/lib/puppet/type/package/yum.rb +16 -9
  108. data/lib/puppet/type/parsedtype.rb +7 -5
  109. data/lib/puppet/type/parsedtype/mount.rb +55 -34
  110. data/lib/puppet/type/parsedtype/port.rb +7 -1
  111. data/lib/puppet/type/parsedtype/sshkey.rb +6 -16
  112. data/lib/puppet/type/pfile.rb +115 -23
  113. data/lib/puppet/type/pfile/checksum.rb +18 -5
  114. data/lib/puppet/type/pfile/content.rb +2 -2
  115. data/lib/puppet/type/pfile/ensure.rb +3 -3
  116. data/lib/puppet/type/pfile/group.rb +2 -2
  117. data/lib/puppet/type/pfile/source.rb +28 -17
  118. data/lib/puppet/type/pfile/target.rb +25 -17
  119. data/lib/puppet/type/pfilebucket.rb +25 -6
  120. data/lib/puppet/type/schedule.rb +6 -6
  121. data/lib/puppet/type/service.rb +24 -14
  122. data/lib/puppet/type/service/debian.rb +1 -1
  123. data/lib/puppet/type/service/redhat.rb +13 -10
  124. data/lib/puppet/type/service/smf.rb +3 -3
  125. data/lib/puppet/type/state.rb +1 -2
  126. data/lib/puppet/type/symlink.rb +3 -4
  127. data/lib/puppet/type/user.rb +22 -10
  128. data/lib/puppet/type/yumrepo.rb +6 -1
  129. data/lib/puppet/type/zone.rb +595 -0
  130. data/lib/puppet/util.rb +58 -12
  131. data/test/client/client.rb +2 -2
  132. data/test/client/master.rb +92 -3
  133. data/test/client/pelement.rb +99 -0
  134. data/test/executables/puppetbin.rb +3 -4
  135. data/test/executables/puppetca.rb +3 -3
  136. data/test/executables/puppetd.rb +3 -3
  137. data/test/executables/puppetmasterd.rb +1 -5
  138. data/test/executables/puppetmodule.rb +2 -2
  139. data/test/language/ast.rb +200 -11
  140. data/test/language/functions.rb +245 -0
  141. data/test/language/interpreter.rb +155 -6
  142. data/test/language/lexer.rb +35 -2
  143. data/test/language/node.rb +48 -1
  144. data/test/language/parser.rb +250 -1
  145. data/test/language/rails.rb +105 -0
  146. data/test/language/scope.rb +304 -10
  147. data/test/language/snippets.rb +54 -5
  148. data/test/language/transportable.rb +60 -28
  149. data/test/other/config.rb +214 -1
  150. data/test/other/events.rb +67 -9
  151. data/test/other/log.rb +31 -5
  152. data/test/other/metrics.rb +23 -21
  153. data/test/other/parsedfile.rb +29 -2
  154. data/test/other/puppet.rb +79 -0
  155. data/test/other/report.rb +106 -0
  156. data/test/other/storage.rb +2 -2
  157. data/test/other/transactions.rb +128 -2
  158. data/test/puppet/utiltest.rb +10 -5
  159. data/test/puppettest.rb +193 -21
  160. data/test/server/authstore.rb +13 -4
  161. data/test/server/bucket.rb +33 -8
  162. data/test/server/ca.rb +44 -6
  163. data/test/server/master.rb +6 -7
  164. data/test/server/pelement.rb +15 -5
  165. data/test/server/report.rb +93 -0
  166. data/test/server/runner.rb +107 -0
  167. data/test/server/server.rb +28 -1
  168. data/test/types/cron.rb +339 -31
  169. data/test/types/file.rb +256 -24
  170. data/test/types/filebucket.rb +6 -2
  171. data/test/types/filesources.rb +41 -92
  172. data/test/types/group.rb +31 -1
  173. data/test/types/host.rb +2 -1
  174. data/test/types/mount.rb +18 -1
  175. data/test/types/package.rb +200 -18
  176. data/test/types/service.rb +5 -1
  177. data/test/types/sshkey.rb +2 -1
  178. data/test/types/symlink.rb +3 -2
  179. data/test/types/type.rb +180 -1
  180. data/test/types/user.rb +65 -27
  181. data/test/types/yumrepo.rb +15 -0
  182. data/test/types/zone.rb +437 -0
  183. metadata +43 -4
  184. data/bin/cf2puppet +0 -186
  185. data/conf/redhat/puppetmasterd.conf +0 -5
@@ -10,17 +10,77 @@ module Puppet::Parser
10
10
  attr_accessor :file, :line, :type, :name
11
11
  end
12
12
 
13
+ # A simple wrapper for templates, so they don't have full access to
14
+ # the scope objects.
15
+ class TemplateWrapper
16
+ attr_accessor :scope, :file
17
+ include Puppet::Util
18
+ Puppet::Util.logmethods(self)
19
+
20
+ def initialize(scope, file)
21
+ @scope = scope
22
+ if file =~ /^#{File::SEPARATOR}/
23
+ @file = file
24
+ else
25
+ @file = File.join(Puppet[:templatedir], file)
26
+ end
27
+
28
+ unless FileTest.exists?(@file)
29
+ raise Puppet::ParseError,
30
+ "Could not find template %s" % file
31
+ end
32
+
33
+ # We'll only ever not have an interpreter in testing, but, eh.
34
+ if @scope.interp
35
+ @scope.interp.newfile(@file)
36
+ end
37
+ end
38
+
39
+ def method_missing(name, *args)
40
+ if value = @scope.lookupvar(name.to_s) and value != :undefined and value != ""
41
+ return value
42
+ else
43
+ # Just throw an error immediately, instead of searching for
44
+ # other missingmethod things or whatever.
45
+ raise Puppet::ParseError,
46
+ "Could not find value for '%s'" % name
47
+ end
48
+ end
49
+
50
+ def result
51
+ result = nil
52
+ benchmark(:info, "Interpolated template #{@file}") do
53
+ template = ERB.new(File.read(@file))
54
+ result = template.result(binding)
55
+ end
56
+
57
+ result
58
+ end
59
+
60
+ def to_s
61
+ "template[%s]" % @file
62
+ end
63
+ end
64
+
65
+ # This doesn't actually work right now.
66
+ Puppet.config.setdefaults(:puppet,
67
+ :lexical => [false, "Whether to use lexical scoping (vs. dynamic)."],
68
+ :templatedir => ["$vardir/templates",
69
+ "Where Puppet looks for template files."
70
+ ]
71
+ )
72
+
13
73
  Puppet::Util.logmethods(self)
14
74
 
15
75
  include Enumerable
16
76
  attr_accessor :parent, :level, :interp
17
77
  attr_accessor :name, :type, :topscope, :base, :keyword
18
78
 
19
- attr_accessor :top, :context
79
+ attr_accessor :top, :context, :translated, :collectable
20
80
 
21
81
  # This is probably not all that good of an idea, but...
22
82
  # This way a parent can share its tables with all of its children.
23
- attr_writer :nodetable, :classtable, :definedtable
83
+ attr_writer :nodetable, :classtable, :definedtable, :exportable
24
84
 
25
85
  # Whether we behave declaratively. Note that it's a class variable,
26
86
  # so all scopes behave the same.
@@ -90,17 +150,23 @@ module Puppet::Parser
90
150
  if typeklass and ! typeklass.isomorphic?
91
151
  Puppet.info "Allowing duplicate %s" % type
92
152
  else
153
+ exobj = @definedtable[type][name]
154
+
93
155
  # Either it's a defined type, which are never
94
156
  # isomorphic, or it's a non-isomorphic type.
95
157
  msg = "Duplicate definition: %s[%s] is already defined" %
96
158
  [type, name]
97
- error = Puppet::ParseError.new(msg)
98
- if hash[:line]
99
- error.line = hash[:line]
159
+
160
+ if exobj.file and exobj.line
161
+ msg << " in file %s at line %s" %
162
+ [exobj.file, exobj.line]
100
163
  end
101
- if hash[:file]
102
- error.file = hash[:file]
164
+
165
+ if hash[:line] or hash[:file]
166
+ msg << "; cannot redefine"
103
167
  end
168
+
169
+ error = Puppet::ParseError.new(msg)
104
170
  raise error
105
171
  end
106
172
  end
@@ -146,6 +212,12 @@ module Puppet::Parser
146
212
  raise Puppet::DevError, "No classtable has been defined"
147
213
  end
148
214
 
215
+ if defined? @exportable
216
+ scope.exportable = @exportable
217
+ else
218
+ raise Puppet::DevError, "No exportable has been defined"
219
+ end
220
+
149
221
  if defined? @definedtable
150
222
  scope.definedtable = @definedtable
151
223
  else
@@ -174,12 +246,20 @@ module Puppet::Parser
174
246
  unless defined? @classtable
175
247
  raise Puppet::DevError, "Scope did not receive class table"
176
248
  end
177
- return @classtable.values
249
+ return @classtable.collect { |id, klass|
250
+ # The class table can contain scopes or strings as its values
251
+ # so support them accordingly.
252
+ if klass.is_a? Scope
253
+ klass.type
254
+ else
255
+ klass
256
+ end
257
+ }
178
258
  end
179
259
 
180
260
  # Yield each child scope in turn
181
261
  def each
182
- @children.reject { |child|
262
+ @children.each { |child|
183
263
  yield child
184
264
  }
185
265
  end
@@ -189,11 +269,9 @@ module Puppet::Parser
189
269
  return unless classes
190
270
  classes.each do |klass|
191
271
  if code = lookuptype(klass)
192
- code.safeevaluate(
193
- :scope => self,
194
- :facts => {},
195
- :type => klass
196
- )
272
+ # Just reuse the 'include' function, since that's the equivalent
273
+ # of what we're doing here.
274
+ function_include(klass)
197
275
  end
198
276
  end
199
277
  end
@@ -201,7 +279,6 @@ module Puppet::Parser
201
279
  # Evaluate a specific node's code. This method will normally be called
202
280
  # on the top-level scope, but it actually evaluates the node at the
203
281
  # appropriate scope.
204
- #def evalnode(names, facts, classes = nil, parent = nil)
205
282
  def evalnode(hash)
206
283
  objects = hash[:ast]
207
284
  names = hash[:names] or
@@ -210,12 +287,20 @@ module Puppet::Parser
210
287
  classes = hash[:classes]
211
288
  parent = hash[:parent]
212
289
 
290
+ # Always add "default" to our name list, so we're always searching
291
+ # for a default node.
292
+ names << "default"
293
+
213
294
  scope = code = nil
214
295
  # Find a node that matches one of our names
215
296
  names.each { |node|
216
297
  if nodehash = @nodetable[node]
217
298
  code = nodehash[:node]
218
299
  scope = nodehash[:scope]
300
+
301
+ if node == "default"
302
+ Puppet.info "Using default node"
303
+ end
219
304
  break
220
305
  end
221
306
  }
@@ -240,17 +325,19 @@ module Puppet::Parser
240
325
  scope.evalclasses(classes)
241
326
  end
242
327
 
243
- # Evaluate normally, with no node definitions. This is a bit of a
244
- # silly method, in that it just calls evaluate on the passed-in
245
- # objects, and then calls to_trans on itself. It just conceals
246
- # a paltry amount of info from whomever's using the scope object.
328
+ # The top-level evaluate, used to evaluate a whole AST tree. This is
329
+ # a strange method, in that it turns around and calls evaluate() on its
330
+ # :ast argument.
247
331
  def evaluate(hash)
248
332
  objects = hash[:ast]
249
333
  facts = hash[:facts] || {}
250
334
 
335
+ @@done = []
336
+
251
337
  unless objects
252
338
  raise Puppet::DevError, "Evaluation requires an AST tree"
253
339
  end
340
+
254
341
  # Set all of our facts in the top-level scope.
255
342
  facts.each { |var, value|
256
343
  self.setvar(var, value)
@@ -258,10 +345,11 @@ module Puppet::Parser
258
345
 
259
346
  # Evaluate all of our configuration. This does not evaluate any
260
347
  # node definitions.
261
- objects.safeevaluate(:scope => self)
348
+ result = objects.safeevaluate(:scope => self)
262
349
 
263
- # If they've provided a name or a parent, we assume they're looking for nodes.
264
- if hash.include? :parentnode
350
+ # If they've provided a name or a parent, we assume they're looking
351
+ # for nodes.
352
+ if hash[:searched]
265
353
  # Specifying a parent node takes precedence, because it is assumed
266
354
  # that this node was found in a remote repository like ldap.
267
355
  gennode(hash)
@@ -277,15 +365,44 @@ module Puppet::Parser
277
365
  # a cfengine module
278
366
  end
279
367
 
280
- objects = self.to_trans
281
- objects.top = true
368
+ bucket = self.to_trans
282
369
 
283
370
  # Add our class list
284
371
  unless self.classlist.empty?
285
- objects.classes = self.classlist
372
+ bucket.classes = self.classlist
373
+ end
374
+
375
+ # Now clean up after ourselves
376
+ [@@done].each do |table|
377
+ table.clear
286
378
  end
287
379
 
288
- return objects
380
+ return bucket
381
+ end
382
+
383
+ # Return the hash of objects that we specifically exported. We return
384
+ # a hash to make it easy for the caller to deduplicate based on name.
385
+ def exported(type)
386
+ if @exportable.include?(type)
387
+ return @exportable[type].dup
388
+ else
389
+ return {}
390
+ end
391
+ end
392
+
393
+ # Store our object in the central export table.
394
+ def exportobject(obj)
395
+ if @exportable.include?(obj.type) and
396
+ @exportable[obj.type].include?(obj.name)
397
+ raise Puppet::ParseError, "Object %s[%s] is already exported" %
398
+ [obj.type, obj.name]
399
+ end
400
+
401
+ debug "Exporting %s[%s]" % [obj.type, obj.name]
402
+
403
+ @exportable[obj.type][obj.name] = obj
404
+
405
+ return obj
289
406
  end
290
407
 
291
408
  # Pull in all of the appropriate classes and evaluate them. It'd
@@ -306,8 +423,8 @@ module Puppet::Parser
306
423
 
307
424
  #Puppet.notice "hash is %s" %
308
425
  # hash.inspect
309
- Puppet.notice "Classes are %s, parent is %s" %
310
- [classes.inspect, parent.inspect]
426
+ #Puppet.notice "Classes are %s, parent is %s" %
427
+ # [classes.inspect, parent.inspect]
311
428
 
312
429
  if parent
313
430
  arghash[:parentclass] = parent
@@ -325,52 +442,6 @@ module Puppet::Parser
325
442
  scope.evalclasses(classes)
326
443
  end
327
444
 
328
- # Take all of our objects and evaluate them.
329
- # def finish
330
- # self.info "finishing"
331
- # @objectlist.each { |object|
332
- # if object.is_a? ScopeObj
333
- # self.info "finishing %s" % object.name
334
- # if obj = finishobject(object)
335
- # @children << obj
336
- # end
337
- # end
338
- # }
339
- #
340
- # @finished = true
341
- #
342
- # self.info "finished"
343
- # end
344
- #
345
- # # If the object is defined in an upper scope, then add our
346
- # # params to that upper scope; else, create a transobject
347
- # # or evaluate the definition.
348
- # def finishobject(object)
349
- # type = object.type
350
- # name = object.name
351
- #
352
- # # It should be a defined type.
353
- # definedtype = lookuptype(type)
354
- #
355
- # unless definedtype
356
- # error = Puppet::ParseError.new("No such type %s" % type)
357
- # error.line = object.line
358
- # error.file = object.file
359
- # raise error
360
- # end
361
- #
362
- # return definedtype.safeevaluate(
363
- # :scope => self,
364
- # :arguments => object,
365
- # :type => type,
366
- # :name => name
367
- # )
368
- # end
369
- #
370
- # def finished?
371
- # @finished
372
- # end
373
-
374
445
  # Initialize our new scope. Defaults to having no parent and to
375
446
  # being declarative.
376
447
  def initialize(hash = {})
@@ -395,7 +466,10 @@ module Puppet::Parser
395
466
  end
396
467
  self.istop(hash[:declarative])
397
468
  else
469
+ # This is here, rather than in newchild(), so that all
470
+ # of the later variable initialization works.
398
471
  @parent.child = self
472
+
399
473
  @level = @parent.level + 1
400
474
  @interp = @parent.interp
401
475
  @topscope = @parent.topscope
@@ -425,9 +499,6 @@ module Puppet::Parser
425
499
  typehash[typekey] = Hash.new(nil)
426
500
  }
427
501
 
428
- # The list of simpler hash objects.
429
- @objectlist = []
430
-
431
502
  # This is just for collecting statements locally, so we can
432
503
  # verify that there is no overlap within this specific scope
433
504
  @localobjectable = Hash.new { |typehash,typekey|
@@ -463,6 +534,11 @@ module Puppet::Parser
463
534
  # A table for storing nodes.
464
535
  @nodetable = Hash.new(nil)
465
536
 
537
+ # The list of objects that will available for export.
538
+ @exportable = Hash.new { |types, type|
539
+ types[type] = {}
540
+ }
541
+
466
542
  # Eventually, if we support sites, this will allow definitions
467
543
  # of nodes with the same name in different sites. For now
468
544
  # the top-level scope is always the only site scope.
@@ -517,6 +593,30 @@ module Puppet::Parser
517
593
  return values
518
594
  end
519
595
 
596
+ # Look up all of the exported objects of a given type. Just like
597
+ # lookupobject, this only searches up through parent classes, not
598
+ # the whole scope tree.
599
+ def lookupexported(type)
600
+ found = []
601
+ sub = proc { |table|
602
+ # We always return nil so that it will search all the way
603
+ # up the scope tree.
604
+ if table.has_key?(type)
605
+ table[type].each do |name, obj|
606
+ found << obj
607
+ end
608
+ nil
609
+ else
610
+ info table.keys.inspect
611
+ nil
612
+ end
613
+ }
614
+
615
+ value = lookup("object",sub, false)
616
+
617
+ return found
618
+ end
619
+
520
620
  # Look up a node by name
521
621
  def lookupnode(name)
522
622
  #Puppet.debug "Looking up type %s" % name
@@ -567,19 +667,18 @@ module Puppet::Parser
567
667
 
568
668
  # Look up a variable. The simplest value search we do.
569
669
  def lookupvar(name)
570
- #Puppet.debug "Looking up variable %s" % name
571
670
  value = lookup("variable", name)
572
671
  if value == :undefined
573
672
  return ""
574
- #error = Puppet::ParseError.new(
575
- # "Undefined variable '%s'" % name
576
- #)
577
- #raise error
578
673
  else
579
674
  return value
580
675
  end
581
676
  end
582
677
 
678
+ def newcollection(coll)
679
+ @children << coll
680
+ end
681
+
583
682
  # Add a new object to our object table.
584
683
  def newobject(hash)
585
684
  if @objectable[hash[:type]].include?(hash[:name])
@@ -591,25 +690,14 @@ module Puppet::Parser
591
690
 
592
691
  obj = nil
593
692
 
594
- # If it's a builtin type, then use a transobject, else use
595
- # a ScopeObj, which will get replaced later.
596
- if self.builtintype?(hash[:type])
597
- obj = Puppet::TransObject.new(hash[:name], hash[:type])
693
+ obj = Puppet::TransObject.new(hash[:name], hash[:type])
598
694
 
599
- @children << obj
600
- else
601
- obj = ScopeObj.new(nil)
602
- obj.name = hash[:name]
603
- obj.type = hash[:type]
604
- end
695
+ @children << obj
605
696
 
606
697
  @objectable[hash[:type]][hash[:name]] = obj
607
698
 
608
699
  @definedtable[hash[:type]][hash[:name]] = obj
609
700
 
610
- # Keep them in order, just for kicks
611
- @objectlist << obj
612
-
613
701
  return obj
614
702
  end
615
703
 
@@ -631,15 +719,17 @@ module Puppet::Parser
631
719
  # hash. We store the object ID, not class name, so that we
632
720
  # can support multiple unrelated classes with the same name.
633
721
  def setclass(id, name)
634
- unless name =~ /^[a-z]\w*$/
722
+ unless name =~ /^[a-z][\w-]*$/
635
723
  raise Puppet::ParseError, "Invalid class name '%s'" % name
636
724
  end
637
725
 
638
- if self.topscope?
639
- @classtable[id] = name
640
- else
641
- @parent.setclass(id, name)
642
- end
726
+ @classtable[id] = name
727
+ end
728
+
729
+ # Store the scope for each class, so that other subclasses can look
730
+ # them up.
731
+ def setscope(id, scope)
732
+ @classtable[id] = scope
643
733
  end
644
734
 
645
735
  # Set defaults for a type. The typename should already be downcased,
@@ -687,6 +777,7 @@ module Puppet::Parser
687
777
  # We have to store both the scope that's setting the node and
688
778
  # the node itself, so that the node gets evaluated in the correct
689
779
  # scope.
780
+ code.scope = self
690
781
  @nodetable[name] = {
691
782
  :scope => self,
692
783
  :node => code
@@ -701,6 +792,7 @@ module Puppet::Parser
701
792
  raise Puppet::ParseError,
702
793
  "%s is already defined" % name
703
794
  else
795
+ ltype.scope = self
704
796
  @typetable[name] = ltype
705
797
  end
706
798
  end
@@ -722,6 +814,8 @@ module Puppet::Parser
722
814
  file = hash[:file]
723
815
  line = hash[:line]
724
816
 
817
+ collectable = hash[:collectable] || self.collectable
818
+
725
819
  # Verify that we're not overriding any already-set parameters.
726
820
  if localobj = @localobjectable[type][name]
727
821
  params.each { |var, value|
@@ -737,48 +831,63 @@ module Puppet::Parser
737
831
  }
738
832
  end
739
833
 
740
- if objecttype = lookuptype(type)
741
- # It's a defined type
742
- objecttype.safeevaluate(
743
- :name => name,
744
- :type => type,
745
- :arguments => params,
746
- :scope => self
747
- )
748
- else
749
- # First look for it in a parent scope
750
- obj = lookupobject(:name => name, :type => type)
751
-
752
- unless obj and obj != :undefined
753
- unless obj = @objectable[type][name]
754
- obj = self.newobject(
755
- :type => type,
756
- :name => name,
757
- :line => line,
758
- :file => file
759
- )
834
+ # First look for it in a parent scope
835
+ obj = lookupobject(:name => name, :type => type)
760
836
 
761
- # only set these if we've created the object,
762
- # which is the most common case
763
- # FIXME we eventually need to store the file
764
- # and line with each param, not the object
765
- # itself.
766
- obj.file = file
767
- obj.line = line
837
+ if obj
838
+ unless collectable == obj.collectable
839
+ msg = nil
840
+ if collectable
841
+ msg = "Exported %s[%s] cannot override local objects"
842
+ [type, name]
843
+ else
844
+ msg = "Local %s[%s] cannot override exported objects"
845
+ [type, name]
768
846
  end
847
+
848
+ error = Puppet::ParseError.new(msg)
849
+ error.line = line
850
+ error.file = file
851
+ raise error
769
852
  end
853
+ end
770
854
 
771
- # Now add our parameters. This has the function of overriding
772
- # existing values, which might have been defined in a higher
773
- # scope.
774
- params.each { |var,value|
775
- # Add it to our found object
776
- obj[var] = value
777
- }
855
+ unless obj and obj != :undefined
856
+ unless obj = @objectable[type][name]
857
+ obj = self.newobject(
858
+ :type => type,
859
+ :name => name,
860
+ :line => line,
861
+ :file => file
862
+ )
863
+
864
+ obj.collectable = collectable
865
+
866
+ # only set these if we've created the object,
867
+ # which is the most common case
868
+ # FIXME we eventually need to store the file
869
+ # and line with each param, not the object
870
+ # itself.
871
+ obj.file = file
872
+ obj.line = line
873
+ end
778
874
  end
779
875
 
780
- @localobjectable[type][name] ||= {}
876
+ # Now add our parameters. This has the function of overriding
877
+ # existing values, which might have been defined in a higher
878
+ # scope.
879
+ params.each { |var,value|
880
+ # Add it to our found object
881
+ obj[var] = value
882
+ }
781
883
 
884
+ # This is only used for override verification -- the local object
885
+ # table does not have transobjects or whatever in it, it just has
886
+ # simple hashes. This is necessary because setobject can modify
887
+ # our object table or a parent class's object table, and we
888
+ # still need to make sure param settings cannot be duplicated
889
+ # within our scope.
890
+ @localobjectable[type][name] ||= {}
782
891
  params.each { |var,value|
783
892
  # And add it to the local table; mmm, hack
784
893
  @localobjectable[type][name][var] = value
@@ -805,20 +914,16 @@ module Puppet::Parser
805
914
 
806
915
  # Return an interpolated string.
807
916
  def strinterp(string)
808
- newstring = string.dup
809
- regex = Regexp.new('\$\{(\w+)\}|\$(\w+)')
810
- #Puppet.debug("interpreting '%s'" % string)
811
- while match = regex.match(newstring) do
812
- if match[1]
813
- newstring.sub!(regex,lookupvar(match[1]).to_s)
814
- elsif match[2]
815
- newstring.sub!(regex,lookupvar(match[2]).to_s)
816
- else
817
- raise Puppet::DevError, "Could not match variable in %s" %
818
- newstring
917
+ newstring = string.gsub(/\\\$|\$\{(\w+)\}|\$(\w+)/) do |value|
918
+ # If it matches the backslash, then just retun the dollar sign.
919
+ if value == '\\$'
920
+ '$'
921
+ else # look the variable up
922
+ var = $1 || $2
923
+ lookupvar($1 || $2)
819
924
  end
820
925
  end
821
- #Puppet.debug("result is '%s'" % newstring)
926
+
822
927
  return newstring.gsub(/\\t/, "\t").gsub(/\\n/, "\n").gsub(/\\s/, "\s")
823
928
  end
824
929
 
@@ -845,6 +950,7 @@ module Puppet::Parser
845
950
  tmp << @type.to_s
846
951
  end
847
952
  if @parent
953
+ #info "Looking for tags in %s" % @parent.type
848
954
  @parent.tags.each { |tag|
849
955
  if tag.nil? or tag == ""
850
956
  Puppet.debug "parent returned tag %s" % tag.inspect
@@ -867,33 +973,36 @@ module Puppet::Parser
867
973
  end
868
974
  end
869
975
 
870
- # Convert our scope to a list of Transportable objects.
976
+ # Convert our scope to a TransBucket. Everything in our @localobjecttable
977
+ # gets converted to either an evaluated definition, or a TransObject
871
978
  def to_trans
872
-
873
979
  results = []
874
-
875
- # Iterate across our child scopes and call to_trans on them
876
- @children.each { |child|
877
- if child.is_a?(Scope)
878
- cresult = child.to_trans
879
-
880
- # Scopes normally result in a TransBucket, but they could
881
- # also result in a normal array; if that happens, get rid
882
- # of the array.
883
- unless cresult.is_a?(Puppet::TransBucket)
884
- cresult.each { |result|
885
- results.push(result)
886
- }
887
- else
888
- unless cresult.empty?
889
- # Otherwise, just add it to our list of results.
890
- results.push(cresult)
891
- end
892
- end
893
- elsif child.is_a?(Puppet::TransObject)
894
- if child.empty?
895
- next
896
- end
980
+
981
+ # Set this on entry, just in case someone tries to get all weird
982
+ @translated = true
983
+
984
+ @children.dup.each do |child|
985
+ if @@done.include?(child)
986
+ raise Puppet::DevError, "Already translated %s" %
987
+ child.object_id
988
+ else
989
+ @@done << child
990
+ end
991
+ #warning "Working on %s of type %s with id %s" %
992
+ # [child.type, child.class, child.object_id]
993
+
994
+ # If it's a scope, then it can only be a subclass's scope, so
995
+ # convert it to a transbucket and store it in our results list
996
+ result = nil
997
+ case child
998
+ when Scope
999
+ result = child.to_trans
1000
+ when Puppet::TransObject
1001
+ # These objects can map to defined types or builtin types.
1002
+ # Builtin types should be passed out as they are, but defined
1003
+ # types need to be evaluated. We have to wait until this
1004
+ # point so that subclass overrides can happen.
1005
+
897
1006
  # Wait until the last minute to set tags, although this
898
1007
  # probably should not matter
899
1008
  child.tags = self.tags
@@ -905,16 +1014,57 @@ module Puppet::Parser
905
1014
  # central table. This should maybe be in the evaluate
906
1015
  # methods, but, eh.
907
1016
  @topscope.addtags(child)
908
- results.push(child)
1017
+
1018
+ # Now that all that is done, check to see what kind of object
1019
+ # it is.
1020
+ if objecttype = lookuptype(child.type)
1021
+ # It's a defined type, so evaluate it. Retain whether
1022
+ # the object is collectable. If the object is collectable,
1023
+ # then it will store all of its contents into the
1024
+ # @exportable table, rather than returning them.
1025
+ result = objecttype.safeevaluate(
1026
+ :name => child.name,
1027
+ :type => child.type,
1028
+ :arguments => child.to_hash,
1029
+ :scope => self,
1030
+ :collectable => child.collectable
1031
+ )
1032
+ else
1033
+ # If it's collectable, then store it. It will be
1034
+ # stripped out in the interpreter using the collectstrip
1035
+ # method. If we don't do this, then these objects
1036
+ # don't get stored in the DB.
1037
+ if child.collectable
1038
+ exportobject(child)
1039
+ end
1040
+ result = child
1041
+ end
1042
+ # This is pretty hackish, but the collection has to actually
1043
+ # be performed after all of the classes and definitions are
1044
+ # evaluated, otherwise we won't catch objects that are exported
1045
+ # in them. I think this will still be pretty limited in some
1046
+ # cases, especially those where you are both exporting and
1047
+ # collecting, but it's the best I can do for now.
1048
+ when Puppet::Parser::AST::Collection
1049
+ child.perform(self).each do |obj|
1050
+ results << obj
1051
+ end
909
1052
  else
910
1053
  raise Puppet::DevError,
911
1054
  "Puppet::Parse::Scope cannot handle objects of type %s" %
912
1055
  child.class
913
1056
  end
914
- }
1057
+
1058
+ # Skip nil objects or empty transbuckets
1059
+ if result
1060
+ unless result.is_a? Puppet::TransBucket and result.empty?
1061
+ results << result
1062
+ end
1063
+ end
1064
+ end
915
1065
 
916
1066
  # Get rid of any nil objects.
917
- results = results.reject { |child|
1067
+ results.reject! { |child|
918
1068
  child.nil?
919
1069
  }
920
1070
 
@@ -927,18 +1077,12 @@ module Puppet::Parser
927
1077
  if defined? @name and @name
928
1078
  bucket.name = @name
929
1079
  end
930
-
931
1080
  # it'd be nice not to have to do this...
932
1081
  results.each { |result|
933
1082
  #Puppet.warning "Result type is %s" % result.class
934
1083
  bucket.push(result)
935
1084
  }
936
- if defined? @type
937
- bucket.type = @type
938
- else
939
- raise Puppet::ParseError,
940
- "No type for scope %s" % @name
941
- end
1085
+ bucket.type = @type
942
1086
 
943
1087
  if defined? @keyword
944
1088
  bucket.keyword = @keyword
@@ -961,11 +1105,18 @@ module Puppet::Parser
961
1105
  # [bucket.name,self.object_id]
962
1106
  return bucket
963
1107
  else
964
- Puppet.debug "nameless scope; just returning a list"
1108
+ Puppet.debug "typeless scope; just returning a list"
965
1109
  return results
966
1110
  end
967
1111
  end
968
1112
 
1113
+ # Undefine a variable; only used for testing.
1114
+ def unsetvar(var)
1115
+ if @symtable.include?(var)
1116
+ @symtable.delete(var)
1117
+ end
1118
+ end
1119
+
969
1120
  protected
970
1121
 
971
1122
  # This method abstracts recursive searching. It accepts the type
@@ -986,8 +1137,7 @@ module Puppet::Parser
986
1137
  elsif table.include?(sub)
987
1138
  return table[sub]
988
1139
  elsif ! @parent.nil?
989
- #self.notice "Context is %s, parent %s is %s" %
990
- # [self.context, @parent.type, @parent.context]
1140
+ # Context is used for retricting overrides.
991
1141
  if usecontext and self.context != @parent.context
992
1142
  return :undefined
993
1143
  else
@@ -1000,4 +1150,4 @@ module Puppet::Parser
1000
1150
  end
1001
1151
  end
1002
1152
 
1003
- # $Id: scope.rb 1104 2006-04-11 17:48:14Z luke $
1153
+ # $Id: scope.rb 1401 2006-07-18 14:00:33Z luke $