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.

Files changed (213) hide show
  1. data/CHANGELOG +58 -0
  2. data/README +21 -18
  3. data/Rakefile +176 -36
  4. data/bin/puppet +34 -48
  5. data/bin/puppetca +41 -28
  6. data/bin/puppetd +87 -65
  7. data/bin/puppetdoc +99 -23
  8. data/bin/puppetmasterd +72 -91
  9. data/conf/redhat/client.init +80 -0
  10. data/conf/redhat/client.sysconfig +11 -0
  11. data/conf/redhat/fileserver.conf +12 -0
  12. data/conf/redhat/puppet.spec +130 -0
  13. data/conf/redhat/server.init +89 -0
  14. data/conf/redhat/server.sysconfig +9 -0
  15. data/examples/code/allatonce +2 -2
  16. data/examples/code/assignments +1 -1
  17. data/examples/code/classing +2 -2
  18. data/examples/code/components +2 -2
  19. data/examples/code/file.bl +5 -5
  20. data/examples/code/filedefaults +2 -2
  21. data/examples/code/fileparsing +1 -1
  22. data/examples/code/filerecursion +1 -1
  23. data/examples/code/functions +1 -1
  24. data/examples/code/groups +1 -1
  25. data/examples/code/importing +1 -1
  26. data/examples/code/nodes +1 -1
  27. data/examples/code/one +1 -1
  28. data/examples/code/relationships +2 -2
  29. data/examples/code/simpletests +5 -5
  30. data/examples/code/snippets/argumentdefaults +2 -2
  31. data/examples/code/snippets/casestatement +16 -8
  32. data/examples/code/snippets/classheirarchy.pp +4 -4
  33. data/examples/code/snippets/classincludes.pp +4 -4
  34. data/examples/code/snippets/classpathtest +2 -2
  35. data/examples/code/snippets/componentmetaparams.pp +11 -0
  36. data/examples/code/snippets/dirchmod +5 -5
  37. data/examples/code/snippets/emptyclass.pp +9 -0
  38. data/examples/code/snippets/failmissingexecpath.pp +1 -1
  39. data/examples/code/snippets/falsevalues.pp +1 -1
  40. data/examples/code/snippets/filecreate +5 -5
  41. data/examples/code/snippets/implicititeration +5 -5
  42. data/examples/code/snippets/multipleinstances +4 -4
  43. data/examples/code/snippets/namevartest +3 -3
  44. data/examples/code/snippets/scopetest +1 -1
  45. data/examples/code/snippets/selectorvalues.pp +3 -3
  46. data/examples/code/snippets/simpledefaults +2 -2
  47. data/examples/code/snippets/simpleselector +5 -5
  48. data/examples/code/snippets/singleary.pp +19 -0
  49. data/examples/root/etc/init.d/sleeper +3 -2
  50. data/ext/emacs/puppet-mode-init.el +6 -0
  51. data/ext/emacs/puppet-mode.el +189 -0
  52. data/ext/ldap/puppet.schema +17 -0
  53. data/ext/{module:puppet → module_puppet} +30 -31
  54. data/ext/vim/filetype.vim +9 -0
  55. data/ext/vim/puppet.vim +87 -0
  56. data/install.rb +63 -30
  57. data/lib/puppet.rb +216 -122
  58. data/lib/puppet/client.rb +51 -416
  59. data/lib/puppet/client/ca.rb +17 -0
  60. data/lib/puppet/client/dipper.rb +78 -0
  61. data/lib/puppet/client/file.rb +20 -0
  62. data/lib/puppet/client/log.rb +17 -0
  63. data/lib/puppet/client/master.rb +246 -0
  64. data/lib/puppet/client/proxy.rb +27 -0
  65. data/lib/puppet/client/status.rb +7 -0
  66. data/lib/puppet/config.rb +563 -13
  67. data/lib/puppet/daemon.rb +50 -22
  68. data/lib/puppet/element.rb +4 -4
  69. data/lib/puppet/event-loop.rb +1 -0
  70. data/lib/puppet/event-loop/better-definers.rb +367 -0
  71. data/lib/puppet/event-loop/event-loop.rb +355 -0
  72. data/lib/puppet/event-loop/signal-system.rb +220 -0
  73. data/lib/puppet/event.rb +9 -11
  74. data/lib/puppet/filetype.rb +195 -0
  75. data/lib/puppet/log.rb +35 -12
  76. data/lib/puppet/metric.rb +2 -2
  77. data/lib/puppet/networkclient.rb +145 -0
  78. data/lib/puppet/parameter.rb +335 -0
  79. data/lib/puppet/parser/ast.rb +42 -1453
  80. data/lib/puppet/parser/ast/astarray.rb +88 -0
  81. data/lib/puppet/parser/ast/branch.rb +47 -0
  82. data/lib/puppet/parser/ast/caseopt.rb +66 -0
  83. data/lib/puppet/parser/ast/casestatement.rb +78 -0
  84. data/lib/puppet/parser/ast/classdef.rb +78 -0
  85. data/lib/puppet/parser/ast/compdef.rb +111 -0
  86. data/lib/puppet/parser/ast/component.rb +105 -0
  87. data/lib/puppet/parser/ast/hostclass.rb +82 -0
  88. data/lib/puppet/parser/ast/leaf.rb +86 -0
  89. data/lib/puppet/parser/ast/node.rb +103 -0
  90. data/lib/puppet/parser/ast/nodedef.rb +68 -0
  91. data/lib/puppet/parser/ast/objectdef.rb +336 -0
  92. data/lib/puppet/parser/ast/objectparam.rb +30 -0
  93. data/lib/puppet/parser/ast/objectref.rb +76 -0
  94. data/lib/puppet/parser/ast/selector.rb +60 -0
  95. data/lib/puppet/parser/ast/typedefaults.rb +45 -0
  96. data/lib/puppet/parser/ast/vardef.rb +44 -0
  97. data/lib/puppet/parser/interpreter.rb +31 -14
  98. data/lib/puppet/parser/lexer.rb +2 -4
  99. data/lib/puppet/parser/parser.rb +332 -242
  100. data/lib/puppet/parser/scope.rb +55 -38
  101. data/lib/puppet/server.rb +43 -44
  102. data/lib/puppet/server/authstore.rb +3 -6
  103. data/lib/puppet/server/ca.rb +5 -2
  104. data/lib/puppet/server/filebucket.rb +2 -4
  105. data/lib/puppet/server/fileserver.rb +28 -12
  106. data/lib/puppet/server/logger.rb +15 -4
  107. data/lib/puppet/server/master.rb +62 -7
  108. data/lib/puppet/sslcertificates.rb +41 -607
  109. data/lib/puppet/sslcertificates/ca.rb +291 -0
  110. data/lib/puppet/sslcertificates/certificate.rb +283 -0
  111. data/lib/puppet/statechange.rb +6 -1
  112. data/lib/puppet/storage.rb +67 -56
  113. data/lib/puppet/transaction.rb +25 -9
  114. data/lib/puppet/transportable.rb +102 -22
  115. data/lib/puppet/type.rb +1096 -315
  116. data/lib/puppet/type/component.rb +30 -21
  117. data/lib/puppet/type/cron.rb +409 -448
  118. data/lib/puppet/type/exec.rb +234 -174
  119. data/lib/puppet/type/group.rb +65 -82
  120. data/lib/puppet/type/nameservice.rb +247 -3
  121. data/lib/puppet/type/nameservice/netinfo.rb +29 -40
  122. data/lib/puppet/type/nameservice/objectadd.rb +52 -66
  123. data/lib/puppet/type/nameservice/posix.rb +6 -194
  124. data/lib/puppet/type/package.rb +447 -295
  125. data/lib/puppet/type/package/apt.rb +51 -50
  126. data/lib/puppet/type/package/bsd.rb +82 -0
  127. data/lib/puppet/type/package/dpkg.rb +85 -88
  128. data/lib/puppet/type/package/rpm.rb +67 -63
  129. data/lib/puppet/type/package/sun.rb +119 -98
  130. data/lib/puppet/type/package/yum.rb +41 -37
  131. data/lib/puppet/type/parsedtype.rb +295 -0
  132. data/lib/puppet/type/parsedtype/host.rb +143 -0
  133. data/lib/puppet/type/parsedtype/port.rb +232 -0
  134. data/lib/puppet/type/parsedtype/sshkey.rb +129 -0
  135. data/lib/puppet/type/pfile.rb +484 -460
  136. data/lib/puppet/type/pfile/checksum.rb +237 -181
  137. data/lib/puppet/type/pfile/content.rb +67 -0
  138. data/lib/puppet/type/pfile/ensure.rb +212 -0
  139. data/lib/puppet/type/pfile/group.rb +106 -105
  140. data/lib/puppet/type/pfile/mode.rb +98 -101
  141. data/lib/puppet/type/pfile/source.rb +228 -209
  142. data/lib/puppet/type/pfile/type.rb +18 -21
  143. data/lib/puppet/type/pfile/uid.rb +127 -130
  144. data/lib/puppet/type/pfilebucket.rb +68 -63
  145. data/lib/puppet/type/schedule.rb +341 -0
  146. data/lib/puppet/type/service.rb +351 -255
  147. data/lib/puppet/type/service/base.rb +9 -14
  148. data/lib/puppet/type/service/debian.rb +32 -38
  149. data/lib/puppet/type/service/init.rb +130 -130
  150. data/lib/puppet/type/service/smf.rb +48 -20
  151. data/lib/puppet/type/state.rb +229 -16
  152. data/lib/puppet/type/symlink.rb +51 -63
  153. data/lib/puppet/type/tidy.rb +105 -102
  154. data/lib/puppet/type/user.rb +118 -180
  155. data/lib/puppet/util.rb +100 -6
  156. data/test/certmgr/certmgr.rb +0 -1
  157. data/test/client/client.rb +4 -4
  158. data/test/executables/puppetbin.rb +7 -14
  159. data/test/executables/puppetca.rb +18 -24
  160. data/test/executables/puppetd.rb +7 -16
  161. data/test/executables/puppetmasterd.rb +7 -9
  162. data/test/executables/puppetmodule.rb +11 -16
  163. data/test/language/ast.rb +11 -7
  164. data/test/language/interpreter.rb +1 -1
  165. data/test/language/scope.rb +2 -0
  166. data/test/language/snippets.rb +30 -5
  167. data/test/language/transportable.rb +77 -0
  168. data/test/other/config.rb +316 -0
  169. data/test/other/events.rb +22 -21
  170. data/test/other/log.rb +14 -14
  171. data/test/other/metrics.rb +4 -8
  172. data/test/other/overrides.rb +5 -5
  173. data/test/other/relationships.rb +4 -2
  174. data/test/other/storage.rb +64 -3
  175. data/test/other/transactions.rb +20 -20
  176. data/test/parser/parser.rb +7 -4
  177. data/test/puppet/conffiles.rb +12 -12
  178. data/test/puppet/defaults.rb +13 -11
  179. data/test/puppet/utiltest.rb +14 -11
  180. data/test/puppettest.rb +156 -48
  181. data/test/server/bucket.rb +2 -2
  182. data/test/server/fileserver.rb +6 -6
  183. data/test/server/logger.rb +19 -11
  184. data/test/server/master.rb +33 -4
  185. data/test/server/server.rb +2 -7
  186. data/test/types/basic.rb +5 -7
  187. data/test/types/component.rb +22 -18
  188. data/test/types/cron.rb +111 -44
  189. data/test/types/exec.rb +116 -59
  190. data/test/types/file.rb +262 -137
  191. data/test/types/filebucket.rb +13 -15
  192. data/test/types/fileignoresource.rb +12 -16
  193. data/test/types/filesources.rb +73 -48
  194. data/test/types/filetype.rb +13 -15
  195. data/test/types/group.rb +15 -13
  196. data/test/types/host.rb +146 -0
  197. data/test/types/package.rb +74 -63
  198. data/test/types/port.rb +139 -0
  199. data/test/types/query.rb +8 -8
  200. data/test/types/schedule.rb +335 -0
  201. data/test/types/service.rb +137 -21
  202. data/test/types/sshkey.rb +140 -0
  203. data/test/types/symlink.rb +3 -5
  204. data/test/types/tidy.rb +5 -14
  205. data/test/types/type.rb +67 -11
  206. data/test/types/user.rb +25 -23
  207. metadata +186 -122
  208. data/lib/puppet/type/pfile/create.rb +0 -108
  209. data/lib/puppet/type/pprocess.rb +0 -97
  210. data/lib/puppet/type/typegen.rb +0 -149
  211. data/lib/puppet/type/typegen/filerecord.rb +0 -243
  212. data/lib/puppet/type/typegen/filetype.rb +0 -316
  213. data/test/other/state.rb +0 -106
@@ -0,0 +1,341 @@
1
+ module Puppet
2
+ newtype(:schedule) do
3
+ @doc = "Defined schedules for Puppet. The important thing to understand
4
+ about how schedules are currently implemented in Puppet is that they
5
+ can only be used to stop an element from being applied, they never
6
+ guarantee that it is applied.
7
+
8
+ Every time Puppet applies its configuration, it will collect the
9
+ list of elements whose schedule does not eliminate them from
10
+ running right then, but there is currently no system in place to
11
+ guarantee that a given element runs at a given time. If you
12
+ specify a very restrictive schedule and Puppet happens to run at a
13
+ time within that schedule, then the elements will get applied;
14
+ otherwise, that work may never get done.
15
+
16
+ Thus, it behooves you to use wider scheduling (e.g., over a couple of
17
+ hours) combined with periods and repetitions. For instance, if you
18
+ wanted to restrict certain elements to only running once, between
19
+ the hours of two and 4 AM, then you would use this schedule::
20
+
21
+ schedule { maint:
22
+ range => \"2 - 4\",
23
+ period => daily,
24
+ repeat => 1
25
+ }
26
+
27
+ With this schedule, the first time that Puppet runs between 2 and 4 AM,
28
+ all elements with this schedule will get applied, but they won't
29
+ get applied again between 2 and 4 because they will have already
30
+ run once that day, and they won't get applied outside that schedule
31
+ because they will be outside the scheduled range.
32
+
33
+ Puppet automatically creates a schedule for each valid period with the
34
+ same name as that period (e.g., hourly and daily). Additionally,
35
+ a schedule named *puppet* is created and used as the default,
36
+ with the following attributes::
37
+
38
+ schedule { puppet:
39
+ period => hourly,
40
+ repeat => 2
41
+ }
42
+
43
+ This will cause elements to be applied every 30 minutes by default.
44
+ "
45
+
46
+ @states = []
47
+
48
+ newparam(:name) do
49
+ desc "The name of the schedule. This name is used to retrieve the
50
+ schedule when assigning it to an object::
51
+
52
+ schedule { daily:
53
+ period => daily,
54
+ range => [2, 4]
55
+ }
56
+
57
+ exec { \"/usr/bin/apt-get update\":
58
+ schedule => daily
59
+ }
60
+
61
+ "
62
+ isnamevar
63
+ end
64
+
65
+ newparam(:range) do
66
+ desc "The earliest and latest that an element can be applied. This
67
+ is always a range within a 24 hour period, and hours must be
68
+ specified in numbers between 0 and 23, inclusive. Minutes and
69
+ seconds can be provided, using the normal colon as a separator.
70
+ For instance::
71
+
72
+ schedule { maintenance:
73
+ range => \"1:30 - 4:30\"
74
+ }
75
+
76
+ This is mostly useful for restricting certain elements to being
77
+ applied in maintenance windows or during off-peak hours."
78
+
79
+ # This is lame; states all use arrays as values, but parameters don't.
80
+ # That's going to hurt eventually.
81
+ validate do |values|
82
+ values = [values] unless values.is_a?(Array)
83
+ values.each { |value|
84
+ unless value.is_a?(String) and
85
+ value =~ /\d+(:\d+){0,2}\s*-\s*\d+(:\d+){0,2}/
86
+ self.fail "Invalid range value '%s'" % value
87
+ end
88
+ }
89
+ end
90
+
91
+ munge do |values|
92
+ values = [values] unless values.is_a?(Array)
93
+ ret = []
94
+
95
+ values.each { |value|
96
+ range = []
97
+ # Split each range value into a hour, minute, second triad
98
+ value.split(/\s*-\s*/).each { |val|
99
+ # Add the values as an array.
100
+ range << val.split(":").collect { |n| n.to_i }
101
+ }
102
+
103
+ if range.length != 2
104
+ self.fail "Invalid range %s" % value
105
+ end
106
+
107
+ if range[0][0] > range[1][0]
108
+ self.fail(("Invalid range %s; " % value) +
109
+ "ranges cannot span days."
110
+ )
111
+ end
112
+ ret << range
113
+ }
114
+
115
+ # Now our array of arrays
116
+ ret
117
+ end
118
+
119
+ def match?(previous, now)
120
+ # The lowest-level array is of the hour, minute, second triad
121
+ # then it's an array of two of those, to present the limits
122
+ # then it's array of those ranges
123
+ unless @value[0][0].is_a?(Array)
124
+ @value = [@value]
125
+ end
126
+
127
+ @value.each do |value|
128
+ limits = value.collect do |range|
129
+ ary = [now.year, now.month, now.day, range[0]]
130
+ if range[1]
131
+ ary << range[1]
132
+ else
133
+ ary << now.min
134
+ end
135
+
136
+ if range[2]
137
+ ary << range[2]
138
+ else
139
+ ary << now.sec
140
+ end
141
+
142
+ time = Time.local(*ary)
143
+
144
+ unless time.hour == range[0]
145
+ self.devfail(
146
+ "Incorrectly converted time: %s: %s vs %s" %
147
+ [time, time.hour, range[0]]
148
+ )
149
+ end
150
+
151
+ time
152
+ end
153
+
154
+ unless limits[0] < limits[1]
155
+ self.info(
156
+ "Assuming upper limit should be that time the next day"
157
+ )
158
+
159
+ ary = limits[1].to_a
160
+ ary[3] += 1
161
+ limits[1] = Time.local(*ary)
162
+
163
+ #self.devfail("Lower limit is above higher limit: %s" %
164
+ # limits.inspect
165
+ #)
166
+ end
167
+
168
+ #self.info limits.inspect
169
+ #self.notice now
170
+ return now.between?(*limits)
171
+ end
172
+
173
+ # Else, return false, since our current time isn't between
174
+ # any valid times
175
+ return false
176
+ end
177
+ end
178
+
179
+ newparam(:periodmatch) do
180
+ desc "Whether periods should be matched by number (e.g., the two times
181
+ are in the same hour) or by distance (e.g., the two times are
182
+ 60 minutes apart). *number*/**distance**"
183
+
184
+ newvalues(:number, :distance)
185
+
186
+ defaultto :distance
187
+ end
188
+
189
+ newparam(:period) do
190
+ desc "The period of repetition for an element. Choose from among
191
+ a fixed list of *hourly*, *daily*, *weekly*, and *monthly*.
192
+ The default is for an element to get applied every time that
193
+ Puppet runs, whatever that period is.
194
+
195
+ Note that the period defines how often a given element will get
196
+ applied but not when; if you would like to restrict the hours
197
+ that a given element can be applied (e.g., only at night during
198
+ a maintenance window) then use the ``range`` attribute.
199
+
200
+ If the provided periods are not sufficient, you can provide a
201
+ value to the *repeat* attribute, which will cause Puppet to
202
+ schedule the affected elements evenly in the period the
203
+ specified number of times. Take this schedule::
204
+
205
+ schedule { veryoften:
206
+ period => hourly,
207
+ repeat => 6
208
+ }
209
+
210
+ This can cause Puppet to apply that element up to every 10 minutes.
211
+
212
+ At the moment, Puppet cannot guarantee that level of
213
+ repetition; that is, it can run up to every 10 minutes, but
214
+ internal factors might prevent it from actually running that
215
+ often (e.g., long-running Puppet runs will squash conflictingly
216
+ scheduled runs).
217
+
218
+ See the ``periodmatch`` attribute for tuning whether to match
219
+ times by their distance apart or by their specific value."
220
+
221
+ newvalues(:hourly, :daily, :weekly, :monthly)
222
+
223
+ @@scale = {
224
+ :hourly => 3600,
225
+ :daily => 86400,
226
+ :weekly => 604800,
227
+ :monthly => 2592000
228
+ }
229
+ @@methods = {
230
+ :hourly => :hour,
231
+ :daily => :day,
232
+ :monthly => :month,
233
+ :weekly => proc do |prev, now|
234
+ prev.strftime("%U") == now.strftime("%U")
235
+ end
236
+ }
237
+
238
+ def match?(previous, now)
239
+ value = self.value
240
+ case @parent[:periodmatch]
241
+ when :number
242
+ method = @@methods[value]
243
+ if method.is_a?(Proc)
244
+ return method.call(previous, now)
245
+ else
246
+ # We negate it, because if they're equal we don't run
247
+ val = now.send(method) != previous.send(method)
248
+ return val
249
+ end
250
+ when :distance
251
+ scale = @@scale[value]
252
+
253
+ # If the number of seconds between the two times is greater
254
+ # than the unit of time, we match. We divide the scale
255
+ # by the repeat, so that we'll repeat that often within
256
+ # the scale.
257
+ return (now.to_i - previous.to_i) >= (scale / @parent[:repeat])
258
+ end
259
+ end
260
+ end
261
+
262
+ newparam(:repeat) do
263
+ desc "How often the application gets repeated in a given period.
264
+ Defaults to 1."
265
+
266
+ defaultto 1
267
+
268
+ validate do |value|
269
+ unless value.is_a?(Integer) or value =~ /^\d+$/
270
+ raise Puppet::Error,
271
+ "Repeat must be a number"
272
+ end
273
+
274
+ # This implicitly assumes that 'periodmatch' is distance -- that
275
+ # is, if there's no value, we assume it's a valid value.
276
+ return unless @parent[:periodmatch]
277
+
278
+ if value != 1 and @parent[:periodmatch] != :distance
279
+ raise Puppet::Error,
280
+ "Repeat must be 1 unless periodmatch is 'distance', not '%s'" %
281
+ @parent[:periodmatch]
282
+ end
283
+ end
284
+
285
+ munge do |value|
286
+ unless value.is_a?(Integer)
287
+ value = Integer(value)
288
+ end
289
+
290
+ value
291
+ end
292
+
293
+ def match?(previous, now)
294
+ true
295
+ end
296
+ end
297
+
298
+ def self.mkdefaultschedules
299
+ Puppet.info "Creating default schedules"
300
+ # Create our default schedule
301
+ self.create(
302
+ :name => "puppet",
303
+ :period => :hourly,
304
+ :repeat => "2"
305
+ )
306
+
307
+ # And then one for every period
308
+ @parameters.find { |p| p.name == :period }.values.each { |value|
309
+ self.create(
310
+ :name => value.to_s,
311
+ :period => value
312
+ )
313
+ }
314
+ end
315
+
316
+ def match?(previous = nil, now = nil)
317
+
318
+ # If we've got a value, then convert it to a Time instance
319
+ if previous
320
+ previous = Time.at(previous)
321
+ end
322
+
323
+ now ||= Time.now
324
+
325
+ # Pull them in order
326
+ self.class.allattrs.each { |param|
327
+ if @parameters.include?(param) and
328
+ @parameters[param].respond_to?(:match?)
329
+ #self.notice "Trying to match %s" % param
330
+ return false unless @parameters[param].match?(previous, now)
331
+ end
332
+ }
333
+
334
+ # If we haven't returned false, then return true; in other words,
335
+ # any provided schedules need to all match
336
+ return true
337
+ end
338
+ end
339
+ end
340
+
341
+ # $Id: schedule.rb 848 2006-01-24 06:01:58Z luke $
@@ -5,58 +5,68 @@
5
5
  # which is why they have a search path for initscripts and such
6
6
 
7
7
  module Puppet
8
- class State
9
- # Handle whether the service is started at boot time.
10
- class ServiceEnabled < State
11
- @doc = "Whether a service should be enabled to start at boot.
12
- **true**/*false*/*runlevel*"
13
- @name = :enabled
14
8
 
15
- def retrieve
16
- unless @parent.respond_to?(:enabled?)
17
- raise Puppet::Error, "Service %s does not support enabling"
18
- end
19
- @is = @parent.enabled?
20
- end
21
-
22
- def shouldprocess(should)
23
- @runlevel = nil
24
- case should
25
- when true: return :enabled
26
- when false: return :disabled
27
- when /^\d+$/:
28
- @runlevel = should
29
- return :enabled
30
- else
31
- raise Puppet::Error, "Invalid 'enabled' value %s" % should
32
- end
33
- end
34
-
35
- def sync
36
- case self.should
37
- when :enabled
38
- unless @parent.respond_to?(:enable)
39
- raise Puppet::Error, "Service %s does not support enabling"
40
- end
41
- @parent.enable(@runlevel)
42
- return :service_enabled
43
- when :disabled
44
- unless @parent.respond_to?(:disable)
45
- raise Puppet::Error,
46
- "Service %s does not support disabling"
47
- end
48
- @parent.disable
49
- return :service_disabled
50
- end
51
- end
52
- end
9
+ newtype(:service) do
10
+ @doc = "Manage running services. Service support unfortunately varies
11
+ widely by platform -- some platforms have very little if any
12
+ concept of a running service, and some have a very codified and
13
+ powerful concept. Puppet's service support will generally be able
14
+ to make up for any inherent shortcomings (e.g., if there is no
15
+ 'status' command, then Puppet will look in the process table for a
16
+ command matching the service name), but the more information you
17
+ can provide the better behaviour you will get. Or, you can just
18
+ use a platform that has very good service support."
19
+
20
+ attr_reader :stat
21
+
22
+ # newstate(:enabled) do
23
+ # desc "Whether a service should be enabled to start at boot.
24
+ # **true**/*false*/*runlevel*"
25
+ #
26
+ # def retrieve
27
+ # unless @parent.respond_to?(:enabled?)
28
+ # raise Puppet::Error, "Service %s does not support enabling"
29
+ # end
30
+ # @is = @parent.enabled?
31
+ # end
32
+ #
33
+ # munge do |should|
34
+ # @runlevel = nil
35
+ # case should
36
+ # when true: return :enabled
37
+ # when false: return :disabled
38
+ # when /^\d+$/:
39
+ # @runlevel = should
40
+ # return :enabled
41
+ # else
42
+ # raise Puppet::Error, "Invalid 'enabled' value %s" % should
43
+ # end
44
+ # end
45
+ #
46
+ # def sync
47
+ # case self.should
48
+ # when :enabled
49
+ # unless @parent.respond_to?(:enable)
50
+ # raise Puppet::Error, "Service %s does not support enabling"
51
+ # end
52
+ # @parent.enable(@runlevel)
53
+ # return :service_enabled
54
+ # when :disabled
55
+ # unless @parent.respond_to?(:disable)
56
+ # raise Puppet::Error,
57
+ # "Service %s does not support disabling"
58
+ # end
59
+ # @parent.disable
60
+ # return :service_disabled
61
+ # end
62
+ # end
63
+ # end
53
64
 
54
65
  # Handle whether the service should actually be running right now.
55
- class ServiceRunning < State
56
- @doc = "Whether a service should be running. **true**/*false*"
57
- @name = :running
66
+ newstate(:running) do
67
+ desc "Whether a service should be running. **true**/*false*"
58
68
 
59
- def shouldprocess(should)
69
+ munge do |should|
60
70
  case should
61
71
  when false,0,"0", "stopped", :stopped:
62
72
  should = :stopped
@@ -64,10 +74,9 @@ module Puppet
64
74
  should = :running
65
75
  else
66
76
  self.warning "%s: interpreting '%s' as false" %
67
- [self.class,should]
77
+ [self.class,should.inspect]
68
78
  should = 0
69
79
  end
70
- self.debug "Service should is %s" % should
71
80
  return should
72
81
  end
73
82
 
@@ -81,260 +90,347 @@ module Puppet
81
90
  case self.should
82
91
  when :running
83
92
  @parent.start
84
- event = :service_started
93
+ self.info "started"
94
+ return :service_started
85
95
  when :stopped
96
+ self.info "stopped"
86
97
  @parent.stop
87
- event = :service_stopped
98
+ return :service_stopped
88
99
  else
89
100
  self.debug "Not running '%s' and shouldn't be running" %
90
101
  self
91
102
  end
92
103
  end
93
104
  end
94
- end
95
105
 
96
- class Type
97
- class Service < Type
98
- attr_reader :stat
99
- @states = [
100
- Puppet::State::ServiceRunning
101
- ]
102
- @parameters = [
103
- :binary,
104
- :hasstatus,
105
- :name,
106
- :path,
107
- :pattern,
108
- :restart,
109
- :start,
110
- :status,
111
- :stop,
112
- :type
113
- ]
114
-
115
- @paramdoc[:binary] = "The path to the daemon. This is only used for
116
- systems that do not support init scripts."
117
- @paramdoc[:hasstatus] = "Declare the the service's init script has a
118
- functional status command. This is assumed to be default for
119
- most systems, although there might be platforms on which this is
120
- assumed to be true."
121
- @paramdoc[:name] = "The name of the service to run. This name
122
- is used to find the init script in the search path."
123
- @paramdoc[:path] = "The search path for finding init scripts.
124
- There is currently no default, but hopefully soon there will
125
- be a reasonable default for all platforms."
126
- @paramdoc[:pattern] = "The pattern to search for in the process table.
127
- This is used for stopping services on platforms that do not
128
- support init scripts, and is also used for determining service
129
- status on those service whose init scripts do not include a status
130
- command."
131
- @paramdoc[:restart] = "Specify a *restart* command manually. If left
132
- unspecified, the restart method will be determined automatically."
133
- @paramdoc[:start] = "Specify a *start* command manually. If left
134
- unspecified, the start method will be determined automatically."
135
- @paramdoc[:status] = "Specify a *status* command manually. If left
136
- unspecified, the status method will be determined automatically."
137
- @paramdoc[:stop] = "Specify a *stop* command manually. If left
138
- unspecified, the stop method will be determined automatically."
139
-
140
- @doc = "Manage running services. Rather than supporting managing
141
- individual processes, puppet uses init scripts to simplify
142
- specification of how to start, stop, or test processes. The
143
- `path` parameter is provided to enable creation of multiple
144
- init script directories, including supporting them for normal
145
- users."
146
- @name = :service
147
- @namevar = :name
148
-
149
- # Return the service type we're using. Default to the Service
150
- # class itself, but could be set to a module.
151
- class << self
152
- attr_accessor :svctype
106
+ newparam(:type) do
107
+ desc "The service type. For most platforms, it does not make
108
+ sense to change set this parameter, as the default is based on
109
+ the builtin service facilities. The service types available are:
110
+
111
+ * ``base``: You must specify everything.
112
+ * ``init``: Assumes ``start`` and ``stop`` commands exist, but you
113
+ must specify everything else.
114
+ * ``debian``: Debian's own specific version of ``init``.
115
+ * ``smf``: Solaris 10's new Service Management Facility.
116
+ "
117
+
118
+ defaultto { @parent.class.defaulttype }
119
+
120
+ # Make sure we've got the actual module, not just a string
121
+ # representing the module.
122
+ munge do |type|
123
+ if type.is_a?(String)
124
+ type = @parent.class.svctype(type.intern)
125
+ end
126
+ Puppet.debug "Service type is %s" % type.name
127
+ @parent.extend(type)
128
+
129
+ return type
153
130
  end
