diff --git a/lib/puppet/provider/service/gentoo.rb b/lib/puppet/provider/service/gentoo.rb index 8928d4459..4beb9ea6c 100644 --- a/lib/puppet/provider/service/gentoo.rb +++ b/lib/puppet/provider/service/gentoo.rb @@ -1,51 +1,56 @@ # Manage gentoo services. Start/stop is the same as InitSvc, but enable/disable # is special. Puppet::Type.type(:service).provide :gentoo, :parent => :init do desc <<-EOT Gentoo's form of `init`-style service management. Uses `rc-update` for service enabling and disabling. EOT commands :update => "/sbin/rc-update" confine :operatingsystem => :gentoo defaultfor :operatingsystem => :gentoo def self.defpath superclass.defpath end + def self.instances + # this exclude list was found with grep -L '\/sbin\/runscript' /etc/init.d/* + self.get_services(self.defpath, ['functions.sh', 'reboot.sh', 'shutdown.sh']) + end + def disable output = update :del, @resource[:name], :default rescue Puppet::ExecutionFailure raise Puppet::Error, "Could not disable #{self.name}: #{output}" end def enabled? begin output = update :show rescue Puppet::ExecutionFailure return :false end line = output.split(/\n/).find { |l| l.include?(@resource[:name]) } return :false unless line # If it's enabled then it will print output showing service | runlevel if output =~ /^\s*#{@resource[:name]}\s*\|\s*(boot|default)/ return :true else return :false end end def enable output = update :add, @resource[:name], :default rescue Puppet::ExecutionFailure raise Puppet::Error, "Could not enable #{self.name}: #{output}" end end diff --git a/spec/fixtures/unit/provider/service/gentoo/rc_update_show b/spec/fixtures/unit/provider/service/gentoo/rc_update_show new file mode 100644 index 000000000..6dcca3518 --- /dev/null +++ b/spec/fixtures/unit/provider/service/gentoo/rc_update_show @@ -0,0 +1,30 @@ + alsasound | default + bootmisc | boot + devfs | sysinit + dmcrypt | boot + dmesg | sysinit + fsck | boot + hostname | boot + hwclock | boot + keymaps | boot + killprocs | shutdown + local | default + localmount | boot + lvm | boot + modules | boot + mount-ro | shutdown + mtab | boot + net.lo | boot + netmount | default + procfs | boot + root | boot + rsyslog | boot + savecache | shutdown + swap | boot + swapfiles | boot + sysctl | boot + termencoding | boot + udev | sysinit + udev-postmount | default + urandom | boot + xdm | default diff --git a/spec/unit/provider/service/gentoo_spec.rb b/spec/unit/provider/service/gentoo_spec.rb new file mode 100755 index 000000000..d5a50b4d0 --- /dev/null +++ b/spec/unit/provider/service/gentoo_spec.rb @@ -0,0 +1,224 @@ +#!/usr/bin/env rspec + +require 'spec_helper' + +describe Puppet::Type.type(:service).provider(:gentoo) do + + before :each do + Puppet::Type.type(:service).stubs(:defaultprovider).returns described_class + FileTest.stubs(:file?).with('/sbin/rc-update').returns true + FileTest.stubs(:executable?).with('/sbin/rc-update').returns true + end + + let :initscripts do + [ + 'alsasound', + 'bootmisc', + 'functions.sh', + 'hwclock', + 'reboot.sh', + 'rsyncd', + 'shutdown.sh', + 'sshd', + 'vixie-cron', + 'wpa_supplicant', + 'xdm-setup' + ] + end + + let :helperscripts do + [ + 'functions.sh', + 'reboot.sh', + 'shutdown.sh' + ] + end + + describe ".instances" do + + it "should have an instances method" do + described_class.should respond_to :instances + end + + it "should get a list of services from /etc/init.d but exclude helper scripts" do + Dir.expects(:entries).with('/etc/init.d').returns initscripts + (initscripts - helperscripts).each do |script| + FileTest.expects(:executable?).with("/etc/init.d/#{script}").returns true + end + helperscripts.each do |script| + FileTest.expects(:executable?).with("/etc/init.d/#{script}").never + end + described_class.instances.map(&:name).should == [ + 'alsasound', + 'bootmisc', + 'hwclock', + 'rsyncd', + 'sshd', + 'vixie-cron', + 'wpa_supplicant', + 'xdm-setup' + ] + end + end + + describe "#start" do + it "should use the supplied start command if specified" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :start => '/bin/foo')) + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.start + end + it "should start the service with start otherwise" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:execute).with(['/etc/init.d/sshd',:start], :failonfail => true, :squelch => true) + provider.start + end + end + + describe "#stop" do + it "should use the supplied stop command if specified" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :stop => '/bin/foo')) + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.stop + end + it "should stop the service with stop otherwise" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:execute).with(['/etc/init.d/sshd',:stop], :failonfail => true, :squelch => true) + provider.stop + end + end + + describe "#enabled?" do + + before :each do + described_class.any_instance.stubs(:update).with(:show).returns File.read(my_fixture('rc_update_show')) + end + + it "should run rc-update show to get a list of enabled services" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:update).with(:show).returns "\n" + provider.enabled? + end + + ['hostname', 'net.lo', 'procfs'].each do |service| + it "should consider service #{service} in runlevel boot as enabled" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => service)) + provider.enabled?.should == :true + end + end + + ['alsasound', 'xdm', 'netmount'].each do |service| + it "should consider service #{service} in runlevel default as enabled" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => service)) + provider.enabled?.should == :true + end + end + + ['rsyncd', 'lighttpd', 'mysql'].each do |service| + it "should consider unused service #{service} as disabled" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => service)) + provider.enabled?.should == :false + end + end + + end + + describe "#enable" do + it "should run rc-update add to enable a service" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:update).with(:add, 'sshd', :default) + provider.enable + end + end + + describe "#disable" do + it "should run rc-update del to disable a service" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) + provider.expects(:update).with(:del, 'sshd', :default) + provider.disable + end + end + + describe "#status" do + + describe "when a special status command is specified" do + it "should use the status command from the resource" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + provider.status + end + + it "should return :stopped when the status command returns with a non-zero exitcode" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + $CHILD_STATUS.stubs(:exitstatus).returns 3 + provider.status.should == :stopped + end + + it "should return :running when the status command returns with a zero exitcode" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + $CHILD_STATUS.stubs(:exitstatus).returns 0 + provider.status.should == :running + end + end + + describe "when hasstatus is false" do + it "should return running if a pid can be found" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => false)) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:getpid).returns 1000 + provider.status.should == :running + end + + it "should return stopped if no pid can be found" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => false)) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:getpid).returns nil + provider.status.should == :stopped + end + end + + describe "when hasstatus is true" do + it "should return running if status exits with a zero exitcode" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => true)) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true) + $CHILD_STATUS.stubs(:exitstatus).returns 0 + provider.status.should == :running + end + + it "should return stopped if status exits with a non-zero exitcode" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => true)) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true) + $CHILD_STATUS.stubs(:exitstatus).returns 3 + provider.status.should == :stopped + end + end + end + + describe "#restart" do + it "should use the supplied restart command if specified" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :restart => '/bin/foo')) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.restart + end + + it "should restart the service with restart if hasrestart is true" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasrestart => true)) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true) + provider.restart + end + + it "should restart the service with stop/start if hasrestart is false" do + provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasrestart => false)) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true).never + provider.expects(:execute).with(['/etc/init.d/sshd',:stop], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:start], :failonfail => true, :squelch => true) + provider.restart + end + end + +end