from cinder.openstack.common import imageutils
from cinder.openstack.common import log as logging
from cinder.openstack.common import processutils
-from cinder.openstack.common import strutils
+from cinder import units
from cinder import utils
from cinder.volume import utils as volume_utils
def fetch_verify_image(context, image_service, image_id, dest,
- user_id=None, project_id=None):
+ user_id=None, project_id=None, size=None):
fetch(context, image_service, image_id, dest,
None, None)
reason=(_("fmt=%(fmt)s backed by: %(backing_file)s") %
{'fmt': fmt, 'backing_file': backing_file}))
+ # NOTE(xqueralt): If the image virtual size doesn't fit in the
+ # requested volume there is no point on resizing it because it will
+ # generate an unusable image.
+ if size is not None and data.virtual_size > size:
+ params = {'image_size': data.virtual_size, 'volume_size': size}
+ reason = _("Size is %(image_size)dGB and doesn't fit in a "
+ "volume of size %(volume_size)dGB.") % params
+ raise exception.ImageUnacceptable(image_id=image_id, reason=reason)
+
def fetch_to_vhd(context, image_service,
image_id, dest,
def fetch_to_raw(context, image_service,
image_id, dest,
- user_id=None, project_id=None):
+ user_id=None, project_id=None, size=None):
fetch_to_volume_format(context, image_service, image_id, dest, 'raw',
- user_id, project_id)
+ user_id, project_id, size)
def fetch_to_volume_format(context, image_service,
image_id, dest, volume_format,
- user_id=None, project_id=None):
+ user_id=None, project_id=None, size=None):
if (CONF.image_conversion_dir and not
os.path.exists(CONF.image_conversion_dir)):
os.makedirs(CONF.image_conversion_dir)
- no_qemu_img = False
+ qemu_img = True
image_meta = image_service.show(context, image_id)
# NOTE(avishay): I'm not crazy about creating temp files which may be
# Use the empty tmp file to make sure qemu_img_info works.
qemu_img_info(tmp)
except processutils.ProcessExecutionError:
- no_qemu_img = True
+ qemu_img = False
if image_meta:
if image_meta['disk_format'] != 'raw':
raise exception.ImageUnacceptable(
if is_xenserver_image(context, image_service, image_id):
replace_xenserver_image_with_coalesced_vhd(tmp)
- if no_qemu_img:
+ if not 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.
return
data = qemu_img_info(tmp)
+ virt_size = data.virtual_size / units.GiB
+
+ # NOTE(xqueralt): If the image virtual size doesn't fit in the
+ # requested volume there is no point on resizing it because it will
+ # generate an unusable image.
+ if size is not None and virt_size > size:
+ params = {'image_size': virt_size, 'volume_size': size}
+ reason = _("Size is %(image_size)dGB and doesn't fit in a "
+ "volume of size %(volume_size)dGB.") % params
+ raise exception.ImageUnacceptable(image_id=image_id, reason=reason)
+
fmt = data.file_format
if fmt is None:
raise exception.ImageUnacceptable(
import contextlib
import mox
import tempfile
-import textwrap
from cinder import context
from cinder import exception
from cinder.image import image_utils
+from cinder.openstack.common import processutils
from cinder import test
from cinder import units
from cinder import utils
def setUp(self):
super(TestUtils, self).setUp()
self._mox = mox.Mox()
+ self._image_service = FakeImageService()
+
self.addCleanup(self._mox.UnsetStubs)
def test_resize_image(self):
self.assertEquals(str(inf), TEST_STR)
- def test_fetch_to_raw(self):
- TEST_RET = "image: qemu.qcow2\n"\
- "file_format: qcow2 \n"\
- "virtual_size: 50M (52428800 bytes)\n"\
- "cluster_size: 65536\n"\
- "disk_size: 196K (200704 bytes)"
- TEST_RETURN_RAW = "image: qemu.raw\n"\
- "file_format: raw\n"\
- "virtual_size: 50M (52428800 bytes)\n"\
- "cluster_size: 65536\n"\
- "disk_size: 196K (200704 bytes)\n"\
-
- fake_image_service = FakeImageService()
+ def _test_fetch_to_raw(self, has_qemu=True, src_inf=None, dest_inf=None):
mox = self._mox
-
mox.StubOutWithMock(image_utils, 'create_temporary_file')
mox.StubOutWithMock(utils, 'execute')
mox.StubOutWithMock(image_utils, 'fetch')
- image_utils.create_temporary_file().AndReturn(self.TEST_DEV_PATH)
- image_utils.fetch(context, fake_image_service,
- self.TEST_IMAGE_ID, self.TEST_DEV_PATH, None, None)
-
- 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(
- 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
- self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RET, 'ignored')
- )
+ TEST_INFO = ("image: qemu.qcow2\n"
+ "file format: raw\n"
+ "virtual size: 0 (0 bytes)\n"
+ "disk size: 0")
- utils.execute('qemu-img', 'convert', '-O', 'raw',
- self.TEST_DEV_PATH, self.TEST_DEV_PATH, run_as_root=True)
+ image_utils.create_temporary_file().AndReturn(self.TEST_DEV_PATH)
- utils.execute(
+ test_qemu_img = utils.execute(
'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
- self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RETURN_RAW, 'ignored')
- )
-
- mox.ReplayAll()
+ self.TEST_DEV_PATH, run_as_root=True)
+
+ if has_qemu:
+ test_qemu_img.AndReturn((TEST_INFO, 'ignored'))
+ image_utils.fetch(context, self._image_service, self.TEST_IMAGE_ID,
+ self.TEST_DEV_PATH, None, None)
+ else:
+ test_qemu_img.AndRaise(processutils.ProcessExecutionError())
+
+ if has_qemu and src_inf:
+ utils.execute(
+ 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
+ self.TEST_DEV_PATH, run_as_root=True).AndReturn(
+ (src_inf, 'ignored')
+ )
+
+ if has_qemu and dest_inf:
+ utils.execute(
+ 'qemu-img', 'convert', '-O', 'raw',
+ self.TEST_DEV_PATH, self.TEST_DEV_PATH, run_as_root=True)
+
+ utils.execute(
+ 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
+ self.TEST_DEV_PATH, run_as_root=True).AndReturn(
+ (dest_inf, 'ignored')
+ )
+
+ self._mox.ReplayAll()
- image_utils.fetch_to_raw(context, fake_image_service,
+ def test_fetch_to_raw(self):
+ SRC_INFO = ("image: qemu.qcow2\n"
+ "file_format: qcow2 \n"
+ "virtual_size: 50M (52428800 bytes)\n"
+ "cluster_size: 65536\n"
+ "disk_size: 196K (200704 bytes)")
+ DST_INFO = ("image: qemu.raw\n"
+ "file_format: raw\n"
+ "virtual_size: 50M (52428800 bytes)\n"
+ "cluster_size: 65536\n"
+ "disk_size: 196K (200704 bytes)\n")
+
+ self._test_fetch_to_raw(src_inf=SRC_INFO, dest_inf=DST_INFO)
+
+ image_utils.fetch_to_raw(context, self._image_service,
self.TEST_IMAGE_ID, self.TEST_DEV_PATH)
- mox.VerifyAll()
+ self._mox.VerifyAll()
- def test_fetch_to_raw_on_error_parsing_failed(self):
- TEST_RET = "image: qemu.qcow2\n"\
- "virtual_size: 50M (52428800 bytes)\n"\
- "cluster_size: 65536\n"\
- "disk_size: 196K (200704 bytes)"
+ def test_fetch_to_raw_no_qemu_img(self):
+ self._test_fetch_to_raw(has_qemu=False)
- fake_image_service = FakeImageService()
- mox = self._mox
-
- mox.StubOutWithMock(image_utils, 'create_temporary_file')
- mox.StubOutWithMock(utils, 'execute')
- mox.StubOutWithMock(image_utils, 'fetch')
-
- image_utils.create_temporary_file().AndReturn(self.TEST_DEV_PATH)
- image_utils.fetch(context, fake_image_service,
- self.TEST_IMAGE_ID, self.TEST_DEV_PATH, None, None)
+ self.assertRaises(exception.ImageUnacceptable,
+ image_utils.fetch_to_raw,
+ context, self._image_service,
+ self.TEST_IMAGE_ID, self.TEST_DEV_PATH)
- utils.execute(
- 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
- self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RET, 'ignored')
- )
+ self._mox.VerifyAll()
- utils.execute(
- 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
- self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RET, 'ignored')
- )
+ def test_fetch_to_raw_on_error_parsing_failed(self):
+ SRC_INFO_NO_FORMAT = ("image: qemu.qcow2\n"
+ "virtual_size: 50M (52428800 bytes)\n"
+ "cluster_size: 65536\n"
+ "disk_size: 196K (200704 bytes)")
- mox.ReplayAll()
+ self._test_fetch_to_raw(src_inf=SRC_INFO_NO_FORMAT)
self.assertRaises(exception.ImageUnacceptable,
- image_utils.fetch_to_raw, context,
- fake_image_service, self.TEST_IMAGE_ID,
- self.TEST_DEV_PATH)
+ image_utils.fetch_to_raw,
+ context, self._image_service,
+ self.TEST_IMAGE_ID, self.TEST_DEV_PATH)
+ self._mox.VerifyAll()
def test_fetch_to_raw_on_error_backing_file(self):
- TEST_RET = "image: qemu.qcow2\n"\
- "backing_file: qemu.qcow2 (actual path: qemu.qcow2)\n"\
- "file_format: qcow2 \n"\
- "virtual_size: 50M (52428800 bytes)\n"\
- "cluster_size: 65536\n"\
- "disk_size: 196K (200704 bytes)"
+ SRC_INFO_BACKING_FILE = ("image: qemu.qcow2\n"
+ "backing_file: qemu.qcow2\n"
+ "file_format: qcow2 \n"
+ "virtual_size: 50M (52428800 bytes)\n"
+ "cluster_size: 65536\n"
+ "disk_size: 196K (200704 bytes)")
- fake_image_service = FakeImageService()
- mox = self._mox
+ self._test_fetch_to_raw(src_inf=SRC_INFO_BACKING_FILE)
- mox.StubOutWithMock(image_utils, 'create_temporary_file')
- mox.StubOutWithMock(utils, 'execute')
- mox.StubOutWithMock(image_utils, 'fetch')
-
- image_utils.create_temporary_file().AndReturn(self.TEST_DEV_PATH)
- image_utils.fetch(context, fake_image_service,
- self.TEST_IMAGE_ID, self.TEST_DEV_PATH, None, None)
+ self.assertRaises(exception.ImageUnacceptable,
+ image_utils.fetch_to_raw,
+ context, self._image_service,
+ self.TEST_IMAGE_ID, self.TEST_DEV_PATH)
+ self._mox.VerifyAll()
- utils.execute(
- 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
- self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RET, 'ignored')
- )
+ def test_fetch_to_raw_on_error_not_convert_to_raw(self):
+ IMG_INFO = ("image: qemu.qcow2\n"
+ "file_format: qcow2 \n"
+ "virtual_size: 50M (52428800 bytes)\n"
+ "cluster_size: 65536\n"
+ "disk_size: 196K (200704 bytes)")
- utils.execute(
- 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
- self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RET, 'ignored')
- )
+ self._test_fetch_to_raw(src_inf=IMG_INFO, dest_inf=IMG_INFO)
- mox.ReplayAll()
self.assertRaises(exception.ImageUnacceptable,
image_utils.fetch_to_raw,
- context, fake_image_service,
+ context, self._image_service,
self.TEST_IMAGE_ID, self.TEST_DEV_PATH)
- def test_fetch_to_raw_on_error_not_convert_to_raw(self):
- TEST_RET = "image: qemu.qcow2\n"\
- "file_format: qcow2 \n"\
- "virtual_size: 50M (52428800 bytes)\n"\
- "cluster_size: 65536\n"\
- "disk_size: 196K (200704 bytes)"
+ def test_fetch_to_raw_on_error_image_size(self):
+ TEST_VOLUME_SIZE = 1
+ SRC_INFO = ("image: qemu.qcow2\n"
+ "file_format: qcow2 \n"
+ "virtual_size: 2G (2147483648 bytes)\n"
+ "cluster_size: 65536\n"
+ "disk_size: 196K (200704 bytes)")
+ self._test_fetch_to_raw(src_inf=SRC_INFO)
+
+ self.assertRaises(exception.ImageUnacceptable,
+ image_utils.fetch_to_raw,
+ context, self._image_service,
+ self.TEST_IMAGE_ID, self.TEST_DEV_PATH,
+ size=TEST_VOLUME_SIZE)
+
+ def _test_fetch_verify_image(self, qemu_info, volume_size=1):
fake_image_service = FakeImageService()
mox = self._mox
-
- mox.StubOutWithMock(image_utils, 'create_temporary_file')
- mox.StubOutWithMock(utils, 'execute')
mox.StubOutWithMock(image_utils, 'fetch')
-
- image_utils.create_temporary_file().AndReturn(self.TEST_DEV_PATH)
+ mox.StubOutWithMock(utils, 'execute')
image_utils.fetch(context, fake_image_service,
self.TEST_IMAGE_ID, self.TEST_DEV_PATH, None, None)
utils.execute(
'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RET, 'ignored')
+ (qemu_info, '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)
-
- 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._mox.ReplayAll()
self.assertRaises(exception.ImageUnacceptable,
- image_utils.fetch_to_raw,
+ image_utils.fetch_verify_image,
context, fake_image_service,
- self.TEST_IMAGE_ID, self.TEST_DEV_PATH)
+ self.TEST_IMAGE_ID, self.TEST_DEV_PATH,
+ size=volume_size)
def test_fetch_verify_image_with_backing_file(self):
TEST_RETURN = "image: qemu.qcow2\n"\
"ID TAG VM SIZE DATE VM CLOCK\n"\
"1 snap1 1.7G 2011-10-04 19:04:00 32:06:34.974"
- fake_image_service = FakeImageService()
- mox = self._mox
- mox.StubOutWithMock(image_utils, 'fetch')
- mox.StubOutWithMock(utils, 'execute')
- image_utils.fetch(context, fake_image_service,
- self.TEST_IMAGE_ID, self.TEST_DEV_PATH, None, None)
-
- utils.execute(
- 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
- self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RETURN, 'ignored')
- )
-
- mox.ReplayAll()
-
- self.assertRaises(exception.ImageUnacceptable,
- image_utils.fetch_verify_image,
- context, fake_image_service,
- self.TEST_IMAGE_ID, self.TEST_DEV_PATH)
+ self._test_fetch_verify_image(TEST_RETURN)
def test_fetch_verify_image_without_file_format(self):
TEST_RETURN = "image: qemu.qcow2\n"\
"ID TAG VM SIZE DATE VM CLOCK\n"\
"1 snap1 1.7G 2011-10-04 19:04:00 32:06:34.974"
- fake_image_service = FakeImageService()
- mox = self._mox
- mox.StubOutWithMock(image_utils, 'fetch')
- mox.StubOutWithMock(utils, 'execute')
- image_utils.fetch(context, fake_image_service,
- self.TEST_IMAGE_ID, self.TEST_DEV_PATH, None, None)
+ self._test_fetch_verify_image(TEST_RETURN)
- utils.execute(
- 'env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info',
- self.TEST_DEV_PATH, run_as_root=True).AndReturn(
- (TEST_RETURN, 'ignored')
- )
-
- mox.ReplayAll()
+ def test_fetch_verify_image_image_size(self):
+ TEST_RETURN = "image: qemu.qcow2\n"\
+ "file_format: qcow2\n"\
+ "virtual_size: 2G (2147483648 bytes)\n"\
+ "cluster_size: 65536\n"\
+ "disk_size: 196K (200704 bytes)\n"\
+ "Snapshot list:\n"\
+ "ID TAG VM SIZE DATE VM CLOCK\n"\
+ "1 snap1 1.7G 2011-10-04 19:04:00 32:06:34.974"
- self.assertRaises(exception.ImageUnacceptable,
- image_utils.fetch_verify_image,
- context, fake_image_service,
- self.TEST_IMAGE_ID, self.TEST_DEV_PATH)
+ self._test_fetch_verify_image(TEST_RETURN)
def test_upload_volume(self):
image_meta = {'id': 1, 'disk_format': 'qcow2'}