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.
28 from typing import Optional, Type
29 from types import TracebackType
30 from qemu.console_socket import ConsoleSocket
34 LOG = logging.getLogger(__name__)
37 class QEMUMachineError(Exception):
39 Exception called when an error in QEMUMachine happens.
43 class QEMUMachineAddDeviceError(QEMUMachineError):
45 Exception raised when a request to add a device can not be fulfilled
47 The failures are caused by limitations, lack of information or conflicting
48 requests on the QEMUMachine methods. This exception does not represent
49 failures reported by the QEMU binary itself.
53 class AbnormalShutdown(QEMUMachineError):
55 Exception raised when a graceful shutdown was requested, but not performed.
59 class MonitorResponseError(qmp.QMPError):
61 Represents erroneous QMP monitor reply
63 def __init__(self, reply):
65 desc = reply["error"]["desc"]
68 super().__init__(desc)
76 Use this object as a context manager to ensure
77 the QEMU process terminates::
79 with VM(binary) as vm:
81 # vm is guaranteed to be shut down here
84 def __init__(self, binary, args=None, wrapper=None, name=None,
85 test_dir="/var/tmp", monitor_address=None,
86 socket_scm_helper=None, sock_dir=None,
87 drain_console=False, console_log=None):
89 Initialize a QEMUMachine
91 @param binary: path to the qemu binary
92 @param args: list of extra arguments
93 @param wrapper: list of arguments used as prefix to qemu binary
94 @param name: prefix for socket and log file names (default: qemu-PID)
95 @param test_dir: where to create socket and log file
96 @param monitor_address: address for QMP monitor
97 @param socket_scm_helper: helper program, required for send_fd_scm()
98 @param sock_dir: where to create socket (overrides test_dir for sock)
99 @param console_log: (optional) path to console log file
100 @param drain_console: (optional) True to drain console socket to buffer
101 @note: Qemu process is not started until launch() is used.
108 name = "qemu-%d" % os.getpid()
112 self._monitor_address = monitor_address
113 self._vm_monitor = None
114 self._qemu_log_path = None
115 self._qemu_log_file = None
117 self._binary = binary
118 self._args = list(args) # Force copy args in case we modify them
119 self._wrapper = wrapper
122 self._socket_scm_helper = socket_scm_helper
123 self._qmp_set = True # Enable QMP monitor by default.
125 self._qemu_full_args = None
126 self._test_dir = test_dir
127 self._temp_dir = None
128 self._sock_dir = sock_dir
129 self._launched = False
131 self._console_index = 0
132 self._console_set = False
133 self._console_device_type = None
134 self._console_address = None
135 self._console_socket = None
136 self._remove_files = []
137 self._user_killed = False
138 self._console_log_path = console_log
139 if self._console_log_path:
140 # In order to log the console, buffering needs to be enabled.
141 self._drain_console = True
143 self._drain_console = drain_console
149 exc_type: Optional[Type[BaseException]],
150 exc_val: Optional[BaseException],
151 exc_tb: Optional[TracebackType]) -> None:
154 def add_monitor_null(self):
156 This can be used to add an unused monitor instance.
158 self._args.append('-monitor')
159 self._args.append('null')
161 def add_fd(self, fd, fdset, opaque, opts=''):
163 Pass a file descriptor to the VM
165 options = ['fd=%d' % fd,
167 'opaque=%s' % opaque]
171 # This did not exist before 3.4, but since then it is
172 # mandatory for our purpose
173 if hasattr(os, 'set_inheritable'):
174 os.set_inheritable(fd, True)
176 self._args.append('-add-fd')
177 self._args.append(','.join(options))
180 def send_fd_scm(self, fd=None, file_path=None):
182 Send an fd or file_path to socket_scm_helper.
184 Exactly one of fd and file_path must be given.
185 If it is file_path, the helper will open that file and pass its own fd.
187 # In iotest.py, the qmp should always use unix socket.
188 assert self._qmp.is_scm_available()
189 if self._socket_scm_helper is None:
190 raise QEMUMachineError("No path to socket_scm_helper set")
191 if not os.path.exists(self._socket_scm_helper):
192 raise QEMUMachineError("%s does not exist" %
193 self._socket_scm_helper)
195 # This did not exist before 3.4, but since then it is
196 # mandatory for our purpose
197 if hasattr(os, 'set_inheritable'):
198 os.set_inheritable(self._qmp.get_sock_fd(), True)
200 os.set_inheritable(fd, True)
202 fd_param = ["%s" % self._socket_scm_helper,
203 "%d" % self._qmp.get_sock_fd()]
205 if file_path is not None:
207 fd_param.append(file_path)
209 assert fd is not None
210 fd_param.append(str(fd))
212 devnull = open(os.path.devnull, 'rb')
213 proc = subprocess.Popen(
214 fd_param, stdin=devnull, stdout=subprocess.PIPE,
215 stderr=subprocess.STDOUT, close_fds=False
217 output = proc.communicate()[0]
221 return proc.returncode
224 def _remove_if_exists(path):
226 Remove file object at path if it exists
230 except OSError as exception:
231 if exception.errno == errno.ENOENT:
235 def is_running(self):
236 """Returns true if the VM is running."""
237 return self._popen is not None and self._popen.poll() is None
240 """Returns the exit code if possible, or None."""
241 if self._popen is None:
243 return self._popen.poll()
246 """Returns the PID of the running process, or None."""
247 if not self.is_running():
249 return self._popen.pid
251 def _load_io_log(self):
252 if self._qemu_log_path is not None:
253 with open(self._qemu_log_path, "r") as iolog:
254 self._iolog = iolog.read()
256 def _base_args(self):
257 args = ['-display', 'none', '-vga', 'none']
259 if isinstance(self._monitor_address, tuple):
260 moncdev = "socket,id=mon,host=%s,port=%s" % (
261 self._monitor_address[0],
262 self._monitor_address[1])
264 moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
265 args.extend(['-chardev', moncdev, '-mon',
266 'chardev=mon,mode=control'])
267 if self._machine is not None:
268 args.extend(['-machine', self._machine])
269 for _ in range(self._console_index):
270 args.extend(['-serial', 'null'])
271 if self._console_set:
272 self._console_address = os.path.join(self._sock_dir,
273 self._name + "-console.sock")
274 self._remove_files.append(self._console_address)
275 chardev = ('socket,id=console,path=%s,server,nowait' %
276 self._console_address)
277 args.extend(['-chardev', chardev])
278 if self._console_device_type is None:
279 args.extend(['-serial', 'chardev:console'])
281 device = '%s,chardev=console' % self._console_device_type
282 args.extend(['-device', device])
285 def _pre_launch(self):
286 self._temp_dir = tempfile.mkdtemp(dir=self._test_dir)
287 self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
288 self._qemu_log_file = open(self._qemu_log_path, 'wb')
291 if self._monitor_address is not None:
292 self._vm_monitor = self._monitor_address
294 self._vm_monitor = os.path.join(self._sock_dir,
295 self._name + "-monitor.sock")
296 self._remove_files.append(self._vm_monitor)
297 self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True,
300 def _post_launch(self):
304 def _post_shutdown(self):
306 Called to cleanup the VM instance after the process has exited.
307 May also be called after a failed launch.
309 # Comprehensive reset for the failed launch case:
310 self._early_cleanup()
318 if self._qemu_log_file is not None:
319 self._qemu_log_file.close()
320 self._qemu_log_file = None
322 self._qemu_log_path = None
324 if self._temp_dir is not None:
325 shutil.rmtree(self._temp_dir)
326 self._temp_dir = None
328 while len(self._remove_files) > 0:
329 self._remove_if_exists(self._remove_files.pop())
331 exitcode = self.exitcode()
332 if (exitcode is not None and exitcode < 0
333 and not (self._user_killed and exitcode == -signal.SIGKILL)):
334 msg = 'qemu received signal %i; command: "%s"'
335 if self._qemu_full_args:
336 command = ' '.join(self._qemu_full_args)
339 LOG.warning(msg, -int(exitcode), command)
341 self._user_killed = False
342 self._launched = False
346 Launch the VM and make sure we cleanup and expose the
347 command line/output in case of exception
351 raise QEMUMachineError('VM already launched')
354 self._qemu_full_args = None
357 self._launched = True
359 self._post_shutdown()
361 LOG.debug('Error launching VM')
362 if self._qemu_full_args:
363 LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
365 LOG.debug('Output: %r', self._iolog)
370 Launch the VM and establish a QMP connection
372 devnull = open(os.path.devnull, 'rb')
374 self._qemu_full_args = (self._wrapper + [self._binary] +
375 self._base_args() + self._args)
376 LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
377 self._popen = subprocess.Popen(self._qemu_full_args,
379 stdout=self._qemu_log_file,
380 stderr=subprocess.STDOUT,
385 def _early_cleanup(self) -> None:
387 Perform any cleanup that needs to happen before the VM exits.
389 May be invoked by both soft and hard shutdown in failover scenarios.
390 Called additionally by _post_shutdown for comprehensive cleanup.
392 # If we keep the console socket open, we may deadlock waiting
393 # for QEMU to exit, while QEMU is waiting for the socket to
395 if self._console_socket is not None:
396 self._console_socket.close()
397 self._console_socket = None
399 def _hard_shutdown(self) -> None:
401 Perform early cleanup, kill the VM, and wait for it to terminate.
403 :raise subprocess.Timeout: When timeout is exceeds 60 seconds
404 waiting for the QEMU process to terminate.
406 self._early_cleanup()
408 self._popen.wait(timeout=60)
410 def _soft_shutdown(self, has_quit: bool = False,
411 timeout: Optional[int] = 3) -> None:
413 Perform early cleanup, attempt to gracefully shut down the VM, and wait
416 :param has_quit: When True, don't attempt to issue 'quit' QMP command
417 :param timeout: Optional timeout in seconds for graceful shutdown.
418 Default 3 seconds, A value of None is an infinite wait.
420 :raise ConnectionReset: On QMP communication errors
421 :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
422 the QEMU process to terminate.
424 self._early_cleanup()
426 if self._qmp is not None:
428 # Might raise ConnectionReset
429 self._qmp.cmd('quit')
431 # May raise subprocess.TimeoutExpired
432 self._popen.wait(timeout=timeout)
434 def _do_shutdown(self, has_quit: bool = False,
435 timeout: Optional[int] = 3) -> None:
437 Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
439 :param has_quit: When True, don't attempt to issue 'quit' QMP command
440 :param timeout: Optional timeout in seconds for graceful shutdown.
441 Default 3 seconds, A value of None is an infinite wait.
443 :raise AbnormalShutdown: When the VM could not be shut down gracefully.
444 The inner exception will likely be ConnectionReset or
445 subprocess.TimeoutExpired. In rare cases, non-graceful termination
446 may result in its own exceptions, likely subprocess.TimeoutExpired.
449 self._soft_shutdown(has_quit, timeout)
450 except Exception as exc:
451 self._hard_shutdown()
452 raise AbnormalShutdown("Could not perform graceful shutdown") \
455 def shutdown(self, has_quit: bool = False,
457 timeout: Optional[int] = 3) -> None:
459 Terminate the VM (gracefully if possible) and perform cleanup.
460 Cleanup will always be performed.
462 If the VM has not yet been launched, or shutdown(), wait(), or kill()
463 have already been called, this method does nothing.
465 :param has_quit: When true, do not attempt to issue 'quit' QMP command.
466 :param hard: When true, do not attempt graceful shutdown, and
467 suppress the SIGKILL warning log message.
468 :param timeout: Optional timeout in seconds for graceful shutdown.
469 Default 3 seconds, A value of None is an infinite wait.
471 if not self._launched:
476 self._user_killed = True
477 self._hard_shutdown()
479 self._do_shutdown(has_quit, timeout=timeout)
481 self._post_shutdown()
485 Terminate the VM forcefully, wait for it to exit, and perform cleanup.
487 self.shutdown(hard=True)
489 def wait(self, timeout: Optional[int] = 3) -> None:
491 Wait for the VM to power off and perform post-shutdown cleanup.
493 :param timeout: Optional timeout in seconds.
494 Default 3 seconds, A value of None is an infinite wait.
496 self.shutdown(has_quit=True, timeout=timeout)
498 def set_qmp_monitor(self, enabled=True):
502 @param enabled: if False, qmp monitor options will be removed from
503 the base arguments of the resulting QEMU command
504 line. Default is True.
505 @note: call this function before launch().
510 self._qmp_set = False
513 def qmp(self, cmd, conv_keys=True, **args):
515 Invoke a QMP command and return the response dict
518 for key, value in args.items():
520 qmp_args[key.replace('_', '-')] = value
522 qmp_args[key] = value
524 return self._qmp.cmd(cmd, args=qmp_args)
526 def command(self, cmd, conv_keys=True, **args):
528 Invoke a QMP command.
529 On success return the response dict.
530 On failure raise an exception.
532 reply = self.qmp(cmd, conv_keys, **args)
534 raise qmp.QMPError("Monitor is closed")
536 raise MonitorResponseError(reply)
537 return reply["return"]
539 def get_qmp_event(self, wait=False):
541 Poll for one queued QMP events and return it
544 return self._events.pop(0)
545 return self._qmp.pull_event(wait=wait)
547 def get_qmp_events(self, wait=False):
549 Poll for queued QMP events and return a list of dicts
551 events = self._qmp.get_events(wait=wait)
552 events.extend(self._events)
554 self._qmp.clear_events()
558 def event_match(event, match=None):
560 Check if an event matches optional match criteria.
562 The match criteria takes the form of a matching subdict. The event is
563 checked to be a superset of the subdict, recursively, with matching
564 values whenever the subdict values are not None.
566 This has a limitation that you cannot explicitly check for None values.
568 Examples, with the subdict queries on the left:
569 - None matches any object.
570 - {"foo": None} matches {"foo": {"bar": 1}}
571 - {"foo": None} matches {"foo": 5}
572 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
573 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
581 if not QEMUMachine.event_match(event[key], match[key]):
587 # either match or event wasn't iterable (not a dict)
588 return match == event
590 def event_wait(self, name, timeout=60.0, match=None):
592 event_wait waits for and returns a named event from QMP with a timeout.
594 name: The event to wait for.
595 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
596 match: Optional match criteria. See event_match for details.
598 return self.events_wait([(name, match)], timeout)
600 def events_wait(self, events, timeout=60.0):
602 events_wait waits for and returns a named event
603 from QMP with a timeout.
605 events: a sequence of (name, match_criteria) tuples.
606 The match criteria are optional and may be None.
607 See event_match for details.
608 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
611 for name, match in events:
612 if event['event'] == name and self.event_match(event, match):
616 # Search cached events
617 for event in self._events:
619 self._events.remove(event)
622 # Poll for new events
624 event = self._qmp.pull_event(wait=timeout)
627 self._events.append(event)
633 After self.shutdown or failed qemu execution, this returns the output
638 def add_args(self, *args):
640 Adds to the list of extra arguments to be given to the QEMU binary
642 self._args.extend(args)
644 def set_machine(self, machine_type):
646 Sets the machine type
648 If set, the machine type will be added to the base arguments
649 of the resulting QEMU command line.
651 self._machine = machine_type
653 def set_console(self, device_type=None, console_index=0):
655 Sets the device type for a console device
657 If set, the console device and a backing character device will
658 be added to the base arguments of the resulting QEMU command
661 This is a convenience method that will either use the provided
662 device type, or default to a "-serial chardev:console" command
665 The actual setting of command line arguments will be be done at
666 machine launch time, as it depends on the temporary directory
669 @param device_type: the device type, such as "isa-serial". If
670 None is given (the default value) a "-serial
671 chardev:console" command line argument will
672 be used instead, resorting to the machine's
674 @param console_index: the index of the console device to use.
675 If not zero, the command line will create
676 'index - 1' consoles and connect them to
677 the 'null' backing character device.
679 self._console_set = True
680 self._console_device_type = device_type
681 self._console_index = console_index
684 def console_socket(self):
686 Returns a socket connected to the console
688 if self._console_socket is None:
689 if self._drain_console:
690 self._console_socket = ConsoleSocket(self._console_address,
691 file=self._console_log_path)
693 self._console_socket = socket.socket(socket.AF_UNIX,
695 self._console_socket.connect(self._console_address)
696 return self._console_socket