diff options
author | kaustubh-d <kausubh@clogeny.com> | 2013-07-23 04:57:47 -0700 |
---|---|---|
committer | adamedx <adamed@opscode.com> | 2013-08-04 08:27:07 -0700 |
commit | a3dbaab9287a2dce7d3c972dc54166b3c079d62e (patch) | |
tree | 17417c32e53f481dbc3e6444ca714af874d5d39a | |
parent | 126f8b7c1df884ccb55f1010ecca944e27a707be (diff) | |
download | chef-a3dbaab9287a2dce7d3c972dc54166b3c079d62e.tar.gz |
popen4 can yield while child has already died.
-rw-r--r-- | lib/chef/provider/cron.rb | 11 | ||||
-rw-r--r-- | spec/unit/provider/cron_spec.rb | 17 |
2 files changed, 26 insertions, 2 deletions
diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb index 19fe9a64af..4430e3e18f 100644 --- a/lib/chef/provider/cron.rb +++ b/lib/chef/provider/cron.rb @@ -196,10 +196,17 @@ class Chef end def write_crontab(crontab) + write_exception = false status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr| - stdin.write crontab + begin + stdin.write crontab + rescue Errno::EPIPE => e + # popen4 could yield while child has already died. + write_exception = true + Chef::Log.debug("#{e.message}") + end end - if status.exitstatus > 0 + if status.exitstatus > 0 || write_exception raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{status.exitstatus}" end end diff --git a/spec/unit/provider/cron_spec.rb b/spec/unit/provider/cron_spec.rb index 56d51cd23f..f0d800741d 100644 --- a/spec/unit/provider/cron_spec.rb +++ b/spec/unit/provider/cron_spec.rb @@ -809,5 +809,22 @@ MAILTO=foo@example.com @provider.send(:write_crontab, "Foo") end.should raise_error(Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: 1") end + + it "should raise an exception if the command die's and parent tries to write" do + class WriteErrPipe + def write(str) + raise Errno::EPIPE, "Test" + end + end + @status.stub!(:exitstatus).and_return(1) + @provider.stub!(:popen4).and_yield(1234, WriteErrPipe.new, StringIO.new, StringIO.new).and_return(@status) + + Chef::Log.should_receive(:debug).with("Broken pipe - Test") + + lambda do + @provider.send(:write_crontab, "Foo") + end.should raise_error(Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: 1") + end + end end |