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 = 5
     59
     60 -    def __init__(self):
     61          PBClientFactory.__init__(self)
     62          self._doingLogin = False
     63          self._doingGetPerspective = False
     64
     65 -    def clientConnectionFailed(self, connector, reason):
     66          PBClientFactory.clientConnectionFailed(self, connector, reason)
     67          # Twisted-1.3 erroneously abandons the connection on non-UserErrors.
     68          # To avoid this bug, don't upcall, and implement the correct version
     69          # of the method here.
     70          if self.continueTrying:
     71              self.connector = connector
     72              self.retry()
     73
     74 -    def clientConnectionLost(self, connector, reason, reconnecting=1):
     75          PBClientFactory.clientConnectionLost(self, connector, reason,
     76                                               reconnecting=reconnecting)
     77          RCF = protocol.ReconnectingClientFactory
     78          RCF.clientConnectionLost(self, connector, reason)
     79
     80 -    def clientConnectionMade(self, broker):
     81          self.resetDelay()
     82          PBClientFactory.clientConnectionMade(self, broker)
     83          if self._doingLogin:
     84              self.doLogin(self._root)
     85          if self._doingGetPerspective:
     86              self.doGetPerspective(self._root)
     87          self.gotRootObject(self._root)
     88
     89 -    def __getstate__(self):
     90          # this should get folded into ReconnectingClientFactory
     91          d = self.__dict__.copy()
     92          d['connector'] = None
     93          d['_callID'] = None
     94          return d
     95
     96      # oldcred methods
     97
     98 -    def getPerspective(self, *args):
     99          raise RuntimeError( "getPerspective is one-shot: use startGettingPerspective instead" )
    100
    101 -    def startGettingPerspective(self, username, password, serviceName,
    102                                  perspectiveName=None, client=None):
    103          self._doingGetPerspective = True
    104          if perspectiveName == None:
    105              perspectiveName = username
    106          self._oldcredArgs = (username, password, serviceName,
    107                               perspectiveName, client)
    108
    109 -    def doGetPerspective(self, root):
    110          # oldcred getPerspective()
    111          (username, password,
    112           serviceName, perspectiveName, client) = self._oldcredArgs
    113          d = self._cbAuthIdentity(root, username, password)
    114          d.addCallback(self._cbGetPerspective,
    115                        serviceName, perspectiveName, client)
    116          d.addCallbacks(self.gotPerspective, self.failedToGetPerspective)
    117
    118
    119      # newcred methods
    120
    121 -    def login(self, credentials, client=None):
    122          from Products.ZenUtils.Utils import unused
    123          unused(credentials, client)
    124          raise RuntimeError( "Login is one-shot: use startLogin instead" )
    125
    126 -    def startLogin(self, credentials, client=None):
    127          self._credentials = credentials
    128          self._client = client
    129          self._doingLogin = True
    130
    131 -    def doLogin(self, root):
    132          # newcred login()
    133          d = self._cbSendUsername(root, self._credentials.username,
    134                                   self._credentials.password, self._client)
    135          d.addCallbacks(self.gotPerspective, self.failedToGetPerspective)
    136          return d
    137
    138
    139      # methods to override
    140
    141 -    def gotPerspective(self, perspective):
    142          """The remote avatar or perspective (obtained each time this factory
    143          connects) is now available."""
    144          pass
    145
    146 -    def gotRootObject(self, root):
    147          """The remote root object (obtained each time this factory connects)
    148          is now available. This method will be called each time the connection
    149          is established and the object reference is retrieved."""
    150          pass
    151
    152 -    def failedToGetPerspective(self, why):
    153          """The login process failed, most likely because of an authorization
    154          failure (bad password), but it is also possible that we lost the new
    155          connection before we managed to send our credentials.
    156          """
    157          log.msg("ReconnectingPBClientFactory.failedToGetPerspective")
    158          if why.check(pb.PBConnectionLost):
    159              log.msg("we lost the brand-new connection")
    160              # retrying might help here, let clientConnectionLost decide
    161              return
    162          # probably authorization
    163          self.stopTrying() # logging in harder won't help
    164          log.err(why)
    165