Package buildbot :: Module pbmanager
[frames] | no frames]

Source Code for Module buildbot.pbmanager

  1  # This file is part of Buildbot.  Buildbot is free software: you can 
  2  # redistribute it and/or modify it under the terms of the GNU General Public 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  5  # This program is distributed in the hope that it will be useful, but WITHOUT 
  6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 10  # You should have received a copy of the GNU General Public License along with 
 11  # this program; if not, write to the Free Software Foundation, Inc., 51 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16  from zope.interface import implements 
 17  from twisted.spread import pb 
 18  from twisted.python import failure, log 
 19  from twisted.internet import defer 
 20  from twisted.cred import portal, checkers, credentials, error 
 21  from twisted.application import service, strports 
 22   
 23  debug = False 
 24   
25 -class PBManager(service.MultiService):
26 """ 27 A centralized manager for PB ports and authentication on them. 28 29 Allows various pieces of code to request a (port, username) combo, along 30 with a password and a perspective factory. 31 """
32 - def __init__(self):
33 service.MultiService.__init__(self) 34 self.dispatchers = {}
35
36 - def register(self, portstr, username, password, pfactory):
37 """ 38 Register a perspective factory PFACTORY to be executed when a PB 39 connection arrives on PORTSTR with USERNAME/PASSWORD. Returns a 40 Registration object which can be used to unregister later. 41 """ 42 # do some basic normalization of portstrs 43 if type(portstr) == type(0) or ':' not in portstr: 44 portstr = "tcp:%s" % portstr 45 46 reg = Registration(self, portstr, username) 47 48 if portstr not in self.dispatchers: 49 disp = self.dispatchers[portstr] = Dispatcher(portstr) 50 disp.setServiceParent(self) 51 else: 52 disp = self.dispatchers[portstr] 53 54 disp.register(username, password, pfactory) 55 56 return reg
57
58 - def _unregister(self, registration):
59 disp = self.dispatchers[registration.portstr] 60 disp.unregister(registration.username) 61 registration.username = None 62 if not disp.users: 63 disp = self.dispatchers[registration.portstr] 64 del self.dispatchers[registration.portstr] 65 return disp.disownServiceParent() 66 return defer.succeed(None)
67 68
69 -class Registration(object):
70 - def __init__(self, pbmanager, portstr, username):
71 self.portstr = portstr 72 "portstr this registration is active on" 73 self.username = username 74 "username of this registration" 75 76 self.pbmanager = pbmanager
77
78 - def unregister(self):
79 """ 80 Unregister this registration, removing the username from the port, and 81 closing the port if there are no more users left. Returns a Deferred. 82 """ 83 return self.pbmanager._unregister(self)
84 85
86 -class Dispatcher(service.MultiService):
87 implements(portal.IRealm, checkers.ICredentialsChecker) 88 89 credentialInterfaces = [ credentials.IUsernamePassword, 90 credentials.IUsernameHashedPassword ] 91
92 - def __init__(self, portstr):
93 service.MultiService.__init__(self) 94 self.portstr = portstr 95 self.users = {} 96 97 # there's lots of stuff to set up for a PB connection! 98 self.portal = portal.Portal(self) 99 self.portal.registerChecker(self) 100 self.serverFactory = pb.PBServerFactory(self.portal) 101 self.serverFactory.unsafeTraceback = True 102 self.serverPort = strports.service(portstr, self.serverFactory) 103 self.serverPort.setServiceParent(self)
104
105 - def getPort(self):
106 # helper method for testing 107 return self.serverPort.getHost().port
108
109 - def startService(self):
110 return service.MultiService.startService(self)
111
112 - def stopService(self):
113 return service.MultiService.stopService(self)
114
115 - def register(self, username, password, pfactory):
116 if debug: 117 log.msg("registering username '%s' on pb port %s: %s" 118 % (username, self.portstr, pfactory)) 119 if username in self.users: 120 raise KeyError, ("username '%s' is already registered on PB port %s" 121 % (username, self.portstr)) 122 self.users[username] = (password, pfactory)
123
124 - def unregister(self, username):
125 if debug: 126 log.msg("unregistering username '%s' on pb port %s" 127 % (username, self.portstr)) 128 del self.users[username]
129 130 # IRealm 131
132 - def requestAvatar(self, username, mind, interface):
133 assert interface == pb.IPerspective 134 if username not in self.users: 135 d = defer.succeed(None) # no perspective 136 else: 137 _, afactory = self.users.get(username) 138 d = defer.maybeDeferred(afactory, mind, username) 139 140 # check that we got a perspective 141 def check(persp): 142 if not persp: 143 raise ValueError("no perspective for '%s'" % username) 144 return persp
145 d.addCallback(check) 146 147 # call the perspective's attached(mind) 148 def call_attached(persp): 149 d = defer.maybeDeferred(persp.attached, mind) 150 d.addCallback(lambda _ : persp) # keep returning the perspective 151 return d
152 d.addCallback(call_attached) 153 154 # return the tuple requestAvatar is expected to return 155 def done(persp): 156 return (pb.IPerspective, persp, lambda: persp.detached(mind)) 157 d.addCallback(done) 158 159 return d 160 161 # ICredentialsChecker 162
163 - def requestAvatarId(self, creds):
164 if creds.username in self.users: 165 password, _ = self.users[creds.username] 166 d = defer.maybeDeferred(creds.checkPassword, password) 167 def check(matched): 168 if not matched: 169 return failure.Failure(error.UnauthorizedLogin()) 170 return creds.username
171 d.addCallback(check) 172 return d 173 else: 174 return defer.fail(error.UnauthorizedLogin()) 175