diff --git a/cinder/image/image_utils.py b/cinder/image/image_utils.py index 032919595f6..dbfb7232c80 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 a6f7a11e3e9..fd1d29b9c4c 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)