diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py index cae6991d1d3..e3cbe6b94c5 100644 --- a/neutron/agent/linux/ip_lib.py +++ b/neutron/agent/linux/ip_lib.py @@ -125,12 +125,21 @@ class IPWrapper(SubProcessBase): # we call out manually because in order to avoid screen scraping # iproute2 we use find to see what is in the sysfs directory, as # suggested by Stephen Hemminger (iproute2 dev). - output = utils.execute(['ip', 'netns', 'exec', self.namespace, - 'find', SYS_NET_PATH, '-maxdepth', '1', - '-type', 'l', '-printf', '%f '], - run_as_root=True, - log_fail_as_error=self.log_fail_as_error - ).split() + try: + cmd = ['ip', 'netns', 'exec', self.namespace, + 'find', SYS_NET_PATH, '-maxdepth', '1', + '-type', 'l', '-printf', '%f '] + output = utils.execute( + cmd, + run_as_root=True, + log_fail_as_error=self.log_fail_as_error).split() + except RuntimeError: + # We could be racing with a cron job deleting namespaces. + # Just return a empty list if the namespace is deleted. + with excutils.save_and_reraise_exception() as ctx: + if not self.netns.exists(self.namespace): + ctx.reraise = False + return [] else: output = ( i for i in os.listdir(SYS_NET_PATH) diff --git a/neutron/tests/unit/agent/linux/test_ip_lib.py b/neutron/tests/unit/agent/linux/test_ip_lib.py index 58a5ed6c218..20f1cce70ca 100644 --- a/neutron/tests/unit/agent/linux/test_ip_lib.py +++ b/neutron/tests/unit/agent/linux/test_ip_lib.py @@ -282,6 +282,24 @@ class TestIpWrapper(base.BaseTestCase): self.assertTrue(fake_str.split.called) self.assertEqual(retval, [ip_lib.IPDevice('lo', namespace='foo')]) + @mock.patch('neutron.agent.common.utils.execute') + def test_get_devices_namespaces_ns_not_exists(self, mocked_execute): + mocked_execute.side_effect = RuntimeError( + "Cannot open network namespace") + with mock.patch.object(ip_lib.IpNetnsCommand, 'exists', + return_value=False): + retval = ip_lib.IPWrapper(namespace='foo').get_devices() + self.assertEqual([], retval) + + @mock.patch('neutron.agent.common.utils.execute') + def test_get_devices_namespaces_ns_exists(self, mocked_execute): + mocked_execute.side_effect = RuntimeError( + "Cannot open network namespace") + with mock.patch.object(ip_lib.IpNetnsCommand, 'exists', + return_value=True): + self.assertRaises(RuntimeError, + ip_lib.IPWrapper(namespace='foo').get_devices) + @mock.patch('neutron.agent.common.utils.execute') def test_get_devices_exclude_loopback_and_gre(self, mocked_execute): device_name = 'somedevice'