diff options
Diffstat (limited to 'scripts/qemu.py')
-rw-r--r-- | scripts/qemu.py | 94 |
1 files changed, 62 insertions, 32 deletions
diff --git a/scripts/qemu.py b/scripts/qemu.py index 9bfdf6d37d..305a946562 100644 --- a/scripts/qemu.py +++ b/scripts/qemu.py @@ -15,9 +15,10 @@ import errno import logging import os -import sys import subprocess import qmp.qmp +import shutil +import tempfile LOG = logging.getLogger(__name__) @@ -73,10 +74,11 @@ class QEMUMachine(object): wrapper = [] if name is None: name = "qemu-%d" % os.getpid() - if monitor_address is None: - monitor_address = os.path.join(test_dir, name + "-monitor.sock") + self._name = name self._monitor_address = monitor_address - self._qemu_log_path = os.path.join(test_dir, name + ".log") + self._vm_monitor = None + self._qemu_log_path = None + self._qemu_log_file = None self._popen = None self._binary = binary self._args = list(args) # Force copy args in case we modify them @@ -86,6 +88,9 @@ class QEMUMachine(object): self._socket_scm_helper = socket_scm_helper self._qmp = None self._qemu_full_args = None + self._test_dir = test_dir + self._temp_dir = None + self._launched = False # just in case logging wasn't configured by the main script: logging.basicConfig() @@ -146,12 +151,12 @@ class QEMUMachine(object): raise def is_running(self): - return self._popen is not None and self._popen.returncode is None + return self._popen is not None and self._popen.poll() is None def exitcode(self): if self._popen is None: return None - return self._popen.returncode + return self._popen.poll() def get_pid(self): if not self.is_running(): @@ -159,8 +164,9 @@ class QEMUMachine(object): return self._popen.pid def _load_io_log(self): - with open(self._qemu_log_path, "r") as iolog: - self._iolog = iolog.read() + if self._qemu_log_path is not None: + with open(self._qemu_log_path, "r") as iolog: + self._iolog = iolog.read() def _base_args(self): if isinstance(self._monitor_address, tuple): @@ -168,45 +174,54 @@ class QEMUMachine(object): self._monitor_address[0], self._monitor_address[1]) else: - moncdev = 'socket,id=mon,path=%s' % self._monitor_address + moncdev = 'socket,id=mon,path=%s' % self._vm_monitor return ['-chardev', moncdev, '-mon', 'chardev=mon,mode=control', '-display', 'none', '-vga', 'none'] def _pre_launch(self): - self._qmp = qmp.qmp.QEMUMonitorProtocol(self._monitor_address, + self._temp_dir = tempfile.mkdtemp(dir=self._test_dir) + if self._monitor_address is not None: + self._vm_monitor = self._monitor_address + else: + self._vm_monitor = os.path.join(self._temp_dir, + self._name + "-monitor.sock") + self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log") + self._qemu_log_file = open(self._qemu_log_path, 'wb') + + self._qmp = qmp.qmp.QEMUMonitorProtocol(self._vm_monitor, server=True) def _post_launch(self): self._qmp.accept() def _post_shutdown(self): - if not isinstance(self._monitor_address, tuple): - self._remove_if_exists(self._monitor_address) - self._remove_if_exists(self._qemu_log_path) + if self._qemu_log_file is not None: + self._qemu_log_file.close() + self._qemu_log_file = None + + self._qemu_log_path = None + + if self._temp_dir is not None: + shutil.rmtree(self._temp_dir) + self._temp_dir = None def launch(self): - '''Launch the VM and establish a QMP connection''' + """ + Launch the VM and make sure we cleanup and expose the + command line/output in case of exception + """ + + if self._launched: + raise QEMUMachineError('VM already launched') + self._iolog = None self._qemu_full_args = None - devnull = open(os.path.devnull, 'rb') - qemulog = open(self._qemu_log_path, 'wb') try: - self._pre_launch() - self._qemu_full_args = (self._wrapper + [self._binary] + - self._base_args() + self._args) - self._popen = subprocess.Popen(self._qemu_full_args, - stdin=devnull, - stdout=qemulog, - stderr=subprocess.STDOUT, - shell=False) - self._post_launch() + self._launch() + self._launched = True except: - if self.is_running(): - self._popen.kill() - self._popen.wait() - self._load_io_log() - self._post_shutdown() + self.shutdown() LOG.debug('Error launching VM') if self._qemu_full_args: @@ -215,6 +230,19 @@ class QEMUMachine(object): LOG.debug('Output: %r', self._iolog) raise + def _launch(self): + '''Launch the VM and establish a QMP connection''' + devnull = open(os.path.devnull, 'rb') + self._pre_launch() + self._qemu_full_args = (self._wrapper + [self._binary] + + self._base_args() + self._args) + self._popen = subprocess.Popen(self._qemu_full_args, + stdin=devnull, + stdout=self._qemu_log_file, + stderr=subprocess.STDOUT, + shell=False) + self._post_launch() + def wait(self): '''Wait for the VM to power off''' self._popen.wait() @@ -232,8 +260,8 @@ class QEMUMachine(object): self._popen.kill() self._popen.wait() - self._load_io_log() - self._post_shutdown() + self._load_io_log() + self._post_shutdown() exitcode = self.exitcode() if exitcode is not None and exitcode < 0: @@ -244,6 +272,8 @@ class QEMUMachine(object): command = '' LOG.warn(msg, exitcode, command) + self._launched = False + def qmp(self, cmd, conv_keys=True, **args): '''Invoke a QMP command and return the response dict''' qmp_args = dict() |