Merge "Remove dest node allocations during live migration rollback"

This commit is contained in:
Jenkins 2017-10-06 14:30:19 +00:00 committed by Gerrit Code Review
commit ef76319541
4 changed files with 70 additions and 43 deletions

View File

@ -5963,6 +5963,19 @@ class ComputeManager(manager.Manager):
Contains the status we want to set for the migration object
"""
# Remove allocations created in Placement for the dest node.
# NOTE(mriedem): The migrate_data.migration object does not have the
# dest_node (or dest UUID) set, so we have to lookup the destination
# ComputeNode with only the hostname.
dest_node = objects.ComputeNode.get_first_node_by_host_for_old_compat(
context, dest, use_slave=True)
reportclient = self.scheduler_client.reportclient
resources = scheduler_utils.resources_from_flavor(
instance, instance.flavor)
reportclient.remove_provider_from_instance_allocation(
instance.uuid, dest_node.uuid, instance.user_id,
instance.project_id, resources)
instance.task_state = None
instance.progress = 0
instance.save(expected_task_state=[task_states.MIGRATING])

View File

@ -2269,23 +2269,12 @@ class ServerMovingTests(ProviderUsageBaseTestCase):
dest_usages = self._get_provider_usages(dest_rp_uuid)
# Assert the allocations, created by the scheduler, are cleaned up
# after the rollback happens.
# FIXME: This is bug 1715182 where rollback doesn't remove the
# allocations against the dest node. Uncomment once fixed.
self.assertFlavorMatchesAllocation(self.flavor1, dest_usages)
# self.assertFlavorMatchesAllocation(
# {'vcpus': 0, 'ram': 0, 'disk': 0}, dest_usages)
self.assertFlavorMatchesAllocation(
{'vcpus': 0, 'ram': 0, 'disk': 0}, dest_usages)
allocations = self._get_allocations_by_server_uuid(server['id'])
# There should only be 1 allocation for the instance on the source node
# FIXME: This is bug 1715182 where rollback doesn't remove the
# allocations against the dest node. Uncomment once fixed.
# self.assertEqual(1, len(allocations))
self.assertEqual(2, len(allocations))
self.assertIn(dest_rp_uuid, allocations)
self.assertFlavorMatchesAllocation(
self.flavor1, allocations[dest_rp_uuid]['resources'])
self.assertEqual(1, len(allocations))
self.assertIn(source_rp_uuid, allocations)
self.assertFlavorMatchesAllocation(
self.flavor1, allocations[source_rp_uuid]['resources'])
@ -2477,14 +2466,8 @@ class ServerMovingTests(ProviderUsageBaseTestCase):
self._run_periodics()
allocations = self._get_allocations_by_server_uuid(server['id'])
# Note(lajos katona): After solving bug #1714237 there should be
# only 1 allocation:
# self.assertEqual(1, len(allocations))
self.assertEqual(2, len(allocations))
# Note(lajos katona): After solving bug #1714237 the destination
# resource provider should not be among the allocations:
# self.assertNotIn(dest_rp_uuid, allocations)
self.assertEqual(1, len(allocations))
self.assertNotIn(dest_rp_uuid, allocations)
source_usages = self._get_provider_usages(source_rp_uuid)
self.assertFlavorMatchesAllocation(self.flavor1, source_usages)
@ -2493,18 +2476,8 @@ class ServerMovingTests(ProviderUsageBaseTestCase):
self.assertFlavorMatchesAllocation(self.flavor1, source_allocation)
dest_usages = self._get_provider_usages(dest_rp_uuid)
# Note(lajos katona): After solving bug #1714237 on the destination
# there should be zero usage:
# self.assertFlavorMatchesAllocation(
# {'ram': 0, 'disk': 0, 'vcpus': 0}, dest_usages)
self.assertFlavorMatchesAllocation(self.flavor1, dest_usages)
dest_allocation = allocations[dest_rp_uuid]['resources']
# Note(lajos katona): After solving bug #1714237 on the destination
# there should be zero allocation:
# self.assertFlavorMatchesAllocation(
# {'ram': 0, 'disk': 0, 'vcpus': 0}, dest_allocation)
self.assertFlavorMatchesAllocation(self.flavor1, dest_allocation)
self.assertFlavorMatchesAllocation(
{'ram': 0, 'disk': 0, 'vcpus': 0}, dest_usages)
self._delete_and_check_allocations(
server, source_rp_uuid, dest_rp_uuid)

View File

@ -5867,6 +5867,10 @@ class ComputeTestCase(BaseTestCase,
@mock.patch.object(fake.FakeDriver, 'get_instance_disk_info')
@mock.patch.object(compute_rpcapi.ComputeAPI, 'pre_live_migration')
@mock.patch.object(objects.ComputeNode,
'get_first_node_by_host_for_old_compat')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'remove_provider_from_instance_allocation')
@mock.patch.object(objects.BlockDeviceMappingList, 'get_by_instance_uuid')
@mock.patch.object(compute_rpcapi.ComputeAPI, 'remove_volume_connection')
@mock.patch.object(compute_rpcapi.ComputeAPI,
@ -5874,7 +5878,8 @@ class ComputeTestCase(BaseTestCase,
@mock.patch('nova.objects.Migration.save')
def test_live_migration_exception_rolls_back(self, mock_save,
mock_rollback, mock_remove,
mock_get_uuid, mock_pre, mock_get_disk):
mock_get_uuid, mock_remove_allocs,
mock_get_node, mock_pre, mock_get_disk):
# Confirm exception when pre_live_migration fails.
c = context.get_admin_context()
@ -5884,7 +5889,9 @@ class ComputeTestCase(BaseTestCase,
updated_instance = self._create_fake_instance_obj(
{'host': 'fake-dest-host'})
dest_host = updated_instance['host']
fake_bdms = [
dest_node = objects.ComputeNode(host=dest_host, uuid=uuids.dest_node)
mock_get_node.return_value = dest_node
fake_bdms = objects.BlockDeviceMappingList(objects=[
objects.BlockDeviceMapping(
**fake_block_device.FakeDbBlockDeviceDict(
{'volume_id': uuids.volume_id_1,
@ -5895,7 +5902,7 @@ class ComputeTestCase(BaseTestCase,
{'volume_id': uuids.volume_id_2,
'source_type': 'volume',
'destination_type': 'volume'}))
]
])
migrate_data = migrate_data_obj.XenapiLiveMigrateData(
block_migration=True)
@ -5925,6 +5932,9 @@ class ComputeTestCase(BaseTestCase,
block_device_info=block_device_info)
mock_pre.assert_called_once_with(c,
instance, True, 'fake_disk', dest_host, migrate_data)
mock_remove_allocs.assert_called_once_with(
instance.uuid, dest_node.uuid, instance.user_id,
instance.project_id, test.MatchType(dict))
mock_setup.assert_called_once_with(c, instance, self.compute.host)
mock_get_uuid.assert_called_with(c, instance.uuid)
mock_remove.assert_has_calls([
@ -6259,14 +6269,21 @@ class ComputeTestCase(BaseTestCase,
terminate_connection.assert_called_once_with(
c, uuids.volume_id, 'fake-connector')
@mock.patch.object(objects.ComputeNode,
'get_first_node_by_host_for_old_compat')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'remove_provider_from_instance_allocation')
@mock.patch('nova.objects.BlockDeviceMappingList.get_by_instance_uuid')
def test_rollback_live_migration(self, mock_bdms):
def test_rollback_live_migration(self, mock_bdms, mock_remove_allocs,
mock_get_node):
c = context.get_admin_context()
instance = mock.MagicMock()
migration = mock.MagicMock()
migrate_data = {'migration': migration}
mock_bdms.return_value = []
dest_node = objects.ComputeNode(host='foo', uuid=uuids.dest_node)
mock_get_node.return_value = dest_node
mock_bdms.return_value = objects.BlockDeviceMappingList()
@mock.patch('nova.compute.utils.notify_about_instance_action')
@mock.patch.object(self.compute, '_live_migration_cleanup_flags')
@ -6275,6 +6292,9 @@ class ComputeTestCase(BaseTestCase,
mock_lmcf.return_value = False, False
self.compute._rollback_live_migration(c, instance, 'foo',
migrate_data=migrate_data)
mock_remove_allocs.assert_called_once_with(
instance.uuid, dest_node.uuid, instance.user_id,
instance.project_id, test.MatchType(dict))
mock_notify.assert_has_calls([
mock.call(c, instance, self.compute.host,
action='live_migration_rollback', phase='start'),
@ -6288,14 +6308,22 @@ class ComputeTestCase(BaseTestCase,
self.assertEqual(0, instance.progress)
migration.save.assert_called_once_with()
@mock.patch.object(objects.ComputeNode,
'get_first_node_by_host_for_old_compat')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'remove_provider_from_instance_allocation')
@mock.patch('nova.objects.BlockDeviceMappingList.get_by_instance_uuid')
def test_rollback_live_migration_set_migration_status(self, mock_bdms):
def test_rollback_live_migration_set_migration_status(self, mock_bdms,
mock_remove_allocs,
mock_get_node):
c = context.get_admin_context()
instance = mock.MagicMock()
migration = mock.MagicMock()
migrate_data = {'migration': migration}
mock_bdms.return_value = []
dest_node = objects.ComputeNode(host='foo', uuid=uuids.dest_node)
mock_get_node.return_value = dest_node
mock_bdms.return_value = objects.BlockDeviceMappingList()
@mock.patch('nova.compute.utils.notify_about_instance_action')
@mock.patch.object(self.compute, '_live_migration_cleanup_flags')
@ -6305,6 +6333,9 @@ class ComputeTestCase(BaseTestCase,
self.compute._rollback_live_migration(c, instance, 'foo',
migrate_data=migrate_data,
migration_status='fake')
mock_remove_allocs.assert_called_once_with(
instance.uuid, dest_node.uuid, instance.user_id,
instance.project_id, test.MatchType(dict))
mock_notify.assert_has_calls([
mock.call(c, instance, self.compute.host,
action='live_migration_rollback', phase='start'),

View File

@ -6071,8 +6071,15 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase):
_test()
def test_rollback_live_migration_handles_dict(self):
@mock.patch.object(objects.ComputeNode,
'get_first_node_by_host_for_old_compat')
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
'remove_provider_from_instance_allocation')
def test_rollback_live_migration_handles_dict(self, mock_remove_allocs,
mock_get_node):
compute = manager.ComputeManager()
dest_node = objects.ComputeNode(host='foo', uuid=uuids.dest_node)
mock_get_node.return_value = dest_node
@mock.patch('nova.compute.utils.notify_about_instance_action')
@mock.patch.object(compute.network_api, 'setup_networks_on_host')
@ -6081,12 +6088,15 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase):
@mock.patch('nova.objects.BlockDeviceMappingList.get_by_instance_uuid')
def _test(mock_bdm, mock_lmcf, mock_notify, mock_nwapi,
mock_notify_about_instance_action):
mock_bdm.return_value = []
mock_bdm.return_value = objects.BlockDeviceMappingList()
mock_lmcf.return_value = False, False
mock_instance = mock.MagicMock()
compute._rollback_live_migration(self.context,
mock_instance,
'foo', {})
mock_remove_allocs.assert_called_once_with(
mock_instance.uuid, dest_node.uuid, mock_instance.user_id,
mock_instance.project_id, test.MatchType(dict))
mock_notify_about_instance_action.assert_has_calls([
mock.call(self.context, mock_instance, compute.host,
action='live_migration_rollback', phase='start'),