131
+ end
132
+ newparam(:binary) do
133
+ desc "The path to the daemon. This is only used for
134
+ systems that do not support init scripts. This binary will be
135
+ used to start the service if no ``start`` parameter is
136
+ provided."
137
+ end
138
+ newparam(:hasstatus) do
139
+ desc "Declare the the service's init script has a
140
+ functional status command. Based on testing, it was found
141
+ that a large number of init scripts on different platforms do
142
+ not support any kind of status command; thus, you must specify
143
+ manually whether the service you are running has such a
144
+ command (or you can specify a specific command using the
145
+ ``status`` parameter).
146
+
147
+ If you do not specify anything, then the service name will be
148
+ looked for in the process table."
149
+ end
150
+ newparam(:name) do
151
+ desc "The name of the service to run. This name
152
+ is used to find the service in whatever service subsystem it
153
+ is in."
154
+ isnamevar
155
+ end
156
+ newparam(:path) do
157
+ desc "The search path for finding init scripts."
158
+
159
+ munge do |value|
160
+ paths = []
161
+ if value.is_a?(Array)
162
+ paths += value.flatten.collect { |p|
163
+ p.split(":")
164
+ }.flatten
165
+ else
166
+ paths = value.split(":")
167
+ end
154
168
 
155
- # Retrieve the default type for the current platform.
156
- def self.defaulttype
157
- unless defined? @defsvctype
158
- @defsvctype = nil
159
- os = Facter["operatingsystem"].value
160
- case os
161
- when "Linux":
162
- case Facter["distro"].value
163
- when "Debian":
164
- @defsvctype = Puppet::ServiceTypes::DebianSvc
165
- end
166
- when "SunOS":
167
- release = Float(Facter["operatingsystemrelease"].value)
168
- if release < 5.10
169
- @defsvctype = Puppet::ServiceTypes::InitSvc
170
- else
171
- @defsvctype = Puppet::ServiceTypes::SMFSvc
172
- end
169
+ paths.each do |path|
170
+ if FileTest.directory?(path)
171
+ next
173
172
  end
