Skip to content

Instantly share code, notes, and snippets.

@zioproto
Last active April 28, 2016 14:35
Show Gist options
  • Save zioproto/9aba7336b18e9769a85d55d520540456 to your computer and use it in GitHub Desktop.
Save zioproto/9aba7336b18e9769a85d55d520540456 to your computer and use it in GitHub Desktop.
commit 74252dd0915310013dbdf7b53fe813590bb4ca0a
Author: Saverio Proto <saverio.proto@switch.ch>
Date: Thu Apr 21 16:50:07 2016 +0200
Check if namespace exists before exec commands
If a neutron router has no ports defined, its namespace is deleted.
It is required to check if the namespace exists before calling
exec commands against the namespace.
It is not enough for the string of the namespace uuid to be defined,
the namespace must really exist on the network node.
Otherwise the agent log file will be flooded with messages like
Cannot open network namespace "qrouter-<uuid>": No such file or directory
Failed to process compatible router '<uuid>'
Related-bug: 1573073
Change-Id: I744ef11529f9da5cbfdb812de0b35b95f9d078bb
diff --git a/neutron/agent/linux/ip_lib.py b/neutron/agent/linux/ip_lib.py
index 903e68f..9e6ba79 100644
--- a/neutron/agent/linux/ip_lib.py
+++ b/neutron/agent/linux/ip_lib.py
@@ -92,16 +92,19 @@ class IPWrapper(SubProcessBase):
def get_devices(self, exclude_loopback=False):
retval = []
+ output = []
if self.namespace:
- # 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()
+ if self.netns.exists(self.namespace):
+ # 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()
+ # if self.namespace is not defined handle the default namespace devices
else:
output = (
i for i in os.listdir(SYS_NET_PATH)
diff --git a/neutron/agent/linux/ipset_manager.py b/neutron/agent/linux/ipset_manager.py
index 4120693..e63c4ad 100644
--- a/neutron/agent/linux/ipset_manager.py
+++ b/neutron/agent/linux/ipset_manager.py
@@ -14,6 +14,7 @@
import netaddr
from neutron.agent.linux import utils as linux_utils
+from neutron.agent.linux import ip_lib
from neutron.common import utils
IPSET_ADD_BULK_THRESHOLD = 5
@@ -134,9 +135,15 @@ class IpsetManager(object):
cmd_ns = []
if self.namespace:
cmd_ns.extend(['ip', 'netns', 'exec', self.namespace])
- cmd_ns.extend(cmd)
- self.execute(cmd_ns, run_as_root=True, process_input=input,
- check_exit_code=fail_on_errors)
+ cmd_ns.extend(cmd)
+ ip = ip_lib.IPWrapper()
+ if ip.netns.exists(self.namespace):
+ self.execute(cmd_ns, run_as_root=True, process_input=input,
+ check_exit_code=fail_on_errors)
+ else:
+ cmd_ns.extend(cmd)
+ self.execute(cmd_ns, run_as_root=True, process_input=input,
+ check_exit_code=fail_on_errors)
def _get_new_set_ips(self, set_name, expected_ips):
new_member_ips = (set(expected_ips) -
diff --git a/neutron/agent/linux/iptables_manager.py b/neutron/agent/linux/iptables_manager.py
index 604db0c..4c463ea 100644
--- a/neutron/agent/linux/iptables_manager.py
+++ b/neutron/agent/linux/iptables_manager.py
@@ -32,6 +32,7 @@ from oslo_utils import excutils
from neutron.agent.common import config
from neutron.agent.linux import iptables_comments as ic
from neutron.agent.linux import utils as linux_utils
+from neutron.agent.linux import ip_lib
from neutron.common import exceptions as n_exc
from neutron.common import utils
from neutron.i18n import _LE, _LW
@@ -445,8 +446,17 @@ class IptablesManager(object):
args = ['%s-save' % (cmd,), '-c']
if self.namespace:
args = ['ip', 'netns', 'exec', self.namespace] + args
- all_tables = self.execute(args, run_as_root=True)
+ ip = ip_lib.IPWrapper()
+ if ip.netns.exists(self.namespace):
+ all_tables = self.execute(args, run_as_root=True)
+ else:
+ LOG.debug("IPTablesManager.apply tried to access a not "
+ "existing namespace on the network node.")
+ return
+ else:
+ all_tables = self.execute(args, run_as_root=True)
all_lines = all_tables.split('\n')
+ commands = []
# Traverse tables in sorted order for predictable dump output
for table_name in sorted(tables):
table = tables[table_name]
diff --git a/neutron/tests/unit/agent/linux/test_ip_lib.py b/neutron/tests/unit/agent/linux/test_ip_lib.py
index 6ad7b50..d7bcdac 100644
--- a/neutron/tests/unit/agent/linux/test_ip_lib.py
+++ b/neutron/tests/unit/agent/linux/test_ip_lib.py
@@ -253,13 +253,15 @@ class TestIpWrapper(base.BaseTestCase):
fake_str = mock.Mock()
fake_str.split.return_value = ['lo']
mocked_execute.return_value = fake_str
- retval = ip_lib.IPWrapper(namespace='foo').get_devices()
- mocked_execute.assert_called_once_with(
- ['ip', 'netns', 'exec', 'foo', 'find', '/sys/class/net',
- '-maxdepth', '1', '-type', 'l', '-printf', '%f '],
- run_as_root=True, log_fail_as_error=True)
- self.assertTrue(fake_str.split.called)
- self.assertEqual(retval, [ip_lib.IPDevice('lo', namespace='foo')])
+ with mock.patch.object(ip_lib, 'IpNetnsCommand') as ip_ns_cmd:
+ ip_ns_cmd.exists.return_value = True
+ retval = ip_lib.IPWrapper(namespace='foo').get_devices()
+ mocked_execute.assert_called_once_with(
+ ['ip', 'netns', 'exec', 'foo', 'find', '/sys/class/net',
+ '-maxdepth', '1', '-type', 'l', '-printf', '%f '],
+ run_as_root=True, log_fail_as_error=True)
+ self.assertTrue(fake_str.split.called)
+ self.assertEqual(retval, [ip_lib.IPDevice('lo', namespace='foo')])
def test_get_namespaces(self):
self.execute.return_value = '\n'.join(NETNS_SAMPLE)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment