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__ = "Classes for defining rules" 00012 __author__ = "R. Claus <Claus@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online" 00013 __date__ = ("$Date: 2005/02/04 18:27:04 $").split(' ')[1] 00014 __version__ = "$Revision: 2.4 $" 00015 __credits__ = "SLAC" 00016 00017 import LATTE.copyright_SLAC 00018 00019 00020 import gGroup 00021 import logging as log 00022 import LATTE.dispatch.dispatcher as dispatcher 00023 00024 class GruleBase(object): 00025 """\brief Base rule class for use when no rule is appropriate. 00026 00027 """ 00028 def __init__(self): 00029 pass 00030 def evaluate(self, value, attr, node=None): 00031 pass 00032 00033 00034 class Grule(GruleBase): 00035 """\brief Base class for describing rules. 00036 00037 """ 00038 def __init__(self, name, subsystem, category, enabled, continuous = False): 00039 """Constructor. 00040 \param name Rule name 00041 \param subsystem Subsystem gGroup to which the rule belongs 00042 \param category Category gGroup to which the rule belongs 00043 \param enabled Flag indicating whether rule is enabled 00044 \param continuous Flag indicating whether rule can fire repeatedly 00045 00046 """ 00047 self.__name = name 00048 self.__subsystem = subsystem 00049 self.__category = category 00050 self.__enabled = enabled 00051 self.__continuous = continuous 00052 self.__fired = {} # A dict of node:bool pairs indicating if a partic node has fired. 00053 self.__actions = {} 00054 # init self.__fired 00055 self.__fired[None]= False 00056 00057 def _eval_(self, value, attr, node): 00058 """Base method called from derived classes. 00059 determine whether or not this rule can fire or not. 00060 00061 \return a tuple containing the value of the test and whether the rule can fire or not. 00062 """ 00063 key = (node, attr) 00064 # print "baseEval: ", self.__continuous, self.__fired.has_key(key) 00065 00066 if ( (self.__continuous) or\ 00067 (not self.__fired.has_key(key)) or\ 00068 (not self.__continuous and not self.__fired[key]) ): 00069 return (value, True) 00070 else: 00071 return (value, False) 00072 00073 def evaluate(self, value, attr, node=None): 00074 """This method is called to evaluate the rule on 'value' 00075 00076 \param value Value to be evaluated. 00077 \param attr Attribute object whose \a value is being evaluated. 00078 00079 \return Result of the evaluation, if any. 00080 00081 """ 00082 if self.__subsystem.enabled() and \ 00083 self.__category.enabled() and \ 00084 self.__enabled: 00085 return self._eval_(value, attr, node) 00086 else: 00087 return (value, False) 00088 00089 def name(self): 00090 """Method to retrieve the rule's name 00091 00092 \return Rule's name. 00093 00094 """ 00095 return self.__name 00096 00097 def subsystem(self): 00098 """Method for discovering this rule's subsystem 00099 00100 \return Rule's subsystem. 00101 00102 """ 00103 return self.__subsystem 00104 00105 def category(self): 00106 """Method for discovering this rule's category 00107 00108 \return Rule's category. 00109 00110 """ 00111 return self.__category 00112 00113 def enabled(self): 00114 """Method for discovering whether this rule is enabled 00115 00116 \return Whether this rule is enabled or not. 00117 00118 """ 00119 return self.__enabled 00120 00121 def enable(self): 00122 """Method used to enable evaluation of this rule 00123 00124 """ 00125 self.__enabled = True 00126 00127 def disable(self): 00128 """Method used to disable evaluation of this rule 00129 00130 """ 00131 self.__enabled = False 00132 00133 def reset(self, node=None): 00134 """Method used to reenable evaluation of this rule in the case of 00135 noncontinuous mode after it has been violated 00136 00137 """ 00138 self.__fired[node] = False 00139 00140 def fire(self, node=None): 00141 """Method used to tell the rule it has fired 00142 """ 00143 self.__fired[node] = True 00144 00145 def fired(self, node=None): 00146 """Method for discovering whether this rule has fired 00147 00148 \return Whether this rule has fired or not 00149 """ 00150 if node not in self.__fired: 00151 return False 00152 else: 00153 return self.__fired[node] 00154 00155 def registerAction(self, action, method, sender=dispatcher.Any): 00156 """Associate and action with a user \a method, optionally specifying a \a sender. 00157 If a \a sender is not specified, the rule \a action may be fired for all registers 00158 which declare its rule to be the rule of this \a action. If an attribute is 00159 specified as the \a sender then only if the evaluation of that specific attribute 00160 causes the \a action to be fired the \a method will be called. 00161 00162 \param action A string that represents the action to be taken. 00163 This is specified under the <actions> tag in the schema/configuration. 00164 \param method A user method visible to the current context. 00165 \param sender Optional parameter that specifies the sender of the action registration. 00166 If specifed, only the sendAction requests which specify the same sender 00167 will be honored. Defaults to dispatcher.Any. 00168 00169 """ 00170 if action not in self.__actions: 00171 log.error("Unable to register action %s, not specified in the configuration." % action) 00172 else: 00173 dispatcher.connect(method, signal=action, sender=sender) 00174 00175 def setActions(self, actions): 00176 """Convenience method that gets called from the rule constructor 00177 that defines the action names (which is read from the schema/configuration). 00178 00179 \param actions A list containing the action names. 00180 00181 """ 00182 self.__actions = actions 00183 00184 def sendAction(self, action, sender, *arguments, **named): 00185 """Called from the rule evaluation method to fire the appropriate alarm action. 00186 00187 \param action A string that represents the action to be taken. 00188 This is specified under the <actions> tag in the schema/configuration. 00189 \param sender The sender that made the rule firing request. This is usually the 00190 attribute which is being evaluated. 00191 \param *arguments An optional list of arguments which gets passed to the action method. 00192 00193 \return A list of tuple pairs [(receiver, response), ... ] 00194 """ 00195 return dispatcher.send(action, sender, *arguments, **named) 00196 00197 def clearAllActions(self): 00198 """ 00199 Forces all registered actions to be cleared. 00200 If this is not done and the scripts re-register their 00201 actions there may be extraneous rule action firings. 00202 """ 00203 dispatcher.connections = {} 00204 00205 def unregisterAction(self, action, method, sender=dispatcher.Any): 00206 """Reverse of registerAction, disassociates the action from the method. 00207 00208 \param action A string that represents the action to be taken. 00209 This is specified under the <actions> tag in the schema/configuration. 00210 \param method A user method visible to the current context. 00211 \param sender Optional parameter that specifies the sender of the action registration. 00212 If specifed, only the sendAction requests which specify the same sender 00213 will be honored. Defaults to dispatcher.Any. 00214 """ 00215 dispatcher.disconnect(method, action, sender) 00216 00217 class GruleLimit(Grule): 00218 """\brief Rule class that limits a passed in value to given limits. 00219 00220 """ 00221 def __init__(self, name, subsystem, category, enabled, continuous, 00222 low, high): 00223 """Limit rule constructor. 00224 00225 \param name Rule name 00226 \param subsystem Subsystem gGroup to which the rule belongs 00227 \param category Category gGroup to which the rule belongs 00228 \param enabled Flag indicating whether rule is enabled 00229 \param continuous Flag indicating whether rule can fire repeatedly 00230 \param low Low limit 00231 \param high High limit 00232 00233 """ 00234 Grule.__init__(self, name, subsystem, category, enabled, continuous) 00235 self.__low = low 00236 self.__high = high 00237 00238 def _eval_(self, value, attr, node): 00239 """Evaluate the rule. 00240 """ 00241 if value < self.__low: 00242 log.warning("%s rule: value is below low limit" % self.name()) 00243 elif value > self.__high: 00244 log.warning("%s rule: value is above high limit" % self.name()) 00245 00246 class GruleAlarms(Grule): 00247 """\brief Alarm rule 00248 00249 If the value falls below the yellow or red lower limit or it exceeds 00250 the yellow or red upped limit the appropriate registered action is 00251 fired. 00252 """ 00253 def __init__(self, name, subsystem, category, enabled, continuous, 00254 yellowUpperLimit, yellowLowerLimit, 00255 redUpperLimit, redLowerLimit, actions=[]): 00256 """Alarm rule constructor. 00257 00258 \param name Rule name 00259 \param subsystem Subsystem gGroup to which the rule belongs 00260 \param category Category gGroup to which the rule belongs 00261 \param enabled Flag indicating whether rule is enabled 00262 \param continuous Flag indicating whether rule can fire repeatedly 00263 \param yellowUpperLimit Yellow alarm upper limit 00264 \param yellowLowerLimit Yellow alarm lower limit 00265 \param redUpperLimit Red alarm upper limit 00266 \param redLowerLimit Red alarm lower limit 00267 """ 00268 00269 Grule.__init__(self, name, subsystem, category, enabled, continuous) 00270 self.__yellowLowerLimit = yellowLowerLimit 00271 self.__yellowUpperLimit = yellowUpperLimit 00272 self.__redLowerLimit = redLowerLimit 00273 self.__redUpperLimit = redUpperLimit 00274 self.setActions(actions) 00275 00276 def _eval_(self, value, attr, node): 00277 """Alarm rule evaluation method. 00278 00279 If the red alarm is fired then the yellow alarm does not get fired. 00280 """ 00281 action = None 00282 key = (node, attr) 00283 if value < self.__redLowerLimit or value > self.__redUpperLimit: 00284 action = "redAction" 00285 elif value < self.__yellowLowerLimit or value > self.__yellowUpperLimit: 00286 action = "yellowAction" 00287 else: 00288 self.reset(key) 00289 temp, canFire = Grule._eval_(self, value, attr, node) 00290 if action is not None and canFire: 00291 self.fire(key) 00292 self.sendAction(action, attr, value, node=node) 00293 00294