summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2013-06-17 12:11:51 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-06-17 16:09:10 +0100
commit3ea9d647ec35c4d30dcaa5b58e9471b775a4716c (patch)
treee3e5022ce0e34320bd555942c418a3cb02282651 /bitbake
parent194b395f85dbed216b7dd51e66f8b567955307f2 (diff)
downloadpoky-3ea9d647ec35c4d30dcaa5b58e9471b775a4716c.tar.gz
bitbake: knotty, xmlrpc: add observer-only mode
I add an observer only mode for the knotty UI and the XMLRPC server that will allow the UI to register a callback with a server in order to receive events. The observer-UI is able to send read-only commands to the server, and also is able to register as an event handler. Read-only commands are the commands that do not change the state of the server and have been marked as such in the command module. The observer can switch to a full client if it calls addClient at any time, and the server has no other client running. (Bitbake rev: 4de9ee21f1fa4d04937cc7430fb1fc8b7a8f61e2) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rwxr-xr-xbitbake/bin/bitbake8
-rw-r--r--bitbake/lib/bb/command.py7
-rw-r--r--bitbake/lib/bb/server/xmlrpc.py26
-rw-r--r--bitbake/lib/bb/ui/knotty.py29
-rw-r--r--bitbake/lib/bb/ui/uievent.py1
5 files changed, 49 insertions, 22 deletions
diff --git a/bitbake/bin/bitbake b/bitbake/bin/bitbake
index 1fac9feb24..e77266b4ba 100755
--- a/bitbake/bin/bitbake
+++ b/bitbake/bin/bitbake
@@ -197,6 +197,9 @@ class BitBakeConfigParameters(cookerdata.ConfigParameters):
197 parser.add_option("", "--remote-server", help = "Connect to the specified server", 197 parser.add_option("", "--remote-server", help = "Connect to the specified server",
198 action = "store", dest = "remote_server", default = False) 198 action = "store", dest = "remote_server", default = False)
199 199
200 parser.add_option("", "--observe-only", help = "Connect to a server as an observing-only client",
201 action = "store_true", dest = "observe_only", default = False)
202
200 options, targets = parser.parse_args(sys.argv) 203 options, targets = parser.parse_args(sys.argv)
201 return options, targets[1:] 204 return options, targets[1:]
202 205
@@ -269,6 +272,9 @@ def main():
269 if configParams.remote_server and configParams.servertype != "xmlrpc": 272 if configParams.remote_server and configParams.servertype != "xmlrpc":
270 sys.exit("FATAL: If '--remote-server' is defined, we must set the servertype as 'xmlrpc'.\n") 273 sys.exit("FATAL: If '--remote-server' is defined, we must set the servertype as 'xmlrpc'.\n")
271 274
275 if configParams.observe_only and (not configParams.remote_server or configParams.bind):
276 sys.exit("FATAL: '--observe-only' can only be used by UI clients connecting to a server.\n")
277
272 if "BBDEBUG" in os.environ: 278 if "BBDEBUG" in os.environ:
273 level = int(os.environ["BBDEBUG"]) 279 level = int(os.environ["BBDEBUG"])
274 if level > configuration.debug: 280 if level > configuration.debug:
@@ -295,7 +301,7 @@ def main():
295 server = start_server(servermodule, configParams, configuration) 301 server = start_server(servermodule, configParams, configuration)
296 else: 302 else:
297 # we start a stub server that is actually a XMLRPClient to 303 # we start a stub server that is actually a XMLRPClient to
298 server = servermodule.BitBakeXMLRPCClient() 304 server = servermodule.BitBakeXMLRPCClient(configParams.observe_only)
299 server.saveConnectionDetails(configParams.remote_server) 305 server.saveConnectionDetails(configParams.remote_server)
300 306
301 logger.removeHandler(handler) 307 logger.removeHandler(handler)
diff --git a/bitbake/lib/bb/command.py b/bitbake/lib/bb/command.py
index ab6950111f..5f696c2aee 100644
--- a/bitbake/lib/bb/command.py
+++ b/bitbake/lib/bb/command.py
@@ -59,11 +59,14 @@ class Command:
59 # FIXME Add lock for this 59 # FIXME Add lock for this
60 self.currentAsyncCommand = None 60 self.currentAsyncCommand = None
61 61
62 def runCommand(self, commandline): 62 def runCommand(self, commandline, ro_only = False):
63 command = commandline.pop(0) 63 command = commandline.pop(0)
64 if hasattr(CommandsSync, command): 64 if hasattr(CommandsSync, command):
65 # Can run synchronous commands straight away 65 # Can run synchronous commands straight away
66 command_method = getattr(self.cmds_sync, command) 66 command_method = getattr(self.cmds_sync, command)
67 if ro_only:
68 if not hasattr(command_method, 'readonly') or False == getattr(command_method, 'readonly'):
69 return None, "Not able to execute not readonly commands in readonly mode"
67 try: 70 try:
68 result = command_method(self, commandline) 71 result = command_method(self, commandline)
69 except CommandError as exc: 72 except CommandError as exc:
@@ -153,6 +156,7 @@ class CommandsSync:
153 expand = params[1] 156 expand = params[1]
154 157
155 return command.cooker.data.getVar(varname, expand) 158 return command.cooker.data.getVar(varname, expand)
159 getVariable.readonly = True
156 160
157 def setVariable(self, command, params): 161 def setVariable(self, command, params):
158 """ 162 """
@@ -200,6 +204,7 @@ class CommandsSync:
200 Get the CPU count on the bitbake server 204 Get the CPU count on the bitbake server
201 """ 205 """
202 return bb.utils.cpu_count() 206 return bb.utils.cpu_count()
207 getCpuCount.readonly = True
203 208
204 def matchFile(self, command, params): 209 def matchFile(self, command, params):
205 fMatch = params[0] 210 fMatch = params[0]
diff --git a/bitbake/lib/bb/server/xmlrpc.py b/bitbake/lib/bb/server/xmlrpc.py
index 5045e55ae2..026415efd5 100644
--- a/bitbake/lib/bb/server/xmlrpc.py
+++ b/bitbake/lib/bb/server/xmlrpc.py
@@ -93,7 +93,7 @@ class BitBakeServerCommands():
93 """ 93 """
94 Run a cooker command on the server 94 Run a cooker command on the server
95 """ 95 """
96 return self.cooker.command.runCommand(command) 96 return self.cooker.command.runCommand(command, self.server.readonly)
97 97
98 def terminateServer(self): 98 def terminateServer(self):
99 """ 99 """
@@ -124,7 +124,7 @@ class BitBakeServerCommands():
124# ("service unavailable") is returned to the client. 124# ("service unavailable") is returned to the client.
125class BitBakeXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 125class BitBakeXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
126 def __init__(self, request, client_address, server): 126 def __init__(self, request, client_address, server):
127 self.connection_token = server.connection_token 127 self.server = server
128 SimpleXMLRPCRequestHandler.__init__(self, request, client_address, server) 128 SimpleXMLRPCRequestHandler.__init__(self, request, client_address, server)
129 129
130 def do_POST(self): 130 def do_POST(self):
@@ -132,9 +132,13 @@ class BitBakeXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
132 remote_token = self.headers["Bitbake-token"] 132 remote_token = self.headers["Bitbake-token"]
133 except: 133 except:
134 remote_token = None 134 remote_token = None
135 if remote_token != self.connection_token: 135 if remote_token != self.server.connection_token and remote_token != "observer":
136 self.report_503() 136 self.report_503()
137 else: 137 else:
138 if remote_token == "observer":
139 self.server.readonly = True
140 else:
141 self.server.readonly = False
138 SimpleXMLRPCRequestHandler.do_POST(self) 142 SimpleXMLRPCRequestHandler.do_POST(self)
139 143
140 def report_503(self): 144 def report_503(self):
@@ -283,13 +287,17 @@ class XMLRPCServer(SimpleXMLRPCServer, BaseImplServer):
283 self.connection_token = token 287 self.connection_token = token
284 288
285class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection): 289class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection):
286 def __init__(self, serverImpl, clientinfo=("localhost", 0)): 290 def __init__(self, serverImpl, clientinfo=("localhost", 0), observer_only = False):
287 self.connection, self.transport = _create_server(serverImpl.host, serverImpl.port) 291 self.connection, self.transport = _create_server(serverImpl.host, serverImpl.port)
288 self.clientinfo = clientinfo 292 self.clientinfo = clientinfo
289 self.serverImpl = serverImpl 293 self.serverImpl = serverImpl
294 self.observer_only = observer_only
290 295
291 def connect(self): 296 def connect(self):
292 token = self.connection.addClient() 297 if not self.observer_only:
298 token = self.connection.addClient()
299 else:
300 token = "observer"
293 if token is None: 301 if token is None:
294 return None 302 return None
295 self.transport.set_connection_token(token) 303 self.transport.set_connection_token(token)
@@ -299,7 +307,8 @@ class BitBakeXMLRPCServerConnection(BitBakeBaseServerConnection):
299 return self 307 return self
300 308
301 def removeClient(self): 309 def removeClient(self):
302 self.connection.removeClient() 310 if not self.observer_only:
311 self.connection.removeClient()
303 312
304 def terminate(self): 313 def terminate(self):
305 # Don't wait for server indefinitely 314 # Don't wait for server indefinitely
@@ -331,7 +340,8 @@ class BitBakeServer(BitBakeBaseServer):
331 340
332class BitBakeXMLRPCClient(BitBakeBaseServer): 341class BitBakeXMLRPCClient(BitBakeBaseServer):
333 342
334 def __init__(self): 343 def __init__(self, observer_only = False):
344 self.observer_only = observer_only
335 pass 345 pass
336 346
337 def saveConnectionDetails(self, remote): 347 def saveConnectionDetails(self, remote):
@@ -354,7 +364,7 @@ class BitBakeXMLRPCClient(BitBakeBaseServer):
354 except: 364 except:
355 return None 365 return None
356 self.serverImpl = XMLRPCProxyServer(host, port) 366 self.serverImpl = XMLRPCProxyServer(host, port)
357 self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0)) 367 self.connection = BitBakeXMLRPCServerConnection(self.serverImpl, (ip, 0), self.observer_only)
358 return self.connection.connect() 368 return self.connection.connect()
359 369
360 def endSession(self): 370 def endSession(self):
diff --git a/bitbake/lib/bb/ui/knotty.py b/bitbake/lib/bb/ui/knotty.py
index 389c3cc64d..c6a1d3f98a 100644
--- a/bitbake/lib/bb/ui/knotty.py
+++ b/bitbake/lib/bb/ui/knotty.py
@@ -216,21 +216,25 @@ class TerminalFilter(object):
216 fd = sys.stdin.fileno() 216 fd = sys.stdin.fileno()
217 self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup) 217 self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup)
218 218
219def main(server, eventHandler, params, tf = TerminalFilter): 219def _log_settings_from_server(server):
220
221 # Get values of variables which control our output 220 # Get values of variables which control our output
222 includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"]) 221 includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
223 if error: 222 if error:
224 logger.error("Unable to get the value of BBINCLUDELOGS variable: %s" % error) 223 logger.error("Unable to get the value of BBINCLUDELOGS variable: %s" % error)
225 return 1 224 raise BaseException(error)
226 loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"]) 225 loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
227 if error: 226 if error:
228 logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error) 227 logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error)
229 return 1 228 raise BaseException(error)
230 consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"]) 229 consolelogfile, error = server.runCommand(["getVariable", "BB_CONSOLELOG"])
231 if error: 230 if error:
232 logger.error("Unable to get the value of BB_CONSOLELOG variable: %s" % error) 231 logger.error("Unable to get the value of BB_CONSOLELOG variable: %s" % error)
233 return 1 232 raise BaseException(error)
233 return includelogs, loglines, consolelogfile
234
235def main(server, eventHandler, params, tf = TerminalFilter):
236
237 includelogs, loglines, consolelogfile = _log_settings_from_server(server)
234 238
235 if sys.stdin.isatty() and sys.stdout.isatty(): 239 if sys.stdin.isatty() and sys.stdout.isatty():
236 log_exec_tty = True 240 log_exec_tty = True
@@ -254,7 +258,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
254 consolelog.setFormatter(conlogformat) 258 consolelog.setFormatter(conlogformat)
255 logger.addHandler(consolelog) 259 logger.addHandler(consolelog)
256 260
257 try: 261 if not params.observe_only:
258 params.updateFromServer(server) 262 params.updateFromServer(server)
259 cmdline = params.parseActions() 263 cmdline = params.parseActions()
260 if not cmdline: 264 if not cmdline:
@@ -271,9 +275,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
271 elif ret != True: 275 elif ret != True:
272 logger.error("Command '%s' failed: returned %s" % (cmdline, ret)) 276 logger.error("Command '%s' failed: returned %s" % (cmdline, ret))
273 return 1 277 return 1
274 except xmlrpclib.Fault as x: 278
275 logger.error("XMLRPC Fault getting commandline:\n %s" % x)
276 return 1
277 279
278 parseprogress = None 280 parseprogress = None
279 cacheprogress = None 281 cacheprogress = None
@@ -320,7 +322,7 @@ def main(server, eventHandler, params, tf = TerminalFilter):
320 elif event.levelno == format.WARNING: 322 elif event.levelno == format.WARNING:
321 warnings = warnings + 1 323 warnings = warnings + 1
322 # For "normal" logging conditions, don't show note logs from tasks 324 # For "normal" logging conditions, don't show note logs from tasks
323 # but do show them if the user has changed the default log level to 325 # but do show them if the user has changed the default log level to
324 # include verbose/debug messages 326 # include verbose/debug messages
325 if event.taskpid != 0 and event.levelno <= format.NOTE: 327 if event.taskpid != 0 and event.levelno <= format.NOTE:
326 continue 328 continue
@@ -469,12 +471,15 @@ def main(server, eventHandler, params, tf = TerminalFilter):
469 pass 471 pass
470 except KeyboardInterrupt: 472 except KeyboardInterrupt:
471 termfilter.clearFooter() 473 termfilter.clearFooter()
472 if main.shutdown == 1: 474 if params.observe_only:
475 print("\nKeyboard Interrupt, exiting observer...")
476 main.shutdown = 2
477 if not params.observe_only and main.shutdown == 1:
473 print("\nSecond Keyboard Interrupt, stopping...\n") 478 print("\nSecond Keyboard Interrupt, stopping...\n")
474 _, error = server.runCommand(["stateStop"]) 479 _, error = server.runCommand(["stateStop"])
475 if error: 480 if error:
476 logger.error("Unable to cleanly stop: %s" % error) 481 logger.error("Unable to cleanly stop: %s" % error)
477 if main.shutdown == 0: 482 if not params.observe_only and main.shutdown == 0:
478 print("\nKeyboard Interrupt, closing down...\n") 483 print("\nKeyboard Interrupt, closing down...\n")
479 interrupted = True 484 interrupted = True
480 _, error = server.runCommand(["stateShutdown"]) 485 _, error = server.runCommand(["stateShutdown"])
diff --git a/bitbake/lib/bb/ui/uievent.py b/bitbake/lib/bb/ui/uievent.py
index 0b9a836d0f..038029fcfa 100644
--- a/bitbake/lib/bb/ui/uievent.py
+++ b/bitbake/lib/bb/ui/uievent.py
@@ -84,6 +84,7 @@ class BBUIEventQueue:
84 84
85 def startCallbackHandler(self): 85 def startCallbackHandler(self):
86 86
87 self.server.timeout = 1
87 while not self.server.quit: 88 while not self.server.quit:
88 self.server.handle_request() 89 self.server.handle_request()
89 self.server.server_close() 90 self.server.server_close()