summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG10
-rwxr-xr-xlib/puppet/provider/service/init.rb8
-rwxr-xr-xlib/puppet/provider/service/redhat.rb4
-rw-r--r--lib/puppet/type/service.rb176
-rwxr-xr-xspec/unit/ral/types/package.rb2
-rwxr-xr-xspec/unit/ral/types/service.rb249
-rwxr-xr-xtest/ral/providers/service.rb234
7 files changed, 282 insertions, 401 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 590b4d111..430e0c38e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,13 @@
+ Slightly modifying how services manage their list of paths
+ (and adding documention for it). Services now default
+ to the paths specified by the provider classes.
+
+ Removed 'type' as a valid attribute for services, since it's been
+ deprecated since the creation of providers.
+
+ Removed 'running' as a valid attribute for services, since it's
+ been deprecated since February 2006.
+
Added modified patch by Matt Palmer which adds a 'plugins' mount,
fixing #891. See PluginsInModules on the wiki for information on
usage.
diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb
index c3328f517..3b568d5a1 100755
--- a/lib/puppet/provider/service/init.rb
+++ b/lib/puppet/provider/service/init.rb
@@ -20,14 +20,6 @@ Puppet::Type.type(:service).provide :init, :parent => :base do
# We can't confine this here, because the init path can be overridden.
#confine :exists => @defpath
- if self.suitable?
- # Add it to the search paths
- Puppet.type(:service).newpath(:init, defpath())
-
- # Set the default init directory.
- Puppet.type(:service).attrclass(:path).defaultto defpath()
- end
-
# List all services of this type.
def self.instances(name)
# We need to find all paths specified for our type or any parent types
diff --git a/lib/puppet/provider/service/redhat.rb b/lib/puppet/provider/service/redhat.rb
index 41a060ee4..b013c34dc 100755
--- a/lib/puppet/provider/service/redhat.rb
+++ b/lib/puppet/provider/service/redhat.rb
@@ -12,10 +12,6 @@ Puppet::Type.type(:service).provide :redhat, :parent => :init do
superclass.defpath
end
- if self.suitable?
- Puppet.type(:service).newpath(:redhat, defpath())
- end
-
# Remove the symlinks
def disable
begin
diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb
index 24237de35..473c91776 100644
--- a/lib/puppet/type/service.rb
+++ b/lib/puppet/type/service.rb
@@ -28,79 +28,23 @@ module Puppet
feature :enableable, "The provider can enable and disable the service",
:methods => [:disable, :enable, :enabled?]
- attr_reader :stat
-
- newproperty(:enable) do
- attr_reader :runlevel
+ newproperty(:enable, :required_features => :enableable) do
desc "Whether a service should be enabled to start at boot.
This property behaves quite differently depending on the platform;
wherever possible, it relies on local tools to enable or disable
a given service."
newvalue(:true, :event => :service_enabled) do
- unless provider.respond_to?(:enable)
- raise Puppet::Error, "Service %s does not support enabling" %
- @resource.name
- end
provider.enable
end
newvalue(:false, :event => :service_disabled) do
- unless provider.respond_to?(:disable)
- raise Puppet::Error, "Service %s does not support enabling" %
- @resource.name
- end
provider.disable
end
def retrieve
- unless provider.respond_to?(:enabled?)
- raise Puppet::Error, "Service %s does not support enabling" %
- @resource.name
- end
return provider.enabled?
end
-
- validate do |value|
- unless value =~ /^\d+/
- super(value)
- end
- end
-
- munge do |should|
- @runlevel = nil
- if should =~ /^\d+$/
- arity = @resource.method(:enable)
- if @runlevel and arity != 1
- raise Puppet::Error,
- "Services on %s do not accept runlevel specs" %
- @resource.type
- elsif arity != 0
- raise Puppet::Error,
- "Services on %s must specify runlevels" %
- @resource.type
- end
- @runlevel = should
- return :true
- else
- super(should)
- end
- end
-
- def sync
- case self.should
- when :true
- if @runlevel
- provider.enable(@runlevel)
- else
- provider.enable()
- end
- return :service_enabled
- when :false
- provider.disable
- return :service_disabled
- end
- end
end
# Handle whether the service should actually be running right now.
@@ -124,42 +68,16 @@ module Puppet
def sync
event = super()
-# case self.should
-# when :running
-# provider.start
-# event = :service_started
-# when :stopped
-# provider.stop
-# event = :service_stopped
-# else
-# self.debug "Not running '%s' and shouldn't be running" %
-# self
-# end
if property = @resource.property(:enable)
val = property.retrieve
- unless property.insync?(val)
- property.sync
- end
+ property.sync unless property.insync?(val)
end
return event
end
end
- # Produce a warning, rather than just failing.
- newparam(:running) do
- desc "A place-holder parameter that wraps ``ensure``, because
- ``running`` is deprecated. You should use ``ensure`` instead
- of this, but using this will still work, albeit with a
- warning."
-
- munge do |value|
- @resource.warning "'running' is deprecated; please use 'ensure'"
- @resource[:ensure] = value
- end
- end
-
newparam(:binary) do
desc "The path to the daemon. This is only used for
systems that do not support init scripts. This binary will be
@@ -178,53 +96,38 @@ module Puppet
If you do not specify anything, then the service name will be
looked for in the process table."
+
+ newvalues(:true, :false)
end
newparam(:name) do
- desc "The name of the service to run. This name
- is used to find the service in whatever service subsystem it
- is in."
+ desc "The name of the service to run. This name is used to find
+ the service in whatever service subsystem it is in."
isnamevar
end
- newparam(:type) do
- desc "Deprecated form of ``provider``."
-
- munge do |value|
- warning "'type' is deprecated; use 'provider' instead"
- @resource[:provider] = value
- end
- end
-
newparam(:path) do
- desc "The search path for finding init scripts."
+ desc "The search path for finding init scripts. Multiple values should
+ be separated by colons or provided as an array."
munge do |value|
- paths = []
- if value.is_a?(Array)
- paths += value.flatten.collect { |p|
- p.split(":")
- }.flatten
- else
- paths = value.split(":")
- end
-
- paths.each do |path|
+ value = [value] unless value.is_a?(Array)
+ paths = value.flatten.collect { |p| p.split(":") }.flatten.find_all do |path|
if FileTest.directory?(path)
- next
- end
- if FileTest.exists?(path)
- unless FileTest.directory?(path)
- @resource.debug "Search path %s is not a directory" %
- [path]
- end
+ true
else
- @resource.debug("Search path %s does not exist" % [path])
+ if FileTest.exist?(path) and ! FileTest.directory?(path)
+ @resource.debug "Search path %s is not a directory" % [path]
+ else
+ @resource.debug("Search path %s does not exist" % [path])
+ end
+ false
end
- paths.delete(path)
end
paths
end
+
+ defaultto { provider.class.defpath if provider.class.respond_to?(:defpath) }
end
newparam(:pattern) do
desc "The pattern to search for in the process table.
@@ -238,9 +141,7 @@ module Puppet
The pattern can be a simple string or any legal Ruby pattern."
- defaultto {
- @resource[:binary] || @resource[:name]
- }
+ defaultto { @resource[:binary] || @resource[:name] }
end
newparam(:restart) do
desc "Specify a *restart* command manually. If left
@@ -268,45 +169,14 @@ module Puppet
newvalues(:true, :false)
end
- # Add a new path to our list of paths that services could be in.
- def self.newpath(type, path)
- type = type.intern if type.is_a? String
- @paths ||= {}
- @paths[type] ||= []
-
- unless @paths[type].include? path
- @paths[type] << path
- end
- end
-
- def self.paths(type)
- type = type.intern if type.is_a? String
- @paths ||= {}
- @paths[type] ||= []
-
- @paths[type].dup
- end
-
- # Initialize the service. This is basically responsible for merging
- # in the right module.
- def initialize(hash)
- super
-
- # and then see if it needs to be checked
- if self.respond_to?(:configchk)
- self.configchk
- end
- end
-
# Basically just a synonym for restarting. Used to respond
# to events.
def refresh
- # Only restart if we're supposed to be running
-
- if ens = @parameters[:ensure] and ens.should == :running and ens.retrieve == :running
+ # Only restart if we're actually running
+ if (@parameters[:ensure] || newattr(:ensure)).retrieve == :running
provider.restart
else
- debug "Skipping restart; 'ensure' is not set to 'running'"
+ debug "Skipping restart; service is not running"
end
end
end
diff --git a/spec/unit/ral/types/package.rb b/spec/unit/ral/types/package.rb
index f7d93da6e..fd200c56f 100755
--- a/spec/unit/ral/types/package.rb
+++ b/spec/unit/ral/types/package.rb
@@ -4,8 +4,6 @@ require File.dirname(__FILE__) + '/../../../spec_helper'
require 'puppet/type/package'
-$platform = Facter["operatingsystem"].value
-
describe Puppet::Type::Package do
it "should have an :installable feature that requires the :install method" do
Puppet::Type::Package.provider_feature(:installable).methods.should == [:install]
diff --git a/spec/unit/ral/types/service.rb b/spec/unit/ral/types/service.rb
new file mode 100755
index 000000000..ee3d747a8
--- /dev/null
+++ b/spec/unit/ral/types/service.rb
@@ -0,0 +1,249 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+require 'puppet/type/service'
+
+describe Puppet::Type::Service do
+ it "should have an :enableable feature that requires the :enable, :disable, and :enabled? methods" do
+ Puppet::Type::Service.provider_feature(:enableable).methods.should == [:disable, :enable, :enabled?]
+ end
+
+ it "should have a :refreshable feature that requires the :restart method" do
+ Puppet::Type::Service.provider_feature(:refreshable).methods.should == [:restart]
+ end
+end
+
+describe Puppet::Type::Service, "when validating attributes" do
+ [:name, :binary, :hasstatus, :path, :pattern, :start, :restart, :stop, :status, :hasrestart].each do |param|
+ it "should have a #{param} parameter" do
+ Puppet::Type::Service.attrtype(param).should == :param
+ end
+ end
+
+ [:ensure, :enable].each do |param|
+ it "should have an #{param} property" do
+ Puppet::Type::Service.attrtype(param).should == :property
+ end
+ end
+end
+
+describe Puppet::Type::Service, "when validating attribute values" do
+ before do
+ @provider = stub 'provider', :class => Puppet::Type::Service.defaultprovider, :clear => nil
+ Puppet::Type::Service.defaultprovider.stubs(:new).returns(@provider)
+ end
+
+ it "should support :running as a value to :ensure" do
+ Puppet::Type::Service.create(:name => "yay", :ensure => :running)
+ end
+
+ it "should support :stopped as a value to :ensure" do
+ Puppet::Type::Service.create(:name => "yay", :ensure => :stopped)
+ end
+
+ it "should alias the value :true to :running in :ensure" do
+ svc = Puppet::Type::Service.create(:name => "yay", :ensure => true)
+ svc.should(:ensure).should == :running
+ end
+
+ it "should alias the value :false to :stopped in :ensure" do
+ svc = Puppet::Type::Service.create(:name => "yay", :ensure => false)
+ svc.should(:ensure).should == :stopped
+ end
+
+ it "should support :true as a value to :enable" do
+ Puppet::Type::Service.create(:name => "yay", :enable => :true)
+ end
+
+ it "should support :false as a value to :enable" do
+ Puppet::Type::Service.create(:name => "yay", :enable => :false)
+ end
+
+ it "should support :true as a value to :hasstatus" do
+ Puppet::Type::Service.create(:name => "yay", :hasstatus => :true)
+ end
+
+ it "should support :false as a value to :hasstatus" do
+ Puppet::Type::Service.create(:name => "yay", :hasstatus => :false)
+ end
+
+ it "should support :true as a value to :hasrestart" do
+ Puppet::Type::Service.create(:name => "yay", :hasrestart => :true)
+ end
+
+ it "should support :false as a value to :hasrestart" do
+ Puppet::Type::Service.create(:name => "yay", :hasrestart => :false)
+ end
+
+ it "should allow setting the :enable parameter if the provider has the :enableable feature" do
+ Puppet::Type::Service.defaultprovider.stubs(:supports_parameter?).returns(true)
+ Puppet::Type::Service.defaultprovider.expects(:supports_parameter?).with(Puppet::Type::Service.attrclass(:enable)).returns(true)
+ svc = Puppet::Type::Service.create(:name => "yay", :enable => true)
+ svc.should(:enable).should == :true
+ end
+
+ it "should not allow setting the :enable parameter if the provider is missing the :enableable feature" do
+ Puppet::Type::Service.defaultprovider.stubs(:supports_parameter?).returns(true)
+ Puppet::Type::Service.defaultprovider.expects(:supports_parameter?).with(Puppet::Type::Service.attrclass(:enable)).returns(false)
+ svc = Puppet::Type::Service.create(:name => "yay", :enable => true)
+ svc.should(:enable).should be_nil
+ end
+
+ it "should discard paths that do not exist" do
+ FileTest.stubs(:exist?).returns(false)
+ FileTest.stubs(:directory?).returns(false)
+ svc = Puppet::Type::Service.create(:name => "yay", :path => "/one/two")
+ svc[:path].should be_empty
+ end
+
+ it "should discard paths that are not directories" do
+ FileTest.stubs(:exist?).returns(true)
+ FileTest.stubs(:directory?).returns(false)
+ svc = Puppet::Type::Service.create(:name => "yay", :path => "/one/two")
+ svc[:path].should be_empty
+ end
+
+ it "should split paths on ':'" do
+ FileTest.stubs(:exist?).returns(true)
+ FileTest.stubs(:directory?).returns(true)
+ svc = Puppet::Type::Service.create(:name => "yay", :path => "/one/two:/three/four")
+ svc[:path].should == %w{/one/two /three/four}
+ end
+
+ it "should accept arrays of paths joined by ':'" do
+ FileTest.stubs(:exist?).returns(true)
+ FileTest.stubs(:directory?).returns(true)
+ svc = Puppet::Type::Service.create(:name => "yay", :path => ["/one:/two", "/three:/four"])
+ svc[:path].should == %w{/one /two /three /four}
+ end
+
+ after { Puppet::Type::Service.clear }
+end
+
+describe Puppet::Type::Service, "when setting default attribute values" do
+ it "should default to the provider's default path if one is available" do
+ FileTest.stubs(:directory?).returns(true)
+ FileTest.stubs(:exist?).returns(true)
+
+ Puppet::Type::Service.defaultprovider.stubs(:respond_to?).returns(true)
+ Puppet::Type::Service.defaultprovider.stubs(:defpath).returns("testing")
+ svc = Puppet::Type::Service.create(:name => "other")
+ svc[:path].should == ["testing"]
+ end
+
+ it "should default to the binary for the pattern if one is provided" do
+ svc = Puppet::Type::Service.create(:name => "other", :binary => "/some/binary")
+ svc[:pattern].should == "/some/binary"
+ end
+
+ it "should default to the name for the pattern if no pattern is provided" do
+ svc = Puppet::Type::Service.create(:name => "other")
+ svc[:pattern].should == "other"
+ end
+
+ after { Puppet::Type::Service.clear }
+end
+
+describe Puppet::Type::Service, "when retrieving the host's current state" do
+ before do
+ @service = Puppet::Type::Service.create(:name => "yay")
+ end
+
+ it "should use the provider's status to determine whether the service is running" do
+ @service.provider.expects(:status).returns(:yepper)
+ @service[:ensure] = :running
+ @service.property(:ensure).retrieve.should == :yepper
+ end
+
+ it "should ask the provider whether it is enabled" do
+ @service.provider.class.stubs(:supports_parameter?).returns(true)
+ @service.provider.expects(:enabled?).returns(:yepper)
+ @service[:enable] = true
+ @service.property(:enable).retrieve.should == :yepper
+ end
+
+ after { Puppet::Type::Service.clear }
+end
+
+describe Puppet::Type::Service, "when changing the host" do
+ before do
+ @service = Puppet::Type::Service.create(:name => "yay")
+ end
+
+ it "should start the service if it is supposed to be running" do
+ @service[:ensure] = :running
+ @service.provider.expects(:start)
+ @service.property(:ensure).sync
+ end
+
+ it "should stop the service if it is supposed to be stopped" do
+ @service[:ensure] = :stopped
+ @service.provider.expects(:stop)
+ @service.property(:ensure).sync
+ end
+
+ it "should enable the service if it is supposed to be enabled" do
+ @service.provider.class.stubs(:supports_parameter?).returns(true)
+ @service[:enable] = true
+ @service.provider.expects(:enable)
+ @service.property(:enable).sync
+ end
+
+ it "should disable the service if it is supposed to be disabled" do
+ @service.provider.class.stubs(:supports_parameter?).returns(true)
+ @service[:enable] = false
+ @service.provider.expects(:disable)
+ @service.property(:enable).sync
+ end
+
+ it "should sync the service's enable state when changing the state of :ensure if :enable is being managed" do
+ @service.provider.class.stubs(:supports_parameter?).returns(true)
+ @service[:enable] = false
+ @service[:ensure] = :stopped
+
+ @service.property(:enable).expects(:retrieve).returns("whatever")
+ @service.property(:enable).expects(:insync?).returns(false)
+ @service.property(:enable).expects(:sync)
+
+ @provider.stubs(:stop)
+
+ @service.property(:ensure).sync
+ end
+
+ after { Puppet::Type::Service.clear }
+end
+
+describe Puppet::Type::Service, "when refreshing the service" do
+ before do
+ @service = Puppet::Type::Service.create(:name => "yay")
+ end
+
+ it "should restart the service if it is running" do
+ @service[:ensure] = :running
+ @service.provider.expects(:status).returns(:running)
+ @service.provider.expects(:restart)
+ @service.refresh
+ end
+
+ it "should restart the service if it is running, even if it is supposed to stopped" do
+ @service[:ensure] = :stopped
+ @service.provider.expects(:status).returns(:running)
+ @service.provider.expects(:restart)
+ @service.refresh
+ end
+
+ it "should not restart the service if it is not running" do
+ @service[:ensure] = :running
+ @service.provider.expects(:status).returns(:stopped)
+ @service.refresh
+ end
+
+ it "should add :ensure as a property if it is not being managed" do
+ @service.provider.expects(:status).returns(:running)
+ @service.provider.expects(:restart)
+ @service.refresh
+ end
+
+ after { Puppet::Type::Service.clear }
+end
diff --git a/test/ral/providers/service.rb b/test/ral/providers/service.rb
deleted file mode 100755
index d527d4356..000000000
--- a/test/ral/providers/service.rb
+++ /dev/null
@@ -1,234 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../lib/puppettest'
-
-require 'puppettest'
-
-$skipsvcs = false
-case Facter["operatingsystem"].value
-when "Darwin", "OpenBSD": $skipsvcs = true
-end
-
-if $skipsvcs
- puts "Skipping service testing on %s" % Facter["operatingsystem"].value
-else
-class TestLocalService < Test::Unit::TestCase
- include PuppetTest
-
- def teardown
- Puppet.type(:service).clear
- super
- end
-
- def mktestsvcs
- list = tstsvcs.collect { |svc,svcargs|
- args = svcargs.dup
- args[:name] = svc
- Puppet.type(:service).create(args)
- }
- end
-
- def tstsvcs
- case Facter["operatingsystem"].value.downcase
- when "solaris":
- case Facter["operatingsystemrelease"].value
- when "5.10":
- return {"smtp" => {}, "xfs" => {}}
- end
- when "debian":
- return {"hddtemp" => {:hasrestart => true}}
- when "centos":
- return {"cups" => {:hasstatus => true}}
- when "redhat":
- return {"saslauthd" => {:hasstatus => true}}
- end
-
- Puppet.notice "No test services for %s-%s" %
- [Facter["operatingsystem"].value,
- Facter["operatingsystemrelease"].value]
- return []
- end
-
- def cycleservice(service)
- assert_nothing_raised() {
- service.retrieve
- }
-
- comp = mk_configuration("servicetst", service)
- service[:ensure] = :running
-
- Puppet.info "Starting %s" % service.name
- assert_apply(service)
-
- # Some package systems background the work, so we need to give them
- # time to do their work.
- sleep(1.5)
- props = nil
- assert_nothing_raised() {
- props = service.retrieve
- }
- props.each do |prop, value|
- if prop.name == :ensure
- assert_equal(:running, value, "Service %s is not running" % service.name)
- end
- end
-
- # test refreshing it
- assert_nothing_raised() {
- service.refresh
- }
-
- # now stop it
- assert_nothing_raised() {
- service[:ensure] = :stopped
- }
- props.each do |prop, value|
- if prop.name == :ensure
- assert_equal(:running, value, "Service %s is not running" % service.name)
- end
- end
- Puppet.info "stopping %s" % service.name
- assert_events([:service_stopped], comp)
- sleep(1.5)
- assert_nothing_raised() {
- props = service.retrieve
- }
- props.each do |prop, value|
- if prop.name == :ensure
- assert_equal(:stopped, value, "Service %s is not running" % service.name)
- end
- end
- end
-
- def cycleenable(service)
- assert_nothing_raised() {
- service.retrieve
- }
-
- comp = mk_configuration("servicetst", service)
- service[:enable] = true
-
- Puppet.info "Enabling %s" % service.name
- assert_apply(service)
-
- # Some package systems background the work, so we need to give them
- # time to do their work.
- sleep(1.5)
- props = nil
- assert_nothing_raised() {
- props = service.retrieve
- }
- props.each do |prop, value|
- if prop.name == :enable
- assert_equal(value, :true, "Service %s is not enabled" % service.name)
- end
- end
-
- # now disable it
- assert_nothing_raised() {
- service[:enable] = false
- }
- assert_nothing_raised() {
- props = service.retrieve
- }
- props.each do |prop, value|
- assert_equal(value, :true, "Service %s is already disabled" % service.name)
- end
- Puppet.info "disabling %s" % service.name
- assert_events([:service_disabled], comp)
- sleep(1.5)
- assert_nothing_raised() {
- props = service.retrieve
- }
- props.each do |prop, value|
- assert_equal(value, :false, "Service %s is still enabled" % service.name)
- end
- end
-
- def test_status
- mktestsvcs.each { |svc|
- val = nil
- assert_nothing_raised("Could not get status") {
- val = svc.provider.status
- }
- assert_instance_of(Symbol, val)
- }
- end
-
- unless Puppet::Util::SUIDManager.uid == 0
- puts "run as root to test service start/stop"
- else
- def test_servicestartstop
- mktestsvcs.each { |svc|
- startproperty = nil
- assert_nothing_raised("Could not get status") {
- startproperty = svc.provider.status
- }
- cycleservice(svc)
-
- svc[:ensure] = startproperty
- assert_apply(svc)
- Puppet.type(:component).clear
- }
- end
-
- def test_serviceenabledisable
- mktestsvcs.each { |svc|
- assert(svc[:name], "Service has no name")
- startproperty = nil
- svc[:check] = :enable
- assert_nothing_raised("Could not get status") {
- startproperty = svc.provider.enabled?
- }
- cycleenable(svc)
-
- svc[:enable] = startproperty
- assert_apply(svc)
- Puppet.type(:component).clear
- }
- end
-
- def test_serviceenableandrun
- mktestsvcs.each do |svc|
- startenable = nil
- startensure = nil
- svc[:check] = [:ensure, :enable]
- properties = nil
- assert_nothing_raised("Could not get status") {
- properties = svc.retrieve
- }
- initial = properties.dup
-
- svc[:enable] = false
- svc[:ensure] = :stopped
- assert_apply(svc)
-
- sleep 1
- assert_nothing_raised("Could not get status") {
- properties = svc.retrieve
- }
- properties.each do |prop, value|
- assert(prop.insync?(value), "Service did not sync %s property" % prop.name)
- end
-
- svc[:enable] = true
- svc[:ensure] = :running
- assert_apply(svc)
-
- sleep 1
- assert_nothing_raised("Could not get status") {
- properties = svc.retrieve
- }
- assert(svc.insync?(properties), "Service did not sync both properties")
-
- initial.each do |prop, value|
- svc[prop.name] = value
- end
- assert_apply(svc)
- Puppet.type(:component).clear
- end
- end
- end
-end
-end
-