diff options
58 files changed, 818 insertions, 243 deletions
diff --git a/api/resources/env_action.py b/api/resources/env_action.py index 8955f3cb6..917681c37 100644 --- a/api/resources/env_action.py +++ b/api/resources/env_action.py @@ -248,7 +248,7 @@ def _get_remote_rc_file(rc_file, installer_ip, installer_type): cmd = [os_fetch_script, '-d', rc_file, '-i', installer_type, '-a', installer_ip] p = subprocess.Popen(cmd, stdout=subprocess.PIPE) - p.communicate()[0] + p.communicate() if p.returncode != 0: logger.debug('Failed to fetch credentials from installer') diff --git a/api/utils/common.py b/api/utils/common.py index 1c800ce49..3e9bf8f8b 100644 --- a/api/utils/common.py +++ b/api/utils/common.py @@ -33,7 +33,7 @@ def get_command_list(command_list, opts, args): command_list.append(args) - command_list.extend(('--{}'.format(k) for k in opts if 'task-args' != k)) + command_list.extend(('--{}'.format(k) for k in opts if k != 'task-args')) task_args = opts.get('task-args', '') if task_args: diff --git a/api/utils/influx.py b/api/utils/influx.py index 275c63a24..08996b9c9 100644 --- a/api/utils/influx.py +++ b/api/utils/influx.py @@ -24,7 +24,7 @@ def get_data_db_client(): try: parser.read(conf.OUTPUT_CONFIG_FILE_PATH) - if 'influxdb' != parser.get('DEFAULT', 'dispatcher'): + if parser.get('DEFAULT', 'dispatcher') != 'influxdb': raise RuntimeError return _get_client(parser) diff --git a/run_tests.sh b/run_tests.sh index 1f985b6c1..2519d94f6 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -33,32 +33,9 @@ run_flake8() { fi } -get_external_libs() { - cd $(dirname ${BASH_SOURCE[0]}) - TREX_DOWNLOAD="https://trex-tgn.cisco.com/trex/release/v2.05.tar.gz" - TREX_DIR=$PWD/trex/scripts - if [ ! -d "$TREX_DIR" ]; then - rm -rf ${TREX_DOWNLOAD##*/} - if [ ! -e ${TREX_DOWNLOAD##*/} ] ; then - wget -nv $TREX_DOWNLOAD - fi - tar xf ${TREX_DOWNLOAD##*/} - pushd . - rm -rf trex && mkdir -p trex - mv v2.05 trex/scripts - rm -rf v2.05.tar.gz - touch "$PWD/trex/scripts/automation/trex_control_plane/stl/__init__.py" - popd - fi - echo "Done." - export PYTHONPATH=$PYTHONPATH:"$PWD/trex/scripts/automation/trex_control_plane" - export PYTHONPATH=$PYTHONPATH:"$PWD/trex/scripts/automation/trex_control_plane/stl" - echo $PYTHONPATH -} run_tests() { echo "Get external libs needed for unit test" - get_external_libs echo "Running unittest ... " if [ $FILE_OPTION == "f" ]; then diff --git a/samples/nstat.yaml b/samples/nstat.yaml new file mode 100644 index 000000000..0a5aa80c9 --- /dev/null +++ b/samples/nstat.yaml @@ -0,0 +1,35 @@ +--- + +schema: "yardstick:task:0.1" + +description: > + Sample benchmark task config file; + Monitor network metrics provided by the kernel in a host and calculate + IP datagram error rate, ICMP message error rate, TCP segment error rate and + UDP datagram error rate. + +scenarios: +- + type: Nstat + options: + duration: 60 + + host: poseidon.demo + + runner: + type: Iteration + iterations: 1 + +context: + name: demo + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + servers: + poseidon: + floating_ip: true + + networks: + test: + cidr: '10.0.1.0/24' diff --git a/tests/ci/load_images.sh b/tests/ci/load_images.sh index e1d717749..6f950ec72 100755 --- a/tests/ci/load_images.sh +++ b/tests/ci/load_images.sh @@ -206,7 +206,7 @@ create_nova_flavor() # Create the nova flavor used by some sample test cases openstack flavor create --id 100 --ram 512 --disk 3 --vcpus 1 yardstick-flavor # DPDK-enabled OVS requires guest memory to be backed by large pages - if [[ "$DEPLOY_SCENARIO" == *"-ovs-"* ]]; then + if [[ $DEPLOY_SCENARIO == *[_-]ovs[_-]* ]]; then openstack flavor set --property hw:mem_page_size=large yardstick-flavor fi # VPP requires guest memory to be backed by large pages diff --git a/tests/ci/yardstick-verify b/tests/ci/yardstick-verify index f9d98a4da..575bdc821 100755 --- a/tests/ci/yardstick-verify +++ b/tests/ci/yardstick-verify @@ -146,11 +146,11 @@ report(){ \"version\":\"$(basename ${YARDSTICK_BRANCH})\", \"scenario\":\"${DEPLOY_SCENARIO}\", \"description\": \"yardstick ci scenario status\", - \"criteria\":\"$1\", - \"start_date\":\"$2\", - \"stop_date\":\"$3\", + \"criteria\":\"${1}\", + \"start_date\":\"${2}\", + \"stop_date\":\"${3}\", \"details\":\"\"}" \ - ${DISPATCHER_HTTP_TARGET} + "${DISPATCHER_HTTP_TARGET}" } run_test() @@ -220,7 +220,7 @@ EOF scenario_status="FAILED" fi - report $scenario_status $start_date $stop_date + report "${scenario_status}" "${start_date}" "${stop_date}" if [ $failed -gt 0 ]; then echo "---------------------------" diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc019.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc019.yaml index b49019633..5eb477943 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc019.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc019.yaml @@ -16,7 +16,7 @@ scenarios: wait_time: 10 monitors: - monitor_type: "openstack-cmd" - command_name: "nova image-list" + command_name: "openstack image list" monitor_time: 10 sla: max_outage_time: 5 @@ -42,4 +42,4 @@ scenarios: context: type: Node name: LF - file: /root/yardstick/etc/yardstick/nodes/fuel_virtual/pod.yaml + file: etc/yardstick/nodes/fuel_virtual/pod.yaml diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc025.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc025.yaml index 0bbc5b8a6..78cc5cb27 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc025.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc025.yaml @@ -14,16 +14,16 @@ scenarios: monitors: - monitor_type: "openstack-cmd" - command_name: "nova image-list" + command_name: "openstack image list" monitor_time: 10 - monitor_type: "openstack-cmd" - command_name: "neutron router-list" + command_name: "openstack router list" monitor_time: 10 - monitor_type: "openstack-cmd" - command_name: "heat stack-list" + command_name: "openstack stack list" monitor_time: 10 - monitor_type: "openstack-cmd" - command_name: "cinder list" + command_name: "openstack volume list" monitor_time: 10 nodes: @@ -41,4 +41,4 @@ scenarios: context: type: Node name: LF - file: /root/yardstick/etc/yardstick/nodes/fuel_virtual/pod.yaml + file: etc/yardstick/nodes/fuel_virtual/pod.yaml diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc045.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc045.yaml index 196994544..c6dde5cc5 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc045.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc045.yaml @@ -15,7 +15,7 @@ scenarios: monitors: - monitor_type: "openstack-cmd" - command_name: "neutron agent-list" + command_name: "openstack router list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc046.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc046.yaml index 1af561964..786a1f9a1 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc046.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc046.yaml @@ -15,7 +15,7 @@ scenarios: monitors: - monitor_type: "openstack-cmd" - command_name: "keystone user-list" + command_name: "openstack user list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc047.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc047.yaml index 24c28f5de..3f2e8752e 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc047.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc047.yaml @@ -15,7 +15,7 @@ scenarios: monitors: - monitor_type: "openstack-cmd" - command_name: "glance image-list" + command_name: "openstack image list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc048.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc048.yaml index 190084db9..32be5d976 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc048.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc048.yaml @@ -15,7 +15,7 @@ scenarios: monitors: - monitor_type: "openstack-cmd" - command_name: "cinder list" + command_name: "openstack volume list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc050.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc050.yaml index a8cb920ea..88100aa21 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc050.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc050.yaml @@ -54,7 +54,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "nova-image-list" - command_name: "nova image-list" + command_name: "openstack image list" monitor_time: 10 sla: max_outage_time: 5 @@ -62,7 +62,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "neutron-router-list" - command_name: "neutron router-list" + command_name: "openstack router list" monitor_time: 10 sla: max_outage_time: 5 @@ -70,7 +70,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "heat-stack-list" - command_name: "heat stack-list" + command_name: "openstack stack list" monitor_time: 10 sla: max_outage_time: 5 @@ -78,7 +78,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "cinder-list" - command_name: "cinder list" + command_name: "openstack volume list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc051.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc051.yaml index 1115b35f6..264f01b3c 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc051.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc051.yaml @@ -20,7 +20,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "nova-image-list" - command_name: "nova image-list" + command_name: "openstack image list" monitor_time: 10 sla: max_outage_time: 5 @@ -28,7 +28,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "neutron-router-list" - command_name: "neutron router-list" + command_name: "openstack router list" monitor_time: 10 sla: max_outage_time: 5 @@ -36,7 +36,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "heat-stack-list" - command_name: "heat stack-list" + command_name: "openstack stack list" monitor_time: 10 sla: max_outage_time: 5 @@ -44,7 +44,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "cinder-list" - command_name: "cinder list" + command_name: "openstack volume list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc052.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc052.yaml index 67619d3d0..4d3ae93f5 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc052.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc052.yaml @@ -20,7 +20,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "nova-flavor-list" - command_name: "nova flavor-list" + command_name: "openstack flavor list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc053.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc053.yaml index 16a971124..19b406aa6 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc053.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc053.yaml @@ -29,7 +29,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "list-images" - command_name: "nova image-list" + command_name: "openstack image list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc054.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc054.yaml index 93948d3b1..3f1b0171c 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc054.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc054.yaml @@ -19,7 +19,7 @@ scenarios: - monitor_type: "openstack-cmd" key: "list-images" - command_name: "nova image-list" + command_name: "openstack image list" monitor_time: 10 sla: max_outage_time: 5 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc076.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc076.yaml new file mode 100644 index 000000000..c23ee97c2 --- /dev/null +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc076.yaml @@ -0,0 +1,56 @@ +--- + +schema: "yardstick:task:0.1" + +description: > + Yardstick TC076 config file; + Monitor network metrics provided by the kernel in a host and calculate + IP datagram error rate, ICMP message error rate, TCP segment error rate and + UDP datagram error rate. + +scenarios: +- + type: Ping + run_in_background: true + options: + packetsize: 200 + + host: demeter.yardstick-TC076 + target: poseidon.yardstick-TC076 + +- + type: Nstat + options: + duration: 300 + + host: poseidon.yardstick-TC076 + + runner: + type: Iteration + iterations: 1 + + sla: + IP_datagram_error_rate: 0.01 + action: monitor + +context: + name: yardstick-TC076 + image: yardstick-image + flavor: yardstick-flavor + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + demeter: + floating_ip: true + placement: "pgrp1" + poseidon: + floating_ip: true + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' diff --git a/tests/unit/apiserver/resources/test_env_action.py b/tests/unit/apiserver/resources/test_env_action.py index e8f99b706..0411a66c4 100644 --- a/tests/unit/apiserver/resources/test_env_action.py +++ b/tests/unit/apiserver/resources/test_env_action.py @@ -10,7 +10,7 @@ class EnvTestCase(APITestCase): def test_create_grafana(self): url = 'yardstick/env/action' - data = dict(action='createGrafanaContainer') + data = {'action': 'createGrafanaContainer'} resp = self._post(url, data) time.sleep(1) diff --git a/tests/unit/benchmark/contexts/test_node.py b/tests/unit/benchmark/contexts/test_node.py index 64fe4a566..53a8ffa93 100644 --- a/tests/unit/benchmark/contexts/test_node.py +++ b/tests/unit/benchmark/contexts/test_node.py @@ -14,6 +14,7 @@ from __future__ import absolute_import import os import unittest +import mock from yardstick.benchmark.contexts import node @@ -123,3 +124,98 @@ class NodeContextTestCase(unittest.TestCase): curr_path = os.path.dirname(os.path.abspath(__file__)) file_path = os.path.join(curr_path, filename) return file_path + + prefix = 'yardstick.benchmark.contexts.node' + + @mock.patch('{}.NodeContext._execute_script'.format(prefix)) + def test_deploy(self, execute_script_mock): + obj = node.NodeContext() + obj.env = { + 'setup': [ + {'node5': {}} + ] + } + obj.deploy() + self.assertTrue(execute_script_mock.called) + + @mock.patch('{}.NodeContext._execute_script'.format(prefix)) + def test_undeploy(self, execute_script_mock): + obj = node.NodeContext() + obj.env = { + 'teardown': [ + {'node5': {}} + ] + } + obj.undeploy() + self.assertTrue(execute_script_mock.called) + + @mock.patch('{}.ssh.SSH._put_file_shell'.format(prefix)) + @mock.patch('{}.ssh.SSH.execute'.format(prefix)) + def test_execute_remote_script(self, execute_mock, put_file_mock): + obj = node.NodeContext() + obj.env = {'prefix': 'yardstick.benchmark.scenarios.compute'} + node_name_args = 'node5' + obj.nodes = [{ + 'name': node_name_args, + 'user': 'ubuntu', + 'ip': '10.10.10.10', + 'pwd': 'ubuntu', + }] + + info = {'script': 'computecapacity.bash'} + execute_mock.return_value = (0, '', '') + obj._execute_remote_script('node5', info) + + self.assertTrue(put_file_mock.called) + self.assertTrue(execute_mock.called) + + @mock.patch('{}.NodeContext._execute_local_script'.format(prefix)) + def test_execute_script_local(self, local_execute_mock): + node_name = 'local' + info = {} + node.NodeContext()._execute_script(node_name, info) + self.assertTrue(local_execute_mock.called) + + @mock.patch('{}.NodeContext._execute_remote_script'.format(prefix)) + def test_execute_script_remote(self, remote_execute_mock): + node_name = 'node5' + info = {} + node.NodeContext()._execute_script(node_name, info) + self.assertTrue(remote_execute_mock.called) + + def test_get_script(self): + script_args = 'hello.bash' + info_args = { + 'script': script_args + } + script, options = node.NodeContext()._get_script(info_args) + self.assertEqual(script_args, script) + self.assertEqual('', options) + + def test_node_info(self): + node_name_args = 'node5' + obj = node.NodeContext() + obj.nodes = [{'name': node_name_args, 'check': node_name_args}] + node_info = obj._get_node_info(node_name_args) + self.assertEqual(node_info.get('check'), node_name_args) + + @mock.patch('{}.ssh.SSH.wait'.format(prefix)) + def test_get_client(self, wait_mock): + node_name_args = 'node5' + obj = node.NodeContext() + obj.nodes = [{ + 'name': node_name_args, + 'user': 'ubuntu', + 'ip': '10.10.10.10', + 'pwd': 'ubuntu', + }] + obj._get_client(node_name_args) + self.assertTrue(wait_mock.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/core/test_task.py b/tests/unit/benchmark/core/test_task.py index c56e21047..cd7ffdebb 100644 --- a/tests/unit/benchmark/core/test_task.py +++ b/tests/unit/benchmark/core/test_task.py @@ -155,6 +155,30 @@ class TaskTestCase(unittest.TestCase): self.assertEqual(task_args_fnames[0], None) self.assertEqual(task_args_fnames[1], None) + def test_change_server_name_host_str(self): + scenario = {'host': 'demo'} + suffix = '-8' + task.change_server_name(scenario, suffix) + self.assertTrue(scenario['host'], 'demo-8') + + def test_change_server_name_host_dict(self): + scenario = {'host': {'name': 'demo'}} + suffix = '-8' + task.change_server_name(scenario, suffix) + self.assertTrue(scenario['host']['name'], 'demo-8') + + def test_change_server_name_target_str(self): + scenario = {'target': 'demo'} + suffix = '-8' + task.change_server_name(scenario, suffix) + self.assertTrue(scenario['target'], 'demo-8') + + def test_change_server_name_target_dict(self): + scenario = {'target': {'name': 'demo'}} + suffix = '-8' + task.change_server_name(scenario, suffix) + self.assertTrue(scenario['target']['name'], 'demo-8') + def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) file_path = os.path.join(curr_path, filename) diff --git a/tests/unit/benchmark/scenarios/networking/test_nstat.py b/tests/unit/benchmark/scenarios/networking/test_nstat.py new file mode 100644 index 000000000..87a766302 --- /dev/null +++ b/tests/unit/benchmark/scenarios/networking/test_nstat.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +############################################################################## +# Copyright (c) 2017 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.scenarios.networking.nstat.Nstat + +from __future__ import absolute_import + +import unittest + +import mock + +from yardstick.benchmark.scenarios.networking import nstat + +@mock.patch('yardstick.benchmark.scenarios.networking.nstat.ssh') +class NstatTestCase(unittest.TestCase): + + def setUp(self): + self.ctx = { + "host": { + "ip": "192.168.50.28", + "user": "root", + "key_filename": "mykey.key" + } + } + + def test_nstat_successful_setup(self, mock_ssh): + + n = nstat.Nstat({}, self.ctx) + n.setup() + + mock_ssh.SSH().execute.return_value = (0, '', '') + self.assertIsNotNone(n.client) + self.assertEqual(n.setup_done, True) + + def test_nstat_successful_no_sla(self, mock_ssh): + + options = { + "duration": 60 + } + args = { + "options": options, + } + n = nstat.Nstat(args, self.ctx) + result = {} + + sample_output = '#kernel\nIpInReceives 1837 0.0\nIpInHdrErrors 0 0.0\nIpInAddrErrors 2 0.0\nIcmpInMsgs 319 0.0\nIcmpInErrors 0 0.0\nTcpInSegs 36 0.0\nTcpInErrs 0 0.0\nUdpInDatagrams 1318 0.0\nUdpInErrors 0 0.0\n' + + mock_ssh.SSH().execute.return_value = (0, sample_output, '') + + n.run(result) + expected_result = {"TcpInErrs": 0, "UdpInDatagrams": 1318, + "Tcp_segment_error_rate": 0.0, "IpInAddrErrors": 2, + "IpInHdrErrors": 0, "IcmpInErrors": 0, "IpErrors": 2, + "TcpInSegs": 36, "IpInReceives": 1837, "IcmpInMsgs": 319, + "IP_datagram_error_rate": 0.001, "Udp_datagram_error_rate": 0.0, + "Icmp_message_error_rate": 0.0, "UdpInErrors": 0} + self.assertEqual(result, expected_result) + + def test_nstat_successful_sla(self, mock_ssh): + + options = { + "duration": 60 + } + sla = { + "IP_datagram_error_rate": 0.1 + } + args = { + "options": options, + "sla": sla + } + n = nstat.Nstat(args, self.ctx) + result = {} + + sample_output = '#kernel\nIpInReceives 1837 0.0\nIpInHdrErrors 0 0.0\nIpInAddrErrors 2 0.0\nIcmpInMsgs 319 0.0\nIcmpInErrors 0 0.0\nTcpInSegs 36 0.0\nTcpInErrs 0 0.0\nUdpInDatagrams 1318 0.0\nUdpInErrors 0 0.0\n' + + mock_ssh.SSH().execute.return_value = (0, sample_output, '') + + n.run(result) + expected_result = {"TcpInErrs": 0, "UdpInDatagrams": 1318, + "Tcp_segment_error_rate": 0.0, "IpInAddrErrors": 2, + "IpInHdrErrors": 0, "IcmpInErrors": 0, "IpErrors": 2, + "TcpInSegs": 36, "IpInReceives": 1837, "IcmpInMsgs": 319, + "IP_datagram_error_rate": 0.001, "Udp_datagram_error_rate": 0.0, + "Icmp_message_error_rate": 0.0, "UdpInErrors": 0} + self.assertEqual(result, expected_result) + + def test_nstat_unsuccessful_cmd_error(self, mock_ssh): + + options = { + "duration": 60 + } + sla = { + "IP_datagram_error_rate": 0.1 + } + args = { + "options": options, + "sla": sla + } + n = nstat.Nstat(args, self.ctx) + result = {} + + mock_ssh.SSH().execute.return_value = (1, '', 'FOOBAR') + self.assertRaises(RuntimeError, n.run, result) + + +def main(): + unittest.main() + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py b/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py index 0d9fbafc5..1b02b6eff 100644 --- a/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py +++ b/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py @@ -18,12 +18,14 @@ # Unittest for yardstick.benchmark.scenarios.networking.test_vnf_generic from __future__ import absolute_import + +import os import unittest + import mock -import os from yardstick.benchmark.scenarios.networking.vnf_generic import \ - ssh_manager, NetworkServiceTestCase, IncorrectConfig, IncorrectSetup + SshManager, NetworkServiceTestCase, IncorrectConfig, IncorrectSetup from yardstick.network_services.collector.subscriber import Collector from yardstick.network_services.vnf_generic.vnf.base import \ GenericTrafficGen, GenericVNF @@ -164,14 +166,14 @@ lrwxrwxrwx 1 root root 0 sie 3 10:37 eth2 -> """ """ TRAFFIC_PROFILE = { - "schema": "isb:traffic_profile:0.1", - "name": "fixed", - "description": "Fixed traffic profile to run UDP traffic", - "traffic_profile": { - "traffic_type": "FixedTraffic", - "frame_rate": 100, # pps - "flow_number": 10, - "frame_size": 64}} + "schema": "isb:traffic_profile:0.1", + "name": "fixed", + "description": "Fixed traffic profile to run UDP traffic", + "traffic_profile": { + "traffic_type": "FixedTraffic", + "frame_rate": 100, # pps + "flow_number": 10, + "frame_size": 64}} class TestNetworkServiceTestCase(unittest.TestCase): @@ -236,60 +238,72 @@ class TestNetworkServiceTestCase(unittest.TestCase): 'if': 'xe1'}], 'password': 'r00t'}}} - self.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': [{'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'}, - {'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'} - - self.scenario_cfg = {'tc_options': - {'rfc2544': {'allowed_drop_rate': '0.8 - 1'}}, - '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': 'vpe_vnf_topology.yaml'} - - self.scenario_cfg["topology"] = \ - self._get_file_abspath("vpe_vnf_topology.yaml") + self.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': [ + { + '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' + }, + { + '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', + } + + self.scenario_cfg = { + 'tc_options': {'rfc2544': {'allowed_drop_rate': '0.8 - 1'}}, + '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")} + self.s = NetworkServiceTestCase(self.scenario_cfg, self.context_cfg) def _get_file_abspath(self, filename): @@ -301,10 +315,10 @@ class TestNetworkServiceTestCase(unittest.TestCase): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ - mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, "")) + mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, "")) ssh.return_value = ssh_mock for node, node_dict in self.context_cfg["nodes"].items(): - with ssh_manager(node_dict) as conn: + with SshManager(node_dict) as conn: self.assertIsNotNone(conn) def test___init__(self): @@ -342,7 +356,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ - mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, "")) + mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, "")) ssh.return_value = ssh_mock self.s.map_topology_to_infrastructure(self.context_cfg, self.topology) @@ -356,7 +370,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ - mock.Mock(return_value=(1, SYS_CLASS_NET+IP_ADDR_SHOW, "")) + mock.Mock(return_value=(1, SYS_CLASS_NET + IP_ADDR_SHOW, "")) ssh.return_value = ssh_mock self.assertRaises(IncorrectSetup, @@ -364,12 +378,12 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.context_cfg, self.topology) def test_map_topology_to_infrastructure_config_invalid(self): - del self.context_cfg\ - ['nodes']['trexvnf__1']['interfaces']['xe0']['local_mac'] + cfg = dict(self.context_cfg) + del cfg['nodes']['trexvnf__1']['interfaces']['xe0']['local_mac'] with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ - mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, "")) + mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, "")) ssh.return_value = ssh_mock self.assertRaises(IncorrectConfig, @@ -380,7 +394,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ - mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, "")) + mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, "")) ssh.return_value = ssh_mock del self.context_cfg['nodes'] @@ -413,7 +427,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ - mock.Mock(return_value=(0, SYS_CLASS_NET+IP_ADDR_SHOW, "")) + mock.Mock(return_value=(0, SYS_CLASS_NET + IP_ADDR_SHOW, "")) ssh.return_value = ssh_mock tgen = mock.Mock(autospec=GenericTrafficGen) @@ -443,11 +457,15 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.context_cfg)) def test__get_traffic_profile_exception(self): - self.assertRaises(IOError, self.s._get_traffic_profile, - self.scenario_cfg, self.context_cfg) + cfg = dict(self.scenario_cfg) + cfg["traffic_profile"] = "" + self.assertRaises(IOError, self.s._get_traffic_profile, cfg, + self.context_cfg) def test___get_traffic_imix_exception(self): - self.assertEqual({}, self.s._get_traffic_imix(self.scenario_cfg)) + cfg = dict(self.scenario_cfg) + cfg["traffic_options"]["imix"] = "" + self.assertEqual({}, self.s._get_traffic_imix(cfg)) def test__fill_traffic_profile(self): with mock.patch.dict("sys.modules", STL_MOCKS): diff --git a/tests/unit/network_services/test_utils.py b/tests/unit/network_services/test_utils.py index ecacac7c3..8d9e74adf 100644 --- a/tests/unit/network_services/test_utils.py +++ b/tests/unit/network_services/test_utils.py @@ -16,6 +16,8 @@ # Unittest for yardstick.network_services.utils from __future__ import absolute_import + +import os import unittest import mock @@ -25,19 +27,24 @@ from yardstick.network_services import utils class UtilsTestCase(unittest.TestCase): """Test all VNF helper methods.""" - DPDK_PATH = "/opt/nsb_bin/dpdk_nic_bind.py" + DPDK_PATH = os.path.join(utils.NSB_ROOT, "dpdk_nic_bind.py") def setUp(self): super(UtilsTestCase, self).setUp() def test_get_nsb_options(self): result = utils.get_nsb_option("bin_path", None) - self.assertEqual(result, "/opt/nsb_bin") + self.assertEqual(result, utils.NSB_ROOT) - def test_get_nsb_optionsi_invalid_key(self): + def test_get_nsb_option_is_invalid_key(self): result = utils.get_nsb_option("bin", None) self.assertEqual(result, None) + def test_get_nsb_option_default(self): + default = object() + result = utils.get_nsb_option("nosuch", default) + self.assertIs(result, default) + def test_provision_tool(self): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) 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 eb0dbf628..a76fbbd2a 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 @@ -195,7 +195,7 @@ class TestTrexTrafficGen(unittest.TestCase): self.assertEqual({}, restult) def test_listen_traffic(self): - with mock.patch("yardstick.ssh.SSH") as ssh: + with mock.patch("yardstick.ssh.SSH") as ssh: vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ diff --git a/tools/ubuntu-server-cloudimg-dpdk-modify.sh b/tools/ubuntu-server-cloudimg-dpdk-modify.sh index aa4e252ea..9a3857ee3 100755 --- a/tools/ubuntu-server-cloudimg-dpdk-modify.sh +++ b/tools/ubuntu-server-cloudimg-dpdk-modify.sh @@ -63,10 +63,13 @@ linuxheadersversion=`echo ls boot/vmlinuz* | cut -d- -f2-` apt-get update apt-get install -y \ + bc \ fio \ gcc \ git \ iperf3 \ + iproute2 \ + ethtool \ linux-tools-common \ linux-tools-generic \ lmbench \ diff --git a/tools/ubuntu-server-cloudimg-modify.sh b/tools/ubuntu-server-cloudimg-modify.sh index 49c842c97..c0ae774ef 100755 --- a/tools/ubuntu-server-cloudimg-modify.sh +++ b/tools/ubuntu-server-cloudimg-modify.sh @@ -58,10 +58,13 @@ bootcmd: EOF fi apt-get install -y \ + bc \ fio \ git \ gcc \ iperf3 \ + ethtool \ + iproute2 \ linux-tools-common \ linux-tools-generic \ lmbench \ diff --git a/yardstick/__init__.py b/yardstick/__init__.py index fbbc101a9..1ad6eb0b1 100644 --- a/yardstick/__init__.py +++ b/yardstick/__init__.py @@ -39,6 +39,8 @@ def _init_logging(): # don't append to log file, clobber _LOG_FILE_HDLR.setFormatter(_LOG_FORMATTER) + # set log file to store debug info + _LOG_FILE_HDLR.setLevel(logging.DEBUG) del logging.root.handlers[:] logging.root.addHandler(_LOG_STREAM_HDLR) diff --git a/yardstick/benchmark/contexts/dummy.py b/yardstick/benchmark/contexts/dummy.py index f7530035c..0edc250f8 100644 --- a/yardstick/benchmark/contexts/dummy.py +++ b/yardstick/benchmark/contexts/dummy.py @@ -22,7 +22,7 @@ class DummyContext(Context): __context_type__ = "Dummy" def __init__(self): - super(self.__class__, self).__init__() + super(DummyContext, self).__init__() def init(self, attrs): pass diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index 0346efcf4..4c7f05236 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -55,7 +55,7 @@ class HeatContext(Context): self.key_filename = ''.join( [YARDSTICK_ROOT_PATH, 'yardstick/resources/files/yardstick_key-', get_short_key_uuid(self.key_uuid)]) - super(self.__class__, self).__init__() + super(HeatContext, self).__init__() def init(self, attrs): """initializes itself from the supplied arguments""" @@ -94,9 +94,10 @@ class HeatContext(Context): rsa_key = paramiko.RSAKey.generate(bits=2048, progress_func=None) rsa_key.write_private_key_file(self.key_filename) - open(self.key_filename + ".pub", "w").write("%s %s\n" % - (rsa_key.get_name(), - rsa_key.get_base64())) + print("Writing %s ..." % self.key_filename) + 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 @@ -220,9 +221,9 @@ class HeatContext(Context): # copy some vital stack output into server objects for server in self.servers: - if len(server.ports) > 0: + if server.ports: # TODO(hafe) can only handle one internal network for now - port = list(server.ports.values())[0] + port = next(iter(server.ports.values())) server.private_ip = self.stack.outputs[port["stack_name"]] if server.floating_ip: diff --git a/yardstick/benchmark/contexts/model.py b/yardstick/benchmark/contexts/model.py index 636abfa35..c83a209cf 100644 --- a/yardstick/benchmark/contexts/model.py +++ b/yardstick/benchmark/contexts/model.py @@ -66,7 +66,7 @@ class Router(Object): """Class that represents a router in the logical model""" def __init__(self, name, network_name, context, external_gateway_info): - super(self.__class__, self).__init__(name, context) + super(Router, self).__init__(name, context) self.stack_name = context.name + "-" + network_name + "-" + self.name self.stack_if_name = self.stack_name + "-if0" @@ -78,7 +78,7 @@ class Network(Object): list = [] def __init__(self, name, context, attrs): - super(self.__class__, self).__init__(name, context) + super(Network, self).__init__(name, context) self.stack_name = context.name + "-" + self.name self.subnet_stack_name = self.stack_name + "-subnet" self.subnet_cidr = attrs.get('cidr', '10.0.1.0/24') @@ -118,7 +118,7 @@ class Server(Object): list = [] def __init__(self, name, context, attrs): - super(self.__class__, self).__init__(name, context) + super(Server, self).__init__(name, context) self.stack_name = self.name + "." + context.name self.keypair_name = context.keypair_name self.secgroup_name = context.secgroup_name diff --git a/yardstick/benchmark/contexts/node.py b/yardstick/benchmark/contexts/node.py index 9242e2727..6fa9aa99a 100644 --- a/yardstick/benchmark/contexts/node.py +++ b/yardstick/benchmark/contexts/node.py @@ -8,14 +8,18 @@ ############################################################################## from __future__ import absolute_import -import logging import errno +import subprocess import os import collections +import logging + import yaml +import pkg_resources +from yardstick import ssh from yardstick.benchmark.contexts.base import Context -from yardstick.definitions import YARDSTICK_ROOT_PATH +from yardstick.common.constants import YARDSTICK_ROOT_PATH LOG = logging.getLogger(__name__) @@ -32,7 +36,8 @@ class NodeContext(Context): self.controllers = [] self.computes = [] self.baremetals = [] - super(self.__class__, self).__init__() + self.env = {} + super(NodeContext, self).__init__() def read_config_file(self): """Read from config file""" @@ -69,13 +74,20 @@ class NodeContext(Context): LOG.debug("Computes: %r", self.computes) LOG.debug("BareMetals: %r", self.baremetals) + self.env = attrs.get('env', {}) + LOG.debug("Env: %r", self.env) + def deploy(self): - """don't need to deploy""" - pass + setups = self.env.get('setup', []) + for setup in setups: + for host, info in setup.items(): + self._execute_script(host, info) def undeploy(self): - """don't need to undeploy""" - pass + teardowns = self.env.get('teardown', []) + for teardown in teardowns: + for host, info in teardown.items(): + self._execute_script(host, info) def _get_server(self, attr_name): """lookup server info by name from context @@ -106,3 +118,61 @@ class NodeContext(Context): node["name"] = attr_name return node + + def _execute_script(self, node_name, info): + if node_name == 'local': + self._execute_local_script(info) + else: + self._execute_remote_script(node_name, info) + + def _execute_remote_script(self, node_name, info): + prefix = self.env.get('prefix', '') + script, options = self._get_script(info) + + script_file = pkg_resources.resource_filename(prefix, script) + + self._get_client(node_name) + self.client._put_file_shell(script_file, '~/{}'.format(script)) + + cmd = 'sudo bash {} {}'.format(script, options) + status, stdout, stderr = self.client.execute(cmd) + if status: + raise RuntimeError(stderr) + + def _execute_local_script(self, info): + script, options = self._get_script(info) + script = os.path.join(YARDSTICK_ROOT_PATH, script) + cmd = ['bash', script, options] + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + LOG.debug('\n%s', p.communicate()[0]) + + def _get_script(self, info): + return info.get('script'), info.get('options', '') + + def _get_client(self, node_name): + node = self._get_node_info(node_name.strip()) + + if node is None: + raise SystemExit('No such node') + + user = node.get('user', 'ubuntu') + ssh_port = node.get("ssh_port", ssh.DEFAULT_PORT) + ip = node.get('ip') + pwd = node.get('password') + key_fname = node.get('key_filename', '/root/.ssh/id_rsa') + + if pwd is not None: + LOG.debug("Log in via pw, user:%s, host:%s, password:%s", + user, ip, pwd) + self.client = ssh.SSH(user, ip, password=pwd, port=ssh_port) + else: + LOG.debug("Log in via key, user:%s, host:%s, key_filename:%s", + user, ip, key_fname) + self.client = ssh.SSH(user, ip, key_filename=key_fname, + port=ssh_port) + + self.client.wait(timeout=600) + + def _get_node_info(self, name): + return next((n for n in self.nodes if n['name'].strip() == name)) diff --git a/yardstick/benchmark/contexts/standalone.py b/yardstick/benchmark/contexts/standalone.py index c1d963f50..eff700974 100644 --- a/yardstick/benchmark/contexts/standalone.py +++ b/yardstick/benchmark/contexts/standalone.py @@ -37,7 +37,7 @@ class StandaloneContext(Context): self.file_path = None self.nodes = [] self.nfvi_node = [] - super(self.__class__, self).__init__() + super(StandaloneContext, self).__init__() def read_config_file(self): """Read from config file""" diff --git a/yardstick/benchmark/core/__init__.py b/yardstick/benchmark/core/__init__.py index 161e448cc..79ebc732f 100644 --- a/yardstick/benchmark/core/__init__.py +++ b/yardstick/benchmark/core/__init__.py @@ -33,6 +33,6 @@ class Param(object): def print_hbar(barlen): """print to stdout a horizontal bar""" - print("+"), - print("-" * barlen), + print("+") + print("-" * barlen) print("+") diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index 87d70f42f..522ad4d23 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -85,7 +85,7 @@ class Task(object): # pragma: no cover # (hide it for exit handler) Context.list = [] else: - for context in Context.list: + for context in Context.list[::-1]: context.undeploy() Context.list = [] one_task_end_time = time.time() @@ -348,17 +348,23 @@ def atexit_handler(): if len(Context.list) > 0: print("Undeploying all contexts") - for context in Context.list: + for context in Context.list[::-1]: context.undeploy() def is_ip_addr(addr): """check if string addr is an IP address""" try: + addr = addr.get('public_ip_attr', addr.get('private_ip_attr')) + except AttributeError: + pass + + try: ipaddress.ip_address(addr.encode('utf-8')) - return True except ValueError: return False + else: + return True def _is_same_heat_context(host_attr, target_attr): @@ -499,14 +505,24 @@ def check_environment(): def change_server_name(scenario, suffix): try: - scenario['host'] += suffix + host = scenario['host'] except KeyError: pass + else: + try: + host['name'] += suffix + except TypeError: + scenario['host'] += suffix try: - scenario['target'] += suffix + target = scenario['target'] except KeyError: pass + else: + try: + target['name'] += suffix + except TypeError: + scenario['target'] += suffix try: key = 'targets' diff --git a/yardstick/benchmark/runners/arithmetic.py b/yardstick/benchmark/runners/arithmetic.py index d5605f755..65fdb9d66 100755 --- a/yardstick/benchmark/runners/arithmetic.py +++ b/yardstick/benchmark/runners/arithmetic.py @@ -139,7 +139,7 @@ def _worker_process(queue, cls, method_name, scenario_cfg, sequence += 1 - if (errors and sla_action is None): + if errors and sla_action is None: break benchmark.teardown() diff --git a/yardstick/benchmark/scenarios/availability/attacker/attacker_general.py b/yardstick/benchmark/scenarios/availability/attacker/attacker_general.py index 38a966803..24888af98 100644 --- a/yardstick/benchmark/scenarios/availability/attacker/attacker_general.py +++ b/yardstick/benchmark/scenarios/availability/attacker/attacker_general.py @@ -62,11 +62,11 @@ class GeneralAttacker(BaseAttacker): self.fault_cfg['recovery_script']) def inject_fault(self): - LOG.debug("{0} starting inject!".format(self.key)) - LOG.debug("the inject_script path:{0}".format(self.inject_script)) + LOG.debug("%s starting inject!", self.key) + LOG.debug("the inject_script path:%s", self.inject_script) if "action_parameter" in self._config: - LOG.debug("the shell command is: {0}".format(self.action_param)) + LOG.debug("the shell command is: %s", self.action_param) with open(self.inject_script, "r") as stdin_file: exit_status, stdout, stderr = self.connection.execute( self.action_param, @@ -88,7 +88,7 @@ class GeneralAttacker(BaseAttacker): def recover(self): if "rollback_parameter" in self._config: - LOG.debug("the shell command is: {0}".format(self.rollback_param)) + LOG.debug("the shell command is: %s", self.rollback_param) with open(self.recovery_script, "r") as stdin_file: exit_status, stdout, stderr = self.connection.execute( self.rollback_param, diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_flavor.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_flavor.bash index 5c2d6d70e..38dbe0cee 100644 --- a/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_flavor.bash +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/create_flavor.bash @@ -16,4 +16,4 @@ set -e source /root/openrc -nova flavor-create $1 $2 $3 $4 $5 +openstack flavor create $1 --id $2 --ram $3 --disk $4 --vcpus $5 diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_flavor.bash b/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_flavor.bash index 67d0c902e..37d2cf6c0 100644 --- a/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_flavor.bash +++ b/yardstick/benchmark/scenarios/availability/ha_tools/nova/delete_flavor.bash @@ -16,4 +16,4 @@ set -e source /root/openrc -nova flavor-delete $1
\ No newline at end of file +openstack flavor delete $1 diff --git a/yardstick/benchmark/scenarios/availability/result_checker/result_checker_general.py b/yardstick/benchmark/scenarios/availability/result_checker/result_checker_general.py index 75c433a0e..8f987a647 100644 --- a/yardstick/benchmark/scenarios/availability/result_checker/result_checker_general.py +++ b/yardstick/benchmark/scenarios/availability/result_checker/result_checker_general.py @@ -61,28 +61,26 @@ class GeneralResultChecker(BaseResultChecker): exit_status, stdout, stderr = self.connection.execute( self.shell_cmd, stdin=stdin_file) - LOG.debug("action script of the operation is: {0}" - .format(self.verify_script)) - LOG.debug("action parameter the of operation is: {0}" - .format(self.shell_cmd)) + LOG.debug("action script of the operation is: %s", + self.verify_script) + LOG.debug("action parameter the of operation is: %s", + self.shell_cmd) else: with open(self.verify_script, "r") as stdin_file: exit_status, stdout, stderr = self.connection.execute( "/bin/bash -s ", stdin=stdin_file) - LOG.debug("action script of the operation is: {0}" - .format(self.verify_script)) + LOG.debug("action script of the operation is: %s", + self.verify_script) LOG.debug("exit_status ,stdout : %s ,%s", exit_status, stdout) if exit_status == 0 and stdout: self.actualResult = stdout - LOG.debug("verifying resultchecker: {0}".format(self.key)) - LOG.debug("verifying resultchecker,expected: {0}" - .format(self.expectedResult)) - LOG.debug("verifying resultchecker,actual: {0}" - .format(self.actualResult)) - LOG.debug("verifying resultchecker,condition: {0}" - .format(self.condition)) + LOG.debug("verifying resultchecker: %s", self.key) + LOG.debug("verifying resultchecker,expected: %s", + self.expectedResult) + LOG.debug("verifying resultchecker,actual: %s", self.actualResult) + LOG.debug("verifying resultchecker,condition: %s", self.condition) if (type(self.expectedResult) is int): self.actualResult = int(self.actualResult) if self.condition == Condition.EQUAL: @@ -100,13 +98,13 @@ class GeneralResultChecker(BaseResultChecker): else: self.success = False LOG.debug( - "error happened when resultchecker: {0} Invalid condition" - .format(self.key)) + "error happened when resultchecker: %s Invalid condition", + self.key) else: self.success = False LOG.debug( - "error happened when resultchecker: {0} verifying the result" - .format(self.key)) + "error happened when resultchecker: %s verifying the result", + self.key) LOG.error(stderr) LOG.debug( diff --git a/yardstick/benchmark/scenarios/availability/scenario_general.py b/yardstick/benchmark/scenarios/availability/scenario_general.py index 2d7ce664e..a950ef933 100644 --- a/yardstick/benchmark/scenarios/availability/scenario_general.py +++ b/yardstick/benchmark/scenarios/availability/scenario_general.py @@ -47,8 +47,8 @@ class ScenarioGeneral(base.Scenario): except Exception: LOG.exception("Exception") LOG.debug( - "\033[91m exception when running step: {0} .... \033[0m" - .format(orderedSteps.index(step))) + "\033[91m exception when running step: %s .... \033[0m", + orderedSteps.index(step)) break finally: pass diff --git a/yardstick/benchmark/scenarios/networking/nstat.py b/yardstick/benchmark/scenarios/networking/nstat.py new file mode 100644 index 000000000..df96dbda7 --- /dev/null +++ b/yardstick/benchmark/scenarios/networking/nstat.py @@ -0,0 +1,130 @@ +############################################################################## +# Copyright (c) 2017 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 +############################################################################## +from __future__ import print_function +from __future__ import absolute_import + +import time +import logging + +import yardstick.ssh as ssh +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + +PRECISION = 3 + + +class Nstat(base.Scenario): + """Use nstat to monitor network metrics and measure IP datagram error rate + and etc. + """ + + __scenario_type__ = "Nstat" + + def __init__(self, scenario_cfg, context_cfg): + """Scenario construction""" + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.setup_done = False + + def setup(self): + """scenario setup""" + host = self.context_cfg["host"] + user = host.get("user", "ubuntu") + ssh_port = host.get("ssh_port", ssh.DEFAULT_PORT) + ip = host.get("ip", None) + key_filename = host.get('key_filename', "~/.ssh/id_rsa") + + LOG.info("user:%s, host:%s", user, ip) + self.client = ssh.SSH(user, ip, key_filename=key_filename, + port=ssh_port) + self.client.wait(timeout=600) + + self.setup_done = True + + def match(self, key, field, line, results): + """match data in the output""" + if key in line: + results[key] = int(line.split()[field]) + + def calculate_error_rate(self, x, y): + """calculate error rate""" + try: + return round(float(x) / float(y), PRECISION) + except ZeroDivisionError: + # If incoming Errors is non-zero, but incoming data is zero + # consider it as 100% error rate + if x: + return 1 + else: + return 0 + + def process_output(self, out): + """process output""" + results = {} + for line in out.splitlines(): + self.match('IpInReceives', 1, line, results) + self.match('IpInHdrErrors', 1, line, results) + self.match('IpInAddrErrors', 1, line, results) + self.match('IcmpInMsgs', 1, line, results) + self.match('IcmpInErrors', 1, line, results) + self.match('TcpInSegs', 1, line, results) + self.match('TcpInErrs', 1, line, results) + self.match('UdpInDatagrams', 1, line, results) + self.match('UdpInErrors', 1, line, results) + results['IpErrors'] = \ + results['IpInHdrErrors'] + results['IpInAddrErrors'] + results['IP_datagram_error_rate'] = \ + self.calculate_error_rate(results['IpErrors'], + results['IpInReceives']) + results['Icmp_message_error_rate'] = \ + self.calculate_error_rate(results['IcmpInErrors'], + results['IcmpInMsgs']) + results['Tcp_segment_error_rate'] = \ + self.calculate_error_rate(results['TcpInErrs'], + results['TcpInSegs']) + results['Udp_datagram_error_rate'] = \ + self.calculate_error_rate(results['UdpInErrors'], + results['UdpInDatagrams']) + return results + + def run(self, result): + """execute the benchmark""" + + if not self.setup_done: + self.setup() + + options = self.scenario_cfg['options'] + duration = options.get('duration', 60) + + time.sleep(duration) + + cmd = "nstat -z" + + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.client.execute(cmd) + + if status: + raise RuntimeError(stderr) + + results = self.process_output(stdout) + + result.update(results) + + if "sla" in self.scenario_cfg: + sla_error = "" + for i, rate in result.items(): + if i not in self.scenario_cfg['sla']: + continue + sla_rate = float(self.scenario_cfg['sla'][i]) + rate = float(rate) + if rate > sla_rate: + sla_error += "%s rate %f > sla:%s_rate(%f); " % \ + (i, rate, i, sla_rate) + assert sla_error == "", sla_error diff --git a/yardstick/benchmark/scenarios/networking/sfc_openstack.py b/yardstick/benchmark/scenarios/networking/sfc_openstack.py index caaf10060..be24add32 100644 --- a/yardstick/benchmark/scenarios/networking/sfc_openstack.py +++ b/yardstick/benchmark/scenarios/networking/sfc_openstack.py @@ -81,7 +81,7 @@ def create_floating_ips(neutron_client): # pragma: no cover ips = [] props = {'floating_network_id': extnet_id} try: - while (len(ips) < 2): + while len(ips) < 2: ip_json = neutron_client.create_floatingip({'floatingip': props}) fip_addr = ip_json['floatingip']['floating_ip_address'] ips.append(fip_addr) diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py index d7ba418c3..447c550ed 100644 --- a/yardstick/benchmark/scenarios/networking/vnf_generic.py +++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py @@ -15,7 +15,6 @@ from __future__ import absolute_import import logging -from contextlib import contextmanager import yaml from yardstick.benchmark.scenarios import base @@ -49,31 +48,32 @@ class IncorrectSetup(Exception): pass -@contextmanager -def ssh_manager(node): - """ - args -> network device mappings - returns -> ssh connection ready to be used - """ - conn = None - try: - ssh_port = node.get("ssh_port", ssh.DEFAULT_PORT) - conn = ssh.SSH(user=node.get("user", ""), - host=node.get("ip", ""), - password=node.get("password", ""), - port=ssh_port) - conn.wait() - - except (SSHError) as error: - LOG.info("connect failed to %s, due to %s", node.get("ip", ""), error) - try: - if conn: - yield conn - else: - yield False - finally: - if conn: - conn.close() +class SshManager(object): + def __init__(self, node): + super(SshManager, self).__init__() + self.node = node + self.conn = None + + def __enter__(self): + """ + args -> network device mappings + returns -> ssh connection ready to be used + """ + try: + ssh_port = self.node.get("ssh_port", ssh.DEFAULT_PORT) + self.conn = ssh.SSH(user=self.node["user"], + host=self.node["ip"], + password=self.node["password"], + port=ssh_port) + self.conn.wait() + except (SSHError) as error: + LOG.info("connect failed to %s, due to %s", self.node["ip"], error) + # self.conn defaults to None + return self.conn + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.conn: + self.conn.close() class NetworkServiceTestCase(base.Scenario): @@ -208,7 +208,7 @@ class NetworkServiceTestCase(base.Scenario): for node, node_dict in context_cfg["nodes"].items(): cmd = "PATH=$PATH:/sbin:/usr/sbin ip addr show" - with ssh_manager(node_dict) as conn: + with SshManager(node_dict) as conn: exit_status = conn.execute(cmd)[0] if exit_status != 0: raise IncorrectSetup("Node's %s lacks ip tool." % node) @@ -237,10 +237,10 @@ class NetworkServiceTestCase(base.Scenario): 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] + impl = (c for c in itersubclasses(GenericVNF) + if c.__name__ == expected_name) try: - return next(iter(impl)) + return next(impl) except StopIteration: raise IncorrectConfig("No implementation for %s", expected_name) diff --git a/yardstick/cmd/NSBperf.py b/yardstick/cmd/NSBperf.py index dd96b7fc8..c3730f834 100755 --- a/yardstick/cmd/NSBperf.py +++ b/yardstick/cmd/NSBperf.py @@ -115,7 +115,7 @@ class YardstickNSCli(object): def generate_final_report(self, test_case): """ Function will check if partial test results are available and generates final report in rst format. -""" + """ report_caption = '{}\n{} ({})\n{}\n\n'.format( '================================================================', diff --git a/yardstick/cmd/commands/task.py b/yardstick/cmd/commands/task.py index 20ab086e5..16a4db291 100644 --- a/yardstick/cmd/commands/task.py +++ b/yardstick/cmd/commands/task.py @@ -14,7 +14,7 @@ from __future__ import absolute_import from yardstick.benchmark.core.task import Task from yardstick.common.utils import cliargs from yardstick.common.utils import write_json_to_file -from yardstick.common import constants as consts +from yardstick.common.utils import read_json_from_file from yardstick.cmd.commands import change_osloobj_to_paras output_file_default = "/tmp/yardstick.out" @@ -24,7 +24,7 @@ class TaskCommands(object): """Task commands. Set of commands to manage benchmark tasks. - """ + """ @cliargs("inputfile", type=str, help="path to task or suite file", nargs=1) @cliargs("--task-args", dest="task_args", @@ -44,18 +44,25 @@ class TaskCommands(object): action="store_true") def do_start(self, args, **kwargs): param = change_osloobj_to_paras(args) + self.output_file = param.output_file self._init_result_file() try: - Task().start(param) + Task().start(param, **kwargs) + self._finish() except Exception as e: self._write_error_data(e) def _init_result_file(self): data = {'status': 0, 'result': []} - write_json_to_file(consts.DEFAULT_OUTPUT_FILE, data) + write_json_to_file(self.output_file, data) + + def _finish(self): + result = read_json_from_file(self.output_file).get('result') + data = {'status': 1, 'result': result} + write_json_to_file(self.output_file, data) def _write_error_data(self, error): data = {'status': 2, 'result': str(error)} - write_json_to_file(consts.DEFAULT_OUTPUT_FILE, data) + write_json_to_file(self.output_file, data) diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index e351d16d3..5026e819d 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -65,7 +65,7 @@ def get_credentials(): creds.update({"insecure": "True", "https_insecure": "True"}) if not os.path.isfile(cacert): log.info("WARNING: The 'OS_CACERT' environment variable is set\ - to %s but the file does not exist." % cacert) + to %s but the file does not exist.", cacert) return creds diff --git a/yardstick/common/task_template.py b/yardstick/common/task_template.py index bda8a1b13..9acc21336 100755 --- a/yardstick/common/task_template.py +++ b/yardstick/common/task_template.py @@ -45,11 +45,11 @@ def is_really_missing(mis, task_template): # Removing variables that have default values from # missing. Construction that won't be properly # check is {% set x = x or 1} - if re.search(mis.join(["{%\s*set\s+", "\s*=\s*", "[^\w]+"]), + if re.search(mis.join([r"{%\s*set\s+", "\s*=\s*", r"[^\w]+"]), task_template): return False # Also check for a default filter which can show up as # a missing variable - if re.search(mis + "\s*\|\s*default\(", task_template): + if re.search(mis + r"\s*\|\s*default\(", task_template): return False return True diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index 473bbf540..04536190b 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -148,8 +148,14 @@ def get_neutron_client(): return neutron_client +def read_json_from_file(path): + with open(path, 'r') as f: + return jsonutils.load(f) + + def write_json_to_file(path, data, mode='w'): - write_file(path, jsonutils.dump_as_bytes(data), mode) + with open(path, mode) as f: + jsonutils.dump(data, f) def write_file(path, data, mode='w'): diff --git a/yardstick/dispatcher/file.py b/yardstick/dispatcher/file.py index 8d3c3693d..6fc81d419 100644 --- a/yardstick/dispatcher/file.py +++ b/yardstick/dispatcher/file.py @@ -39,5 +39,8 @@ class FileDispatcher(DispatchBase): def flush_result_data(self): file_path = self.conf.get('file_path', consts.DEFAULT_OUTPUT_FILE) - data = {'status': 1, 'result': self.result} + res = utils.read_json_from_file(file_path).get('result') + res.extend(self.result) + + data = {'status': 0, 'result': res} utils.write_json_to_file(file_path, data) diff --git a/yardstick/dispatcher/influxdb.py b/yardstick/dispatcher/influxdb.py index 427e669a2..d388d28a1 100644 --- a/yardstick/dispatcher/influxdb.py +++ b/yardstick/dispatcher/influxdb.py @@ -164,7 +164,7 @@ class InfluxdbDispatcher(DispatchBase): timeout=self.timeout) if res.status_code != 204: LOG.error('Test result posting finished with status code' - ' %d.' % res.status_code) + ' %d.', res.status_code) LOG.error(res.text) except Exception as err: diff --git a/yardstick/network_services/utils.py b/yardstick/network_services/utils.py index b75091326..cb71a6029 100644 --- a/yardstick/network_services/utils.py +++ b/yardstick/network_services/utils.py @@ -15,18 +15,21 @@ from __future__ import absolute_import import logging +import os from oslo_config import cfg from oslo_config.cfg import NoSuchOptError from oslo_utils import encodeutils +NSB_ROOT = "/opt/nsb_bin" + CONF = cfg.CONF OPTS = [ cfg.StrOpt('bin_path', - default='/opt/nsb_bin', + default=NSB_ROOT, help='bin_path for VNFs location.'), cfg.StrOpt('trex_path', - default='/opt/nsb_bin/trex/scripts', + default=os.path.join(NSB_ROOT, 'trex/scripts'), help='trex automation lib pathh.'), ] CONF.register_opts(OPTS, group="nsb") @@ -39,8 +42,7 @@ def get_nsb_option(option, default=None): return CONF.nsb.__getitem__(option) except NoSuchOptError: logging.debug("Invalid key %s", option) - else: - return default + return default def provision_tool(connection, tool_path): diff --git a/yardstick/network_services/vnf_generic/vnfdgen.py b/yardstick/network_services/vnf_generic/vnfdgen.py index 9a02050a2..64554cdaf 100644 --- a/yardstick/network_services/vnf_generic/vnfdgen.py +++ b/yardstick/network_services/vnf_generic/vnfdgen.py @@ -16,7 +16,6 @@ from __future__ import absolute_import import collections import yaml -import six from yardstick.common.task_template import TaskTemplate @@ -46,13 +45,14 @@ def dict_key_flatten(data): """ next_data = {} + # check for non-string iterables if not any((isinstance(v, collections.Iterable) and not isinstance(v, str)) for v in data.values()): return data - for key, val in six.iteritems(data): + for key, val in data.items(): if isinstance(val, collections.Mapping): - for n_k, n_v in six.iteritems(val): + for n_k, n_v in val.items(): next_data["%s.%s" % (key, n_k)] = n_v elif isinstance(val, collections.Iterable) and not isinstance(val, str): diff --git a/yardstick/orchestrator/heat.py b/yardstick/orchestrator/heat.py index c098de9e3..e39c4356c 100644 --- a/yardstick/orchestrator/heat.py +++ b/yardstick/orchestrator/heat.py @@ -179,7 +179,7 @@ class HeatTemplate(HeatObject): with open(template_file) as stream: print("Parsing external template:", template_file) template_str = stream.read() - self._template = template_format.parse(template_str) + self._template = template_format.parse(template_str) self._parameters = heat_parameters else: self._init_template() diff --git a/yardstick/vTC/apexlake/experimental_framework/heat_template_generation.py b/yardstick/vTC/apexlake/experimental_framework/heat_template_generation.py index 1904af20b..bbf55853d 100644 --- a/yardstick/vTC/apexlake/experimental_framework/heat_template_generation.py +++ b/yardstick/vTC/apexlake/experimental_framework/heat_template_generation.py @@ -18,9 +18,11 @@ Generation of the heat templates from the base template """ from __future__ import absolute_import -import json import os import shutil + +from oslo_serialization import jsonutils + from experimental_framework import common from experimental_framework.constants import framework_parameters as fp @@ -193,7 +195,7 @@ def generates_templates(base_heat_template, deployment_configuration): new_template += "_" + str(counter) + template_file_extension shutil.copy(base_template, new_template) - metadata = dict() + metadata = {} for var in heat_template_vars: if var.get_variable_name(): common.replace_in_file(new_template, "#" + @@ -203,7 +205,8 @@ def generates_templates(base_heat_template, deployment_configuration): # Save the metadata on a JSON file with open(new_template + ".json", 'w') as outfile: - json.dump(metadata, outfile) + # sort keys to maintain persistent order for git + jsonutils.dump(metadata, outfile, sort_keys=True) common.LOG.debug("Heat Templates and Metadata file " + str(counter) + " created") @@ -222,7 +225,7 @@ def get_all_heat_templates(template_dir, template_file_extension): (type: str) :return: type: list """ - template_files = list() + template_files = [] for dirname, dirnames, filenames in os.walk(template_dir): for filename in filenames: if template_file_extension in filename and \ diff --git a/yardstick/vTC/apexlake/tests/data/generated_templates/experiment_1.yaml.json b/yardstick/vTC/apexlake/tests/data/generated_templates/experiment_1.yaml.json index 3af9a1cc7..44a8aeb2e 100644 --- a/yardstick/vTC/apexlake/tests/data/generated_templates/experiment_1.yaml.json +++ b/yardstick/vTC/apexlake/tests/data/generated_templates/experiment_1.yaml.json @@ -1 +1 @@ -{"vnic_type": "normal", "ram": "1024", "vcpus": "2"}
\ No newline at end of file +{"ram": "1024", "vcpus": "2", "vnic_type": "normal"}
\ No newline at end of file diff --git a/yardstick/vTC/apexlake/tests/data/generated_templates/experiment_2.yaml.json b/yardstick/vTC/apexlake/tests/data/generated_templates/experiment_2.yaml.json index 9f246891d..0a66448b7 100644 --- a/yardstick/vTC/apexlake/tests/data/generated_templates/experiment_2.yaml.json +++ b/yardstick/vTC/apexlake/tests/data/generated_templates/experiment_2.yaml.json @@ -1 +1 @@ -{"vnic_type": "direct", "ram": "1024", "vcpus": "2"}
\ No newline at end of file +{"ram": "1024", "vcpus": "2", "vnic_type": "direct"}
\ No newline at end of file |