Source

raa / raa-web-scgi

Full commit
#!/usr/bin/env python

#
# Copyright (c) 2006-2008 rPath, Inc.
# All rights reserved
#

import cherrypy
import fcntl
import logging
import os
from os.path import *
import sys, urllib
import raa.constants

import conary.lib.util

from cherrypy._cpwsgi       import wsgiApp

from raa.controllers import Root, loadConfig

from paste.util.scgiserver import SWAP
from scgi import scgi_server
from types import MethodType
import signal
import socket
import time

from raa.service import daemon
from raa.service import logger

class rAASCGIServer(scgi_server.SCGIServer):
    def hup_signal(self, signum, frame):
        scgi_server.SCGIServer.hup_signal(self, signum, frame)
        reexec(signum)

class rAAWebDaemon(daemon.Daemon):
    name = "raa"
    class Config(daemon.DaemonConfig):
        logPath = '/var/log/raa/'
        lockPath = '/var/run/raa/'
    cfgobject = Config
    server = None

    def loadConfiguration(self, cfgFile):
        pass

    def setupLogger(self, consoleLevel, logfileLevel):
        logFile = os.path.join(self.cfg.logPath, 'web')
        logger.setupLogger(logFile, consoleLevel, logfileLevel)

    def serve_application(self, application, prefix, port, host):
        #Handle older raa-web-scgi restarts that saved the socket
        sock = int(os.environ.get('RAA_WEB_SCGI_SOCKET', -1))
        if sock > 0:
            try:
                os.close(sock)
            except OSError:
                pass
        class rAASCGIAppHandler(SWAP):
            def serve(self, *args, **kwargs):
                #Clear the thread_data
                cherrypy.thread_data = cherrypy.local()
                return SWAP.serve(self, *args, **kwargs)

            def __init__(self, *args, **kwargs):
                self.prefix = prefix
                self.app_obj = application
                SWAP.__init__(self, *args, **kwargs)

            def read_env(self, input):
                # The original read_env is fine, but in order to support REDIRECT_URI, fix it up before returning
                # Remove this when deprecating the /rAA part of the URL can be completed.
                env = SWAP.read_env(self, input)
                if env.get('REDIRECT_URI', None) is not None:
                    env['ORIGINAL_URI'] = env['REQUEST_URI']
                    env['REQUEST_URI'] = env.get('REDIRECT_URI')
                return env

        self.server = rAASCGIServer(rAASCGIAppHandler, port=port, host=host)

        def stop(signalNum, frame):
            self.log.info("Signal %d caught: stopping service", signalNum)
            cherrypy.server.stop()
            self.server.do_stop()
            logging.shutdown()
            sys.exit()

        signal.signal(signal.SIGTERM, stop)
        #Don't register SIGHUP, the SCGI server handles that
        signal.signal(signal.SIGUSR1, self.server.hup_signal)

        loopcount = 0
        while True:
            try:
                self.server.serve()
                break
            except socket.error, e:
                if e.args[0] != 98:
                    raise
                else:
                    loopcount += 1
                    if loopcount > 4:
                        raise
                    time.sleep(1)

    def doWork(self):
        self.log.info('raa-web-scgi version %s starting', raa.constants.RAA_VERSION)
        cherrypy.tree.apps[''].root.init()

        # FIXME: hack to get access to not print to stdout.
        cherrypy.config.update({"tg.new_style_logging": True})

        # Start the server
        cherrypy.server.quickstart()
        cherrypy.engine.start(blocking=False)

        try:
            self.serve_application(application=wsgiApp, prefix="/", port=4000, host='127.0.0.1')
        except SystemExit:
            #We're running off the stack anyway, so just swallow it
            self.log.warning("SystemExit raised by SCGI server, exiting")


# Load the configuration before we fork.
loadConfig([x for x in sys.argv if not x.startswith('-')])
root = Root()
cherrypy.tree.mount(root)

# Fork off this process.
d = rAAWebDaemon('raa.web.scgi')

def reexec(signalNum):
    if os._urandomfd:
        fcntl.fcntl(os._urandomfd, fcntl.F_SETFD, 1)
    d.removeLock()
    d.log.info("Signal %d caught: restarting service", signalNum)
    cherrypy.server.stop()
    d.server.do_stop()
    logging.shutdown()
    #Close all open file descriptors
    for x in xrange(3, 1024):
        try:
            os.close(x)
        except:
            pass
    argv = sys.argv
    if '--no-daemon' not in argv and '-n' not in argv:
        argv.append('--no-daemon')
    os.execv(argv[0], argv)


d.main()