diff options
author | Robert Brewer <fumanchu@aminus.org> | 2008-03-18 17:47:35 +0000 |
---|---|---|
committer | Robert Brewer <fumanchu@aminus.org> | 2008-03-18 17:47:35 +0000 |
commit | 573102df129892f925b349ebf24ec580c2527547 (patch) | |
tree | 70e5ee5f7900df15a6c8a4b83375b1fd574a4c3f | |
parent | 8f61db36c144df4eb3765676e14866f621f8f08d (diff) | |
download | cherrypy-573102df129892f925b349ebf24ec580c2527547.tar.gz |
Working cherryd daemon script. New FlupFCGIServer wrapper in servers.py. Also added a config arg to cherrypy.Application.
-rw-r--r-- | cherrypy/_cpconfig.py | 4 | ||||
-rw-r--r-- | cherrypy/_cptree.py | 4 | ||||
-rw-r--r-- | cherrypy/cherryd | 66 | ||||
-rw-r--r-- | cherrypy/cherryd.py | 87 | ||||
-rw-r--r-- | cherrypy/process/restctl.sh | 71 | ||||
-rw-r--r-- | cherrypy/process/restd.py | 69 | ||||
-rw-r--r-- | cherrypy/process/servers.py | 32 | ||||
-rw-r--r-- | cherrypy/scaffold/__init__.py | 2 | ||||
-rw-r--r-- | cherrypy/scaffold/cpdeploy.py | 49 | ||||
-rw-r--r-- | cherrypy/scaffold/example.conf | 8 | ||||
-rw-r--r-- | cherrypy/scaffold/site.conf | 8 |
11 files changed, 113 insertions, 287 deletions
diff --git a/cherrypy/_cpconfig.py b/cherrypy/_cpconfig.py index fcc74334..aeaec512 100644 --- a/cherrypy/_cpconfig.py +++ b/cherrypy/_cpconfig.py @@ -65,6 +65,8 @@ Current namespaces: engine: Controls the 'application engine', including autoreload. These can only be declared in the global config. + tree: Grafts cherrypy.Application objects onto cherrypy.tree. + These can only be declared in the global config. hooks: Declares additional request-processing functions. log: Configures the logging for each application. These can only be declared in the global or / config. @@ -314,7 +316,7 @@ Config.namespaces["engine"] = _engine_namespace_handler def _tree_namespace_handler(k, v): """Namespace handler for the 'tree' config namespace.""" cherrypy.tree.graft(v, v.script_name) - cherrypy.engine.log("Mounted: %s on %s" % (v, v.script_name)) + cherrypy.engine.log("Mounted: %s on %s" % (v, v.script_name or "/")) Config.namespaces["tree"] = _tree_namespace_handler diff --git a/cherrypy/_cptree.py b/cherrypy/_cptree.py index f074c0e6..a58a5267 100644 --- a/cherrypy/_cptree.py +++ b/cherrypy/_cptree.py @@ -45,7 +45,7 @@ class Application(object): relative_urls = False - def __init__(self, root, script_name=""): + def __init__(self, root, script_name="", config=None): self.log = _cplogging.LogManager(id(self), cherrypy.log.logger_root) self.root = root self.script_name = script_name @@ -56,6 +56,8 @@ class Application(object): self.namespaces["wsgi"] = self.wsgiapp.namespace_handler self.config = self.__class__.config.copy() + if config: + self.merge(config) def __repr__(self): return "%s.%s(%r, %r)" % (self.__module__, self.__class__.__name__, diff --git a/cherrypy/cherryd b/cherrypy/cherryd new file mode 100644 index 00000000..9d6402b0 --- /dev/null +++ b/cherrypy/cherryd @@ -0,0 +1,66 @@ +#! /usr/bin/env python +"""The CherryPy daemon.""" + +import cherrypy +from cherrypy.process import plugins, servers + + +def start(configfile=None, daemonize=False, environment=None, + fastcgi=False, pidfile=None): + """Subscribe all engine plugins and start the engine.""" + if configfile: + cherrypy.config.update(configfile) + + engine = cherrypy.engine + + if environment is not None: + cherrypy.config.update({'environment': environment}) + + # Only daemonize if asked to. + if daemonize: + # Don't print anything to stdout/sterr. + cherrypy.config.update({'log.screen': False}) + plugins.Daemonizer(engine).subscribe() + + if pidfile: + plugins.PIDFile(engine, pidfile).subscribe() + + cherrypy.signal_handler.subscribe() + + if fastcgi: + # turn off autoreload when using fastcgi + cherrypy.config.update({'autoreload.on': False}) + + cherrypy.server.unsubscribe() + + fastcgi_port = cherrypy.config.get('server.socket_port', 4000) + fastcgi_bindaddr = cherrypy.config.get('server.socket_host', '0.0.0.0') + bindAddress = (fastcgi_bindaddr, fastcgi_port) + f = servers.FlupFCGIServer(application=cherrypy.tree, bindAddress=bindAddress) + s = servers.ServerAdapter(engine, httpserver=f, bind_addr=bindAddress) + s.subscribe() + + # Always start the engine; this will start all other services + engine.start() + engine.block() + + +if __name__ == '__main__': + from optparse import OptionParser + + p = OptionParser() + p.add_option('-c', '--config', dest='config', + help="specify a config file") + p.add_option('-d', action="store_true", dest='daemonize', + help="run the server as a daemon") + p.add_option('-e', '--environment', dest='environment', default=None, + help="apply the given config environment") + p.add_option('-f', action="store_true", dest='fastcgi', + help="start a fastcgi server instead of the default HTTP server") + p.add_option('-p', '--pidfile', dest='pidfile', default=None, + help="store the process id in the given file") + options, args = p.parse_args() + + start(options.config, options.daemonize, + options.environment, options.fastcgi, options.pidfile) + diff --git a/cherrypy/cherryd.py b/cherrypy/cherryd.py deleted file mode 100644 index 011fa353..00000000 --- a/cherrypy/cherryd.py +++ /dev/null @@ -1,87 +0,0 @@ -#! /usr/bin/env python -"""The CherryPy daemon.""" - -import getopt -import sys - -import cherrypy -from cherrypy.process import plugins - - -shortopts = ["d", "e"] -longopts = [] - -# Help for restd command-line options. -help = """ -cherryd. Start the cherrypy daemon. - -Usage: - cherryd <config filename> - -""" - - -def start(options, configfile, *args): - engine = cherrypy.engine - - siteconf = {} - cherrypy._cpconfig.merge(siteconf, configfile) - - cherrypy.config.update(configfile) - - if options.has_key('-e'): - cherrypy.config.update({'environment': options['-e']}) - - # TODO: Make sure that log files are configurable from the conf file. - - # Only daemonize if asked to. - if options.has_key('-d'): - # Don't print anything to stdout/sterr. - cherrypy.config.update({'log.screen': False}) - plugins.Daemonizer(engine).subscribe() - - if options.has_key('--pidfile'): - plugins.PIDFile(engine, options['--pidfile']).subscribe() - - cherrypy.signal_handler.subscribe() - - # TODO: call a 'site setup' function (probably passing it siteconf). - - if options.has_key('--fastcgi'): - # turn off autoreload when using fastcgi - cherrypy.config.update({'autoreload.on': False}) - - cherrypy.server.unsubscribe() - - fastcgi_port = cherrypy.config.get('server.socket_port', 4000) - fastcgi_bindaddr = cherrypy.config.get('server.socket_host', '0.0.0.0') - bindAddress = (fastcgi_bindaddr, fastcgi_port) - try: - # Always start the engine; this will start all other services - engine.start() - - from flup.server.fcgi import WSGIServer - engine.log('Serving FastCGI on %s:%d' % bindAddress) - engine.fcgi = WSGIServer(application=wsgiapp, - bindAddress=bindAddress) - engine.fcgi.run() - engine.log('FastCGI Server on %s:%d shut down' % bindAddress) - finally: - engine.stop() - else: - # Always start the engine; this will start all other services - s = cherrypy.server - s.httpserver, s.bind_addr = s.httpserver_from_self() - s.httpserver.wsgi_app = wsgiapp - engine.start() - engine.block() - - -if __name__ == '__main__': - try: - opts, args = getopt.getopt(sys.argv[1:], shortopts, longopts) - except getopt.GetoptError: - print help - sys.exit(2) - - start(dict(opts), *tuple(args)) diff --git a/cherrypy/process/restctl.sh b/cherrypy/process/restctl.sh deleted file mode 100644 index cbdf8a6c..00000000 --- a/cherrypy/process/restctl.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/sh
-#
-# Control script for the restsrv daemon
-
-ERROR=0
-PYTHON=python
-RESTD=restd.py
-PIDFILE=/var/log/restsrv/restd.pid
-
-# Determine if restsrv is already running.
-RUNNING=0
-if [ -f $PIDFILE ]; then
- PID=`cat $PIDFILE`
- if [ "x$PID" != "x" ]; then
- if kill -0 $PID 2>/dev/null ; then
- # a process using PID is running
- if ps -p $PID -o args | grep restsrv > /dev/null 2>&1; then
- # that process is restsrv itself
- RUNNING=1
- fi
- fi
- fi
- if ["$RUNNING" = "0"]; then
- STATUS="restsrv (stale pid file removed) not running"
- rm -f $PIDFILE
- fi
-else
- STATUS="restsrv (no pid) not running"
-fi
-
-ARGS=""
-COMMAND=""
-for ARG in $@; do
- case $ARG in
- start|stop|restart|graceful|status)
- COMMAND=$ARG
- ;;
- *)
- ARGS="$ARGS $ARG"
- esac
- fi
-done
-
-case $COMMAND in
-start)
- echo "Starting restd"
- $RESTD $ARGS
- ERROR=$?
- ;;
-stop)
- echo "Stopping restd"
- kill -TERM `cat $PIDFILE`
- ERROR=$?
- ;;
-restart)
- echo "Restarting restd"
- kill -HUP `cat $PIDFILE`
- ;;
-graceful)
- echo "Gracefully restarting restd"
- kill -USR1 `cat $PIDFILE`
- ;;
-status)
- echo $STATUS
- ;;
-*)
- $RESTD $ARGS
- ERROR=$?
-esac
-
-exit $ERROR
\ No newline at end of file diff --git a/cherrypy/process/restd.py b/cherrypy/process/restd.py deleted file mode 100644 index b1f3ac79..00000000 --- a/cherrypy/process/restd.py +++ /dev/null @@ -1,69 +0,0 @@ -"""The restsrv daemon.""" - -import getopt -import sys - -from cherrypy import restsrv - - -class _Optionset(object): - host = '0.0.0.0' - port = 80 - protocol = 'HTTP/1.1' - scheme = 'http' -options = _Optionset() - -shortopts = [] -longopts = [ - # someday: 'cover', 'profile', 'validate', 'conquer', - 'host=', 'port=', '1.0', 'ssl', - 'project=', 'help', - ] - - -def help(): - """Print help for restd command-line options.""" - - print """ -restd. Start the restsrv daemon. - -Usage: - restd [options] - -Options: - --host=<name or IP addr>: use a host other than the default (%s). - --port=<int>: use a port other than the default (%s) - --1.0: use HTTP/1.0 servers instead of default HTTP/1.1 - --ssl: use HTTPS instead of default HTTP - --project=<module name>: import a module to set up the project - --help: print this usage message and exit -""" % (options.host, options.port) - - -def start(opts): - if '--project' in opts: - # delay import until after daemonize has a chance to run - def _import(): - __import__(opts['--project'], {}, {}, ['']) - _import.priority = 20 - restsrv.bus.subscribe('start', _import) - - if 'win' not in sys.platform: - restsrv.bus.subscribe('start', restsrv.plugins.daemonize) - - restsrv.bus.start() - restsrv.bus.block() - - -if __name__ == '__main__': - try: - opts, args = getopt.getopt(sys.argv[1:], shortopts, longopts) - except getopt.GetoptError: - help() - sys.exit(2) - - if "--help" in opts: - help() - sys.exit(0) - - start(dict(opts)) diff --git a/cherrypy/process/servers.py b/cherrypy/process/servers.py index 8405b529..0181d83c 100644 --- a/cherrypy/process/servers.py +++ b/cherrypy/process/servers.py @@ -121,6 +121,38 @@ class ServerAdapter(object): self.start() +class FlupFCGIServer(object): + """Adapter for a flup.server.fcgi.WSGIServer.""" + + def __init__(self, *args, **kwargs): + from flup.server.fcgi import WSGIServer + self.fcgiserver = WSGIServer(*args, **kwargs) + # TODO: report this bug upstream to flup. + # If we don't set _oldSIGs on Windows, we get: + # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", + # line 108, in run + # self._restoreSignalHandlers() + # File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py", + # line 156, in _restoreSignalHandlers + # for signum,handler in self._oldSIGs: + # AttributeError: 'WSGIServer' object has no attribute '_oldSIGs' + self.fcgiserver._oldSIGs = [] + self.ready = False + + def start(self): + """Start the FCGI server.""" + self.ready = True + self.fcgiserver.run() + + def stop(self): + """Stop the HTTP server.""" + self.ready = False + # Forcibly stop the fcgi server main event loop. + self.fcgiserver._keepGoing = False + # Force all worker threads to die off. + self.fcgiserver._threadPool.maxSpare = 0 + + def client_host(server_host): """Return the host on which a client can connect to the given listener.""" if server_host == '0.0.0.0': diff --git a/cherrypy/scaffold/__init__.py b/cherrypy/scaffold/__init__.py index cc5f1df8..026267ae 100644 --- a/cherrypy/scaffold/__init__.py +++ b/cherrypy/scaffold/__init__.py @@ -8,7 +8,7 @@ then tweak as desired. Even before any tweaking, this should serve a few demonstration pages. Change to this directory and run: - python cpdeploy.py --config=example.conf + python cherrypy\cherryd cherrypy\scaffold\site.conf """ diff --git a/cherrypy/scaffold/cpdeploy.py b/cherrypy/scaffold/cpdeploy.py deleted file mode 100644 index 1fc9378a..00000000 --- a/cherrypy/scaffold/cpdeploy.py +++ /dev/null @@ -1,49 +0,0 @@ -#! /usr/bin/env python -"""Deployment script for <MyProject> (a CherryPy application). - -Run this from the command-line and give it a --config argument: - - python cpdeploy.py --config=example.conf - -""" - -import os -local_dir = os.path.join(os.getcwd(), os.path.dirname(__file__)) - -import cherrypy -from cherrypy.process.plugins import Daemonizer, PIDFile - -# TODO: Change this to import your project root. -from cherrypy import scaffold - - -if __name__ == "__main__": - from optparse import OptionParser - - p = OptionParser() - p.add_option('-c', '--config', dest='config_file', - help="specify a config file") - p.add_option('-D', '--daemonize', action="store_true", dest='daemonize', - help="run the server as a daemon") - options, args = p.parse_args() - cherrypy.config.update(options.config_file) - - # Only daemonize if asked to. - if options.daemonize: - # Don't print anything to stdout/sterr. - cherrypy.config.update({'log.screen': False}) - - d = Daemonizer(cherrypy.engine) - d.subscribe() - - pidfile = cherrypy.config.get('pidfile') - if pidfile: - PIDFile(cherrypy.engine, pidfile).subscribe() - - # You can replace the next 4 lines with: - # cherrypy.quickstart(scaffold.root, "/", options.config_file) - cherrypy.signal_handler.subscribe() - cherrypy.tree.mount(scaffold.root, "/", options.config_file) - cherrypy.engine.start() - cherrypy.engine.block() - diff --git a/cherrypy/scaffold/example.conf b/cherrypy/scaffold/example.conf index ca3dc112..93a6e53c 100644 --- a/cherrypy/scaffold/example.conf +++ b/cherrypy/scaffold/example.conf @@ -1,11 +1,3 @@ -[global] -# Uncomment this when you're done developing -#environment: "production" - -server.socket_host: "0.0.0.0" -server.socket_port: 8088 - - [/] log.error_file: "error.log" log.access_file: "access.log"
\ No newline at end of file diff --git a/cherrypy/scaffold/site.conf b/cherrypy/scaffold/site.conf new file mode 100644 index 00000000..6fc8f4ec --- /dev/null +++ b/cherrypy/scaffold/site.conf @@ -0,0 +1,8 @@ +[global] +# Uncomment this when you're done developing +#environment: "production" + +server.socket_host: "0.0.0.0" +server.socket_port: 8088 + +tree.myapp: cherrypy.Application(scaffold.root, "/", "cherrypy/scaffold/example.conf") |