@@ -241,11 +241,13 @@ def compare_images(image, reference, baseimg=None, expected_match=True):
expected_ret = 0 if expected_match else 1
if baseimg:
qemu_img("rebase", "-u", "-b", baseimg, '-F', iotests.imgfmt, image)
- ret = qemu_img("compare", image, reference)
+
+ sub = qemu_img("compare", image, reference, check=False)
+
log('qemu_img compare "{:s}" "{:s}" ==> {:s}, {:s}'.format(
image, reference,
- "Identical" if ret == 0 else "Mismatch",
- "OK!" if ret == expected_ret else "ERROR!"),
+ "Identical" if sub.returncode == 0 else "Mismatch",
+ "OK!" if sub.returncode == expected_ret else "ERROR!"),
filters=[iotests.filter_testfiles])
def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
@@ -37,9 +37,10 @@
from contextlib import contextmanager
+from qemu.aqmp.legacy import QEMUMonitorProtocol
from qemu.machine import qtest
from qemu.qmp import QMPMessage
-from qemu.aqmp.legacy import QEMUMonitorProtocol
+from qemu.utils import VerboseProcessError
# Use this logger for logging messages directly from the iotests module
logger = logging.getLogger('qemu.iotests')
@@ -215,9 +216,50 @@ def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]:
return qemu_tool_pipe_and_status('qemu-img', full_args,
drop_successful_output=is_create)
-def qemu_img(*args: str) -> int:
- '''Run qemu-img and return the exit code'''
- return qemu_img_pipe_and_status(*args)[1]
+def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True
+ ) -> 'subprocess.CompletedProcess[str]':
+ """
+ Run qemu_img and return the status code and console output.
+
+ This function always prepends QEMU_IMG_OPTIONS and may further alter
+ the args for 'create' commands.
+
+ :param args: command-line arguments to qemu-img.
+ :param check: Enforce a return code of zero.
+ :param combine_stdio: set to False to keep stdout/stderr separated.
+
+ :raise VerboseProcessError:
+ When the return code is negative, or on any non-zero exit code
+ when 'check=True' was provided (the default). This exception has
+ 'stdout', 'stderr', and 'returncode' properties that may be
+ inspected to show greater detail. If this exception is not
+ handled, the command-line, return code, and all console output
+ will be included at the bottom of the stack trace.
+
+ :return:
+ a CompletedProcess. This object has args, returncode, and stdout
+ properties. If streams are not combined, it will also have a
+ stderr property.
+ """
+ full_args = qemu_img_args + qemu_img_create_prepare_args(list(args))
+
+ subp = subprocess.run(
+ full_args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT if combine_stdio else subprocess.PIPE,
+ universal_newlines=True,
+ check=False
+ )
+
+ if check and subp.returncode or (subp.returncode < 0):
+ raise VerboseProcessError(
+ subp.returncode, full_args,
+ output=subp.stdout,
+ stderr=subp.stderr,
+ )
+
+ return subp
+
def ordered_qmp(qmsg, conv_keys=True):
# Dictionaries are not ordered prior to 3.6, therefore:
@@ -232,7 +274,7 @@ def ordered_qmp(qmsg, conv_keys=True):
return od
return qmsg
-def qemu_img_create(*args):
+def qemu_img_create(*args: str) -> 'subprocess.CompletedProcess[str]':
return qemu_img('create', *args)
def qemu_img_measure(*args):
@@ -467,8 +509,9 @@ def qemu_nbd_popen(*args):
def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
'''Return True if two image files are identical'''
- return qemu_img('compare', '-f', fmt1,
- '-F', fmt2, img1, img2) == 0
+ res = qemu_img('compare', '-f', fmt1,
+ '-F', fmt2, img1, img2, check=False)
+ return res.returncode == 0
def create_image(name, size):
'''Create a fully-allocated raw image with sector markers'''