freezer_dr.common.daemon

Source code for freezer_dr.common.daemon

#!/usr/bin/env python
"""Generic deamon."""
# (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import print_function

import atexit
import logging as log
import os
import sys
import time

from signal import SIGTERM


[docs]class Daemon(object): """A generic daemon class. Usage: subclass the Daemon class and override the run() method """ def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): """Instantiantion.""" self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile
[docs] def daemonize(self): """Do the UNIX double-fork magic. See Stevens' "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 """ try: pid = os.fork() if pid > 0: # exit first parent sys.exit(0) except OSError as e: sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) log.error(e) sys.exit(1) # decouple from parent environment os.chdir("/") os.setsid() os.umask(0) # do second fork try: pid = os.fork() if pid > 0: # exit from second parent sys.exit(0) except OSError as e: sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) log.error(e) sys.exit(1) # redirect standard file descriptors sys.stdout.flush() sys.stderr.flush() si = open(self.stdin, 'r') so = open(self.stdout, 'a+') se = open(self.stderr, 'a+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # write pidfile atexit.register(self.delpid) pid = str(os.getpid()) f = open(self.pidfile, 'w+') f.write("%s\n" % pid) f.close()
[docs] def delpid(self): """Delete PID file.""" os.remove(self.pidfile)
[docs] def start(self): """Start the daemon.""" log.error("Test") # Check for a pidfile to see if the daemon already runs try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if pid: message = "pidfile %s already exist. Daemon" \ " already running?\n" sys.stderr.write(message % self.pidfile) sys.exit(1) # Start the daemon self.daemonize() self.run()
# @todo needs some enhancement like check /proc/%pid/status if it's # really running or not ! may be it's killed by external process # the PID won't be updated !
[docs] def status(self): """Check daemon status.""" try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if pid: message = "pidfile %s already exist. Daemon already " \ "running. PID: %d \n" sys.stdout.write(message % (self.pidfile, pid)) sys.exit(0) else: message = "Service not running!\n" sys.stdout.write(message) sys.exit(0)
[docs] def stop(self): """Stop the daemon.""" # Get the pid from the pidfile try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if not pid: message = "pidfile %s does not exist." \ " Daemon not running?\n" sys.stderr.write(message % self.pidfile) return # not an error in a restart # Try killing the daemon process try: while 1: os.kill(pid, SIGTERM) time.sleep(0.1) except OSError as err: err = str(err) if err.find("No such process") > 0: if os.path.exists(self.pidfile): os.remove(self.pidfile) else: print(str(err)) sys.exit(1)
[docs] def restart(self): """Restart the daemon.""" self.stop() self.start()
[docs] def run(self): """You should override this method when you subclass Daemon. It will be called after the process has been daemonized by start() or restart(). """
Creative Commons Attribution 3.0 License

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.