Puppet::Type.type(:service).provide :base do desc "The simplest form of service support. You have to specify enough about your service for this to work; the minimum you can specify is a binary for starting the process, and this same binary will be searched for in the process table to stop the service. It is preferable to specify start, stop, and status commands, akin to how you would do so using ``init``. " commands :kill => "kill" def self.instances [] end # Get the process ID for a running process. Requires the 'pattern' # parameter. def getpid unless @resource[:pattern] @resource.fail "Either a stop command or a pattern must be specified" end ps = Facter["ps"].value unless ps and ps != "" @resource.fail( "You must upgrade Facter to a version that includes 'ps'" ) end regex = Regexp.new(@resource[:pattern]) self.debug "Executing '#{ps}'" IO.popen(ps) { |table| table.each { |line| if regex.match(line) ary = line.sub(/^\s+/, '').split(/\s+/) return ary[1] end } } return nil end # How to restart the process. def restart if @resource[:restart] or self.respond_to?(:restartcmd) ucommand(:restart) else self.stop self.start end end # Check if the process is running. Prefer the 'status' parameter, # then 'statuscmd' method, then look in the process table. We give # the object the option to not return a status command, which might # happen if, for instance, it has an init script (and thus responds to # 'statuscmd') but does not have 'hasstatus' enabled. def status if @resource[:status] or ( self.respond_to?(:statuscmd) and self.statuscmd ) # Don't fail when the exit status is not 0. output = ucommand(:status, false) if $? == 0 return :running else return :stopped end elsif pid = self.getpid self.debug "PID is %s" % pid return :running else return :stopped end end # Run the 'start' parameter command, or the specified 'startcmd'. def start ucommand(:start) end # The command used to start. Generated if the 'binary' argument # is passed. def startcmd if @resource[:binary] return @resource[:binary] else raise Puppet::Error, "Services must specify a start command or a binary" end end # Stop the service. If a 'stop' parameter is specified, it # takes precedence; otherwise checks if the object responds to # a 'stopcmd' method, and if so runs that; otherwise, looks # for the process in the process table. # This method will generally not be overridden by submodules. def stop if @resource[:stop] or self.respond_to?(:stopcmd) ucommand(:stop) else pid = getpid unless pid self.info "%s is not running" % self.name return false end begin output = kill pid rescue Puppet::ExecutionFailure => detail @resource.fail "Could not kill %s, PID %s: %s" % [self.name, pid, output] end return true end end # A simple wrapper so execution failures are a bit more informative. def texecute(type, command, fof = true) begin # #565: Services generally produce no output, so squelch them. execute(command, :failonfail => fof, :squelch => true) rescue Puppet::ExecutionFailure => detail @resource.fail "Could not %s %s: %s" % [type, @resource.ref, detail] end return nil end # Use either a specified command or the default for our provider. def ucommand(type, fof = true) if c = @resource[type] cmd = [c] else cmd = self.send("%scmd" % type) end return texecute(type, cmd, fof) end end