Commit 09aa563f authored by Jeremy Hylton's avatar Jeremy Hylton

Checkpoint of wrapper for uncoperative programs.

Adds an option to spawn a process and capture its I/O.  Just a
checkpoint because it doesn't do anything with the captured I/O yet.
parent f6a3ddd7
...@@ -14,10 +14,15 @@ ...@@ -14,10 +14,15 @@
"""Windows Services installer/controller for Zope/ZEO/ZRS instance homes""" """Windows Services installer/controller for Zope/ZEO/ZRS instance homes"""
import win32serviceutil import win32api
import win32service import win32con
import win32event import win32event
import win32file
import win32pipe
import win32process import win32process
import win32security
import win32service
import win32serviceutil
import pywintypes import pywintypes
import time import time
import os import os
...@@ -49,6 +54,9 @@ class Service(win32serviceutil.ServiceFramework): ...@@ -49,6 +54,9 @@ class Service(win32serviceutil.ServiceFramework):
r'"C:\Program Files\Zope-2.7.0-a1\lib\python\Zope\Startup\run.py" ' r'"C:\Program Files\Zope-2.7.0-a1\lib\python\Zope\Startup\run.py" '
r'-C "C:\Zope-Instance\etc\zope.conf"' r'-C "C:\Zope-Instance\etc\zope.conf"'
) )
capture_io = False
log_file = None
def __init__(self, args): def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args) win32serviceutil.ServiceFramework.__init__(self, args)
...@@ -69,9 +77,12 @@ class Service(win32serviceutil.ServiceFramework): ...@@ -69,9 +77,12 @@ class Service(win32serviceutil.ServiceFramework):
win32event.SetEvent(self.hWaitStop) win32event.SetEvent(self.hWaitStop)
def createProcess(self, cmd): def createProcess(self, cmd):
return win32process.CreateProcess( if self.capture_io:
None, cmd, None, None, 0, 0, None, None, return self.createProcessCaptureIO(cmd)
win32process.STARTUPINFO()) else:
return win32process.CreateProcess(
None, cmd, None, None, 0, 0, None, None,
win32process.STARTUPINFO()), None
def logmsg(self, event): def logmsg(self, event):
# log a service event using servicemanager.LogMsg # log a service event using servicemanager.LogMsg
...@@ -124,12 +135,14 @@ class Service(win32serviceutil.ServiceFramework): ...@@ -124,12 +135,14 @@ class Service(win32serviceutil.ServiceFramework):
while 1: while 1:
start_time = time.time() start_time = time.time()
info = self.createProcess(self.start_cmd) info, handles = self.createProcess(self.start_cmd)
# XXX integrate handles into the wait and make a loop
# that reads data and writes it into a logfile
self.hZope = info[0] # the pid self.hZope = info[0] # the pid
if backoff_interval > BACKOFF_INITIAL_INTERVAL: if backoff_interval > BACKOFF_INITIAL_INTERVAL:
self.info("created process") self.info("created process")
rc = win32event.WaitForMultipleObjects( rc = win32event.WaitForMultipleObjects(
(self.hWaitStop, self.hZope), 0, win32event.INFINITE) (self.hWaitStop, self.hZope) + handles, 0, win32event.INFINITE)
if rc == win32event.WAIT_OBJECT_0: if rc == win32event.WAIT_OBJECT_0:
# user sent a stop service request # user sent a stop service request
self.SvcStop() self.SvcStop()
...@@ -161,8 +174,51 @@ class Service(win32serviceutil.ServiceFramework): ...@@ -161,8 +174,51 @@ class Service(win32serviceutil.ServiceFramework):
backoff_cumulative += backoff_interval backoff_cumulative += backoff_interval
backoff_interval *= 2 backoff_interval *= 2
self.logmsg(servicemanager.PYS_SERVICE_STOPPED) self.logmsg(servicemanager.PYS_SERVICE_STOPPED)
def createProcessCaptureIO(self, cmd):
stdin = self.newPipe()
stdout = self.newPipe()
stderr = self.newPipe()
si = win32process.STARTUPINFO()
si.hStdInput = stdin[0]
si.hStdOutput = stdout[1]
si.hStdError = stderr[1]
si.dwFlags = (win32process.STARTF_USESTDHANDLES
| win32process.STARTF_USESHOWWINDOW)
si.wShowWindow = win32con.SW_HIDE
c_stdin = self.dup(stdin[1])
c_stdout = self.dup(stdout[0])
c_stderr = self.dup(stderr[0])
# pass True to allow handles to be inherited. Inheritance is
# problematic in general, but should work in the controlled
# circumstances of a service process.
info = win32process.CreateProcess(None, cmd, None, None, True, 0,
None, None, si)
win32file.CloseHandle(stdin[0])
win32file.CloseHandle(stdout[1])
win32file.CloseHandle(stderr[1])
return info, (c_stdin, c_stdout, c_stderr)
def newPipe(self):
sa = win32security.SECURITY_ATTRIBUTES()
sa.bInheritHandle = True
return win32pipe.CreatePipe(sa, 0)
def dup(self, pipe):
# create a duplicate handle that is not inherited, so that
# it can be closed in the parent. close the original pipe in
# the process.
pid = win32api.GetCurrentProcess()
dup = win32api.DuplicateHandle(pid, pipe, pid, 0, 0,
win32con.DUPLICATE_SAME_ACCESS)
win32file.CloseHandle(pipe)
return dup
if __name__ == '__main__': if __name__ == '__main__':
win32serviceutil.HandleCommandLine(Service) win32serviceutil.HandleCommandLine(Service)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment