Add a check for virtual_size at API layer

When creating a bootable volume from image, we check if the volume
can fit the image which includes several checks like size, min_disk,
virtual_size etc of image should be <= volume size.
We do check the virtual_size but however that check comes at a very
later stage in the cinder-volume process which makes the check
asynchronous.
In a case where nova requests cinder to create a bootable volume
from image, it gets an OK status from cinder-api and then fails
later at the cinder-volume layer but nova isn't aware about the
failure and times out waiting for a reply from cinder.
To avoid the above scenario, we are adding a virtual_size check at
the API layer to fail fast if the volume size doesn't satisfy the
contraints to store the image.

Closes-Bug: #1980268

Change-Id: Ia5950c2dc6186b721c9c9cfc4629d72e3b731889
This commit is contained in:
whoami-rajat 2022-06-23 17:41:30 +05:30
parent 2774c2537e
commit 75d5fabff0
3 changed files with 46 additions and 0 deletions

View File

@ -1144,6 +1144,36 @@ class VolumeUtilsTestCase(test.TestCase):
vol_size)
self.assertIn("Image 1 is not active.", str(res))
@ddt.data(None, 1, 3)
def test_check_image_metadata_virtual_size(self, fake_virtual_size):
image_meta = {'id': 1, 'min_disk': 1, 'status': 'active',
'size': 1 * units.Gi,
'virtual_size': fake_virtual_size * units.Gi
if fake_virtual_size else None}
vol_size = 2
if fake_virtual_size and fake_virtual_size > vol_size:
res = self.assertRaises(
exception.ImageUnacceptable,
volume_utils.check_image_metadata,
image_meta,
vol_size)
self.assertIn("Image virtual size is %(image_size)dGB"
" and doesn't fit in a volume of size"
" %(volume_size)dGB." %
{'image_size': fake_virtual_size,
'volume_size': vol_size}, str(res))
else:
with mock.patch(
'cinder.image.image_utils.check_virtual_size') as \
mock_check_virtual_size:
volume_utils.check_image_metadata(image_meta, vol_size)
if fake_virtual_size:
mock_check_virtual_size.assert_called_once_with(
image_meta['virtual_size'], vol_size,
image_meta['id'])
else:
mock_check_virtual_size.assert_not_called()
def test_enable_volume_bootable(self):
ctxt = context.get_admin_context()
volume = test_utils.create_volume(ctxt, bootable=False)

View File

@ -1125,6 +1125,12 @@ def check_image_metadata(image_meta: dict[str, Union[str, int]],
msg = msg % {'volume_size': vol_size, 'min_disk': min_disk}
raise exception.InvalidInput(reason=msg)
# Check if virtual size is not greater than volume size
virtual_size = utils.as_int(image_meta.get('virtual_size'))
if virtual_size:
image_utils.check_virtual_size(virtual_size, vol_size,
image_meta['id'])
def enable_bootable_flag(volume: 'objects.Volume') -> None:
try:

View File

@ -0,0 +1,10 @@
---
fixes:
- |
`Bug #1980268 <https://bugs.launchpad.net/cinder/+bug/1980268>`_:
When creating a volume from an image, a check has been added to compare
the requested volume size to the image's ``virtual_size`` property and
fail the request if the volume will be too small to contain the image.
If the image record does not contain this property, the request is
accepted but the volume will go to ``error`` status if the image does
not fit (which is the current behavior).