Merge "libvirt: flatten rbd image during cross-cell move spawn at dest"
This commit is contained in:
commit
7e15762c0a
|
@ -5925,13 +5925,6 @@ class ComputeManager(manager.Manager):
|
|||
# If we spawned from a temporary snapshot image we can delete that now,
|
||||
# similar to how unshelve works.
|
||||
if snapshot_id:
|
||||
# FIXME(mriedem): Need to deal with bug 1653953 for libvirt with
|
||||
# the rbd image backend. I think the cleanest thing we can do is
|
||||
# from the driver check to see if instance.migration_context is not
|
||||
# None and if so, get the Migration record for that context
|
||||
# (instance.migration_context.migration_id) and from that check the
|
||||
# Migration.cross_cell_move flag and if True, then flatten the
|
||||
# image.
|
||||
compute_utils.delete_image(
|
||||
ctxt, instance, self.image_api, snapshot_id)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ from oslo_utils import versionutils
|
|||
|
||||
from nova.db import api as db
|
||||
from nova import exception
|
||||
from nova import objects
|
||||
from nova.objects import base
|
||||
from nova.objects import fields
|
||||
|
||||
|
@ -120,3 +121,19 @@ class MigrationContext(base.NovaPersistentObject, base.NovaObject):
|
|||
for upd_dev in updated_pci_devs
|
||||
if curr_dev.request_id == upd_dev.request_id}
|
||||
return {}
|
||||
|
||||
def is_cross_cell_move(self):
|
||||
"""Helper to determine if this is a context for a cross-cell move.
|
||||
|
||||
Based on the ``migration_id`` in this context, gets the Migration
|
||||
object and returns its ``cross_cell_move`` value.
|
||||
|
||||
The result is cached for subsequent lookups.
|
||||
|
||||
:return: True if this is a cross cell move migration, False otherwise.
|
||||
"""
|
||||
if not hasattr(self, '_cached_cross_cell_move'):
|
||||
migration = objects.Migration.get_by_id(
|
||||
self._context, self.migration_id)
|
||||
setattr(self, '_cached_cross_cell_move', migration.cross_cell_move)
|
||||
return self._cached_cross_cell_move
|
||||
|
|
|
@ -14,6 +14,7 @@ import mock
|
|||
from oslo_serialization import jsonutils
|
||||
from oslo_utils.fixture import uuidsentinel as uuids
|
||||
|
||||
from nova import context
|
||||
from nova import exception
|
||||
from nova import objects
|
||||
from nova.tests.unit.objects import test_instance_numa
|
||||
|
@ -125,6 +126,17 @@ class _TestMigrationContext(object):
|
|||
objects.MigrationContext.get_by_instance_uuid,
|
||||
self.context, 'fake_uuid')
|
||||
|
||||
@mock.patch('nova.objects.Migration.get_by_id',
|
||||
return_value=objects.Migration(cross_cell_move=True))
|
||||
def test_is_cross_cell_move(self, mock_get_by_id):
|
||||
ctxt = context.get_admin_context()
|
||||
mig_ctx = get_fake_migration_context_obj(ctxt)
|
||||
self.assertTrue(mig_ctx.is_cross_cell_move())
|
||||
mock_get_by_id.assert_called_once_with(ctxt, mig_ctx.migration_id)
|
||||
# Call it again to make sure the result was cached.
|
||||
self.assertTrue(mig_ctx.is_cross_cell_move())
|
||||
mock_get_by_id.assert_called_once_with(ctxt, mig_ctx.migration_id)
|
||||
|
||||
|
||||
class TestMigrationContext(test_objects._LocalTest, _TestMigrationContext):
|
||||
|
||||
|
|
|
@ -919,6 +919,7 @@ def _create_test_instance():
|
|||
'vm_state': None,
|
||||
'trusted_certs': None,
|
||||
'resources': None,
|
||||
'migration_context': None,
|
||||
}
|
||||
|
||||
|
||||
|
@ -20394,9 +20395,12 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
# Attributes which we need to be set so they don't touch the db,
|
||||
# but it's not worth the effort to fake properly
|
||||
for field in ['numa_topology', 'vcpu_model', 'trusted_certs',
|
||||
'resources', 'migration_context']:
|
||||
'resources']:
|
||||
setattr(instance, field, None)
|
||||
|
||||
# fake_instance_obj nulls migration_context so set it here.
|
||||
instance.migration_context = params.get('migration_context')
|
||||
|
||||
return instance
|
||||
|
||||
@mock.patch(('nova.virt.libvirt.driver.LibvirtDriver.'
|
||||
|
@ -21421,9 +21425,7 @@ 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})
|
||||
def _test_noop_flatten_fetch_image_cache(self, instance):
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
mock_imagebackend = mock.Mock(spec=imagebackend.Lvm)
|
||||
mock_imagebackend.flatten.side_effect = NotImplementedError()
|
||||
|
@ -21434,16 +21436,28 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
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.
|
||||
# still SHELVED_OFFLOADED or doing a cross-cell move 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):
|
||||
def test_unshelve_noop_flatten_fetch_image_cache(self):
|
||||
instance = self._create_instance(
|
||||
params={'vm_state': vm_states.SHELVED_OFFLOADED})
|
||||
self._test_noop_flatten_fetch_image_cache(instance)
|
||||
|
||||
@mock.patch('nova.objects.MigrationContext.is_cross_cell_move',
|
||||
return_value=True)
|
||||
def test_cross_cell_move_noop_flatten_fetch_image_cache(self, mock_is_ccm):
|
||||
instance = self._create_instance(
|
||||
params={'migration_context': objects.MigrationContext()})
|
||||
self._test_noop_flatten_fetch_image_cache(instance)
|
||||
mock_is_ccm.assert_called_once_with()
|
||||
|
||||
def _test_rbd_image_flatten_during_fetch_image_cache(self, instance):
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
mock_rbd_driver = mock.Mock(spec=rbd_utils.RBDDriver)
|
||||
mock_rbd_driver.pool = mock.sentinel.rbd_pool
|
||||
|
@ -21460,7 +21474,8 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
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.
|
||||
# still SHELVED_OFFLOADED or doing a cross-cell move 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,
|
||||
|
@ -21469,6 +21484,27 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
mock_rbd_driver.flatten.assert_called_once_with(
|
||||
mock.sentinel.rbd_name, pool=mock.sentinel.rbd_pool)
|
||||
|
||||
@mock.patch('nova.virt.libvirt.driver.LOG.debug')
|
||||
def test_rbd_image_flatten_during_fetch_image_cache(self, mock_debug):
|
||||
instance = self._create_instance(
|
||||
params={'vm_state': vm_states.SHELVED_OFFLOADED})
|
||||
self._test_rbd_image_flatten_during_fetch_image_cache(instance)
|
||||
mock_debug.assert_called_once()
|
||||
self.assertEqual('unshelving instance', mock_debug.call_args[0][2])
|
||||
|
||||
@mock.patch('nova.virt.libvirt.driver.LOG.debug')
|
||||
@mock.patch('nova.objects.MigrationContext.is_cross_cell_move',
|
||||
return_value=True)
|
||||
def test_cross_cell_move_rbd_flatten_fetch_image_cache(self, mock_is_ccm,
|
||||
mock_debug):
|
||||
instance = self._create_instance(
|
||||
params={'migration_context': objects.MigrationContext()})
|
||||
self._test_rbd_image_flatten_during_fetch_image_cache(instance)
|
||||
mock_is_ccm.assert_called_once_with()
|
||||
mock_debug.assert_called_once()
|
||||
self.assertEqual('migrating instance across cells',
|
||||
mock_debug.call_args[0][2])
|
||||
|
||||
@mock.patch('nova.virt.libvirt.driver.imagebackend')
|
||||
@mock.patch('nova.virt.libvirt.driver.LibvirtDriver._inject_data')
|
||||
@mock.patch('nova.virt.libvirt.driver.imagecache')
|
||||
|
|
|
@ -9243,17 +9243,27 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
|
||||
# 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(mriedem): Alternatively if we are doing a cross-cell move of a
|
||||
# non-volume-backed server and finishing (spawning) on the dest host,
|
||||
# we have to flatten the rbd image so we can delete the temporary
|
||||
# snapshot in the compute manager.
|
||||
mig_context = instance.migration_context
|
||||
cross_cell_move = (
|
||||
mig_context and mig_context.is_cross_cell_move() or False)
|
||||
if instance.vm_state == vm_states.SHELVED_OFFLOADED or cross_cell_move:
|
||||
# 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.
|
||||
action = (
|
||||
'migrating instance across cells' if cross_cell_move
|
||||
else 'unshelving instance')
|
||||
try:
|
||||
image.flatten()
|
||||
LOG.debug('Image %s flattened successfully while unshelving '
|
||||
'instance.', image.path, instance=instance)
|
||||
LOG.debug('Image %s flattened successfully while %s.',
|
||||
image.path, action, 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
|
||||
|
|
Loading…
Reference in New Issue