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):
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()
94 self
._monitor
_address
= monitor_address
95 self
._vm
_monitor
= None
96 self
._qemu
_log
_path
= None
97 self
._qemu
_log
_file
= None
100 self
._args
= list(args
) # Force copy args in case we modify them
101 self
._wrapper
= wrapper
104 self
._socket
_scm
_helper
= socket_scm_helper
106 self
._qemu
_full
_args
= None
107 self
._test
_dir
= test_dir
108 self
._temp
_dir
= None
109 self
._launched
= False
111 self
._console
_set
= False
112 self
._console
_device
_type
= None
113 self
._console
_address
= None
114 self
._console
_socket
= None
116 # just in case logging wasn't configured by the main script:
117 logging
.basicConfig()
122 def __exit__(self
, exc_type
, exc_val
, exc_tb
):
126 def add_monitor_null(self
):
128 This can be used to add an unused monitor instance.
130 self
._args
.append('-monitor')
131 self
._args
.append('null')
133 def add_fd(self
, fd
, fdset
, opaque
, opts
=''):
135 Pass a file descriptor to the VM
137 options
= ['fd=%d' % fd
,
139 'opaque=%s' % opaque
]
143 # This did not exist before 3.4, but since then it is
144 # mandatory for our purpose
145 if hasattr(os
, 'set_inheritable'):
146 os
.set_inheritable(fd
, True)
148 self
._args
.append('-add-fd')
149 self
._args
.append(','.join(options
))
152 def send_fd_scm(self
, fd
=None, file_path
=None):
154 Send an fd or file_path to socket_scm_helper.
156 Exactly one of fd and file_path must be given.
157 If it is file_path, the helper will open that file and pass its own fd.
159 # In iotest.py, the qmp should always use unix socket.
160 assert self
._qmp
.is_scm_available()
161 if self
._socket
_scm
_helper
is None:
162 raise QEMUMachineError("No path to socket_scm_helper set")
163 if not os
.path
.exists(self
._socket
_scm
_helper
):
164 raise QEMUMachineError("%s does not exist" %
165 self
._socket
_scm
_helper
)
167 # This did not exist before 3.4, but since then it is
168 # mandatory for our purpose
169 if hasattr(os
, 'set_inheritable'):
170 os
.set_inheritable(self
._qmp
.get_sock_fd(), True)
172 os
.set_inheritable(fd
, True)
174 fd_param
= ["%s" % self
._socket
_scm
_helper
,
175 "%d" % self
._qmp
.get_sock_fd()]
177 if file_path
is not None:
179 fd_param
.append(file_path
)
181 assert fd
is not None
182 fd_param
.append(str(fd
))
184 devnull
= open(os
.path
.devnull
, 'rb')
185 proc
= subprocess
.Popen(fd_param
, stdin
=devnull
, stdout
=subprocess
.PIPE
,
186 stderr
=subprocess
.STDOUT
, close_fds
=False)
187 output
= proc
.communicate()[0]
191 return proc
.returncode
194 def _remove_if_exists(path
):
196 Remove file object at path if it exists
200 except OSError as exception
:
201 if exception
.errno
== errno
.ENOENT
:
205 def is_running(self
):
206 """Returns true if the VM is running."""
207 return self
._popen
is not None and self
._popen
.poll() is None
210 """Returns the exit code if possible, or None."""
211 if self
._popen
is None:
213 return self
._popen
.poll()
216 """Returns the PID of the running process, or None."""
217 if not self
.is_running():
219 return self
._popen
.pid
221 def _load_io_log(self
):
222 if self
._qemu
_log
_path
is not None:
223 with
open(self
._qemu
_log
_path
, "r") as iolog
:
224 self
._iolog
= iolog
.read()
226 def _base_args(self
):
227 if isinstance(self
._monitor
_address
, tuple):
228 moncdev
= "socket,id=mon,host=%s,port=%s" % (
229 self
._monitor
_address
[0],
230 self
._monitor
_address
[1])
232 moncdev
= 'socket,id=mon,path=%s' % self
._vm
_monitor
233 args
= ['-chardev', moncdev
,
234 '-mon', 'chardev=mon,mode=control',
235 '-display', 'none', '-vga', 'none']
236 if self
._machine
is not None:
237 args
.extend(['-machine', self
._machine
])
238 if self
._console
_set
:
239 self
._console
_address
= os
.path
.join(self
._temp
_dir
,
240 self
._name
+ "-console.sock")
241 chardev
= ('socket,id=console,path=%s,server,nowait' %
242 self
._console
_address
)
243 args
.extend(['-chardev', chardev
])
244 if self
._console
_device
_type
is None:
245 args
.extend(['-serial', 'chardev:console'])
247 device
= '%s,chardev=console' % self
._console
_device
_type
248 args
.extend(['-device', device
])
251 def _pre_launch(self
):
252 self
._temp
_dir
= tempfile
.mkdtemp(dir=self
._test
_dir
)
253 if self
._monitor
_address
is not None:
254 self
._vm
_monitor
= self
._monitor
_address
256 self
._vm
_monitor
= os
.path
.join(self
._temp
_dir
,
257 self
._name
+ "-monitor.sock")
258 self
._qemu
_log
_path
= os
.path
.join(self
._temp
_dir
, self
._name
+ ".log")
259 self
._qemu
_log
_file
= open(self
._qemu
_log
_path
, 'wb')
261 self
._qmp
= qmp
.QEMUMonitorProtocol(self
._vm
_monitor
,
264 def _post_launch(self
):
267 def _post_shutdown(self
):
268 if self
._qemu
_log
_file
is not None:
269 self
._qemu
_log
_file
.close()
270 self
._qemu
_log
_file
= None
272 self
._qemu
_log
_path
= None
274 if self
._console
_socket
is not None:
275 self
._console
_socket
.close()
276 self
._console
_socket
= None
278 if self
._temp
_dir
is not None:
279 shutil
.rmtree(self
._temp
_dir
)
280 self
._temp
_dir
= None
284 Launch the VM and make sure we cleanup and expose the
285 command line/output in case of exception
289 raise QEMUMachineError('VM already launched')
292 self
._qemu
_full
_args
= None
295 self
._launched
= True
299 LOG
.debug('Error launching VM')
300 if self
._qemu
_full
_args
:
301 LOG
.debug('Command: %r', ' '.join(self
._qemu
_full
_args
))
303 LOG
.debug('Output: %r', self
._iolog
)
308 Launch the VM and establish a QMP connection
310 devnull
= open(os
.path
.devnull
, 'rb')
312 self
._qemu
_full
_args
= (self
._wrapper
+ [self
._binary
] +
313 self
._base
_args
() + self
._args
)
314 LOG
.debug('VM launch command: %r', ' '.join(self
._qemu
_full
_args
))
315 self
._popen
= subprocess
.Popen(self
._qemu
_full
_args
,
317 stdout
=self
._qemu
_log
_file
,
318 stderr
=subprocess
.STDOUT
,
325 Wait for the VM to power off
330 self
._post
_shutdown
()
332 def shutdown(self
, has_quit
=False):
334 Terminate the VM and clean up
336 if self
.is_running():
339 self
._qmp
.cmd('quit')
346 self
._post
_shutdown
()
348 exitcode
= self
.exitcode()
349 if exitcode
is not None and exitcode
< 0:
350 msg
= 'qemu received signal %i: %s'
351 if self
._qemu
_full
_args
:
352 command
= ' '.join(self
._qemu
_full
_args
)
355 LOG
.warning(msg
, -exitcode
, command
)
357 self
._launched
= False
359 def qmp(self
, cmd
, conv_keys
=True, **args
):
361 Invoke a QMP command and return the response dict
364 for key
, value
in args
.items():
366 qmp_args
[key
.replace('_', '-')] = value
368 qmp_args
[key
] = value
370 return self
._qmp
.cmd(cmd
, args
=qmp_args
)
372 def command(self
, cmd
, conv_keys
=True, **args
):
374 Invoke a QMP command.
375 On success return the response dict.
376 On failure raise an exception.
378 reply
= self
.qmp(cmd
, conv_keys
, **args
)
380 raise qmp
.QMPError("Monitor is closed")
382 raise MonitorResponseError(reply
)
383 return reply
["return"]
385 def get_qmp_event(self
, wait
=False):
387 Poll for one queued QMP events and return it
390 return self
._events
.pop(0)
391 return self
._qmp
.pull_event(wait
=wait
)
393 def get_qmp_events(self
, wait
=False):
395 Poll for queued QMP events and return a list of dicts
397 events
= self
._qmp
.get_events(wait
=wait
)
398 events
.extend(self
._events
)
400 self
._qmp
.clear_events()
404 def event_match(event
, match
=None):
406 Check if an event matches optional match criteria.
408 The match criteria takes the form of a matching subdict. The event is
409 checked to be a superset of the subdict, recursively, with matching
410 values whenever the subdict values are not None.
412 This has a limitation that you cannot explicitly check for None values.
414 Examples, with the subdict queries on the left:
415 - None matches any object.
416 - {"foo": None} matches {"foo": {"bar": 1}}
417 - {"foo": None} matches {"foo": 5}
418 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
419 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
427 if not QEMUMachine
.event_match(event
[key
], match
[key
]):
433 # either match or event wasn't iterable (not a dict)
434 return match
== event
436 def event_wait(self
, name
, timeout
=60.0, match
=None):
438 event_wait waits for and returns a named event from QMP with a timeout.
440 name: The event to wait for.
441 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
442 match: Optional match criteria. See event_match for details.
444 return self
.events_wait([(name
, match
)], timeout
)
446 def events_wait(self
, events
, timeout
=60.0):
448 events_wait waits for and returns a named event from QMP with a timeout.
450 events: a sequence of (name, match_criteria) tuples.
451 The match criteria are optional and may be None.
452 See event_match for details.
453 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
456 for name
, match
in events
:
457 if event
['event'] == name
and self
.event_match(event
, match
):
461 # Search cached events
462 for event
in self
._events
:
464 self
._events
.remove(event
)
467 # Poll for new events
469 event
= self
._qmp
.pull_event(wait
=timeout
)
472 self
._events
.append(event
)
478 After self.shutdown or failed qemu execution, this returns the output
483 def add_args(self
, *args
):
485 Adds to the list of extra arguments to be given to the QEMU binary
487 self
._args
.extend(args
)
489 def set_machine(self
, machine_type
):
491 Sets the machine type
493 If set, the machine type will be added to the base arguments
494 of the resulting QEMU command line.
496 self
._machine
= machine_type
498 def set_console(self
, device_type
=None):
500 Sets the device type for a console device
502 If set, the console device and a backing character device will
503 be added to the base arguments of the resulting QEMU command
506 This is a convenience method that will either use the provided
507 device type, or default to a "-serial chardev:console" command
510 The actual setting of command line arguments will be be done at
511 machine launch time, as it depends on the temporary directory
514 @param device_type: the device type, such as "isa-serial". If
515 None is given (the default value) a "-serial
516 chardev:console" command line argument will
517 be used instead, resorting to the machine's
520 self
._console
_set
= True
521 self
._console
_device
_type
= device_type
524 def console_socket(self
):
526 Returns a socket connected to the console
528 if self
._console
_socket
is None:
529 self
._console
_socket
= socket
.socket(socket
.AF_UNIX
,
531 self
._console
_socket
.connect(self
._console
_address
)
532 return self
._console
_socket