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 f"qemu-{os.getpid()}-{id(self):02x}"
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
145 self._monitor_address = os.path.join(
146 self.sock_dir, f"{self._name}-monitor.sock"
149 self._console_log_path = console_log
150 if self._console_log_path:
151 # In order to log the console, buffering needs to be enabled.
152 self._drain_console = True
154 self._drain_console = drain_console
157 self._qemu_log_path: Optional[str] = None
158 self._qemu_log_file: Optional[BinaryIO] = None
159 self._popen: Optional['subprocess.Popen[bytes]'] = None
160 self._events: List[QMPMessage] = []
161 self._iolog: Optional[str] = None
162 self._qmp_set = True # Enable QMP monitor by default.
163 self._qmp_connection: Optional[QEMUMonitorProtocol] = None
164 self._qemu_full_args: Tuple[str, ...] = ()
165 self._launched = False
166 self._machine: Optional[str] = None
167 self._console_index = 0
168 self._console_set = False
169 self._console_device_type: Optional[str] = None
170 self._console_address = os.path.join(
171 self.sock_dir, f"{self._name}-console.sock"
173 self._console_socket: Optional[socket.socket] = None
174 self._remove_files: List[str] = []
175 self._user_killed = False
176 self._quit_issued = False
178 def __enter__(self: _T) -> _T:
182 exc_type: Optional[Type[BaseException]],
183 exc_val: Optional[BaseException],
184 exc_tb: Optional[TracebackType]) -> None:
187 def add_monitor_null(self) -> None:
189 This can be used to add an unused monitor instance.
191 self._args.append('-monitor')
192 self._args.append('null')
194 def add_fd(self: _T, fd: int, fdset: int,
195 opaque: str, opts: str = '') -> _T:
197 Pass a file descriptor to the VM
199 options = ['fd=%d' % fd,
201 'opaque=%s' % opaque]
205 # This did not exist before 3.4, but since then it is
206 # mandatory for our purpose
207 if hasattr(os, 'set_inheritable'):
208 os.set_inheritable(fd, True)
210 self._args.append('-add-fd')
211 self._args.append(','.join(options))
214 def send_fd_scm(self, fd: Optional[int] = None,
215 file_path: Optional[str] = None) -> int:
217 Send an fd or file_path to the remote via SCM_RIGHTS.
219 Exactly one of fd and file_path must be given. If it is
220 file_path, the file will be opened read-only and the new file
221 descriptor will be sent to the remote.
223 if file_path is not None:
225 with open(file_path, "rb") as passfile:
226 fd = passfile.fileno()
227 self._qmp.send_fd_scm(fd)
229 assert fd is not None
230 self._qmp.send_fd_scm(fd)
235 def _remove_if_exists(path: str) -> None:
237 Remove file object at path if it exists
241 except OSError as exception:
242 if exception.errno == errno.ENOENT:
246 def is_running(self) -> bool:
247 """Returns true if the VM is running."""
248 return self._popen is not None and self._popen.poll() is None
251 def _subp(self) -> 'subprocess.Popen[bytes]':
252 if self._popen is None:
253 raise QEMUMachineError('Subprocess pipe not present')
256 def exitcode(self) -> Optional[int]:
257 """Returns the exit code if possible, or None."""
258 if self._popen is None:
260 return self._popen.poll()
262 def get_pid(self) -> Optional[int]:
263 """Returns the PID of the running process, or None."""
264 if not self.is_running():
266 return self._subp.pid
268 def _load_io_log(self) -> None:
269 # Assume that the output encoding of QEMU's terminal output is
270 # defined by our locale. If indeterminate, allow open() to fall
271 # back to the platform default.
272 _, encoding = locale.getlocale()
273 if self._qemu_log_path is not None:
274 with open(self._qemu_log_path, "r", encoding=encoding) as iolog:
275 self._iolog = iolog.read()
278 def _base_args(self) -> List[str]:
279 args = ['-display', 'none', '-vga', 'none']
282 if isinstance(self._monitor_address, tuple):
283 moncdev = "socket,id=mon,host={},port={}".format(
284 *self._monitor_address
287 moncdev = f"socket,id=mon,path={self._monitor_address}"
288 args.extend(['-chardev', moncdev, '-mon',
289 'chardev=mon,mode=control'])
291 if self._machine is not None:
292 args.extend(['-machine', self._machine])
293 for _ in range(self._console_index):
294 args.extend(['-serial', 'null'])
295 if self._console_set:
296 chardev = ('socket,id=console,path=%s,server=on,wait=off' %
297 self._console_address)
298 args.extend(['-chardev', chardev])
299 if self._console_device_type is None:
300 args.extend(['-serial', 'chardev:console'])
302 device = '%s,chardev=console' % self._console_device_type
303 args.extend(['-device', device])
307 def args(self) -> List[str]:
308 """Returns the list of arguments given to the QEMU binary."""
311 def _pre_launch(self) -> None:
312 if self._console_set:
313 self._remove_files.append(self._console_address)
316 if isinstance(self._monitor_address, str):
317 self._remove_files.append(self._monitor_address)
318 self._qmp_connection = QEMUMonitorProtocol(
319 self._monitor_address,
324 # NOTE: Make sure any opened resources are *definitely* freed in
326 # pylint: disable=consider-using-with
327 self._qemu_log_path = os.path.join(self.log_dir, self._name + ".log")
328 self._qemu_log_file = open(self._qemu_log_path, 'wb')
331 self._qemu_full_args = tuple(chain(
338 def _post_launch(self) -> None:
339 if self._qmp_connection:
340 self._qmp.accept(self._qmp_timer)
342 def _close_qemu_log_file(self) -> None:
343 if self._qemu_log_file is not None:
344 self._qemu_log_file.close()
345 self._qemu_log_file = None
347 def _post_shutdown(self) -> None:
349 Called to cleanup the VM instance after the process has exited.
350 May also be called after a failed launch.
353 self._close_qmp_connection()
354 except Exception as err: # pylint: disable=broad-except
356 "Exception closing QMP connection: %s",
357 str(err) if str(err) else type(err).__name__
360 assert self._qmp_connection is None
362 self._close_qemu_log_file()
366 self._qemu_log_path = None
368 if self._temp_dir is not None:
369 shutil.rmtree(self._temp_dir)
370 self._temp_dir = None
372 while len(self._remove_files) > 0:
373 self._remove_if_exists(self._remove_files.pop())
375 exitcode = self.exitcode()
376 if (exitcode is not None and exitcode < 0
377 and not (self._user_killed and exitcode == -signal.SIGKILL)):
378 msg = 'qemu received signal %i; command: "%s"'
379 if self._qemu_full_args:
380 command = ' '.join(self._qemu_full_args)
383 LOG.warning(msg, -int(exitcode), command)
385 self._quit_issued = False
386 self._user_killed = False
387 self._launched = False
389 def launch(self) -> None:
391 Launch the VM and make sure we cleanup and expose the
392 command line/output in case of exception
396 raise QEMUMachineError('VM already launched')
401 # We may have launched the process but it may
402 # have exited before we could connect via QMP.
403 # Assume the VM didn't launch or is exiting.
404 # If we don't wait for the process, exitcode() may still be
405 # 'None' by the time control is ceded back to the caller.
409 self._post_shutdown()
411 LOG.debug('Error launching VM')
412 if self._qemu_full_args:
413 LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
415 LOG.debug('Output: %r', self._iolog)
418 def _launch(self) -> None:
420 Launch the VM and establish a QMP connection
423 LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
425 # Cleaning up of this subprocess is guaranteed by _do_shutdown.
426 # pylint: disable=consider-using-with
427 self._popen = subprocess.Popen(self._qemu_full_args,
428 stdin=subprocess.DEVNULL,
429 stdout=self._qemu_log_file,
430 stderr=subprocess.STDOUT,
433 self._launched = True
436 def _close_qmp_connection(self) -> None:
438 Close the underlying QMP connection, if any.
440 Dutifully report errors that occurred while closing, but assume
441 that any error encountered indicates an abnormal termination
442 process and not a failure to close.
444 if self._qmp_connection is None:
450 # EOF can occur as an Exception here when using the Async
451 # QMP backend. It indicates that the server closed the
452 # stream. If we successfully issued 'quit' at any point,
453 # then this was expected. If the remote went away without
454 # our permission, it's worth reporting that as an abnormal
456 if not (self._user_killed or self._quit_issued):
459 self._qmp_connection = None
461 def _early_cleanup(self) -> None:
463 Perform any cleanup that needs to happen before the VM exits.
465 This method may be called twice upon shutdown, once each by soft
466 and hard shutdown in failover scenarios.
468 # If we keep the console socket open, we may deadlock waiting
469 # for QEMU to exit, while QEMU is waiting for the socket to
471 if self._console_socket is not None:
472 self._console_socket.close()
473 self._console_socket = None
475 def _hard_shutdown(self) -> None:
477 Perform early cleanup, kill the VM, and wait for it to terminate.
479 :raise subprocess.Timeout: When timeout is exceeds 60 seconds
480 waiting for the QEMU process to terminate.
482 self._early_cleanup()
484 self._subp.wait(timeout=60)
486 def _soft_shutdown(self, timeout: Optional[int]) -> None:
488 Perform early cleanup, attempt to gracefully shut down the VM, and wait
491 :param timeout: Timeout in seconds for graceful shutdown.
492 A value of None is an infinite wait.
494 :raise ConnectionReset: On QMP communication errors
495 :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
496 the QEMU process to terminate.
498 self._early_cleanup()
500 if self._qmp_connection:
502 if not self._quit_issued:
503 # May raise ExecInterruptedError or StateError if the
504 # connection dies or has *already* died.
507 # Regardless, we want to quiesce the connection.
508 self._close_qmp_connection()
510 # May raise subprocess.TimeoutExpired
511 self._subp.wait(timeout=timeout)
513 def _do_shutdown(self, timeout: Optional[int]) -> None:
515 Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
517 :param timeout: Timeout in seconds for graceful shutdown.
518 A value of None is an infinite wait.
520 :raise AbnormalShutdown: When the VM could not be shut down gracefully.
521 The inner exception will likely be ConnectionReset or
522 subprocess.TimeoutExpired. In rare cases, non-graceful termination
523 may result in its own exceptions, likely subprocess.TimeoutExpired.
526 self._soft_shutdown(timeout)
527 except Exception as exc:
528 self._hard_shutdown()
529 raise AbnormalShutdown("Could not perform graceful shutdown") \
534 timeout: Optional[int] = 30) -> None:
536 Terminate the VM (gracefully if possible) and perform cleanup.
537 Cleanup will always be performed.
539 If the VM has not yet been launched, or shutdown(), wait(), or kill()
540 have already been called, this method does nothing.
542 :param hard: When true, do not attempt graceful shutdown, and
543 suppress the SIGKILL warning log message.
544 :param timeout: Optional timeout in seconds for graceful shutdown.
545 Default 30 seconds, A `None` value is an infinite wait.
547 if not self._launched:
552 self._user_killed = True
553 self._hard_shutdown()
555 self._do_shutdown(timeout)
557 self._post_shutdown()
559 def kill(self) -> None:
561 Terminate the VM forcefully, wait for it to exit, and perform cleanup.
563 self.shutdown(hard=True)
565 def wait(self, timeout: Optional[int] = 30) -> None:
567 Wait for the VM to power off and perform post-shutdown cleanup.
569 :param timeout: Optional timeout in seconds. Default 30 seconds.
570 A value of `None` is an infinite wait.
572 self._quit_issued = True
573 self.shutdown(timeout=timeout)
575 def set_qmp_monitor(self, enabled: bool = True) -> None:
579 @param enabled: if False, qmp monitor options will be removed from
580 the base arguments of the resulting QEMU command
581 line. Default is True.
583 .. note:: Call this function before launch().
585 self._qmp_set = enabled
588 def _qmp(self) -> QEMUMonitorProtocol:
589 if self._qmp_connection is None:
590 raise QEMUMachineError("Attempt to access QMP with no connection")
591 return self._qmp_connection
594 def _qmp_args(cls, conv_keys: bool,
595 args: Dict[str, Any]) -> Dict[str, object]:
597 return {k.replace('_', '-'): v for k, v in args.items()}
601 def qmp(self, cmd: str,
602 args_dict: Optional[Dict[str, object]] = None,
603 conv_keys: Optional[bool] = None,
604 **args: Any) -> QMPMessage:
606 Invoke a QMP command and return the response dict
608 if args_dict is not None:
610 assert conv_keys is None
614 if conv_keys is None:
617 qmp_args = self._qmp_args(conv_keys, args)
618 ret = self._qmp.cmd(cmd, args=qmp_args)
619 if cmd == 'quit' and 'error' not in ret and 'return' in ret:
620 self._quit_issued = True
623 def command(self, cmd: str,
624 conv_keys: bool = True,
625 **args: Any) -> QMPReturnValue:
627 Invoke a QMP command.
628 On success return the response dict.
629 On failure raise an exception.
631 qmp_args = self._qmp_args(conv_keys, args)
632 ret = self._qmp.command(cmd, **qmp_args)
634 self._quit_issued = True
637 def get_qmp_event(self, wait: bool = False) -> Optional[QMPMessage]:
639 Poll for one queued QMP events and return it
642 return self._events.pop(0)
643 return self._qmp.pull_event(wait=wait)
645 def get_qmp_events(self, wait: bool = False) -> List[QMPMessage]:
647 Poll for queued QMP events and return a list of dicts
649 events = self._qmp.get_events(wait=wait)
650 events.extend(self._events)
655 def event_match(event: Any, match: Optional[Any]) -> bool:
657 Check if an event matches optional match criteria.
659 The match criteria takes the form of a matching subdict. The event is
660 checked to be a superset of the subdict, recursively, with matching
661 values whenever the subdict values are not None.
663 This has a limitation that you cannot explicitly check for None values.
665 Examples, with the subdict queries on the left:
666 - None matches any object.
667 - {"foo": None} matches {"foo": {"bar": 1}}
668 - {"foo": None} matches {"foo": 5}
669 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
670 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
678 if not QEMUMachine.event_match(event[key], match[key]):
684 # either match or event wasn't iterable (not a dict)
685 return bool(match == event)
687 def event_wait(self, name: str,
688 timeout: float = 60.0,
689 match: Optional[QMPMessage] = None) -> Optional[QMPMessage]:
691 event_wait waits for and returns a named event from QMP with a timeout.
693 name: The event to wait for.
694 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
695 match: Optional match criteria. See event_match for details.
697 return self.events_wait([(name, match)], timeout)
699 def events_wait(self,
700 events: Sequence[Tuple[str, Any]],
701 timeout: float = 60.0) -> Optional[QMPMessage]:
703 events_wait waits for and returns a single named event from QMP.
704 In the case of multiple qualifying events, this function returns the
707 :param events: A sequence of (name, match_criteria) tuples.
708 The match criteria are optional and may be None.
709 See event_match for details.
710 :param timeout: Optional timeout, in seconds.
711 See QEMUMonitorProtocol.pull_event.
713 :raise QMPTimeoutError: If timeout was non-zero and no matching events
715 :return: A QMP event matching the filter criteria.
716 If timeout was 0 and no event matched, None.
718 def _match(event: QMPMessage) -> bool:
719 for name, match in events:
720 if event['event'] == name and self.event_match(event, match):
724 event: Optional[QMPMessage]
726 # Search cached events
727 for event in self._events:
729 self._events.remove(event)
732 # Poll for new events
734 event = self._qmp.pull_event(wait=timeout)
736 # NB: None is only returned when timeout is false-ish.
737 # Timeouts raise QMPTimeoutError instead!
741 self._events.append(event)
745 def get_log(self) -> Optional[str]:
747 After self.shutdown or failed qemu execution, this returns the output
752 def add_args(self, *args: str) -> None:
754 Adds to the list of extra arguments to be given to the QEMU binary
756 self._args.extend(args)
758 def set_machine(self, machine_type: str) -> None:
760 Sets the machine type
762 If set, the machine type will be added to the base arguments
763 of the resulting QEMU command line.
765 self._machine = machine_type
767 def set_console(self,
768 device_type: Optional[str] = None,
769 console_index: int = 0) -> None:
771 Sets the device type for a console device
773 If set, the console device and a backing character device will
774 be added to the base arguments of the resulting QEMU command
777 This is a convenience method that will either use the provided
778 device type, or default to a "-serial chardev:console" command
781 The actual setting of command line arguments will be be done at
782 machine launch time, as it depends on the temporary directory
785 @param device_type: the device type, such as "isa-serial". If
786 None is given (the default value) a "-serial
787 chardev:console" command line argument will
788 be used instead, resorting to the machine's
790 @param console_index: the index of the console device to use.
791 If not zero, the command line will create
792 'index - 1' consoles and connect them to
793 the 'null' backing character device.
795 self._console_set = True
796 self._console_device_type = device_type
797 self._console_index = console_index
800 def console_socket(self) -> socket.socket:
802 Returns a socket connected to the console
804 if self._console_socket is None:
805 self._console_socket = console_socket.ConsoleSocket(
806 self._console_address,
807 file=self._console_log_path,
808 drain=self._drain_console)
809 return self._console_socket
812 def temp_dir(self) -> str:
814 Returns a temporary directory to be used for this machine
816 if self._temp_dir is None:
817 self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-",
818 dir=self._base_temp_dir)
819 return self._temp_dir
822 def sock_dir(self) -> str:
824 Returns the directory used for sockfiles by this machine.
827 return self._sock_dir
831 def log_dir(self) -> str:
833 Returns a directory to be used for writing logs
835 if self._log_dir is None: