summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt <code@deployable.org>2013-12-05 12:20:39 +0000
committerClaire McQuin <claire@getchef.com>2014-06-18 15:23:33 -0700
commitd950ec4bea3333e8739630c37156d6b9d06eccda (patch)
treed280e92372b4fb41642cedf5e957eedd1035553e
parentd8592902ae09980552f8dd57abe9ed9c76851445 (diff)
downloadchef-d950ec4bea3333e8739630c37156d6b9d06eccda.tar.gz
CHEF-4600 Add timeout for Chef::Provider::Service::Windows
-rw-r--r--lib/chef/provider/service/windows.rb22
-rw-r--r--lib/chef/resource/service.rb8
-rw-r--r--spec/unit/provider/service/windows_spec.rb16
3 files changed, 33 insertions, 13 deletions
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index ae4f29b1b3..ba2d5d76ed 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -41,6 +41,8 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
START_PENDING = 'start pending'
STOP_PENDING = 'stop pending'
+ TIMEOUT = 60
+
def whyrun_supported?
false
end
@@ -70,13 +72,13 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
Chef::Log.debug "#{@new_resource} starting service using the given start_command"
shell_out!(@new_resource.start_command)
else
- spawn_command_thread do
+ command_timeout do
Win32::Service.start(@new_resource.service_name)
wait_for_state(RUNNING)
end
end
@new_resource.updated_by_last_action(true)
- else
+ else
raise Chef::Exceptions::Service, "Service #{@new_resource} can't be started from state [#{state}]"
end
else
@@ -92,7 +94,7 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
Chef::Log.debug "#{@new_resource} stopping service using the given stop_command"
shell_out!(@new_resource.stop_command)
else
- spawn_command_thread do
+ command_timeout do
Win32::Service.stop(@new_resource.service_name)
wait_for_state(STOPPED)
end
@@ -175,13 +177,13 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
sleep 1 until current_state == desired_state
end
- # There ain't no party like a thread party...
- def spawn_command_thread
- worker = Thread.new do
- yield
- end
- Timeout.timeout(60) do
- worker.join
+ def command_timeout
+ timeout = @new_resource.timeout if @new_resource.timeout
+ timeout ||= TIMEOUT
+ Chef::Log.debug "service command timeout [#{timeout}]"
+
+ Timeout.timeout(timeout) do
+ yield
end
end
end
diff --git a/lib/chef/resource/service.rb b/lib/chef/resource/service.rb
index c3d009bc55..a7f1aa3470 100644
--- a/lib/chef/resource/service.rb
+++ b/lib/chef/resource/service.rb
@@ -42,6 +42,7 @@ class Chef
@reload_command = nil
@init_command = nil
@priority = nil
+ @timeout = nil
@action = "nothing"
@supports = { :restart => false, :reload => false, :status => false }
@allowed_actions.push(:enable, :disable, :start, :stop, :restart, :reload)
@@ -155,6 +156,13 @@ class Chef
:kind_of => [ Integer, String, Hash ])
end
+ # timeout only applies to the windows service manager
+ def timeout(arg=nil)
+ set_or_return(:timeout,
+ arg,
+ :kind_of => Integer )
+ end
+
def parameters(arg=nil)
set_or_return(
:parameters,
diff --git a/spec/unit/provider/service/windows_spec.rb b/spec/unit/provider/service/windows_spec.rb
index a007e7b984..d60c6f03ff 100644
--- a/spec/unit/provider/service/windows_spec.rb
+++ b/spec/unit/provider/service/windows_spec.rb
@@ -92,7 +92,7 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
@provider.start_service
@new_resource.updated_by_last_action?.should be_false
end
-
+
it "should raise an error if the service is paused" do
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "paused"))
@@ -112,7 +112,7 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
@provider.start_service
@new_resource.updated_by_last_action?.should be_false
end
-
+
it "should fail if the service is in stop_pending" do
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "stop pending"))
@@ -170,7 +170,7 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
expect { @provider.stop_service }.to raise_error( Chef::Exceptions::Service )
@new_resource.updated_by_last_action?.should be_false
end
-
+
it "should wait and continue if the service is in stop_pending" do
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "stop pending"),
@@ -191,6 +191,16 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
@new_resource.updated_by_last_action?.should be_false
end
+ it "should pass custom timeout to the stop command if provided" do
+ Win32::Service.stub!(:status).with(@new_resource.service_name).and_return(
+ mock("StatusStruct", :current_state => "running"))
+ @new_resource.timeout 1
+ Win32::Service.should_receive(:stop).with(@new_resource.service_name)
+ Timeout.timeout(2) do
+ expect { @provider.stop_service }.to raise_error(Timeout::Error)
+ end
+ @new_resource.updated_by_last_action?.should be_false
+ end
end
describe Chef::Provider::Service::Windows, "restart_service" do