| #!/usr/bin/env python |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you 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. |
| # |
| # Automatically generated by addcopyright.py at 01/29/2013 |
| |
| import sys, os, time, atexit
|
| import traceback
|
| import subprocess |
| from signal import SIGTERM
|
| import cherrypy |
| import copy |
| |
| class Request(object): |
| def __init__(self): |
| self.headers = None |
| self.body = None |
| self.method = None |
| self.query_string = None |
| |
| @staticmethod |
| def from_cherrypy_request(creq): |
| req = Request() |
| req.headers = copy.copy(creq.headers) |
| req.body = creq.body.fp.read() if creq.body else None |
| req.method = copy.copy(creq.method) |
| req.query_string = copy.copy(creq.query_string) if creq.query_string else None |
| return req |
| |
| class ShellError(Exception): |
| '''shell error''' |
| |
| class ShellCmd(object): |
| ''' |
| classdocs |
| ''' |
| def __init__(self, cmd, workdir=None, pipe=True): |
| ''' |
| Constructor |
| ''' |
| self.cmd = cmd |
| if pipe: |
| self.process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/sh', cwd=workdir) |
| else: |
| self.process = subprocess.Popen(cmd, shell=True, executable='/bin/sh', cwd=workdir) |
| |
| self.stdout = None |
| self.stderr = None |
| self.return_code = None |
| |
| def __call__(self, is_exception=True): |
| (self.stdout, self.stderr) = self.process.communicate() |
| if is_exception and self.process.returncode != 0: |
| err = [] |
| err.append('failed to execute shell command: %s' % self.cmd) |
| err.append('return code: %s' % self.process.returncode) |
| err.append('stdout: %s' % self.stdout) |
| err.append('stderr: %s' % self.stderr) |
| raise ShellError('\n'.join(err)) |
| |
| self.return_code = self.process.returncode |
| return self.stdout |
| |
| class Daemon(object): |
| """ |
| A generic daemon class. |
| |
| Usage: subclass the Daemon class and override the run() method |
| """
|
| atexit_hooks = []
|
| |
| def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): |
| self.stdin = stdin |
| self.stdout = stdout |
| self.stderr = stderr |
| self.pidfile = pidfile |
|
|
| @staticmethod
|
| def register_atexit_hook(hook):
|
| Daemon.atexit_hooks.append(hook)
|
|
|
| @staticmethod |
| def _atexit():
|
| for hook in Daemon.atexit_hooks:
|
| try:
|
| hook() |
| except Exception:
|
| content = traceback.format_exc() |
| err = 'Exception when calling atexit hook[%s]\n%s' % (hook.__name__, content)
|
| #logger.error(err)
|
| |
| 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, e: |
| sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) |
| 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, e: |
| sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) |
| sys.exit(1) |
| |
| # redirect standard file descriptors |
| sys.stdout.flush() |
| sys.stderr.flush() |
| si = file(self.stdin, 'r') |
| so = file(self.stdout, 'a+') |
| se = file(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 |
| Daemon.register_atexit_hook(self.delpid) |
| atexit.register(Daemon._atexit)
|
| pid = str(os.getpid()) |
| file(self.pidfile,'w').write("%s\n" % pid) |
| |
| def delpid(self): |
| os.remove(self.pidfile) |
| |
| def start(self): |
| """ |
| Start the daemon |
| """ |
| # Check for a pidfile to see if the daemon already runs |
| try: |
| pf = file(self.pidfile,'r') |
| pid = int(pf.read().strip()) |
| pf.close() |
| except IOError: |
| pid = None |
| |
| if pid: |
| pscmd = ShellCmd('ps -p %s > /dev/null' % pid) |
| pscmd(is_exception=False) |
| if pscmd.return_code == 0: |
| message = "Daemon already running, pid is %s\n" |
| sys.stderr.write(message % pid) |
| sys.exit(0) |
| |
| # Start the daemon |
| self.daemonize()
|
| try: |
| self.run()
|
| except Exception:
|
| content = traceback.format_exc()
|
| #logger.error(content)
|
| sys.exit(1) |
| |
| def stop(self): |
| """ |
| Stop the daemon |
| """ |
| # Get the pid from the pidfile |
| try: |
| pf = file(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, 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) |
| |
| def restart(self): |
| """ |
| Restart the daemon |
| """ |
| self.stop() |
| self.start() |
| |
| 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(). |
| """ |