Fix nova evacuate issues for RBD

For RBD scenario, there are some issues in Nova code
now against evacuate function:

1. Based on current implementation, nova evacuate and
nova rebuild are sharing some code. When user enables
the on_shared_storage option for nova evacuate, nova
will check if the instance path is accessible. For
the RBD scenario, the volume(block) is shared between
different hosts, though the path isn't shared at the
filesystem level. This patch fixes this issue and adds
test cases for that.

2. Missing the 'recreate' parameter for rebuild method.
Though the libvirt driver doesn't implement rebuild
method(only Ironic driver implements it), but we really
need to set 'recreate' in kwargs so it gets passed to
_rebuild_default_impl so we don't call driver.destroy
on evacuate for shared filesystem/block storage cases.
It is fixed in this patch and test case is added as well.

Closes-Bug: 1249319
Closes-Bug: 1340411

Change-Id: Idc8c45b055e986cf85730235d5d25777632ad1c1
(cherry picked from commit 91d3272b97)
This commit is contained in:
Fei Long Wang 2014-09-16 15:43:37 +12:00
parent b86bcb9358
commit 7920cfdab2
4 changed files with 64 additions and 2 deletions

View File

@ -2803,7 +2803,8 @@ class ComputeManager(manager.Manager):
attach_block_devices=self._prep_block_device,
block_device_info=block_device_info,
network_info=network_info,
preserve_ephemeral=preserve_ephemeral)
preserve_ephemeral=preserve_ephemeral,
recreate=recreate)
try:
self.driver.rebuild(**kwargs)
except NotImplementedError:

View File

@ -1974,6 +1974,50 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
do_test()
def test_rebuild_default_impl(self):
def _detach(context, bdms):
pass
def _attach(context, instance, bdms, do_check_attach=True):
return {'block_device_mapping': 'shared_block_storage'}
def _spawn(context, instance, image_meta, injected_files,
admin_password, network_info=None, block_device_info=None):
self.assertEqual(block_device_info['block_device_mapping'],
'shared_block_storage')
with contextlib.nested(
mock.patch.object(self.compute.driver, 'destroy',
return_value=None),
mock.patch.object(self.compute.driver, 'spawn',
side_effect=_spawn),
mock.patch.object(objects.Instance, 'save',
return_value=None)
) as(
mock_destroy,
mock_spawn,
mock_save
):
instance = fake_instance.fake_instance_obj(self.context)
instance.task_state = task_states.REBUILDING
instance.save(expected_task_state=[task_states.REBUILDING])
self.compute._rebuild_default_impl(self.context,
instance,
None,
[],
admin_password='new_pass',
bdms=[],
detach_block_devices=_detach,
attach_block_devices=_attach,
network_info=None,
recreate=True,
block_device_info=None,
preserve_ephemeral=False)
self.assertFalse(mock_destroy.called)
self.assertTrue(mock_save.called)
self.assertTrue(mock_spawn.called)
class ComputeManagerBuildInstanceTestCase(test.NoDBTestCase):
def setUp(self):

View File

@ -12428,6 +12428,17 @@ class LibvirtDriverTestCase(test.TestCase):
vconfig.LibvirtConfigGuestGIDMap,
1, 20000, 10)
def test_instance_on_disk(self):
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
instance = objects.Instance(uuid='fake-uuid', id=1)
self.assertFalse(conn.instance_on_disk(instance))
def test_instance_on_disk_rbd(self):
self.flags(images_type='rbd', group='libvirt')
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
instance = objects.Instance(uuid='fake-uuid', id=1)
self.assertTrue(conn.instance_on_disk(instance))
class LibvirtVolumeUsageTestCase(test.TestCase):
"""Test for LibvirtDriver.get_all_volume_usage."""

View File

@ -6220,7 +6220,13 @@ class LibvirtDriver(driver.ComputeDriver):
# ensure directories exist and are writable
instance_path = libvirt_utils.get_instance_path(instance)
LOG.debug('Checking instance files accessibility %s', instance_path)
return os.access(instance_path, os.W_OK)
shared_instance_path = os.access(instance_path, os.W_OK)
# NOTE(flwang): For shared block storage scenario, the file system is
# not really shared by the two hosts, but the volume of evacuated
# instance is reachable.
shared_block_storage = (self.image_backend.backend().
is_shared_block_storage())
return shared_instance_path or shared_block_storage
def inject_network_info(self, instance, nw_info):
self.firewall_driver.setup_basic_filtering(instance, nw_info)