]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Refactor NetcatTester class
authorJakub Libosvar <libosvar@redhat.com>
Fri, 5 Jun 2015 14:32:51 +0000 (14:32 +0000)
committerJakub Libosvar <libosvar@redhat.com>
Sat, 27 Jun 2015 16:24:19 +0000 (16:24 +0000)
Following capabilities were added:
   - used transport protocol is passed as a constant instead of bool
   - src port for testing was added
   - connection can be established explicitly
   - change constructor parameters of NetcatTester

As a part of removing bool for protocol definition
get_free_namespace_port() was also modified to match the behavior.

Change-Id: Id2ec322e7f731c05a3754a65411c9a5d8b258126

neutron/tests/fullstack/config_fixtures.py
neutron/tests/functional/agent/linux/helpers.py
neutron/tests/functional/agent/linux/test_iptables.py
neutron/tests/functional/agent/test_l3_agent.py

index b887b5ae184c95531881b074d6f61c8f471d829e..ec1248d1b0557861e12794c7cb1b4e835b1685cb 100644 (file)
@@ -140,7 +140,7 @@ class NeutronConfigFixture(ConfigFixture):
         This might fail if some other process occupies this port after this
         function finished but before the neutron-server process started.
         """
-        return str(helpers.get_free_namespace_port())
+        return str(helpers.get_free_namespace_port(constants.PROTO_NAME_TCP))
 
     def _generate_api_paste(self):
         return c_helpers.find_sample_file('api-paste.ini')
index 83caf7984713434dffcdf3737ac77d0f4144cea8..92ac9c92bbd245f53b4cc440b411026deed66e00 100644 (file)
@@ -23,6 +23,7 @@ import subprocess
 from neutron.agent.common import config
 from neutron.agent.linux import ip_lib
 from neutron.agent.linux import utils
+from neutron.common import constants
 from neutron.tests import tools
 
 CHILD_PROCESS_TIMEOUT = os.environ.get('OS_TEST_CHILD_PROCESS_TIMEOUT', 20)
@@ -32,6 +33,8 @@ READ_TIMEOUT = os.environ.get('OS_TEST_READ_TIMEOUT', 5)
 SS_SOURCE_PORT_PATTERN = re.compile(
     r'^.*\s+\d+\s+.*:(?P<port>\d+)\s+[0-9:].*')
 
+TRANSPORT_PROTOCOLS = (constants.PROTO_NAME_TCP, constants.PROTO_NAME_UDP)
+
 
 class RecursivePermDirFixture(tools.SafeFixture):
     """Ensure at least perms permissions on directory and ancestors."""
@@ -53,7 +56,7 @@ class RecursivePermDirFixture(tools.SafeFixture):
             current_directory = os.path.dirname(current_directory)
 
 
-def get_free_namespace_port(tcp=True, namespace=None):
+def get_free_namespace_port(protocol, namespace=None):
     """Return an unused port from given namespace
 
     WARNING: This function returns a port that is free at the execution time of
@@ -61,13 +64,15 @@ def get_free_namespace_port(tcp=True, namespace=None):
              is a potential danger that port will be no longer free. It's up to
              the programmer to handle error if port is already in use.
 
-    :param tcp: Return free port for TCP protocol if set to True, return free
-                port for UDP protocol if set to False
+    :param protocol: Return free port for given protocol. Supported protocols
+                     are 'tcp' and 'udp'.
     """
-    if tcp:
+    if protocol == constants.PROTO_NAME_TCP:
         param = '-tna'
-    else:
+    elif protocol == constants.PROTO_NAME_UDP:
         param = '-una'
+    else:
+        raise ValueError("Unsupported procotol %s" % protocol)
 
     ip_wrapper = ip_lib.IPWrapper(namespace=namespace)
     output = ip_wrapper.netns.execute(['ss', param])
@@ -145,29 +150,47 @@ class RootHelperProcess(subprocess.Popen):
 
 class NetcatTester(object):
     TESTING_STRING = 'foo'
-
-    def __init__(self, client_namespace, server_namespace, server_address,
-                 port, client_address=None, udp=False):
+    TCP = constants.PROTO_NAME_TCP
+    UDP = constants.PROTO_NAME_UDP
+
+    def __init__(self, client_namespace, server_namespace, address,
+                 dst_port, protocol, server_address='0.0.0.0', src_port=None):
+        """
+        Tool for testing connectivity on transport layer using netcat
+        executable.
+
+        The processes are spawned lazily.
+
+        :param client_namespace: Namespace in which netcat process that
+                                 connects to other netcat will be spawned
+        :param server_namespace: Namespace in which listening netcat process
+                                 will be spawned
+        :param address: Server address from client point of view
+        :param dst_port: Port on which netcat listens
+        :param protocol: Transport protocol, either 'tcp' or 'udp'
+        :param server_address: Address in server namespace on which netcat
+                               should listen
+        :param src_port: Source port of netcat process spawned in client
+                         namespace - packet will have src_port in TCP/UDP
+                         header with this value
+
+        """
         self.client_namespace = client_namespace
         self.server_namespace = server_namespace
         self._client_process = None
         self._server_process = None
-        # Use client_address to specify an address to connect client to that is
-        # different from the one that server side is going to listen on (useful
-        # when testing floating IPs)
-        self.client_address = client_address or server_address
+        self.address = address
         self.server_address = server_address
-        self.port = str(port)
-        self.udp = udp
+        self.dst_port = str(dst_port)
+        self.src_port = str(src_port) if src_port else None
+        if protocol not in TRANSPORT_PROTOCOLS:
+            raise ValueError("Unsupported protocol %s" % protocol)
+        self.protocol = protocol
 
     @property
     def client_process(self):
         if not self._client_process:
-            if not self._server_process:
-                self._spawn_server_process()
-            self._client_process = self._spawn_nc_in_namespace(
-                self.client_namespace,
-                address=self.client_address)
+            self.establish_connection()
         return self._client_process
 
     @property
@@ -182,6 +205,22 @@ class NetcatTester(object):
             address=self.server_address,
             listen=True)
 
+    def establish_connection(self):
+        if self._client_process:
+            raise RuntimeError('%(proto)s connection to $(ip_addr)s is already'
+                               ' established' %
+                               {'proto': self.protocol,
+                                'ip_addr': self.address})
+
+        if not self._server_process:
+            self._spawn_server_process()
+        self._client_process = self._spawn_nc_in_namespace(
+            self.client_namespace,
+            address=self.address)
+        if self.protocol == self.UDP:
+            # Create an entry in conntrack table for UDP packets
+            self.client_process.writeline(self.TESTING_STRING)
+
     def test_connectivity(self, respawn=False):
         stop_required = (respawn and self._client_process and
                          self._client_process.poll() is not None)
@@ -196,15 +235,17 @@ class NetcatTester(object):
         return message == self.TESTING_STRING
 
     def _spawn_nc_in_namespace(self, namespace, address, listen=False):
-        cmd = ['nc', address, self.port]
-        if self.udp:
+        cmd = ['nc', address, self.dst_port]
+        if self.protocol == self.UDP:
             cmd.append('-u')
         if listen:
             cmd.append('-l')
-            if not self.udp:
+            if self.protocol == self.TCP:
                 cmd.append('-k')
         else:
             cmd.extend(['-w', '20'])
+            if self.src_port:
+                cmd.extend(['-p', self.src_port])
         proc = RootHelperProcess(cmd, namespace=namespace)
         return proc
 
index ebbf74ce32c6efceaa44d7a1263d46a1a0716e65..3d78459aee0ba31ed0010b68d573a932f9202d2f 100644 (file)
@@ -18,6 +18,7 @@ import testtools
 
 from neutron.agent.linux import iptables_manager
 from neutron.agent.linux import utils
+from neutron.common import constants
 from neutron.tests import base
 from neutron.tests.common import machine_fixtures
 from neutron.tests.common import net_helpers
@@ -43,7 +44,8 @@ class IptablesManagerTestCase(functional_base.BaseSudoTestCase):
         self.client_fw, self.server_fw = self.create_firewalls()
         # The port is used in isolated namespace that precludes possibility of
         # port conflicts
-        self.port = helpers.get_free_namespace_port(self.server.namespace)
+        self.port = helpers.get_free_namespace_port(constants.PROTO_NAME_TCP,
+                                                    self.server.namespace)
 
     def create_firewalls(self):
         client_iptables = iptables_manager.IptablesManager(
@@ -77,14 +79,11 @@ class IptablesManagerTestCase(functional_base.BaseSudoTestCase):
             rule = self.PROTOCOL_BLOCK_RULE % protocol
         return chain, rule
 
-    def _test_with_nc(self, fw_manager, direction, port, udp):
+    def _test_with_nc(self, fw_manager, direction, port, protocol):
         netcat = helpers.NetcatTester(
             self.client.namespace, self.server.namespace,
-            self.server.ip, self.port, udp=udp)
+            self.server.ip, self.port, protocol)
         self.addCleanup(netcat.stop_processes)
-        protocol = 'tcp'
-        if udp:
-            protocol = 'udp'
         self.assertTrue(netcat.test_connectivity())
         self.filter_add_rule(
             fw_manager, self.server.ip, direction, protocol, port)
@@ -121,28 +120,36 @@ class IptablesManagerTestCase(functional_base.BaseSudoTestCase):
         self.client.assert_ping(self.server.ip)
 
     def test_tcp_input_port(self):
-        self._test_with_nc(self.server_fw, 'ingress', self.port, udp=False)
+        self._test_with_nc(self.server_fw, 'ingress', self.port,
+                           protocol=helpers.NetcatTester.TCP)
 
     def test_tcp_output_port(self):
-        self._test_with_nc(self.client_fw, 'egress', self.port, udp=False)
+        self._test_with_nc(self.client_fw, 'egress', self.port,
+                           protocol=helpers.NetcatTester.TCP)
 
     def test_tcp_input(self):
-        self._test_with_nc(self.server_fw, 'ingress', port=None, udp=False)
+        self._test_with_nc(self.server_fw, 'ingress', port=None,
+                           protocol=helpers.NetcatTester.TCP)
 
     def test_tcp_output(self):
-        self._test_with_nc(self.client_fw, 'egress', port=None, udp=False)
+        self._test_with_nc(self.client_fw, 'egress', port=None,
+                           protocol=helpers.NetcatTester.TCP)
 
     def test_udp_input_port(self):
-        self._test_with_nc(self.server_fw, 'ingress', self.port, udp=True)
+        self._test_with_nc(self.server_fw, 'ingress', self.port,
+                           protocol=helpers.NetcatTester.UDP)
 
     def test_udp_output_port(self):
-        self._test_with_nc(self.client_fw, 'egress', self.port, udp=True)
+        self._test_with_nc(self.client_fw, 'egress', self.port,
+                           protocol=helpers.NetcatTester.UDP)
 
     def test_udp_input(self):
-        self._test_with_nc(self.server_fw, 'ingress', port=None, udp=True)
+        self._test_with_nc(self.server_fw, 'ingress', port=None,
+                           protocol=helpers.NetcatTester.UDP)
 
     def test_udp_output(self):
-        self._test_with_nc(self.client_fw, 'egress', port=None, udp=True)
+        self._test_with_nc(self.client_fw, 'egress', port=None,
+                           protocol=helpers.NetcatTester.UDP)
 
 
 class IptablesManagerNonRootTestCase(base.BaseTestCase):
index 74d2e486f95c3471ca1ebf47204458c5b9b1742f..b35fb074a22da0d114667c9c67cebf9e7a2a3d4f 100644 (file)
@@ -400,7 +400,8 @@ class L3AgentTestCase(L3AgentTestFramework):
         router_info = self.generate_router_info(enable_ha=False)
         router = self.manage_router(self.agent, router_info)
 
-        port = helpers.get_free_namespace_port(router.ns_name)
+        port = helpers.get_free_namespace_port(l3_constants.PROTO_NAME_TCP,
+                                               router.ns_name)
         client_address = '19.4.4.3'
         server_address = '35.4.0.4'
 
@@ -413,9 +414,8 @@ class L3AgentTestCase(L3AgentTestFramework):
 
         router_ns = ip_lib.IPWrapper(namespace=router.ns_name)
         netcat = helpers.NetcatTester(router.ns_name, router.ns_name,
-                                      server_address, port,
-                                      client_address=client_address,
-                                      udp=False)
+                                      client_address, port,
+                                      protocol=helpers.NetcatTester.TCP)
         self.addCleanup(netcat.stop_processes)
 
         def assert_num_of_conntrack_rules(n):
@@ -705,12 +705,13 @@ class L3AgentTestCase(L3AgentTestFramework):
         self._add_fip(router, dst_fip, fixed_address=dst_machine.ip)
         router.process(self.agent)
 
-        protocol_port = helpers.get_free_namespace_port(dst_machine.namespace)
+        protocol_port = helpers.get_free_namespace_port(
+            l3_constants.PROTO_NAME_TCP, dst_machine.namespace)
         # client sends to fip
         netcat = helpers.NetcatTester(
             src_machine.namespace, dst_machine.namespace,
-            dst_machine.ip, protocol_port, client_address=dst_fip,
-            udp=False)
+            dst_fip, protocol_port,
+            protocol=helpers.NetcatTester.TCP)
         self.addCleanup(netcat.stop_processes)
         self.assertTrue(netcat.test_connectivity())