4 The machine module primarily provides the QEMUMachine class,
5 which provides facilities for managing the lifetime of a QEMU VM.
8 # Copyright (C) 2015-2016 Red Hat Inc.
9 # Copyright (C) 2012 IBM Corp.
14 # This work is licensed under the terms of the GNU GPL, version 2. See
15 # the COPYING file in the top-level directory.
21 from itertools import chain
30 from types import TracebackType
43 from qemu.qmp import ( # pylint: disable=import-error
49 from . import console_socket
52 if os.environ.get('QEMU_PYTHON_LEGACY_QMP'):
53 from qemu.qmp import QEMUMonitorProtocol
55 from qemu.aqmp.legacy import QEMUMonitorProtocol
58 LOG = logging.getLogger(__name__)
61 class QEMUMachineError(Exception):
63 Exception called when an error in QEMUMachine happens.
67 class QEMUMachineAddDeviceError(QEMUMachineError):
69 Exception raised when a request to add a device can not be fulfilled
71 The failures are caused by limitations, lack of information or conflicting
72 requests on the QEMUMachine methods. This exception does not represent
73 failures reported by the QEMU binary itself.
77 class AbnormalShutdown(QEMUMachineError):
79 Exception raised when a graceful shutdown was requested, but not performed.
83 _T = TypeVar('_T', bound='QEMUMachine')
90 Use this object as a context manager to ensure
91 the QEMU process terminates::
93 with VM(binary) as vm:
95 # vm is guaranteed to be shut down here
97 # pylint: disable=too-many-instance-attributes, too-many-public-methods
101 args: Sequence[str] = (),
102 wrapper: Sequence[str] = (),
103 name: Optional[str] = None,
104 base_temp_dir: str = "/var/tmp",
105 monitor_address: Optional[SocketAddrT] = None,
106 sock_dir: Optional[str] = None,
107 drain_console: bool = False,
108 console_log: Optional[str] = None,
109 log_dir: Optional[str] = None,
110 qmp_timer: Optional[float] = None):
112 Initialize a QEMUMachine
114 @param binary: path to the qemu binary
115 @param args: list of extra arguments
116 @param wrapper: list of arguments used as prefix to qemu binary
117 @param name: prefix for socket and log file names (default: qemu-PID)
118 @param base_temp_dir: default location where temp files are created
119 @param monitor_address: address for QMP monitor
120 @param sock_dir: where to create socket (defaults to base_temp_dir)
121 @param drain_console: (optional) True to drain console socket to buffer
122 @param console_log: (optional) path to console log file
123 @param log_dir: where to create and keep log files
124 @param qmp_timer: (optional) default QMP socket timeout
125 @note: Qemu process is not started until launch() is used.
127 # pylint: disable=too-many-arguments
129 # Direct user configuration
131 self._binary = binary
132 self._args = list(args)
133 self._wrapper = wrapper
134 self._qmp_timer = qmp_timer
136 self._name = name or "qemu-%d" % os.getpid()
137 self._temp_dir: Optional[str] = None
138 self._base_temp_dir = base_temp_dir
139 self._sock_dir = sock_dir
140 self._log_dir = log_dir
142 if monitor_address is not None:
143 self._monitor_address = monitor_address
144 self._remove_monitor_sockfile = False
146 self._monitor_address = os.path.join(
147 self.sock_dir, f"{self._name}-monitor.sock"
149 self._remove_monitor_sockfile = True
151 self._console_log_path = console_log
152 if self._console_log_path:
153 # In order to log the console, buffering needs to be enabled.
154 self._drain_console = True
156 self._drain_console = drain_console
159 self._qemu_log_path: Optional[str] = None
160 self._qemu_log_file: Optional[BinaryIO] = None
161 self._popen: Optional['subprocess.Popen[bytes]'] = None
162 self._events: List[QMPMessage] = []
163 self._iolog: Optional[str] = None
164 self._qmp_set = True # Enable QMP monitor by default.
165 self._qmp_connection: Optional[QEMUMonitorProtocol] = None
166 self._qemu_full_args: Tuple[str, ...] = ()
167 self._launched = False
168 self._machine: Optional[str] = None
169 self._console_index = 0
170 self._console_set = False
171 self._console_device_type: Optional[str] = None
172 self._console_address = os.path.join(
173 self.sock_dir, f"{self._name}-console.sock"
175 self._console_socket: Optional[socket.socket] = None
176 self._remove_files: List[str] = []
177 self._user_killed = False
178 self._quit_issued = False
180 def __enter__(self: _T) -> _T:
184 exc_type: Optional[Type[BaseException]],
185 exc_val: Optional[BaseException],
186 exc_tb: Optional[TracebackType]) -> None:
189 def add_monitor_null(self) -> None:
191 This can be used to add an unused monitor instance.
193 self._args.append('-monitor')
194 self._args.append('null')
196 def add_fd(self: _T, fd: int, fdset: int,
197 opaque: str, opts: str = '') -> _T:
199 Pass a file descriptor to the VM
201 options = ['fd=%d' % fd,
203 'opaque=%s' % opaque]
207 # This did not exist before 3.4, but since then it is
208 # mandatory for our purpose
209 if hasattr(os, 'set_inheritable'):
210 os.set_inheritable(fd, True)
212 self._args.append('-add-fd')
213 self._args.append(','.join(options))
216 def send_fd_scm(self, fd: Optional[int] = None,
217 file_path: Optional[str] = None) -> int:
219 Send an fd or file_path to the remote via SCM_RIGHTS.
221 Exactly one of fd and file_path must be given. If it is
222 file_path, the file will be opened read-only and the new file
223 descriptor will be sent to the remote.
225 if file_path is not None:
227 with open(file_path, "rb") as passfile:
228 fd = passfile.fileno()
229 self._qmp.send_fd_scm(fd)
231 assert fd is not None
232 self._qmp.send_fd_scm(fd)
237 def _remove_if_exists(path: str) -> None:
239 Remove file object at path if it exists
243 except OSError as exception:
244 if exception.errno == errno.ENOENT:
248 def is_running(self) -> bool:
249 """Returns true if the VM is running."""
250 return self._popen is not None and self._popen.poll() is None
253 def _subp(self) -> 'subprocess.Popen[bytes]':
254 if self._popen is None:
255 raise QEMUMachineError('Subprocess pipe not present')
258 def exitcode(self) -> Optional[int]:
259 """Returns the exit code if possible, or None."""
260 if self._popen is None:
262 return self._popen.poll()
264 def get_pid(self) -> Optional[int]:
265 """Returns the PID of the running process, or None."""
266 if not self.is_running():
268 return self._subp.pid
270 def _load_io_log(self) -> None:
271 # Assume that the output encoding of QEMU's terminal output is
272 # defined by our locale. If indeterminate, allow open() to fall
273 # back to the platform default.
274 _, encoding = locale.getlocale()
275 if self._qemu_log_path is not None:
276 with open(self._qemu_log_path, "r", encoding=encoding) as iolog:
277 self._iolog = iolog.read()
280 def _base_args(self) -> List[str]:
281 args = ['-display', 'none', '-vga', 'none']
284 if isinstance(self._monitor_address, tuple):
285 moncdev = "socket,id=mon,host={},port={}".format(
286 *self._monitor_address
289 moncdev = f"socket,id=mon,path={self._monitor_address}"
290 args.extend(['-chardev', moncdev, '-mon',
291 'chardev=mon,mode=control'])
293 if self._machine is not None:
294 args.extend(['-machine', self._machine])
295 for _ in range(self._console_index):
296 args.extend(['-serial', 'null'])
297 if self._console_set:
298 chardev = ('socket,id=console,path=%s,server=on,wait=off' %
299 self._console_address)
300 args.extend(['-chardev', chardev])
301 if self._console_device_type is None:
302 args.extend(['-serial', 'chardev:console'])
304 device = '%s,chardev=console' % self._console_device_type
305 args.extend(['-device', device])
309 def args(self) -> List[str]:
310 """Returns the list of arguments given to the QEMU binary."""
313 def _pre_launch(self) -> None:
314 if self._console_set:
315 self._remove_files.append(self._console_address)
318 if self._remove_monitor_sockfile:
319 assert isinstance(self._monitor_address, str)
320 self._remove_files.append(self._monitor_address)
321 self._qmp_connection = QEMUMonitorProtocol(
322 self._monitor_address,
327 # NOTE: Make sure any opened resources are *definitely* freed in
329 # pylint: disable=consider-using-with
330 self._qemu_log_path = os.path.join(self.log_dir, self._name + ".log")
331 self._qemu_log_file = open(self._qemu_log_path, 'wb')
333 def _post_launch(self) -> None:
334 if self._qmp_connection:
335 self._qmp.accept(self._qmp_timer)
337 def _close_qemu_log_file(self) -> None:
338 if self._qemu_log_file is not None:
339 self._qemu_log_file.close()
340 self._qemu_log_file = None
342 def _post_shutdown(self) -> None:
344 Called to cleanup the VM instance after the process has exited.
345 May also be called after a failed launch.
347 # Comprehensive reset for the failed launch case:
348 self._early_cleanup()
351 self._close_qmp_connection()
352 except Exception as err: # pylint: disable=broad-except
354 "Exception closing QMP connection: %s",
355 str(err) if str(err) else type(err).__name__
358 assert self._qmp_connection is None
360 self._close_qemu_log_file()
364 self._qemu_log_path = None
366 if self._temp_dir is not None:
367 shutil.rmtree(self._temp_dir)
368 self._temp_dir = None
370 while len(self._remove_files) > 0:
371 self._remove_if_exists(self._remove_files.pop())
373 exitcode = self.exitcode()
374 if (exitcode is not None and exitcode < 0
375 and not (self._user_killed and exitcode == -signal.SIGKILL)):
376 msg = 'qemu received signal %i; command: "%s"'
377 if self._qemu_full_args:
378 command = ' '.join(self._qemu_full_args)
381 LOG.warning(msg, -int(exitcode), command)
383 self._quit_issued = False
384 self._user_killed = False
385 self._launched = False
387 def launch(self) -> None:
389 Launch the VM and make sure we cleanup and expose the
390 command line/output in case of exception
394 raise QEMUMachineError('VM already launched')
397 self._qemu_full_args = ()
400 self._launched = True
402 self._post_shutdown()
404 LOG.debug('Error launching VM')
405 if self._qemu_full_args:
406 LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
408 LOG.debug('Output: %r', self._iolog)
411 def _launch(self) -> None:
413 Launch the VM and establish a QMP connection
416 self._qemu_full_args = tuple(
422 LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
424 # Cleaning up of this subprocess is guaranteed by _do_shutdown.
425 # pylint: disable=consider-using-with
426 self._popen = subprocess.Popen(self._qemu_full_args,
427 stdin=subprocess.DEVNULL,
428 stdout=self._qemu_log_file,
429 stderr=subprocess.STDOUT,
434 def _close_qmp_connection(self) -> None:
436 Close the underlying QMP connection, if any.
438 Dutifully report errors that occurred while closing, but assume
439 that any error encountered indicates an abnormal termination
440 process and not a failure to close.
442 if self._qmp_connection is None:
448 # EOF can occur as an Exception here when using the Async
449 # QMP backend. It indicates that the server closed the
450 # stream. If we successfully issued 'quit' at any point,
451 # then this was expected. If the remote went away without
452 # our permission, it's worth reporting that as an abnormal
454 if not (self._user_killed or self._quit_issued):
457 self._qmp_connection = None
459 def _early_cleanup(self) -> None:
461 Perform any cleanup that needs to happen before the VM exits.
463 May be invoked by both soft and hard shutdown in failover scenarios.
464 Called additionally by _post_shutdown for comprehensive cleanup.
466 # If we keep the console socket open, we may deadlock waiting
467 # for QEMU to exit, while QEMU is waiting for the socket to
469 if self._console_socket is not None:
470 self._console_socket.close()
471 self._console_socket = None
473 def _hard_shutdown(self) -> None:
475 Perform early cleanup, kill the VM, and wait for it to terminate.
477 :raise subprocess.Timeout: When timeout is exceeds 60 seconds
478 waiting for the QEMU process to terminate.
480 self._early_cleanup()
482 self._subp.wait(timeout=60)
484 def _soft_shutdown(self, timeout: Optional[int]) -> None:
486 Perform early cleanup, attempt to gracefully shut down the VM, and wait
489 :param timeout: Timeout in seconds for graceful shutdown.
490 A value of None is an infinite wait.
492 :raise ConnectionReset: On QMP communication errors
493 :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
494 the QEMU process to terminate.
496 self._early_cleanup()
498 if self._qmp_connection:
500 if not self._quit_issued:
501 # May raise ExecInterruptedError or StateError if the
502 # connection dies or has *already* died.
505 # Regardless, we want to quiesce the connection.
506 self._close_qmp_connection()
508 # May raise subprocess.TimeoutExpired
509 self._subp.wait(timeout=timeout)
511 def _do_shutdown(self, timeout: Optional[int]) -> None:
513 Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
515 :param timeout: Timeout in seconds for graceful shutdown.
516 A value of None is an infinite wait.
518 :raise AbnormalShutdown: When the VM could not be shut down gracefully.
519 The inner exception will likely be ConnectionReset or
520 subprocess.TimeoutExpired. In rare cases, non-graceful termination
521 may result in its own exceptions, likely subprocess.TimeoutExpired.
524 self._soft_shutdown(timeout)
525 except Exception as exc:
526 self._hard_shutdown()
527 raise AbnormalShutdown("Could not perform graceful shutdown") \
532 timeout: Optional[int] = 30) -> None:
534 Terminate the VM (gracefully if possible) and perform cleanup.
535 Cleanup will always be performed.
537 If the VM has not yet been launched, or shutdown(), wait(), or kill()
538 have already been called, this method does nothing.
540 :param hard: When true, do not attempt graceful shutdown, and
541 suppress the SIGKILL warning log message.
542 :param timeout: Optional timeout in seconds for graceful shutdown.
543 Default 30 seconds, A `None` value is an infinite wait.
545 if not self._launched:
550 self._user_killed = True
551 self._hard_shutdown()
553 self._do_shutdown(timeout)
555 self._post_shutdown()
557 def kill(self) -> None:
559 Terminate the VM forcefully, wait for it to exit, and perform cleanup.
561 self.shutdown(hard=True)
563 def wait(self, timeout: Optional[int] = 30) -> None:
565 Wait for the VM to power off and perform post-shutdown cleanup.
567 :param timeout: Optional timeout in seconds. Default 30 seconds.
568 A value of `None` is an infinite wait.
570 self._quit_issued = True
571 self.shutdown(timeout=timeout)
573 def set_qmp_monitor(self, enabled: bool = True) -> None:
577 @param enabled: if False, qmp monitor options will be removed from
578 the base arguments of the resulting QEMU command
579 line. Default is True.
581 .. note:: Call this function before launch().
583 self._qmp_set = enabled
586 def _qmp(self) -> QEMUMonitorProtocol:
587 if self._qmp_connection is None:
588 raise QEMUMachineError("Attempt to access QMP with no connection")
589 return self._qmp_connection
592 def _qmp_args(cls, conv_keys: bool,
593 args: Dict[str, Any]) -> Dict[str, object]:
595 return {k.replace('_', '-'): v for k, v in args.items()}
599 def qmp(self, cmd: str,
600 args_dict: Optional[Dict[str, object]] = None,
601 conv_keys: Optional[bool] = None,
602 **args: Any) -> QMPMessage:
604 Invoke a QMP command and return the response dict
606 if args_dict is not None:
608 assert conv_keys is None
612 if conv_keys is None:
615 qmp_args = self._qmp_args(conv_keys, args)
616 ret = self._qmp.cmd(cmd, args=qmp_args)
617 if cmd == 'quit' and 'error' not in ret and 'return' in ret:
618 self._quit_issued = True
621 def command(self, cmd: str,
622 conv_keys: bool = True,
623 **args: Any) -> QMPReturnValue:
625 Invoke a QMP command.
626 On success return the response dict.
627 On failure raise an exception.
629 qmp_args = self._qmp_args(conv_keys, args)
630 ret = self._qmp.command(cmd, **qmp_args)
632 self._quit_issued = True
635 def get_qmp_event(self, wait: bool = False) -> Optional[QMPMessage]:
637 Poll for one queued QMP events and return it
640 return self._events.pop(0)
641 return self._qmp.pull_event(wait=wait)
643 def get_qmp_events(self, wait: bool = False) -> List[QMPMessage]:
645 Poll for queued QMP events and return a list of dicts
647 events = self._qmp.get_events(wait=wait)
648 events.extend(self._events)
653 def event_match(event: Any, match: Optional[Any]) -> bool:
655 Check if an event matches optional match criteria.
657 The match criteria takes the form of a matching subdict. The event is
658 checked to be a superset of the subdict, recursively, with matching
659 values whenever the subdict values are not None.
661 This has a limitation that you cannot explicitly check for None values.
663 Examples, with the subdict queries on the left:
664 - None matches any object.
665 - {"foo": None} matches {"foo": {"bar": 1}}
666 - {"foo": None} matches {"foo": 5}
667 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
668 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
676 if not QEMUMachine.event_match(event[key], match[key]):
682 # either match or event wasn't iterable (not a dict)
683 return bool(match == event)
685 def event_wait(self, name: str,
686 timeout: float = 60.0,
687 match: Optional[QMPMessage] = None) -> Optional[QMPMessage]:
689 event_wait waits for and returns a named event from QMP with a timeout.
691 name: The event to wait for.
692 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
693 match: Optional match criteria. See event_match for details.
695 return self.events_wait([(name, match)], timeout)
697 def events_wait(self,
698 events: Sequence[Tuple[str, Any]],
699 timeout: float = 60.0) -> Optional[QMPMessage]:
701 events_wait waits for and returns a single named event from QMP.
702 In the case of multiple qualifying events, this function returns the
705 :param events: A sequence of (name, match_criteria) tuples.
706 The match criteria are optional and may be None.
707 See event_match for details.
708 :param timeout: Optional timeout, in seconds.
709 See QEMUMonitorProtocol.pull_event.
711 :raise QMPTimeoutError: If timeout was non-zero and no matching events
713 :return: A QMP event matching the filter criteria.
714 If timeout was 0 and no event matched, None.
716 def _match(event: QMPMessage) -> bool:
717 for name, match in events:
718 if event['event'] == name and self.event_match(event, match):
722 event: Optional[QMPMessage]
724 # Search cached events
725 for event in self._events:
727 self._events.remove(event)
730 # Poll for new events
732 event = self._qmp.pull_event(wait=timeout)
734 # NB: None is only returned when timeout is false-ish.
735 # Timeouts raise QMPTimeoutError instead!
739 self._events.append(event)
743 def get_log(self) -> Optional[str]:
745 After self.shutdown or failed qemu execution, this returns the output
750 def add_args(self, *args: str) -> None:
752 Adds to the list of extra arguments to be given to the QEMU binary
754 self._args.extend(args)
756 def set_machine(self, machine_type: str) -> None:
758 Sets the machine type
760 If set, the machine type will be added to the base arguments
761 of the resulting QEMU command line.
763 self._machine = machine_type
765 def set_console(self,
766 device_type: Optional[str] = None,
767 console_index: int = 0) -> None:
769 Sets the device type for a console device
771 If set, the console device and a backing character device will
772 be added to the base arguments of the resulting QEMU command
775 This is a convenience method that will either use the provided
776 device type, or default to a "-serial chardev:console" command
779 The actual setting of command line arguments will be be done at
780 machine launch time, as it depends on the temporary directory
783 @param device_type: the device type, such as "isa-serial". If
784 None is given (the default value) a "-serial
785 chardev:console" command line argument will
786 be used instead, resorting to the machine's
788 @param console_index: the index of the console device to use.
789 If not zero, the command line will create
790 'index - 1' consoles and connect them to
791 the 'null' backing character device.
793 self._console_set = True
794 self._console_device_type = device_type
795 self._console_index = console_index
798 def console_socket(self) -> socket.socket:
800 Returns a socket connected to the console
802 if self._console_socket is None:
803 self._console_socket = console_socket.ConsoleSocket(
804 self._console_address,
805 file=self._console_log_path,
806 drain=self._drain_console)
807 return self._console_socket
810 def temp_dir(self) -> str:
812 Returns a temporary directory to be used for this machine
814 if self._temp_dir is None:
815 self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-",
816 dir=self._base_temp_dir)
817 return self._temp_dir
820 def sock_dir(self) -> str:
822 Returns the directory used for sockfiles by this machine.
825 return self._sock_dir
829 def log_dir(self) -> str:
831 Returns a directory to be used for writing logs
833 if self._log_dir is None: