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
-~----------~----~----~----~------~----~------~--~---

Reply via email to