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.
- data/CHANGELOG +0 -0
- data/COPYING +340 -0
- data/LICENSE +17 -0
- data/README +24 -0
- data/Rakefile +294 -0
- data/TODO +4 -0
- data/bin/cf2puppet +186 -0
- data/bin/puppet +176 -0
- data/bin/puppetca +213 -0
- data/bin/puppetd +246 -0
- data/bin/puppetdoc +184 -0
- data/bin/puppetmasterd +258 -0
- data/examples/code/allatonce +13 -0
- data/examples/code/assignments +11 -0
- data/examples/code/classing +35 -0
- data/examples/code/components +73 -0
- data/examples/code/execs +16 -0
- data/examples/code/failers/badclassnoparam +10 -0
- data/examples/code/failers/badclassparam +10 -0
- data/examples/code/failers/badcompnoparam +9 -0
- data/examples/code/failers/badcompparam +9 -0
- data/examples/code/failers/badtypeparam +3 -0
- data/examples/code/file.bl +11 -0
- data/examples/code/filedefaults +10 -0
- data/examples/code/fileparsing +116 -0
- data/examples/code/filerecursion +15 -0
- data/examples/code/functions +3 -0
- data/examples/code/groups +7 -0
- data/examples/code/head +30 -0
- data/examples/code/importing +8 -0
- data/examples/code/nodes +20 -0
- data/examples/code/one +8 -0
- data/examples/code/relationships +34 -0
- data/examples/code/selectors +28 -0
- data/examples/code/simpletests +11 -0
- data/examples/code/snippets/argumentdefaults +14 -0
- data/examples/code/snippets/casestatement +39 -0
- data/examples/code/snippets/classheirarchy.pp +15 -0
- data/examples/code/snippets/classincludes.pp +17 -0
- data/examples/code/snippets/classpathtest +11 -0
- data/examples/code/snippets/dirchmod +19 -0
- data/examples/code/snippets/failmissingexecpath.pp +13 -0
- data/examples/code/snippets/falsevalues.pp +3 -0
- data/examples/code/snippets/filecreate +11 -0
- data/examples/code/snippets/implicititeration +15 -0
- data/examples/code/snippets/multipleinstances +7 -0
- data/examples/code/snippets/namevartest +9 -0
- data/examples/code/snippets/scopetest +13 -0
- data/examples/code/snippets/selectorvalues.pp +22 -0
- data/examples/code/snippets/simpledefaults +5 -0
- data/examples/code/snippets/simpleselector +38 -0
- data/examples/code/svncommit +13 -0
- data/examples/root/bin/sleeper +69 -0
- data/examples/root/etc/configfile +0 -0
- data/examples/root/etc/debian-passwd +29 -0
- data/examples/root/etc/debian-syslog.conf +71 -0
- data/examples/root/etc/init.d/sleeper +65 -0
- data/examples/root/etc/otherfile +0 -0
- data/examples/root/etc/puppet/fileserver.conf +3 -0
- data/examples/root/etc/puppet/puppetmasterd.conf +10 -0
- data/ext/module:puppet +195 -0
- data/install.rb +270 -0
- data/lib/puppet.rb +249 -0
- data/lib/puppet/base64.rb +19 -0
- data/lib/puppet/client.rb +519 -0
- data/lib/puppet/config.rb +49 -0
- data/lib/puppet/daemon.rb +208 -0
- data/lib/puppet/element.rb +71 -0
- data/lib/puppet/event.rb +259 -0
- data/lib/puppet/log.rb +321 -0
- data/lib/puppet/metric.rb +250 -0
- data/lib/puppet/parsedfile.rb +38 -0
- data/lib/puppet/parser/ast.rb +1560 -0
- data/lib/puppet/parser/interpreter.rb +150 -0
- data/lib/puppet/parser/lexer.rb +226 -0
- data/lib/puppet/parser/parser.rb +1354 -0
- data/lib/puppet/parser/scope.rb +755 -0
- data/lib/puppet/server.rb +170 -0
- data/lib/puppet/server/authstore.rb +227 -0
- data/lib/puppet/server/ca.rb +140 -0
- data/lib/puppet/server/filebucket.rb +147 -0
- data/lib/puppet/server/fileserver.rb +477 -0
- data/lib/puppet/server/logger.rb +43 -0
- data/lib/puppet/server/master.rb +103 -0
- data/lib/puppet/server/servlet.rb +247 -0
- data/lib/puppet/sslcertificates.rb +737 -0
- data/lib/puppet/statechange.rb +150 -0
- data/lib/puppet/storage.rb +95 -0
- data/lib/puppet/transaction.rb +179 -0
- data/lib/puppet/transportable.rb +151 -0
- data/lib/puppet/type.rb +1354 -0
- data/lib/puppet/type/component.rb +141 -0
- data/lib/puppet/type/cron.rb +543 -0
- data/lib/puppet/type/exec.rb +316 -0
- data/lib/puppet/type/group.rb +152 -0
- data/lib/puppet/type/nameservice.rb +3 -0
- data/lib/puppet/type/nameservice/netinfo.rb +173 -0
- data/lib/puppet/type/nameservice/objectadd.rb +146 -0
- data/lib/puppet/type/nameservice/posix.rb +200 -0
- data/lib/puppet/type/package.rb +420 -0
- data/lib/puppet/type/package/apt.rb +70 -0
- data/lib/puppet/type/package/dpkg.rb +108 -0
- data/lib/puppet/type/package/rpm.rb +81 -0
- data/lib/puppet/type/package/sun.rb +117 -0
- data/lib/puppet/type/package/yum.rb +58 -0
- data/lib/puppet/type/pfile.rb +569 -0
- data/lib/puppet/type/pfile/checksum.rb +219 -0
- data/lib/puppet/type/pfile/create.rb +108 -0
- data/lib/puppet/type/pfile/group.rb +129 -0
- data/lib/puppet/type/pfile/mode.rb +131 -0
- data/lib/puppet/type/pfile/source.rb +264 -0
- data/lib/puppet/type/pfile/type.rb +31 -0
- data/lib/puppet/type/pfile/uid.rb +166 -0
- data/lib/puppet/type/pfilebucket.rb +80 -0
- data/lib/puppet/type/pprocess.rb +97 -0
- data/lib/puppet/type/service.rb +347 -0
- data/lib/puppet/type/service/base.rb +17 -0
- data/lib/puppet/type/service/debian.rb +50 -0
- data/lib/puppet/type/service/init.rb +145 -0
- data/lib/puppet/type/service/smf.rb +29 -0
- data/lib/puppet/type/state.rb +182 -0
- data/lib/puppet/type/symlink.rb +183 -0
- data/lib/puppet/type/tidy.rb +183 -0
- data/lib/puppet/type/typegen.rb +149 -0
- data/lib/puppet/type/typegen/filerecord.rb +243 -0
- data/lib/puppet/type/typegen/filetype.rb +316 -0
- data/lib/puppet/type/user.rb +290 -0
- data/lib/puppet/util.rb +138 -0
- data/test/certmgr/certmgr.rb +265 -0
- data/test/client/client.rb +203 -0
- data/test/executables/puppetbin.rb +53 -0
- data/test/executables/puppetca.rb +79 -0
- data/test/executables/puppetd.rb +71 -0
- data/test/executables/puppetmasterd.rb +153 -0
- data/test/executables/puppetmodule.rb +60 -0
- data/test/language/ast.rb +412 -0
- data/test/language/interpreter.rb +71 -0
- data/test/language/scope.rb +412 -0
- data/test/language/snippets.rb +445 -0
- data/test/other/events.rb +111 -0
- data/test/other/log.rb +195 -0
- data/test/other/metrics.rb +92 -0
- data/test/other/overrides.rb +115 -0
- data/test/other/parsedfile.rb +31 -0
- data/test/other/relationships.rb +113 -0
- data/test/other/state.rb +106 -0
- data/test/other/storage.rb +39 -0
- data/test/other/transactions.rb +235 -0
- data/test/parser/lexer.rb +120 -0
- data/test/parser/parser.rb +180 -0
- data/test/puppet/conffiles.rb +104 -0
- data/test/puppet/defaults.rb +100 -0
- data/test/puppet/error.rb +23 -0
- data/test/puppet/utiltest.rb +120 -0
- data/test/puppettest.rb +774 -0
- data/test/server/authstore.rb +209 -0
- data/test/server/bucket.rb +227 -0
- data/test/server/ca.rb +201 -0
- data/test/server/fileserver.rb +710 -0
- data/test/server/logger.rb +175 -0
- data/test/server/master.rb +150 -0
- data/test/server/server.rb +130 -0
- data/test/tagging/tagging.rb +80 -0
- data/test/test +51 -0
- data/test/types/basic.rb +119 -0
- data/test/types/component.rb +272 -0
- data/test/types/cron.rb +261 -0
- data/test/types/exec.rb +273 -0
- data/test/types/file.rb +616 -0
- data/test/types/filebucket.rb +167 -0
- data/test/types/fileignoresource.rb +287 -0
- data/test/types/filesources.rb +587 -0
- data/test/types/filetype.rb +162 -0
- data/test/types/group.rb +271 -0
- data/test/types/package.rb +205 -0
- data/test/types/query.rb +101 -0
- data/test/types/service.rb +100 -0
- data/test/types/symlink.rb +93 -0
- data/test/types/tidy.rb +124 -0
- data/test/types/type.rb +135 -0
- data/test/types/user.rb +371 -0
- 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 $
|