bitbake: bitbake: xmlrpc transport has identification token

In order to be able to identify different clients over a
stateless XMLRPC connection, we add a custom header named
Bitbake-token, which identifies each client.

We refactor the rest of the code to use the new transport.

Based on a patch by Bogdan Marinescu <bogdan.a.marinescu@intel.com>

(Bitbake rev: a00c2186bffe848a7cedf31969b904f8f7322ae6)

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Alexandru DAMIAN 2013-05-28 13:55:09 +00:00 committed by Richard Purdie
parent b6b30095de
commit 0fc3a1eddf
1 changed files with 89 additions and 55 deletions

View File

@ -54,82 +54,104 @@ if sys.hexversion < 0x020600F0:
# Upstream Python bug is #8194 (http://bugs.python.org/issue8194) # Upstream Python bug is #8194 (http://bugs.python.org/issue8194)
# This bug is relevant for Python 2.7.0 and 2.7.1 but was fixed for # This bug is relevant for Python 2.7.0 and 2.7.1 but was fixed for
# Python > 2.7.2 # Python > 2.7.2
#
# To implement a simple form of client control, we use a special transport
# that adds a HTTP header field ("Bitbake-token") to ensure that a server
# can communicate with only a client at a given time (the client must use
# the same token).
## ##
if (2, 7, 0) <= sys.version_info < (2, 7, 2):
class BBTransport(xmlrpclib.Transport):
def __init__(self):
self.connection_token = None
xmlrpclib.Transport.__init__(self)
class BBTransport(xmlrpclib.Transport): def request(self, host, handler, request_body, verbose=0):
def request(self, host, handler, request_body, verbose=0): h = self.make_connection(host)
h = self.make_connection(host) if verbose:
if verbose: h.set_debuglevel(1)
h.set_debuglevel(1)
self.send_request(h, handler, request_body) self.send_request(h, handler, request_body)
self.send_host(h, host) self.send_host(h, host)
self.send_user_agent(h) self.send_user_agent(h)
self.send_content(h, request_body) if self.connection_token:
h.putheader("Bitbake-token", self.connection_token)
self.send_content(h, request_body)
errcode, errmsg, headers = h.getreply() errcode, errmsg, headers = h.getreply()
if errcode != 200: if errcode != 200:
raise ProtocolError( raise ProtocolError(
host + handler, host + handler,
errcode, errmsg, errcode, errmsg,
headers headers
) )
self.verbose = verbose self.verbose = verbose
try: try:
sock = h._conn.sock sock = h._conn.sock
except AttributeError: except AttributeError:
sock = None sock = None
return self._parse_response(h.getfile(), sock) return self._parse_response(h.getfile(), sock)
def make_connection(self, host): def make_connection(self, host):
import httplib import httplib
host, extra_headers, x509 = self.get_host_info(host) host, extra_headers, x509 = self.get_host_info(host)
return httplib.HTTP(host) return httplib.HTTP(host)
def _parse_response(self, file, sock): def _parse_response(self, file, sock):
p, u = self.getparser() p, u = self.getparser()
while 1: while 1:
if sock: if sock:
response = sock.recv(1024) response = sock.recv(1024)
else: else:
response = file.read(1024) response = file.read(1024)
if not response: if not response:
break break
if self.verbose: if self.verbose:
print("body:", repr(response)) print("body:", repr(response))
p.feed(response) p.feed(response)
file.close() file.close()
p.close() p.close()
return u.close() return u.close()
def set_connection_token(self, token):
self.connection_token = token
else:
class BBTransport(xmlrpclib.Transport):
def __init__(self):
self.connection_token = None
xmlrpclib.Transport.__init__(self)
def set_connection_token(self, token):
self.connection_token = token
def send_content(self, h, body):
if self.connection_token:
h.putheader("Bitbake-token", self.connection_token)
xmlrpclib.Transport.send_content(self, h, body)
def _create_server(host, port): def _create_server(host, port):
# Python 2.7.0 and 2.7.1 have a buggy Transport implementation t = BBTransport()
# For those versions of Python, and only those versions, use our s = xmlrpclib.Server("http://%s:%d/" % (host, port), transport=t, allow_none=True)
# own copy/paste BBTransport class. return s, t
if (2, 7, 0) <= sys.version_info < (2, 7, 2):
t = BBTransport()
s = xmlrpclib.Server("http://%s:%d/" % (host, port), transport=t, allow_none=True)
else:
s = xmlrpclib.Server("http://%s:%d/" % (host, port), allow_none=True)
return s
class BitBakeServerCommands(): class BitBakeServerCommands():
def __init__(self, server): def __init__(self, server):
self.server = server self.server = server
self.has_client = False
def registerEventHandler(self, host, port): def registerEventHandler(self, host, port):
""" """
Register a remote UI Event Handler Register a remote UI Event Handler
""" """
s = _create_server(host, port) s, t = _create_server(host, port)
return bb.event.register_UIHhandler(s) return bb.event.register_UIHhandler(s)
@ -248,10 +270,22 @@ class BitbakeServerInfo():
class BitBakeServerConnection(): class BitBakeServerConnection():
def __init__(self, serverinfo, clientinfo=("localhost", 0)): def __init__(self, serverinfo, clientinfo=("localhost", 0)):
self.connection = _create_server(serverinfo.host, serverinfo.port) self.connection, self.transport = _create_server(serverinfo.host, serverinfo.port)
self.events = uievent.BBUIEventQueue(self.connection, clientinfo) self.clientinfo = clientinfo
self.serverinfo = serverinfo
def connect(self):
token = self.connection.addClient()
if token is None:
return None
self.transport.set_connection_token(token)
self.events = uievent.BBUIEventQueue(self.connection, self.clientinfo)
for event in bb.event.ui_queue: for event in bb.event.ui_queue:
self.events.queue_event(event) self.events.queue_event(event)
return self
def removeClient(self):
self.connection.removeClient()
def terminate(self): def terminate(self):
# Don't wait for server indefinitely # Don't wait for server indefinitely
@ -277,7 +311,7 @@ class BitBakeServer(object):
def getServerIdleCB(self): def getServerIdleCB(self):
return self.server.register_idle_function return self.server.register_idle_function
def saveConnectionDetails(self): def saveConnectionDetails(self):
self.serverinfo = BitbakeServerInfo(self.server.host, self.server.port) self.serverinfo = BitbakeServerInfo(self.server.host, self.server.port)
def detach(self): def detach(self):