wcs/wcs/ctl/start.py

153 lines
5.6 KiB
Python

# w.c.s. - web application for online forms
# Copyright (C) 2005-2010 Entr'ouvert
#
# 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 2 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/>.
import os
import socket
import sys
import qommon.scgi_server
import quixote
import quixote.server.simple_server
from qommon.ctl import Command, make_option
class CmdStart(Command):
name = 'start'
def __init__(self):
Command.__init__(self, [
make_option('--port', metavar='PORT', action='store',
dest='port', default=3001),
make_option('--handler-connection-limit', metavar='LIMIT',
action='store',
dest='handler_connection_limit', default=None),
make_option('--script-name', metavar='NAME', action='store',
dest='script_name', default=None),
make_option('--http', action='store_true',
dest='http', default=False),
make_option('--silent', action='store_true',
dest='silent', default=False),
make_option('--daemonize', action='store_true',
dest='daemonize', default=False),
make_option('--pidfile', metavar='FILENAME',
dest='pidfile'),
make_option('--max-children', metavar='MAX_CHILDREN',
type='int', action='store', dest='max_children')
])
def make_silent(self):
sys.stdout.flush()
sys.stderr.flush()
si = file('/dev/null', 'r')
so = file('/dev/null', 'a+')
se = file('/dev/null', 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
def del_pid(self):
if not hasattr(self, 'pidfile'):
return
try:
os.remove(self.pidfile)
except OSError:
pass
def execute(self, base_options, sub_options, args):
import publisher
run_kwargs = {}
run_kwargs['port'] = int(sub_options.port)
run_kwargs['spawn_cron'] = True
run_function = qommon.scgi_server.run
publisher.WcsPublisher.configure(self.config)
if sub_options.handler_connection_limit:
run_kwargs['handler_connection_limit'] = int(sub_options.handler_connection_limit)
elif self.config.has_option('main', 'handler_connection_limit'):
run_kwargs['handler_connection_limit'] = self.config.getint('main', 'handler_connection_limit')
if sub_options.script_name:
run_kwargs['script_name'] = sub_options.script_name
if sub_options.max_children:
run_kwargs['max_children'] = sub_options.max_children
elif self.config.has_option('main', 'max_children'):
run_kwargs['max_children'] = self.config.getint('main', 'max_children')
if sub_options.http:
run_function = qommon.scgi_server.http_run
if sub_options.silent:
self.make_silent()
# iterate over all tenants to execute required SQL migrations
# beforehand.
pub = publisher.WcsPublisher.create_publisher(register_cron=False)
quixote.cleanup()
base_app_dir = pub.app_dir
for hostname in publisher.WcsPublisher.get_tenants():
tenant_path = os.path.join(base_app_dir, hostname)
if not os.path.exists(os.path.join(tenant_path, 'config.pck')):
continue
pub = publisher.WcsPublisher.create_publisher(register_cron=False)
pub.app_dir = tenant_path
pub.set_config()
if pub.is_using_postgresql():
pub.migrate_sql()
pub.cleanup()
quixote.cleanup()
if sub_options.daemonize:
try:
pid = os.fork()
if pid > 0: # exit first parent
sys.exit(0)
except OSError, e:
print >> sys.stderr, 'failure in first fork (%s)' % e.strerror
sys.exit(1)
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:
print >> sys.stderr, 'failure in second fork (%s)' % e.strerror
sys.exit(1)
if not sub_options.silent:
self.make_silent()
if sub_options.pidfile:
self.pidfile = sub_options.pidfile
file(self.pidfile, 'w+').write("%s\n" % os.getpid())
try:
run_function(publisher.WcsPublisher.create_publisher, **run_kwargs)
except socket.error, e:
self.del_pid()
if e[0] == 98:
print >> sys.stderr, 'address already in use'
sys.exit(1)
raise
except KeyboardInterrupt:
self.del_pid()
sys.exit(1)
self.del_pid()
CmdStart.register()