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