Merge "libvirt: flatten rbd images when unshelving an instance" into stable/stein
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user