diff --git a/neutron/agent/linux/iptables_manager.py b/neutron/agent/linux/iptables_manager.py index a7678909847..3f12e1a6f69 100644 --- a/neutron/agent/linux/iptables_manager.py +++ b/neutron/agent/linux/iptables_manager.py @@ -33,6 +33,7 @@ import six from neutron._i18n import _, _LE, _LW from neutron.agent.common import config +from neutron.agent.linux import ip_lib from neutron.agent.linux import iptables_comments as ic from neutron.agent.linux import utils as linux_utils from neutron.common import exceptions as n_exc @@ -471,7 +472,20 @@ class IptablesManager(object): args = ['%s-save' % (cmd,)] if self.namespace: args = ['ip', 'netns', 'exec', self.namespace] + args - save_output = self.execute(args, run_as_root=True) + try: + save_output = self.execute(args, run_as_root=True) + except RuntimeError: + # We could be racing with a cron job deleting namespaces. + # It is useless to try to apply iptables rules over and + # over again in a endless loop if the namespace does not + # exist. + with excutils.save_and_reraise_exception() as ctx: + if (self.namespace and not + ip_lib.IPWrapper().netns.exists(self.namespace)): + ctx.reraise = False + LOG.error(_LE("Namespace %s was deleted during " + "IPTables operations."), self.namespace) + return [] all_lines = save_output.split('\n') commands = [] # Traverse tables in sorted order for predictable dump output diff --git a/neutron/tests/unit/agent/linux/test_iptables_manager.py b/neutron/tests/unit/agent/linux/test_iptables_manager.py index cb0d8289e50..2d243f06948 100644 --- a/neutron/tests/unit/agent/linux/test_iptables_manager.py +++ b/neutron/tests/unit/agent/linux/test_iptables_manager.py @@ -982,6 +982,20 @@ class IptablesManagerStateFulTestCase(base.BaseTestCase): {'wrap': True, 'top': False, 'rule': '-j DROP', 'chain': 'nonexistent'}) + def test_iptables__apply_synchronized_no_namespace(self): + self.execute.side_effect = RuntimeError + # no namespace set so should raise + self.assertRaises(RuntimeError, + self.iptables._apply_synchronized) + self.iptables.namespace = 'test' + with mock.patch('neutron.agent.linux.ip_lib.IpNetnsCommand.exists', + return_value=True): + self.assertRaises(RuntimeError, + self.iptables._apply_synchronized) + with mock.patch('neutron.agent.linux.ip_lib.IpNetnsCommand.exists', + return_value=False): + self.assertEqual([], self.iptables._apply_synchronized()) + def test_iptables_failure_with_no_failing_line_number(self): with mock.patch.object(iptables_manager, "LOG") as log: # generate Runtime errors on iptables-restore calls