blob: 80c4d4a8b6e7ef438afed6b351d7cbf2175790d3 [file] [log] [blame]
John Snow306dfcd2019-06-27 17:28:15 -04001"""
2QEMU machine module:
3
4The machine module primarily provides the QEMUMachine class,
5which provides facilities for managing the lifetime of a QEMU VM.
6"""
7
John Snowabf0bf92019-06-27 17:28:14 -04008# Copyright (C) 2015-2016 Red Hat Inc.
9# Copyright (C) 2012 IBM Corp.
10#
11# Authors:
12# Fam Zheng <famz@redhat.com>
13#
14# This work is licensed under the terms of the GNU GPL, version 2. See
15# the COPYING file in the top-level directory.
16#
17# Based on qmp.py.
18#
19
20import errno
21import logging
22import os
23import subprocess
John Snowabf0bf92019-06-27 17:28:14 -040024import shutil
John Snowde6e08b2020-07-10 01:06:48 -040025import signal
John Snowabf0bf92019-06-27 17:28:14 -040026import socket
27import tempfile
John Snow1dda0402020-05-14 01:53:44 -040028from typing import Optional, Type
29from types import TracebackType
Robert Foley0fc8f662020-07-01 14:56:24 +010030from qemu.console_socket import ConsoleSocket
John Snowabf0bf92019-06-27 17:28:14 -040031
32from . import qmp
33
34LOG = logging.getLogger(__name__)
35
John Snow8dfac2e2020-05-28 18:21:29 -040036
John Snowabf0bf92019-06-27 17:28:14 -040037class QEMUMachineError(Exception):
38 """
39 Exception called when an error in QEMUMachine happens.
40 """
41
42
43class QEMUMachineAddDeviceError(QEMUMachineError):
44 """
45 Exception raised when a request to add a device can not be fulfilled
46
47 The failures are caused by limitations, lack of information or conflicting
48 requests on the QEMUMachine methods. This exception does not represent
49 failures reported by the QEMU binary itself.
50 """
51
52
John Snow193bf1c2020-07-10 01:06:47 -040053class AbnormalShutdown(QEMUMachineError):
54 """
55 Exception raised when a graceful shutdown was requested, but not performed.
56 """
57
58
John Snow9b8ccd62020-05-28 18:21:28 -040059class QEMUMachine:
John Snowabf0bf92019-06-27 17:28:14 -040060 """
61 A QEMU VM
62
John Snow8dfac2e2020-05-28 18:21:29 -040063 Use this object as a context manager to ensure
64 the QEMU process terminates::
John Snowabf0bf92019-06-27 17:28:14 -040065
66 with VM(binary) as vm:
67 ...
68 # vm is guaranteed to be shut down here
69 """
70
71 def __init__(self, binary, args=None, wrapper=None, name=None,
72 test_dir="/var/tmp", monitor_address=None,
Robert Foley0fc8f662020-07-01 14:56:24 +010073 socket_scm_helper=None, sock_dir=None,
74 drain_console=False, console_log=None):
John Snowabf0bf92019-06-27 17:28:14 -040075 '''
76 Initialize a QEMUMachine
77
78 @param binary: path to the qemu binary
79 @param args: list of extra arguments
80 @param wrapper: list of arguments used as prefix to qemu binary
81 @param name: prefix for socket and log file names (default: qemu-PID)
82 @param test_dir: where to create socket and log file
83 @param monitor_address: address for QMP monitor
84 @param socket_scm_helper: helper program, required for send_fd_scm()
Robert Foley0fc8f662020-07-01 14:56:24 +010085 @param sock_dir: where to create socket (overrides test_dir for sock)
86 @param console_log: (optional) path to console log file
87 @param drain_console: (optional) True to drain console socket to buffer
John Snowabf0bf92019-06-27 17:28:14 -040088 @note: Qemu process is not started until launch() is used.
89 '''
90 if args is None:
91 args = []
92 if wrapper is None:
93 wrapper = []
94 if name is None:
95 name = "qemu-%d" % os.getpid()
Max Reitz32558ce2019-10-17 15:31:34 +020096 if sock_dir is None:
97 sock_dir = test_dir
John Snowabf0bf92019-06-27 17:28:14 -040098 self._name = name
99 self._monitor_address = monitor_address
100 self._vm_monitor = None
101 self._qemu_log_path = None
102 self._qemu_log_file = None
103 self._popen = None
104 self._binary = binary
105 self._args = list(args) # Force copy args in case we modify them
106 self._wrapper = wrapper
107 self._events = []
108 self._iolog = None
109 self._socket_scm_helper = socket_scm_helper
Wainer dos Santos Moschetta74b56bb2019-12-11 13:55:35 -0500110 self._qmp_set = True # Enable QMP monitor by default.
John Snowabf0bf92019-06-27 17:28:14 -0400111 self._qmp = None
112 self._qemu_full_args = None
113 self._test_dir = test_dir
114 self._temp_dir = None
Max Reitz32558ce2019-10-17 15:31:34 +0200115 self._sock_dir = sock_dir
John Snowabf0bf92019-06-27 17:28:14 -0400116 self._launched = False
117 self._machine = None
Philippe Mathieu-Daudé746f2442020-01-21 00:51:56 +0100118 self._console_index = 0
John Snowabf0bf92019-06-27 17:28:14 -0400119 self._console_set = False
120 self._console_device_type = None
121 self._console_address = None
122 self._console_socket = None
Max Reitz32558ce2019-10-17 15:31:34 +0200123 self._remove_files = []
John Snowde6e08b2020-07-10 01:06:48 -0400124 self._user_killed = False
Robert Foley0fc8f662020-07-01 14:56:24 +0100125 self._console_log_path = console_log
126 if self._console_log_path:
127 # In order to log the console, buffering needs to be enabled.
128 self._drain_console = True
129 else:
130 self._drain_console = drain_console
John Snowabf0bf92019-06-27 17:28:14 -0400131
John Snowabf0bf92019-06-27 17:28:14 -0400132 def __enter__(self):
133 return self
134
John Snow1dda0402020-05-14 01:53:44 -0400135 def __exit__(self,
136 exc_type: Optional[Type[BaseException]],
137 exc_val: Optional[BaseException],
138 exc_tb: Optional[TracebackType]) -> None:
John Snowabf0bf92019-06-27 17:28:14 -0400139 self.shutdown()
John Snowabf0bf92019-06-27 17:28:14 -0400140
John Snowabf0bf92019-06-27 17:28:14 -0400141 def add_monitor_null(self):
John Snow306dfcd2019-06-27 17:28:15 -0400142 """
143 This can be used to add an unused monitor instance.
144 """
John Snowabf0bf92019-06-27 17:28:14 -0400145 self._args.append('-monitor')
146 self._args.append('null')
147
148 def add_fd(self, fd, fdset, opaque, opts=''):
149 """
150 Pass a file descriptor to the VM
151 """
152 options = ['fd=%d' % fd,
153 'set=%d' % fdset,
154 'opaque=%s' % opaque]
155 if opts:
156 options.append(opts)
157
158 # This did not exist before 3.4, but since then it is
159 # mandatory for our purpose
160 if hasattr(os, 'set_inheritable'):
161 os.set_inheritable(fd, True)
162
163 self._args.append('-add-fd')
164 self._args.append(','.join(options))
165 return self
166
John Snowabf0bf92019-06-27 17:28:14 -0400167 def send_fd_scm(self, fd=None, file_path=None):
John Snow306dfcd2019-06-27 17:28:15 -0400168 """
169 Send an fd or file_path to socket_scm_helper.
170
171 Exactly one of fd and file_path must be given.
172 If it is file_path, the helper will open that file and pass its own fd.
173 """
John Snowabf0bf92019-06-27 17:28:14 -0400174 # In iotest.py, the qmp should always use unix socket.
175 assert self._qmp.is_scm_available()
176 if self._socket_scm_helper is None:
177 raise QEMUMachineError("No path to socket_scm_helper set")
178 if not os.path.exists(self._socket_scm_helper):
179 raise QEMUMachineError("%s does not exist" %
180 self._socket_scm_helper)
181
182 # This did not exist before 3.4, but since then it is
183 # mandatory for our purpose
184 if hasattr(os, 'set_inheritable'):
185 os.set_inheritable(self._qmp.get_sock_fd(), True)
186 if fd is not None:
187 os.set_inheritable(fd, True)
188
189 fd_param = ["%s" % self._socket_scm_helper,
190 "%d" % self._qmp.get_sock_fd()]
191
192 if file_path is not None:
193 assert fd is None
194 fd_param.append(file_path)
195 else:
196 assert fd is not None
197 fd_param.append(str(fd))
198
199 devnull = open(os.path.devnull, 'rb')
John Snow8dfac2e2020-05-28 18:21:29 -0400200 proc = subprocess.Popen(
201 fd_param, stdin=devnull, stdout=subprocess.PIPE,
202 stderr=subprocess.STDOUT, close_fds=False
203 )
John Snowabf0bf92019-06-27 17:28:14 -0400204 output = proc.communicate()[0]
205 if output:
206 LOG.debug(output)
207
208 return proc.returncode
209
210 @staticmethod
211 def _remove_if_exists(path):
212 """
213 Remove file object at path if it exists
214 """
215 try:
216 os.remove(path)
217 except OSError as exception:
218 if exception.errno == errno.ENOENT:
219 return
220 raise
221
222 def is_running(self):
John Snow306dfcd2019-06-27 17:28:15 -0400223 """Returns true if the VM is running."""
John Snowabf0bf92019-06-27 17:28:14 -0400224 return self._popen is not None and self._popen.poll() is None
225
226 def exitcode(self):
John Snow306dfcd2019-06-27 17:28:15 -0400227 """Returns the exit code if possible, or None."""
John Snowabf0bf92019-06-27 17:28:14 -0400228 if self._popen is None:
229 return None
230 return self._popen.poll()
231
232 def get_pid(self):
John Snow306dfcd2019-06-27 17:28:15 -0400233 """Returns the PID of the running process, or None."""
John Snowabf0bf92019-06-27 17:28:14 -0400234 if not self.is_running():
235 return None
236 return self._popen.pid
237
238 def _load_io_log(self):
239 if self._qemu_log_path is not None:
240 with open(self._qemu_log_path, "r") as iolog:
241 self._iolog = iolog.read()
242
243 def _base_args(self):
Wainer dos Santos Moschetta74b56bb2019-12-11 13:55:35 -0500244 args = ['-display', 'none', '-vga', 'none']
245 if self._qmp_set:
246 if isinstance(self._monitor_address, tuple):
247 moncdev = "socket,id=mon,host=%s,port=%s" % (
248 self._monitor_address[0],
249 self._monitor_address[1])
250 else:
251 moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
252 args.extend(['-chardev', moncdev, '-mon',
253 'chardev=mon,mode=control'])
John Snowabf0bf92019-06-27 17:28:14 -0400254 if self._machine is not None:
255 args.extend(['-machine', self._machine])
John Snow9b8ccd62020-05-28 18:21:28 -0400256 for _ in range(self._console_index):
Philippe Mathieu-Daudé746f2442020-01-21 00:51:56 +0100257 args.extend(['-serial', 'null'])
John Snowabf0bf92019-06-27 17:28:14 -0400258 if self._console_set:
Max Reitz32558ce2019-10-17 15:31:34 +0200259 self._console_address = os.path.join(self._sock_dir,
John Snowabf0bf92019-06-27 17:28:14 -0400260 self._name + "-console.sock")
Max Reitz32558ce2019-10-17 15:31:34 +0200261 self._remove_files.append(self._console_address)
John Snowabf0bf92019-06-27 17:28:14 -0400262 chardev = ('socket,id=console,path=%s,server,nowait' %
263 self._console_address)
264 args.extend(['-chardev', chardev])
265 if self._console_device_type is None:
266 args.extend(['-serial', 'chardev:console'])
267 else:
268 device = '%s,chardev=console' % self._console_device_type
269 args.extend(['-device', device])
270 return args
271
272 def _pre_launch(self):
273 self._temp_dir = tempfile.mkdtemp(dir=self._test_dir)
John Snowabf0bf92019-06-27 17:28:14 -0400274 self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
275 self._qemu_log_file = open(self._qemu_log_path, 'wb')
276
Wainer dos Santos Moschetta74b56bb2019-12-11 13:55:35 -0500277 if self._qmp_set:
278 if self._monitor_address is not None:
279 self._vm_monitor = self._monitor_address
280 else:
281 self._vm_monitor = os.path.join(self._sock_dir,
282 self._name + "-monitor.sock")
283 self._remove_files.append(self._vm_monitor)
Oksana Vohchana566054a2020-03-16 12:32:03 +0200284 self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True,
285 nickname=self._name)
John Snowabf0bf92019-06-27 17:28:14 -0400286
287 def _post_launch(self):
Wainer dos Santos Moschetta74b56bb2019-12-11 13:55:35 -0500288 if self._qmp:
289 self._qmp.accept()
John Snowabf0bf92019-06-27 17:28:14 -0400290
291 def _post_shutdown(self):
John Snowa3842cb2020-07-10 01:06:42 -0400292 """
293 Called to cleanup the VM instance after the process has exited.
294 May also be called after a failed launch.
295 """
296 # Comprehensive reset for the failed launch case:
297 self._early_cleanup()
298
John Snow671940e2020-07-10 01:06:39 -0400299 if self._qmp:
300 self._qmp.close()
301 self._qmp = None
302
John Snow14661d92020-07-10 01:06:38 -0400303 self._load_io_log()
304
John Snowabf0bf92019-06-27 17:28:14 -0400305 if self._qemu_log_file is not None:
306 self._qemu_log_file.close()
307 self._qemu_log_file = None
308
309 self._qemu_log_path = None
310
John Snowabf0bf92019-06-27 17:28:14 -0400311 if self._temp_dir is not None:
312 shutil.rmtree(self._temp_dir)
313 self._temp_dir = None
314
Max Reitz32558ce2019-10-17 15:31:34 +0200315 while len(self._remove_files) > 0:
316 self._remove_if_exists(self._remove_files.pop())
317
John Snow14661d92020-07-10 01:06:38 -0400318 exitcode = self.exitcode()
John Snowde6e08b2020-07-10 01:06:48 -0400319 if (exitcode is not None and exitcode < 0
320 and not (self._user_killed and exitcode == -signal.SIGKILL)):
John Snow14661d92020-07-10 01:06:38 -0400321 msg = 'qemu received signal %i; command: "%s"'
322 if self._qemu_full_args:
323 command = ' '.join(self._qemu_full_args)
324 else:
325 command = ''
326 LOG.warning(msg, -int(exitcode), command)
327
John Snowde6e08b2020-07-10 01:06:48 -0400328 self._user_killed = False
John Snow14661d92020-07-10 01:06:38 -0400329 self._launched = False
330
John Snowabf0bf92019-06-27 17:28:14 -0400331 def launch(self):
332 """
333 Launch the VM and make sure we cleanup and expose the
334 command line/output in case of exception
335 """
336
337 if self._launched:
338 raise QEMUMachineError('VM already launched')
339
340 self._iolog = None
341 self._qemu_full_args = None
342 try:
343 self._launch()
344 self._launched = True
345 except:
John Snowa3842cb2020-07-10 01:06:42 -0400346 self._post_shutdown()
John Snowabf0bf92019-06-27 17:28:14 -0400347
348 LOG.debug('Error launching VM')
349 if self._qemu_full_args:
350 LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
351 if self._iolog:
352 LOG.debug('Output: %r', self._iolog)
353 raise
354
355 def _launch(self):
356 """
357 Launch the VM and establish a QMP connection
358 """
359 devnull = open(os.path.devnull, 'rb')
360 self._pre_launch()
361 self._qemu_full_args = (self._wrapper + [self._binary] +
362 self._base_args() + self._args)
363 LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
364 self._popen = subprocess.Popen(self._qemu_full_args,
365 stdin=devnull,
366 stdout=self._qemu_log_file,
367 stderr=subprocess.STDOUT,
368 shell=False,
369 close_fds=False)
370 self._post_launch()
371
John Snowe2c97f12020-07-10 01:06:40 -0400372 def _early_cleanup(self) -> None:
373 """
374 Perform any cleanup that needs to happen before the VM exits.
John Snowa3842cb2020-07-10 01:06:42 -0400375
John Snow193bf1c2020-07-10 01:06:47 -0400376 May be invoked by both soft and hard shutdown in failover scenarios.
John Snowa3842cb2020-07-10 01:06:42 -0400377 Called additionally by _post_shutdown for comprehensive cleanup.
John Snowe2c97f12020-07-10 01:06:40 -0400378 """
379 # If we keep the console socket open, we may deadlock waiting
380 # for QEMU to exit, while QEMU is waiting for the socket to
381 # become writeable.
382 if self._console_socket is not None:
383 self._console_socket.close()
384 self._console_socket = None
385
John Snow193bf1c2020-07-10 01:06:47 -0400386 def _hard_shutdown(self) -> None:
387 """
388 Perform early cleanup, kill the VM, and wait for it to terminate.
389
390 :raise subprocess.Timeout: When timeout is exceeds 60 seconds
391 waiting for the QEMU process to terminate.
392 """
393 self._early_cleanup()
394 self._popen.kill()
395 self._popen.wait(timeout=60)
396
397 def _soft_shutdown(self, has_quit: bool = False,
398 timeout: Optional[int] = 3) -> None:
399 """
400 Perform early cleanup, attempt to gracefully shut down the VM, and wait
401 for it to terminate.
402
403 :param has_quit: When True, don't attempt to issue 'quit' QMP command
404 :param timeout: Optional timeout in seconds for graceful shutdown.
405 Default 3 seconds, A value of None is an infinite wait.
406
407 :raise ConnectionReset: On QMP communication errors
408 :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
409 the QEMU process to terminate.
410 """
411 self._early_cleanup()
412
413 if self._qmp is not None:
414 if not has_quit:
415 # Might raise ConnectionReset
416 self._qmp.cmd('quit')
417
418 # May raise subprocess.TimeoutExpired
419 self._popen.wait(timeout=timeout)
420
421 def _do_shutdown(self, has_quit: bool = False,
422 timeout: Optional[int] = 3) -> None:
423 """
424 Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
425
426 :param has_quit: When True, don't attempt to issue 'quit' QMP command
427 :param timeout: Optional timeout in seconds for graceful shutdown.
428 Default 3 seconds, A value of None is an infinite wait.
429
430 :raise AbnormalShutdown: When the VM could not be shut down gracefully.
431 The inner exception will likely be ConnectionReset or
432 subprocess.TimeoutExpired. In rare cases, non-graceful termination
433 may result in its own exceptions, likely subprocess.TimeoutExpired.
434 """
435 try:
436 self._soft_shutdown(has_quit, timeout)
437 except Exception as exc:
438 self._hard_shutdown()
439 raise AbnormalShutdown("Could not perform graceful shutdown") \
440 from exc
441
John Snowc9b30452020-07-10 01:06:43 -0400442 def shutdown(self, has_quit: bool = False,
443 hard: bool = False,
444 timeout: Optional[int] = 3) -> None:
John Snowabf0bf92019-06-27 17:28:14 -0400445 """
John Snow193bf1c2020-07-10 01:06:47 -0400446 Terminate the VM (gracefully if possible) and perform cleanup.
447 Cleanup will always be performed.
448
449 If the VM has not yet been launched, or shutdown(), wait(), or kill()
450 have already been called, this method does nothing.
451
452 :param has_quit: When true, do not attempt to issue 'quit' QMP command.
453 :param hard: When true, do not attempt graceful shutdown, and
454 suppress the SIGKILL warning log message.
455 :param timeout: Optional timeout in seconds for graceful shutdown.
456 Default 3 seconds, A value of None is an infinite wait.
John Snowabf0bf92019-06-27 17:28:14 -0400457 """
John Snowa3842cb2020-07-10 01:06:42 -0400458 if not self._launched:
459 return
460
John Snow193bf1c2020-07-10 01:06:47 -0400461 try:
Vladimir Sementsov-Ogievskiye0e925a2020-02-17 18:02:42 +0300462 if hard:
John Snowde6e08b2020-07-10 01:06:48 -0400463 self._user_killed = True
John Snow193bf1c2020-07-10 01:06:47 -0400464 self._hard_shutdown()
465 else:
466 self._do_shutdown(has_quit, timeout=timeout)
467 finally:
468 self._post_shutdown()
John Snowabf0bf92019-06-27 17:28:14 -0400469
Vladimir Sementsov-Ogievskiye0e925a2020-02-17 18:02:42 +0300470 def kill(self):
John Snow193bf1c2020-07-10 01:06:47 -0400471 """
472 Terminate the VM forcefully, wait for it to exit, and perform cleanup.
473 """
Vladimir Sementsov-Ogievskiye0e925a2020-02-17 18:02:42 +0300474 self.shutdown(hard=True)
475
John Snow04f0e362020-07-10 01:06:49 -0400476 def wait(self, timeout: Optional[int] = 3) -> None:
John Snow89528052020-07-10 01:06:44 -0400477 """
478 Wait for the VM to power off and perform post-shutdown cleanup.
479
480 :param timeout: Optional timeout in seconds.
John Snow04f0e362020-07-10 01:06:49 -0400481 Default 3 seconds, A value of None is an infinite wait.
John Snow89528052020-07-10 01:06:44 -0400482 """
483 self.shutdown(has_quit=True, timeout=timeout)
484
Wainer dos Santos Moschetta74b56bb2019-12-11 13:55:35 -0500485 def set_qmp_monitor(self, enabled=True):
486 """
487 Set the QMP monitor.
488
489 @param enabled: if False, qmp monitor options will be removed from
490 the base arguments of the resulting QEMU command
491 line. Default is True.
492 @note: call this function before launch().
493 """
494 if enabled:
495 self._qmp_set = True
496 else:
497 self._qmp_set = False
498 self._qmp = None
499
John Snowabf0bf92019-06-27 17:28:14 -0400500 def qmp(self, cmd, conv_keys=True, **args):
501 """
502 Invoke a QMP command and return the response dict
503 """
504 qmp_args = dict()
505 for key, value in args.items():
506 if conv_keys:
507 qmp_args[key.replace('_', '-')] = value
508 else:
509 qmp_args[key] = value
510
511 return self._qmp.cmd(cmd, args=qmp_args)
512
513 def command(self, cmd, conv_keys=True, **args):
514 """
515 Invoke a QMP command.
516 On success return the response dict.
517 On failure raise an exception.
518 """
519 reply = self.qmp(cmd, conv_keys, **args)
520 if reply is None:
521 raise qmp.QMPError("Monitor is closed")
522 if "error" in reply:
John Snowe3a23b42020-07-10 01:22:07 -0400523 raise qmp.QMPResponseError(reply)
John Snowabf0bf92019-06-27 17:28:14 -0400524 return reply["return"]
525
526 def get_qmp_event(self, wait=False):
527 """
528 Poll for one queued QMP events and return it
529 """
John Snow306dfcd2019-06-27 17:28:15 -0400530 if self._events:
John Snowabf0bf92019-06-27 17:28:14 -0400531 return self._events.pop(0)
532 return self._qmp.pull_event(wait=wait)
533
534 def get_qmp_events(self, wait=False):
535 """
536 Poll for queued QMP events and return a list of dicts
537 """
538 events = self._qmp.get_events(wait=wait)
539 events.extend(self._events)
540 del self._events[:]
541 self._qmp.clear_events()
542 return events
543
544 @staticmethod
545 def event_match(event, match=None):
546 """
547 Check if an event matches optional match criteria.
548
549 The match criteria takes the form of a matching subdict. The event is
550 checked to be a superset of the subdict, recursively, with matching
551 values whenever the subdict values are not None.
552
553 This has a limitation that you cannot explicitly check for None values.
554
555 Examples, with the subdict queries on the left:
556 - None matches any object.
557 - {"foo": None} matches {"foo": {"bar": 1}}
558 - {"foo": None} matches {"foo": 5}
559 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
560 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
561 """
562 if match is None:
563 return True
564
565 try:
566 for key in match:
567 if key in event:
568 if not QEMUMachine.event_match(event[key], match[key]):
569 return False
570 else:
571 return False
572 return True
573 except TypeError:
574 # either match or event wasn't iterable (not a dict)
575 return match == event
576
577 def event_wait(self, name, timeout=60.0, match=None):
578 """
579 event_wait waits for and returns a named event from QMP with a timeout.
580
581 name: The event to wait for.
582 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
583 match: Optional match criteria. See event_match for details.
584 """
585 return self.events_wait([(name, match)], timeout)
586
587 def events_wait(self, events, timeout=60.0):
588 """
John Snow8dfac2e2020-05-28 18:21:29 -0400589 events_wait waits for and returns a named event
590 from QMP with a timeout.
John Snowabf0bf92019-06-27 17:28:14 -0400591
592 events: a sequence of (name, match_criteria) tuples.
593 The match criteria are optional and may be None.
594 See event_match for details.
595 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
596 """
597 def _match(event):
598 for name, match in events:
John Snow306dfcd2019-06-27 17:28:15 -0400599 if event['event'] == name and self.event_match(event, match):
John Snowabf0bf92019-06-27 17:28:14 -0400600 return True
601 return False
602
603 # Search cached events
604 for event in self._events:
605 if _match(event):
606 self._events.remove(event)
607 return event
608
609 # Poll for new events
610 while True:
611 event = self._qmp.pull_event(wait=timeout)
612 if _match(event):
613 return event
614 self._events.append(event)
615
616 return None
617
618 def get_log(self):
619 """
620 After self.shutdown or failed qemu execution, this returns the output
621 of the qemu process.
622 """
623 return self._iolog
624
625 def add_args(self, *args):
626 """
627 Adds to the list of extra arguments to be given to the QEMU binary
628 """
629 self._args.extend(args)
630
631 def set_machine(self, machine_type):
632 """
633 Sets the machine type
634
635 If set, the machine type will be added to the base arguments
636 of the resulting QEMU command line.
637 """
638 self._machine = machine_type
639
Philippe Mathieu-Daudé746f2442020-01-21 00:51:56 +0100640 def set_console(self, device_type=None, console_index=0):
John Snowabf0bf92019-06-27 17:28:14 -0400641 """
642 Sets the device type for a console device
643
644 If set, the console device and a backing character device will
645 be added to the base arguments of the resulting QEMU command
646 line.
647
648 This is a convenience method that will either use the provided
649 device type, or default to a "-serial chardev:console" command
650 line argument.
651
652 The actual setting of command line arguments will be be done at
653 machine launch time, as it depends on the temporary directory
654 to be created.
655
656 @param device_type: the device type, such as "isa-serial". If
657 None is given (the default value) a "-serial
658 chardev:console" command line argument will
659 be used instead, resorting to the machine's
660 default device type.
Philippe Mathieu-Daudé746f2442020-01-21 00:51:56 +0100661 @param console_index: the index of the console device to use.
662 If not zero, the command line will create
663 'index - 1' consoles and connect them to
664 the 'null' backing character device.
John Snowabf0bf92019-06-27 17:28:14 -0400665 """
666 self._console_set = True
667 self._console_device_type = device_type
Philippe Mathieu-Daudé746f2442020-01-21 00:51:56 +0100668 self._console_index = console_index
John Snowabf0bf92019-06-27 17:28:14 -0400669
670 @property
671 def console_socket(self):
672 """
673 Returns a socket connected to the console
674 """
675 if self._console_socket is None:
Robert Foley0fc8f662020-07-01 14:56:24 +0100676 if self._drain_console:
677 self._console_socket = ConsoleSocket(self._console_address,
678 file=self._console_log_path)
679 else:
680 self._console_socket = socket.socket(socket.AF_UNIX,
681 socket.SOCK_STREAM)
682 self._console_socket.connect(self._console_address)
John Snowabf0bf92019-06-27 17:28:14 -0400683 return self._console_socket