# Daemontools service management
#
# author Brice Figureau <brice-puppet@daysofwonder.com>
Puppet::Type.type(:service).provide :runit, :parent => :daemontools do
  desc "Runit service management.

  This provider manages daemons running supervised by Runit.
  It tries to detect the service directory, with by order of preference:

  * /service
  * /var/service
  * /etc/service

  The daemon directory should be placed in a directory that can be
  by default in:

  * /etc/sv

  or this can be overriden in the service resource parameters::

      service { \"myservice\":
        provider => \"runit\",
        path => \"/path/to/daemons\",
      }

  This provider supports out of the box:

  * start/stop
  * enable/disable
  * restart
  * status


"

  commands :sv => "/usr/bin/sv"

  class << self
    # this is necessary to autodetect a valid resource
    # default path, since there is no standard for such directory.
    def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
      unless @defpath
        ["/etc/sv", "/var/lib/service"].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

  # find the service dir on this node
  def servicedir
    unless @servicedir
      ["/service", "/etc/service","/var/service"].each do |path|
        if FileTest.exist?(path)
          @servicedir = path
          break
        end
      end
      raise "Could not find service directory" unless @servicedir
    end
    @servicedir
  end

  def status
    begin
      output = sv "status", self.daemon
      return :running if output =~ /^run: /
    rescue Puppet::ExecutionFailure => detail
      unless detail.message =~ /(warning: |runsv not running$)/
        raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}" )
      end
    end
    :stopped
  end

  def stop
    sv "stop", self.service
  end

  def start
    enable unless enabled? == :true
    sv "start", self.service
  end

  def restart
    sv "restart", self.service
  end

  # disable by removing the symlink so that runit
  # doesn't restart our service behind our back
  # note that runit doesn't need to perform a stop
  # before a disable
  def disable
    # unlink the daemon symlink to disable it
    File.unlink(self.service) if FileTest.symlink?(self.service)
  end
end

