chef 0.9.8 → 0.9.10.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/README.rdoc +1 -1
  2. data/distro/common/man/man8/knife.8 +89 -79
  3. data/distro/common/markdown/knife.mkd +7 -0
  4. data/distro/debian/etc/default/chef-server +3 -0
  5. data/distro/debian/etc/default/chef-server-webui +3 -0
  6. data/distro/debian/etc/default/chef-solr +3 -0
  7. data/distro/debian/etc/default/chef-solr-indexer +3 -0
  8. data/distro/debian/etc/init.d/chef-server +3 -1
  9. data/distro/debian/etc/init.d/chef-server-webui +3 -1
  10. data/distro/redhat/etc/init.d/chef-client +1 -1
  11. data/lib/chef/application.rb +2 -0
  12. data/lib/chef/application/client.rb +5 -3
  13. data/lib/chef/application/knife.rb +16 -5
  14. data/lib/chef/application/solo.rb +0 -1
  15. data/lib/chef/checksum.rb +65 -1
  16. data/lib/chef/checksum_cache.rb +173 -0
  17. data/lib/chef/client.rb +84 -121
  18. data/lib/chef/cookbook/remote_file_vendor.rb +10 -3
  19. data/lib/chef/cookbook/syntax_check.rb +2 -2
  20. data/lib/chef/cookbook_loader.rb +2 -0
  21. data/lib/chef/cookbook_site_streaming_uploader.rb +29 -0
  22. data/lib/chef/cookbook_uploader.rb +8 -7
  23. data/lib/chef/cookbook_version.rb +155 -114
  24. data/lib/chef/exceptions.rb +5 -0
  25. data/lib/chef/handler.rb +43 -0
  26. data/lib/chef/index_queue/consumer.rb +1 -1
  27. data/lib/chef/index_queue/indexable.rb +1 -1
  28. data/lib/chef/knife.rb +18 -5
  29. data/lib/chef/knife/bootstrap.rb +2 -2
  30. data/lib/chef/knife/bootstrap/archlinux-gems.erb +44 -0
  31. data/lib/chef/knife/bootstrap/client-install.vbs +80 -0
  32. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +2 -2
  33. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +6 -7
  34. data/lib/chef/knife/bootstrap/windows-gems.erb +34 -0
  35. data/lib/chef/knife/configure_client.rb +4 -2
  36. data/lib/chef/knife/cookbook_metadata.rb +1 -1
  37. data/lib/chef/knife/cookbook_site_share.rb +2 -1
  38. data/lib/chef/knife/cookbook_site_vendor.rb +6 -0
  39. data/lib/chef/knife/cookbook_test.rb +1 -1
  40. data/lib/chef/knife/ec2_server_create.rb +51 -26
  41. data/lib/chef/knife/exec.rb +52 -0
  42. data/lib/chef/knife/ssh.rb +27 -15
  43. data/lib/chef/knife/status.rb +27 -10
  44. data/lib/chef/knife/windows_bootstrap.rb +154 -0
  45. data/lib/chef/mixin/checksum.rb +2 -2
  46. data/lib/chef/mixin/xml_escape.rb +75 -49
  47. data/lib/chef/node.rb +54 -58
  48. data/lib/chef/node/attribute.rb +61 -53
  49. data/lib/chef/platform.rb +19 -2
  50. data/lib/chef/provider/breakpoint.rb +1 -1
  51. data/lib/chef/provider/cookbook_file.rb +3 -3
  52. data/lib/chef/provider/cron.rb +3 -3
  53. data/lib/chef/provider/cron/solaris.rb +195 -0
  54. data/lib/chef/provider/deploy.rb +3 -3
  55. data/lib/chef/provider/directory.rb +2 -2
  56. data/lib/chef/provider/env.rb +5 -5
  57. data/lib/chef/provider/execute.rb +1 -1
  58. data/lib/chef/provider/file.rb +10 -9
  59. data/lib/chef/provider/git.rb +12 -4
  60. data/lib/chef/provider/group.rb +5 -5
  61. data/lib/chef/provider/http_request.rb +25 -9
  62. data/lib/chef/provider/ifconfig.rb +2 -2
  63. data/lib/chef/provider/link.rb +11 -6
  64. data/lib/chef/provider/log.rb +1 -0
  65. data/lib/chef/provider/mdadm.rb +3 -3
  66. data/lib/chef/provider/mount.rb +5 -5
  67. data/lib/chef/provider/mount/mount.rb +1 -1
  68. data/lib/chef/provider/ohai.rb +41 -0
  69. data/lib/chef/provider/package.rb +5 -5
  70. data/lib/chef/provider/package/yum-dump.py +5 -2
  71. data/lib/chef/provider/remote_directory.rb +11 -5
  72. data/lib/chef/provider/remote_file.rb +2 -2
  73. data/lib/chef/provider/route.rb +154 -133
  74. data/lib/chef/provider/ruby_block.rb +1 -1
  75. data/lib/chef/provider/service.rb +6 -6
  76. data/lib/chef/provider/subversion.rb +12 -9
  77. data/lib/chef/provider/template.rb +2 -2
  78. data/lib/chef/provider/user.rb +7 -7
  79. data/lib/chef/provider/user/useradd.rb +15 -1
  80. data/lib/chef/providers.rb +2 -0
  81. data/lib/chef/resource.rb +164 -58
  82. data/lib/chef/resource/http_request.rb +9 -0
  83. data/lib/chef/resource/ohai.rb +40 -0
  84. data/lib/chef/resource/remote_directory.rb +10 -1
  85. data/lib/chef/resource/rpm_package.rb +34 -0
  86. data/lib/chef/resource_collection.rb +3 -2
  87. data/lib/chef/resources.rb +2 -0
  88. data/lib/chef/rest.rb +13 -7
  89. data/lib/chef/rest/auth_credentials.rb +1 -1
  90. data/lib/chef/rest/rest_request.rb +3 -1
  91. data/lib/chef/runner.rb +31 -55
  92. data/lib/chef/shef/shef_session.rb +1 -1
  93. data/lib/chef/util/windows/net_use.rb +1 -1
  94. data/lib/chef/version.rb +1 -1
  95. data/lib/chef/webui_user.rb +0 -1
  96. metadata +38 -19
  97. data/lib/chef/cache.rb +0 -61
  98. data/lib/chef/cache/checksum.rb +0 -91
@@ -29,14 +29,12 @@ class Chef
29
29
  :default,
30
30
  :override,
31
31
  :automatic,
32
- :state,
33
32
  :current_normal,
34
33
  :current_default,
35
34
  :current_override,
36
35
  :current_automatic,
37
36
  :auto_vivifiy_on_read,
38
37
  :set_unless_value_present,
39
- :has_been_read,
40
38
  :set_type
41
39
 
42
40
  include Enumerable
@@ -50,7 +48,7 @@ class Chef
50
48
  @current_override = override
51
49
  @automatic = automatic
52
50
  @current_automatic = automatic
53
- @state = state
51
+ @current_nesting_level = state
54
52
  @auto_vivifiy_on_read = false
55
53
  @set_unless_value_present = false
56
54
  @set_type = nil
@@ -78,18 +76,18 @@ class Chef
78
76
  end
79
77
  end
80
78
 
81
- # Reset our internal state to the top of every tree
79
+ # Reset our internal current_nesting_level to the top of every tree
82
80
  def reset
83
81
  @current_normal = @normal
84
82
  @current_default = @default
85
83
  @current_override = @override
86
84
  @current_automatic = @automatic
87
85
  @has_been_read = false
88
- @state = []
86
+ @current_nesting_level = []
89
87
  end
90
88
 
91
89
  def [](key)
92
- @state << key
90
+ @current_nesting_level << key
93
91
 
94
92
  # We set this to so that we can cope with ||= as a setting.
95
93
  # See the comments in []= for more details.
@@ -114,21 +112,18 @@ class Chef
114
112
  end
115
113
  end
116
114
 
117
- def attribute?(key)
118
- return true if get_value(automatic, key)
119
- return true if get_value(override, key)
120
- return true if get_value(normal, key)
121
- return true if get_value(default, key)
122
- false
123
- end
124
-
125
115
  def has_key?(key)
126
- attribute?(key)
116
+ return true if component_has_key?(@default,key)
117
+ return true if component_has_key?(@automatic,key)
118
+ return true if component_has_key?(@normal,key)
119
+ return true if component_has_key?(@override,key)
120
+ false
127
121
  end
128
122
 
129
- alias :include? :has_key?
130
- alias :key? :has_key?
131
- alias :member? :has_key?
123
+ alias :attribute? :has_key?
124
+ alias :include? :has_key?
125
+ alias :key? :has_key?
126
+ alias :member? :has_key?
132
127
 
133
128
  def each(&block)
134
129
  get_keys.each do |key|
@@ -263,7 +258,7 @@ class Chef
263
258
  def get_value(data_hash, key)
264
259
  last = nil
265
260
 
266
- if state.length == 0
261
+ if @current_nesting_level.length == 0
267
262
  if data_hash.has_key?(key) && ! data_hash[key].nil?
268
263
  return data_hash[key]
269
264
  else
@@ -271,18 +266,18 @@ class Chef
271
266
  end
272
267
  end
273
268
 
274
- 0.upto(state.length) do |i|
269
+ 0.upto(@current_nesting_level.length) do |i|
275
270
  if i == 0
276
- last = auto_vivifiy(data_hash, state[i])
277
- elsif i == state.length
278
- fk = last[state[i - 1]]
271
+ last = auto_vivifiy(data_hash, @current_nesting_level[i])
272
+ elsif i == @current_nesting_level.length
273
+ fk = last[@current_nesting_level[i - 1]]
279
274
  if fk.has_key?(key) && ! fk[key].nil?
280
275
  return fk[key]
281
276
  else
282
277
  return nil
283
278
  end
284
279
  else
285
- last = auto_vivifiy(last[state[i - 1]], state[i])
280
+ last = auto_vivifiy(last[@current_nesting_level[i - 1]], @current_nesting_level[i])
286
281
  end
287
282
  end
288
283
  end
@@ -327,7 +322,7 @@ class Chef
327
322
 
328
323
  if set_unless_value_present
329
324
  if get_value(set_type_hash, key) != nil
330
- Chef::Log.debug("Not setting #{state.join("/")}/#{key} to #{value.inspect} because it has a #{@set_type} value already")
325
+ Chef::Log.debug("Not setting #{@current_nesting_level.join("/")}/#{key} to #{value.inspect} because it has a #{@set_type} value already")
331
326
  return false
332
327
  end
333
328
  end
@@ -338,7 +333,7 @@ class Chef
338
333
  #
339
334
  # In practice, these objects are single use - this is just
340
335
  # supporting one more single-use style.
341
- @state.pop if @has_been_read && @state.last == key
336
+ @current_nesting_level.pop if @has_been_read && @current_nesting_level.last == key
342
337
 
343
338
  set_value(set_type_hash, key, value)
344
339
  value
@@ -347,23 +342,23 @@ class Chef
347
342
  def set_value(data_hash, key, value)
348
343
  last = nil
349
344
 
350
- # If there is no state, just set the value
351
- if state.length == 0
345
+ # If there is no current_nesting_level, just set the value
346
+ if @current_nesting_level.length == 0
352
347
  data_hash[key] = value
353
348
  return data_hash
354
349
  end
355
350
 
356
351
  # Walk all the previous places we have been
357
- 0.upto(state.length) do |i|
352
+ 0.upto(@current_nesting_level.length) do |i|
358
353
  # If we are the first, we are top level, and should vivifiy the data_hash
359
354
  if i == 0
360
- last = auto_vivifiy(data_hash, state[i])
361
- # If we are one past the last state, we are adding a key to that hash with a value
362
- elsif i == state.length
363
- last[state[i - 1]][key] = value
355
+ last = auto_vivifiy(data_hash, @current_nesting_level[i])
356
+ # If we are one past the last current_nesting_level, we are adding a key to that hash with a value
357
+ elsif i == @current_nesting_level.length
358
+ last[@current_nesting_level[i - 1]][key] = value
364
359
  # Otherwise, we're auto-vivifiy-ing an interim mash
365
360
  else
366
- last = auto_vivifiy(last[state[i - 1]], state[i])
361
+ last = auto_vivifiy(last[@current_nesting_level[i - 1]], @current_nesting_level[i])
367
362
  end
368
363
  end
369
364
  data_hash
@@ -372,7 +367,7 @@ class Chef
372
367
  def auto_vivifiy(data_hash, key)
373
368
  if data_hash.has_key?(key)
374
369
  unless data_hash[key].respond_to?(:has_key?)
375
- raise ArgumentError, "You tried to set a nested key, where the parent is not a hash-like object: #{@state.join("/")}/#{key} " unless auto_vivifiy_on_read
370
+ raise ArgumentError, "You tried to set a nested key, where the parent is not a hash-like object: #{@current_nesting_level.join("/")}/#{key} " unless auto_vivifiy_on_read
376
371
  end
377
372
  else
378
373
  data_hash[key] = Mash.new
@@ -390,7 +385,7 @@ class Chef
390
385
  end
391
386
 
392
387
  if data_hash[key].respond_to?(:has_key?)
393
- cna = Chef::Node::Attribute.new(@normal, @default, @override, @automatic, @state)
388
+ cna = Chef::Node::Attribute.new(@normal, @default, @override, @automatic, @current_nesting_level)
394
389
  cna.current_normal = current_normal.nil? ? Mash.new : current_normal[key]
395
390
  cna.current_default = current_default.nil? ? Mash.new : current_default[key]
396
391
  cna.current_override = current_override.nil? ? Mash.new : current_override[key]
@@ -404,27 +399,30 @@ class Chef
404
399
  end
405
400
  end
406
401
 
402
+ # Fetches or sets the value, depending on if any arguments are given.
403
+ # ==== Fetching
404
+ # If no arguments are given, fetches the value:
405
+ # node.network
406
+ # => {network data}
407
+ # Getters will find either a string or symbol key.
408
+ # ==== Setting
409
+ # If arguments are given, a value will be set. Both normal setter and DSL
410
+ # style setters are allowed:
411
+ # node.foo = "bar"
412
+ # node.foo("bar")
413
+ # Both set node[:foo] = "bar"
407
414
  def method_missing(symbol, *args)
408
- by = symbol
409
- if self.attribute?(symbol)
410
- by = symbol
411
- elsif self.attribute?(symbol.to_s)
412
- by = symbol.to_s
413
- else
414
- if args.length != 0
415
- by = symbol
415
+ if args.empty?
416
+ if key?(symbol)
417
+ self[symbol]
418
+ elsif key?(symbol.to_s)
419
+ self[symbol.to_s]
416
420
  else
417
- raise ArgumentError, "Attribute #{symbol.to_s} is not defined!" unless auto_vivifiy_on_read
421
+ raise ArgumentError, "Attribute #{symbol} is not defined!" unless auto_vivifiy_on_read
418
422
  end
419
- end
420
-
421
- if args.length != 0
422
- if by.to_s =~ /^(.+)=$/
423
- by = $1
424
- end
425
- self[by] = args.length == 1 ? args[0] : args
426
423
  else
427
- self[by]
424
+ key_to_set = symbol.to_s[/^(.+)=$/, 1] || symbol
425
+ self[key_to_set] = (args.length == 1 ? args[0] : args)
428
426
  end
429
427
  end
430
428
 
@@ -445,6 +443,16 @@ class Chef
445
443
  end
446
444
  end
447
445
 
446
+ def component_has_key?(component_attrs,key)
447
+ # get the Hash-like object at the current nesting level:
448
+ nested_attrs = @current_nesting_level.inject(component_attrs) do |subtree, intermediate_key|
449
+ # if the intermediate value isn't a hash or doesn't have the intermediate key,
450
+ # it can't have the bottom-level key we're looking for.
451
+ (subtree.respond_to?(:key?) && subtree[intermediate_key]) or (return false)
452
+ end
453
+ nested_attrs.respond_to?(:key?) && nested_attrs.key?(key)
454
+ end
455
+
448
456
  end
449
457
  end
450
458
  end
@@ -80,6 +80,22 @@ class Chef
80
80
  :mdadm => Chef::Provider::Mdadm
81
81
  }
82
82
  },
83
+ :amazon => {
84
+ :default => {
85
+ :service => Chef::Provider::Service::Redhat,
86
+ :cron => Chef::Provider::Cron,
87
+ :package => Chef::Provider::Package::Yum,
88
+ :mdadm => Chef::Provider::Mdadm
89
+ }
90
+ },
91
+ :scientific => {
92
+ :default => {
93
+ :service => Chef::Provider::Service::Redhat,
94
+ :cron => Chef::Provider::Cron,
95
+ :package => Chef::Provider::Package::Yum,
96
+ :mdadm => Chef::Provider::Mdadm
97
+ }
98
+ },
83
99
  :fedora => {
84
100
  :default => {
85
101
  :service => Chef::Provider::Service::Redhat,
@@ -150,8 +166,9 @@ class Chef
150
166
  :solaris2 => {
151
167
  :default => {
152
168
  :service => Chef::Provider::Service::Solaris,
153
- :package => Chef::Provider::Package::Solaris,
154
- :cron => Chef::Provider::Cron
169
+ :package => Chef::Provider::Package::Solaris,
170
+ :cron => Chef::Provider::Cron::Solaris,
171
+ :group => Chef::Provider::Group::Usermod
155
172
  }
156
173
  },
157
174
  :default => {
@@ -26,7 +26,7 @@ class Chef
26
26
  def action_break
27
27
  if defined?(Shef) && Shef.running?
28
28
  run_context.resource_collection.iterator.pause
29
- @new_resource.updated = true
29
+ @new_resource.updated_by_last_action(true)
30
30
  run_context.resource_collection.iterator
31
31
  end
32
32
  end
@@ -42,11 +42,11 @@ class Chef
42
42
  stage_file_to_tmpdir(staging_file.path)
43
43
  FileUtils.mv(staging_file.path, @new_resource.path)
44
44
  end
45
- @new_resource.updated = true
45
+ @new_resource.updated_by_last_action(true)
46
46
  else
47
47
  set_all_access_controls(@new_resource.path)
48
48
  end
49
- @new_resource.updated
49
+ @new_resource.updated_by_last_action(true)
50
50
  end
51
51
 
52
52
  def action_create_if_missing
@@ -81,7 +81,7 @@ class Chef
81
81
  def set_all_access_controls(file)
82
82
  access_controls = Chef::FileAccessControl.new(@new_resource, file)
83
83
  access_controls.set_all
84
- @new_resource.updated = access_controls.modified?
84
+ @new_resource.updated_by_last_action(access_controls.modified?)
85
85
  end
86
86
 
87
87
  def backup_new_resource
@@ -133,7 +133,7 @@ class Chef
133
133
  crontab.each_line { |line| stdin.puts "#{line}" }
134
134
  end
135
135
  Chef::Log.info("Updated cron '#{@new_resource.name}'")
136
- @new_resource.updated = true
136
+ @new_resource.updated_by_last_action(true)
137
137
  else
138
138
  unless @cron_empty
139
139
  status = popen4("crontab -l -u #{@new_resource.user}") do |pid, stdin, stdout, stderr|
@@ -147,7 +147,7 @@ class Chef
147
147
  crontab.each_line { |line| stdin.puts "#{line}" }
148
148
  end
149
149
  Chef::Log.info("Added cron '#{@new_resource.name}'")
150
- @new_resource.updated = true
150
+ @new_resource.updated_by_last_action(true)
151
151
  end
152
152
  end
153
153
 
@@ -177,7 +177,7 @@ class Chef
177
177
  crontab.each_line { |line| stdin.puts "#{line}" }
178
178
  end
179
179
  Chef::Log.debug("Deleted cron '#{@new_resource.name}'")
180
- @new_resource.updated = true
180
+ @new_resource.updated_by_last_action(true)
181
181
  end
182
182
  end
183
183
 
@@ -0,0 +1,195 @@
1
+ #
2
+ # Author:: Bryan McLellan (btm@loftninjas.org)
3
+ # Author:: Toomas Pelberg (toomasp@gmx.net)
4
+ # Copyright:: Copyright (c) 2009 Bryan McLellan
5
+ # Copyright:: Copyright (c) 2010 Toomas Pelberg
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ require 'chef/log'
22
+ require 'chef/mixin/command'
23
+ require 'chef/provider'
24
+
25
+ class Chef
26
+ class Provider
27
+ class Cron
28
+ class Solaris < Chef::Provider::Cron
29
+ include Chef::Mixin::Command
30
+
31
+ CRON_PATTERN = /([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+)\s([-0-9*,\/]+)\s(.*)/
32
+
33
+ def initialize(new_resource, run_context)
34
+ super(new_resource, run_context)
35
+ @cron_exists = false
36
+ @cron_empty = false
37
+ end
38
+ attr_accessor :cron_exists, :cron_empty
39
+
40
+ def load_current_resource
41
+ crontab_lines = []
42
+ @current_resource = Chef::Resource::Cron.new(@new_resource.name)
43
+ @current_resource.user(@new_resource.user)
44
+ status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
45
+ stdout.each_line { |line| crontab_lines << line }
46
+ end
47
+ if status.exitstatus > 1
48
+ raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}"
49
+ elsif status.exitstatus == 0
50
+ cron_found = false
51
+ crontab_lines.each do |line|
52
+ case line.chomp
53
+ when "# Chef Name: #{@new_resource.name}"
54
+ Chef::Log.debug("Found cron '#{@new_resource.name}'")
55
+ cron_found = true
56
+ @cron_exists = true
57
+ next
58
+ when /^MAILTO=(\S*)/
59
+ @current_resource.mailto($1) if cron_found
60
+ next
61
+ when /^PATH=(\S*)/
62
+ @current_resource.path($1) if cron_found
63
+ next
64
+ when /^SHELL=(\S*)/
65
+ @current_resource.shell($1) if cron_found
66
+ next
67
+ when /^HOME=(\S*)/
68
+ @current_resource.home($1) if cron_found
69
+ next
70
+ when CRON_PATTERN
71
+ if cron_found
72
+ @current_resource.minute($1)
73
+ @current_resource.hour($2)
74
+ @current_resource.day($3)
75
+ @current_resource.month($4)
76
+ @current_resource.weekday($5)
77
+ @current_resource.command($6)
78
+ cron_found=false
79
+ end
80
+ next
81
+ else
82
+ next
83
+ end
84
+ end
85
+ Chef::Log.debug("Cron '#{@new_resource.name}' not found") unless @cron_exists
86
+ elsif status.exitstatus == 1
87
+ Chef::Log.debug("Cron empty for '#{@new_resource.user}'")
88
+ @cron_empty = true
89
+ end
90
+
91
+ @current_resource
92
+ end
93
+
94
+ def compare_cron
95
+ [ :minute, :hour, :day, :month, :weekday, :command, :mailto, :path, :shell, :home ].any? do |cron_var|
96
+ !@new_resource.send(cron_var).nil? && @new_resource.send(cron_var) != @current_resource.send(cron_var)
97
+ end
98
+ end
99
+
100
+ def write_crontab(crontab)
101
+ tempcron = Tempfile.new("chef-cron")
102
+ tempcron << crontab
103
+ tempcron.flush
104
+ tempcron.chmod(0644)
105
+ status = run_command(:command => "/usr/bin/crontab #{tempcron.path}",:user => @new_resource.user)
106
+ if(status == 0)
107
+ @new_resource.updated_by_last_action(true)
108
+ else
109
+ @new_resource.updated_by_last_action(false)
110
+ end
111
+ tempcron.close!
112
+ return status
113
+ end
114
+
115
+ def action_create
116
+ crontab = String.new
117
+ newcron = String.new
118
+ cron_found = false
119
+
120
+ newcron << "# Chef Name: #{new_resource.name}\n"
121
+ [ :mailto, :path, :shell, :home ].each do |v|
122
+ newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v)
123
+ end
124
+ newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
125
+
126
+ if @cron_exists
127
+ unless compare_cron
128
+ Chef::Log.debug("Skipping existing cron entry '#{@new_resource.name}'")
129
+ return
130
+ end
131
+ status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
132
+ stdout.each_line do |line|
133
+ case line.chomp
134
+ when "# Chef Name: #{@new_resource.name}"
135
+ cron_found = true
136
+ next
137
+ when CRON_PATTERN
138
+ if cron_found
139
+ cron_found = false
140
+ crontab << newcron
141
+ next
142
+ end
143
+ else
144
+ next if cron_found
145
+ end
146
+ crontab << line
147
+ end
148
+ end
149
+
150
+ status = write_crontab(crontab)
151
+ Chef::Log.info("Updated cron '#{@new_resource.name}'")
152
+ else
153
+ unless @cron_empty
154
+ status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
155
+ stdout.each { |line| crontab << line }
156
+ end
157
+ end
158
+
159
+ crontab << newcron
160
+ status = write_crontab(crontab)
161
+ Chef::Log.info("Added cron '#{@new_resource.name}'")
162
+ end
163
+ end
164
+
165
+ def action_delete
166
+ if @cron_exists
167
+ crontab = String.new
168
+ cron_found = false
169
+ status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
170
+ stdout.each_line do |line|
171
+ case line.chomp
172
+ when "# Chef Name: #{@new_resource.name}"
173
+ cron_found = true
174
+ next
175
+ when CRON_PATTERN
176
+ if cron_found
177
+ cron_found = false
178
+ next
179
+ end
180
+ else
181
+ next if cron_found
182
+ end
183
+ crontab << line
184
+ end
185
+ end
186
+
187
+ status = write_crontab(crontab)
188
+ Chef::Log.info("Deleted cron '#{@new_resource.name}'")
189
+ end
190
+ end
191
+
192
+ end
193
+ end
194
+ end
195
+ end