From 9b9c2c52f323c536fb90bb29a40efbed1b129594 Mon Sep 17 00:00:00 2001
From: Balazs Gibizer <balazs.gibizer@ericsson.com>
Date: Fri, 11 Aug 2017 11:40:35 +0200
Subject: delete allocation of evacuated instance

After evacuation the instance has allocations on both the source and
the destination computes. This is OK as the source compute is down.
However after the source compute is brought up the allocation from
the source host needs to be cleaned up.

Closes-Bug: #1709902
Change-Id: I0df401a7c91f012fdb25cb0e6b344ca51de8c309
---
 nova/compute/manager.py                          |  5 +++++
 nova/compute/resource_tracker.py                 | 15 +++++++++++++++
 nova/tests/functional/test_servers.py            | 21 +++++----------------
 nova/tests/unit/compute/test_compute.py          |  3 +++
 nova/tests/unit/compute/test_compute_mgr.py      | 16 +++++++++++++---
 nova/tests/unit/compute/test_resource_tracker.py | 16 ++++++++++++++++
 6 files changed, 57 insertions(+), 19 deletions(-)

diff --git a/nova/compute/manager.py b/nova/compute/manager.py
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -675,6 +675,11 @@ class ComputeManager(manager.Manager):
             self.driver.destroy(context, instance,
                                 network_info,
                                 bdi, destroy_disks)
+
+            rt = self._get_resource_tracker()
+            rt.delete_allocation_for_evacuated_instance(
+                instance, migration.source_node)
+
             migration.status = 'completed'
             migration.save()
 
diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py
--- a/nova/compute/resource_tracker.py
+++ b/nova/compute/resource_tracker.py
@@ -903,6 +903,21 @@
         self.scheduler_client.reportclient.remove_deleted_instances(
                 self.compute_node, self.tracked_instances.values())
 
+    def delete_allocation_for_evacuated_instance(self, instance, node):
+        # Clean up the instance allocation from this node in placement
+        my_resources = scheduler_utils.resources_from_flavor(
+            instance, instance.flavor)
+
+        cn_uuid = self.compute_nodes[node].uuid
+
+        res = self.reportclient.remove_provider_from_instance_allocation(
+            instance.uuid, cn_uuid, instance.user_id,
+            instance.project_id, my_resources)
+        if not res:
+            LOG.error("Failed to clean allocation of an evacuated "
+                      "instance on the source node  %s",
+                      cn_uuid, instance=instance)
+
     def _find_orphaned_instances(self):
         """Given the set of instances and migrations already account for
         by resource tracker, sanity check the hypervisor to determine
diff --git a/nova/tests/functional/test_servers.py b/nova/tests/functional/test_servers.py
--- a/nova/tests/unit/compute/test_compute.py
+++ b/nova/tests/unit/compute/test_compute.py
@@ -6947,6 +6947,7 @@ class ComputeTestCase(BaseTestCase,
             {'host': 'otherhost'})
 
         migration = objects.Migration(instance_uuid=evacuated_instance.uuid)
+        migration.source_node = NODENAME
         mock_get_filter.return_value = [migration]
         instances.append(evacuated_instance)
         mock_get_inst.return_value = instances
--- a/nova/tests/unit/compute/test_resource_tracker.py
+++ b/nova/tests/unit/compute/test_resource_tracker.py
@@ -2156,6 +2156,22 @@ class TestUpdateUsageFromInstance(BaseTestCase):
         self.assertEqual(-1024, cn.free_ram_mb)
         self.assertEqual(-1, cn.free_disk_gb)
 
+    @mock.patch('nova.scheduler.utils.resources_from_flavor')
+    def test_delete_allocation_for_evacuated_instance(
+            self, mock_resource_from_flavor):
+        mock_resource = mock.Mock()
+        mock_resource_from_flavor.return_value = mock_resource
+        instance = _INSTANCE_FIXTURES[0].obj_clone()
+        instance.uuid = uuids.inst0
+
+        self.rt.delete_allocation_for_evacuated_instance(instance, _NODENAME)
+
+        rc = self.rt.reportclient
+        mock_remove_allocation = rc.remove_provider_from_instance_allocation
+        mock_remove_allocation.assert_called_once_with(
+            instance.uuid, self.rt.compute_nodes[_NODENAME].uuid,
+            instance.user_id, instance.project_id, mock_resource)
+
 
 class TestInstanceInResizeState(test.NoDBTestCase):
     def test_active_suspending(self):
-- 
cgit v1.1

