chef 0.9.8 → 0.9.10.rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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