diff --git a/neutron/agent/linux/interface.py b/neutron/agent/linux/interface.py index 3470182f366..311e7f5e9c9 100644 --- a/neutron/agent/linux/interface.py +++ b/neutron/agent/linux/interface.py @@ -364,6 +364,11 @@ class OVSInterfaceDriver(LinuxInterfaceDriver): LOG.warning("Failed to set interface %s into namespace %s. " "Interface not found, attempt: %s, retrying.", device, namespace, i + 1) + # NOTE(slaweq) In such case it's required to reset device's + # namespace as it was already set to the "namespace" + # and after retry neutron will look for it in that namespace + # which is wrong + device.namespace = None time.sleep(1) except utils.WaitTimeout: # NOTE(slaweq): if the exception was WaitTimeout then it means diff --git a/neutron/tests/unit/agent/linux/test_interface.py b/neutron/tests/unit/agent/linux/test_interface.py index e8c929729f7..9b3b5ca13eb 100644 --- a/neutron/tests/unit/agent/linux/test_interface.py +++ b/neutron/tests/unit/agent/linux/test_interface.py @@ -517,6 +517,20 @@ class TestOVSInterfaceDriver(TestBase): ovs_br.assert_has_calls([mock.call('br-int'), mock.call().delete_port('tap0')]) + def test__add_device_to_namespace_retries(self): + ovs = interface.OVSInterfaceDriver(self.conf) + namespace_obj = self.ip.return_value.ensure_namespace.return_value + self.ip.ensure_namespace.return_value = namespace_obj + namespace_obj.add_device_to_namespace.side_effect = ( + ip_lib.NetworkInterfaceNotFound) + device = mock.MagicMock() + self.assertRaises( + ip_lib.NetworkInterfaceNotFound, + ovs._add_device_to_namespace, + self.ip, device, "test-ns") + self.assertEqual(10, namespace_obj.add_device_to_namespace.call_count) + self.assertIsNone(device.namespace) + class TestOVSInterfaceDriverWithVeth(TestOVSInterfaceDriver):