Enable heat context to support existing network 51/51751/7
authorrexlee8776 <limingjiang@huawei.com>
Tue, 6 Feb 2018 07:30:37 +0000 (07:30 +0000)
committerrexlee8776 <limingjiang@huawei.com>
Tue, 27 Feb 2018 07:24:10 +0000 (07:24 +0000)
JIRA: YARDSTICK-970

Change-Id: I593af4b3a30e52521e3d77fd84bec16ab4733483
Signed-off-by: rexlee8776 <limingjiang@huawei.com>
samples/ping-one-exising-network.yaml [new file with mode: 0644]
samples/ping-two-exising-network.yaml [new file with mode: 0644]
yardstick/benchmark/contexts/heat.py
yardstick/benchmark/contexts/model.py
yardstick/common/constants.py
yardstick/orchestrator/heat.py
yardstick/tests/unit/benchmark/contexts/test_heat.py
yardstick/tests/unit/benchmark/contexts/test_model.py
yardstick/tests/unit/orchestrator/test_heat.py

diff --git a/samples/ping-one-exising-network.yaml b/samples/ping-one-exising-network.yaml
new file mode 100644 (file)
index 0000000..9e33148
--- /dev/null
@@ -0,0 +1,50 @@
+##############################################################################
+## Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+##
+## All rights reserved. This program and the accompanying materials
+## are made available under the terms of the Apache License, Version 2.0
+## which accompanies this distribution, and is available at
+## http://www.apache.org/licenses/LICENSE-2.0
+###############################################################################
+---
+# Sample benchmark task config file
+# measure network latency using ping
+# This sample use one existing network as both public network and private network.
+
+schema: "yardstick:task:0.1"
+
+{% set public_net = public_net or 'public' %}
+{% set public_subnet = public_subnet or 'public_subnet' %}
+
+scenarios:
+-
+  type: Ping
+  options:
+    packetsize: 200
+  host: athena.demo
+  target: ares.demo
+
+  runner:
+    type: Duration
+    duration: 60
+    interval: 1
+
+  sla:
+    max_rtt: 10
+    action: monitor
+
+context:
+  name: demo
+  image: yardstick-image
+  flavor: yardstick-flavor
+  user: ubuntu
+
+  servers:
+    athena:
+    ares:
+
+  networks:
+    {{ public_net }}:
+      net_flags:
+        is_existing: true
+      subnet: {{ public_subnet }}
diff --git a/samples/ping-two-exising-network.yaml b/samples/ping-two-exising-network.yaml
new file mode 100644 (file)
index 0000000..adea43e
--- /dev/null
@@ -0,0 +1,58 @@
+##############################################################################
+## Copyright (c) 2018 Huawei Technologies Co.,Ltd and others.
+##
+## All rights reserved. This program and the accompanying materials
+## are made available under the terms of the Apache License, Version 2.0
+## which accompanies this distribution, and is available at
+## http://www.apache.org/licenses/LICENSE-2.0
+###############################################################################
+---
+# Sample benchmark task config file
+# measure network latency using ping
+# This sample use two existing network, one as public network to replace for
+# floating ip, one as private network to ping between VMs.
+
+schema: "yardstick:task:0.1"
+
+{% set private_net = private_net or 'private' %}
+{% set private_subnet = private_subnet or 'private_subnet' %}
+{% set public_net = public_net or 'public' %}
+{% set public_subnet = public_subnet or 'public_subnet' %}
+
+scenarios:
+-
+  type: Ping
+  options:
+    packetsize: 200
+  host: athena.demo
+  target: ares.demo
+
+  runner:
+    type: Duration
+    duration: 60
+    interval: 1
+
+  sla:
+    max_rtt: 10
+    action: monitor
+
+context:
+  name: demo
+  image: yardstick-image
+  flavor: yardstick-flavor
+  user: ubuntu
+
+  servers:
+    athena:
+    ares:
+
+  networks:
+    {{ private_net }}:
+      net_flags:
+        is_existing: true
+      subnet: {{ private_subnet }}
+    {{ public_net }}:
+      net_flags:
+        is_existing: true
+        is_public: true
+      subnet: {{ public_subnet }}
index 7b7f1be..3f8da33 100644 (file)
@@ -180,6 +180,9 @@ class HeatContext(Context):
         template.add_security_group(self.secgroup_name)
 
         for network in self.networks.values():
+            # Using existing network
+            if network.is_existing():
+                continue
             template.add_network(network.stack_name,
                                  network.physical_network,
                                  network.provider,
@@ -332,18 +335,35 @@ class HeatContext(Context):
 
         LOG.info("Deploying context '%s' DONE", self.name)
 
+    @staticmethod
+    def _port_net_is_existing(port_info):
+        net_flags = port_info.get('net_flags', {})
+        return net_flags.get(consts.IS_EXISTING)
+
+    @staticmethod
+    def _port_net_is_public(port_info):
+        net_flags = port_info.get('net_flags', {})
+        return net_flags.get(consts.IS_PUBLIC)
+
     def add_server_port(self, server):
-        # use private ip from first port in first network
-        try:
-            private_port = next(iter(server.ports.values()))[0]
-        except IndexError:
-            LOG.exception("Unable to find first private port in %s", server.ports)
-            raise
-        server.private_ip = self.stack.outputs[private_port["stack_name"]]
+        server_ports = server.ports.values()
+        for server_port in server_ports:
+            port_info = server_port[0]
+            port_ip = self.stack.outputs[port_info["stack_name"]]
+            port_net_is_existing = self._port_net_is_existing(port_info)
+            port_net_is_public = self._port_net_is_public(port_info)
+            if port_net_is_existing and (port_net_is_public or
+                                         len(server_ports) == 1):
+                server.public_ip = port_ip
+            if not server.private_ip or len(server_ports) == 1:
+                server.private_ip = port_ip
+
         server.interfaces = {}
         for network_name, ports in server.ports.items():
             for port in ports:
                 # port['port'] is either port name from mapping or default network_name
+                if self._port_net_is_existing(port):
+                    continue
                 server.interfaces[port['port']] = self.make_interface_dict(network_name,
                                                                            port['port'],
                                                                            port['stack_name'],
index ae56066..a55c11f 100644 (file)
@@ -18,6 +18,8 @@ import logging
 from collections import Mapping
 from six.moves import range
 
+from yardstick.common import constants as consts
+
 
 LOG = logging.getLogger(__name__)
 
@@ -132,11 +134,28 @@ class Network(Object):
             if self.gateway_ip is None:
                 self.gateway_ip = "null"
 
-        if "external_network" in attrs:
-            self.router = Router("router", self.name,
-                                 context, attrs["external_network"])
-
-        Network.list.append(self)
+        self.net_flags = attrs.get('net_flags', {})
+        if self.is_existing():
+            self.subnet = attrs.get('subnet')
+            if not self.subnet:
+                raise Warning('No subnet set in existing netwrok!')
+        else:
+            if "external_network" in attrs:
+                self.router = Router("router", self.name,
+                                     context, attrs["external_network"])
+            Network.list.append(self)
+
+    def is_existing(self):
+        net_is_existing = self.net_flags.get(consts.IS_EXISTING)
+        if net_is_existing and not isinstance(net_is_existing, bool):
+            raise SyntaxError('Network flags should be bool type!')
+        return net_is_existing
+
+    def is_public(self):
+        net_is_public = self.net_flags.get(consts.IS_PUBLIC)
+        if net_is_public and not isinstance(net_is_public, bool):
+            raise SyntaxError('Network flags should be bool type!')
+        return net_is_public
 
     def has_route_to(self, network_name):
         """determines if this network has a route to the named network"""
@@ -302,10 +321,13 @@ class Server(Object):     # pragma: no cover
             # otherwise add a port for every network with port name as network name
             else:
                 ports = [network.name]
+            net_flags = network.net_flags
             for port in ports:
                 port_name = "{0}-{1}-port".format(server_name, port)
-                self.ports.setdefault(network.name, []).append(
-                    {"stack_name": port_name, "port": port})
+                port_info = {"stack_name": port_name, "port": port}
+                if net_flags:
+                    port_info['net_flags'] = net_flags
+                self.ports.setdefault(network.name, []).append(port_info)
                 # we can't use secgroups if port_security_enabled is False
                 if network.port_security_enabled is False:
                     sec_group_id = None
@@ -314,11 +336,14 @@ class Server(Object):     # pragma: no cover
                     sec_group_id = self.secgroup_name
                 # don't refactor to pass in network object, that causes JSON
                 # circular ref encode errors
-                template.add_port(port_name, network.stack_name, network.subnet_stack_name,
-                                  network.vnic_type, sec_group_id=sec_group_id,
+                template.add_port(port_name, network,
+                                  sec_group_id=sec_group_id,
                                   provider=network.provider,
                                   allowed_address_pairs=network.allowed_address_pairs)
-                port_name_list.append(port_name)
+                if network.is_public():
+                    port_name_list.insert(0, port_name)
+                else:
+                    port_name_list.append(port_name)
 
                 if self.floating_ip:
                     external_network = self.floating_ip["external_network"]
index 43c2c19..153bd4b 100644 (file)
@@ -145,6 +145,10 @@ BASE_URL = 'http://localhost:5000'
 ENV_ACTION_API = BASE_URL + '/yardstick/env/action'
 ASYNC_TASK_API = BASE_URL + '/yardstick/asynctask'
 
+# flags
+IS_EXISTING = 'is_existing'
+IS_PUBLIC = 'is_public'
+
 # general
 TESTCASE_PRE = 'opnfv_yardstick_'
 TESTSUITE_PRE = 'opnfv_'
index 558b5d2..c55b8f8 100644 (file)
@@ -26,6 +26,7 @@ import shade
 import yardstick.common.openstack_utils as op_utils
 from yardstick.common import exceptions
 from yardstick.common import template_format
+from yardstick.common import constants as consts
 
 log = logging.getLogger(__name__)
 
@@ -322,21 +323,24 @@ name (i.e. %s).
             }
         }
 
-    def add_port(self, name, network_name, subnet_name, vnic_type, sec_group_id=None,
+    def add_port(self, name, network, sec_group_id=None,
                  provider=None, allowed_address_pairs=None):
         """add to the template a named Neutron Port
         """
-        log.debug("adding Neutron::Port '%s', network:'%s', subnet:'%s', vnic_type:'%s', "
-                  "secgroup:%s", name, network_name, subnet_name, vnic_type, sec_group_id)
+        net_is_existing = network.net_flags.get(consts.IS_EXISTING)
+        depends_on = [] if net_is_existing else [network.subnet_stack_name]
+        fixed_ips = [{'subnet': network.subnet}] if net_is_existing else [
+            {'subnet': {'get_resource': network.subnet_stack_name}}]
+        network_ = network.name if net_is_existing else {
+            'get_resource': network.stack_name}
         self.resources[name] = {
             'type': 'OS::Neutron::Port',
-            'depends_on': [subnet_name],
+            'depends_on': depends_on,
             'properties': {
                 'name': name,
-                'binding:vnic_type': vnic_type,
-                'fixed_ips': [{'subnet': {'get_resource': subnet_name}}],
-                'network_id': {'get_resource': network_name},
-                'replacement_policy': 'AUTO',
+                'binding:vnic_type': network.vnic_type,
+                'fixed_ips': fixed_ips,
+                'network': network_,
             }
         }
 
@@ -353,6 +357,8 @@ name (i.e. %s).
             self.resources[name]['properties'][
                 'allowed_address_pairs'] = allowed_address_pairs
 
+        log.debug("adding Neutron::Port %s", self.resources[name])
+
         self._template['outputs'][name] = {
             'description': 'Address for interface %s' % name,
             'value': {'get_attr': [name, 'fixed_ips', 0, 'ip_address']}
index 4348bb0..a87cf81 100644 (file)
@@ -192,6 +192,7 @@ class HeatContextTestCase(unittest.TestCase):
             u'e-network_id': u'net987',
         }
         server = mock.MagicMock()
+        server.private_ip = None
         server.ports = OrderedDict([
             ('a', [{'stack_name': 'b', 'port': 'port_a'}]),
             ('c', [{'stack_name': 'd', 'port': 'port_c'},
index 28011d4..b5f5468 100644 (file)
@@ -241,6 +241,7 @@ class ServerTestCase(unittest.TestCase):
         mock_network.vnic_type = 'normal'
         mock_network.subnet_stack_name = 'some-network-stack-subnet'
         mock_network.provider = 'sriov'
+        mock_network.net_flags = {}
         mock_network.external_network = 'ext_net'
         mock_network.router = model.Router('some-router', 'some-network', self.mock_context,
                                            'ext_net')
@@ -250,9 +251,7 @@ class ServerTestCase(unittest.TestCase):
 
         mock_template.add_port.assert_called_with(
             'some-server-some-network-port',
-            mock_network.stack_name,
-            mock_network.subnet_stack_name,
-            mock_network.vnic_type,
+            mock_network,
             sec_group_id=self.mock_context.secgroup_name,
             provider=mock_network.provider,
             allowed_address_pairs=mock_network.allowed_address_pairs)
@@ -513,6 +512,7 @@ class ServerTestCase(unittest.TestCase):
         mock_network = mock.Mock()
         mock_network.allowed_address_pairs = ["1", "2"]
         mock_network.vnic_type = 'normal'
+        mock_network.net_flags = {}
         mock_network.configure_mock(name='some-network', stack_name='some-network-stack',
                                     subnet_stack_name='some-network-stack-subnet',
                                     provider='some-provider')
@@ -522,9 +522,7 @@ class ServerTestCase(unittest.TestCase):
 
         mock_template.add_port.assert_called_with(
             'ServerFlavor-2-some-network-port',
-            mock_network.stack_name,
-            mock_network.subnet_stack_name,
-            mock_network.vnic_type,
+            mock_network,
             provider=mock_network.provider,
             sec_group_id=self.mock_context.secgroup_name,
             allowed_address_pairs=mock_network.allowed_address_pairs)
@@ -556,6 +554,7 @@ class ServerTestCase(unittest.TestCase):
         mock_network.name = 'some-network'
         mock_network.stack_name = 'some-network-stack'
         mock_network.subnet_stack_name = 'some-network-stack-subnet'
+        mock_network.net_flags = {}
 
         test_server._add_instance(mock_template, 'ServerFlavor-3',
                                   [mock_network], 'hints')
index e0a3538..acf4991 100644 (file)
@@ -184,10 +184,18 @@ class HeatTemplateTestCase(unittest.TestCase):
         heat_template.add_subnet("subnet2", "network2", "cidr2")
         heat_template.add_router("router1", "gw1", "subnet1")
         heat_template.add_router_interface("router_if1", "router1", "subnet1")
-        heat_template.add_port("port1", "network1", "subnet1", "normal")
-        heat_template.add_port("port2", "network2", "subnet2", "normal",
+        network1 = mock.MagicMock()
+        network1.stack_name = "network1"
+        network1.subnet_stack_name = "subnet1"
+        network1.vnic_type = "normal"
+        network2 = mock.MagicMock()
+        network2.stack_name = "network2"
+        network2.subnet_stack_name = "subnet2"
+        network2.vnic_type = "normal"
+        heat_template.add_port("port1", network1)
+        heat_template.add_port("port2", network2,
                                sec_group_id="sec_group1", provider="not-sriov")
-        heat_template.add_port("port3", "network2", "subnet2", "normal",
+        heat_template.add_port("port3", network2,
                                sec_group_id="sec_group1", provider="sriov")
         heat_template.add_floating_ip("floating_ip1", "network1", "port1",
                                       "router_if1")