174
-
175
- unless @defsvctype
176
- Puppet.notice "Defaulting to base service type"
177
- @defsvctype = Puppet::ServiceTypes::BaseSvc
173
+ unless FileTest.directory?(path)
174
+ @parent.info("Search path %s is not a directory" % [path])
175
+ end
176
+ unless FileTest.exists?(path)
177
+ @parent.info("Search path %s does not exist" % [path])
178
178
  end
179
+ paths.delete(path)
179
180
  end
180
181
 
181
- return @defsvctype
182
+ paths
183
+ end
184
+ end
185
+ newparam(:pattern) do
186
+ desc "The pattern to search for in the process table.
187
+ This is used for stopping services on platforms that do not
188
+ support init scripts, and is also used for determining service
189
+ status on those service whose init scripts do not include a status
190
+ command.
191
+
192
+ If this is left unspecified and is needed to check the status
193
+ of a service, then the service name will be used instead.
194
+
195
+ The pattern can be a simple string or any legal Ruby pattern."
196
+ defaultto { @parent.name }
197
+ end
198
+ newparam(:restart) do
199
+ desc "Specify a *restart* command manually. If left
200
+ unspecified, the service will be stopped and then started."
201
+ end
202
+ newparam(:start) do
203
+ desc "Specify a *start* command manually. Most service subsystems
204
+ support a ``start`` command, so this will not need to be
205
+ specified."
206
+ end
207
+ newparam(:status) do
208
+ desc "Specify a *status* command manually. If left
209
+ unspecified, the status method will be determined
210
+ automatically, usually by looking for the service int he
211
+ process table."
212
+ end
213
+
214
+ newparam(:stop) do
215
+ desc "Specify a *stop* command manually."
216
+ end
217
+
218
+ # Create new subtypes of service management.
219
+ def self.newsvctype(name, parent = nil, &block)
220
+ if parent
221
+ parent = self.svctype(parent)
182
222
  end
223
+ svcname = name
224
+ mod = Module.new
225
+ const_set("SvcType" + name.to_s.capitalize,mod)
183
226
 
184
- # Execute a command. Basically just makes sure it exits with a 0
185
- # code.
186
- def execute(type, cmd)
187
- output = %x(#{cmd} 2>&1)
188
- unless $? == 0
189
- raise Puppet::Error, "Could not %s %s: %s" %
190
- [type, self.name, output.chomp]
191
- end
227
+ # Add our parent, if it exists
228
+ if parent
229
+ mod.send(:include, parent)
192
230
  end
193
231
 
194
- # Get the process ID for a running process. Requires the 'pattern'
195
- # parameter.
196
- def getpid
197
- unless self[:pattern]
198
- raise Puppet::Error,
199
- "Either a stop command or a pattern must be specified"
200
- end
201
- ps = Facter["ps"].value
202
- unless ps and ps != ""
203
- raise Puppet::Error,
204
- "You must upgrade Facter to a version that includes 'ps'"
232
+ # And now define the support methods
233
+ code = %{
234
+ def self.name
235
+ "#{svcname}"
205
236
  end
206
- regex = Regexp.new(self[:pattern])
207
- IO.popen(ps) { |table|
208
- table.each { |line|
209
- if regex.match(line)
210
- ary = line.sub(/^\s+/, '').split(/\s+/)
211
- return ary[1]
212
- end
213
- }
214
- }
215
237
 
216
- return nil
217
- end
238
+ def self.inspect
239
+ "SvcType(#{svcname})"
240
+ end
218
241
 
219
- # Initialize the service. This is basically responsible for merging
220
- # in the right module.
221
- def initialize(hash)
222
- # We have to extend the object before we call 'super', so that
223
- # the parameter methods are called correctly.
224
- type = hash[:type] ||
225
- hash["type"] ||
226
- self.class.defaulttype
242
+ def self.to_s
243
+ "SvcType(#{svcname})"
244
+ end
227
245
 
228
- if type.is_a?(String)
229
- type = type2module(type)
246
+ def svctype
247
+ "#{svcname}"
230
248
  end
249
+ }
231
250
 
232
- # Extend the object with the service type
233
- #self.info "extending with %s" % type
234
- self.extend(type)
251
+ mod.module_eval(code)
235
252
 
236
- super
253
+ mod.module_eval(&block)
237
254
 
238
- unless @parameters.include?(:pattern)
239
- # default to using the service name as the pattern
240
- self[:pattern] = self.name
255
+ @modules ||= Hash.new do |hash, key|
256
+ if key.is_a?(String)
257
+ key = key.intern
241
258
  end
242
259
 
243
- # and then see if it needs to be checked
244
- if self.respond_to?(:configchk)
245
- self.configchk
260
+ if hash.include?(key)
261
+ hash[key]
262
+ else
263
+ nil
246
264
  end
247
265
  end
266
+ @modules[name] = mod
267
+ end
268
+
269
+ # Retrieve a service type.
270
+ def self.svctype(name)
271
+ @modules[name]
272
+ end
248
273
 
249
- # Retrieve the service type.
250
- def type2module(type)
251
- case type
252
- when "smf":
253
- return Puppet::ServiceTypes::SMFSvc
254
- when "init":
255
- return Puppet::ServiceTypes::InitSvc
256
- when "launchd":
257
- #return Puppet::ServiceTypes::LaunchDSvc
274
+ # Retrieve the default type for the current platform.
275
+ def self.defaulttype
276
+ unless defined? @defsvctype
277
+ @defsvctype = nil
278
+ os = Facter["operatingsystem"].value
279
+ case os
280
+ when "Debian":
281
+ @defsvctype = self.svctype(:debian)
282
+ when "Solaris":
283
+ release = Facter["operatingsystemrelease"].value
284
+ if release.sub(/5\./,'').to_i < 10
285
+ @defsvctype = self.svctype(:init)
286
+ else
287
+ @defsvctype = self.svctype(:smf)
288
+ end
258
289
  else
259
- raise Puppet::Error, "Invalid service type %s" % type
290
+ if Facter["kernel"] == "Linux"
291
+ Puppet.notice "Using service type %s for %s" %
292
+ ["init", Facter["operatingsystem"].value]
293
+ @defsvctype = self.svctype(:init)
294
+ end
260
295
  end
261
- end
262
296
 
263
- # Basically just a synonym for restarting. Used to respond
264
- # to events.
265
- def refresh
266
- self.restart
297
+ unless @defsvctype
298
+ Puppet.notice "Defaulting to base service type"
299
+ @defsvctype = self.svctype(:base)
300
+ end
267
301
  end
268
302
 
269
- # How to restart the process.
270
- def restart
271
- if self[:restart] or self.respond_to?(:restartcmd)
272
- cmd = self[:restart] || self.restartcmd
273
- self.execute("restart", cmd)
274
- else
275
- self.stop
276
- self.start
277
- end
303
+ Puppet.debug "Default service type is %s" % @defsvctype.name
304
+
305
+ return @defsvctype
306
+ end
307
+
308
+ # Execute a command. Basically just makes sure it exits with a 0
309
+ # code.
310
+ def execute(type, cmd)
311
+ self.info "Executing %s" % cmd.inspect
312
+ output = %x(#{cmd} 2>&1)
313
+ unless $? == 0
314
+ self.fail "Could not %s %s: %s" %
315
+ [type, self.name, output.chomp]
278
316
  end
317
+ end
279
318
 
280
- # Check if the process is running. Prefer the 'status' parameter,
281
- # then 'statuscmd' method, then look in the process table. We give
282
- # the object the option to not return a status command, which might
283
- # happen if, for instance, it has an init script (and thus responds to
284
- # 'statuscmd') but does not have 'hasstatus' enabled.
285
- def status
286
- if self[:status] or (
287
- self.respond_to?(:statuscmd) and self.statuscmd
319
+ # Get the process ID for a running process. Requires the 'pattern'
320
+ # parameter.
321
+ def getpid
322
+ unless self[:pattern]
323
+ self.fail "Either a stop command or a pattern must be specified"
324
+ end
325
+ ps = Facter["ps"].value
326
+ unless ps and ps != ""
327
+ self.fail(
328
+ "You must upgrade Facter to a version that includes 'ps'"
288
329
  )
289
- cmd = self[:status] || self.statuscmd
290
- output = %x(#{cmd} 2>&1)
291
- self.debug "%s status returned %s" %
292
- [self.name, output]
293
- if $? == 0
294
- return :running
295
- else
296
- return :stopped
330
+ end
331
+ regex = Regexp.new(self[:pattern])
332
+ IO.popen(ps) { |table|
333
+ table.each { |line|
334
+ if regex.match(line)
335
+ ary = line.sub(/^\s+/, '').split(/\s+/)
336
+ return ary[1]
297
337
  end
298
- elsif pid = self.getpid
338
+ }
339
+ }
340
+
341
+ return nil
342
+ end
343
+
344
+ # Initialize the service. This is basically responsible for merging
345
+ # in the right module.
346
+ def initialize(hash)
347
+ super
348
+
349
+ # and then see if it needs to be checked
350
+ if self.respond_to?(:configchk)
351
+ self.configchk
352
+ end
353
+ end
354
+
355
+ # Retrieve the service type.
356
+ def type2module(type)
357
+ self.class.svctype(type)
358
+ end
359
+
360
+ # Basically just a synonym for restarting. Used to respond
361
+ # to events.
362
+ def refresh
363
+ self.restart
364
+ end
365
+
366
+ # How to restart the process.
367
+ def restart
368
+ if self[:restart] or self.respond_to?(:restartcmd)
369
+ cmd = self[:restart] || self.restartcmd
370
+ self.execute("restart", cmd)
371
+ else
372
+ self.stop
373
+ self.start
374
+ end
375
+ end
376
+
377
+ # Check if the process is running. Prefer the 'status' parameter,
378
+ # then 'statuscmd' method, then look in the process table. We give
379
+ # the object the option to not return a status command, which might
380
+ # happen if, for instance, it has an init script (and thus responds to
381
+ # 'statuscmd') but does not have 'hasstatus' enabled.
382
+ def status
383
+ if self[:status] or (
384
+ self.respond_to?(:statuscmd) and self.statuscmd
385
+ )
386
+ cmd = self[:status] || self.statuscmd
387
+ self.info "Executing %s" % cmd.inspect
388
+ output = %x(#{cmd} 2>&1)
389
+ self.debug "%s status returned %s" %
390
+ [self.name, output.inspect]
391
+ if $? == 0
299
392
  return :running
300
393
  else
301
394
  return :stopped
302
395
  end
396
+ elsif pid = self.getpid
397
+ return :running
398
+ else
399
+ return :stopped
303
400
  end
401
+ end
304
402
 
305
- # Run the 'start' parameter command, or the specified 'startcmd'.
306
- def start
307
- cmd = self[:start] || self.startcmd
308
- self.execute("start", cmd)
309
- end
403
+ # Run the 'start' parameter command, or the specified 'startcmd'.
404
+ def start
405
+ cmd = self[:start] || self.startcmd
406
+ self.execute("start", cmd)
407
+ end
310
408
 
311
- # Stop the service. If a 'stop' parameter is specified, it
312
- # takes precedence; otherwise checks if the object responds to
313
- # a 'stopcmd' method, and if so runs that; otherwise, looks
314
- # for the process in the process table.
315
- # This method will generally not be overridden by submodules.
316
- def stop
317
- if self[:stop]
318
- return self[:stop]
319
- elsif self.respond_to?(:stopcmd)
320
- self.execute("stop", self.stopcmd)
321
- else
322
- pid = getpid
323
- unless pid
324
- self.info "%s is not running" % self.name
325
- return false
326
- end
327
- output = %x("kill #{pid} 2>&1")
328
- if $? != 0
329
- raise Puppet::Error,
330
- "Could not kill %s, PID %s: %s" %
331
- [self.name, pid, output]
332
- end
333
- return true
409
+ # Stop the service. If a 'stop' parameter is specified, it
410
+ # takes precedence; otherwise checks if the object responds to
411
+ # a 'stopcmd' method, and if so runs that; otherwise, looks
412
+ # for the process in the process table.
413
+ # This method will generally not be overridden by submodules.
414
+ def stop
415
+ if self[:stop]
416
+ return self[:stop]
417
+ elsif self.respond_to?(:stopcmd)
418
+ self.execute("stop", self.stopcmd)
419
+ else
420
+ pid = getpid
421
+ unless pid
422
+ self.info "%s is not running" % self.name
423
+ return false
334
424
  end
425
+ output = %x("kill #{pid} 2>&1")
426
+ if $? != 0
427
+ self.fail "Could not kill %s, PID %s: %s" %
428
+ [self.name, pid, output]
429
+ end
430
+ return true
335
431
  end
336
- end
337
- end
432
+ end
433
+ end
338
434
  end
339
435
 
340
436
  # Load all of the different service types. We could probably get away with
@@ -344,4 +440,4 @@ require 'puppet/type/service/init'
344
440
  require 'puppet/type/service/debian'
345
441
  require 'puppet/type/service/smf'
346
442
 
347
- # $Id: service.rb 742 2005-11-16 17:12:11Z luke $
443
+ # $Id: service.rb 887 2006-02-08 22:56:56Z luke $