xref: /openbmc/qemu/python/qemu/machine/machine.py (revision 7ae71462)
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            monitor_address = None
341            sock = None
342            if self._monitor_address is None:
343                self._sock_pair = socket.socketpair()
344                sock = self._sock_pair[1]
345            if isinstance(self._monitor_address, str):
346                self._remove_files.append(self._monitor_address)
347                monitor_address = self._monitor_address
348            self._qmp_connection = QEMUMonitorProtocol(
349                address=monitor_address,
350                sock=sock,
351                server=True,
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            self._qmp.accept(self._qmp_timer)
374
375    def _close_qemu_log_file(self) -> None:
376        if self._qemu_log_file is not None:
377            self._qemu_log_file.close()
378            self._qemu_log_file = None
379
380    def _post_shutdown(self) -> None:
381        """
382        Called to cleanup the VM instance after the process has exited.
383        May also be called after a failed launch.
384        """
385        LOG.debug("Cleaning up after VM process")
386        try:
387            self._close_qmp_connection()
388        except Exception as err:  # pylint: disable=broad-except
389            LOG.warning(
390                "Exception closing QMP connection: %s",
391                str(err) if str(err) else type(err).__name__
392            )
393        finally:
394            assert self._qmp_connection is None
395
396        self._close_qemu_log_file()
397
398        self._load_io_log()
399
400        self._qemu_log_path = None
401
402        if self._temp_dir is not None:
403            shutil.rmtree(self._temp_dir)
404            self._temp_dir = None
405
406        while len(self._remove_files) > 0:
407            self._remove_if_exists(self._remove_files.pop())
408
409        exitcode = self.exitcode()
410        if (exitcode is not None and exitcode < 0
411                and not (self._user_killed and exitcode == -signal.SIGKILL)):
412            msg = 'qemu received signal %i; command: "%s"'
413            if self._qemu_full_args:
414                command = ' '.join(self._qemu_full_args)
415            else:
416                command = ''
417            LOG.warning(msg, -int(exitcode), command)
418
419        self._quit_issued = False
420        self._user_killed = False
421        self._launched = False
422
423    def launch(self) -> None:
424        """
425        Launch the VM and make sure we cleanup and expose the
426        command line/output in case of exception
427        """
428
429        if self._launched:
430            raise QEMUMachineError('VM already launched')
431
432        try:
433            self._launch()
434        except BaseException as exc:
435            # We may have launched the process but it may
436            # have exited before we could connect via QMP.
437            # Assume the VM didn't launch or is exiting.
438            # If we don't wait for the process, exitcode() may still be
439            # 'None' by the time control is ceded back to the caller.
440            if self._launched:
441                self.wait()
442            else:
443                self._post_shutdown()
444
445            if isinstance(exc, Exception):
446                raise VMLaunchFailure(
447                    exitcode=self.exitcode(),
448                    command=' '.join(self._qemu_full_args),
449                    output=self._iolog
450                ) from exc
451
452            # Don't wrap 'BaseException'; doing so would downgrade
453            # that exception. However, we still want to clean up.
454            raise
455
456    def _launch(self) -> None:
457        """
458        Launch the VM and establish a QMP connection
459        """
460        self._pre_launch()
461        LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
462
463        # Cleaning up of this subprocess is guaranteed by _do_shutdown.
464        # pylint: disable=consider-using-with
465        self._popen = subprocess.Popen(self._qemu_full_args,
466                                       stdin=subprocess.DEVNULL,
467                                       stdout=self._qemu_log_file,
468                                       stderr=subprocess.STDOUT,
469                                       shell=False,
470                                       close_fds=False)
471        self._launched = True
472        self._post_launch()
473
474    def _close_qmp_connection(self) -> None:
475        """
476        Close the underlying QMP connection, if any.
477
478        Dutifully report errors that occurred while closing, but assume
479        that any error encountered indicates an abnormal termination
480        process and not a failure to close.
481        """
482        if self._qmp_connection is None:
483            return
484
485        try:
486            self._qmp.close()
487        except EOFError:
488            # EOF can occur as an Exception here when using the Async
489            # QMP backend. It indicates that the server closed the
490            # stream. If we successfully issued 'quit' at any point,
491            # then this was expected. If the remote went away without
492            # our permission, it's worth reporting that as an abnormal
493            # shutdown case.
494            if not (self._user_killed or self._quit_issued):
495                raise
496        finally:
497            self._qmp_connection = None
498
499    def _early_cleanup(self) -> None:
500        """
501        Perform any cleanup that needs to happen before the VM exits.
502
503        This method may be called twice upon shutdown, once each by soft
504        and hard shutdown in failover scenarios.
505        """
506        # If we keep the console socket open, we may deadlock waiting
507        # for QEMU to exit, while QEMU is waiting for the socket to
508        # become writable.
509        if self._console_socket is not None:
510            LOG.debug("Closing console socket")
511            self._console_socket.close()
512            self._console_socket = None
513
514    def _hard_shutdown(self) -> None:
515        """
516        Perform early cleanup, kill the VM, and wait for it to terminate.
517
518        :raise subprocess.Timeout: When timeout is exceeds 60 seconds
519            waiting for the QEMU process to terminate.
520        """
521        LOG.debug("Performing hard shutdown")
522        self._early_cleanup()
523        self._subp.kill()
524        self._subp.wait(timeout=60)
525
526    def _soft_shutdown(self, timeout: Optional[int]) -> None:
527        """
528        Perform early cleanup, attempt to gracefully shut down the VM, and wait
529        for it to terminate.
530
531        :param timeout: Timeout in seconds for graceful shutdown.
532                        A value of None is an infinite wait.
533
534        :raise ConnectionReset: On QMP communication errors
535        :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
536            the QEMU process to terminate.
537        """
538        LOG.debug("Attempting graceful termination")
539
540        self._early_cleanup()
541
542        if self._quit_issued:
543            LOG.debug(
544                "Anticipating QEMU termination due to prior 'quit' command, "
545                "or explicit call to wait()"
546            )
547        else:
548            LOG.debug("Politely asking QEMU to terminate")
549
550        if self._qmp_connection:
551            try:
552                if not self._quit_issued:
553                    # May raise ExecInterruptedError or StateError if the
554                    # connection dies or has *already* died.
555                    self.qmp('quit')
556            finally:
557                # Regardless, we want to quiesce the connection.
558                self._close_qmp_connection()
559        elif not self._quit_issued:
560            LOG.debug(
561                "Not anticipating QEMU quit and no QMP connection present, "
562                "issuing SIGTERM"
563            )
564            self._subp.terminate()
565
566        # May raise subprocess.TimeoutExpired
567        LOG.debug(
568            "Waiting (timeout=%s) for QEMU process (pid=%s) to terminate",
569            timeout, self._subp.pid
570        )
571        self._subp.wait(timeout=timeout)
572
573    def _do_shutdown(self, timeout: Optional[int]) -> None:
574        """
575        Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
576
577        :param timeout: Timeout in seconds for graceful shutdown.
578                        A value of None is an infinite wait.
579
580        :raise AbnormalShutdown: When the VM could not be shut down gracefully.
581            The inner exception will likely be ConnectionReset or
582            subprocess.TimeoutExpired. In rare cases, non-graceful termination
583            may result in its own exceptions, likely subprocess.TimeoutExpired.
584        """
585        try:
586            self._soft_shutdown(timeout)
587        except Exception as exc:
588            if isinstance(exc, subprocess.TimeoutExpired):
589                LOG.debug("Timed out waiting for QEMU process to exit")
590            LOG.debug("Graceful shutdown failed", exc_info=True)
591            LOG.debug("Falling back to hard shutdown")
592            self._hard_shutdown()
593            raise AbnormalShutdown("Could not perform graceful shutdown") \
594                from exc
595
596    def shutdown(self,
597                 hard: bool = False,
598                 timeout: Optional[int] = 30) -> None:
599        """
600        Terminate the VM (gracefully if possible) and perform cleanup.
601        Cleanup will always be performed.
602
603        If the VM has not yet been launched, or shutdown(), wait(), or kill()
604        have already been called, this method does nothing.
605
606        :param hard: When true, do not attempt graceful shutdown, and
607                     suppress the SIGKILL warning log message.
608        :param timeout: Optional timeout in seconds for graceful shutdown.
609                        Default 30 seconds, A `None` value is an infinite wait.
610        """
611        if not self._launched:
612            return
613
614        LOG.debug("Shutting down VM appliance; timeout=%s", timeout)
615        if hard:
616            LOG.debug("Caller requests immediate termination of QEMU process.")
617
618        try:
619            if hard:
620                self._user_killed = True
621                self._hard_shutdown()
622            else:
623                self._do_shutdown(timeout)
624        finally:
625            self._post_shutdown()
626
627    def kill(self) -> None:
628        """
629        Terminate the VM forcefully, wait for it to exit, and perform cleanup.
630        """
631        self.shutdown(hard=True)
632
633    def wait(self, timeout: Optional[int] = 30) -> None:
634        """
635        Wait for the VM to power off and perform post-shutdown cleanup.
636
637        :param timeout: Optional timeout in seconds. Default 30 seconds.
638                        A value of `None` is an infinite wait.
639        """
640        self._quit_issued = True
641        self.shutdown(timeout=timeout)
642
643    def set_qmp_monitor(self, enabled: bool = True) -> None:
644        """
645        Set the QMP monitor.
646
647        @param enabled: if False, qmp monitor options will be removed from
648                        the base arguments of the resulting QEMU command
649                        line. Default is True.
650
651        .. note:: Call this function before launch().
652        """
653        self._qmp_set = enabled
654
655    @property
656    def _qmp(self) -> QEMUMonitorProtocol:
657        if self._qmp_connection is None:
658            raise QEMUMachineError("Attempt to access QMP with no connection")
659        return self._qmp_connection
660
661    @classmethod
662    def _qmp_args(cls, conv_keys: bool,
663                  args: Dict[str, Any]) -> Dict[str, object]:
664        if conv_keys:
665            return {k.replace('_', '-'): v for k, v in args.items()}
666
667        return args
668
669    def qmp(self, cmd: str,
670            args_dict: Optional[Dict[str, object]] = None,
671            conv_keys: Optional[bool] = None,
672            **args: Any) -> QMPMessage:
673        """
674        Invoke a QMP command and return the response dict
675        """
676        if args_dict is not None:
677            assert not args
678            assert conv_keys is None
679            args = args_dict
680            conv_keys = False
681
682        if conv_keys is None:
683            conv_keys = True
684
685        qmp_args = self._qmp_args(conv_keys, args)
686        ret = self._qmp.cmd(cmd, args=qmp_args)
687        if cmd == 'quit' and 'error' not in ret and 'return' in ret:
688            self._quit_issued = True
689        return ret
690
691    def command(self, cmd: str,
692                conv_keys: bool = True,
693                **args: Any) -> QMPReturnValue:
694        """
695        Invoke a QMP command.
696        On success return the response dict.
697        On failure raise an exception.
698        """
699        qmp_args = self._qmp_args(conv_keys, args)
700        ret = self._qmp.command(cmd, **qmp_args)
701        if cmd == 'quit':
702            self._quit_issued = True
703        return ret
704
705    def get_qmp_event(self, wait: bool = False) -> Optional[QMPMessage]:
706        """
707        Poll for one queued QMP events and return it
708        """
709        if self._events:
710            return self._events.pop(0)
711        return self._qmp.pull_event(wait=wait)
712
713    def get_qmp_events(self, wait: bool = False) -> List[QMPMessage]:
714        """
715        Poll for queued QMP events and return a list of dicts
716        """
717        events = self._qmp.get_events(wait=wait)
718        events.extend(self._events)
719        del self._events[:]
720        return events
721
722    @staticmethod
723    def event_match(event: Any, match: Optional[Any]) -> bool:
724        """
725        Check if an event matches optional match criteria.
726
727        The match criteria takes the form of a matching subdict. The event is
728        checked to be a superset of the subdict, recursively, with matching
729        values whenever the subdict values are not None.
730
731        This has a limitation that you cannot explicitly check for None values.
732
733        Examples, with the subdict queries on the left:
734         - None matches any object.
735         - {"foo": None} matches {"foo": {"bar": 1}}
736         - {"foo": None} matches {"foo": 5}
737         - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
738         - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
739        """
740        if match is None:
741            return True
742
743        try:
744            for key in match:
745                if key in event:
746                    if not QEMUMachine.event_match(event[key], match[key]):
747                        return False
748                else:
749                    return False
750            return True
751        except TypeError:
752            # either match or event wasn't iterable (not a dict)
753            return bool(match == event)
754
755    def event_wait(self, name: str,
756                   timeout: float = 60.0,
757                   match: Optional[QMPMessage] = None) -> Optional[QMPMessage]:
758        """
759        event_wait waits for and returns a named event from QMP with a timeout.
760
761        name: The event to wait for.
762        timeout: QEMUMonitorProtocol.pull_event timeout parameter.
763        match: Optional match criteria. See event_match for details.
764        """
765        return self.events_wait([(name, match)], timeout)
766
767    def events_wait(self,
768                    events: Sequence[Tuple[str, Any]],
769                    timeout: float = 60.0) -> Optional[QMPMessage]:
770        """
771        events_wait waits for and returns a single named event from QMP.
772        In the case of multiple qualifying events, this function returns the
773        first one.
774
775        :param events: A sequence of (name, match_criteria) tuples.
776                       The match criteria are optional and may be None.
777                       See event_match for details.
778        :param timeout: Optional timeout, in seconds.
779                        See QEMUMonitorProtocol.pull_event.
780
781        :raise asyncio.TimeoutError:
782            If timeout was non-zero and no matching events were found.
783
784        :return: A QMP event matching the filter criteria.
785                 If timeout was 0 and no event matched, None.
786        """
787        def _match(event: QMPMessage) -> bool:
788            for name, match in events:
789                if event['event'] == name and self.event_match(event, match):
790                    return True
791            return False
792
793        event: Optional[QMPMessage]
794
795        # Search cached events
796        for event in self._events:
797            if _match(event):
798                self._events.remove(event)
799                return event
800
801        # Poll for new events
802        while True:
803            event = self._qmp.pull_event(wait=timeout)
804            if event is None:
805                # NB: None is only returned when timeout is false-ish.
806                # Timeouts raise asyncio.TimeoutError instead!
807                break
808            if _match(event):
809                return event
810            self._events.append(event)
811
812        return None
813
814    def get_log(self) -> Optional[str]:
815        """
816        After self.shutdown or failed qemu execution, this returns the output
817        of the qemu process.
818        """
819        return self._iolog
820
821    def add_args(self, *args: str) -> None:
822        """
823        Adds to the list of extra arguments to be given to the QEMU binary
824        """
825        self._args.extend(args)
826
827    def set_machine(self, machine_type: str) -> None:
828        """
829        Sets the machine type
830
831        If set, the machine type will be added to the base arguments
832        of the resulting QEMU command line.
833        """
834        self._machine = machine_type
835
836    def set_console(self,
837                    device_type: Optional[str] = None,
838                    console_index: int = 0) -> None:
839        """
840        Sets the device type for a console device
841
842        If set, the console device and a backing character device will
843        be added to the base arguments of the resulting QEMU command
844        line.
845
846        This is a convenience method that will either use the provided
847        device type, or default to a "-serial chardev:console" command
848        line argument.
849
850        The actual setting of command line arguments will be be done at
851        machine launch time, as it depends on the temporary directory
852        to be created.
853
854        @param device_type: the device type, such as "isa-serial".  If
855                            None is given (the default value) a "-serial
856                            chardev:console" command line argument will
857                            be used instead, resorting to the machine's
858                            default device type.
859        @param console_index: the index of the console device to use.
860                              If not zero, the command line will create
861                              'index - 1' consoles and connect them to
862                              the 'null' backing character device.
863        """
864        self._console_set = True
865        self._console_device_type = device_type
866        self._console_index = console_index
867
868    @property
869    def console_socket(self) -> socket.socket:
870        """
871        Returns a socket connected to the console
872        """
873        if self._console_socket is None:
874            self._console_socket = console_socket.ConsoleSocket(
875                self._console_address,
876                file=self._console_log_path,
877                drain=self._drain_console)
878        return self._console_socket
879
880    @property
881    def temp_dir(self) -> str:
882        """
883        Returns a temporary directory to be used for this machine
884        """
885        if self._temp_dir is None:
886            self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-",
887                                              dir=self._base_temp_dir)
888        return self._temp_dir
889
890    @property
891    def sock_dir(self) -> str:
892        """
893        Returns the directory used for sockfiles by this machine.
894        """
895        if self._sock_dir:
896            return self._sock_dir
897        return self.temp_dir
898
899    @property
900    def log_dir(self) -> str:
901        """
902        Returns a directory to be used for writing logs
903        """
904        if self._log_dir is None:
905            return self.temp_dir
906        return self._log_dir
907