service.py (60732B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\sys\service.py 2 from future.utils import raise_ 3 import types 4 import weakref 5 import sys 6 import cPickle 7 import binascii 8 import traceback 9 import blue 10 import locks 11 import log 12 import stackless 13 import uthread 14 from carbon.common.script.sys.serviceConst import * 15 from carbon.common.script.util.logUtil import supersafestr 16 from carbon.common.script.util.timerstuff import ClockThisWithoutTheStars 17 from cluster import SERVICE_BEYONCE, SERVICE_STATION, SERVICE_CHARACTER, SERVICE_CHATX, SERVICE_USER, SERVICE_CLUSTERSINGLETON 18 from eve.common.lib.appConst import CHARNODE_MOD 19 from eveexceptions import UserError 20 from stdlogutils import LineWrap 21 from eveprefs import prefs, boot 22 callWrapperLocks = {} 23 callWrapperID = 0 24 allCallWrappers = weakref.WeakValueDictionary({}) 25 26 def GetCallWrappers(): 27 global allCallWrappers 28 return allCallWrappers 29 30 31 class CachedResult(): 32 33 def __init__(self, result): 34 self.result = result 35 36 37 class FastCallWrapper(object): 38 39 def __init__(self, session, obj, method, parent): 40 self.session = session 41 self.callable = getattr(obj, method) 42 self.parent = parent 43 44 def __repr__(self): 45 return '<FastCallWrapper session:%r, callable:%r>' % (self.session, self.callable) 46 47 def __call__(self, *args, **keywords): 48 with self.session.Masquerade({'base.caller': weakref.ref(self.parent)}): 49 return self.callable(*args, **keywords) 50 51 52 class CallWrapper(): 53 if boot.role == 'client': 54 __precall__ = ['PreCall_IsExportedCall', 'PreCall_CheckPreArgs', 'PreCall_CachedMethodCall'] 55 else: 56 __precall__ = ['PreCall_IsExportedCall', 57 'PreCall_RoleCheck', 58 'PreCall_CheckPreArgs', 59 'PreCall_CachedMethodCall', 60 'PreCall_Lock'] 61 __postcall__ = ['PostCall_CachedMethodCall', 'PostCall_LogCompletedMethodCall', 'PostCall_UnLock'] 62 63 def __init__(self, session, object, method, parent, logname = None): 64 global callWrapperID 65 if logname is None: 66 import carbon.common.script.net.machobase as macho 67 logname = macho.GetLogName(object) 68 self.__logname__ = logname 69 self.__session__ = session 70 self.__method__ = method 71 if method.endswith('_Ex'): 72 self.__method_without_Ex__ = method[:-3] 73 else: 74 self.__method_without_Ex__ = method 75 self.__callable__ = object 76 self.__parent__ = parent 77 self.__metadata__ = getattr(self.__callable__, '__exportedcalls__', {}).get(self.__method_without_Ex__, []) 78 self.__thread__ = stackless.getcurrent() 79 self.requiredRole = ROLE_SERVICE 80 callWrapperID += 1 81 allCallWrappers[callWrapperID] = self 82 83 def __call__(self, *args, **keywords): 84 machoNet = sm.GetServiceIfRunning('machoNet') 85 if machoNet and machoNet.IsClusterShuttingDown() and session.userid: 86 log.general.Log('Cluster shutting down, rejecting service call from %s' % session.userid, log.LGNOTICE) 87 return 88 from carbon.common.script.net.objectCaching import CacheOK 89 from carbon.common.script.sys.basesession import CallTimer 90 with CallTimer(self.__logname__ + '::' + self.__method_without_Ex__): 91 self.__arguments__ = args 92 mask = self.__session__.Masquerade({'base.caller': weakref.ref(self.__parent__)}) 93 try: 94 cookies = {} 95 result = None 96 tb = None 97 try: 98 try: 99 for method in self.__precall__: 100 if type(self.__metadata__) == types.DictType: 101 extra = self.__metadata__.get('callhandlerargs', {}) 102 else: 103 extra = {} 104 cookieName = method 105 if type(method) == types.StringType: 106 method = getattr(self.__callable__, method, getattr(self, method, None)) 107 cookies[cookieName] = method(self.__method__, args, keywords, **extra) 108 109 except CacheOK as result: 110 tb = sys.exc_info()[2] 111 sys.exc_clear() 112 except CachedResult as result: 113 tb = sys.exc_info()[2] 114 sys.exc_clear() 115 except Exception as result: 116 tb = sys.exc_info()[2] 117 sys.exc_clear() 118 except: 119 log.LogTraceback('Bummer in service.py, all bets are off') 120 raise 121 122 try: 123 if result is None: 124 args2 = args 125 if self.__method_without_Ex__ == self.__method__ or not session.role & ROLE_SERVICE: 126 preargs = [] 127 if type(self.__metadata__) == types.DictType: 128 if 'preargs' in self.__metadata__: 129 preargs = self.__metadata__['preargs'] 130 elif len(self.__metadata__) > 1: 131 preargs = self.__metadata__[1:] 132 if preargs: 133 args2 = len(preargs) * [None] + list(args) 134 for i in range(len(preargs)): 135 args2[i] = getattr(session, preargs[i]) 136 137 try: 138 if boot.role == 'server' and self.requiredRole in (ROLE_ANY, ROLE_PLAYER) and getattr(session, 'clientID', None) is not None: 139 if prefs.GetValue('enableSecurityMonitor', 0): 140 sm.GetService('securityMonitor').LogCallFromClient(getattr(self.__callable__, '__guid__', 'guid not found'), self.__method_without_Ex__, args2, keywords) 141 except Exception as e: 142 log.LogException('Exception invoking the security monitor. Continuing processing the call') 143 sys.exc_clear() 144 145 if hasattr(self.__callable__, 'PreCallAction'): 146 self.__callable__.PreCallAction(self.__method_without_Ex__) 147 result = getattr(self.__callable__, self.__method_without_Ex__)(*args2, **keywords) 148 except UserError as result: 149 tb = sys.exc_info()[2] 150 sys.exc_clear() 151 except Exception as result: 152 tb = sys.exc_info()[2] 153 sys.exc_clear() 154 except: 155 log.LogTraceback('OMG caught something else during call') 156 raise 157 158 for method in self.__postcall__: 159 try: 160 if type(self.__metadata__) == types.DictType: 161 extra = self.__metadata__.get('callhandlerargs', {}) 162 else: 163 extra = {} 164 if type(method) == types.StringType: 165 method = getattr(self.__callable__, method, getattr(self, method, None)) 166 method(cookies, result, self.__method__, args, keywords, **extra) 167 except CacheOK as result: 168 tb = sys.exc_info()[2] 169 sys.exc_clear() 170 except CachedResult as result: 171 tb = sys.exc_info()[2] 172 sys.exc_clear() 173 except Exception as result: 174 tb = sys.exc_info()[2] 175 sys.exc_clear() 176 except: 177 log.LogTraceback('argh! caught something else during call') 178 raise 179 180 if result is not None: 181 if isinstance(result, Exception): 182 raise_(result, None, tb) 183 elif isinstance(result, CachedResult): 184 return result.result 185 finally: 186 tb = None 187 188 finally: 189 mask.UnMask() 190 self.__dict__.clear() 191 192 return result 193 194 def PreCall_StartCallTimer(self, method, args, keywords, **mykeywords): 195 from carbon.common.script.sys.basesession import CallTimer 196 return CallTimer(self.__logname__ + '::' + self.__method_without_Ex__) 197 198 def PostCall_StopCallTimer(self, cookies, result, method, args, keywords, **mykeywords): 199 sct = cookies.get('PreCall_StartCallTimer', None) 200 if sct is not None: 201 sct.Done() 202 203 __machomethods__ = ('MachoResolve', 'MachoBindObject', 'MachoResolveObject', 'MachoGetObjectBoundToSession') 204 205 def PreCall_IsExportedCall(self, method, args, keywords, **mykeywords): 206 if method in ('SetLogInfo', 'SetLogWarning', 'SetLogNotice'): 207 return 208 if method not in self.__callable__.__exportedcalls__ and method not in self.__machomethods__: 209 if not (self.__method__ != self.__method_without_Ex__ and self.__method_without_Ex__ in self.__callable__.__exportedcalls__): 210 raise RuntimeError('In %s, method %s is not exported' % (self.__logname__, self.__method_without_Ex__)) 211 212 def PreCall_RoleCheck(self, method, args, keywords, **mykeywords): 213 if not session.role & ROLE_SERVICE: 214 if type(self.__metadata__) == types.DictType: 215 role = self.__metadata__.get('role', ROLE_SERVICE) 216 elif len(self.__metadata__): 217 role = self.__metadata__[0] 218 elif method in self.__machomethods__: 219 role = ROLE_ANY 220 else: 221 role = ROLE_SERVICE 222 self.requiredRole = role 223 if not role & session.role: 224 session.LogSessionError("Called %s::%s, which requires role 0x%x, which the user doesn't have. User has role 0x%x" % (self.__logname__, 225 method, 226 role, 227 session.role)) 228 raise RuntimeError('RoleNotAssigned', "%s::%s requires role 0x%x, which the user doesn't have. User has role 0x%x. Calling session: %s" % (self.__logname__, 229 method, 230 role, 231 session.role, 232 str(session))) 233 234 def PreCall_CheckPreArgs(self, method, args, keywords, **mykeywords): 235 if not (session.role & ROLE_SERVICE and method.endswith('_Ex')): 236 if type(self.__metadata__) == types.DictType: 237 preargs = self.__metadata__.get('preargs', []) 238 elif len(self.__metadata__): 239 preargs = self.__metadata__[1:] 240 else: 241 preargs = [] 242 for each in preargs: 243 prearg = getattr(session, each) 244 if prearg is None: 245 session.LogSessionError('A required parameter exception occurred while the user was calling %s::%s. The missing parameter was %s' % (self.__logname__, self.__method_without_Ex__, each)) 246 raise RuntimeError('RequiredParameterException', "%s::%s requires parameter %s, which the session doesn't have. Calling session: %s" % (self.__logname__, 247 self.__method_without_Ex__, 248 each, 249 str(session))) 250 251 def PostCall_LogCompletedMethodCall(self, cookies, result, method, args, keywords, **mykeywords): 252 logChannel = log.methodcalls 253 if logChannel.IsOpen(log.LGINFO): 254 if isinstance(result, Exception): 255 eorr = ', EXCEPTION=' 256 else: 257 eorr = ', retval=' 258 if keywords: 259 logwhat = [self.__logname__, 260 '::', 261 method, 262 ' args=', 263 args, 264 ', keywords={', 265 keywords, 266 '}', 267 eorr, 268 result] 269 else: 270 logwhat = [self.__logname__, 271 '::', 272 method, 273 ' args=', 274 args, 275 eorr, 276 result] 277 try: 278 s = ''.join(map(supersafestr, logwhat)) 279 if len(s) > 2500: 280 s = s[:2500] 281 logChannel.Log(s, log.LGINFO, 1) 282 except TypeError: 283 logChannel.Log('[X]'.join(map(supersafestr, logwhat)).replace('\x00', '\\0'), log.LGINFO, 1) 284 sys.exc_clear() 285 except UnicodeEncodeError: 286 logChannel.Log('[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, logwhat))), log.LGINFO, 1) 287 sys.exc_clear() 288 289 def PreCall_Lock(self, method, args, keywords, **mykeywords): 290 lock = mykeywords.get('lock.lock', 1) 291 if lock: 292 scope = mykeywords.get('lock.scope', 'usersession') 293 if scope == 'usersession' and self.__session__.role & ROLE_SERVICE: 294 return 295 useargs = mykeywords.get('lock.useargs', 0) 296 try: 297 group = mykeywords['lock.group'] 298 except KeyError: 299 group = (self.__logname__, method) 300 if scope == 'instance': 301 group = self.__logname__ 302 303 if useargs: 304 k = ('PreCall_Lock', group, args) 305 else: 306 k = ('PreCall_Lock', group) 307 if scope in ('usersession', 'session'): 308 k = (k, 'session', self.__session__.sid) 309 elif scope == 'connection': 310 k = (k, 'connection', self.__parent__.__c2ooid__) 311 elif scope == 'instance': 312 k = (k, 'instance', self.__parent__.GetInstanceID()) 313 elif scope == 'service': 314 if isinstance(self.__callable__, CoreService): 315 k = (k, 'service', self.__parent__.GetInstanceID()) 316 else: 317 srv = sm.StartService(self.__parent__.__serviceName__) 318 k = (k, 'service', srv.startedWhen) 319 elif scope in ('class', 'global'): 320 if scope == 'class': 321 try: 322 k = (k, scope, self.__callable__.__class__.__name__) 323 except: 324 k = (k, 325 scope, 326 'logname', 327 self.__logname__) 328 329 l = callWrapperLocks.get(k, None) 330 if not l: 331 l = [uthread.Semaphore(k), None] 332 callWrapperLocks[k] = l 333 cool = True 334 else: 335 cool = l[0].IsCool() 336 if not cool: 337 reaction = mykeywords.get('lock.reaction', 'block') 338 if reaction == 'raise': 339 othermethod = '<unknown>' 340 if l[1] is not None: 341 othermethod = l[1][0] 342 raise UserError(mykeywords.get('lock.raisemsg', 'CallGroupLocked'), {'thismethod': method, 343 'group': group, 344 'scope': scope, 345 'othermethod': othermethod}) 346 else: 347 if reaction == 'inform': 348 keywords['reentrancy'] = l[1] 349 return 350 if reaction == 'ignore': 351 raise CachedResult(None) 352 sys.exc_clear() 353 l[0].acquire() 354 l[1] = (method, args, keywords) 355 return k 356 357 def PostCall_UnLock(self, cookies, result, method, args, keywords, **mykeywords): 358 k = cookies.get('PreCall_Lock', None) 359 if k is not None: 360 l = callWrapperLocks[k] 361 l[1] = None 362 l[0].release() 363 if l[0].IsCool(): 364 try: 365 if callWrapperLocks[k] is l: 366 del callWrapperLocks[k] 367 except KeyError: 368 pass 369 370 def PreCall_CachedMethodCall(self, method, args, keywords, **mykeywords): 371 machoVersion = keywords.get('machoVersion', None) 372 if machoVersion and not mykeywords.get('PreCall_CachedMethodCall.retainMachoVersion', 0): 373 if len(keywords) == 1: 374 keywords.clear() 375 else: 376 del keywords['machoVersion'] 377 cacheInfo = sm.GetService('objectCaching').PerformCachedMethodCall(self.__callable__, self.__logname__, self.__method_without_Ex__, args, machoVersion) 378 cachable, versionCheck, throwOK, cachedResultRecord, cacheKey, cacheDetails = cacheInfo 379 if cachable and not versionCheck: 380 if throwOK: 381 from carbon.common.script.net.objectCaching import CacheOK 382 raise CacheOK() 383 elif cachedResultRecord: 384 if machoVersion: 385 raise CachedResult(cachedResultRecord['rret']) 386 else: 387 raise CachedResult(cachedResultRecord['lret']) 388 return (cacheInfo, machoVersion) 389 390 def PostCall_CachedMethodCall(self, cookies, result, method, args, keywords, **mykeywords): 391 cookie = cookies.get('PreCall_CachedMethodCall', None) 392 if cookie is not None: 393 if not isinstance(result, Exception): 394 cacheInfo, machoVersion = cookie 395 if cacheInfo[0]: 396 srv = sm.StartService('objectCaching') 397 from carbon.common.script.net.objectCaching import CachedMethodCallResult, CacheOK 398 cachable, versionCheck, throwOK, cachedResultRecord, cacheKey, cacheDetails = cacheInfo 399 cmcr = CachedMethodCallResult(cacheKey, cacheDetails, result) 400 srv.CacheMethodCall(self.__logname__, self.__method_without_Ex__, args, cmcr) 401 if machoVersion is not None: 402 if machoVersion != 1 and cmcr.GetVersion()[1] == machoVersion[1]: 403 srv.LogInfo('ObjectCaching ', self.__logname__, '::', self.__method_without_Ex__, '(', args, ') is the correct version. raising CacheOK') 404 raise CacheOK() 405 else: 406 srv.LogInfo('ObjectCaching ', self.__logname__, '::', self.__method_without_Ex__, '(', args, ') is not the correct version. returning a cachable result. caller=', machoVersion, ', server=', cmcr.GetVersion()) 407 raise CachedResult(cmcr) 408 else: 409 errorDesc = "ObjectCaching %s::%s (%s) - the client didn't provide a macho version, not even the default value. Probably an unbound call to a cached method call, which is NOT supported." % (self.__logname__, self.__method_without_Ex__, args) 410 411 412 class ServiceCallWrapper(CallWrapper): 413 if boot.role == 'client': 414 __precall__ = ['PreCall_WaitForRunningState', 415 'PreCall_IsExportedCall', 416 'PreCall_CheckPreArgs', 417 'PreCall_CachedMethodCall'] 418 else: 419 __precall__ = ['PreCall_WaitForRunningState', 420 'PreCall_IsExportedCall', 421 'PreCall_RoleCheck', 422 'PreCall_CheckPreArgs', 423 'PreCall_CachedMethodCall', 424 'PreCall_Lock'] 425 426 def PreCall_WaitForRunningState(self, method, args, keywords, **mykeywords): 427 i = 0 428 while self.__callable__.state != SERVICE_RUNNING: 429 if self.__callable__.state == SERVICE_STOPPED: 430 raise RuntimeError('ServiceStopped', self.__callable__) 431 blue.pyos.synchro.SleepWallclock(100) 432 if i % 600 == 0 and i > 0: 433 self.__callable__.LogWarn('PreCallHandler: ', method, args, keywords, ' has been sleeping for a long time waiting for ', self.__logname__, ' to either get to running state, or to stopped state') 434 435 436 class UnlockedServiceCallWrapper(ServiceCallWrapper): 437 if boot.role == 'client': 438 __precall__ = ['PreCall_WaitForRunningState', 439 'PreCall_IsExportedCall', 440 'PreCall_CheckPreArgs', 441 'PreCall_CachedMethodCall'] 442 else: 443 __precall__ = ['PreCall_WaitForRunningState', 444 'PreCall_IsExportedCall', 445 'PreCall_RoleCheck', 446 'PreCall_CheckPreArgs', 447 'PreCall_CachedMethodCall'] 448 449 450 globalMiniTraceStats = {} 451 452 class MiniTraceCallWrapper(): 453 454 def __init__(self, service, func, funcName, depth): 455 self.service = weakref.proxy(service) 456 self.func = func 457 self.funcName = funcName 458 self.depth = depth 459 460 def __call__(self, *args, **kw): 461 if self.service.logChannel.IsOpen(1): 462 stats = globalMiniTraceStats[self.service.__guid__, self.funcName] 463 l = self.depth 464 if l == -1: 465 l = 2 466 tb = traceback.extract_stack(limit=l)[:-1] 467 tb = [ (i[0], i[2], i[1]) for i in tb ] 468 k0 = tb[-1] 469 for k in tb: 470 stats[k] = stats.get(k, 0) + 1 471 472 self.service.LogInfo(self.funcName, args, kw, ' is being called by ', k0[1], ' in line ', k0[2], ' of ', k0[0]) 473 return self.func(*args, **kw) 474 else: 475 return self.func(*args, **kw) 476 477 478 MiniTraceStats = globalMiniTraceStats 479 480 class CoreService(object): 481 __startupdependencies__ = [] 482 __dependencies__ = [] 483 __required__ = ['Sessions'] 484 __name__ = 'service' 485 __displayname__ = 'Basic Service' 486 __persistvars__ = [] 487 __nonpersistvars__ = [] 488 __exportedcalls__ = {} 489 __notifyevents__ = [] 490 __configvalues__ = {} 491 __counters__ = {} 492 __machocacheobjects__ = 1 493 __machoresolve__ = None 494 495 def __init__(self): 496 super(CoreService, self).__init__() 497 self.boundObjects = {} 498 self.serviceLocks = {} 499 self.startedWhen = blue.os.GetWallclockTimeNow() 500 self.__servicename__ = getattr(self, '__replaceservice__', self.__guid__.split('.')[1]) 501 self.__logname__ = self.__servicename__ 502 self.logChannel = log.GetChannel(self.__guid__) 503 self.InitService() 504 if len(self.__counters__) and 'counter' not in self.__startupdependencies__: 505 self.__startupdependencies__.append('counter') 506 self.isLogInfo = bool(prefs.GetValue('logInfo', 1)) 507 self.isLogNotice = bool(prefs.GetValue('logNotice', 1)) 508 self.isLogWarning = bool(prefs.GetValue('logWarning', 1)) 509 self.logContexts = {} 510 for each in ('Info', 'Warn', 'Error', 'Perf'): 511 self.logContexts[each] = 'Logging::' + each 512 513 def SetLogInfo(self, b): 514 if not b and self.isLogInfo: 515 self.LogInfo('*** LogInfo stopped for ', self.__guid__) 516 old = self.isLogInfo 517 self.isLogInfo = b 518 if b and not old: 519 self.LogInfo('*** LogInfo started for ', self.__guid__) 520 521 def SetLogNotice(self, b): 522 if not b and self.isLogNotice: 523 self.LogNotice('*** LogNotice stopped for ', self.__guid__) 524 old = self.isLogNotice 525 self.isLogNotice = b 526 if b and not old: 527 self.LogNotice('*** LogNotice started for ', self.__guid__) 528 529 def SetLogWarning(self, b): 530 if not b and self.isLogWarning: 531 self.LogWarn('*** LogWarn stopped for ', self.__guid__) 532 old = self.isLogWarning 533 self.isLogWarning = b 534 if b and not old: 535 self.LogWarn('*** LogWarn started for ', self.__guid__) 536 537 def MachoResolve(self, sess): 538 if self.__machoresolve__ is not None: 539 return self._MachoResolveAdditional(sess) 540 541 def _MachoResolveAdditional(self, sess): 542 if self.__machoresolve__ is None: 543 return 544 if sess.role & ROLE_SERVICE: 545 return 546 macho = sm.GetService('machoNet') 547 if self.__machoresolve__ == 'station': 548 if not sess.stationid: 549 return 'You must be located at a station to use this service' 550 return macho.GetNodeFromAddress(SERVICE_STATION, sess.stationid) 551 if self.__machoresolve__ == 'solarsystem': 552 if not sess.solarsystemid: 553 return 'You must be located in a solar system to use this service' 554 return macho.GetNodeFromAddress(SERVICE_BEYONCE, sess.solarsystemid) 555 if self.__machoresolve__ == 'solarsystem2': 556 if not sess.solarsystemid2: 557 return 'Your location must belong to a known solarsystem' 558 return macho.GetNodeFromAddress(SERVICE_BEYONCE, sess.solarsystemid2) 559 if self.__machoresolve__ in ('location', 'locationPreferred'): 560 if not sess.locationid: 561 if self.__machoresolve__ == 'locationPreferred': 562 return 563 return 'You must be located in a solar system or at station to use this service' 564 if sess.solarsystemid: 565 return macho.GetNodeFromAddress(SERVICE_BEYONCE, sess.solarsystemid) 566 if sess.stationid: 567 return macho.GetNodeFromAddress(SERVICE_STATION, sess.stationid) 568 raise RuntimeError('machoresolving a location bound service with without a location session') 569 if self.__machoresolve__ in ('character',): 570 if sess.charid is None: 571 return 572 else: 573 return macho.GetNodeFromAddress(SERVICE_CHARACTER, sess.charid % CHARNODE_MOD) 574 if self.__machoresolve__ in ('corporation',): 575 if sess.corpid is None: 576 return 'You must have a corpid in your session to use this service' 577 else: 578 return macho.GetNodeFromAddress(SERVICE_CHATX, sess.corpid % 200) 579 if self.__machoresolve__.startswith('clustersingleton'): 580 return GetClusterSingletonNodeFromAddress(macho, self.__machoresolve__) 581 if self.__machoresolve__ == 'user': 582 if sess.userid is None: 583 return 'You must have a userid in your session to use this service' 584 return macho.GetNodeFromAddress(SERVICE_USER, sess.userid % const.USERNODE_MOD) 585 raise RuntimeError('__machoresolve__ = %s on service %s is bogus.' % (self.__machoresolve__, self.__logname__)) 586 587 def __GetCachedObject(self, key): 588 return self.boundObjects.get(key, None) 589 590 def __SetCachedObject(self, key, object): 591 if self.__machocacheobjects__: 592 self.boundObjects[key] = object 593 594 def __DelCachedObject(self, key): 595 try: 596 del self.boundObjects[key] 597 except KeyError: 598 pass 599 600 def MachoGetObjectBoundToSession(self, bindParams, callerSession): 601 with self.LockedService(bindParams): 602 obj = self.__GetCachedObject(bindParams) 603 if obj is None: 604 obj = self.MachoBindObject(bindParams) 605 if not hasattr(obj, 'sessionConnections'): 606 obj.objectConnections = {} 607 obj.sessionConnections = weakref.WeakValueDictionary({}) 608 obj.machoInstanceID = blue.os.GetWallclockTimeNow() 609 obj.boundBy = bindParams 610 self.__SetCachedObject(bindParams, obj) 611 return ClockThisWithoutTheStars('CoreService::ConnectToObject', callerSession.ConnectToObject, (obj, self.__servicename__, bindParams)) 612 613 def RemoveSessionConnectionFromObject(self, connection): 614 boundObject = connection.__object__ 615 sessionID = connection.__session__.sid 616 connectionID = connection.__c2ooid__ 617 try: 618 del boundObject.objectConnections[sessionID][connectionID] 619 except KeyError: 620 pass 621 except Exception: 622 log.LogException() 623 624 try: 625 if not boundObject.objectConnections[sessionID]: 626 try: 627 connection.PseudoMethodCall(boundObject, 'OnSessionDetach') 628 except Exception: 629 log.LogException() 630 631 try: 632 del boundObject.sessionConnections[sessionID] 633 except KeyError: 634 self.LogError('Hmmm, session', sessionID, 'missing from', boundObject.sessionConnections.keys(), 'disconnected?', connection.__disconnected__) 635 636 except KeyError: 637 self.LogError('Woot? Session', sessionID, "isn't in", boundObject.objectConnections.keys()) 638 639 try: 640 del connection.__session__.connectedObjects[connectionID] 641 except KeyError: 642 log.LogException() 643 644 with self.LockedService(boundObject.boundBy): 645 if hasattr(boundObject, 'sessionConnections'): 646 if len(boundObject.sessionConnections) == 0: 647 delattr(boundObject, 'sessionConnections') 648 self.__DelCachedObject(boundObject.boundBy) 649 if len(boundObject.objectConnections): 650 boundObject.objectConnections.clear() 651 connection.PseudoMethodCall(boundObject, 'OnStop') 652 if hasattr(boundObject, 'service'): 653 delattr(boundObject, 'service') 654 if hasattr(boundObject, 'session'): 655 delattr(boundObject, 'session') 656 for dependency in getattr(boundObject, 'dependencies', []): 657 delattr(boundObject, dependency) 658 659 def LockService(self, lockID): 660 try: 661 lock = self.serviceLocks[lockID] 662 except KeyError: 663 lock = locks.RLock(('service::serviceLock', self.__logname__, lockID)) 664 self.serviceLocks[lockID] = lock 665 666 lock.acquire() 667 return lock 668 669 def ServiceLockCheck(self, lockID): 670 if lockID not in self.serviceLocks or self.serviceLocks[lockID].IsCool(): 671 return 0 672 else: 673 return max(1, (blue.os.GetWallclockTime() - self.serviceLocks[lockID].lockedWhen) / const.SEC) 674 675 def UnLockService(self, lockID, lock): 676 lock.release() 677 if lock.IsCool(): 678 del self.serviceLocks[lockID] 679 680 class LockedServiceCtxt(object): 681 682 def __init__(self, svc, lockKey): 683 self.svc = svc 684 self.lockKey = lockKey 685 686 def __enter__(self): 687 self.lock = self.svc.LockService(self.lockKey) 688 689 def __exit__(self, e, v, tb): 690 self.svc.UnLockService(self.lockKey, self.lock) 691 692 def LockedService(self, lockKey): 693 return self.LockedServiceCtxt(self, lockKey) 694 695 def StartMiniTrace(self, funcName, depth = 16): 696 if funcName not in globalMiniTraceStats: 697 globalMiniTraceStats[self.__guid__, funcName] = {} 698 setattr(self, funcName, MiniTraceCallWrapper(self, getattr(self, funcName), funcName, depth)) 699 700 def StopMiniTrace(self, funcName, depth = 16): 701 if funcName not in globalMiniTraceStats: 702 del globalMiniTraceStats[self.__guid__, funcName] 703 setattr(self, funcName, getattr(self, funcName).func) 704 705 def GetDependants(self): 706 dependants = [] 707 myName = self.__servicename__ 708 for i in sm.services: 709 if myName in sm.services[i].__dependencies__: 710 dependants.append(sm.services[i].__servicename__) 711 712 return dependants 713 714 def GetDeepDependants(self, theArr): 715 newbies = [] 716 for each in self.GetDependants(): 717 if each not in theArr: 718 newbies.append(each) 719 theArr.append(each) 720 721 for each in newbies: 722 sm.services[each].GetDeepDependants(theArr) 723 724 def GetDeepDependencies(self, theArr): 725 newbies = [] 726 for each in self.__dependencies__: 727 if each not in theArr: 728 newbies.append(each) 729 theArr.append(each) 730 731 for each in newbies: 732 sm.services[each].GetDeepDependencies(theArr) 733 734 def InitService(self): 735 self.state = SERVICE_STOPPED 736 737 def __getattr__(self, key): 738 if key in self.__configvalues__: 739 daKey = '%s.%s' % (self.__logname__, key) 740 return prefs.GetValue(daKey, boot.GetValue(daKey, self.__configvalues__[key])) 741 if key in self.__counters__: 742 self.__dict__[key] = self.counter.CreateCounter(key, self.__counters__[key]) 743 return self.__dict__[key] 744 if hasattr(self.__class__, key): 745 return getattr(self.__class__, key) 746 raise_(AttributeError, key) 747 748 def __setattr__(self, key, value): 749 super(CoreService, self).__setattr__(key, value) 750 if key in self.__configvalues__: 751 value = self.OnSetConfigValue(key, value) 752 prefs.SetValue('%s.%s' % (self.__logname__, key), value) 753 return 754 self.__dict__[key] = value 755 756 def ControlMessage(self, control): 757 if control == SERVICE_CONTROL_STOP: 758 self.state = SERVICE_STOPPED 759 elif control == SERVICE_CONTROL_PAUSE: 760 self.state = SERVICE_PAUSED 761 elif control == SERVICE_CONTROL_CONTINUE: 762 self.state = SERVICE_RUNNING 763 elif control == SERVICE_CONTROL_INTERROGATE: 764 pass 765 elif control == SERVICE_CONTROL_SHUTDOWN: 766 self.state = SERVICE_STOPPED 767 768 def DudLogger(self, *args, **keywords): 769 pass 770 771 def LogMethodCall(self, *args, **keywords): 772 logChannel = log.methodcalls 773 if logChannel.IsOpen(log.LGINFO): 774 try: 775 s = ' '.join(map(supersafestr, args)) 776 logChannel.Log(s, log.LGINFO, 1) 777 except TypeError: 778 logChannel.Log('[X]'.join(map(supersafestr, args)).replace('\x00', '\\0'), log.LGINFO, 1) 779 sys.exc_clear() 780 except UnicodeEncodeError: 781 logChannel.Log('[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args))), log.LGINFO, 1) 782 sys.exc_clear() 783 784 else: 785 self.LogMethodCall = self.DudLogger 786 787 def LogInfo(self, *args, **keywords): 788 if getattr(self, 'isLogInfo', 0) and self.logChannel.IsLogChannelOpen(1): 789 try: 790 s = ' '.join(map(supersafestr, args)) 791 self.logChannel.Log(s, 1, 1, force=True) 792 except TypeError: 793 self.logChannel.Log('[X]'.join(map(supersafestr, args)).replace('\x00', '\\0'), 1, 1, force=True) 794 sys.exc_clear() 795 except UnicodeEncodeError: 796 self.logChannel.Log('[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args))), 1, 1, force=True) 797 sys.exc_clear() 798 799 def LogWarn(self, *args, **keywords): 800 if self.isLogWarning and self.logChannel.IsLogChannelOpen(2) or charsession and not boot.role == 'client': 801 try: 802 s = ' '.join(map(supersafestr, args)) 803 if self.logChannel.IsOpen(2): 804 self.logChannel.Log(s, 2, 1, force=True) 805 for x in LineWrap(s, 10): 806 if charsession and not boot.role == 'client': 807 charsession.LogSessionHistory(x, None, 1) 808 809 except TypeError: 810 sys.exc_clear() 811 x = '[X]'.join(map(supersafestr, args)).replace('\x00', '\\0') 812 if self.logChannel.IsOpen(2): 813 self.logChannel.Log(x, 2, 1, force=True) 814 if charsession and not boot.role == 'client': 815 charsession.LogSessionHistory(x, None, 1) 816 except UnicodeEncodeError: 817 sys.exc_clear() 818 x = '[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args))) 819 if self.logChannel.IsOpen(2): 820 self.logChannel.Log(x, 2, 1, force=True) 821 if charsession and not boot.role == 'client': 822 charsession.LogSessionHistory(x, None, 1) 823 824 def LogError(self, *args, **keywords): 825 if self.logChannel.IsOpen(4) or charsession: 826 try: 827 s = ' '.join(map(supersafestr, args)) 828 if self.logChannel.IsOpen(4): 829 self.logChannel.Log(s, 4, 1) 830 for x in LineWrap(s, 40): 831 if charsession: 832 charsession.LogSessionHistory(x, None, 1) 833 834 except TypeError: 835 sys.exc_clear() 836 x = '[X]'.join(map(supersafestr, args)).replace('\x00', '\\0') 837 if self.logChannel.IsOpen(4): 838 self.logChannel.Log(x, 4, 1) 839 if charsession: 840 charsession.LogSessionHistory(x, None, 1) 841 except UnicodeEncodeError: 842 sys.exc_clear() 843 x = '[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args))) 844 if self.logChannel.IsOpen(4): 845 self.logChannel.Log(x, 4, 1) 846 if charsession and not boot.role == 'client': 847 charsession.LogSessionHistory(x, None, 1) 848 849 def LogNotice(self, *args, **_unused_keywords): 850 if getattr(self, 'isLogNotice', 0) and self.logChannel.IsLogChannelOpen(log.LGNOTICE): 851 try: 852 s = ' '.join(map(supersafestr, args)) 853 self.logChannel.Log(s, log.LGNOTICE, 1, force=True) 854 except TypeError: 855 s = '[X]'.join(map(supersafestr, args)).replace('\x00', '\\0') 856 self.logChannel.Log(s, log.LGNOTICE, 1, force=True) 857 sys.exc_clear() 858 except UnicodeEncodeError: 859 s = '[U]'.join(map(lambda x: x.encode('ascii', 'replace'), map(unicode, args))) 860 self.logChannel.Log(s, log.LGNOTICE, 1, force=True) 861 sys.exc_clear() 862 863 def LogException(self, extraText = ''): 864 log.LogException(extraText, channel=self.__guid__) 865 sys.exc_clear() 866 867 def LogTraceback(self, extraText = ''): 868 log.LogTraceback(extraText, show_locals=2, channel=self.__guid__) 869 870 def Run(self, memStream = None): 871 self.LogInfo('Service: %s starting' % (self.__guid__,)) 872 self.boundObjects = {} 873 874 def Entering(self): 875 pass 876 877 def Stop(self, memStream = None): 878 for bo in self.boundObjects.values(): 879 for sess in bo.sessionConnections.values(): 880 sess.DisconnectObject(bo) 881 882 self.boundObjects = {} 883 884 def IsRunning(self): 885 return getattr(self, 'state', SERVICE_STOPPED) == SERVICE_RUNNING 886 887 def GetSessionState(self, session_ = None): 888 if session_ is not None: 889 session = session_ 890 if session is None: 891 raise RuntimeError('No session') 892 return session.GetBag(self.__guid__) 893 894 def GetServiceState(self): 895 states = {SERVICE_STOPPED: 'Stopped', 896 SERVICE_START_PENDING: 'Start Pending', 897 SERVICE_STOP_PENDING: 'Stop Pending', 898 SERVICE_RUNNING: 'Running', 899 SERVICE_CONTINUE_PENDING: 'Continue Pending', 900 SERVICE_PAUSE_PENDING: 'Pause Pending', 901 SERVICE_PAUSED: 'Paused', 902 SERVICE_FAILED: 'Failed to start'} 903 return states.get(self.state, 'unknown') 904 905 def GetHtmlState(self, writer, session = None, request = None): 906 from carbon.common.script.util import htmlwriter 907 wr = htmlwriter.HtmlWriter() 908 if writer is None: 909 return '(no info available)' 910 writer.Write(self.HTMLDumpProperties('Basic Service properties', 'wpServiceProperties', self, session, request)) 911 if len(self.__configvalues__): 912 hd = ['Key', 913 'Pretty Name', 914 'Value', 915 'Default Value', 916 'Info'] 917 li = [] 918 for each in self.__configvalues__.iterkeys(): 919 prettyname = each 920 info = None 921 value = getattr(self, each) 922 if hasattr(self, 'GetHtmlStateDetails'): 923 r = self.GetHtmlStateDetails(each, value, 0) 924 if r: 925 prettyname, info = r[0], r[1] 926 if value != self.__configvalues__[each]: 927 value = '<b>%s</b>' % value 928 li.append([each, 929 prettyname, 930 value, 931 self.__configvalues__[each], 932 info]) 933 934 li.sort(lambda a, b: -(a[0].upper() < b[0].upper())) 935 edit = '<a href="/admin/services.py?action=EditConfigValues&svcname=%s">Click to edit</a>' % (self.__servicename__,) 936 writer.Write(htmlwriter.WebPart('Service Config Values - ' + edit, wr.GetTable(hd, li, useFilter=True), 'wpServiceConfigValues')) 937 if len(self.__counters__): 938 hd = ['Key', 939 'Pretty Name', 940 'Type', 941 'Current Value', 942 'Description'] 943 li = [] 944 for each in self.__counters__.iterkeys(): 945 cname = each 946 prettyname = cname 947 ctype = self.__counters__[each] 948 cvalue = 0 949 if hasattr(self, each): 950 cvalue = getattr(self, each).Value() 951 info = '' 952 if hasattr(self, 'GetHtmlStateDetails'): 953 r = self.GetHtmlStateDetails(each, cvalue, 0) 954 if r: 955 prettyname, info = r[0], r[1] 956 li.append([cname, 957 prettyname, 958 ctype, 959 cvalue, 960 info]) 961 962 li.sort(lambda a, b: -(a[0].upper() < b[0].upper())) 963 reset = '<a href="/admin/services.py?action=ResetCounters&svcname=%s" onClick="return confirm(\'Are you sure?\')">Click to reset</a>' % (self.__servicename__,) 964 writer.Write(htmlwriter.WebPart('Service Counters - ' + reset, wr.GetTable(hd, li, useFilter=True), 'wpServiceCounters')) 965 det = '<a href="/admin/services.py?svcname=%s&propertyDetail=yes">Click to view details</a><br>' % self.__servicename__ 966 writer.Write(htmlwriter.WebPart('Service Member Variables - %s' % det, self.HTMLDumpGenericMembers(self, session, request), 'wpServiceMemberVariables')) 967 if hasattr(self, 'boundObjects'): 968 if request: 969 objectDetail = request.QueryString('objectDetail') 970 if objectDetail is not None: 971 objectDetail = cPickle.loads(binascii.a2b_hex(objectDetail)) 972 else: 973 objectDetail = None 974 object = self.boundObjects.get(objectDetail, None) 975 if object: 976 writer.WriteH2('Bound Object %s' % unicode(objectDetail)) 977 if object.__doc__ is not None: 978 writer.Write(htmlwriter.Swing(object.__doc__).replace('\n', '<br>')) 979 writer.Write(self.HTMLDumpProperties('Properties of Bound Object %s' % unicode(objectDetail), 'wpBoundObjectProperties %s' % unicode(objectDetail), object, session, request)) 980 writer.Write(self.HTMLDumpGenericMembers(object, session, request)) 981 self.HTMLWriteServiceMethods(writer, session, request) 982 self.HTMLWriteExtraState(writer, session, request) 983 984 def HTMLWriteExtraState(self, writer, session, request): 985 pass 986 987 def HTMLWriteServiceMethods(self, writer, session, request): 988 from carbon.common.script.util import htmlwriter 989 hd = ['Method', 'Roles'] 990 li = [] 991 for method in self.__exportedcalls__: 992 details = self.__exportedcalls__[method] 993 if type(details) == types.DictType: 994 role = details.get('role', 0) 995 elif len(details) > 0: 996 role = details[0] 997 else: 998 role = 0 999 from carbon.common.script.sys import serviceConst 1000 if role == serviceConst.ROLE_ANY: 1001 rolestr = 'ANY' 1002 else: 1003 rolestr = '' 1004 for each in dir(serviceConst): 1005 if each.startswith('ROLE_') and getattr(serviceConst, each) & role != 0: 1006 rolestr += each[5:] + ', ' 1007 1008 rolestr = rolestr[:-2] 1009 li.append([writer.Link('', method, {'action': 'WebExec', 1010 'service': self.__guid__.split('.')[1], 1011 'method': method}), rolestr]) 1012 1013 li.sort() 1014 wr = htmlwriter.HtmlWriter() 1015 writer.Write(htmlwriter.WebPart('Service Methods', wr.GetTable(hd, li, useFilter=True), 'wpServiceMethods')) 1016 svcname = self.__servicename__ 1017 txt = '<table>' 1018 txt += '\n <tr><td>Info Logging:</td><td> %s</td><td>\n | <a href="?action=ToggleInfoLog&svcname=%s&which=%s">Toggle</a>\n · <a href="?action=ToggleInfoLog&svcname=%s&allnodes=1&which=1" OnClick="return confirm(\'Are you sure?\');">Start on All Nodes</a>\n · <a href="?action=ToggleInfoLog&svcname=%s&allnodes=1&which=0">Stop on All Nodes</a></tr>\n ' % (['OFF', '<font color=red><b>ON</b></font>'][self.isLogInfo], 1019 svcname, 1020 int(not self.isLogInfo), 1021 svcname, 1022 svcname) 1023 txt += '\n <tr><td>Notice Logging:</td><td> %s</td><td>\n | <a href="?action=ToggleNoticeLog&svcname=%s&which=%s">Toggle</a>\n · <a href="?action=ToggleNoticeLog&svcname=%s&allnodes=1&which=1" OnClick="return confirm(\'Are you sure?\');">Start on All Nodes</a>\n · <a href="?action=ToggleNoticeLog&svcname=%s&allnodes=1&which=0">Stop on All Nodes</a></tr>\n ' % (['OFF', '<font color=red><b>ON</b></font>'][self.isLogNotice], 1024 svcname, 1025 int(not self.isLogNotice), 1026 svcname, 1027 svcname) 1028 txt += '\n <tr><td>Warning Logging:</td><td> %s</td><td>\n | <a href="?action=ToggleWarningLog&svcname=%s&which=%s">Toggle</a>\n · <a href="?action=ToggleWarningLog&svcname=%s&allnodes=1&which=1">Start on All Nodes</a>\n · <a href="?action=ToggleWarningLog&svcname=%s&allnodes=1&which=0">Stop on All Nodes</a></tr>\n ' % (['OFF', '<b>ON</b>'][self.isLogWarning], 1029 svcname, 1030 int(not self.isLogWarning), 1031 svcname, 1032 svcname) 1033 txt += '</table>' 1034 writer.Write(htmlwriter.WebPart('Logging', '<div style="padding:5px;">%s</div>' % txt, 'wpServiceLogging')) 1035 1036 def HTMLDumpGenericMembers(self, dumpWho, session, request): 1037 from carbon.common.script.util import htmlwriter 1038 wr = htmlwriter.HtmlWriter() 1039 if request: 1040 detail = request.QueryString('detail') 1041 else: 1042 detail = None 1043 if request: 1044 propertyDetails = request.QueryString('propertyDetail') == 'yes' 1045 from carbon.common.script.util.profiling import CalcMemoryUsage 1046 else: 1047 propertyDetails = False 1048 1049 def Str(v): 1050 from carbon.common.script.util import htmlwriter 1051 try: 1052 return htmlwriter.Swing(unicode(v)) 1053 except: 1054 sys.exc_clear() 1055 return '(?)' 1056 1057 li = [] 1058 theItems = dumpWho.__dict__.keys() 1059 theItems.sort(lambda a, b: -(a.upper() < b.upper())) 1060 something = 0 1061 for k in theItems: 1062 v = dumpWho.__dict__[k] 1063 if hasattr(dumpWho, '__dependencies__') and k in dumpWho.__dependencies__: 1064 continue 1065 if hasattr(dumpWho, '__configvalues__') and k in dumpWho.__configvalues__: 1066 continue 1067 if hasattr(dumpWho, '__exportedcalls__') and k in dumpWho.__exportedcalls__: 1068 continue 1069 if hasattr(dumpWho, '__counters__') and k in dumpWho.__counters__: 1070 continue 1071 if k in ('state', 'startedWhen', 'serviceLocks', 'logChannel', 'session', 'boundObjects', '__servicelock__', 'objectConnections', 'sessionConnections', '__sessionfilter__', '__logname__', 'logContexts'): 1072 continue 1073 if k.startswith('_' + dumpWho.__class__.__name__ + '__'): 1074 k = k[len('_' + dumpWho.__class__.__name__):] 1075 r = None 1076 ok = k 1077 if hasattr(dumpWho, 'GetHtmlStateDetails'): 1078 r = dumpWho.GetHtmlStateDetails(k, v, k == detail) 1079 if r: 1080 if propertyDetails and type(r[1]) in types.StringTypes: 1081 xtra = ' [type: %s]' % type(v).__name__ 1082 length = None 1083 try: 1084 length = len(v) 1085 xtra += ' [length: %d]' % len(v) 1086 except: 1087 pass 1088 1089 try: 1090 xtra += ' [memusage: %d]' % CalcMemoryUsage(v)[2] 1091 except: 1092 pass 1093 1094 k, v = r[0], r[1] 1095 else: 1096 k, v = r[0], r[1] 1097 elif k != detail: 1098 if type(v) in (types.ListType, 1099 types.TupleType, 1100 types.DictType, 1101 types.InstanceType) or isinstance(v, dict): 1102 xtra = '' 1103 if propertyDetails and (type(v) in (types.ListType, types.TupleType, types.DictType) or isinstance(v, dict)): 1104 xtra = ' - length: %d' % len(v) 1105 try: 1106 xtra += ' [memusage: %d kB]' % int(int(CalcMemoryUsage(v)[2]) / 1024) 1107 except Exception as e: 1108 xtra += ' [memusage: ??] %s' % e 1109 1110 v = '<click details to view> [type: %s]%s' % (type(v).__name__, xtra) 1111 else: 1112 v = Str(v) 1113 else: 1114 var = getattr(dumpWho, detail, None) 1115 if type(var) in [types.ListType, types.TupleType]: 1116 lines = [] 1117 for i in var: 1118 lines.append([Str(i)]) 1119 1120 v = htmlwriter.GetTable([], lines) 1121 elif isinstance(v, dict): 1122 lines = [] 1123 for key, val in var.iteritems(): 1124 lines.append([Str(key), Str(val)]) 1125 1126 v = htmlwriter.GetTable([], lines) 1127 else: 1128 v = Str(v) 1129 v = '<pre>%s</pre>' % v 1130 k = htmlwriter.Link('', k, [request.query, {'detail': ok}]) 1131 li.append([k, v]) 1132 something = 1 1133 1134 if not something: 1135 return 'This service does not have any custom member variables' 1136 return wr.GetTable([], li) 1137 1138 def HTMLDumpProperties(self, title, page, dumpWho, session, request): 1139 from carbon.common.script.util import htmlwriter 1140 1141 def Str(v): 1142 from carbon.common.script.util import htmlwriter 1143 try: 1144 return htmlwriter.Swing(unicode(v)) 1145 except: 1146 sys.exc_clear() 1147 return '(?)' 1148 1149 hd = ['Property', 'Value'] 1150 deepdependencies = [] 1151 if hasattr(dumpWho, 'GetDeepDependencies'): 1152 dumpWho.GetDeepDependencies(deepdependencies) 1153 deepdependants = [] 1154 if hasattr(dumpWho, 'GetDeepDependendants'): 1155 dumpWho.GetDeepDependants(deepdependants) 1156 dependencies = [] 1157 if hasattr(dumpWho, '__dependencies__'): 1158 dependencies = dumpWho.__dependencies__ 1159 dependants = [] 1160 if hasattr(dumpWho, 'GetDependants'): 1161 dependants = dumpWho.GetDependants() 1162 persistvars = [] 1163 if hasattr(dumpWho, '__persistvars__'): 1164 persistvars = dumpWho.__persistvars__ 1165 nonpersistvars = [] 1166 if hasattr(dumpWho, '__nonpersistvars__'): 1167 nonpersistvars = dumpWho.__nonpersistvars__ 1168 notifyevents = [] 1169 if hasattr(dumpWho, '__notifyevents__'): 1170 notifyevents = list(dumpWho.__notifyevents__) 1171 exportedcalls = [] 1172 if hasattr(dumpWho, '__exportedcalls__'): 1173 exportedcalls = dumpWho.__exportedcalls__.keys() 1174 objectConnections = [] 1175 for connectionByC2OOID in getattr(dumpWho, 'objectConnections', {}).itervalues(): 1176 for connection in connectionByC2OOID.itervalues(): 1177 objectConnections.append(Str(connection)) 1178 1179 sessionConnections = [] 1180 for each in getattr(dumpWho, 'sessionConnections', {}).itervalues(): 1181 sessionConnections.append(Str(each)) 1182 1183 boundObjects = [] 1184 if hasattr(dumpWho, 'boundObjects'): 1185 boundObjects = dumpWho.boundObjects.keys() 1186 sessionfilter = [] 1187 if hasattr(dumpWho, '__sessionfilter__'): 1188 sessionfilter = dumpWho.__sessionfilter__ 1189 1190 def Alphabetize(arr, objectDetail = False, dependency = False): 1191 try: 1192 li = arr[:] 1193 li.sort(lambda a, b: -(Str(a).upper() < Str(b).upper())) 1194 if objectDetail: 1195 li = [ htmlwriter.Link('', unicode(val), [request.query, {'objectDetail': binascii.b2a_hex(cPickle.dumps(val, 1))}]) for val in li ] 1196 elif dependency: 1197 li = [ htmlwriter.Link('', unicode(val), [request.query, {'svcname': unicode(val)}]) for val in li ] 1198 else: 1199 li = [ unicode(val) for val in li ] 1200 if len(li) > 100: 1201 return '< %d entries >' % len(li) 1202 return ', '.join(li) 1203 except: 1204 log.LogException() 1205 sys.exc_clear() 1206 return ', '.join(arr) 1207 1208 li = [['Objects bound to me', Alphabetize(boundObjects, objectDetail=True)], 1209 ['Sessions using me', Alphabetize(sessionConnections)], 1210 ['Objects using me', Alphabetize(objectConnections)], 1211 ['Session Filter', Alphabetize(sessionfilter)], 1212 ['I depend on', Alphabetize(dependencies, dependency=True)], 1213 ['<nobr>I depend on - recursively</nobr>', Alphabetize(deepdependencies, dependency=True)], 1214 ['Who depends on me', Alphabetize(dependants, dependency=True)], 1215 ['Who depends on me - recursively', Alphabetize(deepdependants, dependency=True)], 1216 ['Persistant Variables', Alphabetize(persistvars)], 1217 ['Non-persistant Variables', Alphabetize(nonpersistvars)], 1218 ['I listen to these events', Alphabetize(notifyevents)], 1219 ['I export these calls', Alphabetize(exportedcalls)]] 1220 if hasattr(dumpWho, 'GetServiceState'): 1221 li.append(['Service State', dumpWho.GetServiceState()]) 1222 if hasattr(dumpWho, 'session'): 1223 li.append(['Service Session', htmlwriter.Swing(repr(dumpWho.session))]) 1224 if hasattr(dumpWho, '__servicelock__'): 1225 li.append(['Service Lock', htmlwriter.Swing(unicode(getattr(dumpWho, '__servicelock__', None)))]) 1226 li.sort(lambda a, b: -(a[0].upper() < b[0].upper())) 1227 li = [ each for each in li if each[1] ] 1228 wr = htmlwriter.HtmlWriter() 1229 return htmlwriter.WebPart(title, wr.GetTable(hd, li, useFilter=True), page) 1230 1231 def OnSetConfigValue(self, key, value): 1232 return value 1233 1234 def GetSPConfigValues(self): 1235 r = [] 1236 for a in sorted(self.__configvalues__.keys()): 1237 v = getattr(self, a) 1238 t = type(getattr(self, a)) 1239 r.append((a, v, t)) 1240 1241 return r 1242 1243 def SetSPConfigValues(self, values): 1244 for a in self.__configvalues__.keys(): 1245 if a in values: 1246 setattr(self, a, values[a]) 1247 1248 1249 def GetClusterSingletonNodeFromAddress(mn, machoresolve): 1250 try: 1251 num = int(machoresolve.split('_')[1]) 1252 except: 1253 log.general.Log('clustersingleton machoresolve without mod number. Using 0') 1254 num = 0 1255 1256 numMod = num % const.CLUSTERSINGLETON_MOD 1257 if num >= const.CLUSTERSINGLETON_MOD: 1258 log.general.Log('clustersingleton machoresolve with out-of-bounds mod number', num, 'rolling over to', numMod, log.LGWARN) 1259 return mn.GetNodeFromAddress(SERVICE_CLUSTERSINGLETON, numMod) 1260 1261 1262 class AppProxyService(CoreService): 1263 __solservice__ = None 1264 1265 def __init__(self): 1266 self.solNodeID = None 1267 CoreService.__init__(self) 1268 1269 def GetSolNodeService(self): 1270 if not getattr(self, '__solservice__'): 1271 self.LogError('Application Proxy Service incorrectly configured. The service requires the __solservice__ attribute which is a tuple of (solServiceName, serviceMask, serviceBucket)') 1272 return 1273 solServiceName, serviceMask, bucket = self.__solservice__ 1274 if self.solNodeID is not None: 1275 if self.solNodeID not in sm.services['machoNet'].transportIDbySolNodeID: 1276 self.LogWarn('Sol node', self.solNodeID, ' is no longer available. Finding a new one...') 1277 self.solNodeID = None 1278 if self.solNodeID is None: 1279 svc = self.session.ConnectToSolServerService('machoNet', None) 1280 nodeID = svc.GetNodeFromAddress(serviceMask, bucket) 1281 if nodeID is None or nodeID <= 0: 1282 raise RuntimeError('Could not find any sol nodes with mask %s' % serviceMask) 1283 self.LogInfo('Found a new sol node at', nodeID) 1284 self.solNodeID = nodeID 1285 svc = self.session.ConnectToSolServerService(solServiceName, nodeID=self.solNodeID) 1286 return svc 1287 1288 1289 class ClusterSingletonService(CoreService): 1290 __ready__ = 0 1291 __startupdependencies__ = ['machoNet'] 1292 1293 def __init__(self): 1294 for dep in ClusterSingletonService.__startupdependencies__: 1295 if dep not in self.__startupdependencies__: 1296 self.__startupdependencies__.append(dep) 1297 1298 CoreService.__init__(self) 1299 1300 def Run(self, *args): 1301 CoreService.Run(self, *args) 1302 sm.RegisterForNotifyEvent(self, 'OnClusterStartup') 1303 sm.RegisterForNotifyEvent(self, 'OnNodeDeath') 1304 if self.machoNet.IsClusterStarted(): 1305 uthread.new(self.__ConditionallyPrime) 1306 1307 def PrimeService(self): 1308 raise NotImplementedError('You cannot inherit from ClusterSingletonService without implementing PrimeService()') 1309 1310 def _MachoResolveClusterSingleton(self): 1311 if getattr(self, '__machoresolve__', None): 1312 serviceNodeID = GetClusterSingletonNodeFromAddress(self.machoNet, self.__machoresolve__) 1313 else: 1314 serviceNodeID = self.MachoResolve(session) 1315 return serviceNodeID 1316 1317 def _ShouldPrimeService(self): 1318 if self.__ready__: 1319 return False 1320 serviceNodeID = self._MachoResolveClusterSingleton() 1321 myNodeID = self.machoNet.GetNodeID() 1322 if serviceNodeID and myNodeID != serviceNodeID: 1323 return False 1324 return True 1325 1326 def _PrimeService(self): 1327 with locks.TempLock((self, 'PrimeService')): 1328 if not self.__ready__: 1329 try: 1330 self.LogInfo('Priming clustersingleton service...') 1331 startTime = blue.os.GetWallclockTimeNow() 1332 self.PrimeService() 1333 self.LogNotice('Done priming clustersingleton service %s in %.3f seconds.' % (self.__logname__, (blue.os.GetWallclockTimeNow() - startTime) / float(const.SEC))) 1334 except Exception as e: 1335 log.LogException('Error priming Cluster Singleton service %s' % self.__logname__) 1336 finally: 1337 self.__ready__ = 1 1338 1339 def PreCallAction(self, methodName): 1340 if not self._ShouldPrimeService(): 1341 return 1342 self._PrimeService() 1343 1344 def OnClusterStartup(self): 1345 self.__ConditionallyPrime() 1346 1347 def __ConditionallyPrime(self): 1348 sm.WaitForServiceObjectState(self, (SERVICE_RUNNING,)) 1349 if not self._ShouldPrimeService(): 1350 return 1351 self.LogNotice('I am the right node for this cluster singleton service at startup. Priming the service...') 1352 self._PrimeService() 1353 1354 def OnNodeDeath(self, nodeID, confirmed, reason = None): 1355 if not self._ShouldPrimeService(): 1356 return 1357 self.LogWarn('Old Cluster Singleton node %s for this service has died. I will now service calls. Starting by priming Service' % nodeID) 1358 self._PrimeService() 1359 1360 1361 Service = CoreService