# HG changeset patch # User auc@giediprime.logilab.fr # Date 1260381713 -3600 # Node ID 3b12e4192983746a3db6cadd2c5a2f5e48a17aa4 # Parent d16b2927afe69bca974fa910e8c7d653dd5b1758 be able to run cw instances as windows services diff -r d16b2927afe6 -r 3b12e4192983 cwctl.py --- a/cwctl.py Tue Dec 08 19:25:35 2009 +0100 +++ b/cwctl.py Wed Dec 09 19:01:53 2009 +0100 @@ -12,7 +12,7 @@ def kill(*args): pass def getpgid(): pass -from os.path import exists, join, isfile, isdir +from os.path import exists, join, isfile, isdir, dirname, abspath from logilab.common.clcommands import register_commands, pop_arg from logilab.common.shellutils import ASK @@ -307,6 +307,7 @@ helper.bootstrap(cubes, self.config.config_level) # write down configuration config.save() + self._handle_win32(config, appid) print '-> generated %s' % config.main_config_file() # handle i18n files structure # in the first cube given @@ -332,6 +333,29 @@ print '\n-> creation done for %r.\n' % config.apphome helper.postcreate() + def _handle_win32(self, config, appid): + if sys.platform != 'win32': + return + service_template = """ +import sys +import win32serviceutil +sys.path.insert(0, r"%(CWPATH)s") + +from cubicweb.etwist.service import CWService + +classdict = {'_svc_name_': 'cubicweb-%(APPID)s', + '_svc_display_name_': 'CubicWeb ' + '%(CNAME)s', + 'instance': '%(APPID)s'} +%(CNAME)sService = type('%(CNAME)sService', (CWService,), classdict) + +if __name__ == '__main__': + win32serviceutil.HandleCommandLine(%(CNAME)sService) +""" + open(join(config.apphome, 'win32svc.py'), 'wb').write( + service_template % {'APPID': appid, + 'CNAME': appid.capitalize(), + 'CWPATH': abspath(join(dirname(__file__), '..'))}) + class DeleteInstanceCommand(Command): """Delete an instance. Will remove instance's files and diff -r d16b2927afe6 -r 3b12e4192983 etwist/service.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/etwist/service.py Wed Dec 09 19:01:53 2009 +0100 @@ -0,0 +1,63 @@ +import os +import os.path as osp +import sys + +import win32serviceutil +import win32service +import win32event + +from cubicweb.etwist.server import (CubicWebRootResource, reactor, server, + parsePOSTData, channel) + +from logging import getLogger, handlers +from cubicweb import set_log_methods +from cubicweb.cwconfig import CubicWebConfiguration as cwcfg + +logger = getLogger('cubicweb.twisted') +logger.handlers = [handlers.NTEventLogHandler('cubicweb')] + +os.environ['CW_INSTANCES_DIR'] = r'C:\etc\cubicweb.d' +os.environ['USERNAME'] = 'cubicweb' + + +class CWService(object, win32serviceutil.ServiceFramework): + _svc_name_ = None + _svc_display_name_ = None + instance = None + + def __init__(self, *args, **kwargs): + win32serviceutil.ServiceFramework.__init__(self, *args, **kwargs) + self._stop_event = win32event.CreateEvent(None, 0, 0, None) + cwcfg.load_cwctl_plugins() + set_log_methods(CubicWebRootResource, logger) + server.parsePOSTData = parsePOSTData + + def SvcStop(self): + self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) + logger.info('stopping %s service' % self.instance) + win32event.SetEvent(self._stop_event) + self.ReportServiceStatus(win32service.SERVICE_STOPPED) + + def SvcDoRun(self): + self.ReportServiceStatus(win32service.SERVICE_START_PENDING) + logger = getLogger('cubicweb.twisted') + logger.info('starting %s service' % instance) + try: + # create the site + config = cwcfg.config_for(self.instance) + root_resource = CubicWebRootResource(config, False) + website = server.Site(root_resource) + # serve it via standard HTTP on port set in the configuration + port = config['port'] or 8080 + logger.info('listening on port %s' % port) + reactor.listenTCP(port, channel.HTTPFactory(website)) + root_resource.init_publisher() + root_resource.start_service() + logger.info('instance started on %s', root_resource.base_url) + self.ReportServiceStatus(win32service.SERVICE_RUNNING) + reactor.run() + except Exception, e: + logger.error('service %s stopped (cause: %s)' % (self.instance, e)) + logger.exception('what happened ...') + self.SvcStop() +