Package Products :: Package ZenUtils :: Module PBUtil |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenUtils.PBUtil

      1  ###########################################################################
      2  #
      3  # This program is part of Zenoss Core, an open source monitoring platform.
      4  # Copyright (C) 2007, Zenoss Inc.
      5  #
      6  # This program is free software; you can redistribute it and/or modify it
      7  # under the terms of the GNU General Public License version 2 as published by
      8  # the Free Software Foundation.
      9  #
     10  # For complete information please visit: http://www.zenoss.com/oss/
     11  #
     12  ###########################################################################
     13
     14  # taken from r1.10 of buildbot.sf.net/buildbot/pbutil.py
     15
     16  # flumotion has nearly the same code
     17
     18  __doc__ = """PBUtil
     19  Base classes handy for use with PB clients.
     20  """
     21
     22  from twisted.spread import pb
     23
     24  from twisted.spread.pb import PBClientFactory
     25  from twisted.internet import protocol
     26  from twisted.python import log
     27
     28 -class ReconnectingPBClientFactory(PBClientFactory,
     29                                    protocol.ReconnectingClientFactory):
     30      """Reconnecting client factory for PB brokers.
     31
     32      Like PBClientFactory, but if the connection fails or is lost, the factory
     33      will attempt to reconnect.
     34
     35      Instead of using f.getRootObject (which gives a Deferred that can only
     36      be fired once), override the gotRootObject method.
     37
     38      Instead of using the newcred f.login (which is also one-shot), call
     39      f.startLogin() with the credentials and client, and override the
     40      gotPerspective method.
     41
     42      Instead of using the oldcred f.getPerspective (also one-shot), call
     43      f.startGettingPerspective() with the same arguments, and override
     44      gotPerspective.
     45
     46      gotRootObject and gotPerspective will be called each time the object is
     47      received (once per successful connection attempt). You will probably want
     48      to use obj.notifyOnDisconnect to find out when the connection is lost.
     49
     50      If an authorization error occurs, failedToGetPerspective() will be
     51      invoked.
     52
     53      To use me, subclass, then hand an instance to a connector (like
     54      TCPClient).
     55      """
     56      __pychecker__='no-override'
     57
     58      # maxDelay(secs) set to 5 minute maximum delay before attempting to
     59      # reconnect
     60      maxDelay = 300
     61
     62 -    def __init__(self):
     63          PBClientFactory.__init__(self)
     64          self._doingLogin = False
     65          self._doingGetPerspective = False
     66
     67 -    def clientConnectionFailed(self, connector, reason):
     68          PBClientFactory.clientConnectionFailed(self, connector, reason)
     69          # Twisted-1.3 erroneously abandons the connection on non-UserErrors.
     70          # To avoid this bug, don't upcall, and implement the correct version
     71          # of the method here.
     72          if self.continueTrying:
     73              self.connector = connector
     74              self.retry()
     75
     76 -    def clientConnectionLost(self, connector, reason, reconnecting=1):
     77          PBClientFactory.clientConnectionLost(self, connector, reason,
     78                                               reconnecting=reconnecting)
     79          RCF = protocol.ReconnectingClientFactory
     80          RCF.clientConnectionLost(self, connector, reason)
     81
     82 -    def clientConnectionMade(self, broker):
     83          self.resetDelay()
     84          PBClientFactory.clientConnectionMade(self, broker)
     85          if self._doingLogin:
     86              self.doLogin(self._root)
     87          if self._doingGetPerspective:
     88              self.doGetPerspective(self._root)
     89          self.gotRootObject(self._root)
     90
     91 -    def __getstate__(self):
     92          # this should get folded into ReconnectingClientFactory
     93          d = self.__dict__.copy()
     94          d['connector'] = None
     95          d['_callID'] = None
     96          return d
     97
     98      # oldcred methods
     99
    100 -    def getPerspective(self, *args):
    101          raise RuntimeError( "getPerspective is one-shot: use startGettingPerspective instead" )
    102
    103 -    def startGettingPerspective(self, username, password, serviceName,
    104                                  perspectiveName=None, client=None):
    105          self._doingGetPerspective = True
    106          if perspectiveName == None:
    107              perspectiveName = username
    108          self._oldcredArgs = (username, password, serviceName,
    109                               perspectiveName, client)
    110
    111 -    def doGetPerspective(self, root):
    112          # oldcred getPerspective()
    113          (username, password,
    114           serviceName, perspectiveName, client) = self._oldcredArgs
    115          d = self._cbAuthIdentity(root, username, password)
    116          d.addCallback(self._cbGetPerspective,
    117                        serviceName, perspectiveName, client)
    118          d.addCallbacks(self.gotPerspective, self.failedToGetPerspective)
    119
    120
    121      # newcred methods
    122
    123 -    def login(self, credentials, client=None):
    124          from Products.ZenUtils.Utils import unused
    125          unused(credentials, client)
    126          raise RuntimeError( "Login is one-shot: use startLogin instead" )
    127
    128 -    def startLogin(self, credentials, client=None):
    129          self._credentials = credentials
    130          self._client = client
    131          self._doingLogin = True
    132
    133 -    def doLogin(self, root):
    134          # newcred login()
    135          d = self._cbSendUsername(root, self._credentials.username,
    136                                   self._credentials.password, self._client)
    137          d.addCallbacks(self.gotPerspective, self.failedToGetPerspective)
    138          return d
    139
    140
    141      # methods to override
    142
    143 -    def gotPerspective(self, perspective):
    144          """The remote avatar or perspective (obtained each time this factory
    145          connects) is now available."""
    146          pass
    147
    148 -    def gotRootObject(self, root):
    149          """The remote root object (obtained each time this factory connects)
    150          is now available. This method will be called each time the connection
    151          is established and the object reference is retrieved."""
    152          pass
    153
    154 -    def failedToGetPerspective(self, why):
    155          """The login process failed, most likely because of an authorization
    156          failure (bad password), but it is also possible that we lost the new
    157          connection before we managed to send our credentials.
    158          """
    159          log.msg("ReconnectingPBClientFactory.failedToGetPerspective")
    160          if why.check(pb.PBConnectionLost):
    161              log.msg("we lost the brand-new connection")
    162              # retrying might help here, let clientConnectionLost decide
    163              return
    164          # probably authorization
    165          self.stopTrying() # logging in harder won't help
    166          log.err(why)
    167