diff --git a/lib/puppet/provider/service/smf.rb b/lib/puppet/provider/service/smf.rb index 3efb2eb37..f6f221a7c 100755 --- a/lib/puppet/provider/service/smf.rb +++ b/lib/puppet/provider/service/smf.rb @@ -1,103 +1,103 @@ # Solaris 10 SMF-style services. Puppet::Type.type(:service).provide :smf, :parent => :base do desc "Support for Sun's new Service Management Framework. Starting a service is effectively equivalent to enabling it, so there is only support for starting and stopping services, which also enables and disables them, respectively. By specifying manifest => \"/path/to/service.xml\", the SMF manifest will be imported if it does not exist. " defaultfor :operatingsystem => :solaris confine :operatingsystem => :solaris commands :adm => "/usr/sbin/svcadm", :svcs => "/usr/bin/svcs" commands :svccfg => "/usr/sbin/svccfg" def setupservice if resource[:manifest] [command(:svcs), "-l", @resource[:name]] if $CHILD_STATUS.exitstatus == 1 Puppet.notice "Importing #{@resource[:manifest]} for #{@resource[:name]}" svccfg :import, resource[:manifest] end end rescue Puppet::ExecutionFailure => detail - raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" ) + raise Puppet::Error.new( "Cannot config #{self.name} to enable it: #{detail}" ) end def enable self.start end def enabled? case self.status when :running return :true else return :false end end def disable self.stop end def restartcmd [command(:adm), :restart, @resource[:name]] end def startcmd self.setupservice case self.status - when :stopped - [command(:adm), :enable, @resource[:name]] when :maintenance [command(:adm), :clear, @resource[:name]] + else + [command(:adm), :enable, @resource[:name]] end end def status if @resource[:status] super return end begin # get the current state and the next state, and if the next # state is set (i.e. not "-") use it for state comparison states = svcs("-H", "-o", "state,nstate", @resource[:name]).chomp.split state = states[1] == "-" ? states[0] : states[1] rescue Puppet::ExecutionFailure info "Could not get status on service #{self.name}" return :stopped end case state when "online" #self.warning "matched running #{line.inspect}" return :running when "offline", "disabled", "uninitialized" #self.warning "matched stopped #{line.inspect}" return :stopped when "maintenance" return :maintenance when "legacy_run" raise Puppet::Error, "Cannot manage legacy services through SMF" else raise Puppet::Error, "Unmanageable state '#{state}' on service #{self.name}" end end def stopcmd [command(:adm), :disable, @resource[:name]] end end diff --git a/spec/unit/provider/service/smf_spec.rb b/spec/unit/provider/service/smf_spec.rb new file mode 100755 index 000000000..40e96ab23 --- /dev/null +++ b/spec/unit/provider/service/smf_spec.rb @@ -0,0 +1,137 @@ +#!/usr/bin/env ruby +# +# Unit testing for the SMF service Provider +# +# author Dominic Cleal +# +require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper') + +provider_class = Puppet::Type.type(:service).provider(:smf) + +describe provider_class do + + before(:each) do + # Create a mock resource + @resource = Puppet::Type.type(:service).new( + :name => "/system/myservice", :ensure => :running, :enable => :true) + @provider = provider_class.new(@resource) + + FileTest.stubs(:file?).with('/usr/sbin/svcadm').returns true + FileTest.stubs(:executable?).with('/usr/sbin/svcadm').returns true + FileTest.stubs(:file?).with('/usr/bin/svcs').returns true + FileTest.stubs(:executable?).with('/usr/bin/svcs').returns true + end + + it "should have a restart method" do + @provider.should respond_to(:restart) + end + + it "should have a restartcmd method" do + @provider.should respond_to(:restartcmd) + end + + it "should have a start method" do + @provider.should respond_to(:start) + end + + it "should have a stop method" do + @provider.should respond_to(:stop) + end + + it "should have an enabled? method" do + @provider.should respond_to(:enabled?) + end + + it "should have an enable method" do + @provider.should respond_to(:enable) + end + + it "should have a disable method" do + @provider.should respond_to(:disable) + end + + describe "when checking status" do + it "should call the external command 'svcs /system/myservice' once" do + @provider.expects(:svcs).with('-H', '-o', 'state,nstate', "/system/myservice").returns("online\t-") + @provider.status + end + it "should return stopped if svcs can't find the service" do + @provider.stubs(:svcs).raises(Puppet::ExecutionFailure.new("no svc found")) + @provider.status.should == :stopped + end + it "should return running if online in svcs output" do + @provider.stubs(:svcs).returns("online\t-") + @provider.status.should == :running + end + it "should return stopped if disabled in svcs output" do + @provider.stubs(:svcs).returns("disabled\t-") + @provider.status.should == :stopped + end + it "should return maintenance if in maintenance in svcs output" do + @provider.stubs(:svcs).returns("maintenance\t-") + @provider.status.should == :maintenance + end + it "should return target state if transitioning in svcs output" do + @provider.stubs(:svcs).returns("online\tdisabled") + @provider.status.should == :stopped + end + it "should throw error if it's a legacy service in svcs output" do + @provider.stubs(:svcs).returns("legacy_run\t-") + lambda { @provider.status }.should raise_error(Puppet::Error, "Cannot manage legacy services through SMF") + end + end + + describe "when starting" do + it "should enable the service if it is not enabled" do + @provider.expects(:status).returns :stopped + @provider.expects(:texecute) + @provider.start + end + + it "should always execute external command 'svcadm enable /system/myservice'" do + @provider.stubs(:status).returns :running + @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :enable, "/system/myservice"], true) + @provider.start + end + + it "should execute external command 'svcadm clear /system/myservice' if in maintenance" do + @provider.stubs(:status).returns :maintenance + @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :clear, "/system/myservice"], true) + @provider.start + end + end + + describe "when starting a service with a manifest" do + before(:each) do + @resource = Puppet::Type.type(:service).new(:name => "/system/myservice", :ensure => :running, :enable => :true, :manifest => "/tmp/myservice.xml") + @provider = provider_class.new(@resource) + $CHILD_STATUS.stubs(:exitstatus).returns(1) + end + + it "should import the manifest if service is missing" do + @provider.expects(:svccfg).with(:import, "/tmp/myservice.xml") + @provider.expects(:texecute).with(:start, ["/usr/sbin/svcadm", :enable, "/system/myservice"], true) + @provider.start + end + + it "should handle failures if importing a manifest" do + @provider.expects(:svccfg).raises(Puppet::ExecutionFailure.new("can't svccfg import")) + lambda { @provider.start }.should raise_error(Puppet::Error, "Cannot config /system/myservice to enable it: can't svccfg import") + end + end + + describe "when stopping" do + it "should execute external command 'svcadm disable /system/myservice'" do + @provider.expects(:texecute).with(:stop, ["/usr/sbin/svcadm", :disable, "/system/myservice"], true) + @provider.stop + end + end + + describe "when restarting" do + it "should call 'svcadm restart /system/myservice'" do + @provider.expects(:texecute).with(:restart, ["/usr/sbin/svcadm", :restart, "/system/myservice"], true) + @provider.restart + end + end + +end