puppet 0.9.2 → 0.13.0
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 +58 -0
- data/README +21 -18
- data/Rakefile +176 -36
- data/bin/puppet +34 -48
- data/bin/puppetca +41 -28
- data/bin/puppetd +87 -65
- data/bin/puppetdoc +99 -23
- data/bin/puppetmasterd +72 -91
- data/conf/redhat/client.init +80 -0
- data/conf/redhat/client.sysconfig +11 -0
- data/conf/redhat/fileserver.conf +12 -0
- data/conf/redhat/puppet.spec +130 -0
- data/conf/redhat/server.init +89 -0
- data/conf/redhat/server.sysconfig +9 -0
- data/examples/code/allatonce +2 -2
- data/examples/code/assignments +1 -1
- data/examples/code/classing +2 -2
- data/examples/code/components +2 -2
- data/examples/code/file.bl +5 -5
- data/examples/code/filedefaults +2 -2
- data/examples/code/fileparsing +1 -1
- data/examples/code/filerecursion +1 -1
- data/examples/code/functions +1 -1
- data/examples/code/groups +1 -1
- data/examples/code/importing +1 -1
- data/examples/code/nodes +1 -1
- data/examples/code/one +1 -1
- data/examples/code/relationships +2 -2
- data/examples/code/simpletests +5 -5
- data/examples/code/snippets/argumentdefaults +2 -2
- data/examples/code/snippets/casestatement +16 -8
- data/examples/code/snippets/classheirarchy.pp +4 -4
- data/examples/code/snippets/classincludes.pp +4 -4
- data/examples/code/snippets/classpathtest +2 -2
- data/examples/code/snippets/componentmetaparams.pp +11 -0
- data/examples/code/snippets/dirchmod +5 -5
- data/examples/code/snippets/emptyclass.pp +9 -0
- data/examples/code/snippets/failmissingexecpath.pp +1 -1
- data/examples/code/snippets/falsevalues.pp +1 -1
- data/examples/code/snippets/filecreate +5 -5
- data/examples/code/snippets/implicititeration +5 -5
- data/examples/code/snippets/multipleinstances +4 -4
- data/examples/code/snippets/namevartest +3 -3
- data/examples/code/snippets/scopetest +1 -1
- data/examples/code/snippets/selectorvalues.pp +3 -3
- data/examples/code/snippets/simpledefaults +2 -2
- data/examples/code/snippets/simpleselector +5 -5
- data/examples/code/snippets/singleary.pp +19 -0
- data/examples/root/etc/init.d/sleeper +3 -2
- data/ext/emacs/puppet-mode-init.el +6 -0
- data/ext/emacs/puppet-mode.el +189 -0
- data/ext/ldap/puppet.schema +17 -0
- data/ext/{module:puppet → module_puppet} +30 -31
- data/ext/vim/filetype.vim +9 -0
- data/ext/vim/puppet.vim +87 -0
- data/install.rb +63 -30
- data/lib/puppet.rb +216 -122
- data/lib/puppet/client.rb +51 -416
- data/lib/puppet/client/ca.rb +17 -0
- data/lib/puppet/client/dipper.rb +78 -0
- data/lib/puppet/client/file.rb +20 -0
- data/lib/puppet/client/log.rb +17 -0
- data/lib/puppet/client/master.rb +246 -0
- data/lib/puppet/client/proxy.rb +27 -0
- data/lib/puppet/client/status.rb +7 -0
- data/lib/puppet/config.rb +563 -13
- data/lib/puppet/daemon.rb +50 -22
- data/lib/puppet/element.rb +4 -4
- data/lib/puppet/event-loop.rb +1 -0
- data/lib/puppet/event-loop/better-definers.rb +367 -0
- data/lib/puppet/event-loop/event-loop.rb +355 -0
- data/lib/puppet/event-loop/signal-system.rb +220 -0
- data/lib/puppet/event.rb +9 -11
- data/lib/puppet/filetype.rb +195 -0
- data/lib/puppet/log.rb +35 -12
- data/lib/puppet/metric.rb +2 -2
- data/lib/puppet/networkclient.rb +145 -0
- data/lib/puppet/parameter.rb +335 -0
- data/lib/puppet/parser/ast.rb +42 -1453
- data/lib/puppet/parser/ast/astarray.rb +88 -0
- data/lib/puppet/parser/ast/branch.rb +47 -0
- data/lib/puppet/parser/ast/caseopt.rb +66 -0
- data/lib/puppet/parser/ast/casestatement.rb +78 -0
- data/lib/puppet/parser/ast/classdef.rb +78 -0
- data/lib/puppet/parser/ast/compdef.rb +111 -0
- data/lib/puppet/parser/ast/component.rb +105 -0
- data/lib/puppet/parser/ast/hostclass.rb +82 -0
- data/lib/puppet/parser/ast/leaf.rb +86 -0
- data/lib/puppet/parser/ast/node.rb +103 -0
- data/lib/puppet/parser/ast/nodedef.rb +68 -0
- data/lib/puppet/parser/ast/objectdef.rb +336 -0
- data/lib/puppet/parser/ast/objectparam.rb +30 -0
- data/lib/puppet/parser/ast/objectref.rb +76 -0
- data/lib/puppet/parser/ast/selector.rb +60 -0
- data/lib/puppet/parser/ast/typedefaults.rb +45 -0
- data/lib/puppet/parser/ast/vardef.rb +44 -0
- data/lib/puppet/parser/interpreter.rb +31 -14
- data/lib/puppet/parser/lexer.rb +2 -4
- data/lib/puppet/parser/parser.rb +332 -242
- data/lib/puppet/parser/scope.rb +55 -38
- data/lib/puppet/server.rb +43 -44
- data/lib/puppet/server/authstore.rb +3 -6
- data/lib/puppet/server/ca.rb +5 -2
- data/lib/puppet/server/filebucket.rb +2 -4
- data/lib/puppet/server/fileserver.rb +28 -12
- data/lib/puppet/server/logger.rb +15 -4
- data/lib/puppet/server/master.rb +62 -7
- data/lib/puppet/sslcertificates.rb +41 -607
- data/lib/puppet/sslcertificates/ca.rb +291 -0
- data/lib/puppet/sslcertificates/certificate.rb +283 -0
- data/lib/puppet/statechange.rb +6 -1
- data/lib/puppet/storage.rb +67 -56
- data/lib/puppet/transaction.rb +25 -9
- data/lib/puppet/transportable.rb +102 -22
- data/lib/puppet/type.rb +1096 -315
- data/lib/puppet/type/component.rb +30 -21
- data/lib/puppet/type/cron.rb +409 -448
- data/lib/puppet/type/exec.rb +234 -174
- data/lib/puppet/type/group.rb +65 -82
- data/lib/puppet/type/nameservice.rb +247 -3
- data/lib/puppet/type/nameservice/netinfo.rb +29 -40
- data/lib/puppet/type/nameservice/objectadd.rb +52 -66
- data/lib/puppet/type/nameservice/posix.rb +6 -194
- data/lib/puppet/type/package.rb +447 -295
- data/lib/puppet/type/package/apt.rb +51 -50
- data/lib/puppet/type/package/bsd.rb +82 -0
- data/lib/puppet/type/package/dpkg.rb +85 -88
- data/lib/puppet/type/package/rpm.rb +67 -63
- data/lib/puppet/type/package/sun.rb +119 -98
- data/lib/puppet/type/package/yum.rb +41 -37
- data/lib/puppet/type/parsedtype.rb +295 -0
- data/lib/puppet/type/parsedtype/host.rb +143 -0
- data/lib/puppet/type/parsedtype/port.rb +232 -0
- data/lib/puppet/type/parsedtype/sshkey.rb +129 -0
- data/lib/puppet/type/pfile.rb +484 -460
- data/lib/puppet/type/pfile/checksum.rb +237 -181
- data/lib/puppet/type/pfile/content.rb +67 -0
- data/lib/puppet/type/pfile/ensure.rb +212 -0
- data/lib/puppet/type/pfile/group.rb +106 -105
- data/lib/puppet/type/pfile/mode.rb +98 -101
- data/lib/puppet/type/pfile/source.rb +228 -209
- data/lib/puppet/type/pfile/type.rb +18 -21
- data/lib/puppet/type/pfile/uid.rb +127 -130
- data/lib/puppet/type/pfilebucket.rb +68 -63
- data/lib/puppet/type/schedule.rb +341 -0
- data/lib/puppet/type/service.rb +351 -255
- data/lib/puppet/type/service/base.rb +9 -14
- data/lib/puppet/type/service/debian.rb +32 -38
- data/lib/puppet/type/service/init.rb +130 -130
- data/lib/puppet/type/service/smf.rb +48 -20
- data/lib/puppet/type/state.rb +229 -16
- data/lib/puppet/type/symlink.rb +51 -63
- data/lib/puppet/type/tidy.rb +105 -102
- data/lib/puppet/type/user.rb +118 -180
- data/lib/puppet/util.rb +100 -6
- data/test/certmgr/certmgr.rb +0 -1
- data/test/client/client.rb +4 -4
- data/test/executables/puppetbin.rb +7 -14
- data/test/executables/puppetca.rb +18 -24
- data/test/executables/puppetd.rb +7 -16
- data/test/executables/puppetmasterd.rb +7 -9
- data/test/executables/puppetmodule.rb +11 -16
- data/test/language/ast.rb +11 -7
- data/test/language/interpreter.rb +1 -1
- data/test/language/scope.rb +2 -0
- data/test/language/snippets.rb +30 -5
- data/test/language/transportable.rb +77 -0
- data/test/other/config.rb +316 -0
- data/test/other/events.rb +22 -21
- data/test/other/log.rb +14 -14
- data/test/other/metrics.rb +4 -8
- data/test/other/overrides.rb +5 -5
- data/test/other/relationships.rb +4 -2
- data/test/other/storage.rb +64 -3
- data/test/other/transactions.rb +20 -20
- data/test/parser/parser.rb +7 -4
- data/test/puppet/conffiles.rb +12 -12
- data/test/puppet/defaults.rb +13 -11
- data/test/puppet/utiltest.rb +14 -11
- data/test/puppettest.rb +156 -48
- data/test/server/bucket.rb +2 -2
- data/test/server/fileserver.rb +6 -6
- data/test/server/logger.rb +19 -11
- data/test/server/master.rb +33 -4
- data/test/server/server.rb +2 -7
- data/test/types/basic.rb +5 -7
- data/test/types/component.rb +22 -18
- data/test/types/cron.rb +111 -44
- data/test/types/exec.rb +116 -59
- data/test/types/file.rb +262 -137
- data/test/types/filebucket.rb +13 -15
- data/test/types/fileignoresource.rb +12 -16
- data/test/types/filesources.rb +73 -48
- data/test/types/filetype.rb +13 -15
- data/test/types/group.rb +15 -13
- data/test/types/host.rb +146 -0
- data/test/types/package.rb +74 -63
- data/test/types/port.rb +139 -0
- data/test/types/query.rb +8 -8
- data/test/types/schedule.rb +335 -0
- data/test/types/service.rb +137 -21
- data/test/types/sshkey.rb +140 -0
- data/test/types/symlink.rb +3 -5
- data/test/types/tidy.rb +5 -14
- data/test/types/type.rb +67 -11
- data/test/types/user.rb +25 -23
- metadata +186 -122
- data/lib/puppet/type/pfile/create.rb +0 -108
- data/lib/puppet/type/pprocess.rb +0 -97
- data/lib/puppet/type/typegen.rb +0 -149
- data/lib/puppet/type/typegen/filerecord.rb +0 -243
- data/lib/puppet/type/typegen/filetype.rb +0 -316
- data/test/other/state.rb +0 -106
@@ -0,0 +1,335 @@
|
|
1
|
+
module Puppet
|
2
|
+
class Parameter < Puppet::Element
|
3
|
+
class << self
|
4
|
+
attr_reader :validater, :munger, :name, :default
|
5
|
+
attr_accessor :ismetaparameter, :element
|
6
|
+
|
7
|
+
# Define the default value for a given parameter or parameter. This
|
8
|
+
# means that 'nil' is an invalid default value. This defines
|
9
|
+
# the 'default' instance method.
|
10
|
+
def defaultto(value = nil, &block)
|
11
|
+
if block
|
12
|
+
define_method(:default, &block)
|
13
|
+
else
|
14
|
+
define_method(:default) do value end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def nodefault
|
19
|
+
undef_method :default
|
20
|
+
#if defined_method? :default
|
21
|
+
#end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Store documentation for this parameter.
|
25
|
+
def desc(str)
|
26
|
+
@doc = str
|
27
|
+
end
|
28
|
+
|
29
|
+
# This is how we munge the value. Basically, this is our
|
30
|
+
# opportunity to convert the value from one form into another.
|
31
|
+
def munge(&block)
|
32
|
+
# I need to wrap the unsafe version in begin/rescue parameterments,
|
33
|
+
# but if I directly call the block then it gets bound to the
|
34
|
+
# class's context, not the instance's, thus the two methods,
|
35
|
+
# instead of just one.
|
36
|
+
define_method(:unsafe_munge, &block)
|
37
|
+
|
38
|
+
define_method(:munge) do |*args|
|
39
|
+
begin
|
40
|
+
unsafe_munge(*args)
|
41
|
+
rescue Puppet::Error => detail
|
42
|
+
Puppet.debug "Reraising %s" % detail
|
43
|
+
raise
|
44
|
+
rescue => detail
|
45
|
+
raise Puppet::DevError, "Munging failed for class %s: %s" %
|
46
|
+
[self.name, detail]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
#@munger = block
|
50
|
+
end
|
51
|
+
|
52
|
+
#def inspect
|
53
|
+
# "Parameter(#{self.name})"
|
54
|
+
#end
|
55
|
+
|
56
|
+
# Mark whether we're the namevar.
|
57
|
+
def isnamevar
|
58
|
+
@isnamevar = true
|
59
|
+
@required = true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Is this parameter the namevar? Defaults to false.
|
63
|
+
def isnamevar?
|
64
|
+
if defined? @isnamevar
|
65
|
+
return @isnamevar
|
66
|
+
else
|
67
|
+
return false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# This parameter is required.
|
72
|
+
def isrequired
|
73
|
+
@required = true
|
74
|
+
end
|
75
|
+
|
76
|
+
# Is this parameter required? Defaults to false.
|
77
|
+
def required?
|
78
|
+
if defined? @required
|
79
|
+
return @required
|
80
|
+
else
|
81
|
+
return false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s
|
86
|
+
if self.ismetaparameter
|
87
|
+
"Puppet::Type::" + @name.to_s.capitalize
|
88
|
+
else
|
89
|
+
self.element.to_s + @name.to_s.capitalize
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Verify that we got a good value
|
94
|
+
def validate(&block)
|
95
|
+
#@validater = block
|
96
|
+
define_method(:unsafe_validate, &block)
|
97
|
+
|
98
|
+
define_method(:validate) do |*args|
|
99
|
+
begin
|
100
|
+
unsafe_validate(*args)
|
101
|
+
rescue ArgumentError, Puppet::Error, TypeError
|
102
|
+
raise
|
103
|
+
rescue => detail
|
104
|
+
raise Puppet::DevError,
|
105
|
+
"Validate method failed for class %s: %s" %
|
106
|
+
[self.name, detail]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Define a new value for our parameter.
|
112
|
+
def newvalues(*names)
|
113
|
+
@parametervalues ||= []
|
114
|
+
|
115
|
+
names.each { |name|
|
116
|
+
if @parametervalues.include?(name)
|
117
|
+
Puppet.warning "%s already has a value for %s" %
|
118
|
+
[name, name]
|
119
|
+
end
|
120
|
+
@parametervalues << name
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def aliasvalue(name, other)
|
125
|
+
@parametervalues ||= []
|
126
|
+
unless @parametervalues.include?(other)
|
127
|
+
raise Puppet::DevError,
|
128
|
+
"Cannot alias nonexistent value %s" % other
|
129
|
+
end
|
130
|
+
|
131
|
+
@aliasvalues ||= {}
|
132
|
+
@aliasvalues[name] = other
|
133
|
+
end
|
134
|
+
|
135
|
+
def alias(name)
|
136
|
+
@aliasvalues[name]
|
137
|
+
end
|
138
|
+
|
139
|
+
# Return the list of valid values.
|
140
|
+
def values
|
141
|
+
@parametervalues ||= []
|
142
|
+
@aliasvalues ||= {}
|
143
|
+
|
144
|
+
#[@aliasvalues.keys, @parametervalues.keys].flatten
|
145
|
+
@parametervalues.dup
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Just a simple method to proxy instance methods to class methods
|
150
|
+
def self.proxymethods(*values)
|
151
|
+
values.each { |val|
|
152
|
+
eval "def #{val}; self.class.#{val}; end"
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
156
|
+
# And then define one of these proxies for each method in our
|
157
|
+
# ParamHandler class.
|
158
|
+
proxymethods("required?", "isnamevar?")
|
159
|
+
|
160
|
+
attr_accessor :parent
|
161
|
+
|
162
|
+
# This doesn't work, because the instance_eval doesn't bind the inner block
|
163
|
+
# only the outer one.
|
164
|
+
# def munge(value)
|
165
|
+
# if munger = self.class.munger
|
166
|
+
# return @parent.instance_eval {
|
167
|
+
# munger.call(value)
|
168
|
+
# }
|
169
|
+
# else
|
170
|
+
# return value
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
# def validate(value)
|
175
|
+
# if validater = self.class.validater
|
176
|
+
# return @parent.instance_eval {
|
177
|
+
# validater.call(value)
|
178
|
+
# }
|
179
|
+
# end
|
180
|
+
# end
|
181
|
+
|
182
|
+
#def default
|
183
|
+
# default = self.class.default
|
184
|
+
# if default.is_a?(Proc)
|
185
|
+
# val = self.instance_eval(&default)
|
186
|
+
# return val
|
187
|
+
# else
|
188
|
+
# return default
|
189
|
+
# end
|
190
|
+
#end
|
191
|
+
|
192
|
+
def devfail(msg)
|
193
|
+
self.fail(Puppet::DevError, msg)
|
194
|
+
end
|
195
|
+
|
196
|
+
def fail(*args)
|
197
|
+
type = nil
|
198
|
+
if args[0].is_a?(Class)
|
199
|
+
type = args.shift
|
200
|
+
else
|
201
|
+
type = Puppet::Error
|
202
|
+
end
|
203
|
+
|
204
|
+
error = type.new(args.join(" "))
|
205
|
+
|
206
|
+
if defined? @parent and @parent and @parent.line
|
207
|
+
error.line = @parent.line
|
208
|
+
end
|
209
|
+
|
210
|
+
if defined? @parent and @parent and @parent.file
|
211
|
+
error.file = @parent.file
|
212
|
+
end
|
213
|
+
|
214
|
+
raise error
|
215
|
+
end
|
216
|
+
|
217
|
+
# Log a message using the parent's log level.
|
218
|
+
def log(msg)
|
219
|
+
unless @parent[:loglevel]
|
220
|
+
p @parent
|
221
|
+
self.devfail "Parent %s has no loglevel" %
|
222
|
+
@parent.name
|
223
|
+
end
|
224
|
+
Puppet::Log.create(
|
225
|
+
:level => @parent[:loglevel],
|
226
|
+
:message => msg,
|
227
|
+
:source => self
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
# each parameter class must define the name() method, and parameter
|
232
|
+
# instances do not change that name this implicitly means that a given
|
233
|
+
# object can only have one parameter instance of a given parameter
|
234
|
+
# class
|
235
|
+
def name
|
236
|
+
return self.class.name
|
237
|
+
end
|
238
|
+
|
239
|
+
# for testing whether we should actually do anything
|
240
|
+
def noop
|
241
|
+
unless defined? @noop
|
242
|
+
@noop = false
|
243
|
+
end
|
244
|
+
tmp = @noop || self.parent.noop || Puppet[:noop] || false
|
245
|
+
#debug "noop is %s" % tmp
|
246
|
+
return tmp
|
247
|
+
end
|
248
|
+
|
249
|
+
# return the full path to us, for logging and rollback; not currently
|
250
|
+
# used
|
251
|
+
def path
|
252
|
+
return [@parent.path, self.name].join("/")
|
253
|
+
end
|
254
|
+
|
255
|
+
# If the specified value is allowed, then munge appropriately.
|
256
|
+
munge do |value|
|
257
|
+
if self.class.values.empty?
|
258
|
+
# This parameter isn't using defined values to do its work.
|
259
|
+
return value
|
260
|
+
end
|
261
|
+
intern = value.to_s.intern
|
262
|
+
# If it's a valid value, always return it as a symbol.
|
263
|
+
if self.class.values.include?(intern)
|
264
|
+
retval = intern
|
265
|
+
elsif other = self.class.alias(intern)
|
266
|
+
self.info "returning alias %s for %s" % [other, intern]
|
267
|
+
retval = other
|
268
|
+
else
|
269
|
+
retval = value
|
270
|
+
end
|
271
|
+
retval
|
272
|
+
end
|
273
|
+
|
274
|
+
# Verify that the passed value is valid.
|
275
|
+
validate do |value|
|
276
|
+
if self.class.values.empty?
|
277
|
+
# This parameter isn't using defined values to do its work.
|
278
|
+
return
|
279
|
+
end
|
280
|
+
unless value.is_a?(Symbol)
|
281
|
+
value = value.to_s.intern
|
282
|
+
end
|
283
|
+
unless self.class.values.include?(value) or self.class.alias(value)
|
284
|
+
self.fail "Invalid '%s' value '%s'. Valid values are '%s'" %
|
285
|
+
[self.class.name, value, self.class.values.join(", ")]
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# This should only be called for parameters, but go ahead and make
|
290
|
+
# it possible to call for states, too.
|
291
|
+
def value
|
292
|
+
if self.is_a?(Puppet::State)
|
293
|
+
return self.should
|
294
|
+
else
|
295
|
+
if defined? @value
|
296
|
+
return @value
|
297
|
+
else
|
298
|
+
return nil
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
# Store the value provided. All of the checking should possibly be
|
304
|
+
# late-binding (e.g., users might not exist when the value is assigned
|
305
|
+
# but might when it is asked for).
|
306
|
+
def value=(value)
|
307
|
+
# If we're a parameter, just hand the processing off to the should
|
308
|
+
# method.
|
309
|
+
if self.is_a?(Puppet::State)
|
310
|
+
return self.should = value
|
311
|
+
end
|
312
|
+
if respond_to?(:validate)
|
313
|
+
validate(value)
|
314
|
+
end
|
315
|
+
|
316
|
+
if respond_to?(:munge)
|
317
|
+
value = munge(value)
|
318
|
+
end
|
319
|
+
@value = value
|
320
|
+
end
|
321
|
+
|
322
|
+
def inspect
|
323
|
+
s = "Parameter(%s = %s" % [self.name, self.value || "nil"]
|
324
|
+
if defined? @parent
|
325
|
+
s += ", @parent = %s)" % @parent
|
326
|
+
else
|
327
|
+
s += ")"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def to_s
|
332
|
+
s = "Parameter(%s)" % self.name
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
data/lib/puppet/parser/ast.rb
CHANGED
@@ -4,13 +4,17 @@ require 'puppet'
|
|
4
4
|
|
5
5
|
module Puppet
|
6
6
|
module Parser
|
7
|
-
|
8
7
|
# The base class for all of the objects that make up the parse trees.
|
9
8
|
# Handles things like file name, line #, and also does the initialization
|
10
9
|
# for all of the parameters of all of the child objects.
|
11
10
|
class AST
|
12
|
-
|
13
|
-
Puppet
|
11
|
+
# Do this so I don't have to type the full path in all of the subclasses
|
12
|
+
AST = Puppet::Parser::AST
|
13
|
+
|
14
|
+
Puppet.setdefaults("ast",
|
15
|
+
[:typecheck, true, "Whether to validate types during parsing."],
|
16
|
+
[:paramcheck, true, "Whether to validate parameters during parsing."]
|
17
|
+
)
|
14
18
|
attr_accessor :line, :file, :parent
|
15
19
|
|
16
20
|
# Just used for 'tree', which is only used in debugging.
|
@@ -56,19 +60,24 @@ module Puppet
|
|
56
60
|
def safeevaluate(*args)
|
57
61
|
begin
|
58
62
|
self.evaluate(*args)
|
59
|
-
rescue Puppet::DevError
|
63
|
+
rescue Puppet::DevError => except
|
64
|
+
except.line ||= @line
|
65
|
+
except.file ||= @file
|
60
66
|
raise
|
61
|
-
rescue Puppet::ParseError
|
67
|
+
rescue Puppet::ParseError => except
|
68
|
+
except.line ||= @line
|
69
|
+
except.file ||= @file
|
62
70
|
raise
|
63
71
|
rescue => detail
|
64
72
|
if Puppet[:debug]
|
65
|
-
puts
|
73
|
+
puts detail.backtrace
|
66
74
|
end
|
67
75
|
error = Puppet::DevError.new(
|
68
76
|
"Child of type %s failed with error %s: %s" %
|
69
77
|
[self.class, detail.class, detail.to_s]
|
70
78
|
)
|
71
|
-
error.
|
79
|
+
error.line ||= @line
|
80
|
+
error.file ||= @file
|
72
81
|
raise error
|
73
82
|
end
|
74
83
|
end
|
@@ -81,23 +90,22 @@ module Puppet
|
|
81
90
|
"(" + self.class.to_s.sub(/.+::/,'') + ")"
|
82
91
|
end
|
83
92
|
|
84
|
-
# Initialize the object. Requires a hash as the argument, and
|
85
|
-
# each of the parameters of the hash and calls the settor
|
86
|
-
# them. This is probably pretty inefficient and should
|
87
|
-
# at some point.
|
93
|
+
# Initialize the object. Requires a hash as the argument, and
|
94
|
+
# takes each of the parameters of the hash and calls the settor
|
95
|
+
# method for them. This is probably pretty inefficient and should
|
96
|
+
# likely be changed at some point.
|
88
97
|
def initialize(args)
|
89
98
|
@file = nil
|
90
99
|
@line = nil
|
91
100
|
args.each { |param,value|
|
92
101
|
method = param.to_s + "="
|
93
102
|
unless self.respond_to?(method)
|
94
|
-
error = Puppet::
|
103
|
+
error = Puppet::ParseError.new(
|
95
104
|
"Invalid parameter %s to object class %s" %
|
96
105
|
[param,self.class.to_s]
|
97
106
|
)
|
98
107
|
error.line = self.line
|
99
108
|
error.file = self.file
|
100
|
-
error.stack = caller
|
101
109
|
raise error
|
102
110
|
end
|
103
111
|
|
@@ -109,1452 +117,33 @@ module Puppet
|
|
109
117
|
"Could not set parameter %s on class %s: %s" %
|
110
118
|
[method,self.class.to_s,detail]
|
111
119
|
)
|
112
|
-
error.
|
120
|
+
error.line ||= self.line
|
121
|
+
error.file ||= self.file
|
113
122
|
raise error
|
114
123
|
end
|
115
124
|
}
|
116
125
|
end
|
117
|
-
|
118
|
-
# The parent class of all AST objects that contain other AST objects.
|
119
|
-
# Everything but the really simple objects descend from this. It is
|
120
|
-
# important to note that Branch objects contain other AST objects only --
|
121
|
-
# if you want to contain values, use a descendent of the AST::Leaf class.
|
122
|
-
class Branch < AST
|
123
|
-
include Enumerable
|
124
|
-
attr_accessor :pin, :children
|
125
|
-
|
126
|
-
# Yield each contained AST node in turn. Used mostly by 'evaluate'.
|
127
|
-
# This definition means that I don't have to override 'evaluate'
|
128
|
-
# every time, but each child of Branch will likely need to override
|
129
|
-
# this method.
|
130
|
-
def each
|
131
|
-
@children.each { |child|
|
132
|
-
yield child
|
133
|
-
}
|
134
|
-
end
|
135
|
-
|
136
|
-
# Initialize our object. Largely relies on the method from the base
|
137
|
-
# class, but also does some verification.
|
138
|
-
def initialize(arghash)
|
139
|
-
super(arghash)
|
140
|
-
|
141
|
-
# Create the hash, if it was not set at initialization time.
|
142
|
-
unless defined? @children
|
143
|
-
@children = []
|
144
|
-
end
|
145
|
-
|
146
|
-
# Verify that we only got valid AST nodes.
|
147
|
-
@children.each { |child|
|
148
|
-
unless child.is_a?(AST)
|
149
|
-
raise Puppet::DevError,
|
150
|
-
"child %s is not an ast" % child
|
151
|
-
end
|
152
|
-
}
|
153
|
-
end
|
154
|
-
|
155
|
-
# Pretty-print the parse tree.
|
156
|
-
def tree(indent = 0)
|
157
|
-
return ((@@indline * indent) +
|
158
|
-
self.typewrap(self.pin)) + "\n" + self.collect { |child|
|
159
|
-
child.tree(indent + 1)
|
160
|
-
}.join("\n")
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
# The basic container class. This object behaves almost identically
|
165
|
-
# to a normal array except at initialization time. Note that its name
|
166
|
-
# is 'AST::ASTArray', rather than plain 'AST::Array'; I had too many
|
167
|
-
# bugs when it was just 'AST::Array', because things like
|
168
|
-
# 'object.is_a?(Array)' never behaved as I expected.
|
169
|
-
class ASTArray < AST::Branch
|
170
|
-
include Enumerable
|
171
|
-
|
172
|
-
# Return a child by index. Probably never used.
|
173
|
-
def [](index)
|
174
|
-
@children[index]
|
175
|
-
end
|
176
|
-
|
177
|
-
# Evaluate our children.
|
178
|
-
def evaluate(scope)
|
179
|
-
rets = nil
|
180
|
-
# We basically always operate declaratively, and when we
|
181
|
-
# do we need to evaluate the settor-like statements first. This
|
182
|
-
# is basically variable and type-default declarations.
|
183
|
-
if scope.declarative?
|
184
|
-
test = [
|
185
|
-
AST::VarDef, AST::TypeDefaults
|
186
|
-
]
|
187
|
-
|
188
|
-
settors = []
|
189
|
-
others = []
|
190
|
-
@children.each { |child|
|
191
|
-
if test.include?(child.class)
|
192
|
-
settors.push child
|
193
|
-
else
|
194
|
-
others.push child
|
195
|
-
end
|
196
|
-
}
|
197
|
-
rets = [settors,others].flatten.collect { |child|
|
198
|
-
child.safeevaluate(scope)
|
199
|
-
}
|
200
|
-
else
|
201
|
-
# If we're not declarative, just do everything in order.
|
202
|
-
rets = @children.collect { |item|
|
203
|
-
item.safeevaluate(scope)
|
204
|
-
}
|
205
|
-
end
|
206
|
-
rets = rets.reject { |obj| obj.nil? }
|
207
|
-
end
|
208
|
-
|
209
|
-
def push(*ary)
|
210
|
-
ary.each { |child|
|
211
|
-
#Puppet.debug "adding %s(%s) of type %s to %s" %
|
212
|
-
# [child, child.object_id, child.class.to_s.sub(/.+::/,''),
|
213
|
-
# self.object_id]
|
214
|
-
@children.push(child)
|
215
|
-
}
|
216
|
-
|
217
|
-
return self
|
218
|
-
end
|
219
|
-
|
220
|
-
# Convert to a string. Only used for printing the parse tree.
|
221
|
-
def to_s
|
222
|
-
return "[" + @children.collect { |child|
|
223
|
-
child.to_s
|
224
|
-
}.join(", ") + "]"
|
225
|
-
end
|
226
|
-
|
227
|
-
# Print the parse tree.
|
228
|
-
def tree(indent = 0)
|
229
|
-
#puts((AST.indent * indent) + self.pin)
|
230
|
-
self.collect { |child|
|
231
|
-
child.tree(indent)
|
232
|
-
}.join("\n" + (AST.midline * (indent+1)) + "\n")
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
# A simple container class, containing the parameters for an object.
|
237
|
-
# Used for abstracting the grammar declarations. Basically unnecessary
|
238
|
-
# except that I kept finding bugs because I had too many arrays that
|
239
|
-
# meant completely different things.
|
240
|
-
class ObjectInst < ASTArray; end
|
241
|
-
|
242
|
-
# Another simple container class to make sure we can correctly arrayfy
|
243
|
-
# things.
|
244
|
-
class CompArgument < ASTArray; end
|
245
|
-
|
246
|
-
# The base class for all of the leaves of the parse trees. These
|
247
|
-
# basically just have types and values. Both of these parameters
|
248
|
-
# are simple values, not AST objects.
|
249
|
-
class Leaf < AST
|
250
|
-
attr_accessor :value, :type
|
251
|
-
|
252
|
-
# Return our value.
|
253
|
-
def evaluate(scope)
|
254
|
-
return @value
|
255
|
-
end
|
256
|
-
|
257
|
-
# Print the value in parse tree context.
|
258
|
-
def tree(indent = 0)
|
259
|
-
return ((@@indent * indent) + self.typewrap(self.value))
|
260
|
-
end
|
261
|
-
|
262
|
-
def to_s
|
263
|
-
return @value
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
# The boolean class. True or false. Converts the string it receives
|
268
|
-
# to a Ruby boolean.
|
269
|
-
class Boolean < AST::Leaf
|
270
|
-
|
271
|
-
# Use the parent method, but then convert to a real boolean.
|
272
|
-
def initialize(hash)
|
273
|
-
super
|
274
|
-
|
275
|
-
unless @value == 'true' or @value == 'false'
|
276
|
-
error = Puppet::DevError.new(
|
277
|
-
"'%s' is not a boolean" % @value
|
278
|
-
)
|
279
|
-
error.stack = caller
|
280
|
-
raise error
|
281
|
-
end
|
282
|
-
if @value == 'true'
|
283
|
-
@value = true
|
284
|
-
else
|
285
|
-
@value = false
|
286
|
-
end
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
# The base string class.
|
291
|
-
class String < AST::Leaf
|
292
|
-
# Interpolate the string looking for variables, and then return
|
293
|
-
# the result.
|
294
|
-
def evaluate(scope)
|
295
|
-
return scope.strinterp(@value)
|
296
|
-
end
|
297
|
-
end
|
298
|
-
#---------------------------------------------------------------
|
299
|
-
|
300
|
-
# The 'default' option on case statements and selectors.
|
301
|
-
class Default < AST::Leaf; end
|
302
|
-
|
303
|
-
# Capitalized words; used mostly for type-defaults, but also
|
304
|
-
# get returned by the lexer any other time an unquoted capitalized
|
305
|
-
# word is found.
|
306
|
-
class Type < AST::Leaf; end
|
307
|
-
|
308
|
-
# Lower-case words.
|
309
|
-
class Name < AST::Leaf; end
|
310
|
-
|
311
|
-
# A simple variable. This object is only used during interpolation;
|
312
|
-
# the VarDef class is used for assignment.
|
313
|
-
class Variable < Name
|
314
|
-
# Looks up the value of the object in the scope tree (does
|
315
|
-
# not include syntactical constructs, like '$' and '{}').
|
316
|
-
def evaluate(scope)
|
317
|
-
begin
|
318
|
-
return scope.lookupvar(@value)
|
319
|
-
rescue Puppet::ParseError => except
|
320
|
-
except.line = self.line
|
321
|
-
except.file = self.file
|
322
|
-
raise except
|
323
|
-
rescue => detail
|
324
|
-
error = Puppet::DevError.new(detail)
|
325
|
-
error.line = self.line
|
326
|
-
error.file = self.file
|
327
|
-
error.stack = caller
|
328
|
-
raise error
|
329
|
-
end
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
# Any normal puppet object declaration. Can result in a class or a
|
334
|
-
# component, in addition to builtin types.
|
335
|
-
class ObjectDef < AST::Branch
|
336
|
-
attr_accessor :name, :type
|
337
|
-
attr_reader :params
|
338
|
-
|
339
|
-
# probably not used at all
|
340
|
-
def []=(index,obj)
|
341
|
-
@params[index] = obj
|
342
|
-
end
|
343
|
-
|
344
|
-
# probably not used at all
|
345
|
-
def [](index)
|
346
|
-
return @params[index]
|
347
|
-
end
|
348
|
-
|
349
|
-
# Auto-generate a name
|
350
|
-
def autoname(type, object)
|
351
|
-
case object
|
352
|
-
when Puppet::Type:
|
353
|
-
raise Puppet::Error,
|
354
|
-
"Built-in types must be provided with a name"
|
355
|
-
when HostClass:
|
356
|
-
return type
|
357
|
-
else
|
358
|
-
Puppet.info "Autogenerating name for object of type %s" %
|
359
|
-
type
|
360
|
-
return [type, "-", self.object_id].join("")
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
# Iterate across all of our children.
|
365
|
-
def each
|
366
|
-
[@type,@name,@params].flatten.each { |param|
|
367
|
-
#Puppet.debug("yielding param %s" % param)
|
368
|
-
yield param
|
369
|
-
}
|
370
|
-
end
|
371
|
-
|
372
|
-
# Does not actually return an object; instead sets an object
|
373
|
-
# in the current scope.
|
374
|
-
def evaluate(scope)
|
375
|
-
hash = {}
|
376
|
-
|
377
|
-
# Get our type and name.
|
378
|
-
objtype = @type.safeevaluate(scope)
|
379
|
-
|
380
|
-
# If the type was a variable, we wouldn't have typechecked yet.
|
381
|
-
# Do it now, if so.
|
382
|
-
unless @checked
|
383
|
-
self.typecheck(objtype)
|
384
|
-
end
|
385
|
-
|
386
|
-
# See if our object was defined
|
387
|
-
begin
|
388
|
-
object = scope.lookuptype(objtype)
|
389
|
-
rescue Puppet::ParseError => except
|
390
|
-
except.line = self.line
|
391
|
-
except.file = self.file
|
392
|
-
raise except
|
393
|
-
rescue => detail
|
394
|
-
error = Puppet::ParseError.new(detail)
|
395
|
-
error.line = self.line
|
396
|
-
error.file = self.file
|
397
|
-
error.stack = caller
|
398
|
-
raise error
|
399
|
-
end
|
400
|
-
|
401
|
-
unless object
|
402
|
-
# If not, verify that it's a builtin type
|
403
|
-
begin
|
404
|
-
object = Puppet::Type.type(objtype)
|
405
|
-
rescue TypeError
|
406
|
-
# otherwise, the user specified an invalid type
|
407
|
-
error = Puppet::ParseError.new(
|
408
|
-
"Invalid type %s" % objtype
|
409
|
-
)
|
410
|
-
error.line = @line
|
411
|
-
error.file = @file
|
412
|
-
raise error
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
# Autogenerate the name if one was not passed.
|
417
|
-
if defined? @name
|
418
|
-
objnames = @name.safeevaluate(scope)
|
419
|
-
else
|
420
|
-
objnames = self.autoname(objtype, object)
|
421
|
-
end
|
422
|
-
|
423
|
-
# it's easier to always use an array, even for only one name
|
424
|
-
unless objnames.is_a?(Array)
|
425
|
-
objnames = [objnames]
|
426
|
-
end
|
427
|
-
|
428
|
-
# Retrieve the defaults for our type
|
429
|
-
hash = getdefaults(objtype, scope)
|
430
|
-
|
431
|
-
# then set all of the specified params
|
432
|
-
@params.each { |param|
|
433
|
-
ary = param.safeevaluate(scope)
|
434
|
-
hash[ary[0]] = ary[1]
|
435
|
-
}
|
436
|
-
|
437
|
-
# this is where our implicit iteration takes place;
|
438
|
-
# if someone passed an array as the name, then we act
|
439
|
-
# just like the called us many times
|
440
|
-
objnames.collect { |objname|
|
441
|
-
# If the object is a class, that means it's a builtin type
|
442
|
-
if object.is_a?(Class)
|
443
|
-
begin
|
444
|
-
Puppet.debug(
|
445
|
-
("Setting object '%s' " +
|
446
|
-
"in scope %s " +
|
447
|
-
"with arguments %s") %
|
448
|
-
[objname, scope.object_id, hash.inspect]
|
449
|
-
)
|
450
|
-
obj = scope.setobject(
|
451
|
-
objtype,
|
452
|
-
objname,
|
453
|
-
hash,
|
454
|
-
@file,
|
455
|
-
@line
|
456
|
-
)
|
457
|
-
rescue Puppet::ParseError => except
|
458
|
-
except.line = self.line
|
459
|
-
except.file = self.file
|
460
|
-
raise except
|
461
|
-
rescue => detail
|
462
|
-
error = Puppet::ParseError.new(detail)
|
463
|
-
error.line = self.line
|
464
|
-
error.file = self.file
|
465
|
-
error.stack = caller
|
466
|
-
raise error
|
467
|
-
end
|
468
|
-
else
|
469
|
-
# but things like components create a new type; if we find
|
470
|
-
# one of those, evaluate that with our arguments
|
471
|
-
Puppet.debug("Calling object '%s' with arguments %s" %
|
472
|
-
[object.name, hash.inspect])
|
473
|
-
object.safeevaluate(scope,hash,objtype,objname)
|
474
|
-
end
|
475
|
-
}.reject { |obj| obj.nil? }
|
476
|
-
end
|
477
|
-
|
478
|
-
# Retrieve the defaults for our type
|
479
|
-
def getdefaults(objtype, scope)
|
480
|
-
# first, retrieve the defaults
|
481
|
-
begin
|
482
|
-
defaults = scope.lookupdefaults(objtype)
|
483
|
-
if defaults.length > 0
|
484
|
-
Puppet.debug "Got defaults for %s: %s" %
|
485
|
-
[objtype,defaults.inspect]
|
486
|
-
end
|
487
|
-
rescue => detail
|
488
|
-
raise Puppet::DevError,
|
489
|
-
"Could not lookup defaults for %s: %s" %
|
490
|
-
[objtype, detail.to_s]
|
491
|
-
end
|
492
|
-
|
493
|
-
hash = {}
|
494
|
-
# Add any found defaults to our argument list
|
495
|
-
defaults.each { |var,value|
|
496
|
-
Puppet.debug "Found default %s for %s" %
|
497
|
-
[var,objtype]
|
498
|
-
|
499
|
-
hash[var] = value
|
500
|
-
}
|
501
|
-
|
502
|
-
return hash
|
503
|
-
end
|
504
|
-
|
505
|
-
# Create our ObjectDef. Handles type checking for us.
|
506
|
-
def initialize(hash)
|
507
|
-
@checked = false
|
508
|
-
super
|
509
|
-
|
510
|
-
if @type.is_a?(Variable)
|
511
|
-
Puppet.debug "Delaying typecheck"
|
512
|
-
return
|
513
|
-
else
|
514
|
-
self.typecheck(@type.value)
|
515
|
-
|
516
|
-
objtype = @type.value
|
517
|
-
end
|
518
|
-
|
519
|
-
end
|
520
|
-
|
521
|
-
# Verify that all passed parameters are valid
|
522
|
-
def paramcheck(builtin, objtype)
|
523
|
-
# This defaults to true
|
524
|
-
unless Puppet[:paramcheck]
|
525
|
-
return
|
526
|
-
end
|
527
|
-
|
528
|
-
@params.each { |param|
|
529
|
-
if builtin
|
530
|
-
self.parambuiltincheck(builtin, param)
|
531
|
-
else
|
532
|
-
self.paramdefinedcheck(objtype, param)
|
533
|
-
end
|
534
|
-
}
|
535
|
-
end
|
536
|
-
|
537
|
-
def parambuiltincheck(type, param)
|
538
|
-
unless param.is_a?(AST::ObjectParam)
|
539
|
-
raise Puppet::DevError,
|
540
|
-
"Got something other than param"
|
541
|
-
end
|
542
|
-
begin
|
543
|
-
pname = param.param.value
|
544
|
-
rescue => detail
|
545
|
-
raise Puppet::DevError, detail.to_s
|
546
|
-
end
|
547
|
-
next if pname == "name" # always allow these
|
548
|
-
unless type.validarg?(pname)
|
549
|
-
error = Puppet::ParseError.new(
|
550
|
-
"Invalid parameter '%s' for type '%s'" %
|
551
|
-
[pname,type.name]
|
552
|
-
)
|
553
|
-
error.stack = caller
|
554
|
-
error.line = self.line
|
555
|
-
error.file = self.file
|
556
|
-
raise error
|
557
|
-
end
|
558
|
-
end
|
559
|
-
|
560
|
-
def paramdefinedcheck(objtype, param)
|
561
|
-
# FIXME we might need to do more here eventually...
|
562
|
-
if Puppet::Type.metaparam?(param.param.value.intern)
|
563
|
-
next
|
564
|
-
end
|
565
|
-
|
566
|
-
begin
|
567
|
-
pname = param.param.value
|
568
|
-
rescue => detail
|
569
|
-
raise Puppet::DevError, detail.to_s
|
570
|
-
end
|
571
|
-
|
572
|
-
unless @@settypes[objtype].validarg?(pname)
|
573
|
-
error = Puppet::ParseError.new(
|
574
|
-
"Invalid parameter '%s' for type '%s'" %
|
575
|
-
[pname,objtype]
|
576
|
-
)
|
577
|
-
error.stack = caller
|
578
|
-
error.line = self.line
|
579
|
-
error.file = self.file
|
580
|
-
raise error
|
581
|
-
end
|
582
|
-
end
|
583
|
-
|
584
|
-
# Set the parameters for our object.
|
585
|
-
def params=(params)
|
586
|
-
if params.is_a?(AST::ASTArray)
|
587
|
-
@params = params
|
588
|
-
else
|
589
|
-
@params = AST::ASTArray.new(
|
590
|
-
:line => params.line,
|
591
|
-
:file => params.file,
|
592
|
-
:children => [params]
|
593
|
-
)
|
594
|
-
end
|
595
|
-
end
|
596
|
-
|
597
|
-
# Print this object out.
|
598
|
-
def tree(indent = 0)
|
599
|
-
return [
|
600
|
-
@type.tree(indent + 1),
|
601
|
-
@name.tree(indent + 1),
|
602
|
-
((@@indline * indent) + self.typewrap(self.pin)),
|
603
|
-
@params.collect { |param|
|
604
|
-
begin
|
605
|
-
param.tree(indent + 1)
|
606
|
-
rescue NoMethodError => detail
|
607
|
-
Puppet.err @params.inspect
|
608
|
-
error = Puppet::DevError.new(
|
609
|
-
"failed to tree a %s" % self.class
|
610
|
-
)
|
611
|
-
error.stack = caller
|
612
|
-
raise error
|
613
|
-
end
|
614
|
-
}.join("\n")
|
615
|
-
].join("\n")
|
616
|
-
end
|
617
|
-
|
618
|
-
# Verify that the type is valid. This throws an error if there's
|
619
|
-
# a problem, so the return value doesn't matter
|
620
|
-
def typecheck(objtype)
|
621
|
-
# This will basically always be on, but I wanted to make it at
|
622
|
-
# least simple to turn off if it came to that
|
623
|
-
unless Puppet[:typecheck]
|
624
|
-
return
|
625
|
-
end
|
626
|
-
|
627
|
-
builtin = false
|
628
|
-
begin
|
629
|
-
builtin = Puppet::Type.type(objtype)
|
630
|
-
rescue TypeError
|
631
|
-
# nothing; we've already set builtin to false
|
632
|
-
end
|
633
|
-
|
634
|
-
unless builtin or @@settypes.include?(objtype)
|
635
|
-
error = Puppet::ParseError.new(
|
636
|
-
"Unknown type '%s'" % objtype
|
637
|
-
)
|
638
|
-
error.line = self.line
|
639
|
-
error.file = self.file
|
640
|
-
error.stack = caller
|
641
|
-
raise error
|
642
|
-
end
|
643
|
-
|
644
|
-
unless builtin
|
645
|
-
Puppet.debug "%s is a defined type" % objtype
|
646
|
-
end
|
647
|
-
|
648
|
-
self.paramcheck(builtin, objtype)
|
649
|
-
|
650
|
-
@checked = true
|
651
|
-
end
|
652
|
-
|
653
|
-
def to_s
|
654
|
-
return "%s => { %s }" % [@name,
|
655
|
-
@params.collect { |param|
|
656
|
-
param.to_s
|
657
|
-
}.join("\n")
|
658
|
-
]
|
659
|
-
end
|
660
|
-
end
|
661
|
-
|
662
|
-
# A reference to an object. Only valid as an rvalue.
|
663
|
-
class ObjectRef < AST::Branch
|
664
|
-
attr_accessor :name, :type
|
665
|
-
|
666
|
-
def each
|
667
|
-
[@type,@name].flatten.each { |param|
|
668
|
-
#Puppet.debug("yielding param %s" % param)
|
669
|
-
yield param
|
670
|
-
}
|
671
|
-
end
|
672
|
-
|
673
|
-
# Evaluate our object, but just return a simple array of the type
|
674
|
-
# and name.
|
675
|
-
def evaluate(scope)
|
676
|
-
objtype = @type.safeevaluate(scope)
|
677
|
-
objnames = @name.safeevaluate(scope)
|
678
|
-
|
679
|
-
# it's easier to always use an array, even for only one name
|
680
|
-
unless objnames.is_a?(Array)
|
681
|
-
objnames = [objnames]
|
682
|
-
end
|
683
|
-
|
684
|
-
# Verify we can find the object.
|
685
|
-
begin
|
686
|
-
object = scope.lookuptype(objtype)
|
687
|
-
rescue Puppet::ParseError => except
|
688
|
-
except.line = self.line
|
689
|
-
except.file = self.file
|
690
|
-
raise except
|
691
|
-
rescue => detail
|
692
|
-
error = Puppet::ParseError.new(detail)
|
693
|
-
error.line = self.line
|
694
|
-
error.file = self.file
|
695
|
-
error.stack = caller
|
696
|
-
raise error
|
697
|
-
end
|
698
|
-
Puppet.debug "ObjectRef returned type %s" % object
|
699
|
-
|
700
|
-
# should we implicitly iterate here?
|
701
|
-
# yes, i believe that we essentially have to...
|
702
|
-
objnames.collect { |objname|
|
703
|
-
if object.is_a?(AST::Component)
|
704
|
-
objname = "%s[%s]" % [objtype,objname]
|
705
|
-
objtype = "component"
|
706
|
-
end
|
707
|
-
[objtype,objname]
|
708
|
-
}.reject { |obj| obj.nil? }
|
709
|
-
end
|
710
|
-
|
711
|
-
def tree(indent = 0)
|
712
|
-
return [
|
713
|
-
@type.tree(indent + 1),
|
714
|
-
@name.tree(indent + 1),
|
715
|
-
((@@indline * indent) + self.typewrap(self.pin))
|
716
|
-
].join("\n")
|
717
|
-
end
|
718
|
-
|
719
|
-
def to_s
|
720
|
-
return "%s[%s]" % [@name,@type]
|
721
|
-
end
|
722
|
-
end
|
723
|
-
|
724
|
-
# The AST object for the parameters inside ObjectDefs and Selectors.
|
725
|
-
class ObjectParam < AST::Branch
|
726
|
-
attr_accessor :value, :param
|
727
|
-
|
728
|
-
def each
|
729
|
-
[@param,@value].each { |child| yield child }
|
730
|
-
end
|
731
|
-
|
732
|
-
# Return the parameter and the value.
|
733
|
-
def evaluate(scope)
|
734
|
-
param = @param.safeevaluate(scope)
|
735
|
-
value = @value.safeevaluate(scope)
|
736
|
-
return [param, value]
|
737
|
-
end
|
738
|
-
|
739
|
-
def tree(indent = 0)
|
740
|
-
return [
|
741
|
-
@param.tree(indent + 1),
|
742
|
-
((@@indline * indent) + self.typewrap(self.pin)),
|
743
|
-
@value.tree(indent + 1)
|
744
|
-
].join("\n")
|
745
|
-
end
|
746
|
-
|
747
|
-
def to_s
|
748
|
-
return "%s => %s" % [@param,@value]
|
749
|
-
end
|
750
|
-
end
|
751
|
-
|
752
|
-
# The basic logical structure in Puppet. Supports a list of
|
753
|
-
# tests and statement arrays.
|
754
|
-
class CaseStatement < AST::Branch
|
755
|
-
attr_accessor :test, :options, :default
|
756
|
-
|
757
|
-
# Short-curcuit evaluation. Return the value of the statements for
|
758
|
-
# the first option that matches.
|
759
|
-
def evaluate(scope)
|
760
|
-
value = @test.safeevaluate(scope)
|
761
|
-
|
762
|
-
retvalue = nil
|
763
|
-
found = false
|
764
|
-
|
765
|
-
# Iterate across the options looking for a match.
|
766
|
-
@options.each { |option|
|
767
|
-
if option.eachvalue { |opval| break true if opval == value }
|
768
|
-
# we found a matching option
|
769
|
-
retvalue = option.safeevaluate(scope)
|
770
|
-
found = true
|
771
|
-
break
|
772
|
-
end
|
773
|
-
}
|
774
|
-
|
775
|
-
# Unless we found something, look for the default.
|
776
|
-
unless found
|
777
|
-
if defined? @default
|
778
|
-
retvalue = @default.safeevaluate(scope)
|
779
|
-
else
|
780
|
-
Puppet.debug "No true answers and no default"
|
781
|
-
end
|
782
|
-
end
|
783
|
-
return retvalue
|
784
|
-
end
|
785
|
-
|
786
|
-
# Do some input validation on our options.
|
787
|
-
def initialize(hash)
|
788
|
-
values = {}
|
789
|
-
|
790
|
-
super
|
791
|
-
# this won't work if we move away from only allowing constants
|
792
|
-
# here
|
793
|
-
# but for now, it's fine and useful
|
794
|
-
@options.each { |option|
|
795
|
-
if option.default?
|
796
|
-
@default = option
|
797
|
-
end
|
798
|
-
option.eachvalue { |val|
|
799
|
-
if values.include?(val)
|
800
|
-
raise Puppet::ParseError,
|
801
|
-
"Value %s appears twice in case statement" %
|
802
|
-
val
|
803
|
-
else
|
804
|
-
values[val] = true
|
805
|
-
end
|
806
|
-
}
|
807
|
-
}
|
808
|
-
end
|
809
|
-
|
810
|
-
def tree(indent = 0)
|
811
|
-
rettree = [
|
812
|
-
@test.tree(indent + 1),
|
813
|
-
((@@indline * indent) + self.typewrap(self.pin)),
|
814
|
-
@options.tree(indent + 1)
|
815
|
-
]
|
816
|
-
|
817
|
-
return rettree.flatten.join("\n")
|
818
|
-
end
|
819
|
-
|
820
|
-
def each
|
821
|
-
[@test,@options].each { |child| yield child }
|
822
|
-
end
|
823
|
-
end
|
824
|
-
|
825
|
-
# Each individual option in a case statement.
|
826
|
-
class CaseOpt < AST::Branch
|
827
|
-
attr_accessor :value, :statements
|
828
|
-
|
829
|
-
# CaseOpt is a bit special -- we just want the value first,
|
830
|
-
# so that CaseStatement can compare, and then it will selectively
|
831
|
-
# decide whether to fully evaluate this option
|
832
|
-
|
833
|
-
def each
|
834
|
-
[@value,@statements].each { |child| yield child }
|
835
|
-
end
|
836
|
-
|
837
|
-
# Are we the default option?
|
838
|
-
def default?
|
839
|
-
if defined? @default
|
840
|
-
return @default
|
841
|
-
end
|
842
|
-
|
843
|
-
if @value.is_a?(AST::ASTArray)
|
844
|
-
@value.each { |subval|
|
845
|
-
if subval.is_a?(AST::Default)
|
846
|
-
@default = true
|
847
|
-
break
|
848
|
-
end
|
849
|
-
}
|
850
|
-
else
|
851
|
-
if @value.is_a?(AST::Default)
|
852
|
-
@default = true
|
853
|
-
end
|
854
|
-
end
|
855
|
-
|
856
|
-
unless defined? @default
|
857
|
-
@default = false
|
858
|
-
end
|
859
|
-
|
860
|
-
return @default
|
861
|
-
end
|
862
|
-
|
863
|
-
# You can specify a list of values; return each in turn.
|
864
|
-
def eachvalue
|
865
|
-
if @value.is_a?(AST::ASTArray)
|
866
|
-
@value.each { |subval|
|
867
|
-
yield subval.value
|
868
|
-
}
|
869
|
-
else
|
870
|
-
yield @value.value
|
871
|
-
end
|
872
|
-
end
|
873
|
-
|
874
|
-
# Evaluate the actual statements; this only gets called if
|
875
|
-
# our option matched.
|
876
|
-
def evaluate(scope)
|
877
|
-
return @statements.safeevaluate(scope.newscope)
|
878
|
-
end
|
879
|
-
|
880
|
-
def tree(indent = 0)
|
881
|
-
rettree = [
|
882
|
-
@value.tree(indent + 1),
|
883
|
-
((@@indline * indent) + self.typewrap(self.pin)),
|
884
|
-
@statements.tree(indent + 1)
|
885
|
-
]
|
886
|
-
return rettree.flatten.join("\n")
|
887
|
-
end
|
888
|
-
end
|
889
|
-
|
890
|
-
# The inline conditional operator. Unlike CaseStatement, which executes
|
891
|
-
# code, we just return a value.
|
892
|
-
class Selector < AST::Branch
|
893
|
-
attr_accessor :param, :values
|
894
|
-
|
895
|
-
def each
|
896
|
-
[@param,@values].each { |child| yield child }
|
897
|
-
end
|
898
|
-
|
899
|
-
# Find the value that corresponds with the test.
|
900
|
-
def evaluate(scope)
|
901
|
-
retvalue = nil
|
902
|
-
found = nil
|
903
|
-
|
904
|
-
# Get our parameter.
|
905
|
-
paramvalue = @param.safeevaluate(scope)
|
906
|
-
|
907
|
-
default = nil
|
908
|
-
|
909
|
-
# Then look for a match in the options.
|
910
|
-
@values.each { |obj|
|
911
|
-
param = obj.param.safeevaluate(scope)
|
912
|
-
if param == paramvalue
|
913
|
-
# we found a matching option
|
914
|
-
retvalue = obj.value.safeevaluate(scope)
|
915
|
-
found = true
|
916
|
-
break
|
917
|
-
elsif obj.param.is_a?(Default)
|
918
|
-
default = obj
|
919
|
-
end
|
920
|
-
}
|
921
|
-
|
922
|
-
# Unless we found something, look for the default.
|
923
|
-
unless found
|
924
|
-
if default
|
925
|
-
retvalue = default.value.safeevaluate(scope)
|
926
|
-
else
|
927
|
-
error = Puppet::ParseError.new(
|
928
|
-
"No value for selector param '%s'" % paramvalue
|
929
|
-
)
|
930
|
-
error.line = self.line
|
931
|
-
error.file = self.file
|
932
|
-
raise error
|
933
|
-
end
|
934
|
-
end
|
935
|
-
|
936
|
-
return retvalue
|
937
|
-
end
|
938
|
-
|
939
|
-
def tree(indent = 0)
|
940
|
-
return [
|
941
|
-
@param.tree(indent + 1),
|
942
|
-
((@@indline * indent) + self.typewrap(self.pin)),
|
943
|
-
@values.tree(indent + 1)
|
944
|
-
].join("\n")
|
945
|
-
end
|
946
|
-
end
|
947
|
-
|
948
|
-
# Define a variable. Stores the value in the current scope.
|
949
|
-
class VarDef < AST::Branch
|
950
|
-
attr_accessor :name, :value
|
951
|
-
|
952
|
-
# Look up our name and value, and store them appropriately. The
|
953
|
-
# lexer strips off the syntax stuff like '$'.
|
954
|
-
def evaluate(scope)
|
955
|
-
name = @name.safeevaluate(scope)
|
956
|
-
value = @value.safeevaluate(scope)
|
957
|
-
|
958
|
-
begin
|
959
|
-
scope.setvar(name,value)
|
960
|
-
rescue Puppet::ParseError => except
|
961
|
-
except.line = self.line
|
962
|
-
except.file = self.file
|
963
|
-
raise except
|
964
|
-
rescue => detail
|
965
|
-
error = Puppet::ParseError.new(detail)
|
966
|
-
error.line = self.line
|
967
|
-
error.file = self.file
|
968
|
-
error.stack = caller
|
969
|
-
raise error
|
970
|
-
end
|
971
|
-
end
|
972
|
-
|
973
|
-
def each
|
974
|
-
[@name,@value].each { |child| yield child }
|
975
|
-
end
|
976
|
-
|
977
|
-
def tree(indent = 0)
|
978
|
-
return [
|
979
|
-
@name.tree(indent + 1),
|
980
|
-
((@@indline * 4 * indent) + self.typewrap(self.pin)),
|
981
|
-
@value.tree(indent + 1)
|
982
|
-
].join("\n")
|
983
|
-
end
|
984
|
-
|
985
|
-
def to_s
|
986
|
-
return "%s => %s" % [@name,@value]
|
987
|
-
end
|
988
|
-
end
|
989
|
-
|
990
|
-
# A statement syntactically similar to an ObjectDef, but uses a
|
991
|
-
# capitalized object type and cannot have a name.
|
992
|
-
class TypeDefaults < AST::Branch
|
993
|
-
attr_accessor :type, :params
|
994
|
-
|
995
|
-
def each
|
996
|
-
[@type,@params].each { |child| yield child }
|
997
|
-
end
|
998
|
-
|
999
|
-
# As opposed to ObjectDef, this stores each default for the given
|
1000
|
-
# object type.
|
1001
|
-
def evaluate(scope)
|
1002
|
-
type = @type.safeevaluate(scope)
|
1003
|
-
params = @params.safeevaluate(scope)
|
1004
|
-
|
1005
|
-
begin
|
1006
|
-
scope.setdefaults(type.downcase,params)
|
1007
|
-
rescue Puppet::ParseError => except
|
1008
|
-
except.line = self.line
|
1009
|
-
except.file = self.file
|
1010
|
-
raise except
|
1011
|
-
rescue => detail
|
1012
|
-
error = Puppet::ParseError.new(detail)
|
1013
|
-
error.line = self.line
|
1014
|
-
error.file = self.file
|
1015
|
-
error.stack = caller
|
1016
|
-
raise error
|
1017
|
-
end
|
1018
|
-
end
|
1019
|
-
|
1020
|
-
def tree(indent = 0)
|
1021
|
-
return [
|
1022
|
-
@type.tree(indent + 1),
|
1023
|
-
((@@indline * 4 * indent) + self.typewrap(self.pin)),
|
1024
|
-
@params.tree(indent + 1)
|
1025
|
-
].join("\n")
|
1026
|
-
end
|
1027
|
-
|
1028
|
-
def to_s
|
1029
|
-
return "%s { %s }" % [@type,@params]
|
1030
|
-
end
|
1031
|
-
end
|
1032
|
-
|
1033
|
-
# Define a new component. This basically just stores the
|
1034
|
-
# associated parse tree by name in our current scope. Note that
|
1035
|
-
# there is currently a mismatch in how we look up components -- it
|
1036
|
-
# usually uses scopes, but sometimes uses '@@settypes'.
|
1037
|
-
# FIXME This class should verify that each of its direct children
|
1038
|
-
# has an abstractable name -- i.e., if a file does not include a
|
1039
|
-
# variable in its name, then the user is essentially guaranteed to
|
1040
|
-
# encounter an error if the component is instantiated more than
|
1041
|
-
# once.
|
1042
|
-
class CompDef < AST::Branch
|
1043
|
-
attr_accessor :name, :args, :code
|
1044
|
-
|
1045
|
-
def each
|
1046
|
-
[@name,@args,@code].each { |child| yield child }
|
1047
|
-
end
|
1048
|
-
|
1049
|
-
# Store the parse tree.
|
1050
|
-
def evaluate(scope)
|
1051
|
-
name = @name.safeevaluate(scope)
|
1052
|
-
args = @args.safeevaluate(scope)
|
1053
|
-
|
1054
|
-
begin
|
1055
|
-
scope.settype(name,
|
1056
|
-
AST::Component.new(
|
1057
|
-
:name => name,
|
1058
|
-
:args => args,
|
1059
|
-
:code => @code
|
1060
|
-
)
|
1061
|
-
)
|
1062
|
-
rescue Puppet::ParseError => except
|
1063
|
-
except.line = self.line
|
1064
|
-
except.file = self.file
|
1065
|
-
raise except
|
1066
|
-
rescue => detail
|
1067
|
-
error = Puppet::ParseError.new(detail)
|
1068
|
-
error.line = self.line
|
1069
|
-
error.file = self.file
|
1070
|
-
error.stack = caller
|
1071
|
-
raise error
|
1072
|
-
end
|
1073
|
-
end
|
1074
|
-
|
1075
|
-
def initialize(hash)
|
1076
|
-
@parentclass = nil
|
1077
|
-
super
|
1078
|
-
|
1079
|
-
Puppet.debug "Defining type %s" % @name.value
|
1080
|
-
|
1081
|
-
# we need to both mark that a given argument is valid,
|
1082
|
-
# and we need to also store any provided default arguments
|
1083
|
-
# FIXME This creates a global list of types and their
|
1084
|
-
# acceptable arguments. This should really be scoped
|
1085
|
-
# instead.
|
1086
|
-
@@settypes[@name.value] = self
|
1087
|
-
end
|
1088
|
-
|
1089
|
-
def tree(indent = 0)
|
1090
|
-
return [
|
1091
|
-
@name.tree(indent + 1),
|
1092
|
-
((@@indline * 4 * indent) + self.typewrap("define")),
|
1093
|
-
@args.tree(indent + 1),
|
1094
|
-
@code.tree(indent + 1),
|
1095
|
-
].join("\n")
|
1096
|
-
end
|
1097
|
-
|
1098
|
-
def to_s
|
1099
|
-
return "define %s(%s) {\n%s }" % [@name, @args, @code]
|
1100
|
-
end
|
1101
|
-
|
1102
|
-
# Check whether a given argument is valid. Searches up through
|
1103
|
-
# any parent classes that might exist.
|
1104
|
-
def validarg?(param)
|
1105
|
-
found = false
|
1106
|
-
if @args.is_a?(AST::ASTArray)
|
1107
|
-
found = @args.detect { |arg|
|
1108
|
-
if arg.is_a?(AST::ASTArray)
|
1109
|
-
arg[0].value == param
|
1110
|
-
else
|
1111
|
-
arg.value == param
|
1112
|
-
end
|
1113
|
-
}
|
1114
|
-
else
|
1115
|
-
found = @args.value == param
|
1116
|
-
#Puppet.warning "got arg %s" % @args.inspect
|
1117
|
-
#hash[@args.value] += 1
|
1118
|
-
end
|
1119
|
-
|
1120
|
-
if found
|
1121
|
-
return true
|
1122
|
-
# a nil parentclass is an empty astarray
|
1123
|
-
# stupid but true
|
1124
|
-
elsif @parentclass
|
1125
|
-
parent = @@settypes[@parentclass.value]
|
1126
|
-
if parent and parent != []
|
1127
|
-
return parent.validarg?(param)
|
1128
|
-
else
|
1129
|
-
raise Puppet::Error, "Could not find parent class %s" %
|
1130
|
-
@parentclass.value
|
1131
|
-
end
|
1132
|
-
else
|
1133
|
-
return false
|
1134
|
-
end
|
1135
|
-
|
1136
|
-
end
|
1137
|
-
end
|
1138
|
-
|
1139
|
-
# Define a new class. Syntactically similar to component definitions,
|
1140
|
-
# but classes are always singletons -- only one can exist on a given
|
1141
|
-
# host.
|
1142
|
-
class ClassDef < AST::CompDef
|
1143
|
-
attr_accessor :parentclass
|
1144
|
-
|
1145
|
-
def each
|
1146
|
-
if @parentclass
|
1147
|
-
#[@name,@args,@parentclass,@code].each { |child| yield child }
|
1148
|
-
[@name,@parentclass,@code].each { |child| yield child }
|
1149
|
-
else
|
1150
|
-
#[@name,@args,@code].each { |child| yield child }
|
1151
|
-
[@name,@code].each { |child| yield child }
|
1152
|
-
end
|
1153
|
-
end
|
1154
|
-
|
1155
|
-
# Store our parse tree according to name.
|
1156
|
-
def evaluate(scope)
|
1157
|
-
name = @name.safeevaluate(scope)
|
1158
|
-
#args = @args.safeevaluate(scope)
|
1159
|
-
|
1160
|
-
#:args => args,
|
1161
|
-
arghash = {
|
1162
|
-
:name => name,
|
1163
|
-
:code => @code
|
1164
|
-
}
|
1165
|
-
|
1166
|
-
if @parentclass
|
1167
|
-
arghash[:parentclass] = @parentclass.safeevaluate(scope)
|
1168
|
-
end
|
1169
|
-
|
1170
|
-
#Puppet.debug("defining hostclass '%s' with arguments [%s]" %
|
1171
|
-
# [name,args])
|
1172
|
-
|
1173
|
-
begin
|
1174
|
-
scope.settype(name,
|
1175
|
-
HostClass.new(arghash)
|
1176
|
-
)
|
1177
|
-
rescue Puppet::ParseError => except
|
1178
|
-
except.line = self.line
|
1179
|
-
except.file = self.file
|
1180
|
-
raise except
|
1181
|
-
rescue => detail
|
1182
|
-
error = Puppet::ParseError.new(detail)
|
1183
|
-
error.line = self.line
|
1184
|
-
error.file = self.file
|
1185
|
-
error.stack = caller
|
1186
|
-
raise error
|
1187
|
-
end
|
1188
|
-
end
|
1189
|
-
|
1190
|
-
def initialize(hash)
|
1191
|
-
@parentclass = nil
|
1192
|
-
super
|
1193
|
-
end
|
1194
|
-
|
1195
|
-
def tree(indent = 0)
|
1196
|
-
#@args.tree(indent + 1),
|
1197
|
-
return [
|
1198
|
-
@name.tree(indent + 1),
|
1199
|
-
((@@indline * 4 * indent) + self.typewrap("class")),
|
1200
|
-
@parentclass ? @parentclass.tree(indent + 1) : "",
|
1201
|
-
@code.tree(indent + 1),
|
1202
|
-
].join("\n")
|
1203
|
-
end
|
1204
|
-
|
1205
|
-
def to_s
|
1206
|
-
return "class %s(%s) inherits %s {\n%s }" %
|
1207
|
-
[@name, @parentclass, @code]
|
1208
|
-
#[@name, @args, @parentclass, @code]
|
1209
|
-
end
|
1210
|
-
end
|
1211
|
-
|
1212
|
-
# Define a node. The node definition stores a parse tree for each
|
1213
|
-
# specified node, and this parse tree is only ever looked up when
|
1214
|
-
# a client connects.
|
1215
|
-
class NodeDef < AST::Branch
|
1216
|
-
attr_accessor :names, :code, :parentclass
|
1217
|
-
|
1218
|
-
def each
|
1219
|
-
[@names,@code].each { |child| yield child }
|
1220
|
-
end
|
1221
|
-
|
1222
|
-
# Do implicit iteration over each of the names passed.
|
1223
|
-
def evaluate(scope)
|
1224
|
-
names = @names.safeevaluate(scope)
|
1225
|
-
|
1226
|
-
unless names.is_a?(Array)
|
1227
|
-
names = [names]
|
1228
|
-
end
|
1229
|
-
|
1230
|
-
names.each { |name|
|
1231
|
-
Puppet.debug("defining host '%s' in scope %s" %
|
1232
|
-
[name, scope.object_id])
|
1233
|
-
arghash = {
|
1234
|
-
:name => name,
|
1235
|
-
:code => @code
|
1236
|
-
}
|
1237
|
-
|
1238
|
-
if @parentclass
|
1239
|
-
arghash[:parentclass] = @parentclass.safeevaluate(scope)
|
1240
|
-
end
|
1241
|
-
|
1242
|
-
begin
|
1243
|
-
scope.setnode(name,
|
1244
|
-
Node.new(arghash)
|
1245
|
-
)
|
1246
|
-
rescue Puppet::ParseError => except
|
1247
|
-
except.line = self.line
|
1248
|
-
except.file = self.file
|
1249
|
-
raise except
|
1250
|
-
rescue => detail
|
1251
|
-
error = Puppet::ParseError.new(detail)
|
1252
|
-
error.line = self.line
|
1253
|
-
error.file = self.file
|
1254
|
-
error.stack = caller
|
1255
|
-
raise error
|
1256
|
-
end
|
1257
|
-
}
|
1258
|
-
end
|
1259
|
-
|
1260
|
-
def initialize(hash)
|
1261
|
-
@parentclass = nil
|
1262
|
-
super
|
1263
|
-
end
|
1264
|
-
|
1265
|
-
def tree(indent = 0)
|
1266
|
-
return [
|
1267
|
-
@names.tree(indent + 1),
|
1268
|
-
((@@indline * 4 * indent) + self.typewrap("node")),
|
1269
|
-
@code.tree(indent + 1),
|
1270
|
-
].join("\n")
|
1271
|
-
end
|
1272
|
-
|
1273
|
-
def to_s
|
1274
|
-
return "node %s {\n%s }" % [@name, @code]
|
1275
|
-
end
|
1276
|
-
end
|
1277
|
-
|
1278
|
-
# Evaluate the stored parse tree for a given component. This will
|
1279
|
-
# receive the arguments passed to the component and also the type and
|
1280
|
-
# name of the component.
|
1281
|
-
class Component < AST::Branch
|
1282
|
-
class << self
|
1283
|
-
attr_accessor :name
|
1284
|
-
end
|
1285
|
-
|
1286
|
-
# The class name
|
1287
|
-
@name = :component
|
1288
|
-
|
1289
|
-
attr_accessor :name, :args, :code, :scope
|
1290
|
-
|
1291
|
-
def evaluate(scope,hash,objtype,objname)
|
1292
|
-
|
1293
|
-
scope = scope.newscope
|
1294
|
-
|
1295
|
-
# The type is the component or class name
|
1296
|
-
scope.type = objtype
|
1297
|
-
|
1298
|
-
# The name is the name the user has chosen or that has
|
1299
|
-
# been dynamically generated. This is almost never used
|
1300
|
-
scope.name = objname
|
1301
|
-
|
1302
|
-
#if self.is_a?(Node)
|
1303
|
-
# scope.isnodescope
|
1304
|
-
#end
|
1305
|
-
|
1306
|
-
# Additionally, add a tag for whatever kind of class
|
1307
|
-
# we are
|
1308
|
-
scope.tag(objtype)
|
1309
|
-
|
1310
|
-
unless objname =~ /-\d+/ # it was generated
|
1311
|
-
scope.tag(objname)
|
1312
|
-
end
|
1313
|
-
#scope.base = self.class.name
|
1314
|
-
|
1315
|
-
|
1316
|
-
# define all of the arguments in our local scope
|
1317
|
-
if self.args
|
1318
|
-
|
1319
|
-
# Verify that all required arguments are either present or
|
1320
|
-
# have been provided with defaults.
|
1321
|
-
# FIXME This should probably also require each parent
|
1322
|
-
# class's arguments...
|
1323
|
-
self.args.each { |arg, default|
|
1324
|
-
unless hash.include?(arg)
|
1325
|
-
if defined? default and ! default.nil?
|
1326
|
-
hash[arg] = default
|
1327
|
-
Puppet.debug "Got default %s for %s in %s" %
|
1328
|
-
[default.inspect, arg.inspect, objname.inspect]
|
1329
|
-
else
|
1330
|
-
error = Puppet::ParseError.new(
|
1331
|
-
"Must pass %s to %s of type %s" %
|
1332
|
-
[arg.inspect,name,objtype]
|
1333
|
-
)
|
1334
|
-
error.line = self.line
|
1335
|
-
error.file = self.file
|
1336
|
-
error.stack = caller
|
1337
|
-
raise error
|
1338
|
-
end
|
1339
|
-
end
|
1340
|
-
}
|
1341
|
-
end
|
1342
|
-
|
1343
|
-
# Set each of the provided arguments as variables in the
|
1344
|
-
# component's scope.
|
1345
|
-
hash["name"] = objname
|
1346
|
-
hash.each { |arg,value|
|
1347
|
-
begin
|
1348
|
-
scope.setvar(arg,hash[arg])
|
1349
|
-
rescue Puppet::ParseError => except
|
1350
|
-
except.line = self.line
|
1351
|
-
except.file = self.file
|
1352
|
-
raise except
|
1353
|
-
rescue Puppet::ParseError => except
|
1354
|
-
except.line = self.line
|
1355
|
-
except.file = self.file
|
1356
|
-
raise except
|
1357
|
-
rescue => except
|
1358
|
-
error = Puppet::ParseError.new(except.message)
|
1359
|
-
error.line = self.line
|
1360
|
-
error.file = self.file
|
1361
|
-
error.stack = caller
|
1362
|
-
raise error
|
1363
|
-
end
|
1364
|
-
}
|
1365
|
-
|
1366
|
-
# Now just evaluate the code with our new bindings.
|
1367
|
-
self.code.safeevaluate(scope)
|
1368
|
-
|
1369
|
-
# We return the scope, so that our children can make their scopes
|
1370
|
-
# under ours. This allows them to find our definitions.
|
1371
|
-
return scope
|
1372
|
-
end
|
1373
|
-
end
|
1374
|
-
|
1375
|
-
# The code associated with a class. This is different from components
|
1376
|
-
# in that each class is a singleton -- only one will exist for a given
|
1377
|
-
# node.
|
1378
|
-
class HostClass < AST::Component
|
1379
|
-
@name = :class
|
1380
|
-
attr_accessor :parentclass
|
1381
|
-
|
1382
|
-
def evaluate(scope,hash,objtype,objname)
|
1383
|
-
if scope.lookupclass(@name)
|
1384
|
-
Puppet.debug "%s class already evaluated" % @name
|
1385
|
-
return nil
|
1386
|
-
end
|
1387
|
-
|
1388
|
-
if tmp = self.evalparent(scope, hash, objname)
|
1389
|
-
# Override our scope binding with the parent scope
|
1390
|
-
# binding. This is quite hackish, but I can't think
|
1391
|
-
# of another way to make sure our scopes end up under
|
1392
|
-
# our parent scopes.
|
1393
|
-
scope = tmp
|
1394
|
-
end
|
1395
|
-
|
1396
|
-
# just use the Component evaluate method, but change the type
|
1397
|
-
# to our own type
|
1398
|
-
retval = super(scope,hash,@name,objname)
|
1399
|
-
|
1400
|
-
# Set the mark after we evaluate, so we don't record it but
|
1401
|
-
# then encounter an error
|
1402
|
-
scope.setclass(@name)
|
1403
|
-
return retval
|
1404
|
-
end
|
1405
|
-
|
1406
|
-
# Evaluate our parent class. Parent classes are evaluated in the
|
1407
|
-
# exact same scope as the children. This is maybe not a good idea
|
1408
|
-
# but, eh.
|
1409
|
-
def evalparent(scope, args, name)
|
1410
|
-
if @parentclass
|
1411
|
-
parentobj = nil
|
1412
|
-
|
1413
|
-
begin
|
1414
|
-
parentobj = scope.lookuptype(@parentclass)
|
1415
|
-
rescue Puppet::ParseError => except
|
1416
|
-
except.line = self.line
|
1417
|
-
except.file = self.file
|
1418
|
-
raise except
|
1419
|
-
rescue => detail
|
1420
|
-
error = Puppet::ParseError.new(detail)
|
1421
|
-
error.line = self.line
|
1422
|
-
error.file = self.file
|
1423
|
-
raise error
|
1424
|
-
end
|
1425
|
-
unless parentobj
|
1426
|
-
error = Puppet::ParseError.new(
|
1427
|
-
"Could not find parent '%s' of '%s'" %
|
1428
|
-
[@parentclass,@name])
|
1429
|
-
error.line = self.line
|
1430
|
-
error.file = self.file
|
1431
|
-
raise error
|
1432
|
-
end
|
1433
|
-
|
1434
|
-
# Verify that the parent and child are of the same type
|
1435
|
-
unless parentobj.class == self.class
|
1436
|
-
error = Puppet::ParseError.new(
|
1437
|
-
"Class %s has incompatible parent type, %s vs %s" %
|
1438
|
-
[@name, parentobj.class, self.class]
|
1439
|
-
)
|
1440
|
-
error.file = self.file
|
1441
|
-
error.line = self.line
|
1442
|
-
raise error
|
1443
|
-
end
|
1444
|
-
return parentobj.safeevaluate(scope,args,@parentclass,name)
|
1445
|
-
end
|
1446
|
-
end
|
1447
|
-
|
1448
|
-
def initialize(hash)
|
1449
|
-
@parentclass = nil
|
1450
|
-
super
|
1451
|
-
end
|
1452
|
-
|
1453
|
-
end
|
1454
|
-
|
1455
|
-
# The specific code associated with a host. Nodes are annoyingly unlike
|
1456
|
-
# other objects. That's just the way it is, at least for now.
|
1457
|
-
class Node < AST::HostClass
|
1458
|
-
@name = :node
|
1459
|
-
attr_accessor :name, :args, :code, :parentclass
|
1460
|
-
|
1461
|
-
def evaluate(scope, facts = {})
|
1462
|
-
scope = scope.newscope
|
1463
|
-
|
1464
|
-
# nodes are never instantiated like a normal object,
|
1465
|
-
# but we need the type to be the name users would use for
|
1466
|
-
# instantiation, otherwise tags don't work out
|
1467
|
-
|
1468
|
-
# The name has already been evaluated, so it's a normal
|
1469
|
-
# string.
|
1470
|
-
scope.type = @name
|
1471
|
-
scope.name = @name
|
1472
|
-
|
1473
|
-
# Mark this scope as a nodescope, so that classes will be
|
1474
|
-
# singletons within it
|
1475
|
-
scope.isnodescope
|
1476
|
-
|
1477
|
-
# Now set all of the facts inside this scope
|
1478
|
-
facts.each { |var, value|
|
1479
|
-
scope.setvar(var, value)
|
1480
|
-
}
|
1481
|
-
|
1482
|
-
if tmp = self.evalparent(scope)
|
1483
|
-
# Again, override our scope with the parent scope, if
|
1484
|
-
# there is one.
|
1485
|
-
scope = tmp
|
1486
|
-
end
|
1487
|
-
|
1488
|
-
#scope.tag(@name)
|
1489
|
-
|
1490
|
-
# We never pass the facts to the parent class, because they've
|
1491
|
-
# already been defined at this top-level scope.
|
1492
|
-
#super(scope, facts, @name, @name)
|
1493
|
-
|
1494
|
-
# And then evaluate our code.
|
1495
|
-
@code.safeevaluate(scope)
|
1496
|
-
|
1497
|
-
return scope
|
1498
|
-
end
|
1499
|
-
|
1500
|
-
# Evaluate our parent class.
|
1501
|
-
def evalparent(scope)
|
1502
|
-
if @parentclass
|
1503
|
-
# This is pretty messed up. I don't know if this will
|
1504
|
-
# work in the long term, but we need to evaluate the node
|
1505
|
-
# in our own scope, even though our parent node has
|
1506
|
-
# a scope associated with it, because otherwise we 1) won't
|
1507
|
-
# get our facts defined, and 2) we won't actually get the
|
1508
|
-
# objects returned, based on how nodes work.
|
1509
|
-
|
1510
|
-
# We also can't just evaluate the node itself, because
|
1511
|
-
# it would create a node scope within this scope,
|
1512
|
-
# and that would cause mass havoc.
|
1513
|
-
node = nil
|
1514
|
-
|
1515
|
-
# The 'node' method just returns a hash of the node
|
1516
|
-
# code and name. It's used here, and in 'evalnode'.
|
1517
|
-
unless hash = scope.node(@parentclass)
|
1518
|
-
raise Puppet::ParseError,
|
1519
|
-
"Could not find parent node %s" %
|
1520
|
-
@parentclass
|
1521
|
-
end
|
1522
|
-
|
1523
|
-
node = hash[:node]
|
1524
|
-
# Tag the scope with the parent's name/type.
|
1525
|
-
name = node.name
|
1526
|
-
#Puppet.info "Tagging with parent node %s" % name
|
1527
|
-
scope.tag(name)
|
1528
|
-
|
1529
|
-
begin
|
1530
|
-
code = node.code
|
1531
|
-
code.safeevaluate(scope)
|
1532
|
-
rescue Puppet::ParseError => except
|
1533
|
-
except.line = self.line
|
1534
|
-
except.file = self.file
|
1535
|
-
raise except
|
1536
|
-
rescue => detail
|
1537
|
-
error = Puppet::ParseError.new(detail)
|
1538
|
-
error.line = self.line
|
1539
|
-
error.file = self.file
|
1540
|
-
raise error
|
1541
|
-
end
|
1542
|
-
|
1543
|
-
if node.parentclass
|
1544
|
-
node.evalparent(scope)
|
1545
|
-
end
|
1546
|
-
end
|
1547
|
-
end
|
1548
|
-
|
1549
|
-
def initialize(hash)
|
1550
|
-
@parentclass = nil
|
1551
|
-
super
|
1552
|
-
|
1553
|
-
end
|
1554
|
-
end
|
1555
126
|
#---------------------------------------------------------------
|
1556
127
|
end
|
1557
128
|
end
|
1558
129
|
end
|
1559
130
|
|
1560
|
-
|
131
|
+
require 'puppet/parser/ast/astarray'
|
132
|
+
require 'puppet/parser/ast/branch'
|
133
|
+
require 'puppet/parser/ast/caseopt'
|
134
|
+
require 'puppet/parser/ast/casestatement'
|
135
|
+
require 'puppet/parser/ast/classdef'
|
136
|
+
require 'puppet/parser/ast/compdef'
|
137
|
+
require 'puppet/parser/ast/component'
|
138
|
+
require 'puppet/parser/ast/hostclass'
|
139
|
+
require 'puppet/parser/ast/leaf'
|
140
|
+
require 'puppet/parser/ast/node'
|
141
|
+
require 'puppet/parser/ast/nodedef'
|
142
|
+
require 'puppet/parser/ast/objectdef'
|
143
|
+
require 'puppet/parser/ast/objectparam'
|
144
|
+
require 'puppet/parser/ast/objectref'
|
145
|
+
require 'puppet/parser/ast/selector'
|
146
|
+
require 'puppet/parser/ast/typedefaults'
|
147
|
+
require 'puppet/parser/ast/vardef'
|
148
|
+
|
149
|
+
# $Id: ast.rb 872 2006-02-07 17:07:15Z luke $
|