From 28a7dd12fef78857a0c0f347cf11a63091ea0f5a Mon Sep 17 00:00:00 2001 From: Adrian Chiris Date: Thu, 31 Jan 2019 18:51:33 +0200 Subject: [PATCH] Delete port binding level for deleted bindings Today, if live migration has failed after an inactive binding was created on the destination node but before the activation of the created binding, the port's binding level for the destination host is not cleared during nova's API call to neutron to delete the port binding. This causes future attempts to perform live migration of the instance to the same host to fail. This change removes port binding level object during port binding deletion. Closes-Bug: #1815345 Change-Id: Idd55f7d24a2062c08ac8a0dc2243625632d962a5 (cherry picked from commit b197f7c1c4b9c0dd4c58f5c5a4b654dde5596b85) --- neutron/plugins/ml2/plugin.py | 6 +++++- neutron/tests/unit/plugins/ml2/test_plugin.py | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index f6fede5c045..1a3462c5f2e 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -2266,5 +2266,9 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, @utils.transaction_guard @db_api.retry_if_session_inactive() def delete_port_binding(self, context, host, port_id): - ports_obj.PortBinding.delete_objects(context, host=host, + ports_obj.PortBinding.delete_objects(context, + host=host, port_id=port_id) + db.clear_binding_levels(context, + port_id=port_id, + host=host) diff --git a/neutron/tests/unit/plugins/ml2/test_plugin.py b/neutron/tests/unit/plugins/ml2/test_plugin.py index 08944f24422..a5cacb763b7 100644 --- a/neutron/tests/unit/plugins/ml2/test_plugin.py +++ b/neutron/tests/unit/plugins/ml2/test_plugin.py @@ -1660,6 +1660,23 @@ class TestMl2PluginOnly(Ml2PluginV2TestCase): self.assertEqual(port_id, ml2_plugin.Ml2Plugin._device_to_port_id( self.context, port_id)) + @mock.patch.object(ml2_db, 'clear_binding_levels') + @mock.patch.object(port_obj.PortBinding, 'delete_objects') + def test_delete_port_binding_delete_binding_and_levels( + self, + clear_bl_mock, + delete_port_binding_mock): + port_id = uuidutils.generate_uuid() + host = 'fake-host' + plugin = directory.get_plugin() + plugin.delete_port_binding(self.context, host, port_id) + self.assertTrue(clear_bl_mock.called_with(self.context, + port_id=port_id, + host=host)) + self.assertTrue(delete_port_binding_mock.called_with(self.context, + host=host, + port_id=port_id)) + class Test_GetNetworkMtu(Ml2PluginV2TestCase):