diff options
Diffstat (limited to 'meta/lib/oeqa/utils/qemurunner.py')
-rw-r--r-- | meta/lib/oeqa/utils/qemurunner.py | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/meta/lib/oeqa/utils/qemurunner.py b/meta/lib/oeqa/utils/qemurunner.py index 278904ba0b..f6e1007288 100644 --- a/meta/lib/oeqa/utils/qemurunner.py +++ b/meta/lib/oeqa/utils/qemurunner.py | |||
@@ -20,8 +20,10 @@ import string | |||
20 | import threading | 20 | import threading |
21 | import codecs | 21 | import codecs |
22 | import logging | 22 | import logging |
23 | import tempfile | ||
23 | from oeqa.utils.dump import HostDumper | 24 | from oeqa.utils.dump import HostDumper |
24 | from collections import defaultdict | 25 | from collections import defaultdict |
26 | import importlib | ||
25 | 27 | ||
26 | # Get Unicode non printable control chars | 28 | # Get Unicode non printable control chars |
27 | control_range = list(range(0,32))+list(range(127,160)) | 29 | control_range = list(range(0,32))+list(range(127,160)) |
@@ -172,6 +174,21 @@ class QemuRunner: | |||
172 | return self.launch(launch_cmd, qemuparams=qemuparams, get_ip=get_ip, extra_bootparams=extra_bootparams, env=env) | 174 | return self.launch(launch_cmd, qemuparams=qemuparams, get_ip=get_ip, extra_bootparams=extra_bootparams, env=env) |
173 | 175 | ||
174 | def launch(self, launch_cmd, get_ip = True, qemuparams = None, extra_bootparams = None, env = None): | 176 | def launch(self, launch_cmd, get_ip = True, qemuparams = None, extra_bootparams = None, env = None): |
177 | # use logfile to determine the recipe-sysroot-native path and | ||
178 | # then add in the site-packages path components and add that | ||
179 | # to the python sys.path so qmp.py can be found. | ||
180 | python_path = os.path.dirname(os.path.dirname(self.logfile)) | ||
181 | python_path += "/recipe-sysroot-native/usr/lib/python3.9/site-packages" | ||
182 | sys.path.append(python_path) | ||
183 | importlib.invalidate_caches() | ||
184 | try: | ||
185 | qmp = importlib.import_module("qmp") | ||
186 | except: | ||
187 | self.logger.error("qemurunner: qmp.py missing, please ensure it's installed") | ||
188 | return False | ||
189 | qmp_port = self.tmpdir + "/." + next(tempfile._get_candidate_names()) | ||
190 | qmp_param = ' -S -qmp unix:%s,server,wait' % (qmp_port) | ||
191 | |||
175 | try: | 192 | try: |
176 | if self.serial_ports >= 2: | 193 | if self.serial_ports >= 2: |
177 | self.threadsock, threadport = self.create_socket() | 194 | self.threadsock, threadport = self.create_socket() |
@@ -188,7 +205,8 @@ class QemuRunner: | |||
188 | # and analyze descendents in order to determine it. | 205 | # and analyze descendents in order to determine it. |
189 | if os.path.exists(self.qemu_pidfile): | 206 | if os.path.exists(self.qemu_pidfile): |
190 | os.remove(self.qemu_pidfile) | 207 | os.remove(self.qemu_pidfile) |
191 | self.qemuparams = 'bootparams="{0}" qemuparams="-pidfile {1}"'.format(bootparams, self.qemu_pidfile) | 208 | self.qemuparams = 'bootparams="{0}" qemuparams="-pidfile {1} {2}"'.format(bootparams, self.qemu_pidfile, qmp_param) |
209 | |||
192 | if qemuparams: | 210 | if qemuparams: |
193 | self.qemuparams = self.qemuparams[:-1] + " " + qemuparams + " " + '\"' | 211 | self.qemuparams = self.qemuparams[:-1] + " " + qemuparams + " " + '\"' |
194 | 212 | ||
@@ -242,6 +260,7 @@ class QemuRunner: | |||
242 | while not self.is_alive() and time.time() < endtime: | 260 | while not self.is_alive() and time.time() < endtime: |
243 | if self.runqemu.poll(): | 261 | if self.runqemu.poll(): |
244 | if self.runqemu_exited: | 262 | if self.runqemu_exited: |
263 | self.logger.warning("runqemu during is_alive() test") | ||
245 | return False | 264 | return False |
246 | if self.runqemu.returncode: | 265 | if self.runqemu.returncode: |
247 | # No point waiting any longer | 266 | # No point waiting any longer |
@@ -253,9 +272,51 @@ class QemuRunner: | |||
253 | time.sleep(0.5) | 272 | time.sleep(0.5) |
254 | 273 | ||
255 | if self.runqemu_exited: | 274 | if self.runqemu_exited: |
275 | self.logger.warning("runqemu after timeout") | ||
276 | return False | ||
277 | |||
278 | if self.runqemu.returncode: | ||
279 | self.logger.warning('runqemu exited with code %d' % self.runqemu.returncode) | ||
256 | return False | 280 | return False |
257 | 281 | ||
258 | if not self.is_alive(): | 282 | if not self.is_alive(): |
283 | self.logger.warning('is_alive() failed later') | ||
284 | return False | ||
285 | |||
286 | # Create the client socket for the QEMU Monitor Control Socket | ||
287 | # This will allow us to read status from Qemu if the the process | ||
288 | # is still alive | ||
289 | self.logger.debug("QMP Initializing to %s" % (qmp_port)) | ||
290 | try: | ||
291 | self.qmp = qmp.QEMUMonitorProtocol(qmp_port) | ||
292 | except OSError as msg: | ||
293 | self.logger.warning("Failed to initialize qemu monitor socket: %s File: %s" % (msg, msg.filename)) | ||
294 | return False | ||
295 | |||
296 | self.logger.debug("QMP Connecting to %s" % (qmp_port)) | ||
297 | if not os.path.exists(qmp_port) and self.is_alive(): | ||
298 | self.logger.debug("QMP Port does not exist waiting for it to be created") | ||
299 | endtime = time.time() + self.runqemutime | ||
300 | while not os.path.exists(qmp_port) and self.is_alive() and time.time() < endtime: | ||
301 | self.logger.warning("QMP port does not exist yet!") | ||
302 | time.sleep(0.5) | ||
303 | if not os.path.exists(qmp_port) and self.is_alive(): | ||
304 | self.logger.warning("QMP Port still does not exist but QEMU is alive") | ||
305 | return False | ||
306 | |||
307 | try: | ||
308 | self.qmp.connect() | ||
309 | except OSError as msg: | ||
310 | self.logger.warning("Failed to connect qemu monitor socket: %s File: %s" % (msg, msg.filename)) | ||
311 | return False | ||
312 | except qmp.QMPConnectError as msg: | ||
313 | self.logger.warning("Failed to communicate with qemu monitor: %s" % (msg)) | ||
314 | return False | ||
315 | |||
316 | # Release the qemu porcess to continue running | ||
317 | self.run_monitor('cont') | ||
318 | |||
319 | if not self.is_alive(): | ||
259 | self.logger.error("Qemu pid didn't appear in %s seconds (%s)" % | 320 | self.logger.error("Qemu pid didn't appear in %s seconds (%s)" % |
260 | (self.runqemutime, time.strftime("%D %H:%M:%S"))) | 321 | (self.runqemutime, time.strftime("%D %H:%M:%S"))) |
261 | 322 | ||
@@ -380,7 +441,6 @@ class QemuRunner: | |||
380 | sock.close() | 441 | sock.close() |
381 | stopread = True | 442 | stopread = True |
382 | 443 | ||
383 | |||
384 | if not reachedlogin: | 444 | if not reachedlogin: |
385 | if time.time() >= endtime: | 445 | if time.time() >= endtime: |
386 | self.logger.warning("Target didn't reach login banner in %d seconds (%s)" % | 446 | self.logger.warning("Target didn't reach login banner in %d seconds (%s)" % |
@@ -441,6 +501,9 @@ class QemuRunner: | |||
441 | self.runqemu.stdout.close() | 501 | self.runqemu.stdout.close() |
442 | self.runqemu_exited = True | 502 | self.runqemu_exited = True |
443 | 503 | ||
504 | if hasattr(self, 'qmp') and self.qmp: | ||
505 | self.qmp.close() | ||
506 | self.qmp = None | ||
444 | if hasattr(self, 'server_socket') and self.server_socket: | 507 | if hasattr(self, 'server_socket') and self.server_socket: |
445 | self.server_socket.close() | 508 | self.server_socket.close() |
446 | self.server_socket = None | 509 | self.server_socket = None |
@@ -499,6 +562,9 @@ class QemuRunner: | |||
499 | return True | 562 | return True |
500 | return False | 563 | return False |
501 | 564 | ||
565 | def run_monitor(self, command, timeout=60): | ||
566 | return self.qmp.cmd(command) | ||
567 | |||
502 | def run_serial(self, command, raw=False, timeout=60): | 568 | def run_serial(self, command, raw=False, timeout=60): |
503 | # We assume target system have echo to get command status | 569 | # We assume target system have echo to get command status |
504 | if not raw: | 570 | if not raw: |