[Zope-Checkins] CVS: Zope/lib/python/Zope/Startup/nt - NTService.py:1.4 __init__.py:1.4

Fred L. Drake, Jr. fred@zope.com
Tue, 18 Mar 2003 16:49:06 -0500


Update of /cvs-repository/Zope/lib/python/Zope/Startup/nt
In directory cvs.zope.org:/tmp/cvs-serv29129/nt

Added Files:
	NTService.py __init__.py 
Log Message:
Merging new-install-branch: NT service support; needs testing.

=== Zope/lib/python/Zope/Startup/nt/NTService.py 1.3 => 1.4 ===
--- /dev/null	Tue Mar 18 16:49:06 2003
+++ Zope/lib/python/Zope/Startup/nt/NTService.py	Tue Mar 18 16:49:06 2003
@@ -0,0 +1,241 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""
+ZServer as a NT service.
+
+The serice starts up and monitors a ZServer process.
+
+Features:
+
+  * When you start the service it starts ZServer
+  * When you stop the serivice it stops ZServer
+  * It monitors ZServer and restarts it if it exits abnormally
+  * If ZServer is shutdown from the web, the service stops.
+  * If ZServer cannot be restarted, the service stops.
+
+Usage:
+
+  Installation
+
+    The ZServer service should be installed by the Zope Windows
+    installer. You can manually install, uninstall the service from
+    the commandline.
+
+      ZService.py [options] install|update|remove|start [...]
+          |stop|restart [...]|debug [...]
+
+    Options for 'install' and 'update' commands only:
+
+     --username domain\username : The Username the service is to run
+                                  under
+
+     --password password : The password for the username
+
+     --startup [manual|auto|disabled] : How the service starts,
+                                        default = manual
+
+    Commands
+
+      install : Installs the service
+
+      update : Updates the service, use this when you change
+               ZServer.py
+
+      remove : Removes the service
+
+      start : Starts the service, this can also be done from the
+              services control panel
+
+      stop : Stops the service, this can also be done from the
+             services control panel
+
+      restart : Restarts the service
+
+      debug : Runs the service in debug mode
+
+    You can view the usage options by running ZServer.py without any
+    arguments.
+
+    Note: you may have to register the Python service program first,
+
+      win32\pythonservice.exe /register
+
+  Starting Zope
+
+    Start Zope by clicking the 'start' button in the services control
+    panel. You can set Zope to automatically start at boot time by
+    choosing 'Auto' startup by clicking the 'statup' button.
+
+  Stopping Zope
+
+    Stop Zope by clicking the 'stop' button in the services control
+    panel. You can also stop Zope through the web by going to the
+    Zope control panel and by clicking 'Shutdown'.
+
+  Event logging
+
+    Zope events are logged to the NT application event log. Use the
+    event viewer to keep track of Zope events.
+
+  Registry Settings
+
+    You can change how the service starts ZServer by editing a registry
+    key.
+
+      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\
+        <Service Name>\Parameters\start
+
+    The value of this key is the command which the service uses to
+    start ZServer. For example:
+
+      "C:\Program Files\Zope\bin\python.exe"
+        "C:\Program Files\Zope\z2.py" -w 8888
+
+
+TODO:
+
+  * Integrate it into the Windows installer.
+  * Add ZLOG logging in addition to event log logging.
+  * Make it easier to run multiple Zope services with one Zope install
+
+This script does for NT the same sort of thing zdaemon.py does for UNIX.
+Requires Python win32api extensions.
+"""
+__version__ = '$Revision$'[11:-2]
+import sys, os,  time, imp, getopt
+import win32api
+def magic_import(modulename, filename):
+    # by Mark Hammond
+    try:
+        # See if it does import first!
+        return __import__(modulename)
+    except ImportError:
+        pass
+    # win32 can find the DLL name.
+    h = win32api.LoadLibrary(filename)
+    found = win32api.GetModuleFileName(h)
+    # Python can load the module
+    mod = imp.load_module(modulename, None, found, ('.dll', 'rb',
+                                                    imp.C_EXTENSION))
+    # inject it into the global module list.
+    sys.modules[modulename] = mod
+    # And finally inject it into the namespace.
+    globals()[modulename] = mod
+    win32api.FreeLibrary(h)
+
+magic_import('pywintypes','pywintypes21.dll')
+
+import win32serviceutil, win32service, win32event, win32process
+# servicemanager comes as a builtin if we're running via PythonService.exe,
+# but it's not available outside
+try:
+    import servicemanager
+except:
+    pass
+
+class NTService(win32serviceutil.ServiceFramework):
+
+    # Some trickery to determine the service name. The WISE
+    # installer will write an svcname.txt to the ZServer dir
+    # that we can use to figure out our service name.
+
+    restart_min_time=5 # if ZServer restarts before this many
+                       # seconds then we have a problem, and
+                       # need to stop the service.
+
+    _svc_name_= 'Zope'
+    _svc_display_name_ = _svc_name_
+
+    def __init__(self, args):
+        win32serviceutil.ServiceFramework.__init__(self, args)
+        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
+
+    def SvcDoRun(self):
+        self.start_zserver()
+        while 1:
+            rc=win32event.WaitForMultipleObjects(
+                    (self.hWaitStop, self.hZServer), 0, win32event.INFINITE)
+            if rc - win32event.WAIT_OBJECT_0 == 0:
+                break
+            else:
+                self.restart_zserver()
+        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING, 5000)
+
+    def SvcStop(self):
+        servicemanager.LogInfoMsg('Stopping Zope.')
+        try:
+            self.stop_zserver()
+        except:
+            pass
+        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
+        win32event.SetEvent(self.hWaitStop)
+
+    def restart_zserver(self):
+        if time.time() - self.last_start_time < self.restart_min_time:
+            servicemanager.LogErrorMsg('Zope died and could not be restarted.')
+            self.SvcStop()
+        code=win32process.GetExitCodeProcess(self.hZServer)
+        if code == 0:
+            # Exited with a normal status code,
+            # assume that shutdown is intentional.
+            self.SvcStop()
+        else:
+            servicemanager.LogWarningMsg('Restarting Zope.')
+            self.start_zserver()
+
+    def start_zserver(self):
+        sc=self.get_start_command()
+        result=win32process.CreateProcess(None, sc,
+                None, None, 0, 0, None, None, win32process.STARTUPINFO())
+        self.hZServer=result[0]
+        self.last_start_time=time.time()
+        servicemanager.LogInfoMsg('Starting Zope.')
+
+    def stop_zserver(self):
+        try:
+            win32process.TerminateProcess(self.hZServer,0)
+        except:
+            pass
+        result=win32process.CreateProcess(None, self.get_stop_command(),
+                None, None, 0, 0, None, None, win32process.STARTUPINFO())
+        return result
+
+    def get_start_command(self):
+        return win32serviceutil.GetServiceCustomOption(self,'start', None)
+
+    def get_stop_command(self):
+        cmd =  win32serviceutil.GetServiceCustomOption(self,'stop', None)
+
+def set_start_command(value):
+    "sets the ZServer start command if the start command is not already set"
+    current=win32serviceutil.GetServiceCustomOption(NTService,
+                                                    'start', None)
+    if current is None:
+        win32serviceutil.SetServiceCustomOption(NTService,'start',value)
+
+def set_stop_command(value):
+    "sets the ZServer start command if the start command is not already set"
+    current=win32serviceutil.GetServiceCustomOption(NTService,
+                                                    'stop', None)
+    if current is None:
+        win32serviceutil.SetServiceCustomOption(NTService,'stop',value)
+
+if __name__=='__main__':
+    dn = os.path.dirname
+    zope_home = dn(dn(dn(dn(sys.argv[0]))))
+    win32serviceutil.HandleCommandLine(ZServerService)
+    if 'install' in args:
+        command='"%s" "%s"' % (sys.executable,
+                               os.path.join(zope_home, 'bin', 'zope.py'))
+        set_start_command(command)
+        print "Setting Zope start command to:", command


=== Zope/lib/python/Zope/Startup/nt/__init__.py 1.3 => 1.4 ===
--- /dev/null	Tue Mar 18 16:49:06 2003
+++ Zope/lib/python/Zope/Startup/nt/__init__.py	Tue Mar 18 16:49:06 2003
@@ -0,0 +1 @@
+""" Placeholder module file """