diff options
25 files changed, 638 insertions, 67 deletions
diff --git a/gui/app/images/logo.png b/gui/app/images/logo.png Binary files differnew file mode 100644 index 000000000..c67c0d635 --- /dev/null +++ b/gui/app/images/logo.png diff --git a/gui/app/scripts/controllers/report.controller.js b/gui/app/scripts/controllers/report.controller.js index 9b6b5958b..6a62cf8ea 100644 --- a/gui/app/scripts/controllers/report.controller.js +++ b/gui/app/scripts/controllers/report.controller.js @@ -54,7 +54,7 @@ angular.module('yardStickGui2App') } $scope.goToExternal = function goToExternal(id) { - var url = External_URL + ':' + $scope.jumpPort + '/dashboard/db' + '/' + id; + var url = Grafana_URL +':'+$scope.jumpPort+'/dashboard/db'+ '/' + id; window.open(url, '_blank'); } diff --git a/gui/app/views/environmentList.html b/gui/app/views/environmentList.html index 29273a724..1b00b1cc6 100644 --- a/gui/app/views/environmentList.html +++ b/gui/app/views/environmentList.html @@ -22,21 +22,18 @@ <div dir-paginate="env in environmentList | orderBy:'-id' | itemsPerPage: 10 "> <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;"> - <div> <a style="color:#e95420" ng-click="gotoDetail('false',env.uuid)">{{env.name}}</a></div> + <div> <a style="color:#4dc5cf" ng-click="gotoDetail('false',env.uuid)">{{env.name}}</a></div> <div> <!-- <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(env.uuid,'environment')">Delete</button> --> <div class="btn-group" uib-dropdown is-open="status.isopen" style="margin-right:60px;"> <button id="single-button" type="button" class="btn btn-default btn-sm" uib-dropdown-toggle> - Modify <span class="caret"></span> + delete <span class="caret"></span> </button> <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button"> - <li role="menuitem"><a ng-click="openDeleteEnv(env.uuid,'environment')">Delete</a></li> - <!-- <li role="menuitem"><a href="#">Another action</a></li> - <li role="menuitem"><a href="#">Something else here</a></li> - <li class="divider"></li> - <li role="menuitem"><a href="#">Separated link</a></li> --> + <li role="menuitem"><a ng-click="openDeleteEnv(env.uuid,'environment')">delete</a></li> + </ul> </div> </div> diff --git a/gui/app/views/layout/header.html b/gui/app/views/layout/header.html index 033322a62..ad90de952 100644 --- a/gui/app/views/layout/header.html +++ b/gui/app/views/layout/header.html @@ -4,8 +4,9 @@ <div class="navbar-header"> - + <img src="images/logo.png" style="width:50px;height:50px;float:left;margin-left:20px;" /> <a class="navbar-brand" href="#/">Yardstick</a> + </div> @@ -33,11 +34,11 @@ .navbar { border-radius: 0px; - background-color: #e95420; + background-color: #CAEEF1; color: #fff; } .navbar-default .navbar-brand { - color: #fff; + color: #333; } -</style> +</style>
\ No newline at end of file diff --git a/gui/app/views/layout/sideNav.html b/gui/app/views/layout/sideNav.html index 42dcbbc6e..4fc99cd4f 100644 --- a/gui/app/views/layout/sideNav.html +++ b/gui/app/views/layout/sideNav.html @@ -90,7 +90,7 @@ <style> .bs-sidenav { - margin-top: 40px; + margin-top: 21px; margin-bottom: 20px; width: 124px; } diff --git a/gui/app/views/layout/sideNav2.html b/gui/app/views/layout/sideNav2.html index 104a9c6cf..93e0de4be 100644 --- a/gui/app/views/layout/sideNav2.html +++ b/gui/app/views/layout/sideNav2.html @@ -66,7 +66,7 @@ <style> .bs-sidenav { - margin-top: 40px; + margin-top: 21px; margin-bottom: 20px; width: 124px; } diff --git a/gui/app/views/main.html b/gui/app/views/main.html index d5f7a3af3..36bcbbd3c 100644 --- a/gui/app/views/main.html +++ b/gui/app/views/main.html @@ -105,13 +105,13 @@ } .progressDefine>li.is-complete { - color: #e95420; + color: #4dc5cf; } .progressDefine>li.is-complete:before, .progressDefine>li.is-complete:after { color: #FFF; - background: #e95420; + background: #4dc5cf; } .progressDefine>li.is-active { diff --git a/gui/app/views/main2.html b/gui/app/views/main2.html index 661d604c6..3f49e82e0 100644 --- a/gui/app/views/main2.html +++ b/gui/app/views/main2.html @@ -105,13 +105,13 @@ } .progressDefine>li.is-complete { - color: #e95420; + color: #4dc5cf; } .progressDefine>li.is-complete:before, .progressDefine>li.is-complete:after { color: #FFF; - background: #e95420; + background: #4dc5cf; } .progressDefine>li.is-active { diff --git a/gui/app/views/modal/environmentDialog.html b/gui/app/views/modal/environmentDialog.html index a5b88d240..389de8340 100644 --- a/gui/app/views/modal/environmentDialog.html +++ b/gui/app/views/modal/environmentDialog.html @@ -104,7 +104,7 @@ Next </button> <button class="btn btn-default" ng-click="goToPodPrev()" style="margin-right:5px;float:right"> - Previous + Back </button> </h3> @@ -165,7 +165,7 @@ <h3>{{name}} -- Pod File <div style="float:right"> - <button class="btn btn-default" ng-click="skipPodPrev()">Previous</button> + <button class="btn btn-default" ng-click="skipPodPrev()">Back</button> <button class="btn btn-default" ng-click="skipPod()" ng-show="podData==null">Skip</button> <button class="btn btn-default" ng-click="skipPod()" ng-show="podData!=null">Next</button> @@ -234,7 +234,7 @@ <h3>{{name}} -- Container <div style="float:right"> - <button class="btn btn-default" ng-click="skipContainerPrev()">Previous</button> + <button class="btn btn-default" ng-click="skipContainerPrev()">Back</button> <button class="btn btn-default" ng-click="skipContainer()" ng-show="ifskipOrClose!=1"> Skip </button> diff --git a/gui/app/views/projectList.html b/gui/app/views/projectList.html index ea6e63d6b..6edc32fc1 100644 --- a/gui/app/views/projectList.html +++ b/gui/app/views/projectList.html @@ -11,21 +11,21 @@ <div dw-loading="key" dw-loading-options="{text:'loading'}"> <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;background-color:#f9f9f9;"> <div style="font-weight:600">Name</div> - <div style="font-weight:600;margin-right:4px;">Action</div> + <div style="font-weight:600;margin-right:20px;">Action</div> </div> <div dir-paginate="project in projectListData | orderBy:'-id' | itemsPerPage: 10 "> <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;"> <div> - <a ng-click="gotoDetail(project.uuid)" style="color:#e95420"> {{project.name}}</a> + <a ng-click="gotoDetail(project.uuid)" style="color:#4dc5cf"> {{project.name}}</a> </div> <div> <!-- <button class="btn btn-default btn-sm" ng-click="gotoDetail(project.uuid)">Detail</button> --> <!--<button class="btn btn-default btn-sm" ng-click="openDeleteEnv(project.uuid,'project')">Delete</button>--> - <div class="btn-group" uib-dropdown is-open="status.isopen" style="margin-right:20px;"> + <div class="btn-group" uib-dropdown is-open="status.isopen" > <button id="single-button" type="button" class="btn btn-default btn-sm" uib-dropdown-toggle> - Modify <span class="caret"></span> + delete <span class="caret"></span> </button> <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button"> <li role="menuitem" ng-show="task.status!=0"><a ng-click="openDeleteEnv(project.uuid,'project')">delete</a></li> diff --git a/gui/app/views/projectdetail.html b/gui/app/views/projectdetail.html index ff61c5fed..357a26add 100644 --- a/gui/app/views/projectdetail.html +++ b/gui/app/views/projectdetail.html @@ -24,8 +24,8 @@ </tr> <tr dir-paginate="task in finalTaskListDisplay | orderBy:'-id' | itemsPerPage: 6 " pagination-id="table"> - <td width="10%"> <a ng-click="gotoDetail(task.uuid)" style="color:#e95420"> {{task.name}} </a></td> - <td width="40%"> + <td width="20%"> <a ng-click="gotoDetail(task.uuid)" style="color:#4dc5cf"> {{task.name}} </a></td> + <td width="70%"> <div class="progree-parent" ng-show="task.status!=2"> <div class="progree-child" ng-style="{'width':task.stausWidth}"> </div> @@ -37,11 +37,11 @@ </td> - <td width="50%"> + <td width="10%"> - <div class="btn-group" uib-dropdown is-open="status.isopen" style="margin-right:20px;"> + <div class="btn-group" uib-dropdown is-open="status.isopen"> <button id="single-button" type="button" class="btn btn-default btn-sm" uib-dropdown-toggle> - Modify <span class="caret"></span> + modify <span class="caret"></span> </button> <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button"> <li role="menuitem" ng-show="task.status!=0"><a ng-click="runAtaskForTable(task.uuid)">run</a></li> diff --git a/gui/app/views/suite.html b/gui/app/views/suite.html index 8e1348333..652cf1e0e 100644 --- a/gui/app/views/suite.html +++ b/gui/app/views/suite.html @@ -9,39 +9,44 @@ </button> - <!--<div ng-show="displayOpenrcFile!=null || displayOpenrcFile!=undefined"> - {{displayOpenrcFile.name}} last modified: {{filelastModified}} - </div>--> + <hr/> - <!--<div ng-repeat="env in environmentList"> - {{env.name}} - </div>--> + <div dw-loading="key" dw-loading-options="{text:'loading'}"> - <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;background-color: #f9f9f9;" > - <div style="font-weight:600">Name</div> - <div style="font-weight:600;margin-right:4px;">Operate</div> + <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;background-color: #f9f9f9;"> + <div style="font-weight:600">Name</div> + <div style="font-weight:600;margin-right:20px;">Action</div> - </div> + </div> - <div dir-paginate="suite in testsuitlist | itemsPerPage: 10"> - <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;"> - <div> - <a style="color:#e95420" ng-click="gotoDetail(suite)"> {{suite}} + <div dir-paginate="suite in testsuitlist | itemsPerPage: 10"> + <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;"> + <div> + <a style="color:#4dc5cf" ng-click="gotoDetail(suite)"> {{suite}} </a> </div> - <div> - <!-- <button class="btn btn-default btn-sm" ng-click="gotoDetail(suite)">Detail</button> --> - <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(suite,'test suite')">Delete</button> + <div> + <!-- <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(suite,'test suite')">Delete</button> --> + <div class="btn-group" uib-dropdown is-open="status.isopen"> + <button id="single-button" type="button" class="btn btn-default btn-sm" uib-dropdown-toggle> + delete <span class="caret"></span> + </button> + <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button"> + <li role="menuitem"><a ng-click="openDeleteEnv(suite,'test suite')">delete</a></li> + + </ul> + </div> + + </div> + </div> </div> - - </div> - <center> - <dir-pagination-controls></dir-pagination-controls> - </center> + <center> + <dir-pagination-controls></dir-pagination-controls> + </center> </div> @@ -146,4 +151,4 @@ background-color: #EEEEEE; border-radius: 5px; } -</style> +</style>
\ No newline at end of file diff --git a/gui/app/views/testcaselist.html b/gui/app/views/testcaselist.html index 3e8cfccf9..62237faa8 100644 --- a/gui/app/views/testcaselist.html +++ b/gui/app/views/testcaselist.html @@ -20,7 +20,7 @@ <div dw-loading="key" dw-loading-options="{text:'loading'}"> <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;background-color: #f9f9f9"> <div style="font-weight:600">Name</div> - <div style="font-weight:600;margin-right:4px;">Operate</div> + <div style="font-weight:600;margin-right:20px;">Action</div> </div> @@ -28,14 +28,22 @@ <div style="display:flex;flex-direction:row;justify-content:space-between;padding:8px;border-top: 1px solid #e9ecec;"> <div> - <a style="color:#e95420" ng-click="gotoDetail(test.Name)"> + <a style="color:#4dc5cf" ng-click="gotoDetail(test.Name)"> {{test.Name}} </a> </div> <div style="font-size:10px;">{{test.Description}}</div> <div> - <!-- <button class="btn btn-default btn-sm" ng-click="gotoDetail(test.Name)">Detail</button> --> - <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(test.Name,'test case')">Delete</button> + <!-- <button class="btn btn-default btn-sm" ng-click="openDeleteEnv(test.Name,'test case')">Delete</button> --> + <div class="btn-group" uib-dropdown is-open="status.isopen" > + <button id="single-button" type="button" class="btn btn-default btn-sm" uib-dropdown-toggle> + delete <span class="caret"></span> + </button> + <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button"> + <li role="menuitem"><a ng-click="openDeleteEnv(test.Name,'test case')">delete</a></li> + + </ul> + </div> </div> </div> diff --git a/gui/bower.json b/gui/bower.json index 6da3bee3c..d1d934f64 100644 --- a/gui/bower.json +++ b/gui/bower.json @@ -21,6 +21,9 @@ "angular-bootstrap": "^2.5.0", "angular-sanitize": "^1.6.5" }, + "resolutions": { + "angular": "~1.6.x" + }, "devDependencies": { "angular-mocks": "^1.4.0" }, diff --git a/install.sh b/install.sh index e82ae0233..8a5050a61 100755 --- a/install.sh +++ b/install.sh @@ -89,6 +89,7 @@ pip install -e . /bin/bash "${PWD}/docker/uwsgi.sh" /bin/bash "${PWD}/docker/nginx.sh" cd "${PWD}/gui" && /bin/bash gui.sh +mkdir -p /etc/nginx/yardstick mv dist /etc/nginx/yardstick/gui service nginx restart diff --git a/run_tests.sh b/run_tests.sh index 2519d94f6..2cf54c708 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -13,6 +13,9 @@ getopts ":f" FILE_OPTION +# don't write .pyc files this can cause odd unittest results +export PYTHONDONTWRITEBYTECODE=1 + run_flake8() { echo "Running flake8 ... " logfile=test_results.log diff --git a/samples/container_ping_vm.yaml b/samples/container_ping_vm.yaml new file mode 100644 index 000000000..4b7b64f68 --- /dev/null +++ b/samples/container_ping_vm.yaml @@ -0,0 +1,57 @@ +############################################################################## +# 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.openstack + + runner: + type: Duration + duration: 60 + interval: 1 + + sla: + max_rtt: 10 + action: monitor + +contexts: +- + 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'] +- + type: Heat + name: openstack + image: cirros-0.3.5 + flavor: yardstick-flavor + user: cirros + + servers: + target: + floating_ip: true + + networks: + test: + cidr: '10.0.1.0/24' diff --git a/samples/migrate-node-context.yaml b/samples/migrate-node-context.yaml new file mode 100644 index 000000000..9fe1acf78 --- /dev/null +++ b/samples/migrate-node-context.yaml @@ -0,0 +1,40 @@ +--- + +schema: "yardstick:task:0.1" + +scenarios: +- + type: QemuMigrate + options: + smp: 2 + migrate_to_port: 4444 + incoming_ip: 0 + qmp_src_path: "/tmp/qmp-sock-src" + qmp_dst_path: "/tmp/qmp-sock-dst" + max_down_time: "0.10" + host: kvm.LF + runner: + type: Duration + duration: 1 + interval: 1 + sla: + max_totaltime: 10 + max_downtime: 0.10 + max_setuptime: 0.50 + action: monitor + setup_options: + rpm_dir: "/opt/rpm" + script_dir: "/opt/scripts" + image_dir: "/opt/image" + host_setup_seqs: + - "host-setup0.sh" + - "reboot" + - "host-setup1.sh" + - "setup-ovsdpdk.sh" + - "host-install-qemu.sh" + - "host-run-qemu4lm.sh" + +context: + type: Node + name: LF + file: /root/yardstick/pod.yaml diff --git a/tests/ci/cover.sh b/tests/ci/cover.sh index 71833757a..822ed2ff2 100644 --- a/tests/ci/cover.sh +++ b/tests/ci/cover.sh @@ -34,7 +34,10 @@ run_coverage_test() { git checkout HEAD^ baseline_report=$(mktemp -t yardstick_coverageXXXXXXX) - find . -type f -name "*.pyc" -delete && python setup.py testr --coverage --testr-args="$*" + # workaround 'db type could not be determined' bug + # https://bugs.launchpad.net/testrepository/+bug/1229445 + rm -rf .testrepository + find . -type f -name "*.pyc" -delete && python setup.py testr --coverage --slowest --testr-args="$*" coverage report > $baseline_report baseline_missing=$(awk 'END { print $3 }' $baseline_report) @@ -44,7 +47,10 @@ run_coverage_test() { # Generate and save coverage report current_report=$(mktemp -t yardstick_coverageXXXXXXX) - find . -type f -name "*.pyc" -delete && python setup.py testr --coverage --testr-args="$*" + # workaround 'db type could not be determined' bug + # https://bugs.launchpad.net/testrepository/+bug/1229445 + rm -rf .testrepository + find . -type f -name "*.pyc" -delete && python setup.py testr --coverage --slowest --testr-args="$*" coverage report > $current_report current_missing=$(awk 'END { print $3 }' $current_report) diff --git a/tests/opnfv/test_suites/opnfv_os-odl-sfc-ha_daily.yaml b/tests/opnfv/test_suites/opnfv_os-odl-sfc-ha_daily.yaml new file mode 100644 index 000000000..b464bfeae --- /dev/null +++ b/tests/opnfv/test_suites/opnfv_os-odl-sfc-ha_daily.yaml @@ -0,0 +1,62 @@ +############################################################################## +# 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 +############################################################################## +--- +# os-odl-sfc-ha daily task suite + +schema: "yardstick:suite:0.1" + +name: "os-odl-sfc-ha" +test_cases_dir: "tests/opnfv/test_cases/" +test_cases: +- + file_name: opnfv_yardstick_tc002.yaml +- + file_name: opnfv_yardstick_tc005.yaml +- + file_name: opnfv_yardstick_tc010.yaml +- + file_name: opnfv_yardstick_tc011.yaml +- + file_name: opnfv_yardstick_tc012.yaml +- + file_name: opnfv_yardstick_tc014.yaml +- + file_name: opnfv_yardstick_tc037.yaml +- + file_name: opnfv_yardstick_tc055.yaml + constraint: + installer: compass + pod: huawei-pod1 + task_args: + huawei-pod1: '{"file": "etc/yardstick/nodes/compass_sclab_physical/pod.yaml", + "host": "node5.yardstick-TC055"}' +- + file_name: opnfv_yardstick_tc063.yaml + constraint: + installer: compass + pod: huawei-pod1 + task_args: + huawei-pod1: '{"file": "etc/yardstick/nodes/compass_sclab_physical/pod.yaml", + "host": "node5.yardstick-TC063"}' +- + file_name: opnfv_yardstick_tc069.yaml +- + file_name: opnfv_yardstick_tc070.yaml +- + file_name: opnfv_yardstick_tc071.yaml +- + file_name: opnfv_yardstick_tc072.yaml +- + file_name: opnfv_yardstick_tc075.yaml + constraint: + installer: compass + pod: huawei-pod1 + task_args: + huawei-pod1: '{"file": "etc/yardstick/nodes/compass_sclab_physical/pod.yaml", + "host": "node1.LF"}' diff --git a/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py b/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py new file mode 100644 index 000000000..9514729ba --- /dev/null +++ b/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python + +############################################################################## +# Copyright (c) 2015 Huawei Technologies Co.,Ltd and other. +# +# 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.compute.qemu_migrate.QemuMigrate + +from __future__ import absolute_import + +import unittest + +import mock +from oslo_serialization import jsonutils + +from yardstick.benchmark.scenarios.compute import qemu_migrate + + +@mock.patch('yardstick.benchmark.scenarios.compute.qemu_migrate.ssh') +class QemuMigrateTestCase(unittest.TestCase): + + def setUp(self): + self.scenario_cfg = { + "host": "kvm.LF", + "setup_options": { + "rpm_dir": "/opt/rpm", + "script_dir": "/opt/scripts", + "image_dir": "/opt/image", + "host_setup_seqs": [ + "host-setup0.sh", + "host-setup1.sh", + "setup-ovsdpdk.sh", + "host-install-qemu.sh", + "host-run-qemu4lm.sh" + ] + }, + "sla": { + "action": "monitor", + "max_totaltime": 10, + "max_downtime": 0.10, + "max_setuptime": 0.50 + }, + "options": { + "smp": 99, + "migrate_to_port": 4444, + "incoming_ip": 0, + "qmp_src_path": "/tmp/qmp-sock-src", + "qmp_dst_path": "/tmp/qmp-sock-dst", + "max_down_time": "0.10" + } + } + self.context_cfg = { + "host": { + "ip": "10.229.43.154", + "key_filename": "/yardstick/resources/files/yardstick_key", + "role": "BareMetal", + "name": "kvm.LF", + "user": "root" + } + } + + def test_qemu_migrate_successful_setup(self, mock_ssh): + + q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + + q.setup() + self.assertIsNotNone(q.host) + self.assertEqual(q.setup_done, True) + + def test_qemu_migrate_successful_no_sla(self, mock_ssh): + result = {} + self.scenario_cfg.pop("sla", None) + q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + q.setup() + + sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}' + mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + + q.run(result) + expected_result = jsonutils.loads(sample_output) + self.assertEqual(result, expected_result) + + def test_qemu_migrate_successful_sla(self, mock_ssh): + result = {} + self.scenario_cfg.update({"sla": { + "action": "monitor", + "max_totaltime": 15, + "max_downtime": 2, + "max_setuptime": 1 + } + }) + q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + q.setup() + + sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}' + mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + + q.run(result) + expected_result = jsonutils.loads(sample_output) + self.assertEqual(result, expected_result) + + def test_qemu_migrate_unsuccessful_sla_totaltime(self, mock_ssh): + + result = {} + self.scenario_cfg.update({"sla": {"max_totaltime": 10}}) + q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + q.setup() + + sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}' + + mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + self.assertRaises(AssertionError, q.run, result) + + def test_qemu_migrate_unsuccessful_sla_downtime(self, mock_ssh): + + result = {} + self.scenario_cfg.update({"sla": {"max_downtime": 0.10}}) + q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + q.setup() + + sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}' + + mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + self.assertRaises(AssertionError, q.run, result) + + def test_qemu_migrate_unsuccessful_sla_setuptime(self, mock_ssh): + + result = {} + self.scenario_cfg.update({"sla": {"max_setuptime": 0.50}}) + q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + q.setup() + + sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}' + + mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + self.assertRaises(AssertionError, q.run, result) + + def test_qemu_migrate_unsuccessful_script_error(self, mock_ssh): + + result = {} + self.scenario_cfg.update({"sla": {"max_totaltime": 10}}) + q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + q.setup() + + + mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') + self.assertRaises(RuntimeError, q.run, result) + + +def main(): + unittest.main() + +if __name__ == '__main__': + main() diff --git a/yardstick/benchmark/scenarios/compute/qemu_migrate.py b/yardstick/benchmark/scenarios/compute/qemu_migrate.py new file mode 100644 index 000000000..cee87a545 --- /dev/null +++ b/yardstick/benchmark/scenarios/compute/qemu_migrate.py @@ -0,0 +1,155 @@ +from __future__ import absolute_import +from __future__ import print_function + +import logging +import os +import re +import time + + +import pkg_resources +from oslo_serialization import jsonutils + +import yardstick.ssh as ssh +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) +LOG.setLevel(logging.DEBUG) + + +class QemuMigrate(base.Scenario): + """ + Execute a live migration for two host using qemu + + """ + + __scenario_type__ = "QemuMigrate" + + TARGET_SCRIPT = "qemu_migrate_benchmark.bash" + WORKSPACE = "/root/workspace" + REBOOT_CMD_PATTERN = r";\s*reboot\b" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.setup_done = False + + def _connect_host(self): + host = self.context_cfg["host"] + self.host = ssh.SSH.from_node(host, defaults={"user": "root"}) + self.host.wait(timeout=600) + + def _put_files(self, client): + setup_options = self.scenario_cfg["setup_options"] + script_dir = setup_options["script_dir"] + LOG.debug("Send scripts from %s to workspace %s", + script_dir, self.WORKSPACE) + client.put(script_dir, self.WORKSPACE, recursive=True) + + def _run_setup_cmd(self, client, cmd): + LOG.debug("Run cmd: %s", cmd) + status, stdout, stderr = client.execute(cmd) + if status: + if re.search(self.REBOOT_CMD_PATTERN, cmd): + LOG.debug("Error on reboot") + else: + raise RuntimeError(stderr) + + def _run_host_setup_scripts(self, scripts): + setup_options = self.scenario_cfg["setup_options"] + script_dir = os.path.basename(setup_options["script_dir"]) + + for script in scripts: + cmd = "cd %s/%s; export PATH=./:$PATH; %s" %\ + (self.WORKSPACE, script_dir, script) + self._run_setup_cmd(self.host, cmd) + + if re.search(self.REBOOT_CMD_PATTERN, cmd): + time.sleep(3) + self._connect_host() + + def setup(self): + """scenario setup""" + setup_options = self.scenario_cfg["setup_options"] + host_setup_seqs = setup_options["host_setup_seqs"] + + self._connect_host() + self._put_files(self.host) + self._run_host_setup_scripts(host_setup_seqs) + + # copy script to host + self.target_script = pkg_resources.resource_filename( + "yardstick.benchmark.scenarios.compute", + QemuMigrate.TARGET_SCRIPT) + self.host.put_file(self.target_script, "~/qemu_migrate_benchmark.sh") + + self.setup_done = True + + def run(self, result): + """execute the benchmark""" + + options = self.scenario_cfg["options"] + smp = options.get("smp", 2) + qmp_sock_src = options.get("qmp_src_path", "/tmp/qmp-sock-src") + qmp_sock_dst = options.get("qmp_dst_path", "/tmp/qmp-sock-dst") + incoming_ip = options.get("incoming_ip", 0) + migrate_to_port = options.get("migrate_to_port", 4444) + max_down_time = options.get("max_down_time", 0.10) + cmd_args = " %s %s %s %s %s %s" %\ + (smp, qmp_sock_src, qmp_sock_dst, incoming_ip, + migrate_to_port, max_down_time) + cmd = "bash migrate_benchmark.sh %s" % (cmd_args) + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.host.execute(cmd) + if status: + raise RuntimeError(stderr) + + result.update(jsonutils.loads(stdout)) + + if "sla" in self.scenario_cfg: + sla_error = "" + for t, timevalue in result.items(): + if 'max_%s' % t not in self.scenario_cfg['sla']: + continue + + sla_time = int(self.scenario_cfg['sla'][ + 'max_%s' % t]) + timevalue = int(timevalue) + if timevalue > sla_time: + sla_error += "%s timevalue %d > sla:max_%s(%d); " % \ + (t, timevalue, t, sla_time) + assert sla_error == "", sla_error + + +def _test(): # pragma: no cover + """internal test function""" + key_filename = pkg_resources.resource_filename("yardstick.resources", + "files/yardstick_key") + ctx = { + "host": { + "ip": "10.229.47.137", + "user": "root", + "key_filename": key_filename + } + } + + logger = logging.getLogger("yardstick") + logger.setLevel(logging.DEBUG) + options = { + "smp": 2, + "migrate_to_port": 4444, + "incoming_ip": 0, + "qmp_sock_src": "/tmp/qmp-sock-src", + "qmp_sock_dst": "/tmp/qmp-sock-dst", + "max_down_time": 0.10 + } + args = { + "options": options + } + result = {} + migrate = QemuMigrate(args, ctx) + migrate.run(result) + print(result) + +if __name__ == '__main__': # pragma: no cover + _test() diff --git a/yardstick/benchmark/scenarios/compute/qemu_migrate_benchmark.bash b/yardstick/benchmark/scenarios/compute/qemu_migrate_benchmark.bash new file mode 100644 index 000000000..552098103 --- /dev/null +++ b/yardstick/benchmark/scenarios/compute/qemu_migrate_benchmark.bash @@ -0,0 +1,68 @@ +#!/bin/bash + +############################################################################# +#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 +############################################################################## + +set -e + +# Commandline arguments + +src=$2 +dst_ip=$4 +migrate_to_port=$5 +max_down_time=$6 + +OUTPUT_FILE=/tmp/output-qemu.log + +do_migrate() +{ +# local src=`echo $OPTIONS | cut -d ':' -f 2 | cut -d ',' -f 1` + echo "info status" | nc -U $src + # with no speed limit + echo "migrate_set_speed 0" |nc -U $src + # set the expected max downtime + echo "migrate_set_downtime ${max_down_time}" |nc -U $src + # start live migration + echo "migrate -d tcp:${dst_ip}:$migrate_to_port" |nc -U $src + # wait until live migration completed + status="" + while [ "${status}" == "" ] + do + status=`echo "info migrate" | nc -U $src |grep completed | cut -d: -f2` + echo ${status} + sleep 1; + done +} >/dev/null + +output_qemu() +{ + # print detail information + echo "info migrate" | nc -U $src + echo "quit" | nc -U $src + sleep 5 + +} > $OUTPUT_FILE + +output_json() +{ +totaltime=$(grep "total time" $OUTPUT_FILE | cut -d' ' -f3) +downtime=$(grep "downtime" $OUTPUT_FILE | cut -d' ' -f2) +setuptime=$(grep "setup" $OUTPUT_FILE | cut -d' ' -f2) +echo -e "{ \ + \"totaltime\":\"$totaltime\", \ + \"downtime\":\"$downtime\", \ + \"setuptime\":\"$setuptime\" \ + }" +} +# main entry +main() +{ + do_migrate +} +main diff --git a/yardstick/cmd/NSBperf.py b/yardstick/cmd/NSBperf.py index 4e7590ea5..2dc0f65e7 100755 --- a/yardstick/cmd/NSBperf.py +++ b/yardstick/cmd/NSBperf.py @@ -30,13 +30,6 @@ from six.moves import input CLI_PATH = os.path.dirname(os.path.realpath(__file__)) REPO_PATH = os.path.abspath(os.path.join(CLI_PATH, os.pardir)) -PYTHONPATH = os.environ.get("PYTHONPATH", False) -VIRTUAL_ENV = os.environ.get("VIRTUAL_ENV", False) - - -if not PYTHONPATH or not VIRTUAL_ENV: - print("Please setup env PYTHONPATH & VIRTUAL_ENV environment varaible.") - raise SystemExit(1) def sigint_handler(*args, **kwargs): diff --git a/yardstick/cmd/commands/task.py b/yardstick/cmd/commands/task.py index 03f6b1b1e..8d8ea2b3c 100644 --- a/yardstick/cmd/commands/task.py +++ b/yardstick/cmd/commands/task.py @@ -51,11 +51,17 @@ class TaskCommands(object): # pragma: no cover self.output_file = param.output_file try: - Task().start(param, **kwargs) + result = Task().start(param, **kwargs) except Exception as e: self._write_error_data(e) LOG.exception("") + if result.get('result', {}).get('criteria') == 'PASS': + LOG.info('Task Success') + else: + LOG.info('Task Failed') + raise RuntimeError('Task Failed') + def _write_error_data(self, error): data = {'status': 2, 'result': str(error)} write_json_to_file(self.output_file, data) |