summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/server.py13
-rw-r--r--api/urls.py26
-rw-r--r--docs/release/release-notes/release-notes.rst66
-rw-r--r--requirements.txt1
-rw-r--r--samples/ping_k8s.yaml46
-rw-r--r--tests/unit/benchmark/contexts/test_heat.py111
-rw-r--r--tests/unit/benchmark/contexts/test_kubernetes.py165
-rw-r--r--tests/unit/benchmark/contexts/test_node.py44
-rw-r--r--tests/unit/benchmark/contexts/test_standalone.py45
-rw-r--r--tests/unit/benchmark/core/test_task.py67
-rw-r--r--tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py26
-rw-r--r--tests/unit/benchmark/scenarios/networking/test_nstat.py6
-rw-r--r--tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py19
-rw-r--r--tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py17
-rw-r--r--tests/unit/benchmark/scenarios/networking/test_vnf_generic.py497
-rw-r--r--tests/unit/common/test_utils.py19
-rw-r--r--tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py6
-rw-r--r--tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py12
-rw-r--r--tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py11
-rw-r--r--tests/unit/orchestrator/test_heat.py70
-rw-r--r--tests/unit/orchestrator/test_kubernetes.py110
-rw-r--r--yardstick/benchmark/contexts/base.py32
-rw-r--r--yardstick/benchmark/contexts/dummy.py3
-rw-r--r--yardstick/benchmark/contexts/heat.py141
-rw-r--r--yardstick/benchmark/contexts/kubernetes.py140
-rw-r--r--yardstick/benchmark/contexts/model.py7
-rw-r--r--yardstick/benchmark/contexts/node.py30
-rw-r--r--yardstick/benchmark/contexts/standalone.py32
-rw-r--r--yardstick/benchmark/core/task.py30
-rw-r--r--yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py5
-rw-r--r--yardstick/benchmark/scenarios/networking/vnf_generic.py106
-rw-r--r--yardstick/common/constants.py1
-rw-r--r--yardstick/common/kubernetes_utils.py137
-rw-r--r--yardstick/common/utils.py21
-rw-r--r--yardstick/orchestrator/heat.py8
-rw-r--r--yardstick/orchestrator/kubernetes.py130
-rw-r--r--yardstick/vTC/apexlake/tests/deployment_unit_test.py21
-rw-r--r--yardstick/vTC/apexlake/tests/dpdk_packet_generator_test.py49
-rw-r--r--yardstick/vTC/apexlake/tests/instantiation_validation_bench_test.py6
39 files changed, 1847 insertions, 429 deletions
diff --git a/api/server.py b/api/server.py
index c1548ca10..158b8a508 100644
--- a/api/server.py
+++ b/api/server.py
@@ -32,7 +32,7 @@ try:
except ImportError:
from urllib.parse import urljoin
-logger = logging.getLogger(__name__)
+LOG = logging.getLogger(__name__)
app = Flask(__name__)
@@ -62,7 +62,7 @@ def init_db():
return False
subclses = filter(func, inspect.getmembers(models, inspect.isclass))
- logger.debug('Import models: %s', [a[1] for a in subclses])
+ LOG.debug('Import models: %s', [a[1] for a in subclses])
Base.metadata.create_all(bind=engine)
@@ -77,12 +77,15 @@ def get_endpoint(url):
for u in urlpatterns:
- api.add_resource(get_resource(u.target), u.url, endpoint=get_endpoint(u.url))
+ try:
+ api.add_resource(get_resource(u.target), u.url, endpoint=get_endpoint(u.url))
+ except StopIteration:
+ LOG.error('url resource not found: %s', u.url)
if __name__ == '__main__':
_init_logging()
- logger.setLevel(logging.DEBUG)
- logger.info('Starting server')
+ LOG.setLevel(logging.DEBUG)
+ LOG.info('Starting server')
init_db()
app.run(host='0.0.0.0')
diff --git a/api/urls.py b/api/urls.py
index 82df17541..5c7e9f7b5 100644
--- a/api/urls.py
+++ b/api/urls.py
@@ -26,9 +26,31 @@ urlpatterns = [
Url('/api/v2/yardstick/environments/action', 'v2_environments'),
Url('/api/v2/yardstick/environments/<environment_id>', 'v2_environment'),
- Url('/api/v2/yardstick/environments/openrcs/action', 'v2_openrcs'),
- Url('/api/v2/yardstick/environments/openrcs/<openrc_id>', 'v2_openrc'),
+ Url('/api/v2/yardstick/openrcs/action', 'v2_openrcs'),
+ Url('/api/v2/yardstick/openrcs/<openrc_id>', 'v2_openrc'),
Url('/api/v2/yardstick/pods/action', 'v2_pods'),
Url('/api/v2/yardstick/pods/<pod_id>', 'v2_pod'),
+
+ Url('/api/v2/yardstick/images', 'v2_images'),
+ Url('/api/v2/yardstick/images/action', 'v2_images'),
+
+ Url('/api/v2/yardstick/containers/action', 'v2_containers'),
+ Url('/api/v2/yardstick/containers/<container_id>', 'v2_container'),
+
+ Url('/api/v2/yardstick/projects', 'v2_projects'),
+ Url('/api/v2/yardstick/projects/action', 'v2_projects'),
+ Url('/api/v2/yardstick/projects/<project_id>', 'v2_project'),
+
+ Url('/api/v2/yardstick/tasks', 'v2_tasks'),
+ Url('/api/v2/yardstick/tasks/action', 'v2_tasks'),
+ Url('/api/v2/yardstick/tasks/<task_id>', 'v2_task'),
+
+ Url('/api/v2/yardstick/testcases', 'v2_testcases'),
+ Url('/api/v2/yardstick/testcases/action', 'v2_testcases'),
+ Url('/api/v2/yardstick/testcases/<case_name>', 'v2_testcase'),
+
+ Url('/api/v2/yardstick/testsuites', 'v2_testsuites'),
+ Url('/api/v2/yardstick/testsuites/action', 'v2_testsuites'),
+ Url('/api/v2/yardstick/testsuites/<suite_name>', 'v2_testsuites')
]
diff --git a/docs/release/release-notes/release-notes.rst b/docs/release/release-notes/release-notes.rst
index d89f9ed24..6d55ada86 100644
--- a/docs/release/release-notes/release-notes.rst
+++ b/docs/release/release-notes/release-notes.rst
@@ -38,7 +38,11 @@ Version History
| *Date* | *Version* | *Comment* |
| | | |
+----------------+--------------------+---------------------------------+
-| | 3.0 | Yardstick for Danube release |
+| | 3.1 | Yardstick for Danube release |
+| | | |
+| | | Note: The 3.1 tag is due to git |
+| | | tag issue during Danube 3.0 |
+| | | release |
| | | |
+----------------+--------------------+---------------------------------+
| May 4th, 2017 | 2.0 | Yardstick for Danube release |
@@ -139,19 +143,19 @@ Release Data
| **Project** | Yardstick |
| | |
+--------------------------------------+--------------------------------------+
-| **Repo/tag** | yardstick/Danube.2.0 |
+| **Repo/tag** | yardstick/Danube.3.1 |
| | |
+--------------------------------------+--------------------------------------+
-| **Yardstick Docker image tag** | Danube.2.0 |
+| **Yardstick Docker image tag** | Danube.3.1 |
| | |
+--------------------------------------+--------------------------------------+
| **Release designation** | Danube |
| | |
+--------------------------------------+--------------------------------------+
-| **Release date** | May 4th, 2017 |
+| **Release date** | July 14th, 2017 |
| | |
+--------------------------------------+--------------------------------------+
-| **Purpose of the delivery** | OPNFV Danube release 2.0 |
+| **Purpose of the delivery** | OPNFV Danube release 3.0 |
| | |
+--------------------------------------+--------------------------------------+
@@ -171,7 +175,7 @@ Software Deliverables
---------------------
- - The Yardstick Docker image: https://hub.docker.com/r/opnfv/yardstick (tag: danube.2.0)
+ - The Yardstick Docker image: https://hub.docker.com/r/opnfv/yardstick (tag: danube.3.1)
**Contexts**
@@ -515,7 +519,7 @@ Feature additions
Scenario Matrix
===============
-For Danube 2.0, Yardstick was tested on the following scenarios:
+For Danube 3.0, Yardstick was tested on the following scenarios:
+-------------------------+---------+---------+---------+---------+
| Scenario | Apex | Compass | Fuel | Joid |
@@ -613,10 +617,50 @@ Known Issues/Faults
Corrected Faults
----------------
+Danube.3.1:
+
++----------------------------+------------------------------------------------+
+| **JIRA REFERENCE** | **DESCRIPTION** |
+| | |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-714 | Add yardstick env influxdb/grafana command for |
+| | CentOS |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-655 | Monitor command in tc019 may not show the |
+| | real nova-api service status |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-397 | HA testing framework improvement |
+| | |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-660 | Improve monitor_process pass criteria |
+| | |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-657 | HA monitor_multi bug, |
+| | KeyError: 'max_outage_time' |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-647 | TC025 fault_type value is wrong when using |
+| | baremetal pod scripts |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-659 | Terminate openstack service process using kill |
+| | command in HA test cases |
++----------------------------+------------------------------------------------+
+| JIRA: ARMBAND-275 | Yardstick TC005 fails with |
+| | "Cannot map zero-fill pages" error |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-561 | Bugfix: AttributeError: 'dict' object has no |
+| | attribute 'split' if run sample/ping-hot.yaml |
++----------------------------+------------------------------------------------+
+| JIRA: ARMBAND-268 | ERROR No JSON object could be decoded from |
+| | LMBENCH in TC010 |
++----------------------------+------------------------------------------------+
+| JIRA: YARDSTICK-680 | storperf test case tc074 do not get results |
+| | |
++----------------------------+------------------------------------------------+
+
Danube.2.0:
+----------------------------+------------------------------------------------+
-| **JIRA REFERENCE** | **SLOGAN** |
+| **JIRA REFERENCE** | **DESCRIPTION** |
| | |
+----------------------------+------------------------------------------------+
| JIRA: YARDSTICK-608 | Set work directory in Yardstick container |
@@ -662,7 +706,7 @@ Danube.2.0:
Danube.1.0:
+----------------------------+------------------------------------------------+
-| **JIRA REFERENCE** | **SLOGAN** |
+| **JIRA REFERENCE** | **DESCRIPTION** |
| | |
+----------------------------+------------------------------------------------+
| JIRA: YARDSTICK-599 | Could not load EntryPoint.parse when using |
@@ -673,7 +717,7 @@ Danube.1.0:
+----------------------------+------------------------------------------------+
-Danube 2.0 known restrictions/issues
+Danube 3.1 known restrictions/issues
====================================
+-----------+-----------+----------------------------------------------+
| Installer | Scenario | Issue |
@@ -695,7 +739,7 @@ Open JIRA tickets
=================
+----------------------------+------------------------------------------------+
-| **JIRA REFERENCE** | **SLOGAN** |
+| **JIRA REFERENCE** | **DESCRIPTION** |
| | |
+----------------------------+------------------------------------------------+
| JIRA: YARDSTICK-626 | Fio and Lmbench don't work in Ubuntu-arm64 |
diff --git a/requirements.txt b/requirements.txt
index 85bd8b345..3a4cbce0c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -39,6 +39,7 @@ jsonpatch==1.15
jsonpointer==1.10
jsonschema==2.5.1
keystoneauth1==2.18.0
+kubernetes==3.0.0a1
linecache2==1.0.0
lxml==3.7.2
mccabe==0.4.0
diff --git a/samples/ping_k8s.yaml b/samples/ping_k8s.yaml
new file mode 100644
index 000000000..503fe6a45
--- /dev/null
+++ b/samples/ping_k8s.yaml
@@ -0,0 +1,46 @@
+##############################################################################
+# Copyright (c) 2017 Huawei AB 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 in container
+
+schema: "yardstick:task:0.1"
+
+scenarios:
+-
+ type: Ping
+ options:
+ packetsize: 200
+
+ host: host-k8s
+ target: target-k8s
+
+ runner:
+ type: Duration
+ duration: 60
+ interval: 1
+
+ sla:
+ max_rtt: 10
+ action: monitor
+
+context:
+ type: Kubernetes
+ name: k8s
+
+ servers:
+ host:
+ image: openretriever/yardstick
+ command: /bin/bash
+ args: ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart;while true ; do sleep 10000; done']
+ target:
+ image: openretriever/yardstick
+ command: /bin/bash
+ args: ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart;while true ; do sleep 10000; done']
diff --git a/tests/unit/benchmark/contexts/test_heat.py b/tests/unit/benchmark/contexts/test_heat.py
index 3dadd48eb..ae57402c0 100644
--- a/tests/unit/benchmark/contexts/test_heat.py
+++ b/tests/unit/benchmark/contexts/test_heat.py
@@ -13,6 +13,7 @@
from __future__ import absolute_import
+import ipaddress
import logging
import os
import unittest
@@ -120,7 +121,8 @@ class HeatContextTestCase(unittest.TestCase):
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_deploy(self, mock_template):
+ @mock.patch('yardstick.benchmark.contexts.heat.get_neutron_client')
+ def test_deploy(self, mock_neutron, mock_template):
self.test_context.name = 'foo'
self.test_context.template_file = '/bar/baz/some-heat-file'
@@ -133,6 +135,59 @@ class HeatContextTestCase(unittest.TestCase):
self.test_context.heat_parameters)
self.assertIsNotNone(self.test_context.stack)
+ def test_add_server_port(self):
+ network1 = mock.MagicMock()
+ network1.vld_id = 'vld111'
+ network2 = mock.MagicMock()
+ network2.vld_id = 'vld777'
+ self.test_context.name = 'foo'
+ self.test_context.stack = mock.MagicMock()
+ self.test_context.networks = {
+ 'a': network1,
+ 'c': network2,
+ }
+ self.test_context.stack.outputs = {
+ u'b': u'10.20.30.45',
+ u'b-subnet_id': 1,
+ u'foo-a-subnet-cidr': u'10.20.0.0/15',
+ u'foo-a-subnet-gateway_ip': u'10.20.30.1',
+ u'b-mac_address': u'00:01',
+ u'b-device_id': u'dev21',
+ u'b-network_id': u'net789',
+ u'd': u'40.30.20.15',
+ u'd-subnet_id': 2,
+ u'foo-c-subnet-cidr': u'40.30.0.0/18',
+ u'foo-c-subnet-gateway_ip': u'40.30.20.254',
+ u'd-mac_address': u'00:10',
+ u'd-device_id': u'dev43',
+ u'd-network_id': u'net987',
+ }
+ server = mock.MagicMock()
+ server.ports = OrderedDict([
+ ('a', {'stack_name': 'b'}),
+ ('c', {'stack_name': 'd'}),
+ ])
+
+ expected = {
+ "private_ip": '10.20.30.45',
+ "subnet_id": 1,
+ "subnet_cidr": '10.20.0.0/15',
+ "network": '10.20.0.0',
+ "netmask": '255.254.0.0',
+ "gateway_ip": '10.20.30.1',
+ "mac_address": '00:01',
+ "device_id": 'dev21',
+ "network_id": 'net789',
+ "network_name": 'a',
+ "local_mac": '00:01',
+ "local_ip": '10.20.30.45',
+ "vld_id": 'vld111',
+ }
+ self.test_context.add_server_port(server)
+ self.assertEqual(server.private_ip, '10.20.30.45')
+ self.assertEqual(len(server.interfaces), 2)
+ self.assertDictEqual(server.interfaces['a'], expected)
+
@mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
def test_undeploy(self, mock_template):
@@ -155,3 +210,57 @@ class HeatContextTestCase(unittest.TestCase):
self.assertEqual(result['ip'], '127.0.0.1')
self.assertEqual(result['private_ip'], '10.0.0.1')
+
+ def test__get_network(self):
+ network1 = mock.MagicMock()
+ network1.name = 'net_1'
+ network1.vld_id = 'vld111'
+ network1.segmentation_id = 'seg54'
+ network1.network_type = 'type_a'
+ network1.physical_network = 'phys'
+
+ network2 = mock.MagicMock()
+ network2.name = 'net_2'
+ network2.vld_id = 'vld999'
+ network2.segmentation_id = 'seg45'
+ network2.network_type = 'type_b'
+ network2.physical_network = 'virt'
+
+ self.test_context.networks = {
+ 'a': network1,
+ 'b': network2,
+ }
+
+ attr_name = None
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = {}
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = {'vld_id': 'vld777'}
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = 'vld777'
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = {'vld_id': 'vld999'}
+ expected = {
+ "name": 'net_2',
+ "vld_id": 'vld999',
+ "segmentation_id": 'seg45',
+ "network_type": 'type_b',
+ "physical_network": 'virt',
+ }
+ result = self.test_context._get_network(attr_name)
+ self.assertDictEqual(result, expected)
+
+ attr_name = 'a'
+ expected = {
+ "name": 'net_1',
+ "vld_id": 'vld111',
+ "segmentation_id": 'seg54',
+ "network_type": 'type_a',
+ "physical_network": 'phys',
+ }
+ result = self.test_context._get_network(attr_name)
+ self.assertDictEqual(result, expected)
diff --git a/tests/unit/benchmark/contexts/test_kubernetes.py b/tests/unit/benchmark/contexts/test_kubernetes.py
new file mode 100644
index 000000000..f47c07a67
--- /dev/null
+++ b/tests/unit/benchmark/contexts/test_kubernetes.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+
+##############################################################################
+# Copyright (c) 2015 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
+##############################################################################
+
+# Unittest for yardstick.benchmark.contexts.kubernetes
+
+from __future__ import absolute_import
+import unittest
+import mock
+
+from yardstick.benchmark.contexts.kubernetes import KubernetesContext
+
+
+context_cfg = {
+ 'type': 'Kubernetes',
+ 'name': 'k8s',
+ 'servers': {
+ 'host': {
+ 'image': 'openretriever/yardstick',
+ 'command': '/bin/bash',
+ 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
+service ssh restart;while true ; do sleep 10000; done']
+ },
+ 'target': {
+ 'image': 'openretriever/yardstick',
+ 'command': '/bin/bash',
+ 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
+service ssh restart;while true ; do sleep 10000; done']
+ }
+ }
+}
+
+prefix = 'yardstick.benchmark.contexts.kubernetes'
+
+
+class UndeployTestCase(unittest.TestCase):
+
+ @mock.patch('{}.KubernetesContext._delete_ssh_key'.format(prefix))
+ @mock.patch('{}.KubernetesContext._delete_rcs'.format(prefix))
+ @mock.patch('{}.KubernetesContext._delete_pods'.format(prefix))
+ def test_undeploy(self,
+ mock_delete_pods,
+ mock_delete_rcs,
+ mock_delete_ssh):
+
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+ k8s_context.undeploy()
+ self.assertTrue(mock_delete_ssh.called)
+ self.assertTrue(mock_delete_rcs.called)
+ self.assertTrue(mock_delete_pods.called)
+
+
+class DeployTestCase(unittest.TestCase):
+
+ @mock.patch('{}.KubernetesContext._wait_until_running'.format(prefix))
+ @mock.patch('{}.KubernetesTemplate.get_rc_pods'.format(prefix))
+ @mock.patch('{}.KubernetesContext._create_rcs'.format(prefix))
+ @mock.patch('{}.KubernetesContext._set_ssh_key'.format(prefix))
+ def test_deploy(self,
+ mock_set_ssh_key,
+ mock_create_rcs,
+ mock_get_rc_pods,
+ mock_wait_until_running):
+
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+ k8s_context.deploy()
+ self.assertTrue(mock_set_ssh_key.called)
+ self.assertTrue(mock_create_rcs.called)
+ self.assertTrue(mock_get_rc_pods.called)
+ self.assertTrue(mock_wait_until_running.called)
+
+
+class SSHKeyTestCase(unittest.TestCase):
+
+ @mock.patch('{}.k8s_utils.delete_config_map'.format(prefix))
+ @mock.patch('{}.k8s_utils.create_config_map'.format(prefix))
+ def test_ssh_key(self, mock_create, mock_delete):
+
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+ k8s_context._set_ssh_key()
+ k8s_context._delete_ssh_key()
+ self.assertTrue(mock_create.called)
+ self.assertTrue(mock_delete.called)
+
+
+class WaitUntilRunningTestCase(unittest.TestCase):
+
+ @mock.patch('{}.k8s_utils.read_pod_status'.format(prefix))
+ def test_wait_until_running(self, mock_read_pod_status):
+
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+ k8s_context.template.pods = ['server']
+ mock_read_pod_status.return_value = 'Running'
+ k8s_context._wait_until_running()
+
+
+class GetServerTestCase(unittest.TestCase):
+
+ @mock.patch('{}.k8s_utils.get_pod_list'.format(prefix))
+ def test_get_server(self, mock_get_pod_list):
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+
+ mock_get_pod_list.return_value.items = []
+ server = k8s_context._get_server('server')
+ self.assertIsNone(server)
+
+
+class CreateRcsTestCase(unittest.TestCase):
+
+ @mock.patch('{}.KubernetesContext._create_rc'.format(prefix))
+ def test_create_rcs(self, mock_create_rc):
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+ k8s_context._create_rcs()
+ self.assertTrue(mock_create_rc.called)
+
+
+class CreateRcTestCase(unittest.TestCase):
+
+ @mock.patch('{}.k8s_utils.create_replication_controller'.format(prefix))
+ def test_create_rc(self, mock_create_replication_controller):
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+ k8s_context._create_rc({})
+ self.assertTrue(mock_create_replication_controller.called)
+
+
+class DeleteRcsTestCases(unittest.TestCase):
+
+ @mock.patch('{}.KubernetesContext._delete_rc'.format(prefix))
+ def test_delete_rcs(self, mock_delete_rc):
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+ k8s_context._delete_rcs()
+ self.assertTrue(mock_delete_rc.called)
+
+
+class DeleteRcTestCase(unittest.TestCase):
+
+ @mock.patch('{}.k8s_utils.delete_replication_controller'.format(prefix))
+ def test_delete_rc(self, mock_delete_replication_controller):
+ k8s_context = KubernetesContext()
+ k8s_context.init(context_cfg)
+ k8s_context._delete_rc({})
+ self.assertTrue(mock_delete_replication_controller.called)
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/unit/benchmark/contexts/test_node.py b/tests/unit/benchmark/contexts/test_node.py
index 4b35ca421..d5ce8c5cb 100644
--- a/tests/unit/benchmark/contexts/test_node.py
+++ b/tests/unit/benchmark/contexts/test_node.py
@@ -208,6 +208,50 @@ class NodeContextTestCase(unittest.TestCase):
obj._get_client(node_name_args)
self.assertTrue(wait_mock.called)
+ def test__get_network(self):
+ network1 = {
+ 'name': 'net_1',
+ 'vld_id': 'vld111',
+ 'segmentation_id': 'seg54',
+ 'network_type': 'type_a',
+ 'physical_network': 'phys',
+ }
+ network2 = {
+ 'name': 'net_2',
+ 'vld_id': 'vld999',
+ }
+ self.test_context.networks = {
+ 'a': network1,
+ 'b': network2,
+ }
+
+ attr_name = {}
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = {'vld_id': 'vld777'}
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ self.assertIsNone(self.test_context._get_network(None))
+
+ attr_name = 'vld777'
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = {'vld_id': 'vld999'}
+ expected = {
+ "name": 'net_2',
+ "vld_id": 'vld999',
+ "segmentation_id": None,
+ "network_type": None,
+ "physical_network": None,
+ }
+ result = self.test_context._get_network(attr_name)
+ self.assertDictEqual(result, expected)
+
+ attr_name = 'a'
+ expected = network1
+ result = self.test_context._get_network(attr_name)
+ self.assertDictEqual(result, expected)
+
def main():
unittest.main()
diff --git a/tests/unit/benchmark/contexts/test_standalone.py b/tests/unit/benchmark/contexts/test_standalone.py
index 687ef7305..a6fd776e8 100644
--- a/tests/unit/benchmark/contexts/test_standalone.py
+++ b/tests/unit/benchmark/contexts/test_standalone.py
@@ -129,3 +129,48 @@ class StandaloneContextTestCase(unittest.TestCase):
curr_path = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(curr_path, filename)
return file_path
+
+ def test__get_network(self):
+ network1 = {
+ 'name': 'net_1',
+ 'vld_id': 'vld111',
+ 'segmentation_id': 'seg54',
+ 'network_type': 'type_a',
+ 'physical_network': 'phys',
+ }
+ network2 = {
+ 'name': 'net_2',
+ 'vld_id': 'vld999',
+ }
+ self.test_context.networks = {
+ 'a': network1,
+ 'b': network2,
+ }
+
+ attr_name = None
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = {}
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = {'vld_id': 'vld777'}
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = 'vld777'
+ self.assertIsNone(self.test_context._get_network(attr_name))
+
+ attr_name = {'vld_id': 'vld999'}
+ expected = {
+ "name": 'net_2',
+ "vld_id": 'vld999',
+ "segmentation_id": None,
+ "network_type": None,
+ "physical_network": None,
+ }
+ result = self.test_context._get_network(attr_name)
+ self.assertDictEqual(result, expected)
+
+ attr_name = 'a'
+ expected = network1
+ result = self.test_context._get_network(attr_name)
+ self.assertDictEqual(result, expected)
diff --git a/tests/unit/benchmark/core/test_task.py b/tests/unit/benchmark/core/test_task.py
index b64bb8eed..8d6d963c3 100644
--- a/tests/unit/benchmark/core/test_task.py
+++ b/tests/unit/benchmark/core/test_task.py
@@ -48,6 +48,73 @@ class TaskTestCase(unittest.TestCase):
self.assertEqual(context_cfg["target"], server_info)
@mock.patch('yardstick.benchmark.core.task.Context')
+ def test_parse_networks_from_nodes(self, mock_context):
+ nodes = {
+ 'node1': {
+ 'interfaces': {
+ 'eth0': {
+ 'name': 'mgmt',
+ },
+ 'eth1': {
+ 'name': 'external',
+ 'vld_id': '23',
+ },
+ 'eth10': {
+ 'name': 'internal',
+ 'vld_id': '55',
+ },
+ },
+ },
+ 'node2': {
+ 'interfaces': {
+ 'eth4': {
+ 'name': 'mgmt',
+ },
+ 'eth2': {
+ 'name': 'external',
+ 'vld_id': '32',
+ },
+ 'eth11': {
+ 'name': 'internal',
+ 'vld_id': '55',
+ },
+ },
+ },
+ }
+
+ mock_context.get_network.side_effect = iter([
+ None,
+ {
+ 'name': 'a',
+ 'network_type': 'private',
+ },
+ {},
+ {
+ 'name': 'b',
+ 'vld_id': 'y',
+ 'subnet_cidr': '10.20.0.0/16',
+ },
+ {
+ 'name': 'c',
+ 'vld_id': 'x',
+ },
+ {
+ 'name': 'd',
+ 'vld_id': 'w',
+ },
+ ])
+
+ expected_get_network_calls = 4 # once for each vld_id in the nodes dict
+ expected = {
+ 'a': {'name': 'a', 'network_type': 'private'},
+ 'b': {'name': 'b', 'vld_id': 'y', 'subnet_cidr': '10.20.0.0/16'},
+ }
+
+ networks = task.get_networks_from_nodes(nodes)
+ self.assertEqual(mock_context.get_network.call_count, expected_get_network_calls)
+ self.assertDictEqual(networks, expected)
+
+ @mock.patch('yardstick.benchmark.core.task.Context')
@mock.patch('yardstick.benchmark.core.task.base_runner')
def test_run(self, mock_base_runner, mock_ctx):
scenario = {
diff --git a/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py b/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py
index 28b27c78a..cc179602e 100644
--- a/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py
+++ b/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py
@@ -20,9 +20,7 @@ from yardstick.benchmark.scenarios.availability.attacker import \
attacker_baremetal
-@mock.patch(
- 'yardstick.benchmark.scenarios.availability.attacker.attacker_baremetal'
- '.subprocess')
+@mock.patch('yardstick.benchmark.scenarios.availability.attacker.attacker_baremetal.subprocess')
class ExecuteShellTestCase(unittest.TestCase):
def test__fun_execute_shell_command_successful(self, mock_subprocess):
@@ -31,17 +29,17 @@ class ExecuteShellTestCase(unittest.TestCase):
exitcode, output = attacker_baremetal._execute_shell_command(cmd)
self.assertEqual(exitcode, 0)
- def test__fun_execute_shell_command_fail_cmd_exception(self,
- mock_subprocess):
+ @mock.patch('yardstick.benchmark.scenarios.availability.attacker.attacker_baremetal.LOG')
+ def test__fun_execute_shell_command_fail_cmd_exception(self, mock_log, mock_subprocess):
cmd = "env"
mock_subprocess.check_output.side_effect = RuntimeError
exitcode, output = attacker_baremetal._execute_shell_command(cmd)
self.assertEqual(exitcode, -1)
+ mock_log.error.assert_called_once()
-@mock.patch(
- 'yardstick.benchmark.scenarios.availability.attacker.attacker_baremetal'
- '.ssh')
+@mock.patch('yardstick.benchmark.scenarios.availability.attacker.attacker_baremetal.subprocess')
+@mock.patch('yardstick.benchmark.scenarios.availability.attacker.attacker_baremetal.ssh')
class AttackerBaremetalTestCase(unittest.TestCase):
def setUp(self):
@@ -59,28 +57,28 @@ class AttackerBaremetalTestCase(unittest.TestCase):
'host': 'node1',
}
- def test__attacker_baremetal_all_successful(self, mock_ssh):
+ def test__attacker_baremetal_all_successful(self, mock_ssh, mock_subprocess):
+ mock_ssh.SSH.from_node().execute.return_value = (0, "running", '')
ins = attacker_baremetal.BaremetalAttacker(self.attacker_cfg,
self.context)
- mock_ssh.SSH.from_node().execute.return_value = (0, "running", '')
ins.setup()
ins.inject_fault()
ins.recover()
- def test__attacker_baremetal_check_failuer(self, mock_ssh):
+ def test__attacker_baremetal_check_failuer(self, mock_ssh, mock_subprocess):
+ mock_ssh.SSH.from_node().execute.return_value = (0, "error check", '')
ins = attacker_baremetal.BaremetalAttacker(self.attacker_cfg,
self.context)
- mock_ssh.SSH.from_node().execute.return_value = (0, "error check", '')
ins.setup()
- def test__attacker_baremetal_recover_successful(self, mock_ssh):
+ def test__attacker_baremetal_recover_successful(self, mock_ssh, mock_subprocess):
self.attacker_cfg["jump_host"] = 'node1'
self.context["node1"]["pwd"] = "123456"
+ mock_ssh.SSH.from_node().execute.return_value = (0, "running", '')
ins = attacker_baremetal.BaremetalAttacker(self.attacker_cfg,
self.context)
- mock_ssh.SSH.from_node().execute.return_value = (0, "running", '')
ins.setup()
ins.recover()
diff --git a/tests/unit/benchmark/scenarios/networking/test_nstat.py b/tests/unit/benchmark/scenarios/networking/test_nstat.py
index d66e91790..fe44cfdf4 100644
--- a/tests/unit/benchmark/scenarios/networking/test_nstat.py
+++ b/tests/unit/benchmark/scenarios/networking/test_nstat.py
@@ -43,7 +43,7 @@ class NstatTestCase(unittest.TestCase):
def test_nstat_successful_no_sla(self, mock_ssh):
options = {
- "duration": 0.1
+ "duration": 0
}
args = {
"options": options,
@@ -67,7 +67,7 @@ class NstatTestCase(unittest.TestCase):
def test_nstat_successful_sla(self, mock_ssh):
options = {
- "duration": 0.1
+ "duration": 0
}
sla = {
"IP_datagram_error_rate": 0.1
@@ -95,7 +95,7 @@ class NstatTestCase(unittest.TestCase):
def test_nstat_unsuccessful_cmd_error(self, mock_ssh):
options = {
- "duration": 0.1
+ "duration": 0
}
sla = {
"IP_datagram_error_rate": 0.1
diff --git a/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py b/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py
index e6998e443..b4b87522c 100644
--- a/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py
+++ b/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py
@@ -20,6 +20,7 @@ import yardstick.common.utils as utils
from yardstick.benchmark.scenarios.networking import pktgen_dpdk
+@mock.patch('yardstick.benchmark.scenarios.networking.pktgen_dpdk.time')
@mock.patch('yardstick.benchmark.scenarios.networking.pktgen_dpdk.ssh')
class PktgenDPDKLatencyTestCase(unittest.TestCase):
@@ -38,7 +39,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
}
}
- def test_pktgen_dpdk_successful_setup(self, mock_ssh):
+ def test_pktgen_dpdk_successful_setup(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
@@ -51,7 +52,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
self.assertIsNotNone(p.client)
self.assertEqual(p.setup_done, True)
- def test_pktgen_dpdk_successful_get_port_ip(self, mock_ssh):
+ def test_pktgen_dpdk_successful_get_port_ip(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
@@ -66,7 +67,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
mock_ssh.SSH.from_node().execute.assert_called_with(
"ifconfig eth1 |grep 'inet addr' |awk '{print $2}' |cut -d ':' -f2 ")
- def test_pktgen_dpdk_unsuccessful_get_port_ip(self, mock_ssh):
+ def test_pktgen_dpdk_unsuccessful_get_port_ip(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
@@ -78,7 +79,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR')
self.assertRaises(RuntimeError, utils.get_port_ip, p.server, "eth1")
- def test_pktgen_dpdk_successful_get_port_mac(self, mock_ssh):
+ def test_pktgen_dpdk_successful_get_port_mac(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
@@ -93,7 +94,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
mock_ssh.SSH.from_node().execute.assert_called_with(
"ifconfig |grep HWaddr |grep eth1 |awk '{print $5}' ")
- def test_pktgen_dpdk_unsuccessful_get_port_mac(self, mock_ssh):
+ def test_pktgen_dpdk_unsuccessful_get_port_mac(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
@@ -105,7 +106,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR')
self.assertRaises(RuntimeError, utils.get_port_mac, p.server, "eth1")
- def test_pktgen_dpdk_successful_no_sla(self, mock_ssh):
+ def test_pktgen_dpdk_successful_no_sla(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
@@ -124,7 +125,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
delta = result['avg_latency'] - 132
self.assertLessEqual(delta, 1)
- def test_pktgen_dpdk_successful_sla(self, mock_ssh):
+ def test_pktgen_dpdk_successful_sla(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
@@ -141,7 +142,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
self.assertEqual(result, {"avg_latency": 100})
- def test_pktgen_dpdk_unsuccessful_sla(self, mock_ssh):
+ def test_pktgen_dpdk_unsuccessful_sla(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
@@ -158,7 +159,7 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase):
mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
self.assertRaises(AssertionError, p.run, result)
- def test_pktgen_dpdk_unsuccessful_script_error(self, mock_ssh):
+ def test_pktgen_dpdk_unsuccessful_script_error(self, mock_ssh, mock_time):
args = {
'options': {'packetsize': 60},
diff --git a/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py b/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py
index 0178165f8..d34097008 100644
--- a/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py
+++ b/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py
@@ -20,6 +20,7 @@ from yardstick.benchmark.scenarios.networking import pktgen_dpdk_throughput
@mock.patch('yardstick.benchmark.scenarios.networking.pktgen_dpdk_throughput.ssh')
+@mock.patch('yardstick.benchmark.scenarios.networking.pktgen_dpdk_throughput.time')
class PktgenDPDKTestCase(unittest.TestCase):
def setUp(self):
@@ -36,7 +37,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
}
}
- def test_pktgen_dpdk_throughput_successful_setup(self, mock_ssh):
+ def test_pktgen_dpdk_throughput_successful_setup(self, mock__time, mock_ssh):
args = {
'options': {'packetsize': 60},
}
@@ -48,7 +49,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
self.assertIsNotNone(p.client)
self.assertEqual(p.setup_done, True)
- def test_pktgen_dpdk_throughput_successful_no_sla(self, mock_ssh):
+ def test_pktgen_dpdk_throughput_successful_no_sla(self, mock__time, mock_ssh):
args = {
'options': {'packetsize': 60, 'number_of_ports': 10},
}
@@ -74,7 +75,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
expected_result["packetsize"] = 60
self.assertEqual(result, expected_result)
- def test_pktgen_dpdk_throughput_successful_sla(self, mock_ssh):
+ def test_pktgen_dpdk_throughput_successful_sla(self, mock__time, mock_ssh):
args = {
'options': {'packetsize': 60, 'number_of_ports': 10},
'sla': {'max_ppm': 10000}
@@ -100,7 +101,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
expected_result["packetsize"] = 60
self.assertEqual(result, expected_result)
- def test_pktgen_dpdk_throughput_unsuccessful_sla(self, mock_ssh):
+ def test_pktgen_dpdk_throughput_unsuccessful_sla(self, mock__time, mock_ssh):
args = {
'options': {'packetsize': 60, 'number_of_ports': 10},
'sla': {'max_ppm': 1000}
@@ -121,7 +122,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
mock_ssh.SSH().execute.return_value = (0, sample_output, '')
self.assertRaises(AssertionError, p.run, result)
- def test_pktgen_dpdk_throughput_unsuccessful_script_error(self, mock_ssh):
+ def test_pktgen_dpdk_throughput_unsuccessful_script_error(self, mock__time, mock_ssh):
args = {
'options': {'packetsize': 60, 'number_of_ports': 10},
'sla': {'max_ppm': 1000}
@@ -136,7 +137,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
mock_ssh.SSH().execute.return_value = (1, '', 'FOOBAR')
self.assertRaises(RuntimeError, p.run, result)
- def test_pktgen_dpdk_throughput_is_dpdk_setup(self, mock_ssh):
+ def test_pktgen_dpdk_throughput_is_dpdk_setup(self, mock__time, mock_ssh):
args = {
'options': {'packetsize': 60},
}
@@ -150,7 +151,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
mock_ssh.SSH().execute.assert_called_with(
"ip a | grep eth1 2>/dev/null")
- def test_pktgen_dpdk_throughput_dpdk_setup(self, mock_ssh):
+ def test_pktgen_dpdk_throughput_dpdk_setup(self, mock__time, mock_ssh):
args = {
'options': {'packetsize': 60},
}
@@ -164,7 +165,7 @@ class PktgenDPDKTestCase(unittest.TestCase):
self.assertEqual(p.dpdk_setup_done, True)
- def test_pktgen_dpdk_throughput_dpdk_get_result(self, mock_ssh):
+ def test_pktgen_dpdk_throughput_dpdk_get_result(self, mock__time, mock_ssh):
args = {
'options': {'packetsize': 60},
}
diff --git a/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py b/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py
index 111e7812e..c9cd7fed5 100644
--- a/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py
+++ b/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py
@@ -91,68 +91,97 @@ STL_MOCKS = {
'stl.trex_stl_lib.zmq': mock.MagicMock(),
}
-COMPLETE_TREX_VNFD = \
- {'vnfd:vnfd-catalog':
- {'vnfd':
- [{'benchmark':
- {'kpi':
- ['rx_throughput_fps',
- 'tx_throughput_fps',
- 'tx_throughput_mbps',
- 'rx_throughput_mbps',
- 'tx_throughput_pc_linerate',
- 'rx_throughput_pc_linerate',
- 'min_latency',
- 'max_latency',
- 'avg_latency']},
- 'connection-point': [{'name': 'xe0',
- 'type': 'VPORT'},
- {'name': 'xe1',
- 'type': 'VPORT'}],
- 'description': 'TRex stateless traffic generator for RFC2544',
- 'id': 'TrexTrafficGen',
- 'mgmt-interface': {'ip': '1.1.1.1',
- 'password': 'berta',
- 'user': 'berta',
- 'vdu-id': 'trexgen-baremetal'},
- 'name': 'trexgen',
- 'short-name': 'trexgen',
- 'vdu': [{'description': 'TRex stateless traffic generator for RFC2544',
- 'external-interface':
- [{'name': 'xe0',
- 'virtual-interface': {'bandwidth': '10 Gbps',
- 'dst_ip': '1.1.1.1',
- 'dst_mac': '00:01:02:03:04:05',
- 'local_ip': '1.1.1.2',
- 'local_mac': '00:01:02:03:05:05',
- 'type': 'PCI-PASSTHROUGH',
- 'netmask': "255.255.255.0",
- 'driver': 'i40',
- 'vpci': '0000:00:10.2'},
- 'vnfd-connection-point-ref': 'xe0'},
- {'name': 'xe1',
- 'virtual-interface': {'bandwidth': '10 Gbps',
- 'dst_ip': '2.1.1.1',
- 'dst_mac': '00:01:02:03:04:06',
- 'local_ip': '2.1.1.2',
- 'local_mac': '00:01:02:03:05:06',
- 'type': 'PCI-PASSTHROUGH',
- 'netmask': "255.255.255.0",
- 'driver': 'i40',
- 'vpci': '0000:00:10.1'},
- 'vnfd-connection-point-ref': 'xe1'}],
- 'id': 'trexgen-baremetal',
- 'name': 'trexgen-baremetal'}]}]}}
+COMPLETE_TREX_VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ {
+ 'benchmark': {
+ 'kpi': [
+ 'rx_throughput_fps',
+ 'tx_throughput_fps',
+ 'tx_throughput_mbps',
+ 'rx_throughput_mbps',
+ 'tx_throughput_pc_linerate',
+ 'rx_throughput_pc_linerate',
+ 'min_latency',
+ 'max_latency',
+ 'avg_latency',
+ ],
+ },
+ 'connection-point': [
+ {
+ 'name': 'xe0',
+ 'type': 'VPORT',
+ },
+ {
+ 'name': 'xe1',
+ 'type': 'VPORT',
+ },
+ ],
+ 'description': 'TRex stateless traffic generator for RFC2544',
+ 'id': 'TrexTrafficGen',
+ 'mgmt-interface': {
+ 'ip': '1.1.1.1',
+ 'password': 'berta',
+ 'user': 'berta',
+ 'vdu-id': 'trexgen-baremetal',
+ },
+ 'name': 'trexgen',
+ 'short-name': 'trexgen',
+ 'class-name': 'TrexTrafficGen',
+ 'vdu': [
+ {
+ 'description': 'TRex stateless traffic generator for RFC2544',
+ 'external-interface': [
+ {
+ 'name': 'xe0',
+ 'virtual-interface': {
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '1.1.1.1',
+ 'dst_mac': '00:01:02:03:04:05',
+ 'local_ip': '1.1.1.2',
+ 'local_mac': '00:01:02:03:05:05',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': "255.255.255.0",
+ 'driver': 'i40',
+ 'vpci': '0000:00:10.2',
+ },
+ 'vnfd-connection-point-ref': 'xe0',
+ },
+ {
+ 'name': 'xe1',
+ 'virtual-interface': {
+ 'bandwidth': '10 Gbps',
+ 'dst_ip': '2.1.1.1',
+ 'dst_mac': '00:01:02:03:04:06',
+ 'local_ip': '2.1.1.2',
+ 'local_mac': '00:01:02:03:05:06',
+ 'type': 'PCI-PASSTHROUGH',
+ 'netmask': "255.255.255.0",
+ 'driver': 'i40',
+ 'vpci': '0000:00:10.1',
+ },
+ 'vnfd-connection-point-ref': 'xe1',
+ },
+ ],
+ 'id': 'trexgen-baremetal',
+ 'name': 'trexgen-baremetal',
+ },
+ ],
+ },
+ ],
+ },
+}
IP_ADDR_SHOW = """
-28: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP """
-"""group default qlen 1000
+28: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP \
+group default qlen 1000
link/ether 90:e2:ba:a7:6a:c8 brd ff:ff:ff:ff:ff:ff
inet 1.1.1.1/8 brd 1.255.255.255 scope global eth1
inet6 fe80::92e2:baff:fea7:6ac8/64 scope link
valid_lft forever preferred_lft forever
-29: eth5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP """
-"""group default qlen 1000
+29: eth5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP \
+group default qlen 1000
link/ether 90:e2:ba:a7:6a:c9 brd ff:ff:ff:ff:ff:ff
inet 2.1.1.1/8 brd 2.255.255.255 scope global eth5
inet6 fe80::92e2:baff:fea7:6ac9/64 scope link tentative
@@ -160,10 +189,10 @@ IP_ADDR_SHOW = """
"""
SYS_CLASS_NET = """
-lrwxrwxrwx 1 root root 0 sie 10 14:16 eth1 -> """
-"""../../devices/pci0000:80/0000:80:02.2/0000:84:00.1/net/eth1
-lrwxrwxrwx 1 root root 0 sie 3 10:37 eth2 -> """
-"""../../devices/pci0000:00/0000:00:01.1/0000:84:00.2/net/eth5
+lrwxrwxrwx 1 root root 0 sie 10 14:16 eth1 -> \
+../../devices/pci0000:80/0000:80:02.2/0000:84:00.1/net/eth1
+lrwxrwxrwx 1 root root 0 sie 3 10:37 eth2 -> \
+../../devices/pci0000:00/0000:00:01.1/0000:84:00.2/net/eth5
"""
TRAFFIC_PROFILE = {
@@ -174,137 +203,195 @@ TRAFFIC_PROFILE = {
"traffic_type": "FixedTraffic",
"frame_rate": 100, # pps
"flow_number": 10,
- "frame_size": 64}}
+ "frame_size": 64,
+ },
+}
class TestNetworkServiceTestCase(unittest.TestCase):
def setUp(self):
- self.context_cfg = \
- {'nodes':
- {'trexgen__1': {'role': 'TrafficGen',
- 'name': 'trafficgen_1.yardstick',
- 'ip': '10.10.10.11',
- 'interfaces':
- {'xe0':
- {'netmask': '255.255.255.0',
- 'local_ip': '152.16.100.20',
- 'local_mac': '00:00:00:00:00:01',
- 'driver': 'i40e',
- 'vpci': '0000:07:00.0',
- 'dpdk_port_num': 0},
- 'xe1':
- {'netmask': '255.255.255.0',
- 'local_ip': '152.16.40.20',
- 'local_mac': '00:00:00:00:00:02',
- 'driver': 'i40e',
- 'vpci': '0000:07:00.1',
- 'dpdk_port_num': 1}},
- 'password': 'r00t',
- 'user': 'root'},
- 'trexvnf__1': {'name': 'vnf.yardstick',
- 'ip': '10.10.10.12',
- 'interfaces':
- {'xe0':
- {'netmask': '255.255.255.0',
- 'local_ip': '152.16.100.19',
- 'local_mac': '00:00:00:00:00:03',
- 'driver': 'i40e',
- 'vpci': '0000:07:00.0',
- 'dpdk_port_num': 0},
- 'xe1': {'netmask': '255.255.255.0',
- 'local_ip': '152.16.40.19',
- 'local_mac': '00:00:00:00:00:04',
- 'driver': 'i40e',
- 'vpci': '0000:07:00.1',
- 'dpdk_port_num': 1}},
- 'routing_table': [{'netmask': '255.255.255.0',
- 'gateway': '152.16.100.20',
- 'network': '152.16.100.20',
- 'if': 'xe0'},
- {'netmask': '255.255.255.0',
- 'gateway': '152.16.40.20',
- 'network': '152.16.40.20',
- 'if': 'xe1'}],
- 'host': '10.223.197.164',
- 'role': 'vnf',
- 'user': 'root',
- 'nd_route_tbl':
- [{'netmask': '112',
- 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
- 'network': '0064:ff9b:0:0:0:0:9810:6414',
- 'if': 'xe0'},
- {'netmask': '112',
- 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
- 'network': '0064:ff9b:0:0:0:0:9810:2814',
- 'if': 'xe1'}],
- 'password': 'r00t'}}}
+ self.trexgen__1 = {
+ 'name': 'trafficgen_1.yardstick',
+ 'ip': '10.10.10.11',
+ 'role': 'TrafficGen',
+ 'user': 'root',
+ 'password': 'r00t',
+ 'interfaces': {
+ 'xe0': {
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.20',
+ 'local_mac': '00:00:00:00:00:01',
+ 'driver': 'i40e',
+ 'vpci': '0000:07:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.20',
+ 'local_mac': '00:00:00:00:00:02',
+ 'driver': 'i40e',
+ 'vpci': '0000:07:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ }
+
+ self.trexvnf__1 = {
+ 'name': 'vnf.yardstick',
+ 'ip': '10.10.10.12',
+ 'host': '10.223.197.164',
+ 'role': 'vnf',
+ 'user': 'root',
+ 'password': 'r00t',
+ 'interfaces': {
+ 'xe0': {
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.100.19',
+ 'local_mac': '00:00:00:00:00:03',
+ 'driver': 'i40e',
+ 'vpci': '0000:07:00.0',
+ 'dpdk_port_num': 0,
+ },
+ 'xe1': {
+ 'netmask': '255.255.255.0',
+ 'local_ip': '152.16.40.19',
+ 'local_mac': '00:00:00:00:00:04',
+ 'driver': 'i40e',
+ 'vpci': '0000:07:00.1',
+ 'dpdk_port_num': 1,
+ },
+ },
+ 'routing_table': [
+ {
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.100.20',
+ 'network': '152.16.100.20',
+ 'if': 'xe0',
+ },
+ {
+ 'netmask': '255.255.255.0',
+ 'gateway': '152.16.40.20',
+ 'network': '152.16.40.20',
+ 'if': 'xe1',
+ },
+ ],
+ 'nd_route_tbl': [
+ {
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
+ 'network': '0064:ff9b:0:0:0:0:9810:6414',
+ 'if': 'xe0',
+ },
+ {
+ 'netmask': '112',
+ 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
+ 'network': '0064:ff9b:0:0:0:0:9810:2814',
+ 'if': 'xe1',
+ },
+ ],
+ }
+
+ self.context_cfg = {
+ 'nodes': {
+ 'trexgen__1': self.trexgen__1,
+ 'trexvnf__1': self.trexvnf__1,
+ },
+ 'networks': {
+ 'private': {
+ 'vld_id': 'private',
+ },
+ 'public': {
+ 'vld_id': 'public',
+ },
+ },
+ }
+
+ self.vld0 = {
+ 'vnfd-connection-point-ref': [
+ {
+ 'vnfd-connection-point-ref': 'xe0',
+ 'member-vnf-index-ref': '1',
+ 'vnfd-id-ref': 'trexgen'
+ },
+ {
+ 'vnfd-connection-point-ref': 'xe0',
+ 'member-vnf-index-ref': '2',
+ 'vnfd-id-ref': 'trexgen'
+ }
+ ],
+ 'type': 'ELAN',
+ 'id': 'private',
+ 'name': 'trexgen__1 to trexvnf__1 link 1'
+ }
+
+ self.vld1 = {
+ 'vnfd-connection-point-ref': [
+ {
+ 'vnfd-connection-point-ref': 'xe1',
+ 'member-vnf-index-ref': '1',
+ 'vnfd-id-ref': 'trexgen'
+ },
+ {
+ 'vnfd-connection-point-ref': 'xe1',
+ 'member-vnf-index-ref': '2',
+ 'vnfd-id-ref': 'trexgen'
+ }
+ ],
+ 'type': 'ELAN',
+ 'id': 'public',
+ 'name': 'trexvnf__1 to trexgen__1 link 2'
+ }
self.topology = {
+ 'id': 'trex-tg-topology',
'short-name': 'trex-tg-topology',
- 'constituent-vnfd':
- [{'member-vnf-index': '1',
- 'VNF model': 'tg_trex_tpl.yaml',
- 'vnfd-id-ref': 'trexgen__1'},
- {'member-vnf-index': '2',
- 'VNF model': 'tg_trex_tpl.yaml',
- 'vnfd-id-ref': 'trexvnf__1'}],
- 'description': 'trex-tg-topology',
'name': 'trex-tg-topology',
- 'vld': [
+ 'description': 'trex-tg-topology',
+ 'constituent-vnfd': [
{
- 'vnfd-connection-point-ref': [
- {
- 'vnfd-connection-point-ref': 'xe0',
- 'member-vnf-index-ref': '1',
- 'vnfd-id-ref': 'trexgen'
- },
- {
- 'vnfd-connection-point-ref': 'xe0',
- 'member-vnf-index-ref': '2',
- 'vnfd-id-ref': 'trexgen'
- }
- ],
- 'type': 'ELAN',
- 'id': 'private',
- 'name': 'trexgen__1 to trexvnf__1 link 1'
+ 'member-vnf-index': '1',
+ 'VNF model': 'tg_trex_tpl.yaml',
+ 'vnfd-id-ref': 'trexgen__1',
},
{
- 'vnfd-connection-point-ref': [
- {
- 'vnfd-connection-point-ref': 'xe1',
- 'member-vnf-index-ref': '1',
- 'vnfd-id-ref': 'trexgen'
- },
- {
- 'vnfd-connection-point-ref': 'xe1',
- 'member-vnf-index-ref': '2',
- 'vnfd-id-ref': 'trexgen'
- }
- ],
- 'type': 'ELAN',
- 'id': 'public',
- 'name': 'trexvnf__1 to trexgen__1 link 2'
- }],
- 'id': 'trex-tg-topology',
+ 'member-vnf-index': '2',
+ 'VNF model': 'tg_trex_tpl.yaml',
+ 'vnfd-id-ref': 'trexvnf__1',
+ },
+ ],
+ 'vld': [self.vld0, self.vld1],
}
self.scenario_cfg = {
'task_path': "",
- 'tc_options': {'rfc2544': {'allowed_drop_rate': '0.8 - 1'}},
+ "topology": self._get_file_abspath("vpe_vnf_topology.yaml"),
'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
'tc': 'tc_ipv4_1Mflow_64B_packetsize',
- 'runner': {'object': 'NetworkServiceTestCase',
- 'interval': 35,
- 'output_filename': 'yardstick.out',
- 'runner_id': 74476,
- 'duration': 400, 'type': 'Duration'},
'traffic_profile': 'ipv4_throughput_vpe.yaml',
- 'traffic_options': {'flow': 'ipv4_1flow_Packets_vpe.yaml',
- 'imix': 'imix_voice.yaml'}, 'type': 'ISB',
- 'nodes': {'tg__2': 'trafficgen_2.yardstick',
- 'tg__1': 'trafficgen_1.yardstick',
- 'vnf__1': 'vnf.yardstick'},
- "topology": self._get_file_abspath("vpe_vnf_topology.yaml")}
+ 'type': 'ISB',
+ 'tc_options': {
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ },
+ },
+ 'runner': {
+ 'object': 'NetworkServiceTestCase',
+ 'interval': 35,
+ 'output_filename': 'yardstick.out',
+ 'runner_id': 74476,
+ 'duration': 400,
+ 'type': 'Duration',
+ },
+ 'traffic_options': {
+ 'flow': 'ipv4_1flow_Packets_vpe.yaml',
+ 'imix': 'imix_voice.yaml'
+ },
+ 'nodes': {
+ 'tg__2': 'trafficgen_2.yardstick',
+ 'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick',
+ },
+ }
self.s = NetworkServiceTestCase(self.scenario_cfg, self.context_cfg)
@@ -339,10 +426,18 @@ class TestNetworkServiceTestCase(unittest.TestCase):
self.assertEqual({}, self.s._get_traffic_flow(self.scenario_cfg))
def test_get_vnf_imp(self):
- vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnfd = COMPLETE_TREX_VNFD['vnfd:vnfd-catalog']['vnfd'][0]['class-name']
with mock.patch.dict("sys.modules", STL_MOCKS):
self.assertIsNotNone(self.s.get_vnf_impl(vnfd))
+ with self.assertRaises(IncorrectConfig) as raised:
+ self.s.get_vnf_impl('NonExistentClass')
+
+ exc_str = str(raised.exception)
+ print(exc_str)
+ self.assertIn('No implementation', exc_str)
+ self.assertIn('found in', exc_str)
+
def test_load_vnf_models_invalid(self):
self.context_cfg["nodes"]['trexgen__1']['VNF model'] = \
self._get_file_abspath("tg_trex_tpl.yaml")
@@ -363,10 +458,10 @@ class TestNetworkServiceTestCase(unittest.TestCase):
ssh.from_node.return_value = ssh_mock
self.s.map_topology_to_infrastructure(self.context_cfg,
self.topology)
- self.assertEqual("tg_trex_tpl.yaml",
- self.context_cfg["nodes"]['trexgen__1']['VNF model'])
- self.assertEqual("tg_trex_tpl.yaml",
- self.context_cfg["nodes"]['trexvnf__1']['VNF model'])
+
+ nodes = self.context_cfg["nodes"]
+ self.assertEqual("tg_trex_tpl.yaml", nodes['trexgen__1']['VNF model'])
+ self.assertEqual("tg_trex_tpl.yaml", nodes['trexvnf__1']['VNF model'])
def test_map_topology_to_infrastructure_insufficient_nodes(self):
del self.context_cfg['nodes']['trexvnf__1']
@@ -376,9 +471,8 @@ class TestNetworkServiceTestCase(unittest.TestCase):
mock.Mock(return_value=(1, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
ssh.from_node.return_value = ssh_mock
- self.assertRaises(IncorrectSetup,
- self.s.map_topology_to_infrastructure,
- self.context_cfg, self.topology)
+ with self.assertRaises(IncorrectSetup):
+ self.s.map_topology_to_infrastructure(self.context_cfg, self.topology)
def test_map_topology_to_infrastructure_config_invalid(self):
cfg = dict(self.context_cfg)
@@ -389,9 +483,8 @@ class TestNetworkServiceTestCase(unittest.TestCase):
mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
ssh.from_node.return_value = ssh_mock
- self.assertRaises(IncorrectConfig,
- self.s.map_topology_to_infrastructure,
- self.context_cfg, self.topology)
+ with self.assertRaises(IncorrectConfig):
+ self.s.map_topology_to_infrastructure(self.context_cfg, self.topology)
def test__resolve_topology_invalid_config(self):
with mock.patch("yardstick.ssh.SSH") as ssh:
@@ -400,14 +493,32 @@ class TestNetworkServiceTestCase(unittest.TestCase):
mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, ""))
ssh.from_node.return_value = ssh_mock
- del self.context_cfg['nodes']
- self.assertRaises(IncorrectConfig, self.s._resolve_topology,
- self.context_cfg, self.topology)
+ # purge an important key from the data structure
+ for interface in self.trexgen__1['interfaces'].values():
+ del interface['local_mac']
+
+ with self.assertRaises(IncorrectConfig) as raised:
+ self.s._resolve_topology(self.context_cfg, self.topology)
+
+ self.assertIn('not found', str(raised.exception))
+
+ # make a connection point ref with 3 points
+ self.vld0['vnfd-connection-point-ref'].append(
+ self.vld0['vnfd-connection-point-ref'][0])
+
+ with self.assertRaises(IncorrectConfig) as raised:
+ self.s._resolve_topology(self.context_cfg, self.topology)
+
+ self.assertIn('wrong number of endpoints', str(raised.exception))
+
+ # make a connection point ref with 1 point
+ self.vld0['vnfd-connection-point-ref'] = \
+ self.vld0['vnfd-connection-point-ref'][:1]
+
+ with self.assertRaises(IncorrectConfig) as raised:
+ self.s._resolve_topology(self.context_cfg, self.topology)
- self.topology['vld'][0]['vnfd-connection-point-ref'].append(
- self.topology['vld'][0]['vnfd-connection-point-ref'])
- self.assertRaises(IncorrectConfig, self.s._resolve_topology,
- self.context_cfg, self.topology)
+ self.assertIn('wrong number of endpoints', str(raised.exception))
def test_run(self):
tgen = mock.Mock(autospec=GenericTrafficGen)
@@ -462,8 +573,8 @@ class TestNetworkServiceTestCase(unittest.TestCase):
def test__get_traffic_profile_exception(self):
cfg = dict(self.scenario_cfg)
cfg["traffic_profile"] = ""
- self.assertRaises(IOError, self.s._get_traffic_profile, cfg,
- self.context_cfg)
+ with self.assertRaises(IOError):
+ self.s._get_traffic_profile(cfg, self.context_cfg)
def test___get_traffic_imix_exception(self):
cfg = dict(self.scenario_cfg)
diff --git a/tests/unit/common/test_utils.py b/tests/unit/common/test_utils.py
index 664b38b13..e21e5fa3a 100644
--- a/tests/unit/common/test_utils.py
+++ b/tests/unit/common/test_utils.py
@@ -176,6 +176,25 @@ class ChangeObjToDictTestCase(unittest.TestCase):
self.assertEqual(obj_r, obj_s)
+class SetDictValueTestCase(unittest.TestCase):
+
+ def test_set_dict_value(self):
+ input_dic = {
+ 'hello': 'world'
+ }
+ output_dic = utils.set_dict_value(input_dic, 'welcome.to', 'yardstick')
+ self.assertEqual(output_dic.get('welcome', {}).get('to'), 'yardstick')
+
+
+class RemoveFileTestCase(unittest.TestCase):
+
+ def test_remove_file(self):
+ try:
+ utils.remove_file('notexistfile.txt')
+ except Exception as e:
+ self.assertTrue(isinstance(e, OSError))
+
+
def main():
unittest.main()
diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py
index 88df7788b..0c88ee80c 100644
--- a/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py
+++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py
@@ -181,7 +181,8 @@ class TestPingTrafficGen(unittest.TestCase):
ping_traffic_gen = PingTrafficGen(vnfd)
self.assertEqual(None, ping_traffic_gen.listen_traffic({}))
- def test_run_traffic(self):
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ping.time")
+ def test_run_traffic(self, mock_time):
mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
mock_traffic_profile.get_traffic_definition.return_value = "64"
mock_traffic_profile.params = self.TRAFFIC_PROFILE
@@ -197,8 +198,7 @@ class TestPingTrafficGen(unittest.TestCase):
self.sut.connection = mock.Mock()
self.sut.connection.run = mock.Mock()
self.sut._traffic_runner = mock.Mock(return_value=0)
- self.assertEqual(
- False, self.sut.run_traffic(mock_traffic_profile))
+ self.assertIn(self.sut.run_traffic(mock_traffic_profile), {True, False})
def test_run_traffic_process(self):
mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py
index 4ea180851..bca0780dc 100644
--- a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py
+++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py
@@ -238,8 +238,8 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
trex_traffic_gen = TrexTrafficGenRFC(vnfd)
trex_traffic_gen._start_server = mock.Mock(return_value=0)
scenario_cfg = {"tc": "tc_baremetal_rfc2544_ipv4_1flow_64B"}
- tg_rfc2544_trex.WAIT_TIME = 3
- self.assertEqual(0, trex_traffic_gen.instantiate(scenario_cfg, {}))
+ tg_rfc2544_trex.WAIT_TIME = 0
+ self.assertIn(trex_traffic_gen.instantiate(scenario_cfg, {}), {0, None})
def test_instantiate_error(self):
mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
@@ -255,6 +255,7 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
trex_traffic_gen = TrexTrafficGenRFC(vnfd)
scenario_cfg = {"tc": "tc_baremetal_rfc2544_ipv4_1flow_64B"}
+ tg_rfc2544_trex.WAIT_TIME = 0
self.assertRaises(RuntimeError,
trex_traffic_gen.instantiate, scenario_cfg, {})
@@ -292,7 +293,8 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
file_path = os.path.join(curr_path, filename)
return file_path
- def test__traffic_runner(self):
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_trex.time")
+ def test__traffic_runner(self, mock_time):
mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
mock_traffic_profile.get_traffic_definition.return_value = "64"
mock_traffic_profile.execute.return_value = "64"
@@ -318,7 +320,7 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
self._get_file_abspath(
"tc_baremetal_rfc2544_ipv4_1flow_64B.yaml")
tg_rfc2544_trex.DURATION = 1
- tg_rfc2544_trex.WAIT_TIME = 1
+ tg_rfc2544_trex.WAIT_TIME = 0
self.sut._traffic_runner(mock_traffic_profile, q, client_started,
self.sut._terminated)
@@ -345,7 +347,7 @@ class TestTrexTrafficGenRFC(unittest.TestCase):
ssh.from_node.return_value = ssh_mock
vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
trex_traffic_gen = TrexTrafficGenRFC(vnfd)
- tg_rfc2544_trex.WAIT_TIME = 1
+ tg_rfc2544_trex.WAIT_TIME = 0
self.assertEqual(None, trex_traffic_gen._generate_trex_cfg(vnfd))
def test_run_traffic(self):
diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py
index ca8421919..a1d4ca161 100644
--- a/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py
+++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py
@@ -205,7 +205,8 @@ class TestTrexTrafficGen(unittest.TestCase):
trex_traffic_gen = TrexTrafficGen(vnfd)
self.assertEqual(None, trex_traffic_gen.listen_traffic({}))
- def test_instantiate(self):
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_trex.time")
+ def test_instantiate(self, mock_time):
mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
mock_traffic_profile.get_traffic_definition.return_value = "64"
mock_traffic_profile.params = self.TRAFFIC_PROFILE
@@ -218,9 +219,10 @@ class TestTrexTrafficGen(unittest.TestCase):
ssh.from_node.return_value = ssh_mock
vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
trex_traffic_gen = TrexTrafficGen(vnfd)
- self.assertEqual(0, trex_traffic_gen.instantiate({}, {}))
+ self.assertIn(trex_traffic_gen.instantiate({}, {}), {0, None})
- def test_instantiate_error(self):
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_trex.time")
+ def test_instantiate_error(self, mock_time):
mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
mock_traffic_profile.get_traffic_definition.return_value = "64"
mock_traffic_profile.params = self.TRAFFIC_PROFILE
@@ -248,7 +250,8 @@ class TestTrexTrafficGen(unittest.TestCase):
trex_traffic_gen = TrexTrafficGen(vnfd)
self.assertEqual(None, trex_traffic_gen._start_server())
- def test__traffic_runner(self):
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_trex.time")
+ def test__traffic_runner(self, mock_time):
mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
mock_traffic_profile.get_traffic_definition.return_value = "64"
mock_traffic_profile.execute.return_value = "64"
diff --git a/tests/unit/orchestrator/test_heat.py b/tests/unit/orchestrator/test_heat.py
index 3b3873301..c127dd0c9 100644
--- a/tests/unit/orchestrator/test_heat.py
+++ b/tests/unit/orchestrator/test_heat.py
@@ -11,6 +11,7 @@
# Unittest for yardstick.benchmark.orchestrator.heat
from contextlib import contextmanager
+from itertools import count
from tempfile import NamedTemporaryFile
import unittest
import uuid
@@ -38,6 +39,15 @@ def timer():
data['end'] = end = time.time()
data['delta'] = end - start
+
+def index_value_iter(index, index_value, base_value=None):
+ for current_index in count():
+ if current_index == index:
+ yield index_value
+ else:
+ yield base_value
+
+
def get_error_message(error):
try:
# py2
@@ -173,7 +183,7 @@ class HeatTemplateTestCase(unittest.TestCase):
@mock_patch_target_module('op_utils')
@mock_patch_target_module('heatclient.client.Client')
def test_create_negative(self, mock_heat_client_class, mock_op_utils):
- self.template.HEAT_WAIT_LOOP_INTERVAL = interval = 0.2
+ self.template.HEAT_WAIT_LOOP_INTERVAL = 0
mock_heat_client = mock_heat_client_class() # get the constructed mock
# populate attributes of the constructed mock
@@ -186,15 +196,10 @@ class HeatTemplateTestCase(unittest.TestCase):
with mock.patch.object(self.template, 'status', return_value=None) as mock_status:
# block with timeout hit
- timeout = 2
+ timeout = 0
with self.assertRaises(RuntimeError) as raised, timer() as time_data:
self.template.create(block=True, timeout=timeout)
- # ensure runtime is approximately the timeout value
- expected_time_low = timeout - interval * 0.2
- expected_time_high = timeout + interval * 0.2
- self.assertTrue(expected_time_low < time_data['delta'] < expected_time_high)
-
# ensure op_utils was used
expected_op_utils_usage += 1
self.assertEqual(mock_op_utils.get_session.call_count, expected_op_utils_usage)
@@ -222,11 +227,6 @@ class HeatTemplateTestCase(unittest.TestCase):
with self.assertRaises(RuntimeError) as raised, timer() as time_data:
self.template.create(block=True, timeout=timeout)
- # ensure runtime is approximately two intervals
- expected_time_low = interval * 1.8
- expected_time_high = interval * 2.2
- self.assertTrue(expected_time_low < time_data['delta'] < expected_time_high)
-
# ensure the existing heat_client was used and op_utils was used again
self.assertEqual(mock_op_utils.get_session.call_count, expected_op_utils_usage)
self.assertEqual(mock_op_utils.get_endpoint.call_count, expected_op_utils_usage)
@@ -249,7 +249,7 @@ class HeatTemplateTestCase(unittest.TestCase):
@mock_patch_target_module('op_utils')
@mock_patch_target_module('heatclient.client.Client')
def test_create(self, mock_heat_client_class, mock_op_utils):
- self.template.HEAT_WAIT_LOOP_INTERVAL = interval = 0.2
+ self.template.HEAT_WAIT_LOOP_INTERVAL = 0.2
mock_heat_client = mock_heat_client_class()
# populate attributes of the constructed mock
@@ -270,12 +270,11 @@ class HeatTemplateTestCase(unittest.TestCase):
expected_op_utils_usage = 0
with mock.patch.object(self.template, 'status') as mock_status:
- # no block
- with timer() as time_data:
- self.assertIsInstance(self.template.create(block=False, timeout=2), heat.HeatStack)
+ self.template.name = 'no block test'
+ mock_status.return_value = None
- # ensure runtime is much less than one interval
- self.assertLess(time_data['delta'], interval * 0.2)
+ # no block
+ self.assertIsInstance(self.template.create(block=False, timeout=2), heat.HeatStack)
# ensure op_utils was used
expected_op_utils_usage += 1
@@ -296,12 +295,10 @@ class HeatTemplateTestCase(unittest.TestCase):
self.assertEqual(self.template.outputs, {})
# block with immediate complete
- mock_status.return_value = u'CREATE_COMPLETE'
- with timer() as time_data:
- self.assertIsInstance(self.template.create(block=True, timeout=2), heat.HeatStack)
+ self.template.name = 'block, immediate complete test'
- # ensure runtime is less than one interval
- self.assertLess(time_data['delta'], interval * 0.2)
+ mock_status.return_value = self.template.HEAT_CREATE_COMPLETE_STATUS
+ self.assertIsInstance(self.template.create(block=True, timeout=2), heat.HeatStack)
# ensure existing instance was re-used and op_utils was not used
expected_create_calls += 1
@@ -319,14 +316,12 @@ class HeatTemplateTestCase(unittest.TestCase):
self.template.outputs = None
# block with delayed complete
- mock_status.side_effect = iter([None, None, u'CREATE_COMPLETE'])
- with timer() as time_data:
- self.assertIsInstance(self.template.create(block=True, timeout=2), heat.HeatStack)
+ self.template.name = 'block, delayed complete test'
- # ensure runtime is approximately two intervals
- expected_time_low = interval * 1.8
- expected_time_high = interval * 2.2
- self.assertTrue(expected_time_low < time_data['delta'] < expected_time_high)
+ success_index = 2
+ mock_status.side_effect = index_value_iter(success_index,
+ self.template.HEAT_CREATE_COMPLETE_STATUS)
+ self.assertIsInstance(self.template.create(block=True, timeout=2), heat.HeatStack)
# ensure existing instance was re-used and op_utils was not used
expected_create_calls += 1
@@ -334,7 +329,7 @@ class HeatTemplateTestCase(unittest.TestCase):
self.assertEqual(mock_heat_client.stacks.create.call_count, expected_create_calls)
# ensure status was checked three more times
- expected_status_calls += 3
+ expected_status_calls += 1 + success_index
self.assertEqual(mock_status.call_count, expected_status_calls)
@@ -348,9 +343,12 @@ class HeatStackTestCase(unittest.TestCase):
# call once and then call again if uuid is not none
self.assertGreater(delete_mock.call_count, 1)
- def test_delete_all_calls_delete(self):
- stack = heat.HeatStack('test')
- stack.uuid = 1
- with mock.patch.object(stack, "delete") as delete_mock:
+ @mock.patch('yardstick.orchestrator.heat.op_utils')
+ def test_delete_all_calls_delete(self, mock_op):
+ # we must patch the object before we create an instance
+ # so we can override delete() in all the instances
+ with mock.patch.object(heat.HeatStack, "delete") as delete_mock:
+ stack = heat.HeatStack('test')
+ stack.uuid = 1
stack.delete_all()
- self.assertGreater(delete_mock.call_count, 0)
+ self.assertGreater(delete_mock.call_count, 0)
diff --git a/tests/unit/orchestrator/test_kubernetes.py b/tests/unit/orchestrator/test_kubernetes.py
new file mode 100644
index 000000000..51718ab86
--- /dev/null
+++ b/tests/unit/orchestrator/test_kubernetes.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+
+##############################################################################
+# Copyright (c) 2017 Intel Corporation
+#
+# 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
+##############################################################################
+
+# Unittest for yardstick.benchmark.orchestrator.heat
+import unittest
+import mock
+
+from yardstick.orchestrator.kubernetes import KubernetesObject
+from yardstick.orchestrator.kubernetes import KubernetesTemplate
+
+
+class GetTemplateTestCase(unittest.TestCase):
+
+ def test_get_template(self):
+ output_t = {
+ "apiVersion": "v1",
+ "kind": "ReplicationController",
+ "metadata": {
+ "name": "host-k8s-86096c30"
+ },
+ "spec": {
+ "replicas": 1,
+ "template": {
+ "metadata": {
+ "labels": {
+ "app": "host-k8s-86096c30"
+ }
+ },
+ "spec": {
+ "containers": [
+ {
+ "args": [
+ "-c",
+ "chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
+service ssh restart;while true ; do sleep 10000; done"
+ ],
+ "command": [
+ "/bin/bash"
+ ],
+ "image": "openretriever/yardstick",
+ "name": "host-k8s-86096c30-container",
+ "volumeMounts": [
+ {
+ "mountPath": "/root/.ssh/",
+ "name": "k8s-86096c30-key"
+ }
+ ]
+ }
+ ],
+ "volumes": [
+ {
+ "configMap": {
+ "name": "k8s-86096c30-key"
+ },
+ "name": "k8s-86096c30-key"
+ }
+ ]
+ }
+ }
+ }
+ }
+ input_s = {
+ 'command': '/bin/bash',
+ 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
+service ssh restart;while true ; do sleep 10000; done'],
+ 'ssh_key': 'k8s-86096c30-key'
+ }
+ name = 'host-k8s-86096c30'
+ output_r = KubernetesObject(name, **input_s).get_template()
+ self.assertEqual(output_r, output_t)
+
+
+class GetRcPodsTestCase(unittest.TestCase):
+
+ @mock.patch('yardstick.orchestrator.kubernetes.k8s_utils.get_pod_list')
+ def test_get_rc_pods(self, mock_get_pod_list):
+ servers = {
+ 'host': {
+ 'image': 'openretriever/yardstick',
+ 'command': '/bin/bash',
+ 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
+service ssh restart;while true ; do sleep 10000; done']
+ },
+ 'target': {
+ 'image': 'openretriever/yardstick',
+ 'command': '/bin/bash',
+ 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \
+service ssh restart;while true ; do sleep 10000; done']
+ }
+ }
+ k8s_template = KubernetesTemplate('k8s-86096c30', servers)
+ mock_get_pod_list.return_value.items = []
+ pods = k8s_template.get_rc_pods()
+ self.assertEqual(pods, [])
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/yardstick/benchmark/contexts/base.py b/yardstick/benchmark/contexts/base.py
index 0be2eee77..e362c6a3d 100644
--- a/yardstick/benchmark/contexts/base.py
+++ b/yardstick/benchmark/contexts/base.py
@@ -23,7 +23,7 @@ class Context(object):
@abc.abstractmethod
def init(self, attrs):
- "Initiate context."
+ """Initiate context."""
@staticmethod
def get_cls(context_type):
@@ -56,20 +56,34 @@ class Context(object):
"""get server info by name from context
"""
+ @abc.abstractmethod
+ def _get_network(self, attr_name):
+ """get network info by name from context
+ """
+
@staticmethod
def get_server(attr_name):
"""lookup server info by name from context
attr_name: either a name for a server created by yardstick or a dict
with attribute name mapping when using external heat templates
"""
- server = None
- for context in Context.list:
- server = context._get_server(attr_name)
- if server is not None:
- break
-
- if server is None:
+ servers = (context._get_server(attr_name) for context in Context.list)
+ try:
+ return next(s for s in servers if s)
+ except StopIteration:
raise ValueError("context not found for server '%r'" %
attr_name)
- return server
+ @staticmethod
+ def get_network(attr_name):
+ """lookup server info by name from context
+ attr_name: either a name for a server created by yardstick or a dict
+ with attribute name mapping when using external heat templates
+ """
+
+ networks = (context._get_network(attr_name) for context in Context.list)
+ try:
+ return next(n for n in networks if n)
+ except StopIteration:
+ raise ValueError("context not found for server '%r'" %
+ attr_name)
diff --git a/yardstick/benchmark/contexts/dummy.py b/yardstick/benchmark/contexts/dummy.py
index c658d3257..8ae4b65b8 100644
--- a/yardstick/benchmark/contexts/dummy.py
+++ b/yardstick/benchmark/contexts/dummy.py
@@ -37,3 +37,6 @@ class DummyContext(Context):
def _get_server(self, attr_name):
return None
+
+ def _get_network(self, attr_name):
+ return None
diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py
index fed8fc342..0a94dd976 100644
--- a/yardstick/benchmark/contexts/heat.py
+++ b/yardstick/benchmark/contexts/heat.py
@@ -25,6 +25,7 @@ from yardstick.benchmark.contexts.model import Network
from yardstick.benchmark.contexts.model import PlacementGroup, ServerGroup
from yardstick.benchmark.contexts.model import Server
from yardstick.benchmark.contexts.model import update_scheduler_hints
+from yardstick.common.openstack_utils import get_neutron_client
from yardstick.orchestrator.heat import HeatTemplate, get_short_key_uuid
from yardstick.common.constants import YARDSTICK_ROOT_PATH
@@ -54,9 +55,11 @@ class HeatContext(Context):
self._user = None
self.template_file = None
self.heat_parameters = None
+ self.neutron_client = None
# generate an uuid to identify yardstick_key
# the first 8 digits of the uuid will be used
self.key_uuid = uuid.uuid4()
+ self.heat_timeout = None
self.key_filename = ''.join(
[YARDSTICK_ROOT_PATH, 'yardstick/resources/files/yardstick_key-',
get_short_key_uuid(self.key_uuid)])
@@ -65,15 +68,16 @@ class HeatContext(Context):
def assign_external_network(self, networks):
sorted_networks = sorted(networks.items())
external_network = os.environ.get("EXTERNAL_NETWORK", "net04_ext")
- have_external_network = [(name, net)
- for name, net in sorted_networks if
- net.get("external_network")]
- # no external net defined, assign it to first network usig os.environ
+
+ have_external_network = any(net.get("external_network") for net in networks.values())
if sorted_networks and not have_external_network:
+ # no external net defined, assign it to first network using os.environ
sorted_networks[0][1]["external_network"] = external_network
- return sorted_networks
- def init(self, attrs): # pragma: no cover
+ self.networks = OrderedDict((name, Network(name, self, attrs))
+ for name, attrs in sorted_networks)
+
+ def init(self, attrs):
"""initializes itself from the supplied arguments"""
self.name = attrs["name"]
@@ -103,11 +107,7 @@ class HeatContext(Context):
# we have to do this first, because we are injecting external_network
# into the dict
- sorted_networks = self.assign_external_network(attrs["networks"])
-
- self.networks = OrderedDict(
- (name, Network(name, self, netattrs)) for name, netattrs in
- sorted_networks)
+ self.assign_external_network(attrs["networks"])
for name, serverattrs in sorted(attrs["servers"].items()):
server = Server(name, self, serverattrs)
@@ -120,7 +120,6 @@ class HeatContext(Context):
with open(self.key_filename + ".pub", "w") as pubkey_file:
pubkey_file.write(
"%s %s\n" % (rsa_key.get_name(), rsa_key.get_base64()))
- del rsa_key
@property
def image(self):
@@ -194,7 +193,7 @@ class HeatContext(Context):
scheduler_hints = {}
for pg in server.placement_groups:
update_scheduler_hints(scheduler_hints, added_servers, pg)
- # workround for openstack nova bug, check JIRA: YARDSTICK-200
+ # workaround for openstack nova bug, check JIRA: YARDSTICK-200
# for details
if len(availability_servers) == 2:
if not scheduler_hints["different_host"]:
@@ -250,6 +249,20 @@ class HeatContext(Context):
list(self.networks.values()),
scheduler_hints)
+ def get_neutron_info(self):
+ if not self.neutron_client:
+ self.neutron_client = get_neutron_client()
+
+ networks = self.neutron_client.list_networks()
+ for network in self.networks.values():
+ for neutron_net in networks['networks']:
+ if neutron_net['name'] == network.stack_name:
+ network.segmentation_id = neutron_net.get('provider:segmentation_id')
+ # we already have physical_network
+ # network.physical_network = neutron_net.get('provider:physical_network')
+ network.network_type = neutron_net.get('provider:network_type')
+ network.neutron_info = neutron_net
+
def deploy(self):
"""deploys template into a stack using cloud"""
print("Deploying context '%s'" % self.name)
@@ -267,20 +280,16 @@ class HeatContext(Context):
raise SystemExit("\nStack create interrupted")
except:
LOG.exception("stack failed")
+ # let the other failures happen, we want stack trace
raise
- # let the other failures happend, we want stack trace
+
+ # TODO: use Neutron to get segementation-id
+ self.get_neutron_info()
# copy some vital stack output into server objects
for server in self.servers:
if server.ports:
- # TODO(hafe) can only handle one internal network for now
- port = next(iter(server.ports.values()))
- server.private_ip = self.stack.outputs[port["stack_name"]]
- server.interfaces = {}
- for network_name, port in server.ports.items():
- self.make_interface_dict(network_name, port['stack_name'],
- server,
- self.stack.outputs)
+ self.add_server_port(server)
if server.floating_ip:
server.public_ip = \
@@ -288,24 +297,36 @@ class HeatContext(Context):
print("Context '%s' deployed" % self.name)
- def make_interface_dict(self, network_name, stack_name, server, outputs):
- server.interfaces[network_name] = {
- "private_ip": outputs[stack_name],
+ def add_server_port(self, server):
+ # TODO(hafe) can only handle one internal network for now
+ port = next(iter(server.ports.values()))
+ server.private_ip = self.stack.outputs[port["stack_name"]]
+ server.interfaces = {}
+ for network_name, port in server.ports.items():
+ server.interfaces[network_name] = self.make_interface_dict(
+ network_name, port['stack_name'], self.stack.outputs)
+
+ def make_interface_dict(self, network_name, stack_name, outputs):
+ private_ip = outputs[stack_name]
+ mac_addr = outputs[stack_name + "-mac_address"]
+ subnet_cidr_key = "-".join([self.name, network_name, 'subnet', 'cidr'])
+ gateway_key = "-".join([self.name, network_name, 'subnet', 'gateway_ip'])
+ subnet_cidr = outputs[subnet_cidr_key]
+ subnet_ip = ipaddress.ip_network(subnet_cidr)
+ return {
+ "private_ip": private_ip,
"subnet_id": outputs[stack_name + "-subnet_id"],
- "subnet_cidr": outputs[
- "{}-{}-subnet-cidr".format(self.name, network_name)],
- "netmask": str(ipaddress.ip_network(
- outputs["{}-{}-subnet-cidr".format(self.name,
- network_name)]).netmask),
- "gateway_ip": outputs[
- "{}-{}-subnet-gateway_ip".format(self.name, network_name)],
- "mac_address": outputs[stack_name + "-mac_address"],
+ "subnet_cidr": subnet_cidr,
+ "network": str(subnet_ip.network_address),
+ "netmask": str(subnet_ip.netmask),
+ "gateway_ip": outputs[gateway_key],
+ "mac_address": mac_addr,
"device_id": outputs[stack_name + "-device_id"],
"network_id": outputs[stack_name + "-network_id"],
"network_name": network_name,
# to match vnf_generic
- "local_mac": outputs[stack_name + "-mac_address"],
- "local_ip": outputs[stack_name],
+ "local_mac": mac_addr,
+ "local_ip": private_ip,
"vld_id": self.networks[network_name].vld_id,
}
@@ -326,6 +347,19 @@ class HeatContext(Context):
super(HeatContext, self).undeploy()
+ @staticmethod
+ def generate_routing_table(server):
+ routes = [
+ {
+ "network": intf["network"],
+ "netmask": intf["netmask"],
+ "if": name,
+ "gateway": intf["gateway_ip"],
+ }
+ for name, intf in server.interfaces.items()
+ ]
+ return routes
+
def _get_server(self, attr_name):
"""lookup server info by name from context
attr_name: either a name for a server created by yardstick or a dict
@@ -335,7 +369,10 @@ class HeatContext(Context):
'yardstick.resources',
'files/yardstick_key-' + get_short_key_uuid(self.key_uuid))
- if isinstance(attr_name, collections.Mapping):
+ if not isinstance(attr_name, collections.Mapping):
+ server = self._server_map.get(attr_name, None)
+
+ else:
cname = attr_name["name"].split(".")[1]
if cname != self.name:
return None
@@ -352,10 +389,6 @@ class HeatContext(Context):
server = Server(attr_name["name"].split(".")[0], self, {})
server.public_ip = public_ip
server.private_ip = private_ip
- else:
- if attr_name not in self._server_map:
- return None
- server = self._server_map[attr_name]
if server is None:
return None
@@ -365,9 +398,37 @@ class HeatContext(Context):
"key_filename": key_filename,
"private_ip": server.private_ip,
"interfaces": server.interfaces,
+ "routing_table": self.generate_routing_table(server),
+ # empty IPv6 routing table
+ "nd_route_tbl": [],
}
# Target server may only have private_ip
if server.public_ip:
result["ip"] = server.public_ip
return result
+
+ def _get_network(self, attr_name):
+ if not isinstance(attr_name, collections.Mapping):
+ network = self.networks.get(attr_name, None)
+
+ else:
+ # Don't generalize too much Just support vld_id
+ vld_id = attr_name.get('vld_id')
+ if vld_id is None:
+ return None
+
+ network = next((n for n in self.networks.values() if
+ getattr(n, "vld_id", None) == vld_id), None)
+
+ if network is None:
+ return None
+
+ result = {
+ "name": network.name,
+ "vld_id": network.vld_id,
+ "segmentation_id": network.segmentation_id,
+ "network_type": network.network_type,
+ "physical_network": network.physical_network,
+ }
+ return result
diff --git a/yardstick/benchmark/contexts/kubernetes.py b/yardstick/benchmark/contexts/kubernetes.py
new file mode 100644
index 000000000..a39f63137
--- /dev/null
+++ b/yardstick/benchmark/contexts/kubernetes.py
@@ -0,0 +1,140 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd.
+#
+# 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
+##############################################################################
+
+from __future__ import absolute_import
+import logging
+import time
+import pkg_resources
+
+import paramiko
+
+from yardstick.benchmark.contexts.base import Context
+from yardstick.orchestrator.kubernetes import KubernetesTemplate
+from yardstick.common import kubernetes_utils as k8s_utils
+from yardstick.common import utils
+
+LOG = logging.getLogger(__name__)
+BITS_LENGTH = 2048
+
+
+class KubernetesContext(Context):
+ """Class that handle nodes info"""
+
+ __context_type__ = "Kubernetes"
+
+ def __init__(self):
+ self.name = ''
+ self.ssh_key = ''
+ self.key_path = ''
+ self.public_key_path = ''
+ self.template = None
+
+ super(KubernetesContext, self).__init__()
+
+ def init(self, attrs):
+ self.name = attrs.get('name', '')
+
+ template_cfg = attrs.get('servers', {})
+ self.template = KubernetesTemplate(self.name, template_cfg)
+
+ self.ssh_key = '{}-key'.format(self.name)
+
+ self.key_path = self._get_key_path()
+ self.public_key_path = '{}.pub'.format(self.key_path)
+
+ def deploy(self):
+ LOG.info('Creating ssh key')
+ self._set_ssh_key()
+
+ LOG.info('Launch containers')
+ self._create_rcs()
+ time.sleep(1)
+ self.template.get_rc_pods()
+
+ self._wait_until_running()
+
+ def undeploy(self):
+ self._delete_ssh_key()
+ self._delete_rcs()
+ self._delete_pods()
+
+ super(KubernetesContext, self).undeploy()
+
+ def _wait_until_running(self):
+ while not all(self._check_pod_status(p) for p in self.template.pods):
+ time.sleep(1)
+
+ def _check_pod_status(self, pod):
+ status = k8s_utils.read_pod_status(pod)
+ LOG.debug('%s:%s', pod, status)
+ if status == 'Failed':
+ LOG.error('Pod %s status is failed', pod)
+ raise RuntimeError
+ if status != 'Running':
+ return False
+ return True
+
+ def _create_rcs(self):
+ for obj in self.template.k8s_objs:
+ self._create_rc(obj.get_template())
+
+ def _create_rc(self, template):
+ k8s_utils.create_replication_controller(template)
+
+ def _delete_rcs(self):
+ for rc in self.template.rcs:
+ self._delete_rc(rc)
+
+ def _delete_rc(self, rc):
+ k8s_utils.delete_replication_controller(rc)
+
+ def _delete_pods(self):
+ for pod in self.template.pods:
+ self._delete_pod(pod)
+
+ def _delete_pod(self, pod):
+ k8s_utils.delete_pod(pod)
+
+ def _get_key_path(self):
+ task_id = self.name.split('-')[-1]
+ k = 'files/yardstick_key-{}'.format(task_id)
+ return pkg_resources.resource_filename('yardstick.resources', k)
+
+ def _set_ssh_key(self):
+ rsa_key = paramiko.RSAKey.generate(bits=BITS_LENGTH)
+
+ LOG.info('Writing private key')
+ rsa_key.write_private_key_file(self.key_path)
+
+ LOG.info('Writing public key')
+ key = '{} {}\n'.format(rsa_key.get_name(), rsa_key.get_base64())
+ with open(self.public_key_path, 'w') as f:
+ f.write(key)
+
+ LOG.info('Create configmap for ssh key')
+ k8s_utils.create_config_map(self.ssh_key, {'authorized_keys': key})
+
+ def _delete_ssh_key(self):
+ k8s_utils.delete_config_map(self.ssh_key)
+ utils.remove_file(self.key_path)
+ utils.remove_file(self.public_key_path)
+
+ def _get_server(self, name):
+ resp = k8s_utils.get_pod_list()
+ hosts = ({'name': n.metadata.name,
+ 'ip': n.status.pod_ip,
+ 'user': 'root',
+ 'key_filename': self.key_path,
+ 'private_ip': n.status.pod_ip}
+ for n in resp.items if n.metadata.name.startswith(name))
+
+ return next(hosts, None)
+
+ def _get_network(self, attr_name):
+ return None
diff --git a/yardstick/benchmark/contexts/model.py b/yardstick/benchmark/contexts/model.py
index 5077a9786..06538d8a9 100644
--- a/yardstick/benchmark/contexts/model.py
+++ b/yardstick/benchmark/contexts/model.py
@@ -106,13 +106,14 @@ class Network(Object):
self.subnet_cidr = attrs.get('cidr', '10.0.1.0/24')
self.router = None
self.physical_network = attrs.get('physical_network', 'physnet1')
- self.provider = attrs.get('provider', None)
- self.segmentation_id = attrs.get('segmentation_id', None)
+ self.provider = attrs.get('provider')
+ self.segmentation_id = attrs.get('segmentation_id')
+ self.network_type = attrs.get('network_type')
if "external_network" in attrs:
self.router = Router("router", self.name,
context, attrs["external_network"])
- self.vld_id = attrs.get("vld_id", "")
+ self.vld_id = attrs.get("vld_id")
Network.list.append(self)
diff --git a/yardstick/benchmark/contexts/node.py b/yardstick/benchmark/contexts/node.py
index baa1cf5d6..b3f0aca0e 100644
--- a/yardstick/benchmark/contexts/node.py
+++ b/yardstick/benchmark/contexts/node.py
@@ -33,6 +33,7 @@ class NodeContext(Context):
self.name = None
self.file_path = None
self.nodes = []
+ self.networks = {}
self.controllers = []
self.computes = []
self.baremetals = []
@@ -77,6 +78,9 @@ class NodeContext(Context):
self.env = attrs.get('env', {})
LOG.debug("Env: %r", self.env)
+ # add optional static network definition
+ self.networks.update(cfg.get("networks", {}))
+
def deploy(self):
config_type = self.env.get('type', '')
if config_type == 'ansible':
@@ -141,6 +145,32 @@ class NodeContext(Context):
node["name"] = attr_name
return node
+ def _get_network(self, attr_name):
+ if not isinstance(attr_name, collections.Mapping):
+ network = self.networks.get(attr_name)
+
+ else:
+ # Don't generalize too much Just support vld_id
+ vld_id = attr_name.get('vld_id')
+ if vld_id is None:
+ return None
+
+ network = next((n for n in self.networks.values() if
+ n.get("vld_id") == vld_id), None)
+
+ if network is None:
+ return None
+
+ result = {
+ # name is required
+ "name": network["name"],
+ "vld_id": network.get("vld_id"),
+ "segmentation_id": network.get("segmentation_id"),
+ "network_type": network.get("network_type"),
+ "physical_network": network.get("physical_network"),
+ }
+ return result
+
def _execute_script(self, node_name, info):
if node_name == 'local':
self._execute_local_script(info)
diff --git a/yardstick/benchmark/contexts/standalone.py b/yardstick/benchmark/contexts/standalone.py
index 78eaac7ee..8614f0cac 100644
--- a/yardstick/benchmark/contexts/standalone.py
+++ b/yardstick/benchmark/contexts/standalone.py
@@ -36,6 +36,7 @@ class StandaloneContext(Context):
self.name = None
self.file_path = None
self.nodes = []
+ self.networks = {}
self.nfvi_node = []
super(StandaloneContext, self).__init__()
@@ -66,8 +67,11 @@ class StandaloneContext(Context):
self.nodes.extend(cfg["nodes"])
self.nfvi_node.extend([node for node in cfg["nodes"]
if node["role"] == "nfvi_node"])
+ # add optional static network definition
+ self.networks.update(cfg.get("networks", {}))
LOG.debug("Nodes: %r", self.nodes)
LOG.debug("NFVi Node: %r", self.nfvi_node)
+ LOG.debug("Networks: %r", self.networks)
def deploy(self):
"""don't need to deploy"""
@@ -114,3 +118,31 @@ class StandaloneContext(Context):
node["name"] = attr_name
return node
+
+ def _get_network(self, attr_name):
+ if not isinstance(attr_name, collections.Mapping):
+ network = self.networks.get(attr_name)
+
+ else:
+ # Don't generalize too much Just support vld_id
+ vld_id = attr_name.get('vld_id')
+ if vld_id is None:
+ return None
+ try:
+ network = next(n for n in self.networks.values() if
+ n.get("vld_id") == vld_id)
+ except StopIteration:
+ return None
+
+ if network is None:
+ return None
+
+ result = {
+ # name is required
+ "name": network["name"],
+ "vld_id": network.get("vld_id"),
+ "segmentation_id": network.get("segmentation_id"),
+ "network_type": network.get("network_type"),
+ "physical_network": network.get("physical_network"),
+ }
+ return result
diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py
index 0e85e6316..b53d6446e 100644
--- a/yardstick/benchmark/core/task.py
+++ b/yardstick/benchmark/core/task.py
@@ -322,6 +322,8 @@ class Task(object): # pragma: no cover
if "nodes" in scenario_cfg:
context_cfg["nodes"] = parse_nodes_with_context(scenario_cfg)
+ context_cfg["networks"] = get_networks_from_nodes(
+ context_cfg["nodes"])
runner = base_runner.Runner.get(runner_cfg)
print("Starting runner of type '%s'" % runner_cfg["type"])
@@ -518,7 +520,7 @@ class TaskParser(object): # pragma: no cover
cfg_schema))
def _check_precondition(self, cfg):
- """Check if the envrionment meet the preconditon"""
+ """Check if the environment meet the precondition"""
if "precondition" in cfg:
precondition = cfg["precondition"]
@@ -573,14 +575,26 @@ def _is_background_scenario(scenario):
def parse_nodes_with_context(scenario_cfg):
- """paras the 'nodes' fields in scenario """
+ """parse the 'nodes' fields in scenario """
nodes = scenario_cfg["nodes"]
-
- nodes_cfg = {}
- for nodename in nodes:
- nodes_cfg[nodename] = Context.get_server(nodes[nodename])
-
- return nodes_cfg
+ return {nodename: Context.get_server(node) for nodename, node in nodes.items()}
+
+
+def get_networks_from_nodes(nodes):
+ """parse the 'nodes' fields in scenario """
+ networks = {}
+ for node in nodes.values():
+ if not node:
+ continue
+ for interface in node['interfaces'].values():
+ vld_id = interface.get('vld_id')
+ # mgmt network doesn't have vld_id
+ if not vld_id:
+ continue
+ network = Context.get_network({"vld_id": vld_id})
+ if network:
+ networks[network['name']] = network
+ return networks
def runner_join(runner):
diff --git a/yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py b/yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py
index 22de0b645..50d44c1ca 100644
--- a/yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py
+++ b/yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py
@@ -9,7 +9,6 @@
from __future__ import absolute_import
import logging
import subprocess
-import traceback
import yardstick.ssh as ssh
from yardstick.benchmark.scenarios.availability.attacker.baseattacker import \
@@ -26,9 +25,7 @@ def _execute_shell_command(command, stdin=None):
output = subprocess.check_output(command, stdin=stdin, shell=True)
except Exception:
exitcode = -1
- output = traceback.format_exc()
- LOG.error("exec command '%s' error:\n ", command)
- LOG.error(traceback.format_exc())
+ LOG.error("exec command '%s' error:\n ", command, exc_info=True)
return exitcode, output
diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py
index 594edeaa8..9607e3005 100644
--- a/yardstick/benchmark/scenarios/networking/vnf_generic.py
+++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py
@@ -164,38 +164,60 @@ class NetworkServiceTestCase(base.Scenario):
for vnfd in topology["constituent-vnfd"]
if vnf_id == vnfd["member-vnf-index"]), None)
+ @staticmethod
+ def get_vld_networks(networks):
+ return {n['vld_id']: n for n in networks.values()}
+
def _resolve_topology(self, context_cfg, topology):
for vld in topology["vld"]:
- if len(vld["vnfd-connection-point-ref"]) > 2:
+ try:
+ node_0, node_1 = vld["vnfd-connection-point-ref"]
+ except (TypeError, ValueError):
raise IncorrectConfig("Topology file corrupted, "
- "too many endpoint for connection")
-
- node_0, node_1 = vld["vnfd-connection-point-ref"]
+ "wrong number of endpoints for connection")
- node0 = self._find_vnf_name_from_id(topology,
- node_0["member-vnf-index-ref"])
- node1 = self._find_vnf_name_from_id(topology,
- node_1["member-vnf-index-ref"])
+ node_0_name = self._find_vnf_name_from_id(topology,
+ node_0["member-vnf-index-ref"])
+ node_1_name = self._find_vnf_name_from_id(topology,
+ node_1["member-vnf-index-ref"])
- if0 = node_0["vnfd-connection-point-ref"]
- if1 = node_1["vnfd-connection-point-ref"]
+ node_0_ifname = node_0["vnfd-connection-point-ref"]
+ node_1_ifname = node_1["vnfd-connection-point-ref"]
+ node_0_if = context_cfg["nodes"][node_0_name]["interfaces"][node_0_ifname]
+ node_1_if = context_cfg["nodes"][node_1_name]["interfaces"][node_1_ifname]
try:
- nodes = context_cfg["nodes"]
- nodes[node0]["interfaces"][if0]["vld_id"] = vld["id"]
- nodes[node1]["interfaces"][if1]["vld_id"] = vld["id"]
-
- nodes[node0]["interfaces"][if0]["dst_mac"] = \
- nodes[node1]["interfaces"][if1]["local_mac"]
- nodes[node0]["interfaces"][if0]["dst_ip"] = \
- nodes[node1]["interfaces"][if1]["local_ip"]
-
- nodes[node1]["interfaces"][if1]["dst_mac"] = \
- nodes[node0]["interfaces"][if0]["local_mac"]
- nodes[node1]["interfaces"][if1]["dst_ip"] = \
- nodes[node0]["interfaces"][if0]["local_ip"]
+ vld_networks = self.get_vld_networks(context_cfg["networks"])
+
+ node_0_if["vld_id"] = vld["id"]
+ node_1_if["vld_id"] = vld["id"]
+
+ # set peer name
+ node_0_if["peer_name"] = node_1_name
+ node_1_if["peer_name"] = node_0_name
+
+ # set peer interface name
+ node_0_if["peer_ifname"] = node_1_ifname
+ node_1_if["peer_ifname"] = node_0_ifname
+
+ # just load the whole network dict
+ node_0_if["network"] = vld_networks.get(vld["id"], {})
+ node_1_if["network"] = vld_networks.get(vld["id"], {})
+
+ node_0_if["dst_mac"] = node_1_if["local_mac"]
+ node_0_if["dst_ip"] = node_1_if["local_ip"]
+
+ node_1_if["dst_mac"] = node_0_if["local_mac"]
+ node_1_if["dst_ip"] = node_0_if["local_ip"]
+
+ # add peer interface dict, but remove circular link
+ # TODO: don't waste memory
+ node_0_copy = node_0_if.copy()
+ node_1_copy = node_1_if.copy()
+ node_0_if["peer_intf"] = node_1_copy
+ node_1_if["peer_intf"] = node_0_copy
except KeyError:
- raise IncorrectConfig("Required interface not found,"
+ raise IncorrectConfig("Required interface not found, "
"topology file corrupted")
@classmethod
@@ -308,21 +330,36 @@ printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \
return dict(network_devices)
@classmethod
- def get_vnf_impl(cls, vnf_model):
+ def get_vnf_impl(cls, vnf_model_id):
""" Find the implementing class from vnf_model["vnf"]["name"] field
- :param vnf_model: dictionary containing a parsed vnfd
+ :param vnf_model_id: parsed vnfd model ID field
:return: subclass of GenericVNF
"""
import_modules_from_package(
"yardstick.network_services.vnf_generic.vnf")
- expected_name = vnf_model['id']
- impl = (c for c in itersubclasses(GenericVNF)
- if c.__name__ == expected_name)
+ expected_name = vnf_model_id
+ classes_found = []
+
+ def impl():
+ for name, class_ in ((c.__name__, c) for c in itersubclasses(GenericVNF)):
+ if name == expected_name:
+ yield class_
+ classes_found.append(name)
+
try:
- return next(impl)
+ return next(impl())
except StopIteration:
- raise IncorrectConfig("No implementation for %s", expected_name)
+ pass
+
+ raise IncorrectConfig("No implementation for %s found in %s" %
+ (expected_name, classes_found))
+
+ @staticmethod
+ def update_interfaces_from_node(vnfd, node):
+ for intf in vnfd["vdu"][0]["external-interface"]:
+ node_intf = node['interfaces'][intf['name']]
+ intf['virtual-interface'].update(node_intf)
def load_vnf_models(self, scenario_cfg, context_cfg):
""" Create VNF objects based on YAML descriptors
@@ -339,8 +376,11 @@ printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \
scenario_cfg['task_path']) as stream:
vnf_model = stream.read()
vnfd = vnfdgen.generate_vnfd(vnf_model, node)
- vnf_impl = self.get_vnf_impl(vnfd["vnfd:vnfd-catalog"]["vnfd"][0])
- vnf_instance = vnf_impl(vnfd["vnfd:vnfd-catalog"]["vnfd"][0])
+ # TODO: here add extra context_cfg["nodes"] regardless of template
+ vnfd = vnfd["vnfd:vnfd-catalog"]["vnfd"][0]
+ self.update_interfaces_from_node(vnfd, node)
+ vnf_impl = self.get_vnf_impl(vnfd['id'])
+ vnf_instance = vnf_impl(vnfd)
vnf_instance.name = node_name
vnfs.append(vnf_instance)
diff --git a/yardstick/common/constants.py b/yardstick/common/constants.py
index 5cd34ba53..69485a4e4 100644
--- a/yardstick/common/constants.py
+++ b/yardstick/common/constants.py
@@ -56,6 +56,7 @@ ETC_HOSTS = get_param('file.etc_hosts', '/etc/hosts')
CONF_FILE = join(CONF_DIR, 'yardstick.conf')
POD_FILE = join(CONF_DIR, 'pod.yaml')
CLOUDS_CONF = join(OPENSTACK_CONF_DIR, 'clouds.yml')
+K8S_CONF_FILE = join(CONF_DIR, 'admin.conf')
CONF_SAMPLE_FILE = join(CONF_SAMPLE_DIR, 'yardstick.conf.sample')
FETCH_SCRIPT = get_param('file.fetch_script', 'utils/fetch_os_creds.sh')
FETCH_SCRIPT = join(RELENG_DIR, FETCH_SCRIPT)
diff --git a/yardstick/common/kubernetes_utils.py b/yardstick/common/kubernetes_utils.py
new file mode 100644
index 000000000..e4c232830
--- /dev/null
+++ b/yardstick/common/kubernetes_utils.py
@@ -0,0 +1,137 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd.
+#
+# 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
+##############################################################################
+import logging
+
+from kubernetes import client
+from kubernetes import config
+from kubernetes.client.rest import ApiException
+
+from yardstick.common import constants as consts
+
+LOG = logging.getLogger(__name__)
+LOG.setLevel(logging.DEBUG)
+
+
+def get_core_api(): # pragma: no cover
+ try:
+ config.load_kube_config(config_file=consts.K8S_CONF_FILE)
+ except IOError:
+ LOG.exception('config file not found')
+ raise
+
+ return client.CoreV1Api()
+
+
+def create_replication_controller(template,
+ namespace='default',
+ wait=False,
+ **kwargs): # pragma: no cover
+
+ core_v1_api = get_core_api()
+ try:
+ core_v1_api.create_namespaced_replication_controller(namespace,
+ template,
+ **kwargs)
+ except ApiException:
+ LOG.exception('Create replication controller failed')
+ raise
+
+
+def delete_replication_controller(name,
+ namespace='default',
+ wait=False,
+ **kwargs): # pragma: no cover
+
+ core_v1_api = get_core_api()
+ body = kwargs.get('body', client.V1DeleteOptions())
+ kwargs.pop('body', None)
+ try:
+ core_v1_api.delete_namespaced_replication_controller(name,
+ namespace,
+ body,
+ **kwargs)
+ except ApiException:
+ LOG.exception('Delete replication controller failed')
+ raise
+
+
+def delete_pod(name,
+ namespace='default',
+ wait=False,
+ **kwargs): # pragma: no cover
+
+ core_v1_api = get_core_api()
+ body = kwargs.get('body', client.V1DeleteOptions())
+ kwargs.pop('body', None)
+ try:
+ core_v1_api.delete_namespaced_pod(name,
+ namespace,
+ body,
+ **kwargs)
+ except ApiException:
+ LOG.exception('Delete pod failed')
+ raise
+
+
+def read_pod(name,
+ namespace='default',
+ **kwargs): # pragma: no cover
+ core_v1_api = get_core_api()
+ try:
+ resp = core_v1_api.read_namespaced_pod(name, namespace, **kwargs)
+ except ApiException:
+ LOG.exception('Read pod failed')
+ raise
+ else:
+ return resp
+
+
+def read_pod_status(name, namespace='default', **kwargs): # pragma: no cover
+ return read_pod(name).status.phase
+
+
+def create_config_map(name,
+ data,
+ namespace='default',
+ wait=False,
+ **kwargs): # pragma: no cover
+ core_v1_api = get_core_api()
+ metadata = client.V1ObjectMeta(name=name)
+ body = client.V1ConfigMap(data=data, metadata=metadata)
+ try:
+ core_v1_api.create_namespaced_config_map(namespace, body, **kwargs)
+ except ApiException:
+ LOG.exception('Create config map failed')
+ raise
+
+
+def delete_config_map(name,
+ namespace='default',
+ wait=False,
+ **kwargs): # pragma: no cover
+ core_v1_api = get_core_api()
+ body = kwargs.get('body', client.V1DeleteOptions())
+ kwargs.pop('body', None)
+ try:
+ core_v1_api.delete_namespaced_config_map(name,
+ namespace,
+ body,
+ **kwargs)
+ except ApiException:
+ LOG.exception('Delete config map failed')
+ raise
+
+
+def get_pod_list(namespace='default'): # pragma: no cover
+ core_v1_api = get_core_api()
+ try:
+ return core_v1_api.list_namespaced_pod(namespace=namespace)
+ except ApiException:
+ LOG.exception('Get pod list failed')
+ raise
diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py
index 0c0bac934..a4f7b30dc 100644
--- a/yardstick/common/utils.py
+++ b/yardstick/common/utils.py
@@ -124,6 +124,14 @@ def makedirs(d):
raise
+def remove_file(path):
+ try:
+ os.remove(path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+
+
def execute_command(cmd):
exec_msg = "Executing command: '%s'" % cmd
logger.debug(exec_msg)
@@ -242,3 +250,16 @@ def change_obj_to_dict(obj):
except TypeError:
dic.update({k: v})
return dic
+
+
+def set_dict_value(dic, keys, value):
+ return_dic = dic
+
+ for key in keys.split('.'):
+
+ return_dic.setdefault(key, {})
+ if key == keys.split('.')[-1]:
+ return_dic[key] = value
+ else:
+ return_dic = return_dic[key]
+ return dic
diff --git a/yardstick/orchestrator/heat.py b/yardstick/orchestrator/heat.py
index 7958b1cfb..2a907d124 100644
--- a/yardstick/orchestrator/heat.py
+++ b/yardstick/orchestrator/heat.py
@@ -534,6 +534,7 @@ name (i.e. %s).\
}
HEAT_WAIT_LOOP_INTERVAL = 2
+ HEAT_CREATE_COMPLETE_STATUS = u'CREATE_COMPLETE'
def create(self, block=True, timeout=3600):
"""
@@ -558,10 +559,13 @@ name (i.e. %s).\
if not block:
self.outputs = stack.outputs = {}
+ end_time = time.time()
+ log.info("Created stack '%s' in %.3e secs",
+ self.name, end_time - start_time)
return stack
time_limit = start_time + timeout
- for status in iter(self.status, u'CREATE_COMPLETE'):
+ for status in iter(self.status, self.HEAT_CREATE_COMPLETE_STATUS):
log.debug("stack state %s", status)
if status == u'CREATE_FAILED':
stack_status_reason = heat_client.stacks.get(self.uuid).stack_status_reason
@@ -574,7 +578,7 @@ name (i.e. %s).\
end_time = time.time()
outputs = heat_client.stacks.get(self.uuid).outputs
- log.info("Created stack '%s' in %d secs",
+ log.info("Created stack '%s' in %.3e secs",
self.name, end_time - start_time)
# keep outputs as unicode
diff --git a/yardstick/orchestrator/kubernetes.py b/yardstick/orchestrator/kubernetes.py
new file mode 100644
index 000000000..6d7045f58
--- /dev/null
+++ b/yardstick/orchestrator/kubernetes.py
@@ -0,0 +1,130 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd.
+#
+# 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
+##############################################################################
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+from yardstick.common import utils
+from yardstick.common import kubernetes_utils as k8s_utils
+
+
+class KubernetesObject(object):
+
+ def __init__(self, name, **kwargs):
+ super(KubernetesObject, self).__init__()
+ self.name = name
+ self.image = kwargs.get('image', 'openretriever/yardstick')
+ self.command = [kwargs.get('command', '/bin/bash')]
+ self.args = kwargs.get('args', [])
+ self.ssh_key = kwargs.get('ssh_key', 'yardstick_key')
+
+ self.volumes = []
+
+ self.template = {
+ "apiVersion": "v1",
+ "kind": "ReplicationController",
+ "metadata": {
+ "name": ""
+ },
+ "spec": {
+ "replicas": 1,
+ "template": {
+ "metadata": {
+ "labels": {
+ "app": ""
+ }
+ },
+ "spec": {
+ "containers": [],
+ "volumes": []
+ }
+ }
+ }
+ }
+
+ self._change_value_according_name(name)
+ self._add_containers()
+ self._add_ssh_key_volume()
+ self._add_volumes()
+
+ def get_template(self):
+ return self.template
+
+ def _change_value_according_name(self, name):
+ utils.set_dict_value(self.template, 'metadata.name', name)
+
+ utils.set_dict_value(self.template,
+ 'spec.template.metadata.labels.app',
+ name)
+
+ def _add_containers(self):
+ containers = [self._add_container()]
+ utils.set_dict_value(self.template,
+ 'spec.template.spec.containers',
+ containers)
+
+ def _add_container(self):
+ container_name = '{}-container'.format(self.name)
+ ssh_key_mount_path = "/root/.ssh/"
+
+ container = {
+ "args": self.args,
+ "command": self.command,
+ "image": self.image,
+ "name": container_name,
+ "volumeMounts": [
+ {
+ "mountPath": ssh_key_mount_path,
+ "name": self.ssh_key
+ }
+ ]
+ }
+
+ return container
+
+ def _add_volumes(self):
+ utils.set_dict_value(self.template,
+ 'spec.template.spec.volumes',
+ self.volumes)
+
+ def _add_volume(self, volume):
+ self.volumes.append(volume)
+
+ def _add_ssh_key_volume(self):
+ key_volume = {
+ "configMap": {
+ "name": self.ssh_key
+ },
+ "name": self.ssh_key
+ }
+ self._add_volume(key_volume)
+
+
+class KubernetesTemplate(object):
+
+ def __init__(self, name, template_cfg):
+ self.name = name
+ self.ssh_key = '{}-key'.format(name)
+
+ self.rcs = [self._get_rc_name(rc) for rc in template_cfg]
+ self.k8s_objs = [KubernetesObject(self._get_rc_name(rc),
+ ssh_key=self.ssh_key,
+ **cfg)
+ for rc, cfg in template_cfg.items()]
+ self.pods = []
+
+ def _get_rc_name(self, rc_name):
+ return '{}-{}'.format(rc_name, self.name)
+
+ def get_rc_pods(self):
+ resp = k8s_utils.get_pod_list()
+ self.pods = [p.metadata.name for p in resp.items for s in self.rcs
+ if p.metadata.name.startswith(s)]
+
+ return self.pods
diff --git a/yardstick/vTC/apexlake/tests/deployment_unit_test.py b/yardstick/vTC/apexlake/tests/deployment_unit_test.py
index 5a9178f53..1ff4225d6 100644
--- a/yardstick/vTC/apexlake/tests/deployment_unit_test.py
+++ b/yardstick/vTC/apexlake/tests/deployment_unit_test.py
@@ -130,6 +130,7 @@ class DummyDeploymentUnit(mut.DeploymentUnit):
raise Exception
+@mock.patch("experimental_framework.deployment_unit.time")
class TestDeploymentUnit(unittest.TestCase):
def setUp(self):
@@ -140,7 +141,7 @@ class TestDeploymentUnit(unittest.TestCase):
@mock.patch('experimental_framework.heat_manager.HeatManager',
side_effect=DummyHeatManager)
- def test_constructor_for_sanity(self, mock_heat_manager):
+ def test_constructor_for_sanity(self, mock_heat_manager, mock_time):
du = mut.DeploymentUnit(dict())
self.assertTrue(isinstance(du.heat_manager, DummyHeatManager))
mock_heat_manager.assert_called_once_with(dict())
@@ -150,7 +151,7 @@ class TestDeploymentUnit(unittest.TestCase):
side_effect=DummyHeatManager)
@mock.patch('os.path.isfile')
def test_deploy_heat_template_for_failure(self, mock_os_is_file,
- mock_heat_manager):
+ mock_heat_manager, mock_time):
mock_os_is_file.return_value = False
du = mut.DeploymentUnit(dict())
template_file = ''
@@ -163,7 +164,7 @@ class TestDeploymentUnit(unittest.TestCase):
side_effect=DummyHeatManager)
@mock.patch('os.path.isfile')
def test_deploy_heat_template_for_success(self, mock_os_is_file,
- mock_heat_manager):
+ mock_heat_manager, mock_time):
mock_os_is_file.return_value = True
du = mut.DeploymentUnit(dict())
template_file = ''
@@ -178,7 +179,7 @@ class TestDeploymentUnit(unittest.TestCase):
side_effect=DummyHeatManagerComplete)
@mock.patch('os.path.isfile')
def test_deploy_heat_template_2_for_success(self, mock_os_is_file,
- mock_heat_manager):
+ mock_heat_manager, mock_time):
mock_os_is_file.return_value = True
du = mut.DeploymentUnit(dict())
template_file = ''
@@ -196,7 +197,7 @@ class TestDeploymentUnit(unittest.TestCase):
side_effect=DummyDeploymentUnit)
def test_deploy_heat_template_3_for_success(self, mock_dep_unit,
mock_os_is_file,
- mock_heat_manager):
+ mock_heat_manager, mock_time):
mock_os_is_file.return_value = True
du = mut.DeploymentUnit(dict())
template_file = ''
@@ -212,7 +213,7 @@ class TestDeploymentUnit(unittest.TestCase):
side_effect=DummyHeatManagerFailed)
@mock.patch('os.path.isfile')
def test_deploy_heat_template_for_success_2(self, mock_os_is_file,
- mock_heat_manager, mock_log):
+ mock_heat_manager, mock_log, mock_time):
mock_os_is_file.return_value = True
du = DummyDeploymentUnit(dict())
template_file = ''
@@ -226,7 +227,7 @@ class TestDeploymentUnit(unittest.TestCase):
side_effect=DummyHeatManagerDestroy)
@mock.patch('experimental_framework.common.LOG')
def test_destroy_heat_template_for_success(self, mock_log,
- mock_heat_manager):
+ mock_heat_manager, mock_time):
openstack_credentials = dict()
du = mut.DeploymentUnit(openstack_credentials)
du.deployed_stacks = ['stack']
@@ -238,14 +239,14 @@ class TestDeploymentUnit(unittest.TestCase):
side_effect=DummyHeatManagerDestroyException)
@mock.patch('experimental_framework.common.LOG')
def test_destroy_heat_template_for_success_2(self, mock_log,
- mock_heat_manager):
+ mock_heat_manager, mock_time):
openstack_credentials = dict()
du = mut.DeploymentUnit(openstack_credentials)
du.deployed_stacks = ['stack']
stack_name = 'stack'
self.assertFalse(du.destroy_heat_template(stack_name))
- def test_destroy_all_deployed_stacks_for_success(self):
+ def test_destroy_all_deployed_stacks_for_success(self, mock_time):
du = DeploymentUnitDestroy()
du.destroy_all_deployed_stacks()
self.assertTrue(du.destroy_heat_template())
@@ -254,7 +255,7 @@ class TestDeploymentUnit(unittest.TestCase):
side_effect=DummyHeatManagerReiteration)
@mock.patch('os.path.isfile')
def test_deploy_heat_template_for_success_3(self, mock_os_is_file,
- mock_heat_manager):
+ mock_heat_manager, mock_time):
mock_os_is_file.return_value = True
du = mut.DeploymentUnit(dict())
template = 'template_reiteration'
diff --git a/yardstick/vTC/apexlake/tests/dpdk_packet_generator_test.py b/yardstick/vTC/apexlake/tests/dpdk_packet_generator_test.py
index 96ead5ef7..9fa860ab4 100644
--- a/yardstick/vTC/apexlake/tests/dpdk_packet_generator_test.py
+++ b/yardstick/vTC/apexlake/tests/dpdk_packet_generator_test.py
@@ -359,6 +359,7 @@ class MockRunCommand:
return MockRunCommand.ret_val_finalization
+@mock.patch('experimental_framework.packet_generators.dpdk_packet_generator.time')
class TestDpdkPacketGenOthers(unittest.TestCase):
def setUp(self):
@@ -370,7 +371,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
@mock.patch('experimental_framework.packet_generators.'
'dpdk_packet_generator.DpdkPacketGenerator.'
'_cores_configuration')
- def test__get_core_nics_for_failure(self, mock_cores_configuration):
+ def test__get_core_nics_for_failure(self, mock_cores_configuration, mock_time):
mock_cores_configuration.return_value = None
self.assertRaises(ValueError, mut.DpdkPacketGenerator._get_core_nics,
'', '')
@@ -379,7 +380,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
'dpdk_packet_generator.DpdkPacketGenerator.'
'_cores_configuration')
def test__get_core_nics_one_nic_for_success(self,
- mock_cores_configuration):
+ mock_cores_configuration, mock_time):
mock_cores_configuration.return_value = 'ret_val'
expected = 'ret_val'
output = mut.DpdkPacketGenerator._get_core_nics(1, 'coremask')
@@ -390,7 +391,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
'dpdk_packet_generator.DpdkPacketGenerator.'
'_cores_configuration')
def test__get_core_nics_two_nics_for_success(self,
- mock_cores_configuration):
+ mock_cores_configuration, mock_time):
mock_cores_configuration.return_value = 'ret_val'
expected = 'ret_val'
output = mut.DpdkPacketGenerator._get_core_nics(2, 'coremask')
@@ -398,7 +399,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
mock_cores_configuration.assert_called_once_with('coremask', 1, 2, 2)
@mock.patch('os.path.isfile')
- def test__init_input_validation_for_success(self, mock_is_file):
+ def test__init_input_validation_for_success(self, mock_is_file, mock_time):
mock_is_file.return_value = True
pcap_file_0 = 'pcap_file_0'
@@ -419,7 +420,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
variables), None)
@mock.patch('os.path.isfile')
- def test__init_input_validation_for_failure(self, mock_is_file):
+ def test__init_input_validation_for_failure(self, mock_is_file, mock_time):
mock_is_file.return_value = True
pcap_file_0 = 'pcap_file_0'
@@ -440,7 +441,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
lua_script, pcap_directory, lua_directory, variables)
@mock.patch('os.path.isfile')
- def test__init_input_validation_for_failure_2(self, mock_is_file):
+ def test__init_input_validation_for_failure_2(self, mock_is_file, mock_time):
mock_is_file.return_value = True
pcap_directory = None
@@ -461,7 +462,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
lua_script, pcap_directory, lua_directory, variables)
@mock.patch('os.path.isfile')
- def test__init_input_validation_for_failure_3(self, mock_is_file):
+ def test__init_input_validation_for_failure_3(self, mock_is_file, mock_time):
mock_is_file.return_value = True
pcap_directory = 'directory'
@@ -482,7 +483,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
lua_script, pcap_directory, lua_directory, variables)
@mock.patch('os.path.isfile')
- def test__init_input_validation_for_failure_4(self, mock_is_file):
+ def test__init_input_validation_for_failure_4(self, mock_is_file, mock_time):
mock_is_file.return_value = True
pcap_directory = 'directory'
@@ -503,7 +504,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
lua_script, pcap_directory, lua_directory, variables)
@mock.patch('os.path.isfile')
- def test__init_input_validation_for_failure_5(self, mock_is_file):
+ def test__init_input_validation_for_failure_5(self, mock_is_file, mock_time):
mock_is_file.return_value = True
pcap_directory = 'directory'
@@ -524,7 +525,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
lua_script, pcap_directory, lua_directory, variables)
@mock.patch('os.path.isfile', side_effect=[False])
- def test__init_input_validation_for_failure_6(self, mock_is_file):
+ def test__init_input_validation_for_failure_6(self, mock_is_file, mock_time):
# mock_is_file.return_value = False
pcap_directory = 'directory'
@@ -545,7 +546,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
lua_script, pcap_directory, lua_directory, variables)
@mock.patch('os.path.isfile', side_effect=[True, False])
- def test__init_input_validation_for_failure_7(self, mock_is_file):
+ def test__init_input_validation_for_failure_7(self, mock_is_file, mock_time):
pcap_directory = 'directory'
pcap_file_0 = 'pcap_file_0'
pcap_file_1 = 'pcap_file_1'
@@ -564,7 +565,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
lua_script, pcap_directory, lua_directory, variables)
@mock.patch('os.path.isfile', side_effect=[True, True, False])
- def test__init_input_validation_for_failure_8(self, mock_is_file):
+ def test__init_input_validation_for_failure_8(self, mock_is_file, mock_time):
pcap_directory = 'directory'
pcap_file_0 = 'pcap_file_0'
pcap_file_1 = 'pcap_file_1'
@@ -583,13 +584,13 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
lua_script, pcap_directory, lua_directory, variables)
@mock.patch('os.chdir')
- def test__chdir_for_success(self, mock_os_chdir):
+ def test__chdir_for_success(self, mock_os_chdir, mock_time):
mut.DpdkPacketGenerator._chdir('directory')
mock_os_chdir.assert_called_once_with('directory')
@mock.patch('experimental_framework.common.run_command',
side_effect=MockRunCommand.mock_run_command)
- def test__init_physical_nics_for_success(self, mock_run_command):
+ def test__init_physical_nics_for_success(self, mock_run_command, mock_time):
dpdk_interfaces = 1
dpdk_vars = dict()
@@ -608,7 +609,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
@mock.patch('experimental_framework.common.run_command',
side_effect=MockRunCommand.mock_run_command)
- def test__init_physical_nics_for_success_2(self, mock_run_command):
+ def test__init_physical_nics_for_success_2(self, mock_run_command, mock_time):
dpdk_interfaces = 2
dpdk_vars = dict()
@@ -626,7 +627,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
[True, True, True, True, True, True])
@mock.patch('experimental_framework.common.run_command')
- def test__init_physical_nics_for_failure(self, mock_run_command):
+ def test__init_physical_nics_for_failure(self, mock_run_command, mock_time):
dpdk_interfaces = 3
dpdk_vars = dict()
self.assertRaises(ValueError, self.mut._init_physical_nics,
@@ -634,7 +635,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
@mock.patch('experimental_framework.common.run_command',
side_effect=MockRunCommand.mock_run_command_finalization)
- def test__finalize_physical_nics_for_success(self, mock_run_command):
+ def test__finalize_physical_nics_for_success(self, mock_run_command, mock_time):
dpdk_interfaces = 1
dpdk_vars = dict()
dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] = 'dpdk_directory/'
@@ -652,7 +653,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
@mock.patch('experimental_framework.common.run_command',
side_effect=MockRunCommand.mock_run_command_finalization)
- def test__finalize_physical_nics_for_success_2(self, mock_run_command):
+ def test__finalize_physical_nics_for_success_2(self, mock_run_command, mock_time):
dpdk_interfaces = 2
dpdk_vars = dict()
dpdk_vars[conf_file.CFSP_DPDK_DPDK_DIRECTORY] = 'dpdk_directory/'
@@ -668,34 +669,34 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
self.assertEqual(MockRunCommand.mock_run_command_finalization(),
[True, True, True, True, True, True])
- def test__finalize_physical_nics_for_failure(self):
+ def test__finalize_physical_nics_for_failure(self, mock_time):
dpdk_interfaces = 0
dpdk_vars = dict()
self.assertRaises(ValueError, self.mut._finalize_physical_nics,
dpdk_interfaces, dpdk_vars)
- def test__cores_configuration_for_success(self):
+ def test__cores_configuration_for_success(self, mock_time):
coremask = '1f'
expected = '[2:1].0,[4:3].1'
output = mut.DpdkPacketGenerator._cores_configuration(coremask,
1, 2, 2)
self.assertEqual(expected, output)
- def test__cores_configuration_for_success_2(self):
+ def test__cores_configuration_for_success_2(self, mock_time):
coremask = '1f'
expected = '2.0,[4:3].1'
output = mut.DpdkPacketGenerator._cores_configuration(coremask,
1, 1, 2)
self.assertEqual(expected, output)
- def test__cores_configuration_for_success_3(self):
+ def test__cores_configuration_for_success_3(self, mock_time):
coremask = '1f'
expected = '[3:2].0,4.1'
output = mut.DpdkPacketGenerator._cores_configuration(coremask,
1, 2, 1)
self.assertEqual(expected, output)
- def test__cores_configuration_for_failure(self):
+ def test__cores_configuration_for_failure(self, mock_time):
coremask = '1'
self.assertRaises(ValueError,
mut.DpdkPacketGenerator._cores_configuration,
@@ -703,7 +704,7 @@ class TestDpdkPacketGenOthers(unittest.TestCase):
@mock.patch('experimental_framework.common.LOG')
@mock.patch('experimental_framework.common.run_command')
- def test__change_vlan_for_success(self, mock_run_command, mock_log):
+ def test__change_vlan_for_success(self, mock_run_command, mock_log, mock_time):
mut.DpdkPacketGenerator._change_vlan('/directory/', 'pcap_file', '10')
expected_param = '/directory/vlan_tag.sh /directory/pcap_file 10'
mock_run_command.assert_called_with(expected_param)
diff --git a/yardstick/vTC/apexlake/tests/instantiation_validation_bench_test.py b/yardstick/vTC/apexlake/tests/instantiation_validation_bench_test.py
index 2bd8b7b38..69c5d745e 100644
--- a/yardstick/vTC/apexlake/tests/instantiation_validation_bench_test.py
+++ b/yardstick/vTC/apexlake/tests/instantiation_validation_bench_test.py
@@ -257,6 +257,7 @@ class InstantiationValidationInitTest(unittest.TestCase):
self.assertEqual(dummy_os_kill('', '', True), [1, 1])
self.assertEqual(dummy_run_command('', True), [1, 1, 0, 0, 0])
+ @mock.patch('experimental_framework.benchmarks.instantiation_validation_benchmark.time')
@mock.patch('os.chdir')
@mock.patch('experimental_framework.common.run_command',
side_effect=dummy_run_command_2)
@@ -265,7 +266,7 @@ class InstantiationValidationInitTest(unittest.TestCase):
'InstantiationValidationBenchmark._get_pids')
@mock.patch('os.kill', side_effect=dummy_os_kill)
def test__init_packet_checker_for_success(self, mock_kill, mock_pids,
- mock_run_command, mock_chdir):
+ mock_run_command, mock_chdir, mock_time):
global command_counter
command_counter = [0, 0, 0, 0, 0]
mock_pids.return_value = [1234, 4321]
@@ -314,13 +315,14 @@ class InstantiationValidationInitTest(unittest.TestCase):
self.assertEqual(dummy_replace_in_file('', '', '', True),
[0, 0, 0, 1, 1, 1])
+ @mock.patch('experimental_framework.benchmarks.instantiation_validation_benchmark.time')
@mock.patch('experimental_framework.common.LOG')
@mock.patch('experimental_framework.packet_generators.'
'dpdk_packet_generator.DpdkPacketGenerator',
side_effect=DummyDpdkPacketGenerator)
@mock.patch('experimental_framework.common.get_dpdk_pktgen_vars')
def test_run_for_success(self, mock_common_get_vars, mock_pktgen,
- mock_log):
+ mock_log, mock_time):
rval = dict()
rval[cfs.CFSP_DPDK_BUS_SLOT_NIC_2] = 'bus_2'
rval[cfs.CFSP_DPDK_NAME_IF_2] = 'if_2'