]> git.proxmox.com Git - mirror_qemu.git/blame - python/qemu/machine.py
Merge remote-tracking branch 'remotes/armbru/tags/pull-error-2020-07-24' into staging
[mirror_qemu.git] / python / qemu / machine.py
CommitLineData
306dfcd6
JS
1"""
2QEMU machine module:
3
4The machine module primarily provides the QEMUMachine class,
5which provides facilities for managing the lifetime of a QEMU VM.
6"""
7
abf0bf99
JS
8# Copyright (C) 2015-2016 Red Hat Inc.
9# Copyright (C) 2012 IBM Corp.
10#
11# Authors:
12# Fam Zheng <famz@redhat.com>
13#
14# This work is licensed under the terms of the GNU GPL, version 2. See
15# the COPYING file in the top-level directory.
16#
17# Based on qmp.py.
18#
19
20import errno
21import logging
22import os
23import subprocess
abf0bf99 24import shutil
de6e08b5 25import signal
abf0bf99
JS
26import socket
27import tempfile
1dda0404
JS
28from typing import Optional, Type
29from types import TracebackType
0fc8f660 30from qemu.console_socket import ConsoleSocket
abf0bf99
JS
31
32from . import qmp
33
34LOG = logging.getLogger(__name__)
35
8dfac2ed 36
abf0bf99
JS
37class QEMUMachineError(Exception):
38 """
39 Exception called when an error in QEMUMachine happens.
40 """
41
42
43class QEMUMachineAddDeviceError(QEMUMachineError):
44 """
45 Exception raised when a request to add a device can not be fulfilled
46
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.
50 """
51
52
193bf1c0
JS
53class AbnormalShutdown(QEMUMachineError):
54 """
55 Exception raised when a graceful shutdown was requested, but not performed.
56 """
57
58
9b8ccd6d 59class QEMUMachine:
abf0bf99
JS
60 """
61 A QEMU VM
62
8dfac2ed
JS
63 Use this object as a context manager to ensure
64 the QEMU process terminates::
abf0bf99
JS
65
66 with VM(binary) as vm:
67 ...
68 # vm is guaranteed to be shut down here
69 """
70
71 def __init__(self, binary, args=None, wrapper=None, name=None,
72 test_dir="/var/tmp", monitor_address=None,
0fc8f660
RF
73 socket_scm_helper=None, sock_dir=None,
74 drain_console=False, console_log=None):
abf0bf99
JS
75 '''
76 Initialize a QEMUMachine
77
78 @param binary: path to the qemu binary
79 @param args: list of extra arguments
80 @param wrapper: list of arguments used as prefix to qemu binary
81 @param name: prefix for socket and log file names (default: qemu-PID)
82 @param test_dir: where to create socket and log file
83 @param monitor_address: address for QMP monitor
84 @param socket_scm_helper: helper program, required for send_fd_scm()
0fc8f660
RF
85 @param sock_dir: where to create socket (overrides test_dir for sock)
86 @param console_log: (optional) path to console log file
87 @param drain_console: (optional) True to drain console socket to buffer
abf0bf99
JS
88 @note: Qemu process is not started until launch() is used.
89 '''
90 if args is None:
91 args = []
92 if wrapper is None:
93 wrapper = []
94 if name is None:
95 name = "qemu-%d" % os.getpid()
32558ce7
HR
96 if sock_dir is None:
97 sock_dir = test_dir
abf0bf99
JS
98 self._name = name
99 self._monitor_address = monitor_address
100 self._vm_monitor = None
101 self._qemu_log_path = None
102 self._qemu_log_file = None
103 self._popen = None
104 self._binary = binary
105 self._args = list(args) # Force copy args in case we modify them
106 self._wrapper = wrapper
107 self._events = []
108 self._iolog = None
109 self._socket_scm_helper = socket_scm_helper
74b56bb5 110 self._qmp_set = True # Enable QMP monitor by default.
abf0bf99
JS
111 self._qmp = None
112 self._qemu_full_args = None
113 self._test_dir = test_dir
114 self._temp_dir = None
32558ce7 115 self._sock_dir = sock_dir
abf0bf99
JS
116 self._launched = False
117 self._machine = None
746f244d 118 self._console_index = 0
abf0bf99
JS
119 self._console_set = False
120 self._console_device_type = None
121 self._console_address = None
122 self._console_socket = None
32558ce7 123 self._remove_files = []
de6e08b5 124 self._user_killed = False
0fc8f660
RF
125 self._console_log_path = console_log
126 if self._console_log_path:
127 # In order to log the console, buffering needs to be enabled.
128 self._drain_console = True
129 else:
130 self._drain_console = drain_console
abf0bf99 131
abf0bf99
JS
132 def __enter__(self):
133 return self
134
1dda0404
JS
135 def __exit__(self,
136 exc_type: Optional[Type[BaseException]],
137 exc_val: Optional[BaseException],
138 exc_tb: Optional[TracebackType]) -> None:
abf0bf99 139 self.shutdown()
abf0bf99 140
abf0bf99 141 def add_monitor_null(self):
306dfcd6
JS
142 """
143 This can be used to add an unused monitor instance.
144 """
abf0bf99
JS
145 self._args.append('-monitor')
146 self._args.append('null')
147
148 def add_fd(self, fd, fdset, opaque, opts=''):
149 """
150 Pass a file descriptor to the VM
151 """
152 options = ['fd=%d' % fd,
153 'set=%d' % fdset,
154 'opaque=%s' % opaque]
155 if opts:
156 options.append(opts)
157
158 # This did not exist before 3.4, but since then it is
159 # mandatory for our purpose
160 if hasattr(os, 'set_inheritable'):
161 os.set_inheritable(fd, True)
162
163 self._args.append('-add-fd')
164 self._args.append(','.join(options))
165 return self
166
abf0bf99 167 def send_fd_scm(self, fd=None, file_path=None):
306dfcd6
JS
168 """
169 Send an fd or file_path to socket_scm_helper.
170
171 Exactly one of fd and file_path must be given.
172 If it is file_path, the helper will open that file and pass its own fd.
173 """
abf0bf99
JS
174 # In iotest.py, the qmp should always use unix socket.
175 assert self._qmp.is_scm_available()
176 if self._socket_scm_helper is None:
177 raise QEMUMachineError("No path to socket_scm_helper set")
178 if not os.path.exists(self._socket_scm_helper):
179 raise QEMUMachineError("%s does not exist" %
180 self._socket_scm_helper)
181
182 # This did not exist before 3.4, but since then it is
183 # mandatory for our purpose
184 if hasattr(os, 'set_inheritable'):
185 os.set_inheritable(self._qmp.get_sock_fd(), True)
186 if fd is not None:
187 os.set_inheritable(fd, True)
188
189 fd_param = ["%s" % self._socket_scm_helper,
190 "%d" % self._qmp.get_sock_fd()]
191
192 if file_path is not None:
193 assert fd is None
194 fd_param.append(file_path)
195 else:
196 assert fd is not None
197 fd_param.append(str(fd))
198
199 devnull = open(os.path.devnull, 'rb')
8dfac2ed
JS
200 proc = subprocess.Popen(
201 fd_param, stdin=devnull, stdout=subprocess.PIPE,
202 stderr=subprocess.STDOUT, close_fds=False
203 )
abf0bf99
JS
204 output = proc.communicate()[0]
205 if output:
206 LOG.debug(output)
207
208 return proc.returncode
209
210 @staticmethod
211 def _remove_if_exists(path):
212 """
213 Remove file object at path if it exists
214 """
215 try:
216 os.remove(path)
217 except OSError as exception:
218 if exception.errno == errno.ENOENT:
219 return
220 raise
221
222 def is_running(self):
306dfcd6 223 """Returns true if the VM is running."""
abf0bf99
JS
224 return self._popen is not None and self._popen.poll() is None
225
226 def exitcode(self):
306dfcd6 227 """Returns the exit code if possible, or None."""
abf0bf99
JS
228 if self._popen is None:
229 return None
230 return self._popen.poll()
231
232 def get_pid(self):
306dfcd6 233 """Returns the PID of the running process, or None."""
abf0bf99
JS
234 if not self.is_running():
235 return None
236 return self._popen.pid
237
238 def _load_io_log(self):
239 if self._qemu_log_path is not None:
240 with open(self._qemu_log_path, "r") as iolog:
241 self._iolog = iolog.read()
242
243 def _base_args(self):
74b56bb5
WSM
244 args = ['-display', 'none', '-vga', 'none']
245 if self._qmp_set:
246 if isinstance(self._monitor_address, tuple):
247 moncdev = "socket,id=mon,host=%s,port=%s" % (
248 self._monitor_address[0],
249 self._monitor_address[1])
250 else:
251 moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
252 args.extend(['-chardev', moncdev, '-mon',
253 'chardev=mon,mode=control'])
abf0bf99
JS
254 if self._machine is not None:
255 args.extend(['-machine', self._machine])
9b8ccd6d 256 for _ in range(self._console_index):
746f244d 257 args.extend(['-serial', 'null'])
abf0bf99 258 if self._console_set:
32558ce7 259 self._console_address = os.path.join(self._sock_dir,
abf0bf99 260 self._name + "-console.sock")
32558ce7 261 self._remove_files.append(self._console_address)
abf0bf99
JS
262 chardev = ('socket,id=console,path=%s,server,nowait' %
263 self._console_address)
264 args.extend(['-chardev', chardev])
265 if self._console_device_type is None:
266 args.extend(['-serial', 'chardev:console'])
267 else:
268 device = '%s,chardev=console' % self._console_device_type
269 args.extend(['-device', device])
270 return args
271
272 def _pre_launch(self):
273 self._temp_dir = tempfile.mkdtemp(dir=self._test_dir)
abf0bf99
JS
274 self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
275 self._qemu_log_file = open(self._qemu_log_path, 'wb')
276
74b56bb5
WSM
277 if self._qmp_set:
278 if self._monitor_address is not None:
279 self._vm_monitor = self._monitor_address
280 else:
281 self._vm_monitor = os.path.join(self._sock_dir,
282 self._name + "-monitor.sock")
283 self._remove_files.append(self._vm_monitor)
566054a0
OV
284 self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True,
285 nickname=self._name)
abf0bf99
JS
286
287 def _post_launch(self):
74b56bb5
WSM
288 if self._qmp:
289 self._qmp.accept()
abf0bf99
JS
290
291 def _post_shutdown(self):
a3842cb0
JS
292 """
293 Called to cleanup the VM instance after the process has exited.
294 May also be called after a failed launch.
295 """
296 # Comprehensive reset for the failed launch case:
297 self._early_cleanup()
298
671940e6
JS
299 if self._qmp:
300 self._qmp.close()
301 self._qmp = None
302
14661d93
JS
303 self._load_io_log()
304
abf0bf99
JS
305 if self._qemu_log_file is not None:
306 self._qemu_log_file.close()
307 self._qemu_log_file = None
308
309 self._qemu_log_path = None
310
abf0bf99
JS
311 if self._temp_dir is not None:
312 shutil.rmtree(self._temp_dir)
313 self._temp_dir = None
314
32558ce7
HR
315 while len(self._remove_files) > 0:
316 self._remove_if_exists(self._remove_files.pop())
317
14661d93 318 exitcode = self.exitcode()
de6e08b5
JS
319 if (exitcode is not None and exitcode < 0
320 and not (self._user_killed and exitcode == -signal.SIGKILL)):
14661d93
JS
321 msg = 'qemu received signal %i; command: "%s"'
322 if self._qemu_full_args:
323 command = ' '.join(self._qemu_full_args)
324 else:
325 command = ''
326 LOG.warning(msg, -int(exitcode), command)
327
de6e08b5 328 self._user_killed = False
14661d93
JS
329 self._launched = False
330
abf0bf99
JS
331 def launch(self):
332 """
333 Launch the VM and make sure we cleanup and expose the
334 command line/output in case of exception
335 """
336
337 if self._launched:
338 raise QEMUMachineError('VM already launched')
339
340 self._iolog = None
341 self._qemu_full_args = None
342 try:
343 self._launch()
344 self._launched = True
345 except:
a3842cb0 346 self._post_shutdown()
abf0bf99
JS
347
348 LOG.debug('Error launching VM')
349 if self._qemu_full_args:
350 LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
351 if self._iolog:
352 LOG.debug('Output: %r', self._iolog)
353 raise
354
355 def _launch(self):
356 """
357 Launch the VM and establish a QMP connection
358 """
359 devnull = open(os.path.devnull, 'rb')
360 self._pre_launch()
361 self._qemu_full_args = (self._wrapper + [self._binary] +
362 self._base_args() + self._args)
363 LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
364 self._popen = subprocess.Popen(self._qemu_full_args,
365 stdin=devnull,
366 stdout=self._qemu_log_file,
367 stderr=subprocess.STDOUT,
368 shell=False,
369 close_fds=False)
370 self._post_launch()
371
e2c97f16
JS
372 def _early_cleanup(self) -> None:
373 """
374 Perform any cleanup that needs to happen before the VM exits.
a3842cb0 375
193bf1c0 376 May be invoked by both soft and hard shutdown in failover scenarios.
a3842cb0 377 Called additionally by _post_shutdown for comprehensive cleanup.
e2c97f16
JS
378 """
379 # If we keep the console socket open, we may deadlock waiting
380 # for QEMU to exit, while QEMU is waiting for the socket to
381 # become writeable.
382 if self._console_socket is not None:
383 self._console_socket.close()
384 self._console_socket = None
385
193bf1c0
JS
386 def _hard_shutdown(self) -> None:
387 """
388 Perform early cleanup, kill the VM, and wait for it to terminate.
389
390 :raise subprocess.Timeout: When timeout is exceeds 60 seconds
391 waiting for the QEMU process to terminate.
392 """
393 self._early_cleanup()
394 self._popen.kill()
395 self._popen.wait(timeout=60)
396
397 def _soft_shutdown(self, has_quit: bool = False,
398 timeout: Optional[int] = 3) -> None:
399 """
400 Perform early cleanup, attempt to gracefully shut down the VM, and wait
401 for it to terminate.
402
403 :param has_quit: When True, don't attempt to issue 'quit' QMP command
404 :param timeout: Optional timeout in seconds for graceful shutdown.
405 Default 3 seconds, A value of None is an infinite wait.
406
407 :raise ConnectionReset: On QMP communication errors
408 :raise subprocess.TimeoutExpired: When timeout is exceeded waiting for
409 the QEMU process to terminate.
410 """
411 self._early_cleanup()
412
413 if self._qmp is not None:
414 if not has_quit:
415 # Might raise ConnectionReset
416 self._qmp.cmd('quit')
417
418 # May raise subprocess.TimeoutExpired
419 self._popen.wait(timeout=timeout)
420
421 def _do_shutdown(self, has_quit: bool = False,
422 timeout: Optional[int] = 3) -> None:
423 """
424 Attempt to shutdown the VM gracefully; fallback to a hard shutdown.
425
426 :param has_quit: When True, don't attempt to issue 'quit' QMP command
427 :param timeout: Optional timeout in seconds for graceful shutdown.
428 Default 3 seconds, A value of None is an infinite wait.
429
430 :raise AbnormalShutdown: When the VM could not be shut down gracefully.
431 The inner exception will likely be ConnectionReset or
432 subprocess.TimeoutExpired. In rare cases, non-graceful termination
433 may result in its own exceptions, likely subprocess.TimeoutExpired.
434 """
435 try:
436 self._soft_shutdown(has_quit, timeout)
437 except Exception as exc:
438 self._hard_shutdown()
439 raise AbnormalShutdown("Could not perform graceful shutdown") \
440 from exc
441
c9b3045b
JS
442 def shutdown(self, has_quit: bool = False,
443 hard: bool = False,
444 timeout: Optional[int] = 3) -> None:
abf0bf99 445 """
193bf1c0
JS
446 Terminate the VM (gracefully if possible) and perform cleanup.
447 Cleanup will always be performed.
448
449 If the VM has not yet been launched, or shutdown(), wait(), or kill()
450 have already been called, this method does nothing.
451
452 :param has_quit: When true, do not attempt to issue 'quit' QMP command.
453 :param hard: When true, do not attempt graceful shutdown, and
454 suppress the SIGKILL warning log message.
455 :param timeout: Optional timeout in seconds for graceful shutdown.
456 Default 3 seconds, A value of None is an infinite wait.
abf0bf99 457 """
a3842cb0
JS
458 if not self._launched:
459 return
460
193bf1c0 461 try:
e0e925a6 462 if hard:
de6e08b5 463 self._user_killed = True
193bf1c0
JS
464 self._hard_shutdown()
465 else:
466 self._do_shutdown(has_quit, timeout=timeout)
467 finally:
468 self._post_shutdown()
abf0bf99 469
e0e925a6 470 def kill(self):
193bf1c0
JS
471 """
472 Terminate the VM forcefully, wait for it to exit, and perform cleanup.
473 """
e0e925a6
VSO
474 self.shutdown(hard=True)
475
04f0e36e 476 def wait(self, timeout: Optional[int] = 3) -> None:
89528059
JS
477 """
478 Wait for the VM to power off and perform post-shutdown cleanup.
479
480 :param timeout: Optional timeout in seconds.
04f0e36e 481 Default 3 seconds, A value of None is an infinite wait.
89528059
JS
482 """
483 self.shutdown(has_quit=True, timeout=timeout)
484
74b56bb5
WSM
485 def set_qmp_monitor(self, enabled=True):
486 """
487 Set the QMP monitor.
488
489 @param enabled: if False, qmp monitor options will be removed from
490 the base arguments of the resulting QEMU command
491 line. Default is True.
492 @note: call this function before launch().
493 """
494 if enabled:
495 self._qmp_set = True
496 else:
497 self._qmp_set = False
498 self._qmp = None
499
abf0bf99
JS
500 def qmp(self, cmd, conv_keys=True, **args):
501 """
502 Invoke a QMP command and return the response dict
503 """
504 qmp_args = dict()
505 for key, value in args.items():
506 if conv_keys:
507 qmp_args[key.replace('_', '-')] = value
508 else:
509 qmp_args[key] = value
510
511 return self._qmp.cmd(cmd, args=qmp_args)
512
513 def command(self, cmd, conv_keys=True, **args):
514 """
515 Invoke a QMP command.
516 On success return the response dict.
517 On failure raise an exception.
518 """
519 reply = self.qmp(cmd, conv_keys, **args)
520 if reply is None:
521 raise qmp.QMPError("Monitor is closed")
522 if "error" in reply:
e3a23b48 523 raise qmp.QMPResponseError(reply)
abf0bf99
JS
524 return reply["return"]
525
526 def get_qmp_event(self, wait=False):
527 """
528 Poll for one queued QMP events and return it
529 """
306dfcd6 530 if self._events:
abf0bf99
JS
531 return self._events.pop(0)
532 return self._qmp.pull_event(wait=wait)
533
534 def get_qmp_events(self, wait=False):
535 """
536 Poll for queued QMP events and return a list of dicts
537 """
538 events = self._qmp.get_events(wait=wait)
539 events.extend(self._events)
540 del self._events[:]
541 self._qmp.clear_events()
542 return events
543
544 @staticmethod
545 def event_match(event, match=None):
546 """
547 Check if an event matches optional match criteria.
548
549 The match criteria takes the form of a matching subdict. The event is
550 checked to be a superset of the subdict, recursively, with matching
551 values whenever the subdict values are not None.
552
553 This has a limitation that you cannot explicitly check for None values.
554
555 Examples, with the subdict queries on the left:
556 - None matches any object.
557 - {"foo": None} matches {"foo": {"bar": 1}}
558 - {"foo": None} matches {"foo": 5}
559 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
560 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
561 """
562 if match is None:
563 return True
564
565 try:
566 for key in match:
567 if key in event:
568 if not QEMUMachine.event_match(event[key], match[key]):
569 return False
570 else:
571 return False
572 return True
573 except TypeError:
574 # either match or event wasn't iterable (not a dict)
575 return match == event
576
577 def event_wait(self, name, timeout=60.0, match=None):
578 """
579 event_wait waits for and returns a named event from QMP with a timeout.
580
581 name: The event to wait for.
582 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
583 match: Optional match criteria. See event_match for details.
584 """
585 return self.events_wait([(name, match)], timeout)
586
587 def events_wait(self, events, timeout=60.0):
588 """
8dfac2ed
JS
589 events_wait waits for and returns a named event
590 from QMP with a timeout.
abf0bf99
JS
591
592 events: a sequence of (name, match_criteria) tuples.
593 The match criteria are optional and may be None.
594 See event_match for details.
595 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
596 """
597 def _match(event):
598 for name, match in events:
306dfcd6 599 if event['event'] == name and self.event_match(event, match):
abf0bf99
JS
600 return True
601 return False
602
603 # Search cached events
604 for event in self._events:
605 if _match(event):
606 self._events.remove(event)
607 return event
608
609 # Poll for new events
610 while True:
611 event = self._qmp.pull_event(wait=timeout)
612 if _match(event):
613 return event
614 self._events.append(event)
615
616 return None
617
618 def get_log(self):
619 """
620 After self.shutdown or failed qemu execution, this returns the output
621 of the qemu process.
622 """
623 return self._iolog
624
625 def add_args(self, *args):
626 """
627 Adds to the list of extra arguments to be given to the QEMU binary
628 """
629 self._args.extend(args)
630
631 def set_machine(self, machine_type):
632 """
633 Sets the machine type
634
635 If set, the machine type will be added to the base arguments
636 of the resulting QEMU command line.
637 """
638 self._machine = machine_type
639
746f244d 640 def set_console(self, device_type=None, console_index=0):
abf0bf99
JS
641 """
642 Sets the device type for a console device
643
644 If set, the console device and a backing character device will
645 be added to the base arguments of the resulting QEMU command
646 line.
647
648 This is a convenience method that will either use the provided
649 device type, or default to a "-serial chardev:console" command
650 line argument.
651
652 The actual setting of command line arguments will be be done at
653 machine launch time, as it depends on the temporary directory
654 to be created.
655
656 @param device_type: the device type, such as "isa-serial". If
657 None is given (the default value) a "-serial
658 chardev:console" command line argument will
659 be used instead, resorting to the machine's
660 default device type.
746f244d
PMD
661 @param console_index: the index of the console device to use.
662 If not zero, the command line will create
663 'index - 1' consoles and connect them to
664 the 'null' backing character device.
abf0bf99
JS
665 """
666 self._console_set = True
667 self._console_device_type = device_type
746f244d 668 self._console_index = console_index
abf0bf99
JS
669
670 @property
671 def console_socket(self):
672 """
673 Returns a socket connected to the console
674 """
675 if self._console_socket is None:
0fc8f660
RF
676 if self._drain_console:
677 self._console_socket = ConsoleSocket(self._console_address,
678 file=self._console_log_path)
679 else:
680 self._console_socket = socket.socket(socket.AF_UNIX,
681 socket.SOCK_STREAM)
682 self._console_socket.connect(self._console_address)
abf0bf99 683 return self._console_socket