You rock, Brice. Good work. Adam
On Tue, Aug 26, 2008 at 1:56 PM, Brice Figureau <[EMAIL PROTECTED]> wrote: > > This is the second attempt of a daemontools (only for the moment) > provider for the service type. I added a rspec unit type, and tried > to take into account all of Luke's previous comments. > > The development of this provider is hosted at: > http://github.com/masterzen/puppet/tree/feature%2Fdaemontools > which is based on 0.24.x > > Comments are (more than) welcome as usual. > Next revision will bring a runit version. > > Here is the patch description: > This provider manages daemons running supervised under D.J.Bernstein > daemontools. > It tries to detect the service directory, with by order of preference: > * /service > * /etc/service > * /var/lib/svscan > > The daemon directory should be placed in a directory that can be > by default in: > * /var/lib/service > * /etc > or this can be overriden in the service resource parameters: > service { > "myservice": > provider => "daemontools", path => "/path/to/daemons"; > } > > This provider supports out of the box: > * start/stop (mapped to enable/disable) > * enable/disable > * restart > * status > > Signed-off-by: Brice Figureau <[EMAIL PROTECTED]> > --- > lib/puppet/provider/service/daemontools.rb | 152 > ++++++++++++++++++++++++++++ > spec/unit/provider/service/daemontools.rb | 124 ++++++++++++++++++++++ > 2 files changed, 276 insertions(+), 0 deletions(-) > create mode 100644 lib/puppet/provider/service/daemontools.rb > create mode 100644 spec/unit/provider/service/daemontools.rb > > diff --git a/lib/puppet/provider/service/daemontools.rb > b/lib/puppet/provider/service/daemontools.rb > new file mode 100644 > index 0000000..dda27d0 > --- /dev/null > +++ b/lib/puppet/provider/service/daemontools.rb > @@ -0,0 +1,152 @@ > +# Daemontools service management > +# > +# author Brice Figureau <[EMAIL PROTECTED]> > +Puppet::Type.type(:service).provide :daemontools, :parent => :base do > + desc "Daemontools service management. > + This provider manages daemons running supervised by D.J.Bernstein > daemontools. > + It tries to detect the service directory, with by order of preference: > + * /service > + * /etc/service > + * /var/lib/svscan > + The daemon directory should be placed in a directory that can be > + by default in: > + * /var/lib/service > + * /etc > + or this can be overriden in the service resource parameters: > + service { > + \"myservice\": > + provider => \"daemontools\", path => \"/path/to/daemons\"; > + } > + > + This provider supports out of the box: > + * start/stop (mapped to enable/disable) > + * enable/disable > + * restart > + * status" > + > + commands :svc => "/usr/bin/svc" > + commands :svstat => "/usr/bin/svstat" > + > + class << self > + attr_writer :defpath > + > + # this is necessary to autodetect a valid resource > + # default path, since there is no standard for such directory. > + def defpath > + unless defined?(@defpath) and @defpath > + ["/var/lib/service", "/etc"].each do |path| > + if FileTest.exist?(path) > + @defpath = path > + break > + end > + end > + raise "Could not find the daemon directory (tested > [/var/lib/service,/etc])" unless @defpath > + end > + @defpath > + end > + end > + > + attr_writer :servicedir > + > + # returns all providers for all existing services in @defpath > + # ie enabled or not > + def self.instances > + path = self.daemondir > + unless FileTest.directory?(path) > + Puppet.notice "Service path %s does not exist" % path > + next > + end > + > + Dir.entries(path).reject { |e| > + fullpath = File.join(path, e) > + e =~ /^\./ or ! FileTest.directory?(fullpath) > + }.collect do |name| > + new(:name => name, :path => path) > + end > + end > + > + # find the service dir on this node > + def servicedir > + unless defined?(@servicedir) and @servicedir > + ["/service", "/etc/service","/var/lib/svscan"].each do |path| > + if FileTest.exist?(path) > + @servicedir = path > + break > + end > + end > + raise "Could not find service directory" unless @servicedir > + end > + @servicedir > + end > + > + # returns the daemon dir on this node > + def self.daemondir > + self.class.defpath > + end > + > + # returns the full path of this service when enabled > + # (ie in the service directory) > + def service > + File.join(self.servicedir, resource[:name]) > + end > + > + # returns the full path to the current daemon directory > + # note that this path can be overriden in the resource > + # definition > + def daemon > + File.join(resource[:path], resource[:name]) > + end > + > + def restartcmd > + [ command(:svc), "-t", self.service] > + end > + > + # The start command does nothing, service are automatically started > + # when enabled by svscan. But, forces an enable if necessary > + def start > + # to start make sure the sevice is enabled > + self.enable > + # start is then automatic > + end > + > + def status > + begin > + output = svstat self.service > + return :running if output =~ /\bup\b/ > + rescue Puppet::ExecutionFailure => detail > + raise Puppet::Error.new( "Could not get status for service %s: > %s" % [ resource.ref, detail] ) > + end > + return :stopped > + end > + > + # unfortunately it is not possible > + # to stop without disabling the service > + def stop > + self.disable > + end > + > + # disable by stopping the service > + # and removing the symlink so that svscan > + # doesn't restart our service behind our back > + def disable > + # should stop the service > + # stop the log subservice if any > + log = File.join(self.service, "log") > + texecute("stop log", [ command(:svc) , '-dx', log] ) if > FileTest.directory?(log) > + > + # stop the main resource > + texecute("stop", [command(:svc), '-dx', self.service] ) > + > + # unlink the daemon symlink to disable it > + File.unlink(self.service) if FileTest.symlink?(self.service) > + end > + > + def enabled? > + FileTest.symlink?(self.service) > + end > + > + def enable > + File.symlink(self.daemon, self.service) if ! > FileTest.symlink?(self.service) > + end > +end > + > diff --git a/spec/unit/provider/service/daemontools.rb > b/spec/unit/provider/service/daemontools.rb > new file mode 100644 > index 0000000..29e9dd5 > --- /dev/null > +++ b/spec/unit/provider/service/daemontools.rb > @@ -0,0 +1,124 @@ > +#!/usr/bin/env ruby > +# > +# Unit testing for the Daemontools service Provider > +# > +# author Brice Figureau > +# > +require File.dirname(__FILE__) + '/../../../spec_helper' > + > +provider_class = Puppet::Type.type(:service).provider(:daemontools) > + > +describe provider_class do > + > + before(:each) do > + # Create a mock resource > + @resource = stub 'resource' > + > + @provider = provider_class.new > + @servicedir = "/etc/service" > + @[EMAIL PROTECTED] > + @daemondir = "/var/lib/service" > + @[EMAIL PROTECTED] > + > + # A catch all; no parameters set > + @resource.stubs(:[]).returns(nil) > + > + # But set name, source and path (because we won't run > + # the thing that will fetch the resource path from the provider) > + @resource.stubs(:[]).with(:name).returns "myservice" > + @resource.stubs(:[]).with(:ensure).returns :enabled > + @resource.stubs(:[]).with(:path).returns @daemondir > + @resource.stubs(:ref).returns "Service[myservice]" > + > + @provider.stubs(:resource).returns @resource > + 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 starting" do > + it "should call enable" do > + @provider.expects(:enable) > + @provider.start > + end > + end > + > + describe "when stopping" do > + it "should call disable" do > + @provider.expects(:disable) > + @provider.stop > + end > + end > + > + describe "when enabling" do > + it "should create a symlink between daemon dir and service dir" do > + FileTest.stubs(:symlink?).returns(false) > + File.expects(:symlink).with(File.join(@daemondir,"myservice"), > File.join(@servicedir,"myservice")).returns(0) > + @provider.enable > + end > + end > + > + describe "when disabling" do > + it "should stop and then remove the symlink between daemon dir and > service dir" do > + FileTest.stubs(:directory?).returns(false) > + FileTest.stubs(:symlink?).returns(true) > + > File.expects(:unlink).with(File.join(@servicedir,"myservice")).returns(0) > + @provider.stubs(:texecute).returns("") > + @provider.disable > + end > + end > + > + describe "when disabling" do > + it "should also call 'svc -dx /etc/service/myservice'" do > + FileTest.stubs(:directory?).returns(false) > + FileTest.stubs(:symlink?).returns(true) > + > File.expects(:unlink).with(File.join(@servicedir,"myservice")).returns(0) > + @provider.expects(:texecute).with("stop", [nil, '-dx', > File.join(@servicedir,"myservice")]).returns "" > + @provider.disable > + end > + end > + > + describe "when checking status" do > + it "should call the external command 'svstat > /etc/service/myservice'" do > + > @provider.expects(:svstat).with(File.join(@servicedir,"myservice")) > + @provider.status > + end > + end > + > + describe "when checking status" do > + it "and svstat fails, properly raise a Puppet::Error" do > + > @provider.expects(:svstat).with(File.join(@servicedir,"myservice")).raises(Puppet::ExecutionFailure, > "failure") > + lambda { @provider.status }.should raise_error(Puppet::Error, > 'Could not get status for service Service[myservice]: failure') > + end > + it "and svstat returns up, then return :running" do > + > @provider.expects(:svstat).with(File.join(@servicedir,"myservice")).returns("/etc/service/myservice: > up (pid 454) 954326 seconds") > + @provider.status.should == :running > + end > + it "and svstat returns not running, then return :stopped" do > + > @provider.expects(:svstat).with(File.join(@servicedir,"myservice")).returns("/etc/service/myservice: > supervise not running") > + @provider.status.should == :stopped > + end > + end > + > + end > -- > 1.5.6.5 > > > > > -- HJK Solutions - We Launch Startups - http://www.hjksolutions.com Adam Jacob, Senior Partner T: (206) 508-4759 E: [EMAIL PROTECTED] --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en -~----------~----~----~----~------~----~------~--~---
