Merge "Rebase qcow2 images when unshelving an instance" into stable/ussuri
This commit is contained in:
commit
406acd6cb4
|
@ -22436,6 +22436,74 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
||||||
self.assertEqual('migrating instance across cells',
|
self.assertEqual('migrating instance across cells',
|
||||||
mock_debug.call_args[0][2])
|
mock_debug.call_args[0][2])
|
||||||
|
|
||||||
|
@mock.patch.object(libvirt_driver.LibvirtDriver, '_try_fetch_image_cache')
|
||||||
|
@mock.patch.object(libvirt_driver.LibvirtDriver, '_rebase_with_qemu_img')
|
||||||
|
def _test_unshelve_qcow2_rebase_image_during_create(self,
|
||||||
|
mock_rebase, mock_fetch, original_image_in_glance=True):
|
||||||
|
self.flags(images_type='qcow2', group='libvirt')
|
||||||
|
|
||||||
|
# Original image ref from where instance was created, before SHELVE
|
||||||
|
# occurs, base_root_fname is related backing file name.
|
||||||
|
base_image_ref = 'base_image_ref'
|
||||||
|
base_root_fname = imagecache.get_cache_fname(base_image_ref)
|
||||||
|
# Snapshot image ref created during SHELVE.
|
||||||
|
shelved_image_ref = 'shelved_image_ref'
|
||||||
|
shelved_root_fname = imagecache.get_cache_fname(shelved_image_ref)
|
||||||
|
|
||||||
|
# Instance state during unshelve spawn().
|
||||||
|
inst_params = {
|
||||||
|
'image_ref': shelved_image_ref,
|
||||||
|
'vm_state': vm_states.SHELVED_OFFLOADED,
|
||||||
|
'system_metadata': {'image_base_image_ref': base_image_ref}
|
||||||
|
}
|
||||||
|
|
||||||
|
instance = self._create_instance(params=inst_params)
|
||||||
|
disk_images = {'image_id': instance.image_ref}
|
||||||
|
instance_dir = libvirt_utils.get_instance_path(instance)
|
||||||
|
disk_path = os.path.join(instance_dir, 'disk')
|
||||||
|
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||||
|
|
||||||
|
if original_image_in_glance:
|
||||||
|
# We expect final backing file is original image, not shelved one.
|
||||||
|
expected_backing_file = os.path.join(
|
||||||
|
imagecache.ImageCacheManager().cache_dir,
|
||||||
|
base_root_fname)
|
||||||
|
else:
|
||||||
|
# None means rebase will merge backing file into disk(flatten).
|
||||||
|
expected_backing_file = None
|
||||||
|
mock_fetch.side_effect = [
|
||||||
|
None,
|
||||||
|
exception.ImageNotFound(image_id=base_image_ref)
|
||||||
|
]
|
||||||
|
|
||||||
|
drvr._create_and_inject_local_root(
|
||||||
|
self.context, instance, False, '', disk_images, None, None)
|
||||||
|
|
||||||
|
mock_fetch.assert_has_calls([
|
||||||
|
mock.call(test.MatchType(nova.virt.libvirt.imagebackend.Qcow2),
|
||||||
|
libvirt_utils.fetch_image,
|
||||||
|
self.context, shelved_root_fname, shelved_image_ref,
|
||||||
|
instance, instance.root_gb * units.Gi, None),
|
||||||
|
mock.call(test.MatchType(nova.virt.libvirt.imagebackend.Qcow2),
|
||||||
|
libvirt_utils.fetch_image,
|
||||||
|
self.context, base_root_fname, base_image_ref,
|
||||||
|
instance, None)])
|
||||||
|
mock_rebase.assert_called_once_with(disk_path, expected_backing_file)
|
||||||
|
|
||||||
|
def test_unshelve_qcow2_rebase_image_during_create(self):
|
||||||
|
# Original image is present in Glance. In that case the 2nd
|
||||||
|
# fetch succeeds and we rebase instance disk to original image backing
|
||||||
|
# file, instance is back to nominal state: after unshelve,
|
||||||
|
# instance.image_ref will match current backing file.
|
||||||
|
self._test_unshelve_qcow2_rebase_image_during_create()
|
||||||
|
|
||||||
|
def test_unshelve_qcow2_rebase_image_during_create_notfound(self):
|
||||||
|
# Original image is no longer available in Glance, so 2nd fetch
|
||||||
|
# will failed (HTTP 404). In that case qemu-img rebase will merge
|
||||||
|
# backing file into disk, removing backing file dependency.
|
||||||
|
self._test_unshelve_qcow2_rebase_image_during_create(
|
||||||
|
original_image_in_glance=False)
|
||||||
|
|
||||||
@mock.patch('nova.virt.libvirt.driver.imagebackend')
|
@mock.patch('nova.virt.libvirt.driver.imagebackend')
|
||||||
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._inject_data')
|
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._inject_data')
|
||||||
@mock.patch('nova.virt.libvirt.driver.imagecache')
|
@mock.patch('nova.virt.libvirt.driver.imagecache')
|
||||||
|
|
|
@ -4180,6 +4180,14 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||||
root_fname, disk_images['image_id'],
|
root_fname, disk_images['image_id'],
|
||||||
instance, size, fallback_from_host)
|
instance, size, fallback_from_host)
|
||||||
|
|
||||||
|
# During unshelve on Qcow2 backend, we spawn() using snapshot image
|
||||||
|
# created during shelve. Extra work is needed in order to rebase
|
||||||
|
# disk image to its original image_ref. Disk backing file will
|
||||||
|
# then represent back image_ref instead of shelved image.
|
||||||
|
if (instance.vm_state == vm_states.SHELVED_OFFLOADED and
|
||||||
|
isinstance(backend, imagebackend.Qcow2)):
|
||||||
|
self._finalize_unshelve_qcow2_image(context, instance, backend)
|
||||||
|
|
||||||
if need_inject:
|
if need_inject:
|
||||||
self._inject_data(backend, instance, injection_info)
|
self._inject_data(backend, instance, injection_info)
|
||||||
|
|
||||||
|
@ -4189,6 +4197,36 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||||
|
|
||||||
return created_disks
|
return created_disks
|
||||||
|
|
||||||
|
def _finalize_unshelve_qcow2_image(self, context, instance, backend):
|
||||||
|
# NOTE(aarents): During qcow2 instance unshelve, backing file
|
||||||
|
# represents shelved image, not original instance.image_ref.
|
||||||
|
# We rebase here instance disk to original image.
|
||||||
|
# This second fetch call does nothing except downloading original
|
||||||
|
# backing file if missing, as image disk have already been
|
||||||
|
# created/resized by first fetch call.
|
||||||
|
base_dir = self.image_cache_manager.cache_dir
|
||||||
|
base_image_ref = instance.system_metadata.get('image_base_image_ref')
|
||||||
|
root_fname = imagecache.get_cache_fname(base_image_ref)
|
||||||
|
base_backing_fname = os.path.join(base_dir, root_fname)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._try_fetch_image_cache(backend, libvirt_utils.fetch_image,
|
||||||
|
context, root_fname, base_image_ref,
|
||||||
|
instance, None)
|
||||||
|
except exception.ImageNotFound:
|
||||||
|
# We must flatten here in order to remove dependency with an orphan
|
||||||
|
# backing file (as shelved image will be dropped once unshelve
|
||||||
|
# is successfull).
|
||||||
|
LOG.warning('Current disk image is created on top of shelved '
|
||||||
|
'image and cannot be rebased to original image '
|
||||||
|
'because it is no longer available in the image '
|
||||||
|
'service, disk will be consequently flattened.',
|
||||||
|
instance=instance)
|
||||||
|
base_backing_fname = None
|
||||||
|
|
||||||
|
LOG.info('Rebasing disk image.', instance=instance)
|
||||||
|
self._rebase_with_qemu_img(backend.path, base_backing_fname)
|
||||||
|
|
||||||
def _create_configdrive(self, context, instance, injection_info,
|
def _create_configdrive(self, context, instance, injection_info,
|
||||||
rescue=False):
|
rescue=False):
|
||||||
# As this method being called right after the definition of a
|
# As this method being called right after the definition of a
|
||||||
|
|
Loading…
Reference in New Issue