0001 # General purpose service utilities, both for standard Python scripts, 0002 # and for for Python programs which run as services... 0003 # 0004 # Note that most utility functions here will raise win32api.error's 0005 # (which is == win32service.error, pywintypes.error, etc) 0006 # when things go wrong - eg, not enough permissions to hit the 0007 # registry etc. 0008 0009 import win32service, win32api, win32con, winerror 0010 import sys, string, pywintypes, os 0011 0012 error = "Python Service Utility Error" 0013 0014 def LocatePythonServiceExe(exeName = None): 0015 # Try and find the specified EXE somewhere. If specifically registered, 0016 # use it. Otherwise look down sys.path, and the global PATH environment. 0017 if exeName is None: 0018 if win32service.__file__.find("_d")>=0: 0019 exeName = "PythonService_d.exe" 0020 else: 0021 exeName = "PythonService.exe" 0022 # See if it exists as specified 0023 if os.path.isfile(exeName): return win32api.GetFullPathName(exeName) 0024 baseName = os.path.splitext(os.path.basename(exeName))[0] 0025 try: 0026 exeName = win32api.RegQueryValue(win32con.HKEY_LOCAL_MACHINE, 0027 "Software\\Python\\%s\\%s" % (baseName, sys.winver)) 0028 if os.path.isfile(exeName): 0029 return exeName 0030 raise RuntimeError, "The executable '%s' is registered as the Python " \ 0031 "service exe, but it does not exist as specified" \ 0032 % exeName 0033 except win32api.error: 0034 # OK - not there - lets go a-searchin' 0035 for path in sys.path: 0036 look = os.path.join(path, exeName) 0037 if os.path.isfile(look): 0038 return win32api.GetFullPathName(look) 0039 # Try the global Path. 0040 try: 0041 return win32api.SearchPath(None, exeName)[0] 0042 except win32api.error: 0043 msg = "%s is not correctly registered\nPlease locate and run %s, and it will self-register\nThen run this service registration process again." % (exeName, exeName) 0044 raise error, msg 0045 0046 def _GetServiceShortName(longName): 0047 # looks up a services name 0048 # from the display name 0049 # Thanks to Andy McKay for this code. 0050 access = win32con.KEY_READ | win32con.KEY_ENUMERATE_SUB_KEYS | win32con.KEY_QUERY_VALUE 0051 hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services", 0, access) 0052 num = win32api.RegQueryInfoKey(hkey)[0] 0053 # loop through number of subkeys 0054 for x in range(0, num): 0055 # find service name, open subkey 0056 svc = win32api.RegEnumKey(hkey, x) 0057 skey = win32api.RegOpenKey(hkey, svc, 0, access) 0058 try: 0059 # find short name 0060 shortName = str(win32api.RegQueryValueEx(skey, "DisplayName")[0]) 0061 if shortName == longName: 0062 return svc 0063 except win32api.error: 0064 # in case there is no key called DisplayName 0065 pass 0066 return None 0067 0068 # Open a service given either it's long or short name. 0069 def SmartOpenService(hscm, name, access): 0070 try: 0071 return win32service.OpenService(hscm, name, access) 0072 except win32api.error, details: 0073 if details[0]!=winerror.ERROR_SERVICE_DOES_NOT_EXIST: 0074 raise 0075 name = _GetServiceShortName(name) 0076 if name is None: 0077 raise 0078 return win32service.OpenService(hscm, name, access) 0079 0080 def LocateSpecificServiceExe(serviceName): 0081 # Given the name of a specific service, return the .EXE name _it_ uses 0082 # (which may or may not be the Python Service EXE 0083 hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\%s" % (serviceName), 0, win32con.KEY_ALL_ACCESS) 0084 try: 0085 return win32api.RegQueryValueEx(hkey, "ImagePath")[0] 0086 finally: 0087 hkey.Close() 0088 0089 def InstallPerfmonForService(serviceName, iniName, dllName = None): 0090 # If no DLL name, look it up in the INI file name 0091 if not dllName: # May be empty string! 0092 dllName = win32api.GetProfileVal("Python", "dll", "", iniName) 0093 # Still not found - look for the standard one in the same dir as win32service.pyd 0094 if not dllName: 0095 try: 0096 tryName = os.path.join(os.path.split(win32service.__file__)[0], "perfmondata.dll") 0097 if os.path.isfile(tryName): 0098 dllName = tryName 0099 except AttributeError: 0100 # Frozen app? - anyway, can't find it! 0101 pass 0102 if not dllName: 0103 raise ValueError, "The name of the performance DLL must be available" 0104 dllName = win32api.GetFullPathName(dllName) 0105 # Now setup all the required "Performance" entries. 0106 hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\%s" % (serviceName), 0, win32con.KEY_ALL_ACCESS) 0107 try: 0108 subKey = win32api.RegCreateKey(hkey, "Performance") 0109 try: 0110 win32api.RegSetValueEx(subKey, "Library", 0, win32con.REG_SZ, dllName) 0111 win32api.RegSetValueEx(subKey, "Open", 0, win32con.REG_SZ, "OpenPerformanceData") 0112 win32api.RegSetValueEx(subKey, "Close", 0, win32con.REG_SZ, "ClosePerformanceData") 0113 win32api.RegSetValueEx(subKey, "Collect", 0, win32con.REG_SZ, "CollectPerformanceData") 0114 finally: 0115 win32api.RegCloseKey(subKey) 0116 finally: 0117 win32api.RegCloseKey(hkey) 0118 # Now do the "Lodctr" thang... 0119 0120 try: 0121 import perfmon 0122 path, fname = os.path.split(iniName) 0123 oldPath = os.getcwd() 0124 if path: 0125 os.chdir(path) 0126 try: 0127 perfmon.LoadPerfCounterTextStrings("python.exe " + fname) 0128 finally: 0129 os.chdir(oldPath) 0130 except win32api.error, details: 0131 print "The service was installed OK, but the performance monitor" 0132 print "data could not be loaded.", details 0133 0134 def _GetCommandLine(exeName, exeArgs): 0135 if exeArgs is not None: 0136 return exeName + " " + exeArgs 0137 else: 0138 return exeName 0139 0140 def InstallService(pythonClassString, serviceName, displayName, startType = None, errorControl = None, bRunInteractive = 0, serviceDeps = None, userName = None, password = None, exeName = None, perfMonIni = None, perfMonDll = None, exeArgs = None): 0141 # Handle the default arguments. 0142 if startType is None: 0143 startType = win32service.SERVICE_DEMAND_START 0144 serviceType = win32service.SERVICE_WIN32_OWN_PROCESS 0145 if bRunInteractive: 0146 serviceType = serviceType | win32service.SERVICE_INTERACTIVE_PROCESS 0147 if errorControl is None: 0148 errorControl = win32service.SERVICE_ERROR_NORMAL 0149 0150 exeName = '"%s"' % LocatePythonServiceExe(exeName) # None here means use default PythonService.exe 0151 commandLine = _GetCommandLine(exeName, exeArgs) 0152 hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS) 0153 try: 0154 hs = win32service.CreateService(hscm, 0155 serviceName, 0156 displayName, 0157 win32service.SERVICE_ALL_ACCESS, # desired access 0158 serviceType, # service type 0159 startType, 0160 errorControl, # error control type 0161 commandLine, 0162 None, 0163 0, 0164 serviceDeps, 0165 userName, 0166 password) 0167 win32service.CloseServiceHandle(hs) 0168 finally: 0169 win32service.CloseServiceHandle(hscm) 0170 InstallPythonClassString(pythonClassString, serviceName) 0171 # If I have performance monitor info to install, do that. 0172 if perfMonIni is not None: 0173 InstallPerfmonForService(serviceName, perfMonIni, perfMonDll) 0174 0175 def ChangeServiceConfig(pythonClassString, serviceName, startType = None, errorControl = None, bRunInteractive = 0, serviceDeps = None, userName = None, password = None, exeName = None, displayName = None, perfMonIni = None, perfMonDll = None, exeArgs = None): 0176 # Before doing anything, remove any perfmon counters. 0177 try: 0178 import perfmon 0179 perfmon.UnloadPerfCounterTextStrings("python.exe "+serviceName) 0180 except (ImportError, win32api.error): 0181 pass 0182 0183 # The EXE location may have changed 0184 exeName = '"%s"' % LocatePythonServiceExe(exeName) 0185 0186 # Handle the default arguments. 0187 if startType is None: startType = win32service.SERVICE_NO_CHANGE 0188 if errorControl is None: errorControl = win32service.SERVICE_NO_CHANGE 0189 0190 hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS) 0191 serviceType = win32service.SERVICE_WIN32_OWN_PROCESS 0192 if bRunInteractive: 0193 serviceType = serviceType | win32service.SERVICE_INTERACTIVE_PROCESS 0194 commandLine = _GetCommandLine(exeName, exeArgs) 0195 try: 0196 hs = SmartOpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS) 0197 try: 0198 0199 win32service.ChangeServiceConfig(hs, 0200 serviceType, # service type 0201 startType, 0202 errorControl, # error control type 0203 commandLine, 0204 None, 0205 0, 0206 serviceDeps, 0207 userName, 0208 password, 0209 displayName) 0210 finally: 0211 win32service.CloseServiceHandle(hs) 0212 finally: 0213 win32service.CloseServiceHandle(hscm) 0214 InstallPythonClassString(pythonClassString, serviceName) 0215 # If I have performance monitor info to install, do that. 0216 if perfMonIni is not None: 0217 InstallPerfmonForService(serviceName, perfMonIni, perfMonDll) 0218 0219 def InstallPythonClassString(pythonClassString, serviceName): 0220 # Now setup our Python specific entries. 0221 if pythonClassString: 0222 key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\PythonClass" % serviceName) 0223 try: 0224 win32api.RegSetValue(key, None, win32con.REG_SZ, pythonClassString); 0225 finally: 0226 win32api.RegCloseKey(key) 0227 0228 # Utility functions for Services, to allow persistant properties. 0229 def SetServiceCustomOption(serviceName, option, value): 0230 try: 0231 serviceName = serviceName._svc_name_ 0232 except AttributeError: 0233 pass 0234 key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\Parameters" % serviceName) 0235 try: 0236 if type(value)==type(0): 0237 win32api.RegSetValueEx(key, option, 0, win32con.REG_DWORD, value); 0238 else: 0239 win32api.RegSetValueEx(key, option, 0, win32con.REG_SZ, value); 0240 finally: 0241 win32api.RegCloseKey(key) 0242 0243 def GetServiceCustomOption(serviceName, option, defaultValue = None): 0244 # First param may also be a service class/instance. 0245 # This allows services to pass "self" 0246 try: 0247 serviceName = serviceName._svc_name_ 0248 except AttributeError: 0249 pass 0250 key = win32api.RegCreateKey(win32con.HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\%s\\Parameters" % serviceName) 0251 try: 0252 try: 0253 return win32api.RegQueryValueEx(key, option)[0] 0254 except win32api.error: # No value. 0255 return defaultValue 0256 finally: 0257 win32api.RegCloseKey(key) 0258 0259 0260 def RemoveService(serviceName): 0261 try: 0262 import perfmon 0263 perfmon.UnloadPerfCounterTextStrings("python.exe "+serviceName) 0264 except (ImportError, win32api.error): 0265 pass 0266 0267 hscm = win32service.OpenSCManager(None,None,win32service.SC_MANAGER_ALL_ACCESS) 0268 try: 0269 hs = SmartOpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS) 0270 win32service.DeleteService(hs) 0271 win32service.CloseServiceHandle(hs) 0272 finally: 0273 win32service.CloseServiceHandle(hscm) 0274 0275 def ControlService(serviceName, code, machine = None): 0276 hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS) 0277 try: 0278 0279 hs = SmartOpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS) 0280 try: 0281 status = win32service.ControlService(hs, code) 0282 finally: 0283 win32service.CloseServiceHandle(hs) 0284 finally: 0285 win32service.CloseServiceHandle(hscm) 0286 return status 0287 0288 def __FindSvcDeps(findName): 0289 if type(findName) is pywintypes.UnicodeType: findName = str(findName) 0290 dict = {} 0291 k = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services") 0292 num = 0 0293 while 1: 0294 try: 0295 svc = win32api.RegEnumKey(k, num) 0296 except win32api.error: 0297 break 0298 num = num + 1 0299 sk = win32api.RegOpenKey(k, svc) 0300 try: 0301 deps, typ = win32api.RegQueryValueEx(sk, "DependOnService") 0302 except win32api.error: 0303 deps = () 0304 for dep in deps: 0305 dep = string.lower(dep) 0306 dep_on = dict.get(dep, []) 0307 dep_on.append(svc) 0308 dict[dep]=dep_on 0309 0310 return __ResolveDeps(findName, dict) 0311 0312 0313 def __ResolveDeps(findName, dict): 0314 items = dict.get(string.lower(findName), []) 0315 retList = [] 0316 for svc in items: 0317 retList.insert(0, svc) 0318 retList = __ResolveDeps(svc, dict) + retList 0319 return retList 0320 0321 def WaitForServiceStatus(serviceName, status, waitSecs, machine=None): 0322 """Waits for the service to return the specified status. You 0323 should have already requested the service to enter that state""" 0324 hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS) 0325 for i in range(waitSecs*4): 0326 now_status = QueryServiceStatus(serviceName)[1] 0327 if now_status == status: 0328 break 0329 win32api.Sleep(250) 0330 else: 0331 raise pywintypes.error, (winerror.ERROR_SERVICE_REQUEST_TIMEOUT, "QueryServiceStatus", win32api.FormatMessage(winerror.ERROR_SERVICE_REQUEST_TIMEOUT)[:-2]) 0332 0333 def __StopServiceWithTimeout(hs, waitSecs = 30): 0334 try: 0335 status = win32service.ControlService(hs, win32service.SERVICE_CONTROL_STOP) 0336 except pywintypes.error, (hr, name, msg): 0337 if hr!=winerror.ERROR_SERVICE_NOT_ACTIVE: 0338 raise win32service.error, (hr, name, msg) 0339 for i in range(waitSecs): 0340 status = win32service.QueryServiceStatus(hs) 0341 if status[1] == win32service.SERVICE_STOPPED: 0342 break 0343 win32api.Sleep(1000) 0344 else: 0345 raise pywintypes.error, (winerror.ERROR_SERVICE_REQUEST_TIMEOUT, "ControlService", win32api.FormatMessage(winerror.ERROR_SERVICE_REQUEST_TIMEOUT)[:-2]) 0346 0347 0348 def StopServiceWithDeps(serviceName, machine = None, waitSecs = 30): 0349 # Stop a service recursively looking for dependant services 0350 hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS) 0351 try: 0352 deps = __FindSvcDeps(serviceName) 0353 for dep in deps: 0354 hs = win32service.OpenService(hscm, dep, win32service.SERVICE_ALL_ACCESS) 0355 try: 0356 __StopServiceWithTimeout(hs, waitSecs) 0357 finally: 0358 win32service.CloseServiceHandle(hs) 0359 # Now my service! 0360 hs = win32service.OpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS) 0361 try: 0362 __StopServiceWithTimeout(hs, waitSecs) 0363 finally: 0364 win32service.CloseServiceHandle(hs) 0365 0366 finally: 0367 win32service.CloseServiceHandle(hscm) 0368 0369 0370 def StopService(serviceName, machine = None): 0371 return ControlService(serviceName, win32service.SERVICE_CONTROL_STOP, machine) 0372 0373 def StartService(serviceName, args = None, machine = None): 0374 hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_ALL_ACCESS) 0375 try: 0376 0377 hs = SmartOpenService(hscm, serviceName, win32service.SERVICE_ALL_ACCESS) 0378 try: 0379 win32service.StartService(hs, args) 0380 finally: 0381 win32service.CloseServiceHandle(hs) 0382 finally: 0383 win32service.CloseServiceHandle(hscm) 0384 0385 def RestartService(serviceName, args = None, waitSeconds = 30, machine = None): 0386 "Stop the service, and then start it again (with some tolerance for allowing it to stop.)" 0387 try: 0388 StopService(serviceName, machine) 0389 except pywintypes.error, (hr, name, msg): 0390 # Allow only "service not running" error 0391 if hr!=winerror.ERROR_SERVICE_NOT_ACTIVE: 0392 raise win32service.error, (hr, name, msg) 0393 # Give it a few goes, as the service may take time to stop 0394 for i in range(waitSeconds): 0395 try: 0396 StartService(serviceName, args, machine) 0397 break 0398 except pywintypes.error, (hr, name, msg): 0399 if hr!=winerror.ERROR_SERVICE_ALREADY_RUNNING: 0400 raise 0401 win32api.Sleep(1000) 0402 else: 0403 print "Gave up waiting for the old service to stop!" 0404 0405 0406 def GetServiceClassString(cls, argv = None): 0407 if argv is None: 0408 argv = sys.argv 0409 import pickle, os 0410 modName = pickle.whichmodule(cls, cls.__name__) 0411 if modName == '__main__': 0412 try: 0413 fname = win32api.GetFullPathName(argv[0]) 0414 path = os.path.split(fname)[0] 0415 # Eaaaahhhh - sometimes this will be a short filename, which causes 0416 # problems with 1.5.1 and the silly filename case rule. 0417 # Get the long name 0418 fname = os.path.join(path, win32api.FindFiles(fname)[0][8]) 0419 except win32api.error: 0420 raise error, "Could not resolve the path name '%s' to a full path" % (argv[0]) 0421 modName = os.path.splitext(fname)[0] 0422 return modName + "." + cls.__name__ 0423 0424 def QueryServiceStatus(serviceName, machine=None): 0425 hscm = win32service.OpenSCManager(machine,None,win32service.SC_MANAGER_CONNECT) 0426 try: 0427 0428 hs = SmartOpenService(hscm, serviceName, win32service.SERVICE_QUERY_STATUS) 0429 try: 0430 status = win32service.QueryServiceStatus(hs) 0431 finally: 0432 win32service.CloseServiceHandle(hs) 0433 finally: 0434 win32service.CloseServiceHandle(hscm) 0435 return status 0436 0437 def usage(): 0438 try: 0439 fname = os.path.split(sys.argv[0])[1] 0440 except: 0441 fname = sys.argv[0] 0442 print "Usage: '%s [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'" % fname 0443 print "Options for 'install' and 'update' commands only:" 0444 print " --username domain\username : The Username the service is to run under" 0445 print " --password password : The password for the username" 0446 print " --startup [manual|auto|disabled] : How the service starts, default = manual" 0447 print " --interactive : Allow the service to interact with the desktop." 0448 print " --perfmonini file: .ini file to use for registering performance monitor data" 0449 print " --perfmondll file: .dll file to use when querying the service for" 0450 print " performance data, default = perfmondata.dll" 0451 print "Options for 'start' and 'stop' commands only:" 0452 print " --wait seconds: Wait for the service to actually start or stop." 0453 print " If you specify --wait with the 'stop' option, the service" 0454 print " and all dependent services will be stopped, each waiting" 0455 print " the specified period." 0456 sys.exit(1) 0457 0458 def HandleCommandLine(cls, serviceClassString = None, argv = None, customInstallOptions = "", customOptionHandler = None): 0459 """Utility function allowing services to process the command line. 0460 0461 Allows standard commands such as 'start', 'stop', 'debug', 'install' etc. 0462 0463 Install supports 'standard' command line options prefixed with '--', such as 0464 --username, --password, etc. In addition, 0465 the function allows custom command line options to be handled by the calling function. 0466 """ 0467 err = 0 0468 0469 if argv is None: argv = sys.argv 0470 0471 if len(argv)<=1: 0472 usage() 0473 0474 serviceName = cls._svc_name_ 0475 serviceDisplayName = cls._svc_display_name_ 0476 if serviceClassString is None: 0477 serviceClassString = GetServiceClassString(cls) 0478 0479 # Pull apart the command line 0480 import getopt 0481 try: 0482 opts, args = getopt.getopt(argv[1:], customInstallOptions,["password=","username=","startup=","perfmonini=", "perfmondll=", "interactive", "wait="]) 0483 except getopt.error, details: 0484 print details 0485 usage() 0486 userName = None 0487 password = None 0488 perfMonIni = perfMonDll = None 0489 startup = None 0490 interactive = None 0491 waitSecs = 0 0492 for opt, val in opts: 0493 if opt=='--username': 0494 userName = val 0495 elif opt=='--password': 0496 password = val 0497 elif opt=='--perfmonini': 0498 perfMonIni = val 0499 elif opt=='--perfmondll': 0500 perfMonDll = val 0501 elif opt=='--interactive': 0502 interactive = 1 0503 elif opt=='--startup': 0504 map = {"manual": win32service.SERVICE_DEMAND_START, "auto" : win32service.SERVICE_AUTO_START, "disabled": win32service.SERVICE_DISABLED} 0505 try: 0506 startup = map[string.lower(val)] 0507 except KeyError: 0508 print "'%s' is not a valid startup option" % val 0509 elif opt=='--wait': 0510 try: 0511 waitSecs = int(val) 0512 except ValueError: 0513 print "--wait must specify an integer number of seconds." 0514 usage() 0515 0516 arg=args[0] 0517 knownArg = 0 0518 # First we process all arguments which pass additional args on 0519 if arg=="start": 0520 knownArg = 1 0521 print "Starting service %s" % (serviceName) 0522 try: 0523 StartService(serviceName, args[1:]) 0524 if waitSecs: 0525 WaitForServiceStatus(serviceName, win32service.SERVICE_RUNNING, waitSecs) 0526 except win32service.error, (hr, fn, msg): 0527 print "Error starting service: %s" % msg 0528 0529 elif arg=="restart": 0530 knownArg = 1 0531 print "Restarting service %s" % (serviceName) 0532 RestartService(serviceName, args[1:]) 0533 if waitSecs: 0534 WaitForServiceStatus(serviceName, win32service.SERVICE_RUNNING, waitSecs) 0535 0536 elif arg=="debug": 0537 knownArg = 1 0538 svcArgs = string.join(args[1:]) 0539 exeName = LocateSpecificServiceExe(serviceName) 0540 try: 0541 os.system("%s -debug %s %s" % (exeName, serviceName, svcArgs)) 0542 # ^C is used to kill the debug service. Sometimes Python also gets 0543 # interrupted - ignore it... 0544 except KeyboardInterrupt: 0545 pass 0546 0547 if len(args)<>1: 0548 usage() 0549 0550 if arg=="install": 0551 knownArg = 1 0552 try: 0553 serviceDeps = cls._svc_deps_ 0554 except AttributeError: 0555 serviceDeps = None 0556 try: 0557 exeName = cls._exe_name_ 0558 except AttributeError: 0559 exeName = None # Default to PythonService.exe 0560 try: 0561 exeArgs = cls._exe_args_ 0562 except AttributeError: 0563 exeArgs = None 0564 print "Installing service %s to Python class %s" % (serviceName,serviceClassString) 0565 # Note that we install the service before calling the custom option 0566 # handler, so if the custom handler fails, we have an installed service (from NT's POV) 0567 # but is unlikely to work, as the Python code controlling it failed. Therefore 0568 # we remove the service if the first bit works, but the second doesnt! 0569 try: 0570 InstallService(serviceClassString, serviceName, serviceDisplayName, serviceDeps = serviceDeps, startType=startup, bRunInteractive=interactive, userName=userName,password=password, exeName=exeName, perfMonIni=perfMonIni,perfMonDll=perfMonDll,exeArgs=exeArgs) 0571 if customOptionHandler: 0572 apply( customOptionHandler, (opts,) ) 0573 print "Service installed" 0574 except win32service.error, (hr, fn, msg): 0575 if hr==winerror.ERROR_SERVICE_EXISTS: 0576 arg = "update" # Fall through to the "update" param! 0577 else: 0578 print "Error installing service: %s (%d)" % (msg, hr) 0579 err = hr 0580 except ValueError, msg: # Can be raised by custom option handler. 0581 print "Error installing service: %s" % str(msg) 0582 err = -1 0583 # xxx - maybe I should remove after _any_ failed install - however, 0584 # xxx - it may be useful to help debug to leave the service as it failed. 0585 # xxx - We really _must_ remove as per the comments above... 0586 # As we failed here, remove the service, so the next installation 0587 # attempt works. 0588 try: 0589 RemoveService(serviceName) 0590 except win32api.error: 0591 print "Warning - could not remove the partially installed service." 0592 0593 if arg == "update": 0594 knownArg = 1 0595 try: 0596 serviceDeps = cls._svc_deps_ 0597 except AttributeError: 0598 serviceDeps = None 0599 try: 0600 exeName = cls._exe_name_ 0601 except AttributeError: 0602 exeName = None # Default to PythonService.exe 0603 try: 0604 exeArgs = cls._exe_args_ 0605 except AttributeError: 0606 exeArgs = None 0607 print "Changing service configuration" 0608 try: 0609 ChangeServiceConfig(serviceClassString, serviceName, serviceDeps = serviceDeps, startType=startup, bRunInteractive=interactive, userName=userName,password=password, exeName=exeName, displayName = serviceDisplayName, perfMonIni=perfMonIni,perfMonDll=perfMonDll,exeArgs=exeArgs) 0610 print "Service updated" 0611 except win32service.error, (hr, fn, msg): 0612 print "Error changing service configuration: %s (%d)" % (msg,hr) 0613 err = hr 0614 0615 elif arg=="remove": 0616 knownArg = 1 0617 print "Removing service %s" % (serviceName) 0618 try: 0619 RemoveService(serviceName) 0620 print "Service removed" 0621 except win32service.error, (hr, fn, msg): 0622 print "Error removing service: %s (%d)" % (msg,hr) 0623 err = hr 0624 elif arg=="stop": 0625 knownArg = 1 0626 print "Stopping service %s" % (serviceName) 0627 try: 0628 if waitSecs: 0629 StopServiceWithDeps(serviceName, waitSecs = waitSecs) 0630 else: 0631 StopService(serviceName) 0632 except win32service.error, (hr, fn, msg): 0633 print "Error stopping service: %s (%d)" % (msg,hr) 0634 err = hr 0635 if not knownArg: 0636 err = -1 0637 print "Unknown command - '%s'" % arg 0638 usage() 0639 return err 0640 0641 # 0642 # Useful base class to build services from. 0643 # 0644 class ServiceFramework: 0645 # Required Attributes: 0646 # _svc_name = The service name 0647 # _svc_display_name = The service display name 0648 0649 # Optional Attributes: 0650 _svc_deps_ = None # sequence of service names on which this depends 0651 _exe_name_ = None # Default to PythonService.exe 0652 _exe_args_ = None # Default to no arguments 0653 0654 def __init__(self, args): 0655 import servicemanager 0656 self.ssh = servicemanager.RegisterServiceCtrlHandler(args[0], self.ServiceCtrlHandler) 0657 self.checkPoint = 0 0658 0659 def GetAcceptedControls(self): 0660 # Setup the service controls we accept based on our attributes 0661 accepted = 0 0662 if hasattr(self, "SvcStop"): accepted = accepted | win32service.SERVICE_ACCEPT_STOP 0663 if hasattr(self, "SvcPause") and hasattr(self, "SvcContinue"): 0664 accepted = accepted | win32service.SERVICE_ACCEPT_PAUSE_CONTINUE 0665 if hasattr(self, "SvcShutdown"): accepted = accepted | win32service.SERVICE_ACCEPT_SHUTDOWN 0666 return accepted 0667 0668 def ReportServiceStatus(self, serviceStatus, waitHint = 5000, win32ExitCode = 0, svcExitCode = 0): 0669 if self.ssh is None: # Debugging! 0670 return 0671 if serviceStatus == win32service.SERVICE_START_PENDING: 0672 accepted = 0 0673 else: 0674 accepted = self.GetAcceptedControls() 0675 0676 if serviceStatus in [win32service.SERVICE_RUNNING, win32service.SERVICE_STOPPED]: 0677 checkPoint = 0 0678 else: 0679 self.checkPoint = self.checkPoint + 1 0680 checkPoint = self.checkPoint 0681 0682 # Now report the status to the control manager 0683 status = (win32service.SERVICE_WIN32_OWN_PROCESS, 0684 serviceStatus, 0685 accepted, # dwControlsAccepted, 0686 win32ExitCode, # dwWin32ExitCode; 0687 svcExitCode, # dwServiceSpecificExitCode; 0688 checkPoint, # dwCheckPoint; 0689 waitHint) 0690 win32service.SetServiceStatus( self.ssh, status) 0691 0692 def SvcInterrogate(self): 0693 # Assume we are running, and everyone is happy. 0694 self.ReportServiceStatus(win32service.SERVICE_RUNNING) 0695 0696 def SvcOther(self, control): 0697 print "Unknown control status - %d" % control 0698 0699 def ServiceCtrlHandler(self, control): 0700 if control==win32service.SERVICE_CONTROL_STOP: 0701 self.SvcStop() 0702 elif control==win32service.SERVICE_CONTROL_PAUSE: 0703 self.SvcPause() 0704 elif control==win32service.SERVICE_CONTROL_CONTINUE: 0705 self.SvcContinue() 0706 elif control==win32service.SERVICE_CONTROL_INTERROGATE: 0707 self.SvcInterrogate() 0708 elif control==win32service.SERVICE_CONTROL_SHUTDOWN: 0709 self.SvcShutdown() 0710 else: 0711 self.SvcOther(control) 0712 0713 def SvcRun(self): 0714 self.ReportServiceStatus(win32service.SERVICE_RUNNING) 0715 self.SvcDoRun() 0716 # Once SvcDoRun terminates, the service has stopped. 0717 # We tell the SCM the service is still stopping - the C framework 0718 # will automatically tell the SCM it has stopped when this returns. 0719 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 0720
Generated by PyXR 0.9.4