]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Define FakeMachine helper for functional/fullstack tests
authorCedric Brandily <zzelle@gmail.com>
Sun, 1 Mar 2015 22:08:58 +0000 (22:08 +0000)
committerCedric Brandily <zzelle@gmail.com>
Mon, 20 Apr 2015 17:58:39 +0000 (19:58 +0200)
The change defines the FakeMachine fixture/helper which emulates a
machine through a namespace with:
* a port bound to a bridge,
* an ip on the port,
* a gateway (if requested).

The FakeMachine class can be used to emulate:
* a VM for testing network features (ex: metadata service),
* an external machine for testing "external" network features (ex:
  routing/natting),
* a server for low level tests of network features (ex: iptables).

The change also defines PeerMachines fixture/helper to create some fake
machines bound to a bridge.

Change-Id: I4fde1a03badd9adfd14b9124b5602331b69dda9d

neutron/tests/common/machine_fixtures.py [new file with mode: 0644]
neutron/tests/common/net_helpers.py
neutron/tests/functional/agent/linux/base.py
neutron/tests/functional/agent/linux/test_iptables_firewall.py
neutron/tests/functional/agent/test_l3_agent.py

diff --git a/neutron/tests/common/machine_fixtures.py b/neutron/tests/common/machine_fixtures.py
new file mode 100644 (file)
index 0000000..5fa4537
--- /dev/null
@@ -0,0 +1,90 @@
+# Copyright (c) 2015 Thales Services SAS
+#
+#    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 fixtures
+
+from neutron.agent.linux import ip_lib
+from neutron.tests.common import net_helpers
+
+
+class FakeMachine(fixtures.Fixture):
+    """Create a fake machine.
+
+    :ivar bridge: bridge on which the fake machine is bound
+    :ivar ip_cidr: fake machine ip_cidr
+    :type ip_cidr: str
+    :ivar ip: fake machine ip
+    :type ip: str
+    :ivar gateway_ip: fake machine gateway ip
+    :type gateway_ip: str
+
+    :ivar namespace: namespace emulating the machine
+    :type namespace: str
+    :ivar port: port binding the namespace to the bridge
+    :type port: IPDevice
+    """
+
+    def __init__(self, bridge, ip_cidr, gateway_ip=None):
+        super(FakeMachine, self).__init__()
+        self.bridge = bridge
+        self.ip_cidr = ip_cidr
+        self.ip = self.ip_cidr.partition('/')[0]
+        self.gateway_ip = gateway_ip
+
+    def setUp(self):
+        super(FakeMachine, self).setUp()
+        self.namespace = self.useFixture(
+            net_helpers.NamespaceFixture()).name
+
+        self.port = self.useFixture(
+            net_helpers.PortFixture.get(self.bridge, self.namespace)).port
+        self.port.addr.add(self.ip_cidr)
+
+        if self.gateway_ip:
+            net_helpers.set_namespace_gateway(self.port, self.gateway_ip)
+
+    def execute(self, *args, **kwargs):
+        ns_ip_wrapper = ip_lib.IPWrapper(self.namespace)
+        return ns_ip_wrapper.netns.execute(*args, **kwargs)
+
+
+class PeerMachines(fixtures.Fixture):
+    """Create 'amount' peered machines on an ip_cidr.
+
+    :ivar bridge: bridge on which peer machines are bound
+    :ivar ip_cidr: ip_cidr on which peer machines have ips
+    :type ip_cidr: str
+    :ivar machines: fake machines
+    :type machines: FakeMachine list
+    """
+
+    AMOUNT = 2
+    CIDR = '192.168.0.1/24'
+
+    def __init__(self, bridge, ip_cidr=None, gateway_ip=None):
+        super(PeerMachines, self).__init__()
+        self.bridge = bridge
+        self.ip_cidr = ip_cidr or self.CIDR
+        self.gateway_ip = gateway_ip
+
+    def setUp(self):
+        super(PeerMachines, self).setUp()
+        self.machines = []
+
+        for index in range(self.AMOUNT):
+            ip_cidr = net_helpers.increment_ip_cidr(self.ip_cidr, index)
+            self.machines.append(
+                self.useFixture(
+                    FakeMachine(self.bridge, ip_cidr, self.gateway_ip)))
index 4ccf06d2007ffddc54ebb45c31080a5fa763ae77..36a3dfffa49987be2996230276da37830d1a29d0 100644 (file)
@@ -98,11 +98,10 @@ class VethFixture(fixtures.Fixture):
         super(VethFixture, self).setUp()
         ip_wrapper = ip_lib.IPWrapper()
 
-        def _create_veth(name0):
-            name1 = name0.replace(VETH0_PREFIX, VETH1_PREFIX)
-            return ip_wrapper.add_veth(name0, name1)
+        self.ports = common_base.create_resource(
+            VETH0_PREFIX,
+            lambda name: ip_wrapper.add_veth(name, self.get_peer_name(name)))
 
-        self.ports = common_base.create_resource(VETH0_PREFIX, _create_veth)
         self.addCleanup(self.destroy)
 
     def destroy(self):
@@ -116,6 +115,15 @@ class VethFixture(fixtures.Fixture):
                 # when a namespace owning a veth endpoint is deleted.
                 pass
 
+    @staticmethod
+    def get_peer_name(name):
+        if name.startswith(VETH0_PREFIX):
+            return name.replace(VETH0_PREFIX, VETH1_PREFIX)
+        elif name.startswith(VETH1_PREFIX):
+            return name.replace(VETH1_PREFIX, VETH0_PREFIX)
+        else:
+            tools.fail('%s is not a valid VethFixture veth endpoint' % name)
+
 
 @six.add_metaclass(abc.ABCMeta)
 class PortFixture(fixtures.Fixture):
@@ -140,6 +148,17 @@ class PortFixture(fixtures.Fixture):
         if not self.bridge:
             self.bridge = self.useFixture(self._create_bridge_fixture()).bridge
 
+    @classmethod
+    def get(cls, bridge, namespace=None):
+        """Deduce PortFixture class from bridge type and instantiate it."""
+        if isinstance(bridge, ovs_lib.OVSBridge):
+            return OVSPortFixture(bridge, namespace)
+        if isinstance(bridge, bridge_lib.BridgeDevice):
+            return LinuxBridgePortFixture(bridge, namespace)
+        if isinstance(bridge, VethBridge):
+            return VethPortFixture(bridge, namespace)
+        tools.fail('Unexpected bridge type: %s' % type(bridge))
+
 
 class OVSBridgeFixture(fixtures.Fixture):
     """Create an OVS bridge.
index 149c625efa79a9d49224ac6f6c19c1829dd7bf55..43c5aaab8933d485a76f1d4b303d1ce5595d4f7b 100644 (file)
@@ -14,7 +14,9 @@
 
 import testscenarios
 
+from neutron.agent.linux import ip_lib
 from neutron.tests import base as tests_base
+from neutron.tests.common import machine_fixtures
 from neutron.tests.common import net_helpers
 from neutron.tests.functional import base as functional_base
 
@@ -33,9 +35,6 @@ get_rand_name = tests_base.get_rand_name
 
 class BaseLinuxTestCase(functional_base.BaseSudoTestCase):
 
-    def _create_namespace(self, prefix=net_helpers.NS_PREFIX):
-        return self.useFixture(net_helpers.NamespaceFixture(prefix)).ip_wrapper
-
     def create_veth(self):
         return self.useFixture(net_helpers.VethFixture()).ports
 
@@ -54,27 +53,12 @@ class BaseOVSLinuxTestCase(testscenarios.WithScenarios, BaseLinuxTestCase):
         self.config(group='OVS', ovsdb_interface=self.ovsdb_interface)
 
 
-class BaseIPVethTestCase(BaseLinuxTestCase):
-    SRC_ADDRESS = '192.168.0.1'
-    DST_ADDRESS = '192.168.0.2'
-
-    @staticmethod
-    def _set_ip_up(device, cidr):
-        device.addr.add(cidr)
-        device.link.set_up()
+class BaseIPVethTestCase(functional_base.BaseSudoTestCase):
 
     def prepare_veth_pairs(self):
-
-        src_addr = self.SRC_ADDRESS
-        dst_addr = self.DST_ADDRESS
-
-        src_veth, dst_veth = self.create_veth()
-        src_ns = self._create_namespace()
-        dst_ns = self._create_namespace()
-        src_ns.add_device_to_namespace(src_veth)
-        dst_ns.add_device_to_namespace(dst_veth)
-
-        self._set_ip_up(src_veth, '%s/24' % src_addr)
-        self._set_ip_up(dst_veth, '%s/24' % dst_addr)
-
-        return src_ns, dst_ns
+        bridge = self.useFixture(net_helpers.VethBridgeFixture()).bridge
+        machines = self.useFixture(
+            machine_fixtures.PeerMachines(bridge)).machines
+        self.SRC_ADDRESS = machines[0].ip
+        self.DST_ADDRESS = machines[1].ip
+        return [ip_lib.IPWrapper(m.namespace) for m in machines]
index 6a8d02cf335d421ab83ecbe03c82c34cda01086b..4d2c815e8ab0fda99c66fb850c088a225b0a2386 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from neutron.agent.linux import ip_lib
 from neutron.agent.linux import iptables_firewall
 from neutron.agent import securitygroups_rpc as sg_cfg
+from neutron.tests.common import machine_fixtures
 from neutron.tests.common import net_helpers
-from neutron.tests.functional.agent.linux import base
 from neutron.tests.functional.agent.linux import helpers
+from neutron.tests.functional import base
 from oslo_config import cfg
 
 
-class IptablesFirewallTestCase(base.BaseIPVethTestCase):
+class IptablesFirewallTestCase(base.BaseSudoTestCase):
     MAC_REAL = "fa:16:3e:9a:2f:49"
     MAC_SPOOFED = "fa:16:3e:9a:2f:48"
     FAKE_SECURITY_GROUP_ID = "fake_sg_id"
 
     def _set_src_mac(self, mac):
-        self.src_port.link.set_down()
-        self.src_port.link.set_address(mac)
-        self.src_port.link.set_up()
+        self.client.port.link.set_down()
+        self.client.port.link.set_address(mac)
+        self.client.port.link.set_up()
 
     def setUp(self):
         cfg.CONF.register_opts(sg_cfg.security_group_opts, 'SECURITYGROUP')
         super(IptablesFirewallTestCase, self).setUp()
-        bridge = self.useFixture(net_helpers.LinuxBridgeFixture()).bridge
-
-        # FIXME(cbrandily): temporary, will be replaced by fake machines
-        self.src_ip_wrapper = self.useFixture(
-            net_helpers.NamespaceFixture()).ip_wrapper
 
-        src_port_fixture = self.useFixture(
-            net_helpers.LinuxBridgePortFixture(
-                bridge, self.src_ip_wrapper.namespace))
-        self.src_port = src_port_fixture.port
-        self._set_ip_up(self.src_port, '%s/24' % self.SRC_ADDRESS)
-
-        self.dst_ip_wrapper = self.useFixture(
-            net_helpers.NamespaceFixture()).ip_wrapper
-        self.dst_port = self.useFixture(
-            net_helpers.LinuxBridgePortFixture(
-                bridge, self.dst_ip_wrapper.namespace)).port
-        self._set_ip_up(self.dst_port, '%s/24' % self.DST_ADDRESS)
+        bridge = self.useFixture(net_helpers.LinuxBridgeFixture()).bridge
+        self.client, self.server = self.useFixture(
+            machine_fixtures.PeerMachines(bridge)).machines
 
         self.firewall = iptables_firewall.IptablesFirewallDriver(
             namespace=bridge.namespace)
 
         self._set_src_mac(self.MAC_REAL)
 
+        client_br_port_name = net_helpers.VethFixture.get_peer_name(
+            self.client.port.name)
         self.src_port_desc = {'admin_state_up': True,
-                              'device': src_port_fixture.br_port.name,
+                              'device': client_br_port_name,
                               'device_owner': 'compute:None',
-                              'fixed_ips': [self.SRC_ADDRESS],
+                              'fixed_ips': [self.client.ip],
                               'mac_address': self.MAC_REAL,
                               'port_security_enabled': True,
                               'security_groups': [self.FAKE_SECURITY_GROUP_ID],
@@ -73,7 +63,8 @@ class IptablesFirewallTestCase(base.BaseIPVethTestCase):
     # setup firewall on bridge and send packet from src_veth and observe
     # if sent packet can be observed on dst_veth
     def test_port_sec_within_firewall(self):
-        pinger = helpers.Pinger(self.src_ip_wrapper)
+        client_ip_wrapper = ip_lib.IPWrapper(self.client.namespace)
+        pinger = helpers.Pinger(client_ip_wrapper)
 
         # update the sg_group to make ping pass
         sg_rules = [{'ethertype': 'IPv4', 'direction': 'ingress',
@@ -85,13 +76,13 @@ class IptablesFirewallTestCase(base.BaseIPVethTestCase):
                                                 self.FAKE_SECURITY_GROUP_ID,
                                                 sg_rules)
         self.firewall.prepare_port_filter(self.src_port_desc)
-        pinger.assert_ping(self.DST_ADDRESS)
+        pinger.assert_ping(self.server.ip)
 
         # modify the src_veth's MAC and test again
         self._set_src_mac(self.MAC_SPOOFED)
-        pinger.assert_no_ping(self.DST_ADDRESS)
+        pinger.assert_no_ping(self.server.ip)
 
         # update the port's port_security_enabled value and test again
         self.src_port_desc['port_security_enabled'] = False
         self.firewall.update_port_filter(self.src_port_desc)
-        pinger.assert_ping(self.DST_ADDRESS)
+        pinger.assert_ping(self.server.ip)
index 0767b068d3cc493af43c435c38f26135f55413f2..418d0bf16db36341ba8c088f39e06f6b5ce99ec7 100755 (executable)
@@ -44,6 +44,7 @@ from neutron.common import config as common_config
 from neutron.common import constants as l3_constants
 from neutron.common import utils as common_utils
 from neutron.openstack.common import uuidutils
+from neutron.tests.common import machine_fixtures
 from neutron.tests.common import net_helpers
 from neutron.tests.functional.agent.linux import base
 from neutron.tests.functional.agent.linux import helpers
@@ -683,35 +684,25 @@ class L3AgentTestCase(L3AgentTestFramework):
         router_ip_cidr = self._port_first_ip_cidr(router.internal_ports[0])
         router_ip = router_ip_cidr.partition('/')[0]
 
-        src_ip_cidr = net_helpers.increment_ip_cidr(router_ip_cidr)
-        dst_ip_cidr = net_helpers.increment_ip_cidr(src_ip_cidr)
-        dst_ip = dst_ip_cidr.partition('/')[0]
+        br_int = get_ovs_bridge(self.agent.conf.ovs_integration_bridge)
+        src_machine, dst_machine = self.useFixture(
+            machine_fixtures.PeerMachines(
+                br_int,
+                net_helpers.increment_ip_cidr(router_ip_cidr),
+                router_ip)).machines
+
         dst_fip = '19.4.4.10'
         router.router[l3_constants.FLOATINGIP_KEY] = []
-        self._add_fip(router, dst_fip, fixed_address=dst_ip)
+        self._add_fip(router, dst_fip, fixed_address=dst_machine.ip)
         router.process(self.agent)
 
-        br_int = get_ovs_bridge(self.agent.conf.ovs_integration_bridge)
-
-        # FIXME(cbrandily): temporary, will be replaced by fake machines
-        src_ns = self._create_namespace(prefix='test-src-')
-        src_port = self.useFixture(
-            net_helpers.OVSPortFixture(br_int, src_ns.namespace)).port
-        src_port.addr.add(src_ip_cidr)
-        net_helpers.set_namespace_gateway(src_port, router_ip)
-        dst_ns = self._create_namespace(prefix='test-dst-')
-        dst_port = self.useFixture(
-            net_helpers.OVSPortFixture(br_int, dst_ns.namespace)).port
-        dst_port.addr.add(dst_ip_cidr)
-        net_helpers.set_namespace_gateway(dst_port, router_ip)
-
-        protocol_port = helpers.get_free_namespace_port(dst_ns)
+        protocol_port = helpers.get_free_namespace_port(dst_machine.namespace)
         # client sends to fip
-        netcat = helpers.NetcatTester(src_ns, dst_ns, dst_ip,
-                                      protocol_port,
-                                      client_address=dst_fip,
-                                      run_as_root=True,
-                                      udp=False)
+        netcat = helpers.NetcatTester(
+            ip_lib.IPWrapper(src_machine.namespace),
+            ip_lib.IPWrapper(dst_machine.namespace),
+            dst_machine.ip, protocol_port, client_address=dst_fip,
+            run_as_root=True, udp=False)
         self.addCleanup(netcat.stop_processes)
         self.assertTrue(netcat.test_connectivity())
 
@@ -804,24 +795,21 @@ class MetadataL3AgentTestCase(L3AgentTestFramework):
         self._create_metadata_fake_server(webob.exc.HTTPOk.code)
 
         # Create and configure client namespace
-        client_ns = self._create_namespace()
         router_ip_cidr = self._port_first_ip_cidr(router.internal_ports[0])
-        ip_cidr = net_helpers.increment_ip_cidr(router_ip_cidr)
         br_int = get_ovs_bridge(self.agent.conf.ovs_integration_bridge)
 
-        # FIXME(cbrandily): temporary, will be replaced by a fake machine
-        port = self.useFixture(
-            net_helpers.OVSPortFixture(br_int, client_ns.namespace)).port
-        port.addr.add(ip_cidr)
-        net_helpers.set_namespace_gateway(port,
-                                          router_ip_cidr.partition('/')[0])
+        machine = self.useFixture(
+            machine_fixtures.FakeMachine(
+                br_int,
+                net_helpers.increment_ip_cidr(router_ip_cidr),
+                router_ip_cidr.partition('/')[0]))
 
         # Query metadata proxy
         url = 'http://%(host)s:%(port)s' % {'host': dhcp.METADATA_DEFAULT_IP,
                                             'port': dhcp.METADATA_PORT}
         cmd = 'curl', '--max-time', METADATA_REQUEST_TIMEOUT, '-D-', url
         try:
-            raw_headers = client_ns.netns.execute(cmd)
+            raw_headers = machine.execute(cmd)
         except RuntimeError:
             self.fail('metadata proxy unreachable on %s before timeout' % url)