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
29 from types import TracebackType
41 from qemu.qmp import ( # pylint: disable=import-error
48 from . import console_socket
51 LOG = logging.getLogger(__name__)
54 class QEMUMachineError(Exception):
56 Exception called when an error in QEMUMachine happens.
60 class QEMUMachineAddDeviceError(QEMUMachineError):
62 Exception raised when a request to add a device can not be fulfilled
64 The failures are caused by limitations, lack of information or conflicting
65 requests on the QEMUMachine methods. This exception does not represent
66 failures reported by the QEMU binary itself.
70 class AbnormalShutdown(QEMUMachineError):
72 Exception raised when a graceful shutdown was requested, but not performed.
80 Use this object as a context manager to ensure
81 the QEMU process terminates::
83 with VM(binary) as vm:
85 # vm is guaranteed to be shut down here
87 # pylint: disable=too-many-instance-attributes, too-many-public-methods
91 args: Sequence[str] = (),
92 wrapper: Sequence[str] = (),
93 name: Optional[str] = None,
94 base_temp_dir: str = "/var/tmp",
95 monitor_address: Optional[SocketAddrT] = None,
96 socket_scm_helper: Optional[str] = None,
97 sock_dir: Optional[str] = None,
98 drain_console: bool = False,
99 console_log: Optional[str] = None):
101 Initialize a QEMUMachine
103 @param binary: path to the qemu binary
104 @param args: list of extra arguments
105 @param wrapper: list of arguments used as prefix to qemu binary
106 @param name: prefix for socket and log file names (default: qemu-PID)
107 @param base_temp_dir: default location where temp files are created
108 @param monitor_address: address for QMP monitor
109 @param socket_scm_helper: helper program, required for send_fd_scm()
110 @param sock_dir: where to create socket (defaults to base_temp_dir)
111 @param drain_console: (optional) True to drain console socket to buffer
112 @param console_log: (optional) path to console log file
113 @note: Qemu process is not started until launch() is used.
115 # pylint: disable=too-many-arguments
117 # Direct user configuration
119 self._binary = binary
120 self._args = list(args)
121 self._wrapper = wrapper
123 self._name = name or "qemu-%d" % os.getpid()
124 self._base_temp_dir = base_temp_dir
125 self._sock_dir = sock_dir or self._base_temp_dir
126 self._socket_scm_helper = socket_scm_helper
128 if monitor_address is not None:
129 self._monitor_address = monitor_address
130 self._remove_monitor_sockfile = False
132 self._monitor_address = os.path.join(
133 self._sock_dir, f"{self._name}-monitor.sock"
135 self._remove_monitor_sockfile = True
137 self._console_log_path = console_log
138 if self._console_log_path:
139 # In order to log the console, buffering needs to be enabled.
140 self._drain_console = True
142 self._drain_console = drain_console
145 self._qemu_log_path: Optional[str] = None
146 self._qemu_log_file: Optional[BinaryIO] = None
147 self._popen: Optional['subprocess.Popen[bytes]'] = None
148 self._events: List[QMPMessage] = []
149 self._iolog: Optional[str] = None
150 self._qmp_set = True # Enable QMP monitor by default.
151 self._qmp_connection: Optional[QEMUMonitorProtocol] = None
152 self._qemu_full_args: Tuple[str, ...] = ()
153 self._temp_dir: Optional[str] = None
154 self._launched = False
155 self._machine: Optional[str] = None
156 self._console_index = 0
157 self._console_set = False
158 self._console_device_type: Optional[str] = None
159 self._console_address = os.path.join(
160 self._sock_dir, f"{self._name}-console.sock"
162 self._console_socket: Optional[socket.socket] = None
163 self._remove_files: List[str] = []
164 self._user_killed = False
166 def __enter__(self) -> 'QEMUMachine':
170 exc_type: Optional[Type[BaseException]],
171 exc_val: Optional[BaseException],
172 exc_tb: Optional[TracebackType]) -> None:
175 def add_monitor_null(self) -> None:
177 This can be used to add an unused monitor instance.
179 self._args.append('-monitor')
180 self._args.append('null')
182 def add_fd(self, fd: int, fdset: int,
183 opaque: str, opts: str = '') -> 'QEMUMachine':
185 Pass a file descriptor to the VM
187 options = ['fd=%d' % fd,
189 'opaque=%s' % opaque]
193 # This did not exist before 3.4, but since then it is
194 # mandatory for our purpose
195 if hasattr(os, 'set_inheritable'):
196 os.set_inheritable(fd, True)
198 self._args.append('-add-fd')
199 self._args.append(','.join(options))
202 def send_fd_scm(self, fd: Optional[int] = None,
203 file_path: Optional[str] = None) -> int:
205 Send an fd or file_path to socket_scm_helper.
207 Exactly one of fd and file_path must be given.
208 If it is file_path, the helper will open that file and pass its own fd.
210 # In iotest.py, the qmp should always use unix socket.
211 assert self._qmp.is_scm_available()
212 if self._socket_scm_helper is None:
213 raise QEMUMachineError("No path to socket_scm_helper set")
214 if not os.path.exists(self._socket_scm_helper):
215 raise QEMUMachineError("%s does not exist" %
216 self._socket_scm_helper)
218 # This did not exist before 3.4, but since then it is
219 # mandatory for our purpose
220 if hasattr(os, 'set_inheritable'):
221 os.set_inheritable(self._qmp.get_sock_fd(), True)
223 os.set_inheritable(fd, True)
225 fd_param = ["%s" % self._socket_scm_helper,
226 "%d" % self._qmp.get_sock_fd()]
228 if file_path is not None:
230 fd_param.append(file_path)
232 assert fd is not None
233 fd_param.append(str(fd))
235 proc = subprocess.run(
237 stdin=subprocess.DEVNULL,
238 stdout=subprocess.PIPE,
239 stderr=subprocess.STDOUT,
244 LOG.debug(proc.stdout)
246 return proc.returncode
249 def _remove_if_exists(path: str) -> None:
251 Remove file object at path if it exists
255 except OSError as exception:
256 if exception.errno == errno.ENOENT:
260 def is_running(self) -> bool:
261 """Returns true if the VM is running."""
262 return self._popen is not None and self._popen.poll() is None
265 def _subp(self) -> 'subprocess.Popen[bytes]':
266 if self._popen is None:
267 raise QEMUMachineError('Subprocess pipe not present')
270 def exitcode(self) -> Optional[int]:
271 """Returns the exit code if possible, or None."""
272 if self._popen is None:
274 return self._popen.poll()
276 def get_pid(self) -> Optional[int]:
277 """Returns the PID of the running process, or None."""
278 if not self.is_running():
280 return self._subp.pid
282 def _load_io_log(self) -> None:
283 if self._qemu_log_path is not None:
284 with open(self._qemu_log_path, "r") as iolog:
285 self._iolog = iolog.read()
288 def _base_args(self) -> List[str]:
289 args = ['-display', 'none', '-vga', 'none']
292 if isinstance(self._monitor_address, tuple):
293 moncdev = "socket,id=mon,host={},port={}".format(
294 *self._monitor_address
297 moncdev = f"socket,id=mon,path={self._monitor_address}"
298 args.extend(['-chardev', moncdev, '-mon',
299 'chardev=mon,mode=control'])
301 if self._machine is not None:
302 args.extend(['-machine', self._machine])
303 for _ in range(self._console_index):
304 args.extend(['-serial', 'null'])
305 if self._console_set:
306 chardev = ('socket,id=console,path=%s,server=on,wait=off' %
307 self._console_address)
308 args.extend(['-chardev', chardev])
309 if self._console_device_type is None:
310 args.extend(['-serial', 'chardev:console'])
312 device = '%s,chardev=console' % self._console_device_type
313 args.extend(['-device', device])
316 def _pre_launch(self) -> None:
317 self._qemu_log_path = os.path.join(self.temp_dir, self._name + ".log")
319 if self._console_set:
320 self._remove_files.append(self._console_address)
323 if self._remove_monitor_sockfile:
324 assert isinstance(self._monitor_address, str)
325 self._remove_files.append(self._monitor_address)
326 self._qmp_connection = QEMUMonitorProtocol(
327 self._monitor_address,
332 # NOTE: Make sure any opened resources are *definitely* freed in
334 # pylint: disable=consider-using-with
335 self._qemu_log_file = open(self._qemu_log_path, 'wb')
337 def _post_launch(self) -> None:
338 if self._qmp_connection:
341 def _post_shutdown(self) -> None:
343 Called to cleanup the VM instance after the process has exited.
344 May also be called after a failed launch.
346 # Comprehensive reset for the failed launch case:
347 self._early_cleanup()
349 if self._qmp_connection:
351 self._qmp_connection = None
353 if self._qemu_log_file is not None:
354 self._qemu_log_file.close()
355 self._qemu_log_file = None
359 self._qemu_log_path = None
361 if self._temp_dir is not None:
362 shutil.rmtree(self._temp_dir)
363 self._temp_dir = None
365 while len(self._remove_files) > 0:
366 self._remove_if_exists(self._remove_files.pop())
368 exitcode = self.exitcode()
369 if (exitcode is not None and exitcode < 0
370 and not (self._user_killed and exitcode == -signal.SIGKILL)):
371 msg = 'qemu received signal %i; command: "%s"'
372 if self._qemu_full_args:
373 command = ' '.join(self._qemu_full_args)
376 LOG.warning(msg, -int(exitcode), command)
378 self._user_killed = False
379 self._launched = False
381 def launch(self) -> None:
383 Launch the VM and make sure we cleanup and expose the
384 command line/output in case of exception
388 raise QEMUMachineError('VM already launched')
391 self._qemu_full_args = ()
394 self._launched = True
396 self._post_shutdown()
398 LOG.debug('Error launching VM')
399 if self._qemu_full_args:
400 LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
402 LOG.debug('Output: %r', self._iolog)
405 def _launch(self) -> None:
407 Launch the VM and establish a QMP connection
410 self._qemu_full_args = tuple(
416 LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
418 # Cleaning up of this subprocess is guaranteed by _do_shutdown.
419 # pylint: disable=consider-using-with
420 self._popen = subprocess.Popen(self._qemu_full_args,
421 stdin=subprocess.DEVNULL,
422 stdout=self._qemu_log_file,
423 stderr=subprocess.STDOUT,
428 def _early_cleanup(self) -> None:
430 Perform any cleanup that needs to happen before the VM exits.
432 May be invoked by both soft and hard shutdown in failover scenarios.
433 Called additionally by _post_shutdown for comprehensive cleanup.
435 # If we keep the console socket open, we may deadlock waiting
436 # for QEMU to exit, while QEMU is waiting for the socket to
438 if self._console_socket is not None:
439 self._console_socket.close()
440 self._console_socket = None
442 def _hard_shutdown(self) -> None:
444 Perform early cleanup, kill the VM, and wait for it to terminate.
446 :raise subprocess.Timeout: When timeout is exceeds 60 seconds
447 waiting for the QEMU process to terminate.
449 self._early_cleanup()
451 self._subp.wait(timeout=60)
453 def _soft_shutdown(self, timeout: Optional[int],
454 has_quit: bool = False) -> None:
456 Perform early cleanup, attempt to gracefully shut down the VM, and wait
459 :param timeout: Timeout in seconds for graceful shutdown.
460 A value of None is an infinite wait.
461 :param has_quit: When True, don't attempt to issue 'quit' QMP command
463 :raise ConnectionReset: On QMP communication errors
464 :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
465 the QEMU process to terminate.
467 self._early_cleanup()
469 if self._qmp_connection:
471 # Might raise ConnectionReset
472 self._qmp.cmd('quit')
474 # May raise subprocess.TimeoutExpired
475 self._subp.wait(timeout=timeout)
477 def _do_shutdown(self, timeout: Optional[int],
478 has_quit: bool = False) -> None:
480 Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
482 :param timeout: Timeout in seconds for graceful shutdown.
483 A value of None is an infinite wait.
484 :param has_quit: When True, don't attempt to issue 'quit' QMP command
486 :raise AbnormalShutdown: When the VM could not be shut down gracefully.
487 The inner exception will likely be ConnectionReset or
488 subprocess.TimeoutExpired. In rare cases, non-graceful termination
489 may result in its own exceptions, likely subprocess.TimeoutExpired.
492 self._soft_shutdown(timeout, has_quit)
493 except Exception as exc:
494 self._hard_shutdown()
495 raise AbnormalShutdown("Could not perform graceful shutdown") \
498 def shutdown(self, has_quit: bool = False,
500 timeout: Optional[int] = 30) -> None:
502 Terminate the VM (gracefully if possible) and perform cleanup.
503 Cleanup will always be performed.
505 If the VM has not yet been launched, or shutdown(), wait(), or kill()
506 have already been called, this method does nothing.
508 :param has_quit: When true, do not attempt to issue 'quit' QMP command.
509 :param hard: When true, do not attempt graceful shutdown, and
510 suppress the SIGKILL warning log message.
511 :param timeout: Optional timeout in seconds for graceful shutdown.
512 Default 30 seconds, A `None` value is an infinite wait.
514 if not self._launched:
519 self._user_killed = True
520 self._hard_shutdown()
522 self._do_shutdown(timeout, has_quit)
524 self._post_shutdown()
526 def kill(self) -> None:
528 Terminate the VM forcefully, wait for it to exit, and perform cleanup.
530 self.shutdown(hard=True)
532 def wait(self, timeout: Optional[int] = 30) -> None:
534 Wait for the VM to power off and perform post-shutdown cleanup.
536 :param timeout: Optional timeout in seconds. Default 30 seconds.
537 A value of `None` is an infinite wait.
539 self.shutdown(has_quit=True, timeout=timeout)
541 def set_qmp_monitor(self, enabled: bool = True) -> None:
545 @param enabled: if False, qmp monitor options will be removed from
546 the base arguments of the resulting QEMU command
547 line. Default is True.
548 @note: call this function before launch().
550 self._qmp_set = enabled
553 def _qmp(self) -> QEMUMonitorProtocol:
554 if self._qmp_connection is None:
555 raise QEMUMachineError("Attempt to access QMP with no connection")
556 return self._qmp_connection
559 def _qmp_args(cls, _conv_keys: bool = True, **args: Any) -> Dict[str, Any]:
561 for key, value in args.items():
563 qmp_args[key.replace('_', '-')] = value
565 qmp_args[key] = value
568 def qmp(self, cmd: str,
569 conv_keys: bool = True,
570 **args: Any) -> QMPMessage:
572 Invoke a QMP command and return the response dict
574 qmp_args = self._qmp_args(conv_keys, **args)
575 return self._qmp.cmd(cmd, args=qmp_args)
577 def command(self, cmd: str,
578 conv_keys: bool = True,
579 **args: Any) -> QMPReturnValue:
581 Invoke a QMP command.
582 On success return the response dict.
583 On failure raise an exception.
585 qmp_args = self._qmp_args(conv_keys, **args)
586 return self._qmp.command(cmd, **qmp_args)
588 def get_qmp_event(self, wait: bool = False) -> Optional[QMPMessage]:
590 Poll for one queued QMP events and return it
593 return self._events.pop(0)
594 return self._qmp.pull_event(wait=wait)
596 def get_qmp_events(self, wait: bool = False) -> List[QMPMessage]:
598 Poll for queued QMP events and return a list of dicts
600 events = self._qmp.get_events(wait=wait)
601 events.extend(self._events)
603 self._qmp.clear_events()
607 def event_match(event: Any, match: Optional[Any]) -> bool:
609 Check if an event matches optional match criteria.
611 The match criteria takes the form of a matching subdict. The event is
612 checked to be a superset of the subdict, recursively, with matching
613 values whenever the subdict values are not None.
615 This has a limitation that you cannot explicitly check for None values.
617 Examples, with the subdict queries on the left:
618 - None matches any object.
619 - {"foo": None} matches {"foo": {"bar": 1}}
620 - {"foo": None} matches {"foo": 5}
621 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
622 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
630 if not QEMUMachine.event_match(event[key], match[key]):
636 # either match or event wasn't iterable (not a dict)
637 return bool(match == event)
639 def event_wait(self, name: str,
640 timeout: float = 60.0,
641 match: Optional[QMPMessage] = None) -> Optional[QMPMessage]:
643 event_wait waits for and returns a named event from QMP with a timeout.
645 name: The event to wait for.
646 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
647 match: Optional match criteria. See event_match for details.
649 return self.events_wait([(name, match)], timeout)
651 def events_wait(self,
652 events: Sequence[Tuple[str, Any]],
653 timeout: float = 60.0) -> Optional[QMPMessage]:
655 events_wait waits for and returns a single named event from QMP.
656 In the case of multiple qualifying events, this function returns the
659 :param events: A sequence of (name, match_criteria) tuples.
660 The match criteria are optional and may be None.
661 See event_match for details.
662 :param timeout: Optional timeout, in seconds.
663 See QEMUMonitorProtocol.pull_event.
665 :raise QMPTimeoutError: If timeout was non-zero and no matching events
667 :return: A QMP event matching the filter criteria.
668 If timeout was 0 and no event matched, None.
670 def _match(event: QMPMessage) -> bool:
671 for name, match in events:
672 if event['event'] == name and self.event_match(event, match):
676 event: Optional[QMPMessage]
678 # Search cached events
679 for event in self._events:
681 self._events.remove(event)
684 # Poll for new events
686 event = self._qmp.pull_event(wait=timeout)
688 # NB: None is only returned when timeout is false-ish.
689 # Timeouts raise QMPTimeoutError instead!
693 self._events.append(event)
697 def get_log(self) -> Optional[str]:
699 After self.shutdown or failed qemu execution, this returns the output
704 def add_args(self, *args: str) -> None:
706 Adds to the list of extra arguments to be given to the QEMU binary
708 self._args.extend(args)
710 def set_machine(self, machine_type: str) -> None:
712 Sets the machine type
714 If set, the machine type will be added to the base arguments
715 of the resulting QEMU command line.
717 self._machine = machine_type
719 def set_console(self,
720 device_type: Optional[str] = None,
721 console_index: int = 0) -> None:
723 Sets the device type for a console device
725 If set, the console device and a backing character device will
726 be added to the base arguments of the resulting QEMU command
729 This is a convenience method that will either use the provided
730 device type, or default to a "-serial chardev:console" command
733 The actual setting of command line arguments will be be done at
734 machine launch time, as it depends on the temporary directory
737 @param device_type: the device type, such as "isa-serial". If
738 None is given (the default value) a "-serial
739 chardev:console" command line argument will
740 be used instead, resorting to the machine's
742 @param console_index: the index of the console device to use.
743 If not zero, the command line will create
744 'index - 1' consoles and connect them to
745 the 'null' backing character device.
747 self._console_set = True
748 self._console_device_type = device_type
749 self._console_index = console_index
752 def console_socket(self) -> socket.socket:
754 Returns a socket connected to the console
756 if self._console_socket is None:
757 self._console_socket = console_socket.ConsoleSocket(
758 self._console_address,
759 file=self._console_log_path,
760 drain=self._drain_console)
761 return self._console_socket
764 def temp_dir(self) -> str:
766 Returns a temporary directory to be used for this machine
768 if self._temp_dir is None:
769 self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-",
770 dir=self._base_temp_dir)
771 return self._temp_dir