Source code for lib_openmolar.server.daemon.service
#! /usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
## ##
## Copyright 2011, Neil Wallace <rowinggolfer@googlemail.com> ##
## ##
## This program is free software: you can redistribute it and/or modify ##
## it under the terms of the GNU General Public License as published by ##
## the Free Software Foundation, either version 3 of the License, or ##
## (at your option) any later version. ##
## ##
## This program is distributed in the hope that it will be useful, ##
## but WITHOUT ANY WARRANTY; without even the implied warranty of ##
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ##
## GNU General Public License for more details. ##
## ##
## You should have received a copy of the GNU General Public License ##
## along with this program. If not, see <http://www.gnu.org/licenses/>. ##
## ##
###############################################################################
'''
"borrows" heavily from http://code.google.com/p/supay/
and the book python for sysadmins (which I own)
'''
import os
import sys
from signal import SIGTERM
PIDFILE = "/var/run/openmolar/server.pid"
[docs]class Service(object):
[docs] def write_pidfile(self):
dirname = os.path.dirname(PIDFILE)
try:
os.mkdir(dirname)
except OSError as exc:
if exc.errno == 17:
pass
else:
LOGGER.error('Unable to create %s - Are you root?'% dirname)
return False
pid = os.getpid()
try:
f = open(PIDFILE, "w")
f.write("%s\n"% pid)
f.close()
except IOError, exc:
if exc.errno == 13:
LOGGER.error('Unable to create %s - Are you root?' % pid)
else:
LOGGER.exception('The service module had an IO error:')
return False
return True
[docs] def start_(self, stdin="/dev/null", stdout="/dev/null", stderr="/dev/null"):
'''
checks for a PIDfile,
daemonises the process,
writes the new PIDfile
'''
if self.is_running:
LOGGER.warning("openmolar-server is already started")
self.daemonise(stdin, stdout, stderr)
return self.write_pidfile()
[docs] def daemonise(self, stdin, stdout, stderr):
"""
Double forks the process in the background
to avoid zombies, writes a PID.
"""
#we are about to fork the process... so clear any output first
sys.stdout.flush()
sys.stderr.flush()
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError, exc:
LOGGER.exception("fork 1 failed")
sys.exit("%s: fork #1 failed: (%d) %s\n" % (sys.argv[0],
exc.errno, exc.strerror))
os.chdir("/")
os.umask(0)
os.setsid()
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError, exc:
LOGGER.exception("fork 2 failed")
sys.exit("%s: fork #2 failed: (%d) %s\n" % (sys.argv[0],
exc.errno, exc.strerror))
si = file(stdin, "r")
so = file(stdout, "a+")
se = file(stderr, "a+", 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
[docs] def stop_(self):
try:
pidfile = open(PIDFILE, "r")
pid = pidfile.readline()
LOGGER.info("Stopping the openmolar_server. " +
"With pid number %s" % pid)
os.kill(int(pid), SIGTERM)
os.remove(PIDFILE)
except OSError, e:
LOGGER.error("Could not kill process")
if e.errno == 3: # catch a 'no such process'
os.remove(PIDFILE)
LOGGER.info("Removed defunct PID file.")
LOGGER.info("Try restarting openmolar-server now")
except IOError:
LOGGER.warning("PID file not found when stopping server.")
LOGGER.warning("openmolar-server may not be running?")
[docs] def status_(self):
'''
Check the status of the process (running | not running)
'''
LOGGER.info('checking status of openmolar-server process')
try:
pidfile = open(PIDFILE)
pid = pidfile.readline()
os.kill(int(pid), 0)
except OSError:
LOGGER.warning('openmolar-server process not running')
except IOError:
LOGGER.warning('openmolar-server process not running')
else:
LOGGER.info(
'openmolar-server process is running with PID: %s'% pid)
@property
[docs] def is_running(self):
'''
true is the process already exists.
'''
return os.path.isfile(PIDFILE)
def _test():
sd = Service()
if "start" in sys.argv:
sd.start_()
elif "stop" in sys.argv:
sd.stop_()
elif "status" in sys.argv:
sd.status_()
else:
LOGGER.warning("nothing to do")
LOGGER.info("please pass 'start | stop | status' as arguments")
if __name__ == "__main__":
import logging
logging.basicConfig(level=logging.DEBUG)
LOGGER = logging.getLogger("test")
_test()