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 (
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
90 args: Sequence[str] = (),
91 wrapper: Sequence[str] = (),
92 name: Optional[str] = None,
93 base_temp_dir: str = "/var/tmp",
94 monitor_address: Optional[SocketAddrT] = None,
95 socket_scm_helper: Optional[str] = None,
96 sock_dir: Optional[str] = None,
97 drain_console: bool = False,
98 console_log: Optional[str] = None):
100 Initialize a QEMUMachine
102 @param binary: path to the qemu binary
103 @param args: list of extra arguments
104 @param wrapper: list of arguments used as prefix to qemu binary
105 @param name: prefix for socket and log file names (default: qemu-PID)
106 @param base_temp_dir: default location where temp files are created
107 @param monitor_address: address for QMP monitor
108 @param socket_scm_helper: helper program, required for send_fd_scm()
109 @param sock_dir: where to create socket (defaults to base_temp_dir)
110 @param drain_console: (optional) True to drain console socket to buffer
111 @param console_log: (optional) path to console log file
112 @note: Qemu process is not started until launch() is used.
114 # Direct user configuration
116 self._binary = binary
117 self._args = list(args)
118 self._wrapper = wrapper
120 self._name = name or "qemu-%d" % os.getpid()
121 self._base_temp_dir = base_temp_dir
122 self._sock_dir = sock_dir or self._base_temp_dir
123 self._socket_scm_helper = socket_scm_helper
125 if monitor_address is not None:
126 self._monitor_address = monitor_address
127 self._remove_monitor_sockfile = False
129 self._monitor_address = os.path.join(
130 self._sock_dir, f"{self._name}-monitor.sock"
132 self._remove_monitor_sockfile = True
134 self._console_log_path = console_log
135 if self._console_log_path:
136 # In order to log the console, buffering needs to be enabled.
137 self._drain_console = True
139 self._drain_console = drain_console
142 self._qemu_log_path: Optional[str] = None
143 self._qemu_log_file: Optional[BinaryIO] = None
144 self._popen: Optional['subprocess.Popen[bytes]'] = None
145 self._events: List[QMPMessage] = []
146 self._iolog: Optional[str] = None
147 self._qmp_set = True # Enable QMP monitor by default.
148 self._qmp_connection: Optional[QEMUMonitorProtocol] = None
149 self._qemu_full_args: Tuple[str, ...] = ()
150 self._temp_dir: Optional[str] = None
151 self._launched = False
152 self._machine: Optional[str] = None
153 self._console_index = 0
154 self._console_set = False
155 self._console_device_type: Optional[str] = None
156 self._console_address = os.path.join(
157 self._sock_dir, f"{self._name}-console.sock"
159 self._console_socket: Optional[socket.socket] = None
160 self._remove_files: List[str] = []
161 self._user_killed = False
163 def __enter__(self) -> 'QEMUMachine':
167 exc_type: Optional[Type[BaseException]],
168 exc_val: Optional[BaseException],
169 exc_tb: Optional[TracebackType]) -> None:
172 def add_monitor_null(self) -> None:
174 This can be used to add an unused monitor instance.
176 self._args.append('-monitor')
177 self._args.append('null')
179 def add_fd(self, fd: int, fdset: int,
180 opaque: str, opts: str = '') -> 'QEMUMachine':
182 Pass a file descriptor to the VM
184 options = ['fd=%d' % fd,
186 'opaque=%s' % opaque]
190 # This did not exist before 3.4, but since then it is
191 # mandatory for our purpose
192 if hasattr(os, 'set_inheritable'):
193 os.set_inheritable(fd, True)
195 self._args.append('-add-fd')
196 self._args.append(','.join(options))
199 def send_fd_scm(self, fd: Optional[int] = None,
200 file_path: Optional[str] = None) -> int:
202 Send an fd or file_path to socket_scm_helper.
204 Exactly one of fd and file_path must be given.
205 If it is file_path, the helper will open that file and pass its own fd.
207 # In iotest.py, the qmp should always use unix socket.
208 assert self._qmp.is_scm_available()
209 if self._socket_scm_helper is None:
210 raise QEMUMachineError("No path to socket_scm_helper set")
211 if not os.path.exists(self._socket_scm_helper):
212 raise QEMUMachineError("%s does not exist" %
213 self._socket_scm_helper)
215 # This did not exist before 3.4, but since then it is
216 # mandatory for our purpose
217 if hasattr(os, 'set_inheritable'):
218 os.set_inheritable(self._qmp.get_sock_fd(), True)
220 os.set_inheritable(fd, True)
222 fd_param = ["%s" % self._socket_scm_helper,
223 "%d" % self._qmp.get_sock_fd()]
225 if file_path is not None:
227 fd_param.append(file_path)
229 assert fd is not None
230 fd_param.append(str(fd))
232 proc = subprocess.run(
234 stdin=subprocess.DEVNULL,
235 stdout=subprocess.PIPE,
236 stderr=subprocess.STDOUT,
241 LOG.debug(proc.stdout)
243 return proc.returncode
246 def _remove_if_exists(path: str) -> None:
248 Remove file object at path if it exists
252 except OSError as exception:
253 if exception.errno == errno.ENOENT:
257 def is_running(self) -> bool:
258 """Returns true if the VM is running."""
259 return self._popen is not None and self._popen.poll() is None
262 def _subp(self) -> 'subprocess.Popen[bytes]':
263 if self._popen is None:
264 raise QEMUMachineError('Subprocess pipe not present')
267 def exitcode(self) -> Optional[int]:
268 """Returns the exit code if possible, or None."""
269 if self._popen is None:
271 return self._popen.poll()
273 def get_pid(self) -> Optional[int]:
274 """Returns the PID of the running process, or None."""
275 if not self.is_running():
277 return self._subp.pid
279 def _load_io_log(self) -> None:
280 if self._qemu_log_path is not None:
281 with open(self._qemu_log_path, "r") as iolog:
282 self._iolog = iolog.read()
285 def _base_args(self) -> List[str]:
286 args = ['-display', 'none', '-vga', 'none']
289 if isinstance(self._monitor_address, tuple):
290 moncdev = "socket,id=mon,host={},port={}".format(
291 *self._monitor_address
294 moncdev = f"socket,id=mon,path={self._monitor_address}"
295 args.extend(['-chardev', moncdev, '-mon',
296 'chardev=mon,mode=control'])
298 if self._machine is not None:
299 args.extend(['-machine', self._machine])
300 for _ in range(self._console_index):
301 args.extend(['-serial', 'null'])
302 if self._console_set:
303 chardev = ('socket,id=console,path=%s,server=on,wait=off' %
304 self._console_address)
305 args.extend(['-chardev', chardev])
306 if self._console_device_type is None:
307 args.extend(['-serial', 'chardev:console'])
309 device = '%s,chardev=console' % self._console_device_type
310 args.extend(['-device', device])
313 def _pre_launch(self) -> None:
314 self._qemu_log_path = os.path.join(self.temp_dir, self._name + ".log")
316 if self._console_set:
317 self._remove_files.append(self._console_address)
320 if self._remove_monitor_sockfile:
321 assert isinstance(self._monitor_address, str)
322 self._remove_files.append(self._monitor_address)
323 self._qmp_connection = QEMUMonitorProtocol(
324 self._monitor_address,
329 # NOTE: Make sure any opened resources are *definitely* freed in
331 # pylint: disable=consider-using-with
332 self._qemu_log_file = open(self._qemu_log_path, 'wb')
334 def _post_launch(self) -> None:
335 if self._qmp_connection:
338 def _post_shutdown(self) -> None:
340 Called to cleanup the VM instance after the process has exited.
341 May also be called after a failed launch.
343 # Comprehensive reset for the failed launch case:
344 self._early_cleanup()
346 if self._qmp_connection:
348 self._qmp_connection = None
350 if self._qemu_log_file is not None:
351 self._qemu_log_file.close()
352 self._qemu_log_file = None
356 self._qemu_log_path = None
358 if self._temp_dir is not None:
359 shutil.rmtree(self._temp_dir)
360 self._temp_dir = None
362 while len(self._remove_files) > 0:
363 self._remove_if_exists(self._remove_files.pop())
365 exitcode = self.exitcode()
366 if (exitcode is not None and exitcode < 0
367 and not (self._user_killed and exitcode == -signal.SIGKILL)):
368 msg = 'qemu received signal %i; command: "%s"'
369 if self._qemu_full_args:
370 command = ' '.join(self._qemu_full_args)
373 LOG.warning(msg, -int(exitcode), command)
375 self._user_killed = False
376 self._launched = False
378 def launch(self) -> None:
380 Launch the VM and make sure we cleanup and expose the
381 command line/output in case of exception
385 raise QEMUMachineError('VM already launched')
388 self._qemu_full_args = ()
391 self._launched = True
393 self._post_shutdown()
395 LOG.debug('Error launching VM')
396 if self._qemu_full_args:
397 LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
399 LOG.debug('Output: %r', self._iolog)
402 def _launch(self) -> None:
404 Launch the VM and establish a QMP connection
407 self._qemu_full_args = tuple(
413 LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
415 # Cleaning up of this subprocess is guaranteed by _do_shutdown.
416 # pylint: disable=consider-using-with
417 self._popen = subprocess.Popen(self._qemu_full_args,
418 stdin=subprocess.DEVNULL,
419 stdout=self._qemu_log_file,
420 stderr=subprocess.STDOUT,
425 def _early_cleanup(self) -> None:
427 Perform any cleanup that needs to happen before the VM exits.
429 May be invoked by both soft and hard shutdown in failover scenarios.
430 Called additionally by _post_shutdown for comprehensive cleanup.
432 # If we keep the console socket open, we may deadlock waiting
433 # for QEMU to exit, while QEMU is waiting for the socket to
435 if self._console_socket is not None:
436 self._console_socket.close()
437 self._console_socket = None
439 def _hard_shutdown(self) -> None:
441 Perform early cleanup, kill the VM, and wait for it to terminate.
443 :raise subprocess.Timeout: When timeout is exceeds 60 seconds
444 waiting for the QEMU process to terminate.
446 self._early_cleanup()
448 self._subp.wait(timeout=60)
450 def _soft_shutdown(self, timeout: Optional[int],
451 has_quit: bool = False) -> None:
453 Perform early cleanup, attempt to gracefully shut down the VM, and wait
456 :param timeout: Timeout in seconds for graceful shutdown.
457 A value of None is an infinite wait.
458 :param has_quit: When True, don't attempt to issue 'quit' QMP command
460 :raise ConnectionReset: On QMP communication errors
461 :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
462 the QEMU process to terminate.
464 self._early_cleanup()
466 if self._qmp_connection:
468 # Might raise ConnectionReset
469 self._qmp.cmd('quit')
471 # May raise subprocess.TimeoutExpired
472 self._subp.wait(timeout=timeout)
474 def _do_shutdown(self, timeout: Optional[int],
475 has_quit: bool = False) -> None:
477 Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
479 :param timeout: Timeout in seconds for graceful shutdown.
480 A value of None is an infinite wait.
481 :param has_quit: When True, don't attempt to issue 'quit' QMP command
483 :raise AbnormalShutdown: When the VM could not be shut down gracefully.
484 The inner exception will likely be ConnectionReset or
485 subprocess.TimeoutExpired. In rare cases, non-graceful termination
486 may result in its own exceptions, likely subprocess.TimeoutExpired.
489 self._soft_shutdown(timeout, has_quit)
490 except Exception as exc:
491 self._hard_shutdown()
492 raise AbnormalShutdown("Could not perform graceful shutdown") \
495 def shutdown(self, has_quit: bool = False,
497 timeout: Optional[int] = 30) -> None:
499 Terminate the VM (gracefully if possible) and perform cleanup.
500 Cleanup will always be performed.
502 If the VM has not yet been launched, or shutdown(), wait(), or kill()
503 have already been called, this method does nothing.
505 :param has_quit: When true, do not attempt to issue 'quit' QMP command.
506 :param hard: When true, do not attempt graceful shutdown, and
507 suppress the SIGKILL warning log message.
508 :param timeout: Optional timeout in seconds for graceful shutdown.
509 Default 30 seconds, A `None` value is an infinite wait.
511 if not self._launched:
516 self._user_killed = True
517 self._hard_shutdown()
519 self._do_shutdown(timeout, has_quit)
521 self._post_shutdown()
523 def kill(self) -> None:
525 Terminate the VM forcefully, wait for it to exit, and perform cleanup.
527 self.shutdown(hard=True)
529 def wait(self, timeout: Optional[int] = 30) -> None:
531 Wait for the VM to power off and perform post-shutdown cleanup.
533 :param timeout: Optional timeout in seconds. Default 30 seconds.
534 A value of `None` is an infinite wait.
536 self.shutdown(has_quit=True, timeout=timeout)
538 def set_qmp_monitor(self, enabled: bool = True) -> None:
542 @param enabled: if False, qmp monitor options will be removed from
543 the base arguments of the resulting QEMU command
544 line. Default is True.
545 @note: call this function before launch().
547 self._qmp_set = enabled
550 def _qmp(self) -> QEMUMonitorProtocol:
551 if self._qmp_connection is None:
552 raise QEMUMachineError("Attempt to access QMP with no connection")
553 return self._qmp_connection
556 def _qmp_args(cls, _conv_keys: bool = True, **args: Any) -> Dict[str, Any]:
558 for key, value in args.items():
560 qmp_args[key.replace('_', '-')] = value
562 qmp_args[key] = value
565 def qmp(self, cmd: str,
566 conv_keys: bool = True,
567 **args: Any) -> QMPMessage:
569 Invoke a QMP command and return the response dict
571 qmp_args = self._qmp_args(conv_keys, **args)
572 return self._qmp.cmd(cmd, args=qmp_args)
574 def command(self, cmd: str,
575 conv_keys: bool = True,
576 **args: Any) -> QMPReturnValue:
578 Invoke a QMP command.
579 On success return the response dict.
580 On failure raise an exception.
582 qmp_args = self._qmp_args(conv_keys, **args)
583 return self._qmp.command(cmd, **qmp_args)
585 def get_qmp_event(self, wait: bool = False) -> Optional[QMPMessage]:
587 Poll for one queued QMP events and return it
590 return self._events.pop(0)
591 return self._qmp.pull_event(wait=wait)
593 def get_qmp_events(self, wait: bool = False) -> List[QMPMessage]:
595 Poll for queued QMP events and return a list of dicts
597 events = self._qmp.get_events(wait=wait)
598 events.extend(self._events)
600 self._qmp.clear_events()
604 def event_match(event: Any, match: Optional[Any]) -> bool:
606 Check if an event matches optional match criteria.
608 The match criteria takes the form of a matching subdict. The event is
609 checked to be a superset of the subdict, recursively, with matching
610 values whenever the subdict values are not None.
612 This has a limitation that you cannot explicitly check for None values.
614 Examples, with the subdict queries on the left:
615 - None matches any object.
616 - {"foo": None} matches {"foo": {"bar": 1}}
617 - {"foo": None} matches {"foo": 5}
618 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
619 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
627 if not QEMUMachine.event_match(event[key], match[key]):
633 # either match or event wasn't iterable (not a dict)
634 return bool(match == event)
636 def event_wait(self, name: str,
637 timeout: float = 60.0,
638 match: Optional[QMPMessage] = None) -> Optional[QMPMessage]:
640 event_wait waits for and returns a named event from QMP with a timeout.
642 name: The event to wait for.
643 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
644 match: Optional match criteria. See event_match for details.
646 return self.events_wait([(name, match)], timeout)
648 def events_wait(self,
649 events: Sequence[Tuple[str, Any]],
650 timeout: float = 60.0) -> Optional[QMPMessage]:
652 events_wait waits for and returns a single named event from QMP.
653 In the case of multiple qualifying events, this function returns the
656 :param events: A sequence of (name, match_criteria) tuples.
657 The match criteria are optional and may be None.
658 See event_match for details.
659 :param timeout: Optional timeout, in seconds.
660 See QEMUMonitorProtocol.pull_event.
662 :raise QMPTimeoutError: If timeout was non-zero and no matching events
664 :return: A QMP event matching the filter criteria.
665 If timeout was 0 and no event matched, None.
667 def _match(event: QMPMessage) -> bool:
668 for name, match in events:
669 if event['event'] == name and self.event_match(event, match):
673 event: Optional[QMPMessage]
675 # Search cached events
676 for event in self._events:
678 self._events.remove(event)
681 # Poll for new events
683 event = self._qmp.pull_event(wait=timeout)
685 # NB: None is only returned when timeout is false-ish.
686 # Timeouts raise QMPTimeoutError instead!
690 self._events.append(event)
694 def get_log(self) -> Optional[str]:
696 After self.shutdown or failed qemu execution, this returns the output
701 def add_args(self, *args: str) -> None:
703 Adds to the list of extra arguments to be given to the QEMU binary
705 self._args.extend(args)
707 def set_machine(self, machine_type: str) -> None:
709 Sets the machine type
711 If set, the machine type will be added to the base arguments
712 of the resulting QEMU command line.
714 self._machine = machine_type
716 def set_console(self,
717 device_type: Optional[str] = None,
718 console_index: int = 0) -> None:
720 Sets the device type for a console device
722 If set, the console device and a backing character device will
723 be added to the base arguments of the resulting QEMU command
726 This is a convenience method that will either use the provided
727 device type, or default to a "-serial chardev:console" command
730 The actual setting of command line arguments will be be done at
731 machine launch time, as it depends on the temporary directory
734 @param device_type: the device type, such as "isa-serial". If
735 None is given (the default value) a "-serial
736 chardev:console" command line argument will
737 be used instead, resorting to the machine's
739 @param console_index: the index of the console device to use.
740 If not zero, the command line will create
741 'index - 1' consoles and connect them to
742 the 'null' backing character device.
744 self._console_set = True
745 self._console_device_type = device_type
746 self._console_index = console_index
749 def console_socket(self) -> socket.socket:
751 Returns a socket connected to the console
753 if self._console_socket is None:
754 self._console_socket = console_socket.ConsoleSocket(
755 self._console_address,
756 file=self._console_log_path,
757 drain=self._drain_console)
758 return self._console_socket
761 def temp_dir(self) -> str:
763 Returns a temporary directory to be used for this machine
765 if self._temp_dir is None:
766 self._temp_dir = tempfile.mkdtemp(prefix="qemu-machine-",
767 dir=self._base_temp_dir)
768 return self._temp_dir