diff options
author | Ross Brattain <ross.b.brattain@intel.com> | 2017-10-17 14:30:37 -0700 |
---|---|---|
committer | Ross Brattain <ross.b.brattain@intel.com> | 2017-12-11 13:00:13 -0800 |
commit | ec6a90d449f8b1ab2b17083188ec65f75ab7818b (patch) | |
tree | 7a80aae3e5d4b8a0f069ea0caab912d05bbebff6 | |
parent | 2085fd018074c2687ade484b9d7087173ea4f1c7 (diff) |
heat: allow overriding Heat/Neutron private IP for DPDK tests
For some L2/L3 DPDK testcases we need to use a custom
IP address space different from what Heat provides.
These testcases require port_security_enabled = False so
Neutron should allow for unrestricted L2 traffic.
This will work because we bind the ports to DPDK and thus
don't need DHCP.
vnf_0:
floating_ip: true
placement: "pgrp1"
network_ports:
mgmt:
- mgmt
uplink_0:
- xe0:
local_ip: 10.44.0.20
netmask: 255.255.255.0
downlink_0:
- xe1:
local_ip: 10.44.0.30
netmask: 255.255.255.0
Also fixup flake8 errors in unittests
Change-Id: Id29dfffa692f16fb1f526d208db43e476e2f7830
Signed-off-by: Ross Brattain <ross.b.brattain@intel.com>
-rw-r--r-- | tests/unit/benchmark/contexts/test_heat.py | 8 | ||||
-rw-r--r-- | tests/unit/benchmark/contexts/test_model.py | 172 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/heat.py | 1 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/model.py | 32 |
4 files changed, 208 insertions, 5 deletions
diff --git a/tests/unit/benchmark/contexts/test_heat.py b/tests/unit/benchmark/contexts/test_heat.py index 223d64060..f2e725df2 100644 --- a/tests/unit/benchmark/contexts/test_heat.py +++ b/tests/unit/benchmark/contexts/test_heat.py @@ -119,8 +119,12 @@ class HeatContextTestCase(unittest.TestCase): "2f2e4997-0a8e-4eb7-9fa4-f3f8fbbc393b") mock_template.add_security_group.assert_called_with("foo-secgroup") # mock_template.add_network.assert_called_with("bar-fool-network", 'physnet1', None) - mock_template.add_router.assert_called_with("bar-fool-network-router", netattrs["external_network"], "bar-fool-network-subnet") - mock_template.add_router_interface.assert_called_with("bar-fool-network-router-if0", "bar-fool-network-router", "bar-fool-network-subnet") + mock_template.add_router.assert_called_with("bar-fool-network-router", + netattrs["external_network"], + "bar-fool-network-subnet") + mock_template.add_router_interface.assert_called_with("bar-fool-network-router-if0", + "bar-fool-network-router", + "bar-fool-network-subnet") @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') def test_attrs_get(self, mock_template): diff --git a/tests/unit/benchmark/contexts/test_model.py b/tests/unit/benchmark/contexts/test_model.py index 48ee01cf0..53b035b82 100644 --- a/tests/unit/benchmark/contexts/test_model.py +++ b/tests/unit/benchmark/contexts/test_model.py @@ -282,6 +282,178 @@ class ServerTestCase(unittest.TestCase): scheduler_hints='hints', availability_zone='zone') + def test_override_ip(self): + network_ports = { + 'mgmt': ['mgmt'], + 'uplink_0': [ + {'xe0': {'local_ip': '10.44.0.20', 'netmask': '255.255.255.0'}}, + ], + 'downlink_0': [ + {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}}, + ], + } + attrs = { + 'image': 'some-image', 'flavor': 'some-flavor', + } + test_server = model.Server('foo', self.mock_context, attrs) + test_server.interfaces = { + "xe0": { + "local_ip": "1.2.3.4", + "netmask": "255.255.255.0", + }, + "xe1": { + "local_ip": "1.2.3.5", + "netmask": "255.255.255.0" + } + } + test_server.network_ports = network_ports + + test_server.override_ip("uplink_0", {"port": "xe0"}) + self.assertEqual(test_server.interfaces["xe0"], network_ports["uplink_0"][0]["xe0"]) + + def test_override_ip_multiple(self): + network_ports = { + 'mgmt': ['mgmt'], + 'uplink_0': [ + {'xe0': {'local_ip': '10.44.0.20', 'netmask': '255.255.255.0'}}, + {'xe0': {'local_ip': '10.44.0.21', 'netmask': '255.255.255.0'}}, + ], + 'downlink_0': [ + {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}}, + ], + } + attrs = { + 'image': 'some-image', 'flavor': 'some-flavor', + } + test_server = model.Server('foo', self.mock_context, attrs) + test_server.interfaces = { + "xe0": { + "local_ip": "1.2.3.4", + "netmask": "255.255.255.0", + }, + "xe1": { + "local_ip": "1.2.3.5", + "netmask": "255.255.255.0" + } + } + test_server.network_ports = network_ports + test_server.override_ip("uplink_0", {"port": "xe0"}) + self.assertEqual(test_server.interfaces["xe0"], network_ports["uplink_0"][0]["xe0"]) + + def test_override_ip_mixed(self): + network_ports = { + 'mgmt': ['mgmt'], + 'uplink_0': [ + 'xe0', + {'xe0': {'local_ip': '10.44.0.21', 'netmask': '255.255.255.0'}}, + ], + 'downlink_0': [ + {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}}, + ], + } + attrs = { + 'image': 'some-image', 'flavor': 'some-flavor', + } + test_server = model.Server('foo', self.mock_context, attrs) + test_server.interfaces = { + "xe0": { + "local_ip": "1.2.3.4", + "netmask": "255.255.255.0", + }, + "xe1": { + "local_ip": "1.2.3.5", + "netmask": "255.255.255.0" + } + } + test_server.network_ports = network_ports + test_server.override_ip("uplink_0", {"port": "xe0"}) + self.assertEqual(test_server.interfaces["xe0"], network_ports["uplink_0"][1]["xe0"]) + + @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') + def test__add_instance_with_ip_override_invalid_syntax(self, mock_template): + network_ports = { + 'mgmt': ['mgmt'], + 'uplink_0': 'xe0', + 'downlink_0': [ + {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}}, + ], + } + attrs = { + 'image': 'some-image', 'flavor': 'some-flavor', + } + test_server = model.Server('foo', self.mock_context, attrs) + test_server.network_ports = network_ports + context = type("Context", (object,), {}) + # can't use Mock because Mock.name is reserved + context.name = "context" + networks = [model.Network(n, context, {}) for n in network_ports] + + with self.assertRaises(SyntaxError): + test_server._add_instance(mock_template, 'some-server', + networks, 'hints') + + @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') + def test__add_instance_with_ip_override(self, mock_template): + network_ports = { + 'mgmt': ['mgmt'], + 'uplink_0': [ + {'xe0': {'local_ip': '10.44.0.20', 'netmask': '255.255.255.0'}}, + ], + 'downlink_0': [ + {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}}, + ], + } + attrs = { + 'image': 'some-image', 'flavor': 'some-flavor', + } + test_server = model.Server('foo', self.mock_context, attrs) + test_server.network_ports = network_ports + context = type("Context", (object,), {}) + # can't use Mock because Mock.name is reserved + context.name = "context" + networks = [model.Network(n, context, {}) for n in network_ports] + + test_server._add_instance(mock_template, 'some-server', + networks, 'hints') + self.assertEqual(test_server.ports, { + 'downlink_0': [{'port': 'xe1', 'stack_name': 'some-server-xe1-port'}], + 'mgmt': [{'port': 'mgmt', 'stack_name': 'some-server-mgmt-port'}], + 'uplink_0': [{'port': 'xe0', 'stack_name': 'some-server-xe0-port'}] + }) + + @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') + def test__add_instance_with_multiple_ip_override(self, mock_template): + network_ports = { + 'mgmt': ['mgmt'], + 'uplink_0': [ + {'xe0': {'local_ip': '10.44.0.20', 'netmask': '255.255.255.0'}}, + {'xe0': {'local_ip': '10.44.0.21', 'netmask': '255.255.255.0'}}, + ], + 'downlink_0': [ + {'xe1': {'local_ip': '10.44.0.30', 'netmask': '255.255.255.0'}}, + ], + } + attrs = { + 'image': 'some-image', 'flavor': 'some-flavor', + } + test_server = model.Server('foo', self.mock_context, attrs) + test_server.network_ports = network_ports + context = type("Context", (object,), {}) + # can't use Mock because Mock.name is reserved + context.name = "context" + networks = [model.Network(n, context, {}) for n in network_ports] + + test_server._add_instance(mock_template, 'some-server', + networks, 'hints') + self.assertEqual(test_server.ports, { + 'downlink_0': [{'port': 'xe1', 'stack_name': 'some-server-xe1-port'}], + 'mgmt': [{'port': 'mgmt', 'stack_name': 'some-server-mgmt-port'}], + 'uplink_0': [{'port': 'xe0', 'stack_name': 'some-server-xe0-port'}, + # this is not an error, we can produce this, it is left to Heat + # to detect duplicate ports and error + {'port': 'xe0', 'stack_name': 'some-server-xe0-port'}] + }) + @mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate') def test__add_instance_with_user_data(self, mock_template): user_data = "USER_DATA" diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index ff3e5f801..4ba543b9e 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -348,6 +348,7 @@ class HeatContext(Context): port['port'], port['stack_name'], self.stack.outputs) + server.override_ip(network_name, port) def make_interface_dict(self, network_name, port, stack_name, outputs): private_ip = outputs[stack_name] diff --git a/yardstick/benchmark/contexts/model.py b/yardstick/benchmark/contexts/model.py index d3c03e100..ae56066ee 100644 --- a/yardstick/benchmark/contexts/model.py +++ b/yardstick/benchmark/contexts/model.py @@ -14,6 +14,8 @@ from __future__ import absolute_import import six import logging + +from collections import Mapping from six.moves import range @@ -241,6 +243,26 @@ class Server(Object): # pragma: no cover Server.list.append(self) + def override_ip(self, network_name, port): + def find_port_overrides(): + for p in ports: + # p can be string or dict + # we can't just use p[port['port'] in case p is a string + # and port['port'] is an int? + if isinstance(p, Mapping): + g = p.get(port['port']) + # filter out empty dicts + if g: + yield g + + ports = self.network_ports.get(network_name, []) + intf = self.interfaces[port['port']] + for override in find_port_overrides(): + intf['local_ip'] = override.get('local_ip', intf['local_ip']) + intf['netmask'] = override.get('netmask', intf['netmask']) + # only use the first value + break + @property def image(self): """returns a server's image name""" @@ -270,9 +292,13 @@ class Server(Object): # pragma: no cover continue else: if isinstance(ports, six.string_types): - if ports.startswith('-'): - LOG.warning("possible YAML error, port name starts with - '%s", ports) - ports = [ports] + # because strings are iterable we have to check specifically + raise SyntaxError("network_port must be a list '{}'".format(ports)) + # convert port subdicts into their just port name + # port subdicts are used to override Heat IP address, + # but we just need the port name + # we allow duplicates here and let Heat raise the error + ports = [next(iter(p)) if isinstance(p, dict) else p for p in ports] # otherwise add a port for every network with port name as network name else: ports = [network.name] |