Skip to content

Instantly share code, notes, and snippets.

@yyuu
Created April 4, 2012 09:39
Show Gist options
  • Select an option

  • Save yyuu/2300009 to your computer and use it in GitHub Desktop.

Select an option

Save yyuu/2300009 to your computer and use it in GitHub Desktop.
a mon's alert plugin to manage syvinit/upstart/daemontools services
#!/usr/bin/env python
#
# service2.alert - a mon's alert plugin to manage syvinit/upstart/daemontools services
#
# you have to permit mon user to run following commands via sudo without password.
#
# * /usr/sbin/service (for sysvinit)
# * /sbin/initctl (for upstart)
# * /usr/bin/svc (for daemontools)
# * /usr/bin/svstat (for daemontools)
#
from __future__ import with_statement
import logging
import optparse
import os
import re
import subprocess
import sys
import time
class service(object):
@classmethod
def exists(cls, name):
return os.path.isfile("/etc/init.d/%s" % (name,))
def __init__(self, name):
assert self.exists(name), "not a %s service: %s" % (self.__class__.__name__, name)
self.name = name
def start(self, options):
return self._system(self._cmdline('start'), options)
def stop(self, options=None):
retry = 3
if options is None:
options = {}
if options.force and not options.dry_run:
for _ in xrange(retry):
self._system(self._cmdline('stop'), options)
if self.status(options) == 0:
break
else:
time.sleep(3)
if self.status(options) != 0:
return 0
else:
raise(RuntimeError("could not stop %s service in %d times" % (self.name, retry)))
else:
return self._system(self._cmdline('stop'), options)
def restart(self, options=None):
if options is None:
options = {}
if options.force:
self.stop(options)
return self.start(options)
else:
return self._system("%s || %s" % (self._cmdline('restart'), self._cmdline('start')), options)
def reload(self, options=None):
if options is None:
options = {}
if options.force:
return self.restart(options)
else:
return self._system("%s || %s" % (self._cmdline('reload'), self._cmdline('start')), options)
def status(self, options=None):
return self._system(self._cmdline('status'), options)
def _cmdline(self, action):
return "sudo service %s %s" % (self.name, action)
def _system(self, cmdline, options=None):
if options is None:
options = {}
if options.dry_run:
logging.info(cmdline)
return 0
else:
if options.verbose:
logging.info(cmdline)
return subprocess.call(["/bin/sh", "-e", "-c", cmdline])
class upstart(service):
@classmethod
def exists(cls, name):
return os.path.isfile("/etc/init/%s.conf" % (name,))
def status(self, options=None):
return self._system("sudo service %s status | grep -q running" % (self.name,), options)
def _cmdline(self, action):
return "sudo initctl %s %s" % (action, self.name)
class daemontools(service):
@classmethod
def exists(cls, name):
return os.path.isdir("/etc/service/%s" % (name,))
@property
def dir(self):
return "/etc/service/%s" % (self.name,)
def status(self, options=None):
return self._system("sudo svstat %s | grep -q '%s: *up'" % (self.dir, self.dir), options)
def _cmdline(self, action):
actions = { "start": "-u", "stop": "-d", "restart": "-t" , "reload": "-t" }
if action in actions:
return "sudo svc %s %s" % (actions[action], self.dir)
else:
raise(ValueError("unknown action for daemontools service of %s: %s" % (self.name, action)))
def main(args):
parser = optparse.OptionParser("usage %prog [OPTIONS]", add_help_option=False)
parser.add_option('-T', '--trap', default=False, action='store_true', dest='trap', help='(if trap)')
parser.add_option('-O', '--traptimeout', default=False, action='store_true', dest='traptimeout', help='(if traptimeout)')
parser.add_option('--action', default='restart', dest='action', help='service action')
parser.add_option('--dry-run', default=False, action='store_true', dest='dry_run', help='perform a trial run with no changes made')
parser.add_option('-f', '--force', default=False, action='store_true', dest='force', help='performing actions forcively')
parser.add_option('-g', '--group', dest='group', help='(will be ignored)')
parser.add_option('-h', '--hosts', dest='hosts', help='(will be ignored)')
parser.add_option('-s', '--service', dest='service', help='service')
parser.add_option('-t', '--tmnow', type='int', dest='tmnow', help='(will be ignored)')
parser.add_option('-u', '--upalert', default=False, action='store_true', dest='upalert', help='(if upalert)')
parser.add_option('-v', '--verbose', default=False, action='store_true', dest='verbose', help='show verbose messages')
(options, args) = parser.parse_args(args)
if options.verbose:
logging.basicConfig(level=logging.DEBUG)
if options.service is None:
raise ValueError("no service was specified")
if re.match(r'force-', options.action):
options.force = True
options.action = re.sub(r'force-', '', options.action)
svc = None
for cls in [ daemontools, upstart, service ]:
try:
svc = cls(options.service)
break
except AssertionError:
logging.debug("%s is not a %s service." % (options.service, cls.__name__))
if svc:
logging.debug("%s is %s service." % (options.service, svc.__class__.__name__))
try:
action = getattr(svc, options.action)
except AttributeError:
raise(RuntimeError("unknown action called for service %s: %s" % (options.service, options.action)))
sys.exit(action(options))
else:
logging.error("unknown service: %s" % (options.service,))
sys.exit(1)
if __name__ == "__main__":
main(sys.argv)
# vim:set ft=python :
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment