|
import argparse |
|
import sys |
|
import logging |
|
|
|
import signal, lockfile, grp, os |
|
|
|
from pwd import getpwnam |
|
from daemonize import Daemonize |
|
|
|
class ExampleDaemon: |
|
def __init__(self, args, logger): |
|
self.args = args |
|
self.logger = logger |
|
self.terminate = False |
|
self.rereadConfig = True |
|
|
|
def signalSigHup(self, *args): |
|
self.rereadConfig = True |
|
|
|
def signalTerm(self, *args): |
|
self.terminate = True |
|
|
|
def __enter__(self): |
|
return self |
|
|
|
def __exit__(self, type, value, tb): |
|
pass |
|
|
|
def run(self): |
|
signal.signal(signal.SIGHUP, self.signalSigHup) |
|
signal.signal(signal.SIGTERM, self.signalTerm) |
|
signal.signal(signal.SIGINT, self.signalTerm) |
|
|
|
self.logger.info("Service running") |
|
|
|
while True: |
|
# Do whatever is required to be done ... |
|
if self.terminate: |
|
break |
|
|
|
self.logger.info("Shutting down due to user request") |
|
|
|
def mainDaemon(): |
|
parg = parseArguments() |
|
args = parg['args'] |
|
logger = parg['logger'] |
|
|
|
logger.debug("Daemon starting ...") |
|
with ExampleDaemon(args, logger) as sampleDaemon: |
|
sampleDaemon.run() |
|
|
|
def parseArguments(): |
|
ap = argparse.ArgumentParser(description = 'Example daemon') |
|
ap.add_argument('-f', '--foreground', action='store_true', help="Do not daemonize - stay in foreground and dump debug information to the terminal") |
|
|
|
ap.add_argument('--uid', type=str, required=False, default=None, help="User ID to impersonate when launching as root") |
|
ap.add_argument('--gid', type=str, required=False, default=None, help="Group ID to impersonate when launching as root") |
|
ap.add_argument('--chroot', type=str, required=False, default=None, help="Chroot directory that should be switched into") |
|
ap.add_argument('--pidfile', type=str, required=False, default="/var/run/sampledaemon.pid", help="PID file to keep only one daemon instance running") |
|
ap.add_argument('--loglevel', type=str, required=False, default="error", help="Loglevel to use (debug, info, warning, error, critical). Default: error") |
|
ap.add_argument('--logfile', type=str, required=False, default="/var/log/sampledaemon.log", help="Logfile that should be used as target for log messages") |
|
|
|
args = ap.parse_args() |
|
loglvls = { |
|
"DEBUG" : logging.DEBUG, |
|
"INFO" : logging.INFO, |
|
"WARNING" : logging.WARNING, |
|
"ERROR" : logging.ERROR, |
|
"CRITICAL" : logging.CRITICAL |
|
} |
|
if not args.loglevel.upper() in loglvls: |
|
print("Unknown log level {}".format(args.loglevel.upper())) |
|
sys.exit(1) |
|
|
|
logger = logging.getLogger() |
|
logger.setLevel(loglvls[args.loglevel.upper()]) |
|
if args.logfile: |
|
fileHandleLog = logging.FileHandler(args.logfile) |
|
logger.addHandler(fileHandleLog) |
|
|
|
return { 'args' : args, 'logger' : logger } |
|
|
|
# Entry function for CLI program |
|
# This also configures the daemon properties |
|
|
|
def mainStartup(): |
|
parg = parseArguments() |
|
args = parg['args'] |
|
logger = parg['logger'] |
|
|
|
daemonPidfile = args.pidfile |
|
daemonUid = None |
|
daemonGid = None |
|
daemonChroot = "/" |
|
|
|
if args.uid: |
|
try: |
|
args.uid = int(args.uid) |
|
except ValueError: |
|
try: |
|
args.uid = getpwnam(args.uid).pw_uid |
|
except KeyError: |
|
logger.critical("Unknown user {}".format(args.uid)) |
|
print("Unknown user {}".format(args.uid)) |
|
sys.exit(1) |
|
daemonUid = args.uid |
|
if args.gid: |
|
try: |
|
args.gid = int(args.gid) |
|
except ValueError: |
|
try: |
|
args.gid = grp.getgrnam(args.gid)[2] |
|
except KeyError: |
|
logger.critical("Unknown group {}".format(args.gid)) |
|
print("Unknown group {}".format(args.gid)) |
|
sys.exit(1) |
|
|
|
daemonGid = args.gid |
|
|
|
if args.chroot: |
|
if not os.path.isdir(args.chroot): |
|
logger.critical("Non existing chroot directors {}".format(args.chroot)) |
|
print("Non existing chroot directors {}".format(args.chroot)) |
|
sys.exit(1) |
|
daemonChroot = args.chroot |
|
|
|
if args.foreground: |
|
logger.debug("Launching in foreground") |
|
with ExampleDaemon(args, logger) as sampleDaemon: |
|
sampleDaemon.run() |
|
else: |
|
logger.debug("Daemonizing ...") |
|
daemon = Daemonize( |
|
app="ExampleDaemon", |
|
action=mainDaemon, |
|
pid=daemonPidfile, |
|
user=daemonUid, |
|
group=daemonGid, |
|
chdir=daemonChroot |
|
) |
|
daemon.start() |
|
|
|
|
|
if __name__ == "__main__": |
|
mainStartup() |