Fix for volume from image snapshot free space issue

create_from_image() function checks for free space in conversion path
(by default /var/lib/cinder/conversion) even if cinder is creating
volume from image snapshot.

If /var/lib/cinder/conversion has less free space than the size of the
image volume is created from, exception will be thrown by
check_available_space() function in image_utils module.

This patch checks if cinder is configured with
allowed_direct_url_schemes = cinder
If so, cinder should not check free space in conversion path because
volume is created from image snapshot.

Closes-Bug: #1683228
Change-Id: I6330ed31dc9336c9d3d09c2d43c8f4913744e9a2
This commit is contained in:
Tadas Ustinavičius 2017-11-30 22:06:46 +02:00
parent 9ae14ed0fc
commit 30bb0dfbe7
2 changed files with 78 additions and 2 deletions

View File

@ -1139,6 +1139,71 @@ class CreateVolumeFlowManagerGlanceCinderBackendCase(test.TestCase):
self.assertFalse(fake_driver.create_cloned_volume.called)
mock_cleanup_cg.assert_called_once_with(volume)
@mock.patch('cinder.volume.flows.manager.create_volume.'
'CreateVolumeFromSpecTask.'
'_cleanup_cg_in_volume')
@mock.patch('cinder.image.image_utils.TemporaryImages.fetch')
@mock.patch('cinder.volume.flows.manager.create_volume.'
'CreateVolumeFromSpecTask.'
'_handle_bootable_volume_glance_meta')
@mock.patch('cinder.image.image_utils.qemu_img_info')
def test_create_from_image_volume_ignore_size(self, mock_qemu_info,
handle_bootable,
mock_fetch_img,
mock_cleanup_cg,
format='raw',
owner=None,
location=True):
self.flags(allowed_direct_url_schemes=['cinder'])
self.override_config('allowed_direct_url_schemes', 'cinder')
mock_fetch_img.return_value = mock.MagicMock(
spec=utils.get_file_spec())
fake_db = mock.MagicMock()
fake_driver = mock.MagicMock()
fake_manager = create_volume_manager.CreateVolumeFromSpecTask(
mock.MagicMock(), fake_db, fake_driver)
fake_image_service = fake_image.FakeImageService()
volume = fake_volume.fake_volume_obj(self.ctxt,
host='host@backend#pool')
image_volume = fake_volume.fake_volume_obj(self.ctxt,
volume_metadata={})
image_id = fakes.IMAGE_ID
image_info = imageutils.QemuImgInfo()
# Making huge image. If cinder will try to convert it, it
# will fail because of free space being too low.
image_info.virtual_size = '1073741824000000000000'
mock_qemu_info.return_value = image_info
url = 'cinder://%s' % image_volume['id']
image_location = None
if location:
image_location = (url, [{'url': url, 'metadata': {}}])
image_meta = {'id': image_id,
'container_format': 'bare',
'disk_format': format,
'size': 1024,
'owner': owner or self.ctxt.project_id,
'virtual_size': None,
'cinder_encryption_key_id': None}
fake_driver.clone_image.return_value = (None, False)
fake_db.volume_get_all_by_host.return_value = [image_volume]
fake_manager._create_from_image(self.ctxt,
volume,
image_location,
image_id,
image_meta,
fake_image_service)
if format is 'raw' and not owner and location:
fake_driver.create_cloned_volume.assert_called_once_with(
volume, image_volume)
handle_bootable.assert_called_once_with(self.ctxt, volume,
image_id=image_id,
image_meta=image_meta)
else:
self.assertFalse(fake_driver.create_cloned_volume.called)
mock_cleanup_cg.assert_called_once_with(volume)
def test_create_from_image_volume_in_qcow2_format(self):
self.test_create_from_image_volume(format='qcow2')

View File

@ -823,8 +823,19 @@ class CreateVolumeFromSpecTask(flow_utils.CinderTask):
os.path.exists(CONF.image_conversion_dir)):
os.makedirs(CONF.image_conversion_dir)
try:
image_utils.check_available_space(CONF.image_conversion_dir,
image_meta['size'], image_id)
# cinder should not check free space in conversion directory
# if it's creating volume from image snapshot (Bug1683228).
# If image disk format is other than raw, cinder should
# convert it (this means free space check will be needed).
if ('cinder' in CONF.allowed_direct_url_schemes and
image_meta.get('disk_format') == 'raw'):
LOG.debug("Creating volume from image snapshot. "
"Skipping free space check on image "
"convert path.")
else:
image_utils.check_available_space(
CONF.image_conversion_dir,
image_meta['size'], image_id)
except exception.ImageTooBig as err:
with excutils.save_and_reraise_exception():
self.message.create(