]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Add a netns-cleanup functional test
authorMiguel Angel Ajo <mangelajo@redhat.com>
Thu, 12 Mar 2015 14:58:39 +0000 (14:58 +0000)
committerMiguel Angel Ajo <mangelajo@redhat.com>
Fri, 13 Mar 2015 17:14:37 +0000 (17:14 +0000)
We have lots of regressions on netns, because unit test
is not enough. This commit adds basic functional testing
to the netns_cleanup.

This work should be extended when we have functional testing
for the dhcp agent, spawning dhcp services, and then
making sure they're fully cleaned up.

Change-Id: I0b5125dfa24a3dbcd44593ae2aee4dbbd47def67

neutron/cmd/netns_cleanup.py
neutron/tests/functional/agent/linux/base.py
neutron/tests/functional/cmd/__init__.py [new file with mode: 0644]
neutron/tests/functional/cmd/test_netns_cleanup.py [new file with mode: 0755]

index 4d7e5f175f3eb2dade7fec1596d97cc969a63296..cde77b1edf6bb4b92b8a8c18ad95a85dc41d2929 100644 (file)
@@ -142,6 +142,19 @@ def destroy_namespace(conf, namespace, force=False):
         LOG.exception(_LE('Error unable to destroy namespace: %s'), namespace)
 
 
+def cleanup_network_namespaces(conf):
+    # Identify namespaces that are candidates for deletion.
+    candidates = [ns for ns in
+                  ip_lib.IPWrapper.get_namespaces()
+                  if eligible_for_deletion(conf, ns, conf.force)]
+
+    if candidates:
+        time.sleep(2)
+
+        for namespace in candidates:
+            destroy_namespace(conf, namespace, conf.force)
+
+
 def main():
     """Main method for cleaning up network namespaces.
 
@@ -162,14 +175,4 @@ def main():
     conf = setup_conf()
     conf()
     config.setup_logging()
-
-    # Identify namespaces that are candidates for deletion.
-    candidates = [ns for ns in
-                  ip_lib.IPWrapper.get_namespaces()
-                  if eligible_for_deletion(conf, ns, conf.force)]
-
-    if candidates:
-        time.sleep(2)
-
-        for namespace in candidates:
-            destroy_namespace(conf, namespace, conf.force)
+    cleanup_network_namespaces(conf)
index c626e0596f7e96a2ac7608c49063859cffb513b7..e1be0a8ec9974b9a05ce360db5c084d7819007ed 100644 (file)
@@ -33,6 +33,7 @@ ICMP_MARK_RULE = ('-j MARK --set-xmark %(value)s/%(mask)s'
 MARKED_BLOCK_RULE = '-m mark --mark %s -j DROP' % MARK_VALUE
 ICMP_BLOCK_RULE = '-p icmp -j DROP'
 VETH_PREFIX = 'tst-vth'
+NS_PREFIX = 'func-'
 
 
 #TODO(jschwarz): Move these two functions to neutron/tests/common/
@@ -62,11 +63,16 @@ class BaseLinuxTestCase(functional_base.BaseSudoTestCase):
                 self.skipTest(skip_msg)
             raise
 
-    def _create_namespace(self):
+    @staticmethod
+    def _cleanup_namespace(namespace):
+        if namespace.netns.exists(namespace.namespace):
+            namespace.netns.delete(namespace.namespace)
+
+    def _create_namespace(self, prefix=NS_PREFIX):
         ip_cmd = ip_lib.IPWrapper()
-        name = "func-%s" % uuidutils.generate_uuid()
+        name = prefix + uuidutils.generate_uuid()
         namespace = ip_cmd.ensure_namespace(name)
-        self.addCleanup(namespace.netns.delete, namespace.namespace)
+        self.addCleanup(BaseLinuxTestCase._cleanup_namespace, namespace)
 
         return namespace
 
@@ -165,14 +171,15 @@ class BaseIPVethTestCase(BaseLinuxTestCase):
         device.addr.add(cidr)
         device.link.set_up()
 
-    def prepare_veth_pairs(self):
+    def prepare_veth_pairs(self, src_ns_prefix=NS_PREFIX,
+                           dst_ns_prefix=NS_PREFIX):
 
         src_addr = self.SRC_ADDRESS
         dst_addr = self.DST_ADDRESS
         src_veth = get_rand_veth_name()
         dst_veth = get_rand_veth_name()
-        src_ns = self._create_namespace()
-        dst_ns = self._create_namespace()
+        src_ns = self._create_namespace(src_ns_prefix)
+        dst_ns = self._create_namespace(dst_ns_prefix)
 
         src_veth, dst_veth = src_ns.add_veth(src_veth,
                                              dst_veth,
diff --git a/neutron/tests/functional/cmd/__init__.py b/neutron/tests/functional/cmd/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/neutron/tests/functional/cmd/test_netns_cleanup.py b/neutron/tests/functional/cmd/test_netns_cleanup.py
new file mode 100755 (executable)
index 0000000..e6405c9
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (c) 2015 Red Hat, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import mock
+
+from neutron.agent.l3 import agent as l3_agent
+from neutron.agent.linux import dhcp
+from neutron.agent.linux import ip_lib
+from neutron.cmd import netns_cleanup
+from neutron.tests.functional.agent.linux import base
+
+GET_NAMESPACES = 'neutron.agent.linux.ip_lib.IPWrapper.get_namespaces'
+TEST_INTERFACE_DRIVER = 'neutron.agent.linux.interface.OVSInterfaceDriver'
+
+
+class NetnsCleanupTest(base.BaseIPVethTestCase):
+    def setUp(self):
+        super(NetnsCleanupTest, self).setUp()
+
+        self.get_namespaces_p = mock.patch(GET_NAMESPACES)
+        self.get_namespaces = self.get_namespaces_p.start()
+
+    def setup_config(self, args=None):
+        if args is None:
+            args = []
+        # force option enabled to make sure non-empty namespaces are
+        # cleaned up and deleted
+        args.append('--force')
+
+        self.conf = netns_cleanup.setup_conf()
+        self.conf.set_override('interface_driver', TEST_INTERFACE_DRIVER)
+        self.config_parse(conf=self.conf, args=args)
+
+    def test_cleanup_network_namespaces_cleans_dhcp_and_l3_namespaces(self):
+        l3_ns, dhcp_ns = self.prepare_veth_pairs(l3_agent.NS_PREFIX,
+                                                 dhcp.NS_PREFIX)
+        # we scope the get_namespaces to our own ones not to affect other
+        # tests, as otherwise cleanup will kill them all
+        self.get_namespaces.return_value = [l3_ns.namespace,
+                                            dhcp_ns.namespace]
+
+        netns_cleanup.cleanup_network_namespaces(self.conf)
+
+        self.get_namespaces_p.stop()
+        namespaces_now = ip_lib.IPWrapper.get_namespaces()
+        self.assertNotIn(l3_ns.namespace, namespaces_now)
+        self.assertNotIn(dhcp_ns.namespace, namespaces_now)