From: Jay S. Bryant Date: Mon, 12 Aug 2013 17:55:48 +0000 (-0500) Subject: Add check for qemu-img to image_utils fetch_to_raw X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=870e984274d9e8d452e7aa383b289955b6896f28;p=openstack-build%2Fcinder-build.git Add check for qemu-img to image_utils fetch_to_raw Some platforms, particularly PowerPC systems running RHEL, do not have qemu-img installed by default and do not support image formats other than RAW. For these systems, functions/drivers that use fetch_to_raw() currently fail because it is assumed that qemu-img will always be installed. This change updates fetch_to_raw() to function more like the upload_volume() function which checks the image format and skips any conversion if the image is already in the RAW format. To minimize the impact upon platforms that have qemu-img installed this is being implemented by checking to see if qemu-img is installed. If it is installed, no changes are made to the flow through fetch_to_raw. If qemu-img is not available and the image format is not already RAW, an exception is thrown. Otherwise, the image is downloaded and we do not progress to the portions of fetch_to_raw that require qemu-img to be installed. This commit also updates the test cases that touch this code. Closes-bug: 1200800 Change-Id: I34540dfa238a8b8e61ff5c30c7e121130bad39b4 --- diff --git a/cinder/image/image_utils.py b/cinder/image/image_utils.py index 032919595..dbfb7232c 100644 --- a/cinder/image/image_utils.py +++ b/cinder/image/image_utils.py @@ -36,9 +36,10 @@ from oslo.config import cfg from cinder import exception from cinder.openstack.common import fileutils from cinder.openstack.common import log as logging +from cinder.openstack.common import processutils from cinder.openstack.common import strutils from cinder import utils - +from cinder.volume import utils as volume_utils LOG = logging.getLogger(__name__) @@ -254,16 +255,55 @@ def fetch_to_volume_format(context, image_service, os.path.exists(CONF.image_conversion_dir)): os.makedirs(CONF.image_conversion_dir) + no_qemu_img = False + image_meta = image_service.show(context, image_id) + # NOTE(avishay): I'm not crazy about creating temp files which may be # large and cause disk full errors which would confuse users. # Unfortunately it seems that you can't pipe to 'qemu-img convert' because # it seeks. Maybe we can think of something for a future version. with temporary_file() as tmp: + # We may be on a system that doesn't have qemu-img installed. That + # is ok if we are working with a RAW image. This logic checks to see + # if qemu-img is installed. If not we make sure the image is RAW and + # throw an exception if not. Otherwise we stop before needing + # qemu-img. Systems with qemu-img will always progress through the + # whole function. + try: + # Use the empty tmp file to make sure qemu_img_info works. + qemu_img_info(tmp) + except processutils.ProcessExecutionError: + no_qemu_img = True + if image_meta: + if image_meta['disk_format'] != 'raw': + raise exception.ImageUnacceptable( + reason=_("qemu-img is not installed and image is of " + "type %s. Only RAW images can be used if " + "qemu-img is not installed.") % + image_meta['disk_format'], + image_id=image_id) + else: + raise exception.ImageUnacceptable( + reason=_("qemu-img is not installed and the disk " + "format is not specified. Only RAW images " + "can be used if qemu-img is not installed."), + image_id=image_id) + fetch(context, image_service, image_id, tmp, user_id, project_id) if is_xenserver_image(context, image_service, image_id): replace_xenserver_image_with_coalesced_vhd(tmp) + if no_qemu_img: + # qemu-img is not installed but we do have a RAW image. As a + # result we only need to copy the image to the destination and then + # return. + LOG.debug(_('Copying image from %(tmp)s to volume %(dest)s - ' + 'size: %(size)s') % {'tmp': tmp, 'dest': dest, + 'size': image_meta['size']}) + volume_utils.copy_volume(tmp, dest, image_meta['size']) + return + data = qemu_img_info(tmp) fmt = data.file_format if fmt is None: diff --git a/cinder/tests/test_image_utils.py b/cinder/tests/test_image_utils.py index a6f7a11e3..fd1d29b9c 100644 --- a/cinder/tests/test_image_utils.py +++ b/cinder/tests/test_image_utils.py @@ -165,6 +165,12 @@ class TestUtils(test.TestCase): (TEST_RET, 'ignored') ) + utils.execute( + 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', + self.TEST_DEV_PATH, run_as_root=True).AndReturn( + (TEST_RET, 'ignored') + ) + utils.execute('qemu-img', 'convert', '-O', 'raw', self.TEST_DEV_PATH, self.TEST_DEV_PATH, run_as_root=True) @@ -203,6 +209,12 @@ class TestUtils(test.TestCase): (TEST_RET, 'ignored') ) + utils.execute( + 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', + self.TEST_DEV_PATH, run_as_root=True).AndReturn( + (TEST_RET, 'ignored') + ) + mox.ReplayAll() self.assertRaises(exception.ImageUnacceptable, @@ -235,6 +247,12 @@ class TestUtils(test.TestCase): (TEST_RET, 'ignored') ) + utils.execute( + 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', + self.TEST_DEV_PATH, run_as_root=True).AndReturn( + (TEST_RET, 'ignored') + ) + mox.ReplayAll() self.assertRaises(exception.ImageUnacceptable, image_utils.fetch_to_raw, @@ -265,6 +283,12 @@ class TestUtils(test.TestCase): (TEST_RET, 'ignored') ) + utils.execute( + 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', + self.TEST_DEV_PATH, run_as_root=True).AndReturn( + (TEST_RET, 'ignored') + ) + utils.execute('qemu-img', 'convert', '-O', 'raw', self.TEST_DEV_PATH, self.TEST_DEV_PATH, run_as_root=True)