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.
12 # Fam Zheng <famz@redhat.com>
14 # This work is licensed under the terms of the GNU GPL, version 2. See
15 # the COPYING file in the top-level directory.
27 from typing
import Optional
, Type
28 from types
import TracebackType
29 from qemu
.console_socket
import ConsoleSocket
33 LOG
= logging
.getLogger(__name__
)
36 class QEMUMachineError(Exception):
38 Exception called when an error in QEMUMachine happens.
42 class QEMUMachineAddDeviceError(QEMUMachineError
):
44 Exception raised when a request to add a device can not be fulfilled
46 The failures are caused by limitations, lack of information or conflicting
47 requests on the QEMUMachine methods. This exception does not represent
48 failures reported by the QEMU binary itself.
52 class MonitorResponseError(qmp
.QMPError
):
54 Represents erroneous QMP monitor reply
56 def __init__(self
, reply
):
58 desc
= reply
["error"]["desc"]
61 super().__init__(desc
)
69 Use this object as a context manager to ensure
70 the QEMU process terminates::
72 with VM(binary) as vm:
74 # vm is guaranteed to be shut down here
77 def __init__(self
, binary
, args
=None, wrapper
=None, name
=None,
78 test_dir
="/var/tmp", monitor_address
=None,
79 socket_scm_helper
=None, sock_dir
=None,
80 drain_console
=False, console_log
=None):
82 Initialize a QEMUMachine
84 @param binary: path to the qemu binary
85 @param args: list of extra arguments
86 @param wrapper: list of arguments used as prefix to qemu binary
87 @param name: prefix for socket and log file names (default: qemu-PID)
88 @param test_dir: where to create socket and log file
89 @param monitor_address: address for QMP monitor
90 @param socket_scm_helper: helper program, required for send_fd_scm()
91 @param sock_dir: where to create socket (overrides test_dir for sock)
92 @param console_log: (optional) path to console log file
93 @param drain_console: (optional) True to drain console socket to buffer
94 @note: Qemu process is not started until launch() is used.
101 name
= "qemu-%d" % os
.getpid()
105 self
._monitor_address
= monitor_address
106 self
._vm_monitor
= None
107 self
._qemu_log_path
= None
108 self
._qemu_log_file
= None
110 self
._binary
= binary
111 self
._args
= list(args
) # Force copy args in case we modify them
112 self
._wrapper
= wrapper
115 self
._socket_scm_helper
= socket_scm_helper
116 self
._qmp_set
= True # Enable QMP monitor by default.
118 self
._qemu_full_args
= None
119 self
._test_dir
= test_dir
120 self
._temp_dir
= None
121 self
._sock_dir
= sock_dir
122 self
._launched
= False
124 self
._console_index
= 0
125 self
._console_set
= False
126 self
._console_device_type
= None
127 self
._console_address
= None
128 self
._console_socket
= None
129 self
._remove_files
= []
130 self
._console_log_path
= console_log
131 if self
._console_log_path
:
132 # In order to log the console, buffering needs to be enabled.
133 self
._drain_console
= True
135 self
._drain_console
= drain_console
141 exc_type
: Optional
[Type
[BaseException
]],
142 exc_val
: Optional
[BaseException
],
143 exc_tb
: Optional
[TracebackType
]) -> None:
146 def add_monitor_null(self
):
148 This can be used to add an unused monitor instance.
150 self
._args
.append('-monitor')
151 self
._args
.append('null')
153 def add_fd(self
, fd
, fdset
, opaque
, opts
=''):
155 Pass a file descriptor to the VM
157 options
= ['fd=%d' % fd
,
159 'opaque=%s' % opaque
]
163 # This did not exist before 3.4, but since then it is
164 # mandatory for our purpose
165 if hasattr(os
, 'set_inheritable'):
166 os
.set_inheritable(fd
, True)
168 self
._args
.append('-add-fd')
169 self
._args
.append(','.join(options
))
172 def send_fd_scm(self
, fd
=None, file_path
=None):
174 Send an fd or file_path to socket_scm_helper.
176 Exactly one of fd and file_path must be given.
177 If it is file_path, the helper will open that file and pass its own fd.
179 # In iotest.py, the qmp should always use unix socket.
180 assert self
._qmp
.is_scm_available()
181 if self
._socket_scm_helper
is None:
182 raise QEMUMachineError("No path to socket_scm_helper set")
183 if not os
.path
.exists(self
._socket_scm_helper
):
184 raise QEMUMachineError("%s does not exist" %
185 self
._socket_scm_helper
)
187 # This did not exist before 3.4, but since then it is
188 # mandatory for our purpose
189 if hasattr(os
, 'set_inheritable'):
190 os
.set_inheritable(self
._qmp
.get_sock_fd(), True)
192 os
.set_inheritable(fd
, True)
194 fd_param
= ["%s" % self
._socket_scm_helper
,
195 "%d" % self
._qmp
.get_sock_fd()]
197 if file_path
is not None:
199 fd_param
.append(file_path
)
201 assert fd
is not None
202 fd_param
.append(str(fd
))
204 devnull
= open(os
.path
.devnull
, 'rb')
205 proc
= subprocess
.Popen(
206 fd_param
, stdin
=devnull
, stdout
=subprocess
.PIPE
,
207 stderr
=subprocess
.STDOUT
, close_fds
=False
209 output
= proc
.communicate()[0]
213 return proc
.returncode
216 def _remove_if_exists(path
):
218 Remove file object at path if it exists
222 except OSError as exception
:
223 if exception
.errno
== errno
.ENOENT
:
227 def is_running(self
):
228 """Returns true if the VM is running."""
229 return self
._popen
is not None and self
._popen
.poll() is None
232 """Returns the exit code if possible, or None."""
233 if self
._popen
is None:
235 return self
._popen
.poll()
238 """Returns the PID of the running process, or None."""
239 if not self
.is_running():
241 return self
._popen
.pid
243 def _load_io_log(self
):
244 if self
._qemu_log_path
is not None:
245 with
open(self
._qemu_log_path
, "r") as iolog
:
246 self
._iolog
= iolog
.read()
248 def _base_args(self
):
249 args
= ['-display', 'none', '-vga', 'none']
251 if isinstance(self
._monitor_address
, tuple):
252 moncdev
= "socket,id=mon,host=%s,port=%s" %
(
253 self
._monitor_address
[0],
254 self
._monitor_address
[1])
256 moncdev
= 'socket,id=mon,path=%s' % self
._vm_monitor
257 args
.extend(['-chardev', moncdev
, '-mon',
258 'chardev=mon,mode=control'])
259 if self
._machine
is not None:
260 args
.extend(['-machine', self
._machine
])
261 for _
in range(self
._console_index
):
262 args
.extend(['-serial', 'null'])
263 if self
._console_set
:
264 self
._console_address
= os
.path
.join(self
._sock_dir
,
265 self
._name
+ "-console.sock")
266 self
._remove_files
.append(self
._console_address
)
267 chardev
= ('socket,id=console,path=%s,server,nowait' %
268 self
._console_address
)
269 args
.extend(['-chardev', chardev
])
270 if self
._console_device_type
is None:
271 args
.extend(['-serial', 'chardev:console'])
273 device
= '%s,chardev=console' % self
._console_device_type
274 args
.extend(['-device', device
])
277 def _pre_launch(self
):
278 self
._temp_dir
= tempfile
.mkdtemp(dir=self
._test_dir
)
279 self
._qemu_log_path
= os
.path
.join(self
._temp_dir
, self
._name
+ ".log")
280 self
._qemu_log_file
= open(self
._qemu_log_path
, 'wb')
283 if self
._monitor_address
is not None:
284 self
._vm_monitor
= self
._monitor_address
286 self
._vm_monitor
= os
.path
.join(self
._sock_dir
,
287 self
._name
+ "-monitor.sock")
288 self
._remove_files
.append(self
._vm_monitor
)
289 self
._qmp
= qmp
.QEMUMonitorProtocol(self
._vm_monitor
, server
=True,
292 def _post_launch(self
):
296 def _post_shutdown(self
):
297 if self
._qemu_log_file
is not None:
298 self
._qemu_log_file
.close()
299 self
._qemu_log_file
= None
301 self
._qemu_log_path
= None
303 if self
._temp_dir
is not None:
304 shutil
.rmtree(self
._temp_dir
)
305 self
._temp_dir
= None
307 while len(self
._remove_files
) > 0:
308 self
._remove_if_exists(self
._remove_files
.pop())
312 Launch the VM and make sure we cleanup and expose the
313 command line/output in case of exception
317 raise QEMUMachineError('VM already launched')
320 self
._qemu_full_args
= None
323 self
._launched
= True
327 LOG
.debug('Error launching VM')
328 if self
._qemu_full_args
:
329 LOG
.debug('Command: %r', ' '.join(self
._qemu_full_args
))
331 LOG
.debug('Output: %r', self
._iolog
)
336 Launch the VM and establish a QMP connection
338 devnull
= open(os
.path
.devnull
, 'rb')
340 self
._qemu_full_args
= (self
._wrapper
+ [self
._binary
] +
341 self
._base_args() + self
._args
)
342 LOG
.debug('VM launch command: %r', ' '.join(self
._qemu_full_args
))
343 self
._popen
= subprocess
.Popen(self
._qemu_full_args
,
345 stdout
=self
._qemu_log_file
,
346 stderr
=subprocess
.STDOUT
,
353 Wait for the VM to power off
359 self
._post_shutdown()
361 def shutdown(self
, has_quit
=False, hard
=False):
363 Terminate the VM and clean up
365 # If we keep the console socket open, we may deadlock waiting
366 # for QEMU to exit, while QEMU is waiting for the socket to
368 if self
._console_socket
is not None:
369 self
._console_socket
.close()
370 self
._console_socket
= None
372 if self
.is_running():
378 self
._qmp
.cmd('quit')
380 self
._popen
.wait(timeout
=3)
386 self
._post_shutdown()
388 exitcode
= self
.exitcode()
389 if exitcode
is not None and exitcode
< 0 and \
390 not (exitcode
== -9 and hard
):
391 msg
= 'qemu received signal %i: %s'
392 if self
._qemu_full_args
:
393 command
= ' '.join(self
._qemu_full_args
)
396 LOG
.warning(msg
, -int(exitcode
), command
)
398 self
._launched
= False
401 self
.shutdown(hard
=True)
403 def set_qmp_monitor(self
, enabled
=True):
407 @param enabled: if False, qmp monitor options will be removed from
408 the base arguments of the resulting QEMU command
409 line. Default is True.
410 @note: call this function before launch().
415 self
._qmp_set
= False
418 def qmp(self
, cmd
, conv_keys
=True, **args
):
420 Invoke a QMP command and return the response dict
423 for key
, value
in args
.items():
425 qmp_args
[key
.replace('_', '-')] = value
427 qmp_args
[key
] = value
429 return self
._qmp
.cmd(cmd
, args
=qmp_args
)
431 def command(self
, cmd
, conv_keys
=True, **args
):
433 Invoke a QMP command.
434 On success return the response dict.
435 On failure raise an exception.
437 reply
= self
.qmp(cmd
, conv_keys
, **args
)
439 raise qmp
.QMPError("Monitor is closed")
441 raise MonitorResponseError(reply
)
442 return reply
["return"]
444 def get_qmp_event(self
, wait
=False):
446 Poll for one queued QMP events and return it
449 return self
._events
.pop(0)
450 return self
._qmp
.pull_event(wait
=wait
)
452 def get_qmp_events(self
, wait
=False):
454 Poll for queued QMP events and return a list of dicts
456 events
= self
._qmp
.get_events(wait
=wait
)
457 events
.extend(self
._events
)
459 self
._qmp
.clear_events()
463 def event_match(event
, match
=None):
465 Check if an event matches optional match criteria.
467 The match criteria takes the form of a matching subdict. The event is
468 checked to be a superset of the subdict, recursively, with matching
469 values whenever the subdict values are not None.
471 This has a limitation that you cannot explicitly check for None values.
473 Examples, with the subdict queries on the left:
474 - None matches any object.
475 - {"foo": None} matches {"foo": {"bar": 1}}
476 - {"foo": None} matches {"foo": 5}
477 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
478 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
486 if not QEMUMachine
.event_match(event
[key
], match
[key
]):
492 # either match or event wasn't iterable (not a dict)
493 return match
== event
495 def event_wait(self
, name
, timeout
=60.0, match
=None):
497 event_wait waits for and returns a named event from QMP with a timeout.
499 name: The event to wait for.
500 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
501 match: Optional match criteria. See event_match for details.
503 return self
.events_wait([(name
, match
)], timeout
)
505 def events_wait(self
, events
, timeout
=60.0):
507 events_wait waits for and returns a named event
508 from QMP with a timeout.
510 events: a sequence of (name, match_criteria) tuples.
511 The match criteria are optional and may be None.
512 See event_match for details.
513 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
516 for name
, match
in events
:
517 if event
['event'] == name
and self
.event_match(event
, match
):
521 # Search cached events
522 for event
in self
._events
:
524 self
._events
.remove(event
)
527 # Poll for new events
529 event
= self
._qmp
.pull_event(wait
=timeout
)
532 self
._events
.append(event
)
538 After self.shutdown or failed qemu execution, this returns the output
543 def add_args(self
, *args
):
545 Adds to the list of extra arguments to be given to the QEMU binary
547 self
._args
.extend(args
)
549 def set_machine(self
, machine_type
):
551 Sets the machine type
553 If set, the machine type will be added to the base arguments
554 of the resulting QEMU command line.
556 self
._machine
= machine_type
558 def set_console(self
, device_type
=None, console_index
=0):
560 Sets the device type for a console device
562 If set, the console device and a backing character device will
563 be added to the base arguments of the resulting QEMU command
566 This is a convenience method that will either use the provided
567 device type, or default to a "-serial chardev:console" command
570 The actual setting of command line arguments will be be done at
571 machine launch time, as it depends on the temporary directory
574 @param device_type: the device type, such as "isa-serial". If
575 None is given (the default value) a "-serial
576 chardev:console" command line argument will
577 be used instead, resorting to the machine's
579 @param console_index: the index of the console device to use.
580 If not zero, the command line will create
581 'index - 1' consoles and connect them to
582 the 'null' backing character device.
584 self
._console_set
= True
585 self
._console_device_type
= device_type
586 self
._console_index
= console_index
589 def console_socket(self
):
591 Returns a socket connected to the console
593 if self
._console_socket
is None:
594 if self
._drain_console
:
595 self
._console_socket
= ConsoleSocket(self
._console_address
,
596 file=self
._console_log_path
)
598 self
._console_socket
= socket
.socket(socket
.AF_UNIX
,
600 self
._console_socket
.connect(self
._console_address
)
601 return self
._console_socket