xref: /openbmc/qemu/python/qemu/machine/machine.py (revision 89aafcf2)
1"""
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
8# 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
21from itertools import chain
22import locale
23import logging
24import os
25import shutil
26import signal
27import socket
28import subprocess
29import tempfile
30from types import TracebackType
31from typing import (
32    Any,
33    BinaryIO,
34    Dict,
35    List,
36    Optional,
37    Sequence,
38    Tuple,
39    Type,
40    TypeVar,
41)
42
43from qemu.qmp import SocketAddrT
44from qemu.qmp.legacy import (
45    QEMUMonitorProtocol,
46    QMPMessage,
47    QMPReturnValue,
48)
49
50from . import console_socket
51
52
53LOG = logging.getLogger(__name__)
54
55
56class QEMUMachineError(Exception):
57    """
58    Exception called when an error in QEMUMachine happens.
59    """
60
61
62class QEMUMachineAddDeviceError(QEMUMachineError):
63    """
64    Exception raised when a request to add a device can not be fulfilled
65
66    The failures are caused by limitations, lack of information or conflicting
67    requests on the QEMUMachine methods.  This exception does not represent
68    failures reported by the QEMU binary itself.
69    """
70
71
72class VMLaunchFailure(QEMUMachineError):
73    """
74    Exception raised when a VM launch was attempted, but failed.
75    """
76    def __init__(self, exitcode: Optional[int],
77                 command: str, output: Optional[str]):
78        super().__init__(exitcode, command, output)
79        self.exitcode = exitcode
80        self.command = command
81        self.output = output
82
83    def __str__(self) -> str:
84        ret = ''
85        if self.__cause__ is not None:
86            name = type(self.__cause__).__name__
87            reason = str(self.__cause__)
88            if reason:
89                ret += f"{name}: {reason}"
90            else:
91                ret += f"{name}"
92        ret += '\n'
93
94        if self.exitcode is not None:
95            ret += f"\tExit code: {self.exitcode}\n"
96        ret += f"\tCommand: {self.command}\n"
97        ret += f"\tOutput: {self.output}\n"
98        return ret
99
100
101class AbnormalShutdown(QEMUMachineError):
102    """
103    Exception raised when a graceful shutdown was requested, but not performed.
104    """
105
106
107_T = TypeVar('_T', bound='QEMUMachine')
108
109
110class QEMUMachine:
111    """
112    A QEMU VM.
113
114    Use this object as a context manager to ensure
115    the QEMU process terminates::
116
117        with VM(binary) as vm:
118            ...
119        # vm is guaranteed to be shut down here
120    """
121    # pylint: disable=too-many-instance-attributes, too-many-public-methods
122
123    def __init__(self,
124                 binary: str,
125                 args: Sequence[str] = (),
126                 wrapper: Sequence[str] = (),
127                 name: Optional[str] = None,
128                 base_temp_dir: str = "/var/tmp",
129                 monitor_address: Optional[SocketAddrT] = None,
130                 sock_dir: Optional[str] = None,
131                 drain_console: bool = False,
132                 console_log: Optional[str] = None,
133                 log_dir: Optional[str] = None,
134                 qmp_timer: Optional[float] = 30):
135        '''
136        Initialize a QEMUMachine
137
138        @param binary: path to the qemu binary
139        @param args: list of extra arguments
140        @param wrapper: list of arguments used as prefix to qemu binary
141        @param name: prefix for socket and log file names (default: qemu-PID)
142        @param base_temp_dir: default location where temp files are created
143        @param monitor_address: address for QMP monitor
144        @param sock_dir: where to create socket (defaults to base_temp_dir)
145        @param drain_console: (optional) True to drain console socket to buffer
146        @param console_log: (optional) path to console log file
147        @param log_dir: where to create and keep log files
148        @param qmp_timer: (optional) default QMP socket timeout
149        @note: Qemu process is not started until launch() is used.
150        '''
151        # pylint: disable=too-many-arguments
152
153        # Direct user configuration
154
155        self._binary = binary
156        self._args = list(args)
157        self._wrapper = wrapper
158        self._qmp_timer = qmp_timer
159
160        self._name = name or f"{id(self):x}"
161        self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None
162        self._temp_dir: Optional[str] = None
163        self._base_temp_dir = base_temp_dir
164        self._sock_dir = sock_dir
165        self._log_dir = log_dir
166
167        self._monitor_address = monitor_address
168
169        self._console_log_path = console_log
170        if self._console_log_path:
171            # In order to log the console, buffering needs to be enabled.
172            self._drain_console = True
173        else:
174            self._drain_console = drain_console
175
176        # Runstate
177        self._qemu_log_path: Optional[str] = None
178        self._qemu_log_file: Optional[BinaryIO] = None
179        self._popen: Optional['subprocess.Popen[bytes]'] = None
180        self._events: List[QMPMessage] = []
181        self._iolog: Optional[str] = None
182        self._qmp_set = True   # Enable QMP monitor by default.
183        self._qmp_connection: Optional[QEMUMonitorProtocol] = None
184        self._qemu_full_args: Tuple[str, ...] = ()
185        self._launched = False
186        self._machine: Optional[str] = None
187        self._console_index = 0
188        self._console_set = False
189        self._console_device_type: Optional[str] = None
190        self._console_address = os.path.join(
191            self.sock_dir, f"{self._name}.con"
192        )
193        self._console_socket: Optional[socket.socket] = None
194        self._remove_files: List[str] = []
195        self._user_killed = False
196        self._quit_issued = False
197
198    def __enter__(self: _T) -> _T:
199        return self
200
201    def __exit__(self,
202                 exc_type: Optional[Type[BaseException]],
203                 exc_val: Optional[BaseException],
204                 exc_tb: Optional[TracebackType]) -> None:
205        self.shutdown()
206
207    def add_monitor_null(self) -> None:
208        """
209        This can be used to add an unused monitor instance.
210        """
211        self._args.append('-monitor')
212        self._args.append('null')
213
214    def add_fd(self: _T, fd: int, fdset: int,
215               opaque: str, opts: str = '') -> _T:
216        """
217        Pass a file descriptor to the VM
218        """
219        options = ['fd=%d' % fd,
220                   'set=%d' % fdset,
221                   'opaque=%s' % opaque]
222        if opts:
223            options.append(opts)
224
225        # This did not exist before 3.4, but since then it is
226        # mandatory for our purpose
227        if hasattr(os, 'set_inheritable'):
228            os.set_inheritable(fd, True)
229
230        self._args.append('-add-fd')
231        self._args.append(','.join(options))
232        return self
233
234    def send_fd_scm(self, fd: Optional[int] = None,
235                    file_path: Optional[str] = None) -> int:
236        """
237        Send an fd or file_path to the remote via SCM_RIGHTS.
238
239        Exactly one of fd and file_path must be given.  If it is
240        file_path, the file will be opened read-only and the new file
241        descriptor will be sent to the remote.
242        """
243        if file_path is not None:
244            assert fd is None
245            with open(file_path, "rb") as passfile:
246                fd = passfile.fileno()
247                self._qmp.send_fd_scm(fd)
248        else:
249            assert fd is not None
250            self._qmp.send_fd_scm(fd)
251
252        return 0
253
254    @staticmethod
255    def _remove_if_exists(path: str) -> None:
256        """
257        Remove file object at path if it exists
258        """
259        try:
260            os.remove(path)
261        except OSError as exception:
262            if exception.errno == errno.ENOENT:
263                return
264            raise
265
266    def is_running(self) -> bool:
267        """Returns true if the VM is running."""
268        return self._popen is not None and self._popen.poll() is None
269
270    @property
271    def _subp(self) -> 'subprocess.Popen[bytes]':
272        if self._popen is None:
273            raise QEMUMachineError('Subprocess pipe not present')
274        return self._popen
275
276    def exitcode(self) -> Optional[int]:
277        """Returns the exit code if possible, or None."""
278        if self._popen is None:
279            return None
280        return self._popen.poll()
281
282    def get_pid(self) -> Optional[int]:
283        """Returns the PID of the running process, or None."""
284        if not self.is_running():
285            return None
286        return self._subp.pid
287
288    def _load_io_log(self) -> None:
289        # Assume that the output encoding of QEMU's terminal output is
290        # defined by our locale. If indeterminate, allow open() to fall
291        # back to the platform default.
292        _, encoding = locale.getlocale()
293        if self._qemu_log_path is not None:
294            with open(self._qemu_log_path, "r", encoding=encoding) as iolog:
295                self._iolog = iolog.read()
296
297    @property
298    def _base_args(self) -> List[str]:
299        args = ['-display', 'none', '-vga', 'none']
300
301        if self._qmp_set:
302            if self._sock_pair:
303                fd = self._sock_pair[0].fileno()
304                os.set_inheritable(fd, True)
305                moncdev = f"socket,id=mon,fd={fd}"
306            elif isinstance(self._monitor_address, tuple):
307                moncdev = "socket,id=mon,host={},port={}".format(
308                    *self._monitor_address
309                )
310            else:
311                moncdev = f"socket,id=mon,path={self._monitor_address}"
312            args.extend(['-chardev', moncdev, '-mon',
313                         'chardev=mon,mode=control'])
314
315        if self._machine is not None:
316            args.extend(['-machine', self._machine])
317        for _ in range(self._console_index):
318            args.extend(['-serial', 'null'])
319        if self._console_set:
320            chardev = ('socket,id=console,path=%s,server=on,wait=off' %
321                       self._console_address)
322            args.extend(['-chardev', chardev])
323            if self._console_device_type is None:
324                args.extend(['-serial', 'chardev:console'])
325            else:
326                device = '%s,chardev=console' % self._console_device_type
327                args.extend(['-device', device])
328        return args
329
330    @property
331    def args(self) -> List[str]:
332        """Returns the list of arguments given to the QEMU binary."""
333        return self._args
334
335    def _pre_launch(self) -> None:
336        if self._console_set:
337            self._remove_files.append(self._console_address)
338
339        if self._qmp_set:
340            if self._monitor_address is None:
341                self._sock_pair = socket.socketpair()
342                sock = self._sock_pair[1]
343            if isinstance(self._monitor_address, str):
344                self._remove_files.append(self._monitor_address)
345
346            sock_or_addr = self._monitor_address or sock
347            assert sock_or_addr is not None
348
349            self._qmp_connection = QEMUMonitorProtocol(
350                sock_or_addr,
351                server=bool(self._monitor_address),
352                nickname=self._name
353            )
354
355        # NOTE: Make sure any opened resources are *definitely* freed in
356        # _post_shutdown()!
357        # pylint: disable=consider-using-with
358        self._qemu_log_path = os.path.join(self.log_dir, self._name + ".log")
359        self._qemu_log_file = open(self._qemu_log_path, 'wb')
360
361        self._iolog = None
362        self._qemu_full_args = tuple(chain(
363            self._wrapper,
364            [self._binary],
365            self._base_args,
366            self._args
367        ))
368
369    def _post_launch(self) -> None:
370        if self._sock_pair:
371            self._sock_pair[0].close()
372        if self._qmp_connection:
373            if self._sock_pair:
374                self._qmp.connect()
375            else:
376                self._qmp.accept(self._qmp_timer)
377
378    def _close_qemu_log_file(self) -> None:
379        if self._qemu_log_file is not None:
380            self._qemu_log_file.close()
381            self._qemu_log_file = None
382
383    def _post_shutdown(self) -> None:
384        """
385        Called to cleanup the VM instance after the process has exited.
386        May also be called after a failed launch.
387        """
388        LOG.debug("Cleaning up after VM process")
389        try:
390            self._close_qmp_connection()
391        except Exception as err:  # pylint: disable=broad-except
392            LOG.warning(
393                "Exception closing QMP connection: %s",
394                str(err) if str(err) else type(err).__name__
395            )
396        finally:
397            assert self._qmp_connection is None
398
399        self._close_qemu_log_file()
400
401        self._load_io_log()
402
403        self._qemu_log_path = None
404
405        if self._temp_dir is not None:
406            shutil.rmtree(self._temp_dir)
407            self._temp_dir = None
408
409        while len(self._remove_files) > 0:
410            self._remove_if_exists(self._remove_files.pop())
411
412        exitcode = self.exitcode()
413        if (exitcode is not None and exitcode < 0
414                and not (self._user_killed and exitcode == -signal.SIGKILL)):
415            msg = 'qemu received signal %i; command: "%s"'
416            if self._qemu_full_args:
417                command = ' '.join(self._qemu_full_args)
418            else:
419                command = ''
420            LOG.warning(msg, -int(exitcode), command)
421
422        self._quit_issued = False
423        self._user_killed = False
424        self._launched = False
425
426    def launch(self) -> None:
427        """
428        Launch the VM and make sure we cleanup and expose the
429        command line/output in case of exception
430        """
431
432        if self._launched:
433            raise QEMUMachineError('VM already launched')
434
435        try:
436            self._launch()
437        except BaseException as exc:
438            # We may have launched the process but it may
439            # have exited before we could connect via QMP.
440            # Assume the VM didn't launch or is exiting.
441            # If we don't wait for the process, exitcode() may still be
442            # 'None' by the time control is ceded back to the caller.
443            if self._launched:
444                self.wait()
445            else:
446                self._post_shutdown()
447
448            if isinstance(exc, Exception):
449                raise VMLaunchFailure(
450                    exitcode=self.exitcode(),
451                    command=' '.join(self._qemu_full_args),
452                    output=self._iolog
453                ) from exc
454
455            # Don't wrap 'BaseException'; doing so would downgrade
456            # that exception. However, we still want to clean up.
457            raise
458
459    def _launch(self) -> None:
460        """
461        Launch the VM and establish a QMP connection
462        """
463        self._pre_launch()
464        LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
465
466        # Cleaning up of this subprocess is guaranteed by _do_shutdown.
467        # pylint: disable=consider-using-with
468        self._popen = subprocess.Popen(self._qemu_full_args,
469                                       stdin=subprocess.DEVNULL,
470                                       stdout=self._qemu_log_file,
471                                       stderr=subprocess.STDOUT,
472                                       shell=False,
473                                       close_fds=False)
474        self._launched = True
475        self._post_launch()
476
477    def _close_qmp_connection(self) -> None:
478        """
479        Close the underlying QMP connection, if any.
480
481        Dutifully report errors that occurred while closing, but assume
482        that any error encountered indicates an abnormal termination
483        process and not a failure to close.
484        """
485        if self._qmp_connection is None:
486            return
487
488        try:
489            self._qmp.close()
490        except EOFError:
491            # EOF can occur as an Exception here when using the Async
492            # QMP backend. It indicates that the server closed the
493            # stream. If we successfully issued 'quit' at any point,
494            # then this was expected. If the remote went away without
495            # our permission, it's worth reporting that as an abnormal
496            # shutdown case.
497            if not (self._user_killed or self._quit_issued):
498                raise
499        finally:
500            self._qmp_connection = None
501
502    def _early_cleanup(self) -> None:
503        """
504        Perform any cleanup that needs to happen before the VM exits.
505
506        This method may be called twice upon shutdown, once each by soft
507        and hard shutdown in failover scenarios.
508        """
509        # If we keep the console socket open, we may deadlock waiting
510        # for QEMU to exit, while QEMU is waiting for the socket to
511        # become writable.
512        if self._console_socket is not None:
513            LOG.debug("Closing console socket")
514            self._console_socket.close()
515            self._console_socket = None
516
517    def _hard_shutdown(self) -> None:
518        """
519        Perform early cleanup, kill the VM, and wait for it to terminate.
520
521        :raise subprocess.Timeout: When timeout is exceeds 60 seconds
522            waiting for the QEMU process to terminate.
523        """
524        LOG.debug("Performing hard shutdown")
525        self._early_cleanup()
526        self._subp.kill()
527        self._subp.wait(timeout=60)
528
529    def _soft_shutdown(self, timeout: Optional[int]) -> None:
530        """
531        Perform early cleanup, attempt to gracefully shut down the VM, and wait
532        for it to terminate.
533
534        :param timeout: Timeout in seconds for graceful shutdown.
535                        A value of None is an infinite wait.
536
537        :raise ConnectionReset: On QMP communication errors
538        :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
539            the QEMU process to terminate.
540        """
541        LOG.debug("Attempting graceful termination")
542
543        self._early_cleanup()
544
545        if self._quit_issued:
546            LOG.debug(
547                "Anticipating QEMU termination due to prior 'quit' command, "
548                "or explicit call to wait()"
549            )
550        else:
551            LOG.debug("Politely asking QEMU to terminate")
552
553        if self._qmp_connection:
554            try:
555                if not self._quit_issued:
556                    # May raise ExecInterruptedError or StateError if the
557                    # connection dies or has *already* died.
558                    self.qmp('quit')
559            finally:
560                # Regardless, we want to quiesce the connection.
561                self._close_qmp_connection()
562        elif not self._quit_issued:
563            LOG.debug(
564                "Not anticipating QEMU quit and no QMP connection present, "
565                "issuing SIGTERM"
566            )
567            self._subp.terminate()
568
569        # May raise subprocess.TimeoutExpired
570        LOG.debug(
571            "Waiting (timeout=%s) for QEMU process (pid=%s) to terminate",
572            timeout, self._subp.pid
573        )
574        self._subp.wait(timeout=timeout)
575
576    def _do_shutdown(self, timeout: Optional[int]) -> None:
577        """
578        Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
579
580        :param timeout: Timeout in seconds for graceful shutdown.
581                        A value of None is an infinite wait.
582
583        :raise AbnormalShutdown: When the VM could not be shut down gracefully.
584            The inner exception will likely be ConnectionReset or
585            subprocess.TimeoutExpired. In rare cases, non-graceful termination
586            may result in its own exceptions, likely subprocess.TimeoutExpired.
587        """
588        try:
589            self._soft_shutdown(timeout)
590        except Exception as exc:
591            if isinstance(exc, subprocess.TimeoutExpired):
592                LOG.debug("Timed out waiting for QEMU process to exit")
593            LOG.debug("Graceful shutdown failed", exc_info=True)
594            LOG.debug("Falling back to hard shutdown")
595            self._hard_shutdown()
596            raise AbnormalShutdown("Could not perform graceful shutdown") \
597                from exc
598
599    def shutdown(self,
600                 hard: bool = False,
601                 timeout: Optional[int] = 30) -> None:
602        """
603        Terminate the VM (gracefully if possible) and perform cleanup.
604        Cleanup will always be performed.
605
606        If the VM has not yet been launched, or shutdown(), wait(), or kill()
607        have already been called, this method does nothing.
608
609        :param hard: When true, do not attempt graceful shutdown, and
610                     suppress the SIGKILL warning log message.
611        :param timeout: Optional timeout in seconds for graceful shutdown.
612                        Default 30 seconds, A `None` value is an infinite wait.
613        """
614        if not self._launched:
615            return
616
617        LOG.debug("Shutting down VM appliance; timeout=%s", timeout)
618        if hard:
619            LOG.debug("Caller requests immediate termination of QEMU process.")
620
621        try:
622            if hard:
623                self._user_killed = True
624                self._hard_shutdown()
625            else:
626                self._do_shutdown(timeout)
627        finally:
628            self._post_shutdown()
629
630    def kill(self) -> None:
631        """
632        Terminate the VM forcefully, wait for it to exit, and perform cleanup.
633        """
634        self.shutdown(hard=True)
635
636    def wait(self, timeout: Optional[int] = 30) -> None:
637        """
638        Wait for the VM to power off and perform post-shutdown cleanup.
639
640        :param timeout: Optional timeout in seconds. Default 30 seconds.
641                        A value of `None` is an infinite wait.
642        """
643        self._quit_issued = True
644        self.shutdown(timeout=timeout)
645
646    def set_qmp_monitor(self, enabled: bool = True) -> None:
647        """
648        Set the QMP monitor.
649
650        @param enabled: if False, qmp monitor options will be removed from
651                        the base arguments of the resulting QEMU command
652                        line. Default is True.
653
654        .. note:: Call this function before launch().
655        """
656        self._qmp_set = enabled
657
658    @property
659    def _qmp(self) -> QEMUMonitorProtocol:
660        if self._qmp_connection is None:
661            raise QEMUMachineError("Attempt to access QMP with no connection")
662        return self._qmp_connection
663
664    @classmethod
665    def _qmp_args(cls, conv_keys: bool,
666                  args: Dict[str, Any]) -> Dict[str, object]:
667        if conv_keys:
668            return {k.replace('_', '-'): v for k, v in args.items()}
669
670        return args
671
672    def qmp(self, cmd: str,
673            args_dict: Optional[Dict[str, object]] = None,
674            conv_keys: Optional[bool] = None,
675            **args: Any) -> QMPMessage:
676        """
677        Invoke a QMP command and return the response dict
678        """
679        if args_dict is not None:
680            assert not args
681            assert conv_keys is None
682            args = args_dict
683            conv_keys = False
684
685        if conv_keys is None:
686            conv_keys = True
687
688        qmp_args = self._qmp_args(conv_keys, args)
689        ret = self._qmp.cmd(cmd, args=qmp_args)
690        if cmd == 'quit' and 'error' not in ret and 'return' in ret:
691            self._quit_issued = True
692        return ret
693
694    def command(self, cmd: str,
695                conv_keys: bool = True,
696                **args: Any) -> QMPReturnValue:
697        """
698        Invoke a QMP command.
699        On success return the response dict.
700        On failure raise an exception.
701        """
702        qmp_args = self._qmp_args(conv_keys, args)
703        ret = self._qmp.command(cmd, **qmp_args)
704        if cmd == 'quit':
705            self._quit_issued = True
706        return ret
707
708    def get_qmp_event(self, wait: bool = False) -> Optional[QMPMessage]:
709        """
710        Poll for one queued QMP events and return it
711        """
712        if self._events:
713            return self._events.pop(0)
714        return self._qmp.pull_event(wait=wait)
715
716    def get_qmp_events(self, wait: bool = False) -> List[QMPMessage]:
717        """
718        Poll for queued QMP events and return a list of dicts
719        """
720        events = self._qmp.get_events(wait=wait)
721        events.extend(self._events)
722        del self._events[:]
723        return events
724
725    @staticmethod
726    def event_match(event: Any, match: Optional[Any]) -> bool:
727        """
728        Check if an event matches optional match criteria.
729
730        The match criteria takes the form of a matching subdict. The event is
731        checked to be a superset of the subdict, recursively, with matching
732        values whenever the subdict values are not None.
733
734        This has a limitation that you cannot explicitly check for None values.
735
736        Examples, with the subdict queries on the left:
737         - None matches any object.
738         - {"foo": None} matches {"foo": {"bar": 1}}
739         - {"foo": None} matches {"foo": 5}
740         - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
741         - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
742        """
743        if match is None:
744            return True
745
746        try:
747            for key in match:
748                if key in event:
749                    if not QEMUMachine.event_match(event[key], match[key]):
750                        return False
751                else:
752                    return False
753            return True
754        except TypeError:
755            # either match or event wasn't iterable (not a dict)
756            return bool(match == event)
757
758    def event_wait(self, name: str,
759                   timeout: float = 60.0,
760                   match: Optional[QMPMessage] = None) -> Optional[QMPMessage]:
761        """
762        event_wait waits for and returns a named event from QMP with a timeout.
763
764        name: The event to wait for.
765        timeout: QEMUMonitorProtocol.pull_event timeout parameter.
766        match: Optional match criteria. See event_match for details.
767        """
768        return self.events_wait([(name, match)], timeout)
769
770    def events_wait(self,
771                    events: Sequence[Tuple[str, Any]],
772                    timeout: float = 60.0) -> Optional[QMPMessage]:
773        """
774        events_wait waits for and returns a single named event from QMP.
775        In the case of multiple qualifying events, this function returns the
776        first one.
777
778        :param events: A sequence of (name, match_criteria) tuples.
779                       The match criteria are optional and may be None.
780                       See event_match for details.
781        :param timeout: Optional timeout, in seconds.
782                        See QEMUMonitorProtocol.pull_event.
783
784        :raise asyncio.TimeoutError:
785            If timeout was non-zero and no matching events were found.
786
787        :return: A QMP event matching the filter criteria.
788                 If timeout was 0 and no event matched, None.
789        """
790        def _match(event: QMPMessage) -> bool:
791            for name, match in events:
792                if event['event'] == name and self.event_match(event, match):
793                    return True
794            return False
795
796        event: Optional[QMPMessage]
797
798        # Search cached events
799        for event in self._events:
800            if _match(event):
801                self._events.remove(event)
802                return event
803
804        # Poll for new events
805        while True:
806            event = self._qmp.pull_event(wait=timeout)
807            if event is None:
808                # NB: None is only returned when timeout is false-ish.
809                # Timeouts raise asyncio.TimeoutError instead!
810                break
811            if _match(event):
812                return event
813            self._events.append(event)
814
815        return None
816
817    def get_log(self) -> Optional[str]:
818        """
819        After self.shutdown or failed qemu execution, this returns the output
820        of the qemu process.
821        """
822        return self._iolog
823
824    def add_args(self, *args: str) -> None:
825        """
826        Adds to the list of extra arguments to be given to the QEMU binary
827        """
828        self._args.extend(args)
829
830    def set_machine(self, machine_type: str) -> None:
831        """
832        Sets the machine type
833
834        If set, the machine type will be added to the base arguments
835        of the resulting QEMU command line.
836        """
837        self._machine = machine_type
838
839    def set_console(self,
840                    device_type: Optional[str] = None,
841                    console_index: int = 0) -> None:
842        """
843        Sets the device type for a console device
844
845        If set, the console device and a backing character device will
846        be added to the base arguments of the resulting QEMU command
847        line.
848
849        This is a convenience method that will either use the provided
850        device type, or default to a "-serial chardev:console" command
851        line argument.
852
853        The actual setting of command line arguments will be be done at
854        machine launch time, as it depends on the temporary directory
855        to be created.
856
857        @param device_type: the device type, such as "isa-serial".  If
858                            None is given (the default value) a "-serial
859                            chardev:console" command line argument will
860                            be used instead, resorting to the machine's
861                            default device type.
862        @param console_index: the index of the console device to use.
863                              If not zero, the command line will create
864                              'index - 1' consoles and connect them to
865                              the 'null' backing character device.
866        """
867        self._console_set = True
868        self._console_device_type = device_type
869        self._console_index = console_index
870
871    @property
872    def console_socket(self) -> socket.socket:
873        """
874        Returns a socket connected to the console
875        """
876        if self._console_socket is None:
877            self._console_socket = console_socket.ConsoleSocket(
878                self._console_address,
879                file=self._console_log_path,
880                drain=self._drain_console)
881        return self._console_socket
882
883    @property
884    def temp_dir(self) -> str:
885        """
886        Returns a temporary directory to be used for this machine
887        """
888        if self._temp_dir is None:
889            self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-",
890                                              dir=self._base_temp_dir)
891        return self._temp_dir
892
893    @property
894    def sock_dir(self) -> str:
895        """
896        Returns the directory used for sockfiles by this machine.
897        """
898        if self._sock_dir:
899            return self._sock_dir
900        return self.temp_dir
901
902    @property
903    def log_dir(self) -> str:
904        """
905        Returns a directory to be used for writing logs
906        """
907        if self._log_dir is None:
908            return self.temp_dir
909        return self._log_dir
910