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 or (at your
      8  # option) any later version as published by 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  import logging
     23  zenlog = logging.getLogger("zen.pbclientfactory")
     24
     25  from twisted.spread import pb
     26
     27  from twisted.spread.pb import PBClientFactory
     28  from twisted.internet import protocol
     29  from twisted.python import log
     30
     31 -class ReconnectingPBClientFactory(PBClientFactory,
     32                                    protocol.ReconnectingClientFactory):
     33      """Reconnecting client factory for PB brokers.
     34
     35      Like PBClientFactory, but if the connection fails or is lost, the factory
     36      will attempt to reconnect.
     37
     38      Instead of using f.getRootObject (which gives a Deferred that can only
     39      be fired once), override the gotRootObject method.
     40
     41      Instead of using the newcred f.login (which is also one-shot), call
     42      f.startLogin() with the credentials and client, and override the
     43      gotPerspective method.
     44
     45      Instead of using the oldcred f.getPerspective (also one-shot), call
     46      f.startGettingPerspective() with the same arguments, and override
     47      gotPerspective.
     48
     49      gotRootObject and gotPerspective will be called each time the object is
     50      received (once per successful connection attempt). You will probably want
     51      to use obj.notifyOnDisconnect to find out when the connection is lost.
     52
     53      If an authorization error occurs, failedToGetPerspective() will be
     54      invoked.
     55
     56      To use me, subclass, then hand an instance to a connector (like
     57      TCPClient).
     58      """
     59      __pychecker__='no-override'
     60
     61      # maxDelay(secs) set to 5 minute maximum delay before attempting to
     62      # reconnect
     63      maxDelay = 300
     64
     65 -    def __init__(self):
     66          PBClientFactory.__init__(self)
     67          self._doingLogin = False
     68          self._doingGetPerspective = False
     69
     70 -    def clientConnectionFailed(self, connector, reason):
     71          PBClientFactory.clientConnectionFailed(self, connector, reason)
     72          # Twisted-1.3 erroneously abandons the connection on non-UserErrors.
     73          # To avoid this bug, don't upcall, and implement the correct version
     74          # of the method here.
     75          if self.continueTrying:
     76              self.connector = connector
     77              self.retry()
     78
     79 -    def clientConnectionLost(self, connector, reason, reconnecting=1):
     80          PBClientFactory.clientConnectionLost(self, connector, reason,
     81                                               reconnecting=reconnecting)
     82          RCF = protocol.ReconnectingClientFactory
     83          RCF.clientConnectionLost(self, connector, reason)
     84
     85 -    def clientConnectionMade(self, broker):
     86          self.resetDelay()
     87          PBClientFactory.clientConnectionMade(self, broker)
     88          if self._doingLogin:
     89              self.doLogin(self._root)
     90          if self._doingGetPerspective:
     91              self.doGetPerspective(self._root)
     92          self.gotRootObject(self._root)
     93
     94 -    def __getstate__(self):
     95          # this should get folded into ReconnectingClientFactory
     96          d = self.__dict__.copy()
     97          d['connector'] = None
     98          d['_callID'] = None
     99          return d
    100
    101      # oldcred methods
    102
    103 -    def getPerspective(self, *args):
    104          raise RuntimeError( "getPerspective is one-shot: use startGettingPerspective instead" )
    105
    106 -    def startGettingPerspective(self, username, password, serviceName,
    107                                  perspectiveName=None, client=None):
    108          self._doingGetPerspective = True
    109          if perspectiveName == None:
    110              perspectiveName = username
    111          self._oldcredArgs = (username, password, serviceName,
    112                               perspectiveName, client)
    113
    114 -    def doGetPerspective(self, root):
    115          # oldcred getPerspective()
    116          (username, password,
    117           serviceName, perspectiveName, client) = self._oldcredArgs
    118          d = self._cbAuthIdentity(root, username, password)
    119          d.addCallback(self._cbGetPerspective,
    120                        serviceName, perspectiveName, client)
    121          d.addCallbacks(self.gotPerspective, self.failedToGetPerspective)
    122
    123
    124      # newcred methods
    125
    126 -    def login(self, credentials, client=None):
    127          from Products.ZenUtils.Utils import unused
    128          unused(credentials, client)
    129          raise RuntimeError( "Login is one-shot: use startLogin instead" )
    130
    131 -    def startLogin(self, credentials, client=None):
    132          self._credentials = credentials
    133          self._client = client
    134          self._doingLogin = True
    135
    136 -    def doLogin(self, root):
    137          # newcred login()
    138          d = self._cbSendUsername(root, self._credentials.username,
    139                                   self._credentials.password, self._client)
    140          d.addCallbacks(self.gotPerspective, self.failedToGetPerspective)
    141          return d
    142
    143
    144      # methods to override
    145
    146 -    def gotPerspective(self, perspective):
    147          """The remote avatar or perspective (obtained each time this factory
    148          connects) is now available."""
    149          pass
    150
    151 -    def gotRootObject(self, root):
    152          """The remote root object (obtained each time this factory connects)
    153          is now available. This method will be called each time the connection
    154          is established and the object reference is retrieved."""
    155          pass
    156
    157 -    def failedToGetPerspective(self, why):
    158          """The login process failed, most likely because of an authorization
    159          failure (bad password), but it is also possible that we lost the new
    160          connection before we managed to send our credentials.
    161          """
    162          log.msg("ReconnectingPBClientFactory.failedToGetPerspective")
    163          if why.check(pb.PBConnectionLost):
    164              log.msg("we lost the brand-new connection")
    165              # retrying might help here, let clientConnectionLost decide
    166              return
    167
    168          self.stopTrying() # logging in harder won't help
    169          if why.type == 'twisted.cred.error.UnauthorizedLogin':
    170              zenlog.critical("zenhub username/password combination is incorrect!")
    171              # Don't exit as Enterprise caches info and can survive
    172          else:
    173              zenlog.critical("Unknown connection problem to zenhub %s", why.type)
    174              log.err(why)
    175