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/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb
index 2a54db24f..902cb18c6 100755
--- a/lib/puppet/provider/service/init.rb
+++ b/lib/puppet/provider/service/init.rb
@@ -1,136 +1,134 @@
# The standard init-based service type. Many other service types are
# customizations of this module.
Puppet::Type.type(:service).provide :init, :parent => :base do
desc "Standard `init`-style service management."
- class << self
- attr_accessor :defpath
- end
-
- case Facter["operatingsystem"].value
- when "FreeBSD"
- @defpath = ["/etc/rc.d", "/usr/local/etc/rc.d"]
- when "HP-UX"
- @defpath = "/sbin/init.d"
- when "Archlinux"
- @defpath = "/etc/rc.d"
- else
- @defpath = "/etc/init.d"
+ def self.defpath
+ case Facter.value(:operatingsystem)
+ when "FreeBSD"
+ ["/etc/rc.d", "/usr/local/etc/rc.d"]
+ when "HP-UX"
+ "/sbin/init.d"
+ when "Archlinux"
+ "/etc/rc.d"
+ else
+ "/etc/init.d"
+ end
end
# We can't confine this here, because the init path can be overridden.
- #confine :exists => @defpath
+ #confine :exists => defpath
# List all services of this type.
def self.instances
get_services(self.defpath)
end
def self.get_services(defpath, exclude=[])
defpath = [defpath] unless defpath.is_a? Array
instances = []
defpath.each do |path|
unless FileTest.directory?(path)
Puppet.debug "Service path #{path} does not exist"
next
end
check = [:ensure]
check << :enable if public_method_defined? :enabled?
Dir.entries(path).each do |name|
fullpath = File.join(path, name)
next if name =~ /^\./
next if exclude.include? name
next if not FileTest.executable?(fullpath)
instances << new(:name => name, :path => path, :hasstatus => true)
end
end
instances
end
# Mark that our init script supports 'status' commands.
def hasstatus=(value)
case value
when true, "true"; @parameters[:hasstatus] = true
when false, "false"; @parameters[:hasstatus] = false
else
raise Puppet::Error, "Invalid 'hasstatus' value #{value.inspect}"
end
end
# Where is our init script?
def initscript
@initscript ||= self.search(@resource[:name])
end
def paths
@paths ||= @resource[:path].find_all do |path|
if File.directory?(path)
true
else
if File.exist?(path) and ! File.directory?(path)
self.debug "Search path #{path} is not a directory"
else
self.debug "Search path #{path} does not exist"
end
false
end
end
end
def search(name)
paths.each { |path|
fqname = File.join(path,name)
begin
stat = File.stat(fqname)
rescue
# should probably rescue specific errors...
self.debug("Could not find #{name} in #{path}")
next
end
# if we've gotten this far, we found a valid script
return fqname
}
paths.each { |path|
fqname_sh = File.join(path,"#{name}.sh")
begin
stat = File.stat(fqname_sh)
rescue
# should probably rescue specific errors...
self.debug("Could not find #{name}.sh in #{path}")
next
end
# if we've gotten this far, we found a valid script
return fqname_sh
}
raise Puppet::Error, "Could not find init script for '#{name}'"
end
# The start command is just the init scriptwith 'start'.
def startcmd
[initscript, :start]
end
# The stop command is just the init script with 'stop'.
def stopcmd
[initscript, :stop]
end
def restartcmd
(@resource[:hasrestart] == :true) && [initscript, :restart]
end
# If it was specified that the init script has a 'status' command, then
# we just return that; otherwise, we return false, which causes it to
# fallback to other mechanisms.
def statuscmd
(@resource[:hasstatus] == :true) && [initscript, :status]
end
end
diff --git a/lib/puppet/provider/service/upstart.rb b/lib/puppet/provider/service/upstart.rb
index a767d7cc6..175a99e1f 100755
--- a/lib/puppet/provider/service/upstart.rb
+++ b/lib/puppet/provider/service/upstart.rb
@@ -1,331 +1,337 @@
require 'semver'
Puppet::Type.type(:service).provide :upstart, :parent => :debian do
START_ON = /^\s*start\s+on/
COMMENTED_START_ON = /^\s*#+\s*start\s+on/
MANUAL = /^\s*manual\s*$/
desc "Ubuntu service management with `upstart`.
This provider manages `upstart` jobs, which have replaced `initd` services
on Ubuntu. For `upstart` documentation, see .
"
# confine to :ubuntu for now because I haven't tested on other platforms
confine :operatingsystem => :ubuntu #[:ubuntu, :fedora, :debian]
defaultfor :operatingsystem => :ubuntu
commands :start => "/sbin/start",
:stop => "/sbin/stop",
:restart => "/sbin/restart",
:status_exec => "/sbin/status",
:initctl => "/sbin/initctl"
# upstart developer haven't implemented initctl enable/disable yet:
# http://www.linuxplanet.com/linuxplanet/tutorials/7033/2/
has_feature :enableable
def self.instances
instances = []
execpipe("#{command(:initctl)} list") { |process|
process.each_line { |line|
# needs special handling of services such as network-interface:
# initctl list:
# network-interface (lo) start/running
# network-interface (eth0) start/running
# network-interface-security start/running
name = \
if matcher = line.match(/^(network-interface)\s\(([^\)]+)\)/)
"#{matcher[1]} INTERFACE=#{matcher[2]}"
else
line.split.first
end
instances << new(:name => name)
}
}
instances
end
def self.defpath
["/etc/init", "/etc/init.d"]
end
def upstart_version
@@upstart_version ||= SemVer.new(initctl(" --version").match(/initctl \(upstart (\d\.\d[\.\d]?)\)/)[1])
end
# Where is our override script?
def overscript
@overscript ||= initscript.gsub(/\.conf$/,".override")
end
def search(name)
# Search prefers .conf as that is what upstart uses
[".conf", "", ".sh"].each do |suffix|
paths.each do |path|
fqname = File.join(path,name+suffix)
if File.exists?(fqname)
return fqname
end
self.debug("Could not find #{name}#{suffix} in #{path}")
end
end
raise Puppet::Error, "Could not find init script or upstart conf file for '#{name}'"
end
def enabled?
return super if not is_upstart?
- script_contents = File.open(initscript).read
+ script_contents = read_script_from(initscript)
if upstart_version < "0.6.7"
enabled_pre_0_6_7?(script_contents)
elsif upstart_version < "0.9.0"
enabled_pre_0_9_0?(script_contents)
elsif upstart_version >= "0.9.0"
enabled_post_0_9_0?(script_contents, read_override_file)
end
end
def enable
return super if not is_upstart?
- script_text = File.open(initscript).read
+ script_text = read_script_from(initscript)
if upstart_version < "0.9.0"
enable_pre_0_9_0(script_text)
else
enable_post_0_9_0(script_text, read_override_file)
end
end
def disable
return super if not is_upstart?
- script_text = File.open(initscript).read
+ script_text = read_script_from(initscript)
if upstart_version < "0.6.7"
disable_pre_0_6_7(script_text)
elsif upstart_version < "0.9.0"
disable_pre_0_9_0(script_text)
elsif upstart_version >= "0.9.0"
disable_post_0_9_0(read_override_file)
end
end
def startcmd
is_upstart? ? [command(:start), @resource[:name]] : super
end
def stopcmd
is_upstart? ? [command(:stop), @resource[:name]] : super
end
def restartcmd
is_upstart? ? (@resource[:hasrestart] == :true) && [command(:restart), @resource[:name]] : super
end
def statuscmd
is_upstart? ? nil : super #this is because upstart is broken with its return codes
end
def status
if @resource[:status]
is_upstart?(@resource[:status]) ? upstart_status(@resource[:status]) : normal_status
elsif is_upstart?
upstart_status
else
super
end
end
def normal_status
ucommand(:status, false)
($?.exitstatus == 0) ? :running : :stopped
end
def upstart_status(exec = @resource[:name])
output = status_exec(@resource[:name].split)
if (! $?.nil?) && (output =~ /start\//)
return :running
else
return :stopped
end
end
def is_upstart?(script = initscript)
return true if (File.symlink?(script) && File.readlink(script) == "/lib/init/upstart-job")
return true if (File.file?(script) && (not script.include?("init.d")))
return false
end
private
def enabled_pre_0_6_7?(script_text)
# Upstart version < 0.6.7 means no manual stanza.
if script_text.match(START_ON)
return :true
else
return :false
end
end
def enabled_pre_0_9_0?(script_text)
# Upstart version < 0.9.0 means no override files
# So we check to see if an uncommented start on or manual stanza is the last one in the file
# The last one in the file wins.
enabled = :false
script_text.each do |line|
if line.match(START_ON)
enabled = :true
elsif line.match(MANUAL)
enabled = :false
end
end
enabled
end
def enabled_post_0_9_0?(script_text, over_text)
# This version has manual stanzas and override files
# So we check to see if an uncommented start on or manual stanza is the last one in the
# conf file and any override files. The last one in the file wins.
enabled = :false
script_text.each do |line|
if line.match(START_ON)
enabled = :true
elsif line.match(MANUAL)
enabled = :false
end
end
over_text.each do |line|
if line.match(START_ON)
enabled = :true
elsif line.match(MANUAL)
enabled = :false
end
end if over_text
enabled
end
def enable_pre_0_9_0(text)
# We also need to remove any manual stanzas to ensure that it is enabled
text = remove_manual_from(text)
if enabled_pre_0_9_0?(text) == :false
enabled_script =
if text.match(COMMENTED_START_ON)
uncomment_start_block_in(text)
else
add_default_start_to(text)
end
else
enabled_script = text
end
write_script_to(initscript, enabled_script)
end
def enable_post_0_9_0(script_text, over_text)
over_text = remove_manual_from(over_text)
if enabled_post_0_9_0?(script_text, over_text) == :false
if script_text.match(START_ON)
over_text << extract_start_on_block_from(script_text)
else
over_text << "\nstart on runlevel [2,3,4,5]"
end
end
write_script_to(overscript, over_text)
end
def disable_pre_0_6_7(script_text)
disabled_script = comment_start_block_in(script_text)
write_script_to(initscript, disabled_script)
end
def disable_pre_0_9_0(script_text)
write_script_to(initscript, ensure_disabled_with_manual(script_text))
end
def disable_post_0_9_0(over_text)
write_script_to(overscript, ensure_disabled_with_manual(over_text))
end
def read_override_file
if File.exists?(overscript)
- File.open(overscript).read
+ read_script_from(overscript)
else
""
end
end
def uncomment(line)
line.gsub(/^(\s*)#+/, '\1')
end
def remove_trailing_comments_from_commented_line_of(line)
line.gsub(/^(\s*#+\s*[^#]*).*/, '\1')
end
def remove_trailing_comments_from(line)
line.gsub(/^(\s*[^#]*).*/, '\1')
end
def unbalanced_parens_on(line)
line.count('(') - line.count(')')
end
def remove_manual_from(text)
text.gsub(MANUAL, "")
end
def comment_start_block_in(text)
parens = 0
text.map do |line|
if line.match(START_ON) || parens > 0
# If there are more opening parens than closing parens, we need to comment out a multiline 'start on' stanza
parens += unbalanced_parens_on(remove_trailing_comments_from(line))
"#" + line
else
line
end
end.join('')
end
def uncomment_start_block_in(text)
parens = 0
text.map do |line|
if line.match(COMMENTED_START_ON) || parens > 0
parens += unbalanced_parens_on(remove_trailing_comments_from_commented_line_of(line))
uncomment(line)
else
line
end
end.join('')
end
def extract_start_on_block_from(text)
parens = 0
text.map do |line|
if line.match(START_ON) || parens > 0
parens += unbalanced_parens_on(remove_trailing_comments_from(line))
line
end
end.join('')
end
def add_default_start_to(text)
text + "\nstart on runlevel [2,3,4,5]"
end
def ensure_disabled_with_manual(text)
remove_manual_from(text) + "\nmanual"
end
+ def read_script_from(filename)
+ File.open(filename) do |file|
+ file.read
+ end
+ end
+
def write_script_to(file, text)
Puppet::Util.replace_file(file, 0644) do |file|
file.write(text)
end
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/integration/provider/service/init_spec.rb b/spec/integration/provider/service/init_spec.rb
index 483507d5f..877c01171 100755
--- a/spec/integration/provider/service/init_spec.rb
+++ b/spec/integration/provider/service/init_spec.rb
@@ -1,30 +1,46 @@
#!/usr/bin/env rspec
require 'spec_helper'
provider = Puppet::Type.type(:service).provider(:init)
describe provider, :'fails_on_ruby_1.9.2' => true do
- describe "when running on FreeBSD", :if => (Facter.value(:operatingsystem) == "FreeBSD") do
+ describe "when running on FreeBSD" do
+ before :each do
+ Facter.stubs(:value).with(:operatingsystem).returns 'FreeBSD'
+ end
+
it "should set its default path to include /etc/rc.d and /usr/local/etc/rc.d" do
provider.defpath.should == ["/etc/rc.d", "/usr/local/etc/rc.d"]
end
end
- describe "when running on HP-UX", :if => (Facter.value(:operatingsystem) == "HP-UX") do
+ describe "when running on HP-UX" do
+ before :each do
+ Facter.stubs(:value).with(:operatingsystem).returns 'HP-UX'
+ end
+
it "should set its default path to include /sbin/init.d" do
provider.defpath.should == "/sbin/init.d"
end
end
- describe "when running on Archlinux", :if => (Facter.value(:operatingsystem) == "Archlinux") do
+ describe "when running on Archlinux" do
+ before :each do
+ Facter.stubs(:value).with(:operatingsystem).returns 'Archlinux'
+ end
+
it "should set its default path to include /etc/rc.d" do
provider.defpath.should == "/etc/rc.d"
end
end
- describe "when not running on FreeBSD, HP-UX or Archlinux", :if => (! %w{HP-UX FreeBSD Archlinux}.include?(Facter.value(:operatingsystem))) do
+ describe "when not running on FreeBSD, HP-UX or Archlinux" do
+ before :each do
+ Facter.stubs(:value).with(:operatingsystem).returns 'RedHat'
+ end
+
it "should set its default path to include /etc/init.d" do
provider.defpath.should == "/etc/init.d"
end
end
end
diff --git a/spec/unit/provider/service/gentoo_spec.rb b/spec/unit/provider/service/gentoo_spec.rb
new file mode 100755
index 000000000..a9a58d5c1
--- /dev/null
+++ b/spec/unit/provider/service/gentoo_spec.rb
@@ -0,0 +1,237 @@
+#!/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
+ Facter.stubs(:value).with(:operatingsystem).returns 'Gentoo'
+
+ # The initprovider (parent of the gentoo provider) does a stat call
+ # before it even tries to execute an initscript. We use sshd in all the
+ # tests so make sure it is considered present.
+ File.stubs(:stat).with('/etc/init.d/sshd')
+ 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
+ FileTest.expects(:directory?).with('/etc/init.d').returns true
+ 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.expects(:search).with('sshd').returns('/etc/init.d/sshd')
+ 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.expects(:search).with('sshd').returns('/etc/init.d/sshd')
+ 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(:search).with('sshd').returns('/etc/init.d/sshd')
+ 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(:search).with('sshd').returns('/etc/init.d/sshd')
+ 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(:search).with('sshd').returns('/etc/init.d/sshd')
+ 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(:search).with('sshd').returns('/etc/init.d/sshd')
+ 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
diff --git a/spec/unit/provider/service/init_spec.rb b/spec/unit/provider/service/init_spec.rb
index 8374594e7..173fb8515 100755
--- a/spec/unit/provider/service/init_spec.rb
+++ b/spec/unit/provider/service/init_spec.rb
@@ -1,170 +1,170 @@
#!/usr/bin/env rspec
#
# Unit testing for the Init service Provider
#
require 'spec_helper'
provider_class = Puppet::Type.type(:service).provider(:init)
describe provider_class do
before :each do
@class = Puppet::Type.type(:service).provider(:init)
@resource = stub 'resource'
@resource.stubs(:[]).returns(nil)
@resource.stubs(:[]).with(:name).returns "myservice"
# @resource.stubs(:[]).with(:ensure).returns :enabled
@resource.stubs(:[]).with(:path).returns ["/service/path","/alt/service/path"]
# @resource.stubs(:ref).returns "Service[myservice]"
File.stubs(:directory?).returns(true)
@provider = provider_class.new
@provider.resource = @resource
end
describe "when getting all service instances" do
before :each do
@services = ['one', 'two', 'three', 'four']
Dir.stubs(:entries).returns @services
FileTest.stubs(:directory?).returns(true)
FileTest.stubs(:executable?).returns(true)
@class.stubs(:defpath).returns('tmp')
end
it "should return instances for all services" do
@services.each do |inst|
@class.expects(:new).with{|hash| hash[:name] == inst}.returns("#{inst}_instance")
end
results = @services.collect {|x| "#{x}_instance"}
@class.instances.should == results
end
it "should omit an array of services from exclude list" do
exclude = ['two', 'four']
(@services-exclude).each do |inst|
@class.expects(:new).with{|hash| hash[:name] == inst}.returns("#{inst}_instance")
end
results = (@services-exclude).collect {|x| "#{x}_instance"}
@class.get_services(@class.defpath, exclude).should == results
end
- it "should omit a single service from the exclude list", :'fails_on_ruby_1.9.2' => true do
+ it "should omit a single service from the exclude list" do
exclude = 'two'
- (@services-exclude.to_a).each do |inst|
+ (@services-[exclude]).each do |inst|
@class.expects(:new).with{|hash| hash[:name] == inst}.returns("#{inst}_instance")
end
results = @services.reject{|x| x==exclude }.collect {|x| "#{x}_instance"}
@class.get_services(@class.defpath, exclude).should == results
end
it "should use defpath" do
@services.each do |inst|
@class.expects(:new).with{|hash| hash[:path] == @class.defpath}.returns("#{inst}_instance")
end
results = @services.sort.collect {|x| "#{x}_instance"}
@class.instances.sort.should == results
end
it "should set hasstatus to true for providers" do
@services.each do |inst|
@class.expects(:new).with{|hash| hash[:name] == inst && hash[:hasstatus] == true}.returns("#{inst}_instance")
end
results = @services.collect {|x| "#{x}_instance"}
@class.instances.should == results
end
end
describe "when searching for the init script" do
it "should discard paths that do not exist" do
File.stubs(:exist?).returns(false)
File.stubs(:directory?).returns(false)
@provider.paths.should be_empty
end
it "should discard paths that are not directories" do
File.stubs(:exist?).returns(true)
File.stubs(:directory?).returns(false)
@provider.paths.should be_empty
end
it "should be able to find the init script in the service path" do
File.stubs(:stat).raises(Errno::ENOENT.new('No such file or directory'))
File.expects(:stat).with("/service/path/myservice").returns true
@provider.initscript.should == "/service/path/myservice"
end
it "should be able to find the init script in the service path" do
File.stubs(:stat).raises(Errno::ENOENT.new('No such file or directory'))
File.expects(:stat).with("/alt/service/path/myservice").returns true
@provider.initscript.should == "/alt/service/path/myservice"
end
it "should fail if the service isn't there" do
lambda { @provider.initscript }.should raise_error(Puppet::Error, "Could not find init script for 'myservice'")
end
end
describe "if the init script is present" do
before :each do
File.stubs(:stat).with("/service/path/myservice").returns true
end
[:start, :stop, :status, :restart].each do |method|
it "should have a #{method} method" do
@provider.should respond_to(method)
end
describe "when running #{method}" do
it "should use any provided explicit command" do
@resource.stubs(:[]).with(method).returns "/user/specified/command"
@provider.expects(:execute).with { |command, *args| command == ["/user/specified/command"] }
@provider.send(method)
end
it "should pass #{method} to the init script when no explicit command is provided" do
@resource.stubs(:[]).with("has#{method}".intern).returns :true
@provider.expects(:execute).with { |command, *args| command == ["/service/path/myservice",method]}
@provider.send(method)
end
end
end
describe "when checking status" do
describe "when hasstatus is :true" do
before :each do
@resource.stubs(:[]).with(:hasstatus).returns :true
end
it "should execute the command" do
@provider.expects(:texecute).with(:status, ['/service/path/myservice', :status], false).returns("")
@provider.status
end
it "should consider the process running if the command returns 0" do
@provider.expects(:texecute).with(:status, ['/service/path/myservice', :status], false).returns("")
$CHILD_STATUS.stubs(:exitstatus).returns(0)
@provider.status.should == :running
end
[-10,-1,1,10].each { |ec|
it "should consider the process stopped if the command returns something non-0" do
@provider.expects(:texecute).with(:status, ['/service/path/myservice', :status], false).returns("")
$CHILD_STATUS.stubs(:exitstatus).returns(ec)
@provider.status.should == :stopped
end
}
end
describe "when hasstatus is not :true" do
it "should consider the service :running if it has a pid" do
@provider.expects(:getpid).returns "1234"
@provider.status.should == :running
end
it "should consider the service :stopped if it doesn't have a pid" do
@provider.expects(:getpid).returns nil
@provider.status.should == :stopped
end
end
end
describe "when restarting and hasrestart is not :true" do
it "should stop and restart the process" do
@provider.expects(:texecute).with(:stop, ['/service/path/myservice', :stop ], true).returns("")
@provider.expects(:texecute).with(:start,['/service/path/myservice', :start], true).returns("")
$CHILD_STATUS.stubs(:exitstatus).returns(0)
@provider.restart
end
end
end
end