Merge "libvirt: flatten rbd images when unshelving an instance" into stable/stein

This commit is contained in:
Zuul
2019-06-28 23:22:21 +00:00
committed by Gerrit Code Review
4 changed files with 89 additions and 2 deletions

View File

@@ -852,6 +852,7 @@ def _create_test_instance():
'vcpu_model': None,
'host': 'fake-host',
'task_state': None,
'vm_state': None,
'trusted_certs': None
}
@@ -17096,8 +17097,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
prepare.side_effect = fake_prepare
drvr = libvirt_driver.LibvirtDriver(virtapi, False)
instance = objects.Instance(vm_state=vm_states.BUILDING,
**self.test_instance)
instance = objects.Instance(**self.test_instance)
instance.vm_state = vm_states.BUILDING
vifs = [{'id': uuids.vif_1, 'active': False},
{'id': uuids.vif_2, 'active': False}]
@@ -18866,6 +18867,7 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
inst['system_metadata'] = {}
inst['metadata'] = {}
inst['task_state'] = None
inst['vm_state'] = None
inst.update(params)
@@ -19849,6 +19851,54 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
bdm.append({'boot_index': 0})
self.assertTrue(func(bdi))
def test_unshelve_noop_flatten_fetch_image_cache(self):
instance = self._create_instance(
params={'vm_state': vm_states.SHELVED_OFFLOADED})
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
mock_imagebackend = mock.Mock(spec=imagebackend.Lvm)
mock_imagebackend.flatten.side_effect = NotImplementedError()
# Assert that this doesn't raise NotImplementedError
drvr._try_fetch_image_cache(mock_imagebackend, mock.sentinel.fetch,
self.context, mock.sentinel.filename, uuids.image_id,
instance, mock.sentinel.size)
# Assert that we cache and then flatten the image when an instance is
# still SHELVED_OFFLOADED during _try_fetch_image_cache.
mock_imagebackend.cache.assert_called_once_with(
fetch_func=mock.sentinel.fetch, context=self.context,
filename=mock.sentinel.filename, image_id=uuids.image_id,
size=mock.sentinel.size, trusted_certs=instance.trusted_certs)
mock_imagebackend.flatten.assert_called_once()
def test_unshelve_rbd_image_flatten_during_fetch_image_cache(self):
instance = self._create_instance(
params={'vm_state': vm_states.SHELVED_OFFLOADED})
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
mock_rbd_driver = mock.Mock(spec=rbd_utils.RBDDriver)
mock_rbd_imagebackend = mock.Mock(spec=imagebackend.Rbd)
mock_rbd_imagebackend.rbd_name = mock.sentinel.rbd_name
mock_rbd_imagebackend.pool = mock.sentinel.rbd_pool
# This is logged so we can't use a sentinel
mock_rbd_imagebackend.path = 'rbd:pool/vol_disk'
mock_rbd_imagebackend.driver = mock_rbd_driver
mock_rbd_imagebackend.flatten.side_effect = \
imagebackend.Rbd.flatten(mock_rbd_imagebackend)
drvr._try_fetch_image_cache(mock_rbd_imagebackend, mock.sentinel.fetch,
self.context, mock.sentinel.filename, uuids.image_id,
instance, mock.sentinel.size)
# Assert that we cache and then flatten the image when an instance is
# still SHELVED_OFFLOADED during _try_fetch_image_cache.
mock_rbd_imagebackend.cache.assert_called_once_with(
fetch_func=mock.sentinel.fetch, context=self.context,
filename=mock.sentinel.filename, image_id=uuids.image_id,
size=mock.sentinel.size, trusted_certs=instance.trusted_certs)
mock_rbd_imagebackend.flatten.assert_called_once()
mock_rbd_driver.flatten.assert_called_once_with(
mock.sentinel.rbd_name, pool=mock.sentinel.rbd_pool)
@mock.patch('nova.virt.libvirt.driver.imagebackend')
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._inject_data')
@mock.patch('nova.virt.libvirt.driver.imagecache')

View File

@@ -1565,6 +1565,12 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
["server1:1899", "server2:1920"]),
model)
@mock.patch.object(rbd_utils.RBDDriver, 'flatten')
def test_flatten(self, mock_flatten):
image = self.image_class(self.INSTANCE, self.NAME)
image.flatten()
mock_flatten.assert_called_once_with(image.rbd_name, pool=self.POOL)
def test_import_file(self):
image = self.image_class(self.INSTANCE, self.NAME)

View File

@@ -8338,6 +8338,26 @@ class LibvirtDriver(driver.ComputeDriver):
image.cache(fetch_func=copy_from_host, size=size,
filename=filename)
# NOTE(lyarwood): If the instance vm_state is shelved offloaded then we
# must be unshelving for _try_fetch_image_cache to be called.
if instance.vm_state == vm_states.SHELVED_OFFLOADED:
# NOTE(lyarwood): When using the rbd imagebackend the call to cache
# above will attempt to clone from the shelved snapshot in Glance
# if available from this compute. We then need to flatten the
# resulting image to avoid it still referencing and ultimately
# blocking the removal of the shelved snapshot at the end of the
# unshelve. This is a no-op for all but the rbd imagebackend.
try:
image.flatten()
LOG.debug('Image %s flattened successfully while unshelving '
'instance.', image.path, instance=instance)
except NotImplementedError:
# NOTE(lyarwood): There's an argument to be made for logging
# our inability to call flatten here, however given this isn't
# implemented for most of the backends it may do more harm than
# good, concerning operators etc so for now just pass.
pass
def _create_images_and_backing(self, context, instance, instance_dir,
disk_info, fallback_from_host=None):
""":param context: security context

View File

@@ -430,6 +430,14 @@ class Image(object):
raise exception.ImageUnacceptable(image_id=image_id_or_uri,
reason=reason)
def flatten(self):
"""Flatten an image.
The implementation of this method is optional and therefore is
not an abstractmethod.
"""
raise NotImplementedError('flatten() is not implemented')
def direct_snapshot(self, context, snapshot_name, image_format, image_id,
base_image_id):
"""Prepare a snapshot for direct reference from glance.
@@ -959,6 +967,9 @@ class Rbd(Image):
raise exception.ImageUnacceptable(image_id=image_id_or_uri,
reason=reason)
def flatten(self):
self.driver.flatten(self.rbd_name, pool=self.pool)
def get_model(self, connection):
secret = None
if CONF.libvirt.rbd_secret_uuid: