sebastien - in flumotion/branches/transcoder-1: . flumotion/admin flumotion/admin/gtk flumotion/common flumotion/component flumotion/test flumotion/twisted

flumotion-commit at lists.fluendo.com flumotion-commit at lists.fluendo.com
Wed May 9 12:57:34 CEST 2007


Author: sebastien
Date: Wed May  9 12:57:29 2007
New Revision: 4904

Added:
   flumotion/branches/transcoder-1/flumotion/common/startset.py
      - copied unchanged from r4867, flumotion/trunk/flumotion/common/startset.py
Modified:
   flumotion/branches/transcoder-1/ChangeLog
   flumotion/branches/transcoder-1/flumotion/admin/admin.py
   flumotion/branches/transcoder-1/flumotion/admin/gtk/client.py
   flumotion/branches/transcoder-1/flumotion/admin/gtk/dialogs.py
   flumotion/branches/transcoder-1/flumotion/admin/gtk/main.py
   flumotion/branches/transcoder-1/flumotion/common/Makefile.am
   flumotion/branches/transcoder-1/flumotion/common/debug.py
   flumotion/branches/transcoder-1/flumotion/common/medium.py
   flumotion/branches/transcoder-1/flumotion/component/feed.py
   flumotion/branches/transcoder-1/flumotion/test/test_component_feed.py
   flumotion/branches/transcoder-1/flumotion/test/test_pb.py
   flumotion/branches/transcoder-1/flumotion/twisted/pb.py
   flumotion/branches/transcoder-1/flumotion/twisted/portal.py
Log:
2007-05-09  Sebastien Merle  <sebastien at fluendo.com>

	* Merged flumotion trunk changesets from [4853] to [4867].

Modified: flumotion/branches/transcoder-1/ChangeLog
==============================================================================
--- flumotion/branches/transcoder-1/ChangeLog	(original)
+++ flumotion/branches/transcoder-1/ChangeLog	Wed May  9 12:57:29 2007
@@ -1,5 +1,9 @@
 2007-05-09  Sebastien Merle  <sebastien at fluendo.com>
 
+	* Merged flumotion trunk changesets from [4853] to [4867].
+
+2007-05-09  Sebastien Merle  <sebastien at fluendo.com>
+
 	* Merged changes from flumotion trunk from revision 4687 to revision 4853.
 
 2007-05-08  Sebastien Merle  <sebastien at fluendo.com>
@@ -30,6 +34,88 @@
 	be jellyed and unjellyed. Now an enum value can be directly 
 	used with spread without converting to int.
 
+2007-05-02  Andy Wingo  <wingo at pobox.com>
+
+	* flumotion/admin/gtk/main.py (startAdminFromGreeter.failed): 
+	* flumotion/admin/gtk/dialogs.py (connection_failed_message): 
+	* flumotion/admin/gtk/client.py
+	(Window.on_open_connection.refused): Change interface to some of
+	the dialogs.
+
+	* flumotion/common/Makefile.am (flumotion_PYTHON): 
+	* flumotion/common/startset.py (StartSet): New data structure,
+	factored out of flumotion.worker.job.DeferredStartSet. Still need
+	to port the jobheaven to use this though.
+
+2007-04-30  Andy Wingo  <wingo at pobox.com>
+
+	* flumotion/twisted/pb.py
+	(FPBClientFactory.login.getKeycardClassesCb)
+	(FPBClientFactory._cbSendKeycard)
+	(FPBClientFactory._cbLoginCallback, Authenticator.issue)
+	(Authenticator.respond_KeycardUACPCC)
+	(Authenticator.respond_KeycardUASPCC): Tweak some logging back to
+	LOG.
+	(FPBClientFactory.disconnect): Error as terror, like protocol.py.
+
+	* flumotion/common/medium.py (BaseMedium.setRemoteReference): Not
+	every remote side is a manager.
+
+	* flumotion/admin/admin.py
+	(AdminClientFactory.clientConnectionFailed): Leave some logging to
+	the base class.
+	(AdminModel.shutdown): Reorder some calls to make logging nicer.
+
+	* flumotion/twisted/pb.py (FPBClientFactory.startedConnecting)
+	(FPBClientFactory.disconnect): Interestingly, there is a window in
+	which calling disconnect() and stopTrying() on a factory still
+	leaves a connection attempt pending. Plug this window, calling a
+	function that will only have effect during the window period.
+	(ReconnectingFPBClientFactory.clientConnectionFailed): Log when we
+	are going to reconnect (or not)
+
+	* flumotion/twisted/portal.py
+	(BouncerPortal.login.onErrorCloseConnection): Close the connection
+	if the login attempt fails, in all cases: database timeout, bad
+	password, etc. Prevents FD leakage on reconnect if the worker
+	can't contact the manager.
+
+	* flumotion/test/test_component_feed.py (TestFeedClient.setUp)
+	(TestFeedClient.tearDown): Use some terrible code that I found in
+	test_pb.py to make trial not count UnauthorizedLogin errors as
+	test errors, since we plan to make them. Trial gets these errors
+	because Flumotion passes failures across the wire whose class is
+	not derived from pb.Error, viz.
+	twisted.cred.error.UnauthorizedLogin. We should pass
+	pb.Error-derived errors, but my brain is too weak right now to
+	handle all of the implications.
+	(TestFeedClient.testBadPass): Enable test.
+
+	* flumotion/test/test_pb.py: Remove
+	ifWeHaveAnOldTwistedAndProgrammerNameEqualsZaheer invocations.
+
+	* flumotion/common/debug.py (print_stack): New kwarg "file",
+	defaulting to stdout.
+
+	* flumotion/component/feed.py
+	(FeedMedium._doFeedTo.mungeTransport._closeSocket): Fix too-clever
+	code.
+
+	* flumotion/admin/admin.py (AdminClientFactory.gotDeferredLogin):
+	Remove old challenge-response code; base classes do it for us now.
+
+	* flumotion/twisted/portal.py (BouncerPortal.login): Return a
+	failure if no bouncer is configured instead of None. Refactor
+	slightly.
+
+	* flumotion/twisted/pb.py (FPBClientFactory._cbLoginCallback):
+	Client-side remote_login() returns will never be None; remove this
+	case.
+	(_BouncerWrapper.remote_login): The one case in which None would
+	be passed as return from BouncerPortal.login() was when no bouncer
+	was configured; since that's fixed, no need to check for None
+	here. Refactor slightly.
+
 2007-04-26  Thomas Vander Stichele  <thomas at apestaart dot org>
 
 	* flumotion/test/test_http.py (FakeRequest.__init__):

Modified: flumotion/branches/transcoder-1/flumotion/admin/admin.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/admin/admin.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/admin/admin.py	Wed May  9 12:57:29 2007
@@ -100,8 +100,6 @@
 
         fpb.ReconnectingFPBClientFactory.clientConnectionFailed(self, 
             connector, reason)
-        # delay is now updated
-        self.debug("will try reconnect in %f seconds" % self.delay)
 
     # vmethod implementation
     def gotDeferredLogin(self, d):
@@ -120,15 +118,6 @@
                     yield None
                 else:
                     raise
-            # if it's not a reference, we need to respond to a
-            # challenge...
-            if not isinstance(result, pb.RemoteReference):
-                keycard = result
-                keycard.setPassword(self.passwd)
-                self.log("_loginCallback: responding to challenge")
-                d = self.login(keycard, self.medium, interfaces.IAdminMedium)
-                yield d
-                result = d.value()
 
             self.medium.setRemoteReference(result)
 
@@ -255,8 +244,10 @@
     def shutdown(self):
         self.debug('shutting down')
         if self.clientFactory is not None:
-            self.clientFactory.disconnect()
+            # order not semantically important, but this way we avoid a
+            # "reconnecting in X seconds" in the log
             self.clientFactory.stopTrying()
+            self.clientFactory.disconnect()
             self.clientFactory = None
 
     def reconnect(self, keepTrying=False):

Modified: flumotion/branches/transcoder-1/flumotion/admin/gtk/client.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/admin/gtk/client.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/admin/gtk/client.py	Wed May  9 12:57:29 2007
@@ -200,7 +200,7 @@
                 d = dialogs.connection_refused_message(i.host,
                                                        self.window)
             else:
-                d = dialogs.connection_failed_message(i.host,
+                d = dialogs.connection_failed_message(i, str(failure),
                                                       self.window)
             d.addCallback(lambda _: self.window.set_sensitive(True))
 

Modified: flumotion/branches/transcoder-1/flumotion/admin/gtk/dialogs.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/admin/gtk/dialogs.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/admin/gtk/dialogs.py	Wed May  9 12:57:29 2007
@@ -19,13 +19,15 @@
 
 # Headers in this file shall remain intact.
 
-from flumotion.common.pygobject import gsignal
-from flumotion.common import pygobject
-
+from gettext import gettext as _
 
 import gtk
 import gobject
 
+from flumotion.common.pygobject import gsignal
+from flumotion.common import pygobject
+
+
 class ProgressDialog(gtk.Dialog):
     def __init__(self, title, message, parent = None):
         gtk.Dialog.__init__(self, title, parent,
@@ -110,7 +112,9 @@
                     % host)
     return d.run()
 
-def connection_failed_message(message, parent=None):
+def connection_failed_message(info, debug, parent=None):
+    message = (_("Connection to manager on %s failed (%s).")
+               % (str(info), debug))
     d = ErrorDialog('Connection failed', parent, True, message)
     return d.run()
 

Modified: flumotion/branches/transcoder-1/flumotion/admin/gtk/main.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/admin/gtk/main.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/admin/gtk/main.py	Wed May  9 12:57:29 2007
@@ -42,6 +42,9 @@
     return greeter.Greeter()
 
 def startAdminFromGreeter(greeter):
+    # fuck python's lexicals!
+    _info = []
+
     def got_state(state):
         greeter.set_sensitive(False)
         authenticator = fpb.Authenticator(username=state['user'],
@@ -49,6 +52,7 @@
         info = connection.PBConnectionInfo(state['host'], state['port'],
                                            not state['use_insecure'],
                                            authenticator)
+        _info.append(info)
         model = AdminModel()
         return model.connectToManager(info)
 
@@ -62,7 +66,8 @@
     def failed(failure):
         failure.trap(errors.ConnectionFailedError)
         message = "".join(failure.value.args)
-        dret = dialogs.connection_failed_message(message, greeter.window)
+        dret = dialogs.connection_failed_message(info[0], message,
+                                                 greeter.window)
         dret.addCallback(lambda _: startAdminFromGreeter(greeter))
         return dret
 

Modified: flumotion/branches/transcoder-1/flumotion/common/Makefile.am
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/common/Makefile.am	(original)
+++ flumotion/branches/transcoder-1/flumotion/common/Makefile.am	Wed May  9 12:57:29 2007
@@ -33,6 +33,7 @@
 	reload.py \
 	server.py \
 	setup.py \
+	startset.py \
 	watched.py \
 	worker.py
 

Modified: flumotion/branches/transcoder-1/flumotion/common/debug.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/common/debug.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/common/debug.py	Wed May  9 12:57:29 2007
@@ -97,7 +97,7 @@
         sys.settrace(None)
         _indent = ''
 
-def print_stack():
+def print_stack(file=None):
     f = sys._getframe(1)
     output = []
     while f:
@@ -110,13 +110,15 @@
         # reversed so we can reverse() later
         if f.f_locals:
             for k, v in f.f_locals.items():
-                output.append('      %s = %r' % (k, v))
-            output.append('    Locals:')
+                output.append('      %s = %r\n' % (k, v))
+            output.append('    Locals:\n')
         if line:
-            output.append('    %s' % line.strip())
-        output.append('  File "%s", line %d, in %s' % (filename,lineno,name))
+            output.append('    %s\n' % line.strip())
+        output.append('  File "%s", line %d, in %s\n' % (filename,lineno,name))
         f = f.f_back
     output.reverse()
+    if file is None:
+        file = sys.stdout
     for line in output:
-        print line
+        file.write(line)
 

Modified: flumotion/branches/transcoder-1/flumotion/common/medium.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/common/medium.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/common/medium.py	Wed May  9 12:57:29 2007
@@ -83,7 +83,7 @@
         except Exception, e:
             self.debug("could not get connection info, reason %r" % e)
         if tarzan and jane:
-            self.debug("connection is from me on %s to manager on %s" % (
+            self.debug("connection is from me on %s to remote on %s" % (
                 common.addressGetHost(tarzan),
                 common.addressGetHost(jane)))
 

Modified: flumotion/branches/transcoder-1/flumotion/component/feed.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/component/feed.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/component/feed.py	Wed May  9 12:57:29 2007
@@ -219,7 +219,7 @@
                     except socket.error:
                         pass
                 else:
-                    tcp.Server._closeSocket(self)
+                    tcp.Server._closeSocket(transport)
             transport._closeSocket = _closeSocket
             return transport
                         

Modified: flumotion/branches/transcoder-1/flumotion/test/test_component_feed.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/test/test_component_feed.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/test/test_component_feed.py	Wed May  9 12:57:29 2007
@@ -28,6 +28,7 @@
 from twisted.cred import error
 from twisted.trial import unittest
 from twisted.internet import reactor, defer
+from twisted.python import log as tlog
 
 from flumotion.twisted import pb as fpb
 from flumotion.common import log
@@ -108,6 +109,9 @@
                    'properties': {'data': "user:qi1Lftt0GZC0o"}}
 
     def setUp(self):
+        # don't output Twisted tracebacks for PB errors we will trigger
+        log._getTheFluLogObserver().ignoreErrors(error.UnauthorizedLogin)
+
         self._fdCount = countOpenFileDescriptors()
 
         self.brain = FakeWorkerBrain()
@@ -123,6 +127,8 @@
                                   % (self._fdCount, additionalFDs, actual)))
 
     def tearDown(self):
+        tlog.flushErrors(error.UnauthorizedLogin)
+        log._getTheFluLogObserver().clearIgnores()
         d = self.feedServer.shutdown()
         d.addCallback(lambda _: self._bouncer.stop())
         d.addCallback(lambda _: self.assertAdditionalFDsOpen(0, 'tearDown'))
@@ -283,8 +289,10 @@
             return factory.login(fpb.Authenticator(username='user',
                                                    password='badpass'))
 
+        def loginOk(root):
+            raise AssertionError, 'should not get here'
+
         def loginFailed(failure):
-            failure.trap(error.UnauthorizedLogin)
             def gotRoot(root):
                 # an idempotent method, should return a network failure if
                 # the remote side disconnects as it should
@@ -292,10 +300,12 @@
             
             def gotError(failure):
                 self.assertAdditionalFDsOpen(1, 'feedSent (socket)')
+                self.info('success')
 
             def gotKeycardClasses(classes):
                 raise AssertionError, 'should not get here'
 
+            self.info('loginFailed: %s', log.getFailureMessage(failure))
             failure.trap(error.UnauthorizedLogin)
             d = factory.getRootObject() # should fire immediately
             d.addCallback(gotRoot)
@@ -304,9 +314,8 @@
             return d
 
         d = login()
-        d.addErrback(loginFailed)
+        d.addCallbacks(loginOk, loginFailed)
         return d
-    testBadPass.skip = 'BouncerPortal does not disconnect on unauthorized login'
 
     def testRequestFeed(self):
         client = feed.FeedMedium(logName='frobby')

Modified: flumotion/branches/transcoder-1/flumotion/test/test_pb.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/test/test_pb.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/test/test_pb.py	Wed May  9 12:57:29 2007
@@ -21,7 +21,6 @@
 
 import common
 from twisted.trial import unittest
-import twisted.copyright #T1.3
 
 import crypt
 
@@ -51,10 +50,6 @@
     'properties': {'data': "user:iamsalt:2f826124ada2b2cdf11f4fd427c9ca48de0ed49b41476266d8df08d2cf86120e"}
 }
 
-#T1.3
-def weHaveAnOldTwisted():
-    return twisted.copyright.version < '2.0.0'
-
 ### lots of fake objects to have fun with
 
 class FakePortalWrapperPlaintext:
@@ -136,12 +131,8 @@
         def wrongPasswordErrback(wrongpasserror):
             self.assert_(isinstance(wrongpasserror.type(), error.UnauthorizedLogin))
 
-        if weHaveAnOldTwisted(): #T1.3
-            failure = unittest.deferredError(d)
-            failure.trap(error.UnauthorizedLogin)
-        else:
-            d.addErrback(wrongPasswordErrback)
-            return d
+        d.addErrback(wrongPasswordErrback)
+        return d
 
 ### SHINY NEW FPB
 class Test_BouncerWrapper(unittest.TestCase):
@@ -167,10 +158,7 @@
             return result
         
         d.addCallback(uacppOkCallback)
-        if weHaveAnOldTwisted(): #1.3
-            result = unittest.deferredResult(d)
-        else:
-            return d
+        return d
     
     def testUACPPWrongPassword(self):
         keycard = keycards.KeycardUACPP('user', 'tes', '127.0.0.1')
@@ -180,12 +168,8 @@
         def uacppWrongPasswordErrback(wrongpasserror):
             self.assert_(isinstance(wrongpasserror.type(), error.UnauthorizedLogin))
         
-        if weHaveAnOldTwisted(): #T1.3
-            failure = unittest.deferredError(d)
-            failure.trap(error.UnauthorizedLogin)
-        else:
-            d.addErrback(uacppWrongPasswordErrback)
-            return d
+        d.addErrback(uacppWrongPasswordErrback)
+        return d
 
     def testUACPCCOk(self):
         # create
@@ -208,10 +192,7 @@
             return d
         
         d.addCallback(uacpccOkCallback)
-        if weHaveAnOldTwisted(): #T1.3
-            unittest.deferredResult(d)
-        else:
-            return d
+        return d
             
     def testUACPCCWrongUser(self):
         # create
@@ -235,11 +216,7 @@
             return d
         
         d.addCallback(uacpccWrongUserCallback)
-        if weHaveAnOldTwisted(): #T1.3
-            result = unittest.deferredResult(d)
-            self.assertEquals(result, True)
-        else:
-            return d
+        return d
 
     def testUACPCCWrongPassword(self):
         # create
@@ -263,11 +240,7 @@
             return d
 
         d.addCallback(uacpccWrongPasswordCallback)
-        if weHaveAnOldTwisted(): #T1.3
-            result = unittest.deferredResult(d)
-            self.assertEquals(result, True)
-        else:
-            return d
+        return d
 
     def testUACPCCTamperWithChallenge(self):
         # create challenger
@@ -294,10 +267,7 @@
             return d
 
         d.addCallback(uacpccTamperCallback)
-        if weHaveAnOldTwisted(): #T1.3
-            unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
 class Test_FPortalRoot(unittest.TestCase):
     def setUp(self):
@@ -387,10 +357,7 @@
             return self.clientDisconnect(factory, result)
         
         d.addCallback(OkCallback)
-        if weHaveAnOldTwisted():
-            result = unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
     def testWrongPassword(self):
         factory = pb.FPBClientFactory()
@@ -410,11 +377,8 @@
             log.debug("trial", "got failure %r" % failure)
             c.disconnect()
             return True
-        if weHaveAnOldTwisted():
-            unittest.deferredError(d)
-        else:
-            d.addErrback(WrongPasswordErrback)
-            return d
+        d.addErrback(WrongPasswordErrback)
+        return d
         
 # FIXME: rewrite such that we can enforce a challenger, possibly
 # by setting a property on the bouncer
@@ -439,10 +403,7 @@
             return d
         
         d.addCallback(uacpccOkCallback)
-        if weHaveAnOldTwisted():
-            unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
     def testWrongUser(self):
         factory = pb.FPBClientFactory()
@@ -469,10 +430,7 @@
         d.addCallback(WrongUserCb)
         d.addErrback(WrongUserEb)
     
-        if weHaveAnOldTwisted():
-            unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
     def notestUACPCCWrongPassword(self):
         factory = pb.FPBClientFactory()
@@ -503,10 +461,7 @@
             return d
         
         d.addCallback(uacpccWrongPasswordCallback)
-        if weHaveAnOldTwisted():
-            unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
     def notestUACPCCTamperWithChallenge(self):
         factory = pb.FPBClientFactory()
@@ -539,10 +494,7 @@
             d.addErrback(uacpccTamperErrback)
             return d
         d.addCallback(uacpccTamperCallback)
-        if weHaveAnOldTwisted():
-            unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
 # test with sha256 bouncer
 class Test_FPBClientFactorySaltSha256(Test_FPBClientFactory):
@@ -564,10 +516,7 @@
             return self.clientDisconnect(factory, result)
         
         d.addCallback(OkCallback)
-        if weHaveAnOldTwisted():
-            result = unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
     def testWrongPassword(self):
         factory = pb.FPBClientFactory()
@@ -587,11 +536,8 @@
             log.debug("trial", "got failure %r" % failure)
             c.disconnect()
             return True
-        if weHaveAnOldTwisted():
-            unittest.deferredError(d)
-        else:
-            d.addErrback(WrongPasswordErrback)
-            return d
+        d.addErrback(WrongPasswordErrback)
+        return d
         
     def testWrongUser(self):
         factory = pb.FPBClientFactory()
@@ -618,10 +564,7 @@
         d.addCallback(WrongUserCb)
         d.addErrback(WrongUserEb)
     
-        if weHaveAnOldTwisted():
-            unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
 # FIXME: do this with a fake authenticator that tampers with the challenge
     def notestUACPCCTamperWithChallenge(self):
@@ -655,10 +598,7 @@
             d.addErrback(uacpccTamperErrback)
             return d
         d.addCallback(uacpccTamperCallback)
-        if weHaveAnOldTwisted():
-            unittest.deferredResult(d)
-        else:
-            return d
+        return d
 
 
 if __name__ == '__main__':

Modified: flumotion/branches/transcoder-1/flumotion/twisted/pb.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/twisted/pb.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/twisted/pb.py	Wed May  9 12:57:29 2007
@@ -30,6 +30,7 @@
 from twisted.cred import checkers, credentials, error
 from twisted.cred.portal import IRealm, Portal
 from twisted.internet import protocol, defer, reactor
+from twisted.internet import error as terror
 from twisted.python import log, reflect, failure
 from twisted.spread import pb, flavors
 from twisted.spread.pb import PBClientFactory
@@ -76,6 +77,21 @@
     keycard = None
     medium = None
     perspectiveInterface = None # override in subclass
+    _fpbconnector = None
+
+    ## from protocol.ClientFactory
+    def startedConnecting(self, connector):
+        self._fpbconnector = connector
+        return pb.PBClientFactory.startedConnecting(self, connector)
+
+    ## from twisted.spread.pb.ClientFactory
+    def disconnect(self):
+        if self._fpbconnector:
+            try:
+                self._fpbconnector.stopConnecting()
+            except terror.NotConnectingError:
+                pass
+        return pb.PBClientFactory.disconnect(self)
 
     def getKeycardClasses(self):
         """
@@ -114,7 +130,7 @@
                           for interface in interfaces]
             
         def getKeycardClassesCb(keycardClasses):
-            self.debug('supported keycard classes: %r' % keycardClasses)
+            self.log('supported keycard classes: %r' % keycardClasses)
             d = authenticator.issue(keycardClasses)
             return d
 
@@ -137,9 +153,9 @@
 
         
     def _cbSendKeycard(self, root, authenticator, client, interfaces, count=0):
-        self.debug("_cbSendKeycard(root=%r, authenticator=%r, client=%r, " \
-            "interfaces=%r, count=%d" % (
-            root, authenticator, client, interfaces, count))
+        self.log("_cbSendKeycard(root=%r, authenticator=%r, client=%r, "
+                 "interfaces=%r, count=%d", root, authenticator, client,
+                 interfaces, count)
         count = count + 1
         d = root.callRemote("login", self.keycard, client, *interfaces)
         return d.addCallback(self._cbLoginCallback, root, authenticator, client,
@@ -151,22 +167,18 @@
         if count > 5:
             # too many recursions, server is h0rked
             self.warning('Too many recursions, internal error.')
-        self.debug("FPBClientFactory(): result %r" % result)
-
-        if not result:
-            self.warning('No result, raising.')
-            raise error.UnauthorizedLogin()
+        self.log("FPBClientFactory(): result %r" % result)
 
         if isinstance(result, pb.RemoteReference):
             # everything done, return reference
-            self.debug('Done, returning result %r' % result)
+            self.debug('login successful, returning %r', result)
             return result
 
         # must be a keycard
         keycard = result
         if not keycard.state == keycards.AUTHENTICATED:
-            self.debug("FPBClientFactory(): requester needs to resend %r" %
-                keycard)
+            self.log("FPBClientFactory(): requester needs to resend %r",
+                     keycard)
             d = authenticator.respond(keycard)
             def _loginAgainCb(keycard):
                 d = root.callRemote("login", keycard, client, *interfaces)
@@ -249,6 +261,10 @@
         FPBClientFactory.clientConnectionFailed(self, connector, reason)
         RCF = protocol.ReconnectingClientFactory
         RCF.clientConnectionFailed(self, connector, reason)
+        if self.continueTrying:
+            self.debug("will try reconnect in %f seconds", self.delay)
+        else:
+            self.debug("not trying to reconnect")
 
     def clientConnectionLost(self, connector, reason):
         log.msg("connection lost to %s, reason %r" % (
@@ -333,34 +349,24 @@
             - a L{twisted.cred.error.UnauthorizedLogin} when authentication
               is denied
         """
+        def loginResponse(result):
+            self.log("loginResponse: result=%r", result)
+            # if the result is a keycard, we're not yet ready
+            if isinstance(result, keycards.Keycard):
+                return result
+            else:
+                # authenticated, so the result is the tuple
+                interface, perspective, logout = result
+                self.broker.notifyOnDisconnect(logout)
+                return pb.AsReferenceable(perspective, "perspective")
+
         # corresponds with FPBClientFactory._cbSendKeycard
         self.log("remote_login(keycard=%s, *interfaces=%r" % (keycard, interfaces))
         interfaces = [freflect.namedAny(interface) for interface in interfaces]
         d = self.bouncerPortal.login(keycard, mind, *interfaces)
-        d.addCallback(self._authenticateCallback, mind, *interfaces)
+        d.addCallback(loginResponse)
         return d
 
-    def _authenticateCallback(self, result, mind, *interfaces):
-        self.log("_authenticateCallback(result=%r, mind=%r, interfaces=%r" % (result, mind, interfaces))
-        # FIXME: coverage indicates that "not result" does not happen,
-        # presumably because a Failure is triggered before us
-        if not result:
-            return failure.Failure(error.UnauthorizedLogin())
-
-        # if the result is a keycard, we're not yet ready
-        if isinstance(result, keycards.Keycard):
-            return result
-
-        # authenticated, so the result is the tuple
-        # FIXME: our keycard should be stored higher up since it was authd
-        # then cleaned up sometime in the future
-        # for that we probably need to pass it along
-        return self._loggedIn(result)
-
-    def _loggedIn(self, (interface, perspective, logout)):
-        self.broker.notifyOnDisconnect(logout)
-        return pb.AsReferenceable(perspective, "perspective")
-
 class Authenticator(flog.Loggable, pb.Referenceable):
     """
     I am an object used by FPB clients to create keycards for me
@@ -421,13 +427,13 @@
 
         for i in keycardClasses:
             if i in supported:
-                self.debug('Keycard interface %s supported, looking up' % i)
+                self.log('Keycard interface %s supported, looking up', i)
                 name = i.split(".")[-1]
                 methodName = "issue_%s" % name
                 method = getattr(self, methodName)
                 keycard = method()
-                self.debug('Issuing keycard %r of class %s' % (
-                    keycard, name))
+                self.debug('Issuing keycard %r of class %s', keycard,
+                           name)
                 keycard.avatarId = self.avatarId
                 return defer.succeed(keycard)
 
@@ -463,12 +469,12 @@
         return defer.succeed(method(keycard))
 
     def respond_KeycardUACPCC(self, keycard):
-        self.debug('setting password')
+        self.log('setting password')
         keycard.setPassword(self.password)
         return keycard
 
     def respond_KeycardUASPCC(self, keycard):
-        self.debug('setting password')
+        self.log('setting password')
         keycard.setPassword(self.password)
         return keycard
 

Modified: flumotion/branches/transcoder-1/flumotion/twisted/portal.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/twisted/portal.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/twisted/portal.py	Wed May  9 12:57:29 2007
@@ -84,41 +84,61 @@
         """
         self.debug("_login(keycard=%r, mind=%r, ifaces=%r)" % (
             keycard, mind, ifaces))
+
         if not self.bouncer:
             self.warning("no bouncer, refusing login")
-            return defer.succeed(None)
-        else:
-            d = defer.maybeDeferred(self.bouncer.authenticate, keycard)
+            return defer.fail(error.UnauthorizedLogin())
+
+        def onErrorCloseConnection(failure):
+            try:
+                host = mind.broker.transport.getHost()
+                remote = '%s:%d' % (host.host, host.port)
+            except:
+                remote = '(unknown)'
+                
+            self.warning('failed login -- closing connection to %s',
+                         remote)
+            self.debug('failure: %s', log.getFailureMessage(failure))
+            try:
+                mind.broker.transport.loseConnection()
+            except Exception, e:
+                self.info('loseConnection failed: %s',
+                          log.getExceptionMessage(e))
+                # ignore it
+            return failure
             
-        d.addCallback(self._authenticateCallback, mind, *ifaces)
+        def bouncerResponse(result):
+            # we either got a keycard as result, or None from the
+            # bouncer; would be better if the bouncers returned failures
+            # directly, but that's not how the current interface works.
+            if not result:
+                self.info("unauthorized login for interfaces %r", ifaces)
+                return defer.fail(error.UnauthorizedLogin())
+
+            keycard = result
+            if not keycard.state == keycards.AUTHENTICATED:
+                # challenge
+                self.log('returning keycard for further authentication')
+                return keycard
+
+            # this is where we request the Avatar and can influence naming
+            self.debug('authenticated login of %r into realm %r', keycard,
+                       self.realm)
+
+            # FIXME: this is a hack
+            if interfaces.IAdminMedium in ifaces:
+                # we decide on a unique name for admin clients here
+                keycard.avatarId = "admin-%06x" % self._adminCounter
+                self._adminCounter += 1
+
+            self.log('calling %r.requestAvatar(keycard=%r, mind=%r, ifaces=%r)',
+                     self.realm, keycard, mind, ifaces)
+
+            return self.realm.requestAvatar(keycard.avatarId, keycard, mind, *ifaces)
+
+        d = defer.maybeDeferred(self.bouncer.authenticate, keycard)
+        d.addCallback(bouncerResponse)
+        d.addErrback(onErrorCloseConnection)
         return d
 
-    def _authenticateCallback(self, result, mind, *ifaces):
-        # we either got a keycard as result, or None from the bouncer
-        if not result:
-            # just like a checker, we return a failure object
-            f = failure.Failure(error.UnauthorizedLogin())
-            self.info("unauthorized login for interfaces %r", ifaces)
-            return f
-
-        keycard = result
-        if not keycard.state == keycards.AUTHENTICATED:
-            # challenge
-            self.log('returning keycard for further authentication')
-            return keycard
-
-        # this is where we request the Avatar and can influence naming
-        
-        self.debug('authenticated login of %r into realm %r', keycard,
-                   self.realm)
-
-        if interfaces.IAdminMedium in ifaces:
-            # we decide on a unique name for admin clients here
-            keycard.avatarId = "admin-%06x" % self._adminCounter
-            self._adminCounter += 1
-
-        self.log('calling %r.requestAvatar(keycard=%r, mind=%r, ifaces=%r)',
-                 self.realm, keycard, mind, ifaces)
-
-        return self.realm.requestAvatar(keycard.avatarId, keycard, mind, *ifaces)
 registerAdapter(_FPortalRoot, BouncerPortal, flavors.IPBRoot)


More information about the flumotion-commit mailing list