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.
30 LOG
= logging
.getLogger(__name__
)
32 class QEMUMachineError(Exception):
34 Exception called when an error in QEMUMachine happens.
38 class QEMUMachineAddDeviceError(QEMUMachineError
):
40 Exception raised when a request to add a device can not be fulfilled
42 The failures are caused by limitations, lack of information or conflicting
43 requests on the QEMUMachine methods. This exception does not represent
44 failures reported by the QEMU binary itself.
48 class MonitorResponseError(qmp
.QMPError
):
50 Represents erroneous QMP monitor reply
52 def __init__(self
, reply
):
54 desc
= reply
["error"]["desc"]
57 super(MonitorResponseError
, self
).__init
__(desc
)
61 class QEMUMachine(object):
65 Use this object as a context manager to ensure the QEMU process terminates::
67 with VM(binary) as vm:
69 # vm is guaranteed to be shut down here
72 def __init__(self
, binary
, args
=None, wrapper
=None, name
=None,
73 test_dir
="/var/tmp", monitor_address
=None,
74 socket_scm_helper
=None, sock_dir
=None):
76 Initialize a QEMUMachine
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()
85 @note: Qemu process is not started until launch() is used.
92 name
= "qemu-%d" % os
.getpid()
96 self
._monitor
_address
= monitor_address
97 self
._vm
_monitor
= None
98 self
._qemu
_log
_path
= None
99 self
._qemu
_log
_file
= None
101 self
._binary
= binary
102 self
._args
= list(args
) # Force copy args in case we modify them
103 self
._wrapper
= wrapper
106 self
._socket
_scm
_helper
= socket_scm_helper
107 self
._qmp
_set
= True # Enable QMP monitor by default.
109 self
._qemu
_full
_args
= None
110 self
._test
_dir
= test_dir
111 self
._temp
_dir
= None
112 self
._sock
_dir
= sock_dir
113 self
._launched
= False
115 self
._console
_set
= False
116 self
._console
_device
_type
= None
117 self
._console
_address
= None
118 self
._console
_socket
= None
119 self
._remove
_files
= []
121 # just in case logging wasn't configured by the main script:
122 logging
.basicConfig()
127 def __exit__(self
, exc_type
, exc_val
, exc_tb
):
131 def add_monitor_null(self
):
133 This can be used to add an unused monitor instance.
135 self
._args
.append('-monitor')
136 self
._args
.append('null')
138 def add_fd(self
, fd
, fdset
, opaque
, opts
=''):
140 Pass a file descriptor to the VM
142 options
= ['fd=%d' % fd
,
144 'opaque=%s' % opaque
]
148 # This did not exist before 3.4, but since then it is
149 # mandatory for our purpose
150 if hasattr(os
, 'set_inheritable'):
151 os
.set_inheritable(fd
, True)
153 self
._args
.append('-add-fd')
154 self
._args
.append(','.join(options
))
157 def send_fd_scm(self
, fd
=None, file_path
=None):
159 Send an fd or file_path to socket_scm_helper.
161 Exactly one of fd and file_path must be given.
162 If it is file_path, the helper will open that file and pass its own fd.
164 # In iotest.py, the qmp should always use unix socket.
165 assert self
._qmp
.is_scm_available()
166 if self
._socket
_scm
_helper
is None:
167 raise QEMUMachineError("No path to socket_scm_helper set")
168 if not os
.path
.exists(self
._socket
_scm
_helper
):
169 raise QEMUMachineError("%s does not exist" %
170 self
._socket
_scm
_helper
)
172 # This did not exist before 3.4, but since then it is
173 # mandatory for our purpose
174 if hasattr(os
, 'set_inheritable'):
175 os
.set_inheritable(self
._qmp
.get_sock_fd(), True)
177 os
.set_inheritable(fd
, True)
179 fd_param
= ["%s" % self
._socket
_scm
_helper
,
180 "%d" % self
._qmp
.get_sock_fd()]
182 if file_path
is not None:
184 fd_param
.append(file_path
)
186 assert fd
is not None
187 fd_param
.append(str(fd
))
189 devnull
= open(os
.path
.devnull
, 'rb')
190 proc
= subprocess
.Popen(fd_param
, stdin
=devnull
, stdout
=subprocess
.PIPE
,
191 stderr
=subprocess
.STDOUT
, close_fds
=False)
192 output
= proc
.communicate()[0]
196 return proc
.returncode
199 def _remove_if_exists(path
):
201 Remove file object at path if it exists
205 except OSError as exception
:
206 if exception
.errno
== errno
.ENOENT
:
210 def is_running(self
):
211 """Returns true if the VM is running."""
212 return self
._popen
is not None and self
._popen
.poll() is None
215 """Returns the exit code if possible, or None."""
216 if self
._popen
is None:
218 return self
._popen
.poll()
221 """Returns the PID of the running process, or None."""
222 if not self
.is_running():
224 return self
._popen
.pid
226 def _load_io_log(self
):
227 if self
._qemu
_log
_path
is not None:
228 with
open(self
._qemu
_log
_path
, "r") as iolog
:
229 self
._iolog
= iolog
.read()
231 def _base_args(self
):
232 args
= ['-display', 'none', '-vga', 'none']
234 if isinstance(self
._monitor
_address
, tuple):
235 moncdev
= "socket,id=mon,host=%s,port=%s" % (
236 self
._monitor
_address
[0],
237 self
._monitor
_address
[1])
239 moncdev
= 'socket,id=mon,path=%s' % self
._vm
_monitor
240 args
.extend(['-chardev', moncdev
, '-mon',
241 'chardev=mon,mode=control'])
242 if self
._machine
is not None:
243 args
.extend(['-machine', self
._machine
])
244 if self
._console
_set
:
245 self
._console
_address
= os
.path
.join(self
._sock
_dir
,
246 self
._name
+ "-console.sock")
247 self
._remove
_files
.append(self
._console
_address
)
248 chardev
= ('socket,id=console,path=%s,server,nowait' %
249 self
._console
_address
)
250 args
.extend(['-chardev', chardev
])
251 if self
._console
_device
_type
is None:
252 args
.extend(['-serial', 'chardev:console'])
254 device
= '%s,chardev=console' % self
._console
_device
_type
255 args
.extend(['-device', device
])
258 def _pre_launch(self
):
259 self
._temp
_dir
= tempfile
.mkdtemp(dir=self
._test
_dir
)
260 self
._qemu
_log
_path
= os
.path
.join(self
._temp
_dir
, self
._name
+ ".log")
261 self
._qemu
_log
_file
= open(self
._qemu
_log
_path
, 'wb')
264 if self
._monitor
_address
is not None:
265 self
._vm
_monitor
= self
._monitor
_address
267 self
._vm
_monitor
= os
.path
.join(self
._sock
_dir
,
268 self
._name
+ "-monitor.sock")
269 self
._remove
_files
.append(self
._vm
_monitor
)
270 self
._qmp
= qmp
.QEMUMonitorProtocol(self
._vm
_monitor
, server
=True)
272 def _post_launch(self
):
276 def _post_shutdown(self
):
277 if self
._qemu
_log
_file
is not None:
278 self
._qemu
_log
_file
.close()
279 self
._qemu
_log
_file
= None
281 self
._qemu
_log
_path
= None
283 if self
._temp
_dir
is not None:
284 shutil
.rmtree(self
._temp
_dir
)
285 self
._temp
_dir
= None
287 while len(self
._remove
_files
) > 0:
288 self
._remove
_if
_exists
(self
._remove
_files
.pop())
292 Launch the VM and make sure we cleanup and expose the
293 command line/output in case of exception
297 raise QEMUMachineError('VM already launched')
300 self
._qemu
_full
_args
= None
303 self
._launched
= True
307 LOG
.debug('Error launching VM')
308 if self
._qemu
_full
_args
:
309 LOG
.debug('Command: %r', ' '.join(self
._qemu
_full
_args
))
311 LOG
.debug('Output: %r', self
._iolog
)
316 Launch the VM and establish a QMP connection
318 devnull
= open(os
.path
.devnull
, 'rb')
320 self
._qemu
_full
_args
= (self
._wrapper
+ [self
._binary
] +
321 self
._base
_args
() + self
._args
)
322 LOG
.debug('VM launch command: %r', ' '.join(self
._qemu
_full
_args
))
323 self
._popen
= subprocess
.Popen(self
._qemu
_full
_args
,
325 stdout
=self
._qemu
_log
_file
,
326 stderr
=subprocess
.STDOUT
,
333 Wait for the VM to power off
339 self
._post
_shutdown
()
341 def shutdown(self
, has_quit
=False):
343 Terminate the VM and clean up
345 # If we keep the console socket open, we may deadlock waiting
346 # for QEMU to exit, while QEMU is waiting for the socket to
348 if self
._console
_socket
is not None:
349 self
._console
_socket
.close()
350 self
._console
_socket
= None
352 if self
.is_running():
356 self
._qmp
.cmd('quit')
363 self
._post
_shutdown
()
365 exitcode
= self
.exitcode()
366 if exitcode
is not None and exitcode
< 0:
367 msg
= 'qemu received signal %i: %s'
368 if self
._qemu
_full
_args
:
369 command
= ' '.join(self
._qemu
_full
_args
)
372 LOG
.warning(msg
, -exitcode
, command
)
374 self
._launched
= False
376 def set_qmp_monitor(self
, enabled
=True):
380 @param enabled: if False, qmp monitor options will be removed from
381 the base arguments of the resulting QEMU command
382 line. Default is True.
383 @note: call this function before launch().
388 self
._qmp
_set
= False
391 def qmp(self
, cmd
, conv_keys
=True, **args
):
393 Invoke a QMP command and return the response dict
396 for key
, value
in args
.items():
398 qmp_args
[key
.replace('_', '-')] = value
400 qmp_args
[key
] = value
402 return self
._qmp
.cmd(cmd
, args
=qmp_args
)
404 def command(self
, cmd
, conv_keys
=True, **args
):
406 Invoke a QMP command.
407 On success return the response dict.
408 On failure raise an exception.
410 reply
= self
.qmp(cmd
, conv_keys
, **args
)
412 raise qmp
.QMPError("Monitor is closed")
414 raise MonitorResponseError(reply
)
415 return reply
["return"]
417 def get_qmp_event(self
, wait
=False):
419 Poll for one queued QMP events and return it
422 return self
._events
.pop(0)
423 return self
._qmp
.pull_event(wait
=wait
)
425 def get_qmp_events(self
, wait
=False):
427 Poll for queued QMP events and return a list of dicts
429 events
= self
._qmp
.get_events(wait
=wait
)
430 events
.extend(self
._events
)
432 self
._qmp
.clear_events()
436 def event_match(event
, match
=None):
438 Check if an event matches optional match criteria.
440 The match criteria takes the form of a matching subdict. The event is
441 checked to be a superset of the subdict, recursively, with matching
442 values whenever the subdict values are not None.
444 This has a limitation that you cannot explicitly check for None values.
446 Examples, with the subdict queries on the left:
447 - None matches any object.
448 - {"foo": None} matches {"foo": {"bar": 1}}
449 - {"foo": None} matches {"foo": 5}
450 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
451 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
459 if not QEMUMachine
.event_match(event
[key
], match
[key
]):
465 # either match or event wasn't iterable (not a dict)
466 return match
== event
468 def event_wait(self
, name
, timeout
=60.0, match
=None):
470 event_wait waits for and returns a named event from QMP with a timeout.
472 name: The event to wait for.
473 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
474 match: Optional match criteria. See event_match for details.
476 return self
.events_wait([(name
, match
)], timeout
)
478 def events_wait(self
, events
, timeout
=60.0):
480 events_wait waits for and returns a named event from QMP with a timeout.
482 events: a sequence of (name, match_criteria) tuples.
483 The match criteria are optional and may be None.
484 See event_match for details.
485 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
488 for name
, match
in events
:
489 if event
['event'] == name
and self
.event_match(event
, match
):
493 # Search cached events
494 for event
in self
._events
:
496 self
._events
.remove(event
)
499 # Poll for new events
501 event
= self
._qmp
.pull_event(wait
=timeout
)
504 self
._events
.append(event
)
510 After self.shutdown or failed qemu execution, this returns the output
515 def add_args(self
, *args
):
517 Adds to the list of extra arguments to be given to the QEMU binary
519 self
._args
.extend(args
)
521 def set_machine(self
, machine_type
):
523 Sets the machine type
525 If set, the machine type will be added to the base arguments
526 of the resulting QEMU command line.
528 self
._machine
= machine_type
530 def set_console(self
, device_type
=None):
532 Sets the device type for a console device
534 If set, the console device and a backing character device will
535 be added to the base arguments of the resulting QEMU command
538 This is a convenience method that will either use the provided
539 device type, or default to a "-serial chardev:console" command
542 The actual setting of command line arguments will be be done at
543 machine launch time, as it depends on the temporary directory
546 @param device_type: the device type, such as "isa-serial". If
547 None is given (the default value) a "-serial
548 chardev:console" command line argument will
549 be used instead, resorting to the machine's
552 self
._console
_set
= True
553 self
._console
_device
_type
= device_type
556 def console_socket(self
):
558 Returns a socket connected to the console
560 if self
._console
_socket
is None:
561 self
._console
_socket
= socket
.socket(socket
.AF_UNIX
,
563 self
._console
_socket
.connect(self
._console
_address
)
564 return self
._console
_socket