puppet 0.16.0 → 0.18.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (185) hide show
  1. data/CHANGELOG +98 -0
  2. data/Rakefile +5 -1
  3. data/bin/puppet +1 -1
  4. data/bin/puppetca +25 -11
  5. data/bin/puppetd +189 -66
  6. data/bin/puppetdoc +79 -62
  7. data/bin/puppetmasterd +93 -49
  8. data/bin/puppetrun +385 -0
  9. data/conf/redhat/client.init +5 -2
  10. data/conf/redhat/fileserver.conf +1 -1
  11. data/conf/redhat/lsb-config.patch +51 -0
  12. data/conf/redhat/puppet.spec +45 -18
  13. data/conf/redhat/puppetd.conf +32 -4
  14. data/conf/redhat/server.init +5 -2
  15. data/conf/solaris/pkginfo +7 -0
  16. data/conf/solaris/smf/puppetd.xml +77 -0
  17. data/conf/solaris/smf/puppetmasterd.xml +77 -0
  18. data/conf/solaris/smf/svc-puppetd +66 -0
  19. data/conf/solaris/smf/svc-puppetmasterd +62 -0
  20. data/examples/code/failers/noobjectrvalue +1 -0
  21. data/examples/code/snippets/deepclassheirarchy.pp +23 -0
  22. data/examples/code/snippets/defineoverrides.pp +17 -0
  23. data/examples/code/snippets/emptyexec.pp +3 -0
  24. data/examples/code/snippets/selectorvalues.pp +6 -1
  25. data/examples/code/snippets/tagged.pp +35 -0
  26. data/ext/ldap/puppet.schema +2 -2
  27. data/install.rb +4 -2
  28. data/lib/puppet.rb +206 -15
  29. data/lib/puppet/client.rb +30 -20
  30. data/lib/puppet/client/ca.rb +2 -2
  31. data/lib/puppet/client/dipper.rb +5 -9
  32. data/lib/puppet/client/master.rb +224 -44
  33. data/lib/puppet/client/pelement.rb +54 -9
  34. data/lib/puppet/client/proxy.rb +3 -2
  35. data/lib/puppet/client/reporter.rb +34 -0
  36. data/lib/puppet/client/runner.rb +17 -0
  37. data/lib/puppet/config.rb +136 -55
  38. data/lib/puppet/daemon.rb +59 -37
  39. data/lib/puppet/element.rb +2 -1
  40. data/lib/puppet/event.rb +14 -3
  41. data/lib/puppet/filetype.rb +28 -19
  42. data/lib/puppet/log.rb +297 -132
  43. data/lib/puppet/metric.rb +31 -131
  44. data/lib/puppet/networkclient.rb +73 -46
  45. data/lib/puppet/parameter.rb +49 -1
  46. data/lib/puppet/parsedfile.rb +32 -12
  47. data/lib/puppet/parser/ast.rb +6 -1
  48. data/lib/puppet/parser/ast/astarray.rb +32 -6
  49. data/lib/puppet/parser/ast/collection.rb +91 -0
  50. data/lib/puppet/parser/ast/compdef.rb +2 -2
  51. data/lib/puppet/parser/ast/component.rb +24 -11
  52. data/lib/puppet/parser/ast/function.rb +50 -0
  53. data/lib/puppet/parser/ast/hostclass.rb +70 -22
  54. data/lib/puppet/parser/ast/node.rb +17 -8
  55. data/lib/puppet/parser/ast/nodedef.rb +1 -1
  56. data/lib/puppet/parser/ast/objectdef.rb +28 -10
  57. data/lib/puppet/parser/ast/selector.rb +4 -1
  58. data/lib/puppet/parser/functions.rb +145 -0
  59. data/lib/puppet/parser/interpreter.rb +243 -86
  60. data/lib/puppet/parser/lexer.rb +5 -4
  61. data/lib/puppet/parser/parser.rb +586 -505
  62. data/lib/puppet/parser/scope.rb +337 -187
  63. data/lib/puppet/rails.rb +115 -0
  64. data/lib/puppet/rails/database.rb +40 -0
  65. data/lib/puppet/rails/host.rb +83 -0
  66. data/lib/puppet/rails/rails_object.rb +42 -0
  67. data/lib/puppet/rails/rails_parameter.rb +5 -0
  68. data/lib/puppet/reports/rrdgraph.rb +20 -0
  69. data/lib/puppet/reports/tagmail.rb +94 -0
  70. data/lib/puppet/server.rb +20 -4
  71. data/lib/puppet/server/authconfig.rb +14 -3
  72. data/lib/puppet/server/authstore.rb +2 -2
  73. data/lib/puppet/server/ca.rb +23 -11
  74. data/lib/puppet/server/filebucket.rb +10 -10
  75. data/lib/puppet/server/fileserver.rb +4 -8
  76. data/lib/puppet/server/master.rb +19 -22
  77. data/lib/puppet/server/pelement.rb +28 -16
  78. data/lib/puppet/server/report.rb +184 -0
  79. data/lib/puppet/server/runner.rb +62 -0
  80. data/lib/puppet/server/servlet.rb +23 -9
  81. data/lib/puppet/sslcertificates/ca.rb +25 -1
  82. data/lib/puppet/statechange.rb +34 -53
  83. data/lib/puppet/storage.rb +1 -2
  84. data/lib/puppet/transaction.rb +305 -133
  85. data/lib/puppet/transaction/report.rb +42 -0
  86. data/lib/puppet/transportable.rb +57 -33
  87. data/lib/puppet/type.rb +260 -127
  88. data/lib/puppet/type/component.rb +9 -21
  89. data/lib/puppet/type/cron.rb +367 -116
  90. data/lib/puppet/type/exec.rb +15 -16
  91. data/lib/puppet/type/group.rb +9 -1
  92. data/lib/puppet/type/nameservice.rb +2 -5
  93. data/lib/puppet/type/nameservice/netinfo.rb +3 -0
  94. data/lib/puppet/type/nameservice/objectadd.rb +23 -10
  95. data/lib/puppet/type/nameservice/pw.rb +16 -3
  96. data/lib/puppet/type/package.rb +25 -75
  97. data/lib/puppet/type/package/apple.rb +15 -1
  98. data/lib/puppet/type/package/apt.rb +37 -2
  99. data/lib/puppet/type/package/blastwave.rb +136 -0
  100. data/lib/puppet/type/package/dpkg.rb +4 -4
  101. data/lib/puppet/type/package/gem.rb +119 -0
  102. data/lib/puppet/type/package/openbsd.rb +7 -6
  103. data/lib/puppet/type/package/ports.rb +7 -2
  104. data/lib/puppet/type/package/rpm.rb +1 -1
  105. data/lib/puppet/type/package/sun.rb +23 -9
  106. data/lib/puppet/type/package/sunfreeware.rb +7 -0
  107. data/lib/puppet/type/package/yum.rb +16 -9
  108. data/lib/puppet/type/parsedtype.rb +7 -5
  109. data/lib/puppet/type/parsedtype/mount.rb +55 -34
  110. data/lib/puppet/type/parsedtype/port.rb +7 -1
  111. data/lib/puppet/type/parsedtype/sshkey.rb +6 -16
  112. data/lib/puppet/type/pfile.rb +115 -23
  113. data/lib/puppet/type/pfile/checksum.rb +18 -5
  114. data/lib/puppet/type/pfile/content.rb +2 -2
  115. data/lib/puppet/type/pfile/ensure.rb +3 -3
  116. data/lib/puppet/type/pfile/group.rb +2 -2
  117. data/lib/puppet/type/pfile/source.rb +28 -17
  118. data/lib/puppet/type/pfile/target.rb +25 -17
  119. data/lib/puppet/type/pfilebucket.rb +25 -6
  120. data/lib/puppet/type/schedule.rb +6 -6
  121. data/lib/puppet/type/service.rb +24 -14
  122. data/lib/puppet/type/service/debian.rb +1 -1
  123. data/lib/puppet/type/service/redhat.rb +13 -10
  124. data/lib/puppet/type/service/smf.rb +3 -3
  125. data/lib/puppet/type/state.rb +1 -2
  126. data/lib/puppet/type/symlink.rb +3 -4
  127. data/lib/puppet/type/user.rb +22 -10
  128. data/lib/puppet/type/yumrepo.rb +6 -1
  129. data/lib/puppet/type/zone.rb +595 -0
  130. data/lib/puppet/util.rb +58 -12
  131. data/test/client/client.rb +2 -2
  132. data/test/client/master.rb +92 -3
  133. data/test/client/pelement.rb +99 -0
  134. data/test/executables/puppetbin.rb +3 -4
  135. data/test/executables/puppetca.rb +3 -3
  136. data/test/executables/puppetd.rb +3 -3
  137. data/test/executables/puppetmasterd.rb +1 -5
  138. data/test/executables/puppetmodule.rb +2 -2
  139. data/test/language/ast.rb +200 -11
  140. data/test/language/functions.rb +245 -0
  141. data/test/language/interpreter.rb +155 -6
  142. data/test/language/lexer.rb +35 -2
  143. data/test/language/node.rb +48 -1
  144. data/test/language/parser.rb +250 -1
  145. data/test/language/rails.rb +105 -0
  146. data/test/language/scope.rb +304 -10
  147. data/test/language/snippets.rb +54 -5
  148. data/test/language/transportable.rb +60 -28
  149. data/test/other/config.rb +214 -1
  150. data/test/other/events.rb +67 -9
  151. data/test/other/log.rb +31 -5
  152. data/test/other/metrics.rb +23 -21
  153. data/test/other/parsedfile.rb +29 -2
  154. data/test/other/puppet.rb +79 -0
  155. data/test/other/report.rb +106 -0
  156. data/test/other/storage.rb +2 -2
  157. data/test/other/transactions.rb +128 -2
  158. data/test/puppet/utiltest.rb +10 -5
  159. data/test/puppettest.rb +193 -21
  160. data/test/server/authstore.rb +13 -4
  161. data/test/server/bucket.rb +33 -8
  162. data/test/server/ca.rb +44 -6
  163. data/test/server/master.rb +6 -7
  164. data/test/server/pelement.rb +15 -5
  165. data/test/server/report.rb +93 -0
  166. data/test/server/runner.rb +107 -0
  167. data/test/server/server.rb +28 -1
  168. data/test/types/cron.rb +339 -31
  169. data/test/types/file.rb +256 -24
  170. data/test/types/filebucket.rb +6 -2
  171. data/test/types/filesources.rb +41 -92
  172. data/test/types/group.rb +31 -1
  173. data/test/types/host.rb +2 -1
  174. data/test/types/mount.rb +18 -1
  175. data/test/types/package.rb +200 -18
  176. data/test/types/service.rb +5 -1
  177. data/test/types/sshkey.rb +2 -1
  178. data/test/types/symlink.rb +3 -2
  179. data/test/types/type.rb +180 -1
  180. data/test/types/user.rb +65 -27
  181. data/test/types/yumrepo.rb +15 -0
  182. data/test/types/zone.rb +437 -0
  183. metadata +43 -4
  184. data/bin/cf2puppet +0 -186
  185. data/conf/redhat/puppetmasterd.conf +0 -5
@@ -77,10 +77,18 @@ module Puppet
77
77
  # dependencies. This will get run once on the top-level component,
78
78
  # and it will do everything necessary.
79
79
  def finalize
80
+ started = {}
80
81
  finished = {}
81
82
 
82
83
  # First do all of the finish work, which mostly involves
83
84
  self.delve do |object|
85
+ # Make sure we don't get into loops
86
+ if started.has_key?(object)
87
+ debug "Already finished %s" % object.name
88
+ next
89
+ else
90
+ started[object] = true
91
+ end
84
92
  unless finished.has_key?(object)
85
93
  object.finish
86
94
  object.builddepends
@@ -133,20 +141,6 @@ module Puppet
133
141
  return @name
134
142
  end
135
143
 
136
- def push(*ary)
137
- ary.each { |child|
138
- unless child.is_a?(Puppet::Element)
139
- self.debug "Got object of type %s" % child.class
140
- self.devfail(
141
- "Containers can only contain Puppet::Elements, not %s" %
142
- child.class
143
- )
144
- end
145
- @children.push child
146
- child.parent = self
147
- }
148
- end
149
-
150
144
  def refresh
151
145
  @children.collect { |child|
152
146
  if child.respond_to?(:refresh)
@@ -156,16 +150,10 @@ module Puppet
156
150
  }
157
151
  end
158
152
 
159
- #def retrieve
160
- # self.collect { |child|
161
- # child.retrieve
162
- # }
163
- #end
164
-
165
153
  def to_s
166
154
  return "component(%s)" % self.name
167
155
  end
168
156
  end
169
157
  end
170
158
 
171
- # $Id: component.rb 965 2006-03-02 07:30:14Z luke $
159
+ # $Id: component.rb 1246 2006-06-08 20:38:44Z luke $
@@ -10,7 +10,6 @@ module Puppet
10
10
  # completely symbolic 'name' paremeter, which gets written to the file
11
11
  # and is used to manage the job.
12
12
  newtype(:cron) do
13
- ensurable
14
13
 
15
14
  # A base class for all of the Cron parameters, since they all have
16
15
  # similar argument checking going on. We're stealing the base class
@@ -18,20 +17,16 @@ module Puppet
18
17
  # but it was just too annoying to do.
19
18
  class CronParam < Puppet::State::ParsedParam
20
19
  class << self
21
- attr_accessor :boundaries
20
+ attr_accessor :boundaries, :default
22
21
  end
23
22
 
24
23
  # We have to override the parent method, because we consume the entire
25
24
  # "should" array
26
25
  def insync?
27
- if self.class.name == :command
28
- return super
26
+ if defined? @should and @should
27
+ self.is_to_s == self.should_to_s
29
28
  else
30
- if @is.is_a? Array
31
- return @is == @should
32
- else
33
- return @is == @should[0]
34
- end
29
+ true
35
30
  end
36
31
  end
37
32
 
@@ -81,23 +76,35 @@ module Puppet
81
76
  return false
82
77
  end
83
78
 
84
- def is_to_s
85
- if @is.empty?
86
- return "*"
87
- else
88
- if @is.is_a? Array
89
- return @is.join(",")
79
+ def should_to_s
80
+ if @should
81
+ unless @should.is_a?(Array)
82
+ fail "wtf?"
83
+ end
84
+
85
+ if self.name == :command or @should[0].is_a? Symbol
86
+ @should[0]
90
87
  else
91
- return @is.to_s
88
+ @should.join(",")
92
89
  end
90
+ else
91
+ nil
93
92
  end
94
93
  end
95
94
 
96
- def should_to_s
97
- if ! defined? @should or @should.empty?
98
- return "*"
95
+ def is_to_s
96
+ if @is
97
+ unless @is.is_a?(Array)
98
+ return @is
99
+ end
100
+
101
+ if self.name == :command or @is[0].is_a? Symbol
102
+ @is[0]
103
+ else
104
+ @is.join(",")
105
+ end
99
106
  else
100
- return @should.join(",")
107
+ nil
101
108
  end
102
109
  end
103
110
 
@@ -112,6 +119,21 @@ module Puppet
112
119
  if value == "absent" or value == :absent
113
120
  return :absent
114
121
  end
122
+
123
+ # Allow the */2 syntax
124
+ if value =~ /^\*\/[0-9]+$/
125
+ return value
126
+ end
127
+
128
+ # Allow ranges
129
+ if value =~ /^[0-9]+-[0-9]+$/
130
+ return value
131
+ end
132
+
133
+ if value == "*"
134
+ return value
135
+ end
136
+
115
137
  return value unless self.class.boundaries
116
138
  lower, upper = self.class.boundaries
117
139
  retval = nil
@@ -132,6 +154,15 @@ module Puppet
132
154
  end
133
155
  end
134
156
  end
157
+
158
+
159
+ # Override 'newstate' so that all states default to having the
160
+ # correct parent type
161
+ def self.newstate(name, parent = nil, &block)
162
+ parent ||= Puppet::State::CronParam
163
+ super(name, parent, &block)
164
+ end
165
+
135
166
  # Somewhat uniquely, this state does not actually change anything -- it
136
167
  # just calls +@parent.sync+, which writes out the whole cron tab for
137
168
  # the user in question. There is no real way to change individual cron
@@ -148,6 +179,33 @@ module Puppet
148
179
 
149
180
  All cron parameters support ``absent`` as a value; this will
150
181
  remove any existing values for that field."
182
+
183
+ def should
184
+ if @should
185
+ if @should.is_a? Array
186
+ @should[0]
187
+ else
188
+ devfail "command is not an array"
189
+ end
190
+ else
191
+ nil
192
+ end
193
+ end
194
+ end
195
+
196
+ newstate(:special, Puppet::State::ParsedParam) do
197
+ desc "Special schedules only supported on FreeBSD."
198
+
199
+ def specials
200
+ %w{reboot yearly annually monthly weekly daily midnight hourly}
201
+ end
202
+
203
+ validate do |value|
204
+ unless specials().include?(value)
205
+ raise ArgumentError, "Invalid special schedule %s" %
206
+ value.inspect
207
+ end
208
+ end
151
209
  end
152
210
 
153
211
  newstate(:minute, CronParam) do
@@ -188,17 +246,58 @@ module Puppet
188
246
  command. Optional; if specified, must be between 1 and 31."
189
247
  end
190
248
 
249
+ newstate(:environment, Puppet::State::ParsedParam) do
250
+ desc "Any environment settings associated with this cron job. They
251
+ will be stored between the header and the job in the crontab. There
252
+ can be no guarantees that other, earlier settings will not also
253
+ affect a given cron job.
254
+
255
+ Also, Puppet cannot automatically determine whether an existing,
256
+ unmanaged environment setting is associated with a given cron
257
+ job. If you already have cron jobs with environment settings,
258
+ then Puppet will keep those settings in the same place in the file,
259
+ but will not associate them with a specific job."
260
+
261
+ validate do |value|
262
+ unless value =~ /^\s*(\w+)\s*=\s*(.+)\s*$/
263
+ raise ArgumentError, "Invalid environment setting %s" %
264
+ value.inspect
265
+ end
266
+ end
267
+
268
+ def insync?
269
+ if @is.is_a? Array
270
+ return @is.sort == @should.sort
271
+ else
272
+ return @is == @should[0]
273
+ end
274
+ end
275
+
276
+ def should
277
+ @should
278
+ end
279
+ end
280
+
191
281
  newparam(:name) do
192
282
  desc "The symbolic name of the cron job. This name
193
283
  is used for human reference only and is generated automatically
194
284
  for cron jobs found on the system. This generally won't
195
285
  matter, as Puppet will do its best to match existing cron jobs
196
- against specified jobs (and Puppet adds a tag to cron jobs it
286
+ against specified jobs (and Puppet adds a comment to cron jobs it
197
287
  adds), but it is at least possible that converting from
198
288
  unmanaged jobs to managed jobs might require manual
199
- intervention."
289
+ intervention.
290
+
291
+ The names can only have alphanumeric characters plus the '-'
292
+ character."
200
293
 
201
294
  isnamevar
295
+
296
+ validate do |value|
297
+ unless value =~ /^[-\w]+$/
298
+ raise ArgumentError, "Invalid name format '%s'" % value
299
+ end
300
+ end
202
301
  end
203
302
 
204
303
  newparam(:user) do
@@ -232,7 +331,7 @@ module Puppet
232
331
  association is made and synced to disk, you can then manage the job
233
332
  normally (e.g., change the schedule of the job).
234
333
 
235
- Example::
334
+ Example:
236
335
 
237
336
  cron { logrotate:
238
337
  command => \"/usr/sbin/logrotate\",
@@ -247,17 +346,18 @@ module Puppet
247
346
 
248
347
  class << self
249
348
  attr_accessor :filetype
349
+
350
+ def cronobj(name)
351
+ if defined? @tabs
352
+ return @tabs[name]
353
+ else
354
+ return nil
355
+ end
356
+ end
250
357
  end
251
358
 
252
359
  attr_accessor :uid
253
360
 
254
- # Override the Puppet::Type#[]= method so that we can store the instances
255
- # in per-user arrays. Then just call +super+.
256
- def self.[]=(name, object)
257
- self.instance(object)
258
- super
259
- end
260
-
261
361
  # In addition to removing the instances in @objects, Cron has to remove
262
362
  # per-user cron tab information.
263
363
  def self.clear
@@ -293,6 +393,55 @@ module Puppet
293
393
  return [:minute, :hour, :monthday, :month, :weekday, :command]
294
394
  end
295
395
 
396
+ # Convert our hash to an object
397
+ def self.hash2obj(hash)
398
+ obj = nil
399
+ namevar = self.namevar
400
+ unless hash.include?(namevar) and hash[namevar]
401
+ Puppet.info "Autogenerating name for %s" % hash[:command]
402
+ hash[:name] = "autocron-%s" % hash.object_id
403
+ end
404
+
405
+ unless hash.include?(:command)
406
+ raise Puppet::DevError, "No command for %s" % name
407
+ end
408
+ # if the cron already exists with that name...
409
+ if obj = (self[hash[:name]] || match(hash))
410
+ # Mark the cron job as present
411
+ obj.is = [:ensure, :present]
412
+
413
+ # Mark all of the values appropriately
414
+ hash.each { |param, value|
415
+ if state = obj.state(param)
416
+ state.is = value
417
+ elsif val = obj[param]
418
+ obj[param] = val
419
+ else
420
+ # There is a value on disk, but it should go away
421
+ obj.is = [param, value]
422
+ obj[param] = :absent
423
+ end
424
+ }
425
+ else
426
+ # create a new cron job, since no existing one
427
+ # seems to match
428
+ obj = self.create(
429
+ :name => hash[namevar]
430
+ )
431
+
432
+ obj.is = [:ensure, :present]
433
+
434
+ obj.notice "created"
435
+
436
+ hash.delete(namevar)
437
+ hash.each { |param, value|
438
+ obj.is = [param, value]
439
+ }
440
+ end
441
+
442
+ instance(obj)
443
+ end
444
+
296
445
  # Return the header placed at the top of each generated file, warning
297
446
  # users that modifying this file manually is probably a bad idea.
298
447
  def self.header
@@ -302,16 +451,13 @@ module Puppet
302
451
  # HEADER not be deleted, as doing so could cause duplicate cron jobs.\n}
303
452
  end
304
453
 
305
- # Store a new instance of a cron job. Called from Cron#initialize.
306
454
  def self.instance(obj)
307
455
  user = obj[:user]
308
- if @instances.include?(user)
309
- unless @instances[obj[:user]].include?(obj)
310
- @instances[obj[:user]] << obj
311
- end
312
- else
313
- @instances[obj[:user]] = [obj]
456
+ unless @instances.include?(user)
457
+ @instances[user] = []
314
458
  end
459
+
460
+ @instances[user] << obj
315
461
  end
316
462
 
317
463
  def self.list
@@ -323,6 +469,53 @@ module Puppet
323
469
  self.collect { |c| c }
324
470
  end
325
471
 
472
+ # See if we can match the hash against an existing cron job.
473
+ def self.match(hash)
474
+ self.find_all { |obj|
475
+ obj[:user] == hash[:user] and obj.value(:command) == hash[:command][0]
476
+ }.each do |obj|
477
+ # we now have a cron job whose command exactly matches
478
+ # let's see if the other fields match
479
+
480
+ # First check the @special stuff
481
+ if hash[:special]
482
+ next unless obj.value(:special) == hash[:special]
483
+ end
484
+
485
+ # Then the normal fields.
486
+ matched = true
487
+ fields().each do |field|
488
+ next if field == :command
489
+ if hash[field] and ! obj.value(field)
490
+ #Puppet.info "Cron is missing %s: %s and %s" %
491
+ # [field, hash[field].inspect, obj.value(field).inspect]
492
+ matched = false
493
+ break
494
+ end
495
+
496
+ if ! hash[field] and obj.value(field)
497
+ #Puppet.info "Hash is missing %s: %s and %s" %
498
+ # [field, obj.value(field).inspect, hash[field].inspect]
499
+ matched = false
500
+ break
501
+ end
502
+
503
+ # FIXME It'd be great if I could somehow reuse how the
504
+ # fields are turned into text, but....
505
+ next if (hash[field] == [:absent] and obj.value(field) == "*")
506
+ next if (hash[field].join(",") == obj.value(field))
507
+ #Puppet.info "Did not match %s: %s vs %s" %
508
+ # [field, obj.value(field).inspect, hash[field].inspect]
509
+ matched = false
510
+ break
511
+ end
512
+ next unless matched
513
+ return obj
514
+ end
515
+
516
+ return false
517
+ end
518
+
326
519
  # Parse a user's cron job into individual cron objects.
327
520
  #
328
521
  # Autogenerates names for any jobs that don't already have one; these
@@ -334,74 +527,67 @@ module Puppet
334
527
  def self.parse(user, text)
335
528
  count = 0
336
529
  hash = {}
337
- name = nil
338
- unless @instances.include?(user)
339
- @instances[user] = []
340
- end
530
+
531
+ envs = []
341
532
  text.chomp.split("\n").each { |line|
342
533
  case line
343
- when /^# Puppet Name: (\w+)$/: name = $1
534
+ when /^# Puppet Name: (.+)$/
535
+ hash[:name] = $1
536
+ next
344
537
  when /^#/:
345
538
  # add other comments to the list as they are
346
539
  @instances[user] << line
540
+ next
541
+ when /^\s*(\w+)\s*=\s*(.+)\s*$/:
542
+ # Match env settings.
543
+ if hash[:name]
544
+ envs << line
545
+ else
546
+ @instances[user] << line
547
+ end
548
+ next
549
+ when /^@(\w+)\s+(.+)/ # FreeBSD special cron crap
550
+ fields().each do |field|
551
+ next if field == :command
552
+ hash[field] = :absent
553
+ end
554
+ hash[:special] = $1
555
+ hash[:command] = $2
347
556
  else
348
557
  if match = /^(\S+) (\S+) (\S+) (\S+) (\S+) (.+)$/.match(line)
349
558
  fields().zip(match.captures).each { |param, value|
350
- unless value == "*"
351
- unless param == :command
559
+ if value == "*"
560
+ hash[param] = [:absent]
561
+ else
562
+ if param == :command
563
+ hash[param] = [value]
564
+ else
352
565
  # We always want the 'is' value to be an
353
566
  # array
354
- value = value.split(",")
567
+ hash[param] = value.split(",")
355
568
  end
356
- hash[param] = value
357
569
  end
358
570
  }
359
571
  else
360
- raise Puppet::Error, "Could not match '%s'" % line
572
+ # Don't fail on unmatched lines, just warn on them
573
+ # and skip them.
574
+ Puppet.warning "Could not match '%s'" % line
575
+ next
361
576
  end
577
+ end
362
578
 
363
- cron = nil
364
- unless name
365
- Puppet.info "Autogenerating name for %s" % hash[:command]
366
- name = "cron-%s" % hash.object_id
367
- end
579
+ unless envs.empty?
580
+ hash[:environment] = envs
581
+ end
368
582
 
369
- unless hash.include?(:command)
370
- raise Puppet::DevError, "No command for %s" % name
371
- end
372
- # if the cron already exists with that name...
373
- if cron = Puppet.type(:cron)[name]
374
- # Mark the cron job as present
375
- cron.is = [:ensure, :present]
376
- elsif tmp = @instances[user].reject { |obj|
377
- ! obj.is_a?(self)
378
- }.find { |obj|
379
- obj.should(:command) == hash[:command]
380
- }
381
- # if we can find a cron whose spec exactly matches
382
-
383
- # we now have a cron job whose command exactly matches
384
- # let's see if the other fields match
385
- txt = tmp.to_record.sub(/#.+\n/,'')
386
-
387
- if txt == line
388
- cron = tmp
389
- end
390
- else
391
- # create a new cron job, since no existing one
392
- # seems to match
393
- cron = self.create(
394
- :name => name
395
- )
396
- end
583
+ hash[:user] = user
397
584
 
398
- hash.each { |param, value|
399
- cron.is = [param, value]
400
- }
401
- hash.clear
402
- name = nil
403
- count += 1
404
- end
585
+ # Now convert our hash to an object.
586
+ hash2obj(hash)
587
+
588
+ hash = {}
589
+ envs.clear
590
+ count += 1
405
591
  }
406
592
  end
407
593
 
@@ -427,10 +613,16 @@ module Puppet
427
613
  self.find_all { |obj|
428
614
  obj[:user] == user
429
615
  }.each { |obj|
430
- obj.each { |state|
431
- state.is = :absent
432
- }
616
+ obj.is = [:ensure, :absent]
433
617
  }
618
+
619
+ # Get rid of the old instances, so we don't get duplicates
620
+ if @instances.include?(user)
621
+ @instances[user].clear
622
+ else
623
+ @instances[user] = []
624
+ end
625
+
434
626
  self.parse(user, text)
435
627
  end
436
628
  end
@@ -443,14 +635,24 @@ module Puppet
443
635
 
444
636
  # Store the user's cron tab. Collects the text of the new tab and
445
637
  # sends it to the +@filetype+ module's +write+ function. Also adds
446
- # header warning users not to modify the file directly.
638
+ # header, warning users not to modify the file directly.
447
639
  def self.store(user)
448
- @tabs[user] ||= @filetype.new(user)
449
- if @instances.include?(user)
450
- @tabs[user].write(self.tab(user))
451
- else
640
+ unless @instances.include?(user) or @objects.find do |n,o|
641
+ o[:user] == user
642
+ end
452
643
  Puppet.notice "No cron instances for %s" % user
644
+ return
645
+ end
646
+
647
+ @tabs[user] ||= @filetype.new(user)
648
+
649
+ self.each do |inst|
650
+ unless (@instances[user] and @instances[user].include? inst)
651
+ @instances[user] ||= []
652
+ @instances[user] << inst
653
+ end
453
654
  end
655
+ @tabs[user].write(self.tab(user))
454
656
  end
455
657
 
456
658
  # Collect all Cron instances for a given user and convert them
@@ -460,8 +662,6 @@ module Puppet
460
662
  if @instances.include?(user)
461
663
  return self.header() + @instances[user].reject { |obj|
462
664
  if obj.is_a?(self) and obj.should(:ensure) == :absent
463
- #obj.log "now absent"
464
- #obj.is = [:ensure, :absent]
465
665
  true
466
666
  else
467
667
  false
@@ -502,21 +702,11 @@ module Puppet
502
702
  def destroy
503
703
  # nothing, since the 'Cron.tab' method just doesn't write out
504
704
  # crons whose 'ensure' states are set to 'absent'.
505
- #@states.each { |n, state|
506
- # next if n == :ensure
507
- # state.should == :absent
508
- #}
509
705
  self.store
510
706
  end
511
707
 
512
708
  def exists?
513
- val = false
514
- if @states.include?(:command) and
515
- @states[:command].is != :absent and
516
- ! @states[:command].is.nil?
517
- val = true
518
- end
519
- return val
709
+ @states.include?(:ensure) and @states[:ensure].is == :present
520
710
  end
521
711
 
522
712
  # Override the default Puppet::Type method because we need to call
@@ -527,7 +717,15 @@ module Puppet
527
717
  end
528
718
 
529
719
  self.class.retrieve(self[:user])
530
- self.eachstate { |st| st.retrieve }
720
+ if withtab = self.class["testwithtab"]
721
+ Puppet.info withtab.is(:ensure).inspect
722
+ end
723
+ self.eachstate { |st|
724
+ st.retrieve
725
+ }
726
+ if withtab = self.class["testwithtab"]
727
+ Puppet.info withtab.is(:ensure).inspect
728
+ end
531
729
  end
532
730
 
533
731
  # Write the entire user's cron tab out.
@@ -538,25 +736,78 @@ module Puppet
538
736
  # Convert the current object a cron-style string. Adds the cron name
539
737
  # as a comment above the cron job, in the form '# Puppet Name: <name>'.
540
738
  def to_record
541
- hash = {:command => @states[:command].should || @states[:command].is }
739
+ hash = {}
542
740
 
543
741
  # Collect all of the values that we have
544
- self.class.fields().reject { |f| f == :command }.each { |param|
545
- if @states.include?(param)
546
- hash[param] = @states[param].should_to_s
742
+ self.class.fields().each { |param|
743
+ hash[param] = self.value(param)
744
+
745
+ unless hash[param]
746
+ devfail "Got no value for %s" % param
547
747
  end
548
748
  }
549
749
 
550
- return "# Puppet Name: %s\n" % self.name +
551
- self.class.fields.collect { |f|
750
+ str = ""
751
+
752
+ str = "# Puppet Name: %s\n" % self.name
753
+
754
+ if @states.include?(:environment) and
755
+ @states[:environment].should != :absent
756
+ envs = @states[:environment].should
757
+ unless envs.is_a? Array
758
+ envs = [envs]
759
+ end
760
+
761
+ envs.each do |line| str += (line + "\n") end
762
+ end
763
+
764
+ line = nil
765
+ if special = self.value(:special)
766
+ line = str + "@%s %s" %
767
+ [special, self.value(:command)]
768
+ else
769
+ line = str + self.class.fields.collect { |f|
552
770
  if hash[f] and hash[f] != :absent
553
771
  hash[f]
554
772
  else
555
773
  "*"
556
774
  end
557
775
  }.join(" ")
776
+ end
777
+
778
+ return line
779
+ end
780
+
781
+ def value(name)
782
+ name = name.intern if name.is_a? String
783
+ ret = nil
784
+ if @states.include?(name)
785
+ ret = @states[name].should_to_s
786
+
787
+ if ret == :absent or ret.nil?
788
+ ret = @states[name].is_to_s
789
+ end
790
+
791
+ if ret == :absent
792
+ ret = nil
793
+ end
794
+ end
795
+
796
+ unless ret
797
+ case name
798
+ when :command
799
+ devfail "No command, somehow"
800
+ when :special
801
+ # nothing
802
+ else
803
+ #ret = (self.class.validstate?(name).default || "*").to_s
804
+ ret = "*"
805
+ end
806
+ end
807
+
808
+ ret
558
809
  end
559
810
  end
560
811
  end
561
812
 
562
- # $Id: cron.rb 1127 2006-04-21 02:36:30Z luke $
813
+ # $Id: cron.rb 1402 2006-07-18 15:35:15Z luke $