summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/server
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2013-05-31 12:06:46 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-06-07 14:13:18 +0100
commit748e3c13c80f698f8396bbc55e42ac3ee6a2a81e (patch)
tree23152dd616209720267647d8a5f36730896983f9 /bitbake/lib/bb/server
parenta62aed41f2d8f874f7ae24d0e5be5dbc66ea2199 (diff)
downloadpoky-748e3c13c80f698f8396bbc55e42ac3ee6a2a81e.tar.gz
bitbake: bitbake server: create common server infrastructure
In an attempt to minimize code duplication, create clear interfaces, and maximize code reuse through OOP, bb.server adds base classes for the BitBakeServer, BitBakeServerConnection and actual server implementations instructed in particular server types. These classes document the minimum interfaces that the derived classes must implement, and provide boilerplate code. Changes to None, Process and XMLRPC servers as to use the common server infrastructure. (Bitbake rev: 6db4a64cef20f8d0aba804db4c4e1eec7b112b46) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/server')
-rw-r--r--bitbake/lib/bb/server/__init__.py96
-rw-r--r--bitbake/lib/bb/server/process.py53
-rw-r--r--bitbake/lib/bb/server/xmlrpc.py64
3 files changed, 141 insertions, 72 deletions
diff --git a/bitbake/lib/bb/server/__init__.py b/bitbake/lib/bb/server/__init__.py
index e69de29bb2..2e1c619b54 100644
--- a/bitbake/lib/bb/server/__init__.py
+++ b/bitbake/lib/bb/server/__init__.py
@@ -0,0 +1,96 @@
1#
2# BitBake Base Server Code
3#
4# Copyright (C) 2006 - 2007 Michael 'Mickey' Lauer
5# Copyright (C) 2006 - 2008 Richard Purdie
6# Copyright (C) 2013 Alexandru Damian
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21""" Base code for Bitbake server process
22
23Have a common base for that all Bitbake server classes ensures a consistent
24approach to the interface, and minimize risks associated with code duplication.
25
26"""
27
28""" BaseImplServer() the base class for all XXServer() implementations.
29
30 These classes contain the actual code that runs the server side, i.e.
31 listens for the commands and executes them. Although these implementations
32 contain all the data of the original bitbake command, i.e the cooker instance,
33 they may well run on a different process or even machine.
34
35"""
36
37class BaseImplServer():
38 def __init__(self):
39 self._idlefuns = {}
40
41 def addcooker(self, cooker):
42 self.cooker = cooker
43
44 def register_idle_function(self, function, data):
45 """Register a function to be called while the server is idle"""
46 assert hasattr(function, '__call__')
47 self._idlefuns[function] = data
48
49
50
51""" BitBakeBaseServerConnection class is the common ancestor to all
52 BitBakeServerConnection classes.
53
54 These classes control the remote server. The only command currently
55 implemented is the terminate() command.
56
57"""
58
59class BitBakeBaseServerConnection():
60 def __init__(self, serverImpl):
61 pass
62
63 def terminate(self):
64 pass
65
66
67""" BitBakeBaseServer class is the common ancestor to all Bitbake servers
68
69 Derive this class in order to implement a BitBakeServer which is the
70 controlling stub for the actual server implementation
71
72"""
73class BitBakeBaseServer(object):
74 def initServer(self):
75 self.serverImpl = None # we ensure a runtime crash if not overloaded
76 self.connection = None
77 return
78
79 def addcooker(self, cooker):
80 self.cooker = cooker
81 self.serverImpl.addcooker(cooker)
82
83 def getServerIdleCB(self):
84 return self.serverImpl.register_idle_function
85
86 def saveConnectionDetails(self):
87 return
88
89 def detach(self):
90 return
91
92 def establishConnection(self):
93 raise "Must redefine the %s.establishConnection()" % self.__class__.__name__
94
95 def endSession(self):
96 self.connection.terminate()
diff --git a/bitbake/lib/bb/server/process.py b/bitbake/lib/bb/server/process.py
index 163dbbb997..d73fe827e4 100644
--- a/bitbake/lib/bb/server/process.py
+++ b/bitbake/lib/bb/server/process.py
@@ -32,6 +32,8 @@ import time
32from Queue import Empty 32from Queue import Empty
33from multiprocessing import Event, Process, util, Queue, Pipe, queues 33from multiprocessing import Event, Process, util, Queue, Pipe, queues
34 34
35from . import BitBakeBaseServer, BitBakeBaseServerConnection, BaseImplServer
36
35logger = logging.getLogger('BitBake') 37logger = logging.getLogger('BitBake')
36 38
37class ServerCommunicator(): 39class ServerCommunicator():
@@ -68,26 +70,21 @@ class EventAdapter():
68 print("EventAdapter puked: %s" % str(err)) 70 print("EventAdapter puked: %s" % str(err))
69 71
70 72
71class ProcessServer(Process): 73class ProcessServer(Process, BaseImplServer):
72 profile_filename = "profile.log" 74 profile_filename = "profile.log"
73 profile_processed_filename = "profile.log.processed" 75 profile_processed_filename = "profile.log.processed"
74 76
75 def __init__(self, command_channel, event_queue): 77 def __init__(self, command_channel, event_queue):
78 BaseImplServer.__init__(self)
76 Process.__init__(self) 79 Process.__init__(self)
77 self.command_channel = command_channel 80 self.command_channel = command_channel
78 self.event_queue = event_queue 81 self.event_queue = event_queue
79 self.event = EventAdapter(event_queue) 82 self.event = EventAdapter(event_queue)
80 self._idlefunctions = {}
81 self.quit = False 83 self.quit = False
82 84
83 self.keep_running = Event() 85 self.keep_running = Event()
84 self.keep_running.set() 86 self.keep_running.set()
85 87
86 def register_idle_function(self, function, data):
87 """Register a function to be called while the server is idle"""
88 assert hasattr(function, '__call__')
89 self._idlefunctions[function] = data
90
91 def run(self): 88 def run(self):
92 for event in bb.event.ui_queue: 89 for event in bb.event.ui_queue:
93 self.event_queue.put(event) 90 self.event_queue.put(event)
@@ -117,11 +114,11 @@ class ProcessServer(Process):
117 def idle_commands(self, delay): 114 def idle_commands(self, delay):
118 nextsleep = delay 115 nextsleep = delay
119 116
120 for function, data in self._idlefunctions.items(): 117 for function, data in self._idlefuns.items():
121 try: 118 try:
122 retval = function(self, data, False) 119 retval = function(self, data, False)
123 if retval is False: 120 if retval is False:
124 del self._idlefunctions[function] 121 del self._idlefuns[function]
125 elif retval is True: 122 elif retval is True:
126 nextsleep = None 123 nextsleep = None
127 elif nextsleep is None: 124 elif nextsleep is None:
@@ -191,12 +188,13 @@ class ProcessServer(Process):
191 if (2, 6, 0) <= sys.version_info < (2, 6, 3): 188 if (2, 6, 0) <= sys.version_info < (2, 6, 3):
192 _bootstrap = bootstrap_2_6_6 189 _bootstrap = bootstrap_2_6_6
193 190
194class BitBakeServerConnection(): 191class BitBakeProcessServerConnection(BitBakeBaseServerConnection):
195 def __init__(self, server): 192 def __init__(self, serverImpl, ui_channel, event_queue):
196 self.server = server 193 self.procserver = serverImpl
197 self.procserver = server.server 194 self.ui_channel = ui_channel
198 self.connection = ServerCommunicator(server.ui_channel) 195 self.event_queue = event_queue
199 self.events = server.event_queue 196 self.connection = ServerCommunicator(self.ui_channel)
197 self.events = self.event_queue
200 198
201 def terminate(self, force = False): 199 def terminate(self, force = False):
202 signal.signal(signal.SIGINT, signal.SIG_IGN) 200 signal.signal(signal.SIGINT, signal.SIG_IGN)
@@ -210,13 +208,13 @@ class BitBakeServerConnection():
210 self.procserver.join() 208 self.procserver.join()
211 while True: 209 while True:
212 try: 210 try:
213 event = self.server.event_queue.get(block=False) 211 event = self.event_queue.get(block=False)
214 except (Empty, IOError): 212 except (Empty, IOError):
215 break 213 break
216 if isinstance(event, logging.LogRecord): 214 if isinstance(event, logging.LogRecord):
217 logger.handle(event) 215 logger.handle(event)
218 self.server.ui_channel.close() 216 self.ui_channel.close()
219 self.server.event_queue.close() 217 self.event_queue.close()
220 if force: 218 if force:
221 sys.exit(1) 219 sys.exit(1)
222 220
@@ -235,7 +233,7 @@ class ProcessEventQueue(multiprocessing.queues.Queue):
235 return None 233 return None
236 234
237 235
238class BitBakeServer(object): 236class BitBakeServer(BitBakeBaseServer):
239 def initServer(self): 237 def initServer(self):
240 # establish communication channels. We use bidirectional pipes for 238 # establish communication channels. We use bidirectional pipes for
241 # ui <--> server command/response pairs 239 # ui <--> server command/response pairs
@@ -243,24 +241,13 @@ class BitBakeServer(object):
243 # 241 #
244 self.ui_channel, self.server_channel = Pipe() 242 self.ui_channel, self.server_channel = Pipe()
245 self.event_queue = ProcessEventQueue(0) 243 self.event_queue = ProcessEventQueue(0)
246 244 self.serverImpl = ProcessServer(self.server_channel, self.event_queue)
247 self.server = ProcessServer(self.server_channel, self.event_queue)
248
249 def addcooker(self, cooker):
250 self.cooker = cooker
251 self.server.cooker = cooker
252
253 def getServerIdleCB(self):
254 return self.server.register_idle_function
255
256 def saveConnectionDetails(self):
257 return
258 245
259 def detach(self): 246 def detach(self):
260 self.server.start() 247 self.serverImpl.start()
261 return 248 return
262 249
263 def establishConnection(self): 250 def establishConnection(self):
264 self.connection = BitBakeServerConnection(self) 251 self.connection = BitBakeProcessServerConnection(self.serverImpl, self.ui_channel, self.event_queue)
265 signal.signal(signal.SIGTERM, lambda i, s: self.connection.terminate(force=True)) 252 signal.signal(signal.SIGTERM, lambda i, s: self.connection.terminate(force=True))
266 return self.connection 253 return self.connection
diff --git a/bitbake/lib/bb/server/xmlrpc.py b/bitbake/lib/bb/server/xmlrpc.py
index 56a643c576..2747ed8bf8 100644
--- a/bitbake/lib/bb/server/xmlrpc.py
+++ b/bitbake/lib/bb/server/xmlrpc.py
@@ -49,6 +49,8 @@ DEBUG = False
49from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler 49from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
50import inspect, select 50import inspect, select
51 51
52from . import BitBakeBaseServer, BitBakeBaseServerConnection, BaseImplServer
53
52if sys.hexversion < 0x020600F0: 54if sys.hexversion < 0x020600F0:
53 print("Sorry, python 2.6 or later is required for bitbake's XMLRPC mode") 55 print("Sorry, python 2.6 or later is required for bitbake's XMLRPC mode")
54 sys.exit(1) 56 sys.exit(1)
@@ -286,7 +288,6 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
286 """ 288 """
287 Register a remote UI Event Handler 289 Register a remote UI Event Handler
288 """ 290 """
289 print "registering handler %s:%s" % (host,port)
290 connection = xmlrpclib.ServerProxy("http://%s:%d/" % (host, port), allow_none=True) 291 connection = xmlrpclib.ServerProxy("http://%s:%d/" % (host, port), allow_none=True)
291 client_hash = "%s:%d" % (host, port) 292 client_hash = "%s:%d" % (host, port)
292 if self.clients.has_key(client_hash): 293 if self.clients.has_key(client_hash):
@@ -301,7 +302,6 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
301 """ 302 """
302 Unregister a remote UI Event Handler 303 Unregister a remote UI Event Handler
303 """ 304 """
304 print "unregistering handler %s:%s" % (host,port)
305 client_thread = self.clients[client_hash] 305 client_thread = self.clients[client_hash]
306 if client_thread: 306 if client_thread:
307 bb.event.unregister_UIHhandler(self.clients_ui_ids[client_hash]) 307 bb.event.unregister_UIHhandler(self.clients_ui_ids[client_hash])
@@ -323,7 +323,16 @@ class BitBakeXMLRPCEventServerController(SimpleXMLRPCServer):
323 self.handle_request() 323 self.handle_request()
324 self.server_close() 324 self.server_close()
325 325
326class BitBakeXMLRPCServer(SimpleXMLRPCServer): 326
327class XMLRPCProxyServer(BaseImplServer):
328 """ not a real working server, but a stub for a proxy server connection
329
330 """
331 def __init__(self, host, port):
332 self.host = host
333 self.port = port
334
335class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer):
327 # remove this when you're done with debugging 336 # remove this when you're done with debugging
328 # allow_reuse_address = True 337 # allow_reuse_address = True
329 338
@@ -331,10 +340,10 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
331 """ 340 """
332 Constructor 341 Constructor
333 """ 342 """
343 BaseImplServer.__init__(self)
334 SimpleXMLRPCServer.__init__(self, interface, 344 SimpleXMLRPCServer.__init__(self, interface,
335 requestHandler=BitBakeXMLRPCRequestHandler, 345 requestHandler=BitBakeXMLRPCRequestHandler,
336 logRequests=False, allow_none=True) 346 logRequests=False, allow_none=True)
337 self._idlefuns = {}
338 self.host, self.port = self.socket.getsockname() 347 self.host, self.port = self.socket.getsockname()
339 self.connection_token = None 348 self.connection_token = None
340 #self.register_introspection_functions() 349 #self.register_introspection_functions()
@@ -343,7 +352,7 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
343 self.interface = interface 352 self.interface = interface
344 353
345 def addcooker(self, cooker): 354 def addcooker(self, cooker):
346 self.cooker = cooker 355 BaseImplServer.addcooker(self, cooker)
347 self.commands.cooker = cooker 356 self.commands.cooker = cooker
348 357
349 def autoregister_all_functions(self, context, prefix): 358 def autoregister_all_functions(self, context, prefix):
@@ -356,10 +365,6 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
356 if name.startswith(prefix): 365 if name.startswith(prefix):
357 self.register_function(method, name[len(prefix):]) 366 self.register_function(method, name[len(prefix):])
358 367
359 def register_idle_function(self, function, data):
360 """Register a function to be called while the server is idle"""
361 assert hasattr(function, '__call__')
362 self._idlefuns[function] = data
363 368
364 def serve_forever(self): 369 def serve_forever(self):
365 # Create and run the event server controller in a separate thread 370 # Create and run the event server controller in a separate thread
@@ -420,16 +425,11 @@ class BitBakeXMLRPCServer(SimpleXMLRPCServer):
420 def set_connection_token(self, token): 425 def set_connection_token(self, token):
421 self.connection_token = token 426 self.connection_token = token
422 427
423class BitbakeServerInfo(): 428class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection):
424 def __init__(self, host, port): 429 def __init__(self, serverImpl, clientinfo=("localhost", 0)):
425 self.host = host 430 self.connection, self.transport = _create_server(serverImpl.host, serverImpl.port)
426 self.port = port
427
428class BitBakeServerConnection():
429 def __init__(self, serverinfo, clientinfo=("localhost", 0)):
430 self.connection, self.transport = _create_server(serverinfo.host, serverinfo.port)
431 self.clientinfo = clientinfo 431 self.clientinfo = clientinfo
432 self.serverinfo = serverinfo 432 self.serverImpl = serverImpl
433 433
434 def connect(self): 434 def connect(self):
435 token = self.connection.addClient() 435 token = self.connection.addClient()
@@ -457,36 +457,22 @@ class BitBakeServerConnection():
457 except: 457 except:
458 pass 458 pass
459 459
460class BitBakeServer(object): 460class BitBakeServer(BitBakeBaseServer):
461 def initServer(self, interface = ("localhost", 0)): 461 def initServer(self, interface = ("localhost", 0)):
462 self.server = BitBakeXMLRPCServer(interface) 462 self.serverImpl = XMLRPCServer(interface)
463
464 def addcooker(self, cooker):
465 self.cooker = cooker
466 self.server.addcooker(cooker)
467
468 def getServerIdleCB(self):
469 return self.server.register_idle_function
470
471 def saveConnectionDetails(self):
472 self.serverinfo = BitbakeServerInfo(self.server.host, self.server.port)
473 463
474 def detach(self): 464 def detach(self):
475 daemonize.createDaemon(self.server.serve_forever, "bitbake-cookerdaemon.log") 465 daemonize.createDaemon(self.serverImpl.serve_forever, "bitbake-cookerdaemon.log")
476 del self.cooker 466 del self.cooker
477 del self.server
478 467
479 def establishConnection(self): 468 def establishConnection(self):
480 self.connection = BitBakeServerConnection(self.serverinfo) 469 self.connection = BitBakeXMLRPCServerConnection(self.serverImpl)
481 return self.connection.connect() 470 return self.connection.connect()
482 471
483 def set_connection_token(self, token): 472 def set_connection_token(self, token):
484 self.connection.transport.set_connection_token(token) 473 self.connection.transport.set_connection_token(token)
485 474
486 def endSession(self): 475class BitBakeXMLRPCClient(BitBakeBaseServer):
487 self.connection.terminate()
488
489class BitBakeXMLRPCClient(object):
490 476
491 def __init__(self): 477 def __init__(self):
492 pass 478 pass
@@ -510,8 +496,8 @@ class BitBakeXMLRPCClient(object):
510 s.close() 496 s.close()
511 except: 497 except:
512 return None 498 return None
513 self.serverinfo = BitbakeServerInfo(host, port) 499 self.serverImpl = XMLRPCProxyServer(host, port)
514 self.connection = BitBakeServerConnection(self.serverinfo, (ip, 0)) 500 self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0))
515 return self.connection.connect() 501 return self.connection.connect()
516 502
517 def endSession(self): 503 def endSession(self):