diff options
author | Luke Kanies <luke@madstop.com> | 2007-11-28 18:38:48 -0600 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2007-11-28 18:38:48 -0600 |
commit | dedc56a6ae583daca304c053b1be8a52bcdbd13a (patch) | |
tree | 79421acea6e98035a2d09b984f1796331af61a51 | |
parent | 600d093df55e012e2e00a5b525daefb77c2eded1 (diff) | |
download | puppet-dedc56a6ae583daca304c053b1be8a52bcdbd13a.tar.gz puppet-dedc56a6ae583daca304c053b1be8a52bcdbd13a.tar.xz puppet-dedc56a6ae583daca304c053b1be8a52bcdbd13a.zip |
Fixing #527 (rewrote service tests), #766 (services only restart when they
are running), and #918 (service tests fail when hddtemp is not installed).
Mostly, I just rewrote the service tests, but I cleaned up the cruft from the
Service class, too.
-rw-r--r-- | CHANGELOG | 10 | ||||
-rwxr-xr-x | lib/puppet/provider/service/init.rb | 8 | ||||
-rwxr-xr-x | lib/puppet/provider/service/redhat.rb | 4 | ||||
-rw-r--r-- | lib/puppet/type/service.rb | 176 | ||||
-rwxr-xr-x | spec/unit/ral/types/package.rb | 2 | ||||
-rwxr-xr-x | spec/unit/ral/types/service.rb | 249 | ||||
-rwxr-xr-x | test/ral/providers/service.rb | 234 |
7 files changed, 282 insertions, 401 deletions
@@ -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 - |