compute: improve exceptions related to disk size checks
Having read several user reports of FlavorDiskTooSmall, it is apparent that this error is not meaningful to users. We create 3 new subclasses of FlavorDiskTooSmall: FlavorDiskSmallerThanImage, FlavorDiskSmallerThanMinDisk, and VolumeSmallerThanMinDisk, because these exceptions require different actions by the user. The new subclasses get a more detailed error message to help the user. Change-Id: I2234c4f4f9b5ac0780b3ec2e6a168380c07ed8c1
This commit is contained in:
parent
9e27fc1f47
commit
30e73e001d
|
@ -705,10 +705,8 @@ class API(base.Base):
|
|||
dest_size *= units.Gi
|
||||
|
||||
if image_min_disk > dest_size:
|
||||
# TODO(mdbooth) Raise a more descriptive exception here.
|
||||
# This is the exception which calling code expects, but
|
||||
# it's potentially misleading to the user.
|
||||
raise exception.FlavorDiskTooSmall()
|
||||
raise exception.VolumeSmallerThanMinDisk(
|
||||
volume_size=dest_size, image_min_disk=image_min_disk)
|
||||
|
||||
# Target disk is a local disk whose size is taken from the flavor
|
||||
else:
|
||||
|
@ -719,10 +717,12 @@ class API(base.Base):
|
|||
# drivers. A value of 0 means don't check size.
|
||||
if dest_size != 0:
|
||||
if image_size > dest_size:
|
||||
raise exception.FlavorDiskTooSmall()
|
||||
raise exception.FlavorDiskSmallerThanImage(
|
||||
flavor_size=dest_size, image_size=image_size)
|
||||
|
||||
if image_min_disk > dest_size:
|
||||
raise exception.FlavorDiskTooSmall()
|
||||
raise exception.FlavorDiskSmallerThanMinDisk(
|
||||
flavor_size=dest_size, image_min_disk=image_min_disk)
|
||||
|
||||
def _get_image_defined_bdms(self, base_options, instance_type, image_meta,
|
||||
root_device_name):
|
||||
|
|
|
@ -1255,7 +1255,24 @@ class FlavorMemoryTooSmall(NovaException):
|
|||
|
||||
|
||||
class FlavorDiskTooSmall(NovaException):
|
||||
msg_fmt = _("Flavor's disk is too small for requested image.")
|
||||
msg_fmt = _("The created instance's disk would be too small.")
|
||||
|
||||
|
||||
class FlavorDiskSmallerThanImage(FlavorDiskTooSmall):
|
||||
msg_fmt = _("Flavor's disk is too small for requested image. Flavor disk "
|
||||
"is %(flavor_size)i bytes, image is %(image_size)i bytes.")
|
||||
|
||||
|
||||
class FlavorDiskSmallerThanMinDisk(FlavorDiskTooSmall):
|
||||
msg_fmt = _("Flavor's disk is smaller than the minimum size specified in "
|
||||
"image metadata. Flavor disk is %(flavor_size)i bytes, "
|
||||
"minimum size is %(image_min_disk)i bytes.")
|
||||
|
||||
|
||||
class VolumeSmallerThanMinDisk(FlavorDiskTooSmall):
|
||||
msg_fmt = _("Volume is smaller than the minimum size specified in image "
|
||||
"metadata. Volume size is %(volume_size)i bytes, minimum "
|
||||
"size is %(image_min_disk)i bytes.")
|
||||
|
||||
|
||||
class InsufficientFreeMemory(NovaException):
|
||||
|
|
|
@ -7412,7 +7412,7 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
self.fake_image['min_disk'] = 2
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanMinDisk,
|
||||
self.compute_api.create, self.context,
|
||||
inst_type, self.fake_image['id'])
|
||||
|
||||
|
@ -7431,7 +7431,7 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
self.compute_api.create, self.context,
|
||||
inst_type, self.fake_image['id'])
|
||||
|
||||
|
@ -7873,7 +7873,7 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
self.fake_image['min_disk'] = 2
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanMinDisk,
|
||||
self.compute_api.rebuild, self.context,
|
||||
instance, self.fake_image['id'], 'new_password')
|
||||
|
||||
|
@ -7942,7 +7942,7 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
self.fake_image['size'] = '1073741825'
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
self.compute_api.rebuild, self.context,
|
||||
instance, self.fake_image['id'], 'new_password')
|
||||
|
||||
|
@ -11580,7 +11580,7 @@ class CheckRequestedImageTestCase(test.TestCase):
|
|||
def test_image_min_disk_check(self):
|
||||
image = dict(id='123', status='active', min_disk='2')
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanMinDisk,
|
||||
self.compute_api._check_requested_image, self.context,
|
||||
image['id'], image, self.instance_type, None)
|
||||
|
||||
|
@ -11591,7 +11591,7 @@ class CheckRequestedImageTestCase(test.TestCase):
|
|||
def test_image_too_large(self):
|
||||
image = dict(id='123', status='active', size='1073741825')
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
self.compute_api._check_requested_image, self.context,
|
||||
image['id'], image, self.instance_type, None)
|
||||
|
||||
|
@ -11659,7 +11659,7 @@ class CheckRequestedImageTestCase(test.TestCase):
|
|||
image_id=image_uuid, volume_id=volume_uuid,
|
||||
volume_size=self.instance_type.root_gb)
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.VolumeSmallerThanMinDisk,
|
||||
self.compute_api._check_requested_image,
|
||||
self.context, image_uuid, image, self.instance_type,
|
||||
root_bdm)
|
||||
|
@ -11703,7 +11703,7 @@ class CheckRequestedImageTestCase(test.TestCase):
|
|||
root_bdm = block_device_obj.BlockDeviceMapping(
|
||||
source_type='image', destination_type='local', image_id=image_uuid)
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
self.compute_api._check_requested_image,
|
||||
self.context, image['id'],
|
||||
image, self.instance_type, root_bdm)
|
||||
|
@ -11718,7 +11718,7 @@ class CheckRequestedImageTestCase(test.TestCase):
|
|||
root_bdm = block_device_obj.BlockDeviceMapping(
|
||||
source_type='image', destination_type='local', image_id=image_uuid)
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanMinDisk,
|
||||
self.compute_api._check_requested_image,
|
||||
self.context, image['id'],
|
||||
image, self.instance_type, root_bdm)
|
||||
|
|
|
@ -3223,9 +3223,15 @@ class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
|
|||
self._test_build_and_run_spawn_exceptions(
|
||||
exception.NoMoreFixedIps("error messge"))
|
||||
|
||||
def test_build_and_run_flavor_disk_too_small_exception(self):
|
||||
def test_build_and_run_flavor_disk_smaller_image_exception(self):
|
||||
self._test_build_and_run_spawn_exceptions(
|
||||
exception.FlavorDiskTooSmall())
|
||||
exception.FlavorDiskSmallerThanImage(
|
||||
flavor_size=0, image_size=1))
|
||||
|
||||
def test_build_and_run_flavor_disk_smaller_min_disk(self):
|
||||
self._test_build_and_run_spawn_exceptions(
|
||||
exception.FlavorDiskSmallerThanMinDisk(
|
||||
flavor_size=0, image_min_disk=1))
|
||||
|
||||
def test_build_and_run_flavor_memory_too_small_exception(self):
|
||||
self._test_build_and_run_spawn_exceptions(
|
||||
|
|
|
@ -489,7 +489,7 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
|
|||
self.mox.ReplayAll()
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
image.create_image, fn, self.TEMPLATE_PATH, 1)
|
||||
self.mox.VerifyAll()
|
||||
|
||||
|
@ -1362,7 +1362,7 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
|
|||
driver_mock.exists.return_value = True
|
||||
driver_mock.size.return_value = 2
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
image.create_image, mock.MagicMock(),
|
||||
self.TEMPLATE_PATH, 1)
|
||||
driver_mock.size.assert_called_once_with(image.rbd_name)
|
||||
|
|
|
@ -651,7 +651,7 @@ disk size: 4.4M
|
|||
target = 'big.qcow2'
|
||||
self.executes = []
|
||||
expected_commands = [('rm', '-f', 'big.qcow2.part')]
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
images.fetch_to_raw,
|
||||
context, image_id, target, user_id, project_id,
|
||||
max_size=1)
|
||||
|
|
|
@ -387,7 +387,8 @@ class FetchVhdImageTestCase(VMUtilsTestBase):
|
|||
|
||||
self.mox.StubOutWithMock(vm_utils, '_check_vdi_size')
|
||||
vm_utils._check_vdi_size(self.context, self.session, self.instance,
|
||||
"vdi").AndRaise(exception.FlavorDiskTooSmall)
|
||||
"vdi").AndRaise(exception.FlavorDiskSmallerThanImage(
|
||||
flavor_size=0, image_size=1))
|
||||
|
||||
self.mox.StubOutWithMock(self.session, 'call_xenapi')
|
||||
self.session.call_xenapi("VDI.get_by_uuid", "vdi").AndReturn("ref")
|
||||
|
@ -398,7 +399,7 @@ class FetchVhdImageTestCase(VMUtilsTestBase):
|
|||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
vm_utils._fetch_vhd_image, self.context, self.session,
|
||||
self.instance, 'image_id')
|
||||
|
||||
|
@ -628,7 +629,7 @@ class CheckVDISizeTestCase(VMUtilsTestBase):
|
|||
with mock.patch.object(self.instance, 'get_flavor') as get:
|
||||
self.flavor.root_gb = 1
|
||||
get.return_value = self.flavor
|
||||
self.assertRaises(exception.FlavorDiskTooSmall,
|
||||
self.assertRaises(exception.FlavorDiskSmallerThanImage,
|
||||
vm_utils._check_vdi_size, self.context,
|
||||
self.session, self.instance, self.vdi_uuid)
|
||||
|
||||
|
|
|
@ -116,7 +116,8 @@ def fetch_to_raw(context, image_href, path, user_id, project_id, max_size=0):
|
|||
{'base': path,
|
||||
'disk_size': disk_size,
|
||||
'size': max_size})
|
||||
raise exception.FlavorDiskTooSmall()
|
||||
raise exception.FlavorDiskSmallerThanImage(
|
||||
flavor_size=max_size, image_size=disk_size)
|
||||
|
||||
if fmt != "raw" and CONF.force_raw_images:
|
||||
staged = "%s.converted" % path
|
||||
|
|
|
@ -286,7 +286,8 @@ class Image(object):
|
|||
LOG.error(msg % {'base': base,
|
||||
'base_size': base_size,
|
||||
'size': size})
|
||||
raise exception.FlavorDiskTooSmall()
|
||||
raise exception.FlavorDiskSmallerThanImage(
|
||||
flavor_size=base_size, image_size=size)
|
||||
|
||||
def get_disk_size(self, name):
|
||||
return disk.get_disk_size(name)
|
||||
|
|
|
@ -139,7 +139,7 @@ PROGRESS_INTERVAL_SECONDS = 300
|
|||
|
||||
# Fudge factor to allow for the VHD chain to be slightly larger than
|
||||
# the partitioned space. Otherwise, legitimate images near their
|
||||
# maximum allowed size can fail on build with FlavorDiskTooSmall.
|
||||
# maximum allowed size can fail on build with FlavorDiskSmallerThanImage.
|
||||
VHD_SIZE_CHECK_FUDGE_FACTOR_GB = 10
|
||||
|
||||
|
||||
|
@ -1497,7 +1497,9 @@ def _check_vdi_size(context, session, instance, vdi_uuid):
|
|||
{'size': size, 'allowed_size': allowed_size},
|
||||
instance=instance)
|
||||
|
||||
raise exception.FlavorDiskTooSmall()
|
||||
raise exception.FlavorDiskSmallerThanImage(
|
||||
flavor_size=(flavor.root_gb * units.Gi),
|
||||
image_size=(size * units.Gi))
|
||||
|
||||
|
||||
def _fetch_disk_image(context, session, instance, name_label, image_id,
|
||||
|
|
Loading…
Reference in New Issue