Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CHEF-4791 Add more windows service states to the start/stop control flow #1166

Merged
merged 2 commits into from Jun 18, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 30 additions & 6 deletions lib/chef/provider/service/windows.rb
Expand Up @@ -28,11 +28,19 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service

include Chef::Mixin::ShellOut

RUNNING = 'running'
STOPPED = 'stopped'
#Win32::Service.get_start_type
AUTO_START = 'auto start'
DISABLED = 'disabled'

#Win32::Service.get_current_state
RUNNING = 'running'
STOPPED = 'stopped'
CONTINUE_PENDING = 'continue pending'
PAUSE_PENDING = 'pause pending'
PAUSED = 'paused'
START_PENDING = 'start pending'
STOP_PENDING = 'stop pending'

def whyrun_supported?
false
end
Expand All @@ -49,9 +57,15 @@ def load_current_resource

def start_service
if Win32::Service.exists?(@new_resource.service_name)
if current_state == RUNNING
state = current_state
if state == RUNNING
Chef::Log.debug "#{@new_resource} already started - nothing to do"
else
elsif state == START_PENDING
Chef::Log.debug "#{@new_resource} already sent start signal - waiting for start"
spawn_command_thread do
wait_for_state(RUNNING)
end
elsif state == STOPPED
if @new_resource.start_command
Chef::Log.debug "#{@new_resource} starting service using the given start_command"
shell_out!(@new_resource.start_command)
Expand All @@ -62,6 +76,8 @@ def start_service
end
end
@new_resource.updated_by_last_action(true)
else
raise Chef::Exceptions::Service, "Service #{@new_resource} can't be started from state [#{state}]"
end
else
Chef::Log.debug "#{@new_resource} does not exist - nothing to do"
Expand All @@ -70,7 +86,8 @@ def start_service

def stop_service
if Win32::Service.exists?(@new_resource.service_name)
if current_state == RUNNING
state = current_state
if state == RUNNING
if @new_resource.stop_command
Chef::Log.debug "#{@new_resource} stopping service using the given stop_command"
shell_out!(@new_resource.stop_command)
Expand All @@ -81,8 +98,15 @@ def stop_service
end
end
@new_resource.updated_by_last_action(true)
else
elsif state == STOPPED
Chef::Log.debug "#{@new_resource} already stopped - nothing to do"
elsif state == STOP_PENDING
Chef::Log.debug "#{@new_resource} already sent stop signal - waiting for stop"
spawn_command_thread do
wait_for_state(STOPPED)
end
else
raise Chef::Exceptions::Service, "Service #{@new_resource} can't be stopped from state [#{state}]"
end
else
Chef::Log.debug "#{@new_resource} does not exist - nothing to do"
Expand Down
135 changes: 98 additions & 37 deletions spec/unit/provider/service/windows_spec.rb
Expand Up @@ -31,11 +31,11 @@
Win32::Service = Class.new
Win32::Service::AUTO_START = 0x00000002
Win32::Service::DISABLED = 0x00000004
Win32::Service.stub!(:status).with(@new_resource.service_name).and_return(
mock("StatusStruct", :current_state => "running"))
Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return(
mock("ConfigStruct", :start_type => "auto start"))
Win32::Service.stub!(:exists?).and_return(true)
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "running"))
Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return(
double("ConfigStruct", :start_type => "auto start"))
Win32::Service.stub(:exists?).and_return(true)
end

it "should set the current resources service name to the new resources service name" do
Expand All @@ -59,9 +59,9 @@

describe Chef::Provider::Service::Windows, "start_service" do
before(:each) do
Win32::Service.stub!(:status).with(@new_resource.service_name).and_return(
mock("StatusStruct", :current_state => "stopped"),
mock("StatusStruct", :current_state => "running"))
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "stopped"),
double("StatusStruct", :current_state => "running"))
end

it "should call the start command if one is specified" do
Expand All @@ -78,28 +78,59 @@
end

it "should do nothing if the service does not exist" do
Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.should_not_receive(:start).with(@new_resource.service_name)
@provider.start_service
@new_resource.updated_by_last_action?.should be_false
end

it "should do nothing if the service is running" do
Win32::Service.stub!(:status).with(@new_resource.service_name).and_return(
mock("StatusStruct", :current_state => "running"))
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "running"))
@provider.load_current_resource
Win32::Service.should_not_receive(:start).with(@new_resource.service_name)
@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"))
@provider.load_current_resource
Win32::Service.should_not_receive(:start).with(@new_resource.service_name)
expect { @provider.start_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 start_pending" do
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "start pending"),
double("StatusStruct", :current_state => "start pending"),
double("StatusStruct", :current_state => "running"))
@provider.load_current_resource
Win32::Service.should_not_receive(:start).with(@new_resource.service_name)
@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"))
@provider.load_current_resource
Win32::Service.should_not_receive(:start).with(@new_resource.service_name)
expect { @provider.start_service }.to raise_error( Chef::Exceptions::Service )
@new_resource.updated_by_last_action?.should be_false
end

end


describe Chef::Provider::Service::Windows, "stop_service" do

before(:each) do
Win32::Service.stub!(:status).with(@new_resource.service_name).and_return(
mock("StatusStruct", :current_state => "running"),
mock("StatusStruct", :current_state => "stopped"))
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "running"),
double("StatusStruct", :current_state => "stopped"))
end

it "should call the stop command if one is specified" do
Expand All @@ -116,20 +147,50 @@
end

it "should do nothing if the service does not exist" do
Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.should_not_receive(:stop).with(@new_resource.service_name)
@provider.stop_service
@new_resource.updated_by_last_action?.should be_false
end

it "should do nothing if the service is stopped" do
Win32::Service.stub!(:status).with(@new_resource.service_name).and_return(
mock("StatusStruct", :current_state => "stopped"))
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "stopped"))
@provider.load_current_resource
Win32::Service.should_not_receive(:stop).with(@new_resource.service_name)
@provider.stop_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"))
@provider.load_current_resource
Win32::Service.should_not_receive(:start).with(@new_resource.service_name)
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"),
double("StatusStruct", :current_state => "stop pending"),
double("StatusStruct", :current_state => "stopped"))
@provider.load_current_resource
Win32::Service.should_not_receive(:stop).with(@new_resource.service_name)
@provider.stop_service
@new_resource.updated_by_last_action?.should be_false
end

it "should fail if the service is in start_pending" do
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "start pending"))
@provider.load_current_resource
Win32::Service.should_not_receive(:stop).with(@new_resource.service_name)
expect { @provider.stop_service }.to raise_error( Chef::Exceptions::Service )
@new_resource.updated_by_last_action?.should be_false
end

end

describe Chef::Provider::Service::Windows, "restart_service" do
Expand All @@ -142,29 +203,29 @@
end

it "should stop then start the service if it is running" do
Win32::Service.stub!(:status).with(@new_resource.service_name).and_return(
mock("StatusStruct", :current_state => "running"),
mock("StatusStruct", :current_state => "stopped"),
mock("StatusStruct", :current_state => "stopped"),
mock("StatusStruct", :current_state => "running"))
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "running"),
double("StatusStruct", :current_state => "stopped"),
double("StatusStruct", :current_state => "stopped"),
double("StatusStruct", :current_state => "running"))
Win32::Service.should_receive(:stop).with(@new_resource.service_name)
Win32::Service.should_receive(:start).with(@new_resource.service_name)
@provider.restart_service
@new_resource.updated_by_last_action?.should be_true
end

it "should just start the service if it is stopped" do
Win32::Service.stub!(:status).with(@new_resource.service_name).and_return(
mock("StatusStruct", :current_state => "stopped"),
mock("StatusStruct", :current_state => "stopped"),
mock("StatusStruct", :current_state => "running"))
Win32::Service.stub(:status).with(@new_resource.service_name).and_return(
double("StatusStruct", :current_state => "stopped"),
double("StatusStruct", :current_state => "stopped"),
double("StatusStruct", :current_state => "running"))
Win32::Service.should_receive(:start).with(@new_resource.service_name)
@provider.restart_service
@new_resource.updated_by_last_action?.should be_true
end

it "should do nothing if the service does not exist" do
Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.should_not_receive(:stop).with(@new_resource.service_name)
Win32::Service.should_not_receive(:start).with(@new_resource.service_name)
@provider.restart_service
Expand All @@ -176,8 +237,8 @@
describe Chef::Provider::Service::Windows, "enable_service" do

before(:each) do
Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return(
mock("ConfigStruct", :start_type => "disabled"))
Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return(
double("ConfigStruct", :start_type => "disabled"))
end

it "should enable service" do
Expand All @@ -187,15 +248,15 @@
end

it "should do nothing if the service does not exist" do
Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.should_not_receive(:configure)
@provider.enable_service
@new_resource.updated_by_last_action?.should be_false
end

it "should do nothing if the service is enabled" do
Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return(
mock("ConfigStruct", :start_type => "auto start"))
Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return(
double("ConfigStruct", :start_type => "auto start"))
Win32::Service.should_not_receive(:configure)
@provider.enable_service
@new_resource.updated_by_last_action?.should be_false
Expand All @@ -205,8 +266,8 @@
describe Chef::Provider::Service::Windows, "disable_service" do

before(:each) do
Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return(
mock("ConfigStruct", :start_type => "auto start"))
Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return(
double("ConfigStruct", :start_type => "auto start"))
end

it "should disable service" do
Expand All @@ -216,15 +277,15 @@
end

it "should do nothing if the service does not exist" do
Win32::Service.stub!(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false)
Win32::Service.should_not_receive(:configure)
@provider.disable_service
@new_resource.updated_by_last_action?.should be_false
end

it "should do nothing if the service is disabled" do
Win32::Service.stub!(:config_info).with(@new_resource.service_name).and_return(
mock("ConfigStruct", :start_type => "disabled"))
Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return(
double("ConfigStruct", :start_type => "disabled"))
@provider.load_current_resource
Win32::Service.should_not_receive(:configure)
@provider.disable_service
Expand Down