Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

rcSuite.py

00001 #!/usr/local/bin/python
00002 #
00003 #                               Copyright 2002
00004 #                                     by
00005 #                        The Board of Trustees of the
00006 #                     Leland Stanford Junior University.
00007 #                            All rights reserved.
00008 #
00009 
00010 __facility__ = "Online"
00011 __abstract__ = "GLAST LAT run control suite execution framework"
00012 __author__   = "S. Tuvi <stuvi@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online"
00013 __date__     = ("$Date: 2005/10/26 01:46:50 $").split(' ')[1]
00014 __version__  = "$Revision: 2.22 $"
00015 __credits__  = "SLAC"
00016 
00017 import LATTE.copyright_SLAC
00018 
00019 import threading
00020 import logging  as log
00021 import types
00022 import copy
00023 
00024 import rcUtil
00025 from RunControlCommon import RunControlCommon
00026 
00027 class rcSuite(object):
00028 
00029   class StopRequestedException(Exception):
00030     def __init__(self,msg,suite,module):
00031       self.args = (msg, suite, module)
00032       self.msg = msg
00033       self.suite = suite
00034       self.module = module
00035 
00036   class SuiteCallbacks(object):
00037     def beforeSetupSuite(self, suite):
00038       pass
00039     def afterSetupSuite(self, suite):
00040       pass
00041     def beforeStartSuite(self, suite):
00042       pass
00043     def afterStartSuite(self, suite):
00044       pass
00045     def beforeStopSuite(self, suite):
00046       pass
00047     def afterStopSuite(self, suite):
00048       pass
00049 
00050   class StandaloneLauncher(object):
00051     def __init__(self, logLevel="INFO"):
00052       self.__common = RunControlCommon()
00053       self.__common.initialize()
00054       self.__common.setLoggingLevel(logLevel)
00055       self.__common.connect()
00056 
00057     def launch(self, suiteClass, user, callbacks=None):
00058       if suiteClass is None:
00059         module = self.__common.options().app
00060         try:
00061           (module, filename) = rcUtil.importModule(module, reload=0)
00062         except Exception, e:
00063           log.exception(e)
00064           return
00065         us = module.userSuite(self, user, self.__common)
00066         if callbacks is None and 'userSuiteCallbacks' in dir(module):
00067           callbacks = module.userSuiteCallbacks()
00068       else:
00069         us = suiteClass(self, user, self.__common)
00070       if callbacks is not None:
00071         callbacks.beforeSetupSuite(us)
00072       us.rcSetupSuite()
00073       if callbacks is not None:
00074         callbacks.afterSetupSuite(us)
00075       if callbacks is not None:
00076         callbacks.beforeStartSuite(us)
00077       us.rcStartSuite(spawn=0)
00078       if callbacks is not None:
00079         callbacks.afterStartSuite(us)
00080       if callbacks is not None:
00081         callbacks.beforeStopSuite(us)
00082       us.rcStopSuite()
00083       if callbacks is not None:
00084         callbacks.afterStopSuite(us)
00085 
00086     def doStopRun(self):
00087       pass
00088 
00089     def preferences(self):
00090       return self.__common.prefMan().preferences()
00091 
00092     def common(self):
00093       return self.__common
00094 
00095 
00096   def __init__(self, gui, userId, debug):
00097     log.debug("rcSuite.__init__()")
00098 
00099     self.__userId      = userId
00100     self.__debug       = debug
00101     self.__cmdCli      = None
00102     self.__evtCli      = None
00103 
00104     #self.__modules     = []
00105     #self.__schemas     = []
00106     self.__isOKtoQuitOrPause  = threading.Event()
00107     self.__cmdQuit     = 0
00108     self.__paused      = False
00109     self.__running     = False
00110     self.__app         = None
00111     self.__scriptSeq   = 0
00112     self.__suite       = None
00113     self.__suiteInst   = None
00114     self.__state       = 'RESET'
00115     self.__appState    = 'RESET'
00116     # Flag to indicate that there was an exception in the running script.
00117     self.__reset       = False
00118 
00119     # The following data members are meant to be marked "protected"
00120     self.gui           = gui
00121 
00122     if self.__debug.__class__.__name__ == 'RunControlCommon':
00123       self.__common = self.__debug
00124       self.__statMon = None
00125     else:
00126       self.__common = self.gui.common()
00127       self.__statMon = self.gui.statusMonitor()
00128 
00129     # Expose the schema to the suite
00130     self.lat = self.getSessionVar('_LATSchema')
00131     self.xbrd = self.getSessionVar('_XBRDSchema')
00132 
00133 #  def addApplication(self, appName, schema):
00134 #    try:
00135 #      (module, filename) = rcUtil.importModule(appName, reload=0)
00136 #    except Exception:
00137 #      gutil.logException()
00138 
00139 
00140 #    if 'userApplication' not in dir(module):
00141 #      msg = 'Application %s is missing a userApplication class' % appName
00142 #      log.error(msg)
00143 #      return msg
00144 
00145 #    log.info("Application loaded from %s" % filename)
00146 #    self.__modules.append(module)
00147 #    self.__schemas.append(schema)
00148 
00149   def setupSuite(self):
00150     """ Override this method to do custom processing before the suite is started and/or
00151     to return a custom schema file
00152     """
00153     return None
00154 
00155   def rcPauseSuite(self):
00156     fn = "rcSuite.rcPauseSuite"
00157     log.debug("%s -- %s" % (fn, self.getName()))
00158     if self.__paused:
00159       return -1
00160     if self.pauseSuite() is not None:
00161       return
00162     if self.__app is not None:
00163       if self.__app.__class__.__name__ == 'userApplication':
00164         self.__isOKtoQuitOrPause.wait()
00165         if self.__app is not None and self.__app.rcPause() is None:
00166           self.__paused = True
00167           return None
00168       else:
00169         if self.__app.rcPauseSuite() is None:
00170           self.__paused = True
00171           return None
00172     return -1
00173 
00174   def pauseSuite(self):
00175     """ Override this method to do custom processing before the currently running
00176     application is paused. Pause can be rejected by not returning None
00177     """
00178     return None
00179 
00180 
00181   def rcSetupSuite(self):
00182     """ This method can be called from either RunControlMain or from another suite.
00183     """
00184     fn = "rcSuite.rcSetupSuite"
00185     log.debug("%s -- %s" % (fn, self.getName()))
00186 
00187     #askForSchema = 0
00188     #if schema is None:
00189     #  reuseSchema = self.getSessionVar('_reuseSchema')
00190     #  schema = self.getSessionVar("_suiteLATSchemaFile")
00191     #  if not reuseSchema:
00192     #    askForSchema = 1
00193 
00194     #if askForSchema:
00195     #  scmCfg = self.gui.createGUI(rcScmCfgSelector.rcScmCfgSelector, self.gui.common().preferences()['reposdir'],
00196     #                              schema, self.gui, 'ScmCfgSelector')
00197     #  scmCfgFile = scmCfg.getValue()
00198     #  # Allow the C++ object to be deleted
00199     #  scmCfg.deleteLater()
00200     #  if scmCfgFile is None or os.path.splitext(scmCfgFile.lower())[1] != '.xml':
00201     #    if scmCfgFile is not None:
00202     #      log.error("%s: Invalid SchemaConfig filename '%s'" % (fn, scmCfgFile))
00203     #    schema = None
00204     #  else:
00205     #    self.setSessionVar("_LATSchemaFile", scmCfgFile)
00206     #    self.setSessionVar("_suiteLATSchemaFile", scmCfgFile)
00207     #    schema = scmCfgFile
00208 
00209     #if schema is not None:
00210     #  self.setupSuite()
00211     #else:
00212 
00213     #return schema
00214 
00215     self.setupSuite()
00216     return 0
00217 
00218   def rcStartSuite(self, spawn=1):
00219     fn = "rcSuite.rcStartSuite"
00220     log.debug("%s -- %s" % (fn, self.getName()))
00221     if self.__running and not self.__paused:
00222       return -1
00223     self.__scriptSeq = 0
00224     self.__running = True
00225     self.__state = 'RUNNING'
00226     if self.__paused:
00227       if self.__app.__class__.__name__ == 'userApplication':
00228         if self.__app.rcResume() is None:
00229           self.__paused = False
00230       else:
00231         self.__app.rcStartSuite()
00232     else:
00233       self.__cmdQuit = 0
00234       if spawn:
00235         self.__suiteRun = threading.Thread(group=None, name="SuiteThread", target=self.startSuite)
00236         self.__suiteRun.start()
00237       else:
00238         self.startSuite()
00239 
00240   def stopSuite(self):
00241     """ Override this method to do custom processing before the suite is terminated
00242     """
00243     pass
00244 
00245   def rcStopSuite(self):
00246     fn = "rcSuite.rcStopSuite"
00247     log.debug("%s -- %s" % (fn, self.getName()))
00248     if self.stopRequested():
00249       self.__running = False
00250       return
00251     if self.__app is not None and self.__app.__class__.__name__ == 'userApplication':
00252       self.__isOKtoQuitOrPause.wait()
00253     self.__cmdQuit = 1
00254     if self.__app is not None:
00255       if self.__app.__class__.__name__ == 'userSuite':
00256         self.__app.rcStopSuite()
00257       else:
00258         if self.__paused:
00259           if self.__app.rcResume() is None:
00260             self.__paused = False
00261             self.__app.rcStopRun()
00262             self.__app.rcTeardown()
00263         else:
00264           self.__app.rcStopRun()
00265           self.__app.rcTeardown()
00266     self.stopSuite()
00267     self.__running = False
00268     self.__state = 'RESET'
00269     #self.__suiteRun.join()
00270 
00271   #def __suiteRunThread(self):
00272   #  i = 0
00273   #  for module in self.__modules:
00274   #    self.scriptRun(module, self.__schemas[i])
00275   #    if self.__cmdQuit: break
00276   #    i += 1
00277 
00278   def scriptRun(self, module, context={}):
00279     fn = "rcSuite.scriptRun"
00280     log.debug("%s: %s" % (fn, module))
00281     self.__scriptSeq += 1
00282     if self.stopRequested():
00283         raise rcSuite.StopRequestedException("Operator requested stop of execution",
00284                                             self.getName(),
00285                                             ""
00286                                             )
00287     self.__isOKtoQuitOrPause.clear()
00288     for (key, value) in context.items():
00289       self.setSessionVar(key, value)
00290     if type(module) is types.StringType:
00291       if self.__statMon is not None:
00292         self.gui.execGUImethod(self.__statMon.stopWatch)
00293       try:
00294         (module, filename) = rcUtil.importModule(module, reload=0)
00295       except Exception, e:
00296         log.exception(e)
00297         if self.__statMon is not None:
00298           self.gui.execGUImethod(self.__statMon.startWatch)
00299         return None
00300       if self.__statMon is not None:
00301         self.gui.execGUImethod(self.__statMon.startWatch)
00302     self.__reset = False
00303     if 'userApplication' in dir(module):
00304       if self.__debug.__class__.__name__ == 'RunControlCommon':
00305         self.__app = module.userApplication(None, self.__userId,
00306                                             self.__debug )
00307       else:
00308         self.__app = module.userApplication(self.gui, self.__userId,
00309                                             self.__debug )
00310       self.__app.setSuite(self.getName())
00311       self.__app.setSuiteInstance(self)
00312       self.__app.setCmdCli(self.__cmdCli)
00313       if self.__app.getEvtCli() is None:
00314         self.__app.setEvtCli(self.__evtCli)
00315       self.__appState = 'RESET'
00316       if self.__app.rcSetup() is not None:
00317         self.__cmdQuit = 1
00318         raise rcSuite.StopRequestedException("setup() is rejected, stopping suite execution",
00319                                             self.__app.getSuite(),
00320                                             self.__app.getName()
00321                                             )
00322       self.__appState = 'STOPPED'
00323       status = self.__app.rcStartRun()
00324       self.__appState = 'RUNNING'
00325       self.__isOKtoQuitOrPause.set()
00326       if status is not None:
00327         self.__cmdQuit = 1
00328         raise rcSuite.StopRequestedException("startRun() is rejected, stopping suite execution",
00329                                             self.__app.getSuite(),
00330                                             self.__app.getName()
00331                                             )
00332       self.__app.wait()
00333       if self.stopRequested():
00334         raise rcSuite.StopRequestedException("Operator requested stop of execution",
00335                                             self.__app.getSuite(),
00336                                             self.__app.getName()
00337                                             )
00338       self.__isOKtoQuitOrPause.wait()
00339       self.__isOKtoQuitOrPause.clear()
00340       if not self.__reset:
00341         self.__app.rcStopRun()
00342         self.__app.rcTeardown()
00343       self.__appState = 'RESET'
00344       del self.__app
00345       self.__app = None
00346       self.__isOKtoQuitOrPause.set()
00347     elif 'userSuite' in dir(module):
00348       self.__app = module.userSuite( self.gui, self.__userId, self.__debug)
00349       log.info("Suite %s loaded from %s" % (self.__app.getName(), filename))
00350       self.__app.setCmdCli(self.__cmdCli)
00351       self.__app.setEvtCli(self.__evtCli)
00352       #if self.__app.rcSetupSuite(self.getSessionVar("_suiteLATSchemaFile")) is None:
00353       #  log.error("Suite setup failed...Aborting suite %s" % self.__app.getName())
00354       #  return
00355       #else:
00356       self.__app.setSuite(self.getName())
00357       self.__app.setSuiteInstance(self)
00358       self.__app.rcSetupSuite()
00359       self.__app.rcStartSuite(spawn=0)
00360       self.__isOKtoQuitOrPause.set()
00361         #self.__app.rcStopSuite()
00362         #self.__app = None
00363     else:
00364       errorMsg = '%s is not a recognized user script. userApplication or userSuite class missing' % module
00365       log.error(errorMsg)
00366       raise RuntimeError, errorMsg
00367     return self.__copySessionVars()
00368 
00369   def resetSuiteScript(self):
00370     if self.__app.__class__.__name__ == 'userApplication' and not self.stopRequested():
00371       self.__isOKtoQuitOrPause.clear()
00372       self.__reset = True
00373       if 'sync' in dir(self.__app):
00374         self.__app.sync()
00375       self.__app.rcStopRun()
00376       self.__app.rcTeardown()
00377       self.__isOKtoQuitOrPause.set()
00378 
00379   def setCmdCli(self, cmdCli):
00380     self.__cmdCli = cmdCli
00381 
00382   def setEvtCli(self, evtCli):
00383     self.__evtCli = evtCli
00384 
00385   def getEvtCli(self):
00386     return self.__evtCli
00387 
00388   def isSuiteScriptAborted(self):
00389     return self.__reset
00390 
00391   def getScriptSequence(self):
00392     return self.__scriptSeq
00393 
00394   def getScriptState(self):
00395     """\brief Return the state of the suite script.
00396 
00397     Currently there are two states. 'RESET' or 'RUNNING'.
00398     If rcSetupSuite or rcStopSuite has completed execution then
00399     the state will be 'RESET'. If rcStartSuite started execution
00400     then the state will be 'RUNNING'.
00401 
00402     \return 'RESET' or 'RUNNING'
00403     """
00404     return self.__state
00405 
00406   def getAppState(self):
00407     """\brief Return the state of the current script.
00408 
00409     \return State of the current script
00410     """
00411     return self.__appState
00412 
00413   def getApp(self):
00414     """\brief Return the instance of current script.
00415 
00416     Returns the instance for the suite script or nested suite
00417     that is currently executing.
00418 
00419     \return userApplication or userSuite instance.
00420     """
00421     return self.__app
00422 
00423   def getSuite(self):
00424     """\brief Get the parent suite name of this suite
00425 
00426     \return Parent suite name or None.
00427     """
00428     return self.__suite
00429 
00430   def setSuite(self, name):
00431     """\brief Set the parent suite name of this suite
00432 
00433     \param name Parent suite name
00434     """
00435     self.__suite = name
00436 
00437   def getSuiteInstance(self):
00438     """\brief Return the parent suite instance that this suite is a part of.
00439 
00440     \return Parent suite instance.
00441     """
00442     return self.__suiteInst
00443 
00444   def setSuiteInstance(self, suiteInst):
00445     """\brief Set the parent suite instance for this suite.
00446 
00447     \param suiteInst Parent suite instance.
00448     """
00449     self.__suiteInst = suiteInst
00450 
00451   def setSessionVar(self, key, value):
00452     """\brief Set a session variable.
00453 
00454     Do not use variable names beginning
00455     with the underscore ('_') character since these are reserved for RunControl
00456     """
00457     sessionVars = self.__common.getDBN()
00458     if sessionVars is not None:
00459       sessionVars[key] = value
00460     else:
00461       raise RuntimeError, "Database node does not exist"
00462 
00463   def getSessionVar(self, key):
00464     """Retrieve the values of the session variable indicated by \a key.
00465 
00466     \return Session variable value
00467     """
00468     sessionVars = self.__common.getDBN()
00469     if sessionVars is not None and sessionVars.has_key(key):
00470       return sessionVars[key]
00471     else:
00472       return None
00473 
00474   def __copySessionVars(self):
00475     newCopy = {}
00476     vars = self.__common.getDBN()
00477     for varName in vars.keys():
00478       if varName.startswith('_'): continue
00479       try:
00480         newCopy[varName] = copy.deepcopy(vars[varName])
00481       except:
00482         newCopy[varName] = copy.copy(vars[varName])
00483     return newCopy
00484 
00485   #def readSchema(self, scmCfgFile):
00486   #  fn = "rcTransitions.readSchema"
00487   #  lat = gSchemaConfig.readSchema(scmCfgFile)
00488   #  if lat is None:
00489   #    log.error("%s: Unable to instatiate a LAT from SchemaConfig file '%s'" % \
00490   #              (fn, scmCfgFile))
00491   #    return None
00492   #  includeFiles = lat._GLAT__includeFiles
00493   #  incFileModTime = {}
00494   #  for f in includeFiles:
00495   #    incFileModTime[f] = os.path.getmtime(f)
00496   #  lat.setCmd(self.__cmdCli)
00497   #  self.setSessionVar('_LATSchema', lat)
00498   #  self.setSessionVar('_LATSchemaFile', scmCfgFile)
00499   #  self.setSessionVar('_LATSchemaFileModTime', os.path.getmtime(scmCfgFile))
00500   #  self.setSessionVar('_LATIncludeFileModTime', incFileModTime)
00501   #  return lat
00502 
00503   def readSchema(self, scmCfgFile):
00504     self.__common.readSchema(scmCfgFile)
00505 
00506   def applyConfig(self, seq=None, gxbrd=None):
00507     if self.lat is not None:
00508       self.lat.applyConfig(seq, gxbrd)
00509 
00510   def stopRequested(self):
00511     return self.__cmdQuit
00512 
00513   def clearStopRequested(self):
00514     self.__cmdQuit = 0
00515 
00516   def isPaused(self):
00517     return self.__paused
00518 
00519   def isRunning(self):
00520     return self.__running
00521 
00522   def getName(self):
00523     return self.__class__.__name__
00524 
00525   def startSuite(self):
00526     raise RuntimeError, "Suite does not define a startSuite method"

Generated on Fri Jul 21 13:26:31 2006 for LATTE R04-12-00 by doxygen 1.4.3