PyXR

c:\python24\lib\site-packages\win32\lib \ win32serviceutil.py



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
SourceForge.net Logo