diff options
79 files changed, 945 insertions, 690 deletions
diff --git a/api/resources/v1/env.py b/api/resources/v1/env.py index 8367fa9eb..98b8ec7e4 100644 --- a/api/resources/v1/env.py +++ b/api/resources/v1/env.py @@ -31,7 +31,7 @@ from yardstick.common import utils from yardstick.common.utils import result_handler from yardstick.common import openstack_utils from yardstick.common.httpClient import HttpClient - +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) @@ -393,7 +393,7 @@ class V1Env(ApiResource): return result_handler(consts.API_ERROR, 'file must be provided') LOG.info('Checking file') - data = yaml.safe_load(pod_file.read()) + data = yaml_load(pod_file.read()) if not isinstance(data, collections.Mapping): return result_handler(consts.API_ERROR, 'invalid yaml file') diff --git a/api/resources/v2/pods.py b/api/resources/v2/pods.py index f2316d353..d98238ca1 100644 --- a/api/resources/v2/pods.py +++ b/api/resources/v2/pods.py @@ -18,6 +18,7 @@ from api.database.v2.handlers import V2EnvironmentHandler from yardstick.common import constants as consts from yardstick.common.utils import result_handler from yardstick.common.task_template import TaskTemplate +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) @@ -48,7 +49,7 @@ class V2Pods(ApiResource): upload_file.save(consts.POD_FILE) with open(consts.POD_FILE) as f: - data = yaml.safe_load(TaskTemplate.render(f.read())) + data = yaml_load(TaskTemplate.render(f.read())) LOG.debug('pod content is: %s', data) LOG.info('create pod in database') diff --git a/gui/app/scripts/controllers/container.controller.js b/gui/app/scripts/controllers/container.controller.js index 6c2ccd8ff..3ad200a91 100644 --- a/gui/app/scripts/controllers/container.controller.js +++ b/gui/app/scripts/controllers/container.controller.js @@ -128,7 +128,7 @@ angular.module('yardStickGui2App') $scope.selectContainer = name; } $scope.goBack = function goBack() { - $state.go('app2.projectList'); + $state.go('app.projectList'); } $scope.openDeleteEnv = function openDeleteEnv(id, name) { diff --git a/gui/app/scripts/controllers/content.controller.js b/gui/app/scripts/controllers/content.controller.js index d2bc19eea..0288fa540 100644 --- a/gui/app/scripts/controllers/content.controller.js +++ b/gui/app/scripts/controllers/content.controller.js @@ -2,7 +2,7 @@ angular.module('yardStickGui2App') .controller('ContentController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', '$location', '$localStorage', - function($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, $localStorage) { + function ($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, $localStorage) { @@ -11,10 +11,11 @@ angular.module('yardStickGui2App') $scope.showEnvironment = false; $scope.counldGoDetail = false; $scope.activeStatus = 0; + $scope.ifshowEnvChild = false; - $scope.$watch(function() { + $scope.$watch(function () { return location.hash - }, function(newvalue, oldvalue) { + }, function (newvalue, oldvalue) { if (location.hash.indexOf('project') > -1) { $scope.projectShow = true; $scope.taskShow = false; @@ -26,6 +27,13 @@ angular.module('yardStickGui2App') $scope.reportShow = true; $scope.taskShow = true; $scope.projectShow = true; + } else if (location.hash.indexOf('envDetail') > -1 || location.hash.indexOf('envimageDetail') > -1 || + location.hash.indexOf('envpodupload') > -1 || location.hash.indexOf('envcontainer') > -1) { + $scope.ifshowEnvChild = true; + $scope.activeStatus=0; + }else{ + $scope.ifshowEnvChild=false; + $scope.activeStatus=-1; } }) @@ -88,30 +96,30 @@ angular.module('yardStickGui2App') } function gotoTestcase() { - $state.go('app2.testcase'); + $state.go('app.testcase'); } function gotoEnviron() { if ($location.path().indexOf('env') > -1 || $location.path().indexOf('environment') > -1) { $scope.counldGoDetail = true; } - $state.go('app2.environment'); + $state.go('app.environment'); } function gotoSuite() { - $state.go('app2.testsuite'); + $state.go('app.testsuite'); } function gotoProject() { - $state.go('app2.projectList'); + $state.go('app.projectList'); } function gotoTask() { - $state.go('app2.tasklist'); + $state.go('app.tasklist'); } function gotoReport() { - $state.go('app2.report'); + $state.go('app.report'); } function goBack() { @@ -119,7 +127,7 @@ angular.module('yardStickGui2App') return; } else if ($location.path().indexOf('main/envDetail/') || $location.path().indexOf('main/imageDetail/') || $location.path().indexOf('main/podupload/') || $location.path().indexOf('main/container/')) { - $state.go('app2.environment'); + $state.go('app.environment'); return; } else { window.history.back(); @@ -133,4 +141,4 @@ angular.module('yardStickGui2App') } - ]);
\ No newline at end of file + ]); diff --git a/gui/app/scripts/controllers/detail.controller.js b/gui/app/scripts/controllers/detail.controller.js index 3e2eaa100..bfdb525f7 100644 --- a/gui/app/scripts/controllers/detail.controller.js +++ b/gui/app/scripts/controllers/detail.controller.js @@ -108,6 +108,7 @@ angular.module('yardStickGui2App') //buildtoEnvInfo function buildToEnvInfo(object) { + $scope.envInfo=[]; var tempKeyArray = Object.keys(object); for (var i = 0; i < tempKeyArray.length; i++) { @@ -118,7 +119,11 @@ angular.module('yardStickGui2App') value: tempValue }; $scope.envInfo.push(temp); + } + + console.log($scope.envInfo); + console.log($scope.openrcInfo); } function uploadFiles($file, $invalidFiles) { diff --git a/gui/app/scripts/controllers/image.controller.js b/gui/app/scripts/controllers/image.controller.js index 53acff405..f6c91592f 100644 --- a/gui/app/scripts/controllers/image.controller.js +++ b/gui/app/scripts/controllers/image.controller.js @@ -149,7 +149,7 @@ angular.module('yardStickGui2App') } $scope.goBack = function goBack() { - $state.go('app2.projectList'); + $state.go('app.projectList'); } $scope.goNext = function goNext() { diff --git a/gui/app/scripts/controllers/main.js b/gui/app/scripts/controllers/main.js index e3e880e62..ab76bf0f2 100644 --- a/gui/app/scripts/controllers/main.js +++ b/gui/app/scripts/controllers/main.js @@ -18,11 +18,7 @@ angular.module('yardStickGui2App') $scope.showNextPod = null; $scope.displayContainerInfo = []; $scope.containerList = [{ value: 'create_influxdb', name: "InfluxDB" }, { value: 'create_grafana', name: "Grafana" }] - $scope.items = [ - 'The first choice!', - 'And another choice for you.', - 'but wait! A third!' - ]; + $scope.$on('$destroy', function() { $interval.cancel($scope.intervalImgae) }); @@ -381,7 +377,7 @@ angular.module('yardStickGui2App') $scope.goBack = function goBack() { - $state.go('app2.projectList'); + $state.go('app.projectList'); } $scope.displayContainerInfo = []; diff --git a/gui/app/scripts/controllers/pod.controller.js b/gui/app/scripts/controllers/pod.controller.js index 3ef236854..56dfee148 100644 --- a/gui/app/scripts/controllers/pod.controller.js +++ b/gui/app/scripts/controllers/pod.controller.js @@ -113,7 +113,7 @@ angular.module('yardStickGui2App') } $scope.goBack = function goBack() { - $state.go('app2.projectList'); + $state.go('app.projectList'); } diff --git a/gui/app/scripts/controllers/project.controller.js b/gui/app/scripts/controllers/project.controller.js index 0a7b8b932..197474567 100644 --- a/gui/app/scripts/controllers/project.controller.js +++ b/gui/app/scripts/controllers/project.controller.js @@ -91,7 +91,7 @@ angular.module('yardStickGui2App') } function gotoDetail(id) { - $state.go('app2.projectdetail', { projectId: id }) + $state.go('app.projectdetail', { projectId: id }) } diff --git a/gui/app/scripts/controllers/projectDetail.controller.js b/gui/app/scripts/controllers/projectDetail.controller.js index a616f3ee7..843f66c57 100644 --- a/gui/app/scripts/controllers/projectDetail.controller.js +++ b/gui/app/scripts/controllers/projectDetail.controller.js @@ -606,16 +606,16 @@ angular.module('yardStickGui2App') function gotoDetail(id) { - $state.go('app2.tasklist', { taskId: id }); + $state.go('app.tasklist', { taskId: id }); } function gotoReport(id) { - $state.go('app2.report', { taskId: id }); + $state.go('app.report', { taskId: id }); } function gotoModify(id) { - $state.go('app2.taskModify', { taskId: id }); + $state.go('app.taskModify', { taskId: id }); } function goBack() { diff --git a/gui/app/scripts/controllers/testcase.controller.js b/gui/app/scripts/controllers/testcase.controller.js index 616ceb4a8..c93fd8cb0 100644 --- a/gui/app/scripts/controllers/testcase.controller.js +++ b/gui/app/scripts/controllers/testcase.controller.js @@ -41,7 +41,7 @@ angular.module('yardStickGui2App') } function gotoDetail(name) { - $state.go('app2.testcasedetail', { name: name }); + $state.go('app.testcasedetail', { name: name }); } @@ -93,7 +93,7 @@ angular.module('yardStickGui2App') } $scope.goBack = function goBack() { - $state.go('app2.projectList'); + $state.go('app.projectList'); } $scope.openDeleteEnv = function openDeleteEnv(id, name) { diff --git a/gui/app/scripts/controllers/testsuit.controller.js b/gui/app/scripts/controllers/testsuit.controller.js index abc9095c7..a15daa776 100644 --- a/gui/app/scripts/controllers/testsuit.controller.js +++ b/gui/app/scripts/controllers/testsuit.controller.js @@ -41,16 +41,16 @@ angular.module('yardStickGui2App') function gotoDetail(name) { var temp = name.split('.')[0]; - $state.go('app2.suitedetail', { name: temp }) + $state.go('app.suitedetail', { name: temp }) } function gotoCreateSuite() { - $state.go('app2.suitcreate'); + $state.go('app.suitcreate'); } $scope.goBack = function goBack() { - $state.go('app2.projectList'); + $state.go('app.projectList'); } diff --git a/gui/app/scripts/router.config.js b/gui/app/scripts/router.config.js index 9d3c045bd..da2eb086b 100644 --- a/gui/app/scripts/router.config.js +++ b/gui/app/scripts/router.config.js @@ -20,14 +20,6 @@ angular.module('yardStickGui2App') $stateProvider - .state('app2', { - url: "/main", - controller: 'ContentController', - templateUrl: "views/main2.html", - ncyBreadcrumb: { - label: 'Main' - } - }) .state('app', { url: "/main", controller: 'ContentController', @@ -37,7 +29,7 @@ angular.module('yardStickGui2App') } }) - .state('app2.environment', { + .state('app.environment', { url: '/environment', templateUrl: 'views/environmentList.html', controller: 'MainCtrl', @@ -45,7 +37,7 @@ angular.module('yardStickGui2App') label: 'Environment' } }) - .state('app2.testcase', { + .state('app.testcase', { url: '/testcase', templateUrl: 'views/testcaselist.html', controller: 'TestcaseController', @@ -53,7 +45,7 @@ angular.module('yardStickGui2App') label: 'Test Case' } }) - .state('app2.testsuite', { + .state('app.testsuite', { url: '/suite', templateUrl: 'views/suite.html', controller: 'SuiteListController', @@ -61,7 +53,7 @@ angular.module('yardStickGui2App') label: 'Test Suite' } }) - .state('app2.suitcreate', { + .state('app.suitcreate', { url: '/suitcreate', templateUrl: 'views/testcasechoose.html', controller: 'suitcreateController', @@ -69,7 +61,7 @@ angular.module('yardStickGui2App') label: 'Suite Create' } }) - .state('app2.testcasedetail', { + .state('app.testcasedetail', { url: '/testdetail/:name', templateUrl: 'views/testcasedetail.html', controller: 'testcaseDetailController', @@ -78,7 +70,7 @@ angular.module('yardStickGui2App') }, params: { name: null } }) - .state('app2.suitedetail', { + .state('app.suitedetail', { url: '/suitedetail/:name', templateUrl: 'views/suitedetail.html', controller: 'suiteDetailController', @@ -124,7 +116,7 @@ angular.module('yardStickGui2App') label: 'Container Manage' } }) - .state('app2.projectList', { + .state('app.projectList', { url: '/project', templateUrl: 'views/projectList.html', controller: 'ProjectController', @@ -133,7 +125,7 @@ angular.module('yardStickGui2App') } }) - .state('app2.tasklist', { + .state('app.tasklist', { url: '/task/:taskId', templateUrl: 'views/taskList.html', controller: 'TaskController', @@ -143,7 +135,7 @@ angular.module('yardStickGui2App') } }) - .state('app2.taskLog', { + .state('app.taskLog', { url: '/task/:taskId/log', templateUrl: 'views/taskLog.html', controller: 'TaskLogController', @@ -153,7 +145,7 @@ angular.module('yardStickGui2App') } }) - .state('app2.report', { + .state('app.report', { url: '/report/:taskId', templateUrl: 'views/report.html', controller: 'ReportController', @@ -163,7 +155,7 @@ angular.module('yardStickGui2App') } }) - .state('app2.projectdetail', { + .state('app.projectdetail', { url: '/projectdetail/:projectId', templateUrl: 'views/projectdetail.html', controller: 'ProjectDetailController', @@ -173,7 +165,7 @@ angular.module('yardStickGui2App') } }) - .state('app2.taskModify', { + .state('app.taskModify', { url: '/taskModify/:taskId', templateUrl: 'views/taskmodify.html', controller: 'TaskModifyController', diff --git a/gui/app/styles/main.css b/gui/app/styles/main.css index e13a66bce..d2ea8ba42 100644 --- a/gui/app/styles/main.css +++ b/gui/app/styles/main.css @@ -20,6 +20,8 @@ body { } + + /* Custom page header */ .header { @@ -206,3 +208,7 @@ input:focus{outline: 0} overflow: hidden; } +.bs-sidenav{ + margin-top:21px !important; +} + diff --git a/gui/app/views/layout/sideNav.html b/gui/app/views/layout/sideNav.html index 4fc99cd4f..6c4426307 100644 --- a/gui/app/views/layout/sideNav.html +++ b/gui/app/views/layout/sideNav.html @@ -18,7 +18,7 @@ </div> </div> - <div class="panel-group" role="tablist" aria-multiselectable="true" bs-collapse style="margin-bottom:0px;" ng-model="activeStatus"> + <div class="panel-group" role="tablist" aria-multiselectable="true" bs-collapse style="margin-bottom:0px;" ng-model="activeStatus" ng-if="ifshowEnvChild"> <div class="panel panel-default"> <div class="panel-heading" role="tab"> <h4 class="panel-title"> @@ -48,6 +48,19 @@ </div> </div> </div> + <div class="panel-group" role="tablist" aria-multiselectable="false" bs-collapse style="margin-bottom:0px;" ng-if="!ifshowEnvChild"> + <div class="panel panel-default"> + <div class="panel-heading" role="tab"> + <h4 class="panel-title"> + <a bs-collapse-toggle style=" text-decoration: none;"> + <div style="display:inline;" ng-click="gotoEnviron()">Environment </div> + <!--<i class="fa fa-sort-asc" aria-hidden="true" style="margin-left: 71px;display:inline"></i>--> + </a> + </h4> + </div> + + </div> + </div> <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; "> <div class="panel panel-default "> @@ -138,4 +151,4 @@ .active.panel-body { background-color: #dfe3e4; } -</style> +</style>
\ No newline at end of file diff --git a/gui/app/views/layout/sideNav2.html b/gui/app/views/layout/sideNav2.html deleted file mode 100644 index 93e0de4be..000000000 --- a/gui/app/views/layout/sideNav2.html +++ /dev/null @@ -1,108 +0,0 @@ -<div class="naviSide"> - - - <ul class="nav bs-sidenav"> - - <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; "> - <div class="panel panel-default "> - <div class="panel-heading " role="tab "> - <h4 class="panel-title "> - <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoProject();"> - Project - </a> - </h4> - - </div> - - </div> - </div> - <div class="panel-group" role="tablist" aria-multiselectable="false" bs-collapse style="margin-bottom:0px;"> - <div class="panel panel-default"> - <div class="panel-heading" role="tab"> - <h4 class="panel-title"> - <a bs-collapse-toggle style=" text-decoration: none;"> - <div style="display:inline;" ng-click="gotoEnviron()">Environment </div> - <!--<i class="fa fa-sort-asc" aria-hidden="true" style="margin-left: 71px;display:inline"></i>--> - </a> - </h4> - </div> - - </div> - </div> - - <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; "> - <div class="panel panel-default "> - <div class="panel-heading " role="tab "> - <h4 class="panel-title "> - <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoTestcase()"> - Test Case - </a> - </h4> - - </div> - - </div> - </div> - - <div class="panel-group " role="tablist " aria-multiselectable="true " bs-collapse style="margin-bottom:0px; "> - <div class="panel panel-default "> - <div class="panel-heading " role="tab "> - <h4 class="panel-title "> - <a bs-collapse-toggle style=" text-decoration: none;" ng-click="gotoSuite()"> - Test Suite - </a> - </h4> - - </div> - - </div> - </div> - - - - </ul> - -</div> - -<style> - .bs-sidenav { - margin-top: 21px; - margin-bottom: 20px; - width: 124px; - } - - .nav { - margin-bottom: 0; - padding-left: 0; - list-style: none; - } - - .nav>li { - position: relative; - display: block; - } - - li { - display: list-item; - text-align: -webkit-match-parent; - } - - a { - cursor: pointer; - } - - a.active { - background-color: #EEEEEE; - border-radius: 5px; - width: 165px; - } - /*a:hover { - width: 165px; - }*/ - - .nav>li>a:hover, - .nav>li>a:focus { - text-decoration: underline; - background-color: transparent; - } -</style> diff --git a/gui/app/views/main2.html b/gui/app/views/main2.html deleted file mode 100644 index 3f49e82e0..000000000 --- a/gui/app/views/main2.html +++ /dev/null @@ -1,174 +0,0 @@ -<div> - <div ng-include="'views/layout/header.html'"></div> -</div> -<div ng-include="'views/layout/sideNav2.html'"></div> - - -<div style="margin-top:80px;margin-left:220px;"> - <!--<div ncy-breadcrumb></div>--> - <div> - <ol class="progressDefine"> - <li data-step="1" ng-click="gotoProject();" style="cursor:pointer" ng-class="{'is-complete':projectShow}"> - Project - </li> - <li data-step="2" ng-class="{'is-complete':taskShow}"> - Task - </li> - - <li data-step="3" ng-class="{'is-complete':reportShow}"> - Reporting - </li> - - </ol> - </div> - - -</div> - - - - - - - - - -<div ui-view></div> - - - -<style> - .stepsContent { - display: flex; - flex-direction: row; - justify-content: space-around; - margin-left: 120px; - margin-top: 100px; - } - - .stepItem { - display: flex; - flex-direction: column; - } - - .nextButton { - margin-left: 500px; - } - - .progressDefine { - list-style: none; - margin: 0; - padding: 0; - display: table; - table-layout: fixed; - width: 100%; - color: #849397; - } - - .progressDefine>li { - position: relative; - display: table-cell; - text-align: center; - font-size: 0.8em; - } - - .progressDefine>li:before { - content: attr(data-step); - display: block; - margin: 0 auto; - background: #DFE3E4; - width: 3em; - height: 3em; - text-align: center; - margin-bottom: 0.25em; - line-height: 3em; - border-radius: 100%; - position: relative; - z-index: 5; - } - - .progressDefine>li:after { - content: ''; - position: absolute; - display: block; - background: #DFE3E4; - width: 100%; - height: 0.5em; - top: 1.25em; - left: 50%; - margin-left: 1.5em\9; - z-index: -1; - } - - .progressDefine>li:last-child:after { - display: none; - } - - .progressDefine>li.is-complete { - color: #4dc5cf; - } - - .progressDefine>li.is-complete:before, - .progressDefine>li.is-complete:after { - color: #FFF; - background: #4dc5cf; - } - - .progressDefine>li.is-active { - color: #3498DB; - } - - .progressDefine>li.is-active:before { - color: #FFF; - background: #3498DB; - } - /** - * Needed for IE8 - */ - - .progressDefine__last:after { - display: none !important; - } - /** - * Size Extensions - */ - - .progressDefine--medium { - font-size: 1.5em; - } - - .progressDefine--large { - font-size: 2em; - } - /** - * Some Generic Stylings - */ - - *, - *:after, - *:before { - box-sizing: border-box; - } - - h1 { - margin-bottom: 1.5em; - } - - .progressDefine { - margin-bottom: 3em; - } - - a { - color: #3498DB; - text-decoration: none; - } - - a:hover { - text-decoration: underline; - } - /* - body { - text-align: center; - color: #444; - }*/ -</style> diff --git a/nsb_setup.sh b/nsb_setup.sh index 88027d9bd..cc2542989 100755 --- a/nsb_setup.sh +++ b/nsb_setup.sh @@ -28,7 +28,7 @@ if [ "$(whoami)" != "root" ]; then fi INSTALL_BIN_PATH="/opt/nsb_bin" -TREX_VERSION="v2.20" +TREX_VERSION="v2.28" TREX_DOWNLOAD="https://trex-tgn.cisco.com/trex/release/$TREX_VERSION.tar.gz" DPDK_DOWNLOAD="http://dpdk.org/browse/dpdk/snapshot/dpdk-16.07.zip" VIRTUAL_VENV="$INSTALL_BIN_PATH/yardstick_venv" @@ -202,6 +202,12 @@ push_nsb_binary() cp "$REPO_DIR/yardstick/network_services/nfvi/collectd.sh" "$INSTALL_BIN_PATH" cp "$REPO_DIR/yardstick/network_services/nfvi/collectd.conf" "$INSTALL_BIN_PATH" cp "$REPO_DIR/nsb_setup.sh" "$INSTALL_BIN_PATH" + + # Get "dpdk-devbind.py" to find the ports for VNF to run + wget http://dpdk.org/browse/dpdk/plain/usertools/dpdk-devbind.py?h=v17.05 -O dpdk-devbind.py + chmod 777 dpdk-devbind.py + mv dpdk-devbind.py "$INSTALL_BIN_PATH" + ln "$INSTALL_BIN_PATH"/dpdk-devbind.py "$INSTALL_BIN_PATH"/dpdk_nic_bind.py echo "Done" } diff --git a/samples/vnf_samples/nsut/vfw/tc_baremetal_http_ixload_1b_Requests-65000_Concurrency.yaml b/samples/vnf_samples/nsut/vfw/tc_baremetal_http_ixload_1b_Requests-65000_Concurrency.yaml index 134722681..d4a4bb706 100644 --- a/samples/vnf_samples/nsut/vfw/tc_baremetal_http_ixload_1b_Requests-65000_Concurrency.yaml +++ b/samples/vnf_samples/nsut/vfw/tc_baremetal_http_ixload_1b_Requests-65000_Concurrency.yaml @@ -37,4 +37,4 @@ context: type: Node name: yardstick nfvi_type: baremetal - file: /etc/yardstick/nodes/pod.yaml + file: /etc/yardstick/nodes/pod_ixia.yaml diff --git a/samples/vnf_samples/nsut/vfw/tc_baremetal_rfc2544_ipv4_1rule_1flow_64B_ixia.yaml b/samples/vnf_samples/nsut/vfw/tc_baremetal_rfc2544_ipv4_1rule_1flow_64B_ixia.yaml index 746023de2..71a803d32 100644 --- a/samples/vnf_samples/nsut/vfw/tc_baremetal_rfc2544_ipv4_1rule_1flow_64B_ixia.yaml +++ b/samples/vnf_samples/nsut/vfw/tc_baremetal_rfc2544_ipv4_1rule_1flow_64B_ixia.yaml @@ -41,4 +41,4 @@ context: type: Node name: yardstick nfvi_type: baremetal - file: /etc/yardstick/nodes/pod.yaml + file: /etc/yardstick/nodes/pod_ixia.yaml diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml index ccd40c33b..6b213a54a 100644 --- a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml +++ b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml @@ -53,6 +53,8 @@ private_1: outer_l4: srcport: "{{get(flow, 'flow.srcport_range', '1234') }}" dstport: "{{get(flow, 'flow.dstport_range', '2001') }}" + count: "{{get(flow, 'flow.count', '1') }}" + public_1: ipv4: outer_l2: @@ -75,6 +77,7 @@ public_1: outer_l4: srcport: "{{get(flow, 'flow.srcport_range', '1234') }}" dstport: "{{get(flow, 'flow.dstport_range', '2001') }}" + count: "{{get(flow, 'flow.count', '1') }}" private_2: ipv4: outer_l2: @@ -97,6 +100,7 @@ private_2: outer_l4: srcport: "{{get(flow, 'flow.srcport_range', '1234') }}" dstport: "{{get(flow, 'flow.dstport_range', '2001') }}" + count: "{{get(flow, 'flow.count', '1') }}" public_2: ipv4: outer_l2: @@ -119,3 +123,4 @@ public_2: outer_l4: srcport: "{{get(flow, 'flow.srcport_range', '1234') }}" dstport: "{{get(flow, 'flow.dstport_range', '2001') }}" + count: "{{get(flow, 'flow.count', '1') }}" diff --git a/tests/ci/apexlake-verify b/tests/ci/apexlake-verify deleted file mode 100755 index 6a691063f..000000000 --- a/tests/ci/apexlake-verify +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -############################################################################## -# Copyright (c) 2015 Ericsson 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 -############################################################################## - -DPDK_HOST=10.118.36.130 - -YARDSTICK=/home/user/yardstick -TESTSUITE=$YARDSTICK/tests/opnfv/test_suites/opnfv_vTC_daily.yaml - -: ${INSTALLER_TYPE:='unknown'} -: ${NODE_NAME:='unknown'} -: ${DEPLOY_SCENARIO:='unknown'} - -commands=" -cd $YARDSTICK -source /home/user/openrc.dasm -export INSTALLER_TYPE=$INSTALLER_TYPE -export NODE_NAME=$NODE_NAME -export DEPLOY_SCENARIO=$DEPLOY_SCENARIO -sudo -E yardstick task start --suite $TESTSUITE" - -echo "$commands" | ssh -l user $DPDK_HOST 'bash -s' -exit $? diff --git a/tests/unit/benchmark/contexts/standalone/__init__.py b/tests/unit/benchmark/contexts/standalone/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/unit/benchmark/contexts/standalone/__init__.py diff --git a/tests/unit/benchmark/contexts/ovs_sample_password.yaml b/tests/unit/benchmark/contexts/standalone/ovs_sample_password.yaml index b1da1ea9f..b1da1ea9f 100644 --- a/tests/unit/benchmark/contexts/ovs_sample_password.yaml +++ b/tests/unit/benchmark/contexts/standalone/ovs_sample_password.yaml diff --git a/tests/unit/benchmark/contexts/ovs_sample_ssh_key.yaml b/tests/unit/benchmark/contexts/standalone/ovs_sample_ssh_key.yaml index 896ec33bb..896ec33bb 100644 --- a/tests/unit/benchmark/contexts/ovs_sample_ssh_key.yaml +++ b/tests/unit/benchmark/contexts/standalone/ovs_sample_ssh_key.yaml diff --git a/tests/unit/benchmark/contexts/ovs_sample_write_to_file.txt b/tests/unit/benchmark/contexts/standalone/ovs_sample_write_to_file.txt index f0eec86f6..f0eec86f6 100644 --- a/tests/unit/benchmark/contexts/ovs_sample_write_to_file.txt +++ b/tests/unit/benchmark/contexts/standalone/ovs_sample_write_to_file.txt diff --git a/tests/unit/benchmark/contexts/sriov_sample_password.yaml b/tests/unit/benchmark/contexts/standalone/sriov_sample_password.yaml index 4f60e46d5..4f60e46d5 100644 --- a/tests/unit/benchmark/contexts/sriov_sample_password.yaml +++ b/tests/unit/benchmark/contexts/standalone/sriov_sample_password.yaml diff --git a/tests/unit/benchmark/contexts/sriov_sample_ssh_key.yaml b/tests/unit/benchmark/contexts/standalone/sriov_sample_ssh_key.yaml index faa496771..faa496771 100644 --- a/tests/unit/benchmark/contexts/sriov_sample_ssh_key.yaml +++ b/tests/unit/benchmark/contexts/standalone/sriov_sample_ssh_key.yaml diff --git a/tests/unit/benchmark/contexts/sriov_sample_write_to_file.txt b/tests/unit/benchmark/contexts/standalone/sriov_sample_write_to_file.txt index f0eec86f6..f0eec86f6 100644 --- a/tests/unit/benchmark/contexts/sriov_sample_write_to_file.txt +++ b/tests/unit/benchmark/contexts/standalone/sriov_sample_write_to_file.txt diff --git a/tests/unit/benchmark/contexts/test_ovsdpdk.py b/tests/unit/benchmark/contexts/standalone/test_ovsdpdk.py index ac25ec877..1d68384c9 100644 --- a/tests/unit/benchmark/contexts/test_ovsdpdk.py +++ b/tests/unit/benchmark/contexts/standalone/test_ovsdpdk.py @@ -13,11 +13,13 @@ # limitations under the License. from __future__ import absolute_import + import os -import mock import unittest -from yardstick.benchmark.contexts import ovsdpdk +import mock + +from yardstick.benchmark.contexts.standalone import ovsdpdk NIC_INPUT = { 'interface': {}, @@ -226,11 +228,11 @@ class OvsdpdkTestCase(unittest.TestCase): mock_ovs = mock.Mock() ssh_mock.put = mock.Mock() ovs_obj.check_output = mock.Mock(return_value=(0, "vm1")) - with mock.patch("yardstick.benchmark.contexts.ovsdpdk.time"): + with mock.patch("yardstick.benchmark.contexts.standalone.ovsdpdk.time"): self.assertIsNone(ovs_obj.setup_ovs_context(PCIS, NIC_DETAILS, DRIVER)) @mock.patch( - 'yardstick.benchmark.contexts.ovsdpdk', + 'yardstick.benchmark.contexts.standalone.ovsdpdk', return_value="Domain vm1 created from /tmp/vm_ovs.xml") def test_is_vm_created(self, NIC_INPUT): with mock.patch("yardstick.ssh.SSH") as ssh: diff --git a/tests/unit/benchmark/contexts/test_sriov.py b/tests/unit/benchmark/contexts/standalone/test_sriov.py index a8641a2eb..ea72e1bab 100644 --- a/tests/unit/benchmark/contexts/test_sriov.py +++ b/tests/unit/benchmark/contexts/standalone/test_sriov.py @@ -13,11 +13,13 @@ # limitations under the License. from __future__ import absolute_import + import os -import mock import unittest -from yardstick.benchmark.contexts import sriov +import mock + +from yardstick.benchmark.contexts.standalone import sriov NIC_INPUT = { 'interface': {}, @@ -185,7 +187,7 @@ class SriovTestCase(unittest.TestCase): nic_details['vf_pci'][i] = sriov_obj.get_vf_datas.return_value vf_pci = [[], []] vf_pci[i] = sriov_obj.get_vf_datas.return_value - with mock.patch("yardstick.benchmark.contexts.sriov.time"): + with mock.patch("yardstick.benchmark.contexts.standalone.sriov.time"): self.assertIsNotNone(sriov_obj.configure_nics_for_sriov(DRIVER, NIC_DETAILS)) def test_setup_sriov_context(self): @@ -224,7 +226,7 @@ class SriovTestCase(unittest.TestCase): mock.Mock(return_value=(0, {}, "")) ssh_mock.put = mock.Mock() sriov_obj.check_output = mock.Mock(return_value=(1, {})) - with mock.patch("yardstick.benchmark.contexts.sriov.time"): + with mock.patch("yardstick.benchmark.contexts.standalone.sriov.time"): self.assertIsNone(sriov_obj.setup_sriov_context(PCIS, nic_details, DRIVER)) def test_setup_sriov_context_vm_already_present(self): @@ -263,11 +265,11 @@ class SriovTestCase(unittest.TestCase): mock.Mock(return_value=(0, {}, "")) ssh_mock.put = mock.Mock() sriov_obj.check_output = mock.Mock(return_value=(0, "vm1")) - with mock.patch("yardstick.benchmark.contexts.sriov.time"): + with mock.patch("yardstick.benchmark.contexts.standalone.sriov.time"): self.assertIsNone(sriov_obj.setup_sriov_context(PCIS, nic_details, DRIVER)) @mock.patch( - 'yardstick.benchmark.contexts.sriov', + 'yardstick.benchmark.contexts.standalone.sriov', return_value="Domain vm1 created from /tmp/vm_sriov.xml") def test_is_vm_created(self, NIC_INPUT): with mock.patch("yardstick.ssh.SSH") as ssh: diff --git a/tests/unit/benchmark/contexts/test_standalone.py b/tests/unit/benchmark/contexts/test_standalone.py index d13e28470..b1402a1c9 100644 --- a/tests/unit/benchmark/contexts/test_standalone.py +++ b/tests/unit/benchmark/contexts/test_standalone.py @@ -18,25 +18,26 @@ # Unittest for yardstick.benchmark.contexts.standalone from __future__ import absolute_import + import os import unittest + import mock from yardstick.benchmark.contexts import standalone -from yardstick.benchmark.contexts import sriov -from yardstick.benchmark.contexts import ovsdpdk +from yardstick.benchmark.contexts.standalone import ovsdpdk, sriov MOCKS = { 'yardstick.benchmark.contexts': mock.MagicMock(), - 'yardstick.benchmark.contexts.sriov': mock.MagicMock(), - 'yardstick.benchmark.contexts.ovsdpdk': mock.MagicMock(), + 'yardstick.benchmark.contexts.standalone.sriov': mock.MagicMock(), + 'yardstick.benchmark.contexts.standalone.ovsdpdk': mock.MagicMock(), 'yardstick.benchmark.contexts.standalone': mock.MagicMock(), } -@mock.patch('yardstick.benchmark.contexts.ovsdpdk.time') +@mock.patch('yardstick.benchmark.contexts.standalone.ovsdpdk.time') @mock.patch('yardstick.benchmark.contexts.standalone.time') -@mock.patch('yardstick.benchmark.contexts.sriov.time') +@mock.patch('yardstick.benchmark.contexts.standalone.sriov.time') class StandaloneContextTestCase(unittest.TestCase): NODES_SAMPLE = "nodes_sample_new.yaml" NODES_SAMPLE_SRIOV = "nodes_sample_new_sriov.yaml" @@ -564,7 +565,7 @@ class StandaloneContextTestCase(unittest.TestCase): self.assertIsNone(self.test_context.undeploy()) def test_get_nfvi_obj_sriov(self, mock_sriov_time, mock_standlalone_time, mock_ovsdpdk_time): - with mock.patch('yardstick.benchmark.contexts.sriov'): + with mock.patch('yardstick.benchmark.contexts.standalone.sriov'): attrs = { 'name': 'sriov', 'file': self._get_file_abspath(self.NODES_SAMPLE) @@ -589,7 +590,7 @@ class StandaloneContextTestCase(unittest.TestCase): self.assertIsNotNone(self.test_context.get_nfvi_obj()) def test_get_nfvi_obj_ovs(self, mock_sriov_time, mock_standlalone_time, mock_ovsdpdk_time): - with mock.patch('yardstick.benchmark.contexts.ovsdpdk'): + with mock.patch('yardstick.benchmark.contexts.standalone.ovsdpdk'): attrs = { 'name': 'ovs', 'file': self._get_file_abspath(self.NODES_SAMPLE_OVSDPDK) diff --git a/tests/unit/benchmark/core/test_task.py b/tests/unit/benchmark/core/test_task.py index 25688bf48..14027e43c 100644 --- a/tests/unit/benchmark/core/test_task.py +++ b/tests/unit/benchmark/core/test_task.py @@ -290,8 +290,9 @@ class TaskTestCase(unittest.TestCase): task.change_server_name(scenario, suffix) self.assertTrue(scenario['target']['name'], 'demo-8') + @mock.patch('yardstick.benchmark.core.task.utils') @mock.patch('yardstick.benchmark.core.task.logging') - def test_set_log(self, mock_logging): + def test_set_log(self, mock_logging, mock_utils): task_obj = task.Task() task_obj.task_id = 'task_id' task_obj._set_log() diff --git a/tests/unit/benchmark/scenarios/lib/test_attach_volume.py b/tests/unit/benchmark/scenarios/lib/test_attach_volume.py new file mode 100644 index 000000000..e69924072 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_attach_volume.py @@ -0,0 +1,33 @@ +############################################################################## +# 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 +############################################################################## +import unittest +import mock + +from yardstick.benchmark.scenarios.lib.attach_volume import AttachVolume + + +class AttachVolumeTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.attach_server_volume') + def test_attach_volume(self, mock_attach_server_volume): + options = { + 'volume_id': '123-456-000', + 'server_id': '000-123-456' + } + args = {"options": options} + obj = AttachVolume(args, {}) + obj.run({}) + self.assertTrue(mock_attach_server_volume.called) + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_create_floating_ip.py b/tests/unit/benchmark/scenarios/lib/test_create_floating_ip.py new file mode 100644 index 000000000..72dbcd7cd --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_floating_ip.py @@ -0,0 +1,34 @@ +############################################################################## +# 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 +############################################################################## +import unittest +import mock + +from yardstick.benchmark.scenarios.lib.create_floating_ip import CreateFloatingIp + + +class CreateFloatingIpTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.create_floating_ip') + @mock.patch('yardstick.common.openstack_utils.get_network_id') + @mock.patch('yardstick.common.openstack_utils.get_neutron_client') + def test_create_floating_ip(self, mock_create_floating_ip, mock_get_network_id, mock_get_neutron_client): + options = {} + args = {"options": options} + obj = CreateFloatingIp(args, {}) + obj.run({}) + self.assertTrue(mock_create_floating_ip.called) + self.assertTrue(mock_get_network_id.called) + self.assertTrue(mock_get_neutron_client.called) + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_create_keypair.py b/tests/unit/benchmark/scenarios/lib/test_create_keypair.py new file mode 100644 index 000000000..99e6b9afa --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_create_keypair.py @@ -0,0 +1,35 @@ +############################################################################## +# 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 +############################################################################## +import unittest +import mock +import paramiko + +from yardstick.benchmark.scenarios.lib.create_keypair import CreateKeypair + + +class CreateKeypairTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.create_keypair') + def test_create_keypair(self, mock_create_keypair): + options = { + 'key_name': 'yardstick_key', + 'key_path': '/tmp/yardstick_key' + } + args = {"options": options} + obj = CreateKeypair(args, {}) + obj.run({}) + self.assertTrue(mock_create_keypair.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py b/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py index e7ba3ca73..680692fdc 100644 --- a/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py +++ b/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py @@ -18,7 +18,7 @@ class GetNumaInfoTestCase(unittest.TestCase): @mock.patch('{}.GetNumaInfo._check_numa_node'.format(BASE)) @mock.patch('{}.GetNumaInfo._get_current_host_name'.format(BASE)) - @mock.patch('yaml.safe_load') + @mock.patch('yardstick.benchmark.scenarios.lib.get_numa_info.yaml_load') @mock.patch('yardstick.common.task_template.TaskTemplate.render') def test_get_numa_info(self, mock_render, @@ -44,7 +44,7 @@ class GetNumaInfoTestCase(unittest.TestCase): @mock.patch('yardstick.ssh.SSH.from_node') @mock.patch('{}.GetNumaInfo._get_current_host_name'.format(BASE)) - @mock.patch('yaml.safe_load') + @mock.patch('yardstick.benchmark.scenarios.lib.get_numa_info.yaml_load') @mock.patch('yardstick.common.task_template.TaskTemplate.render') def test_check_numa_node(self, mock_render, @@ -74,7 +74,7 @@ class GetNumaInfoTestCase(unittest.TestCase): @mock.patch('{}.change_obj_to_dict'.format(BASE)) @mock.patch('{}.get_nova_client'.format(BASE)) - @mock.patch('yaml.safe_load') + @mock.patch('yardstick.benchmark.scenarios.lib.get_numa_info.yaml_load') @mock.patch('yardstick.common.task_template.TaskTemplate.render') def test_get_current_host_name(self, mock_render, diff --git a/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py b/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py index 84b42c832..651614d3e 100644 --- a/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py +++ b/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py @@ -26,7 +26,7 @@ import mock from yardstick.benchmark.scenarios.networking.vnf_generic import \ SshManager, NetworkServiceTestCase, IncorrectConfig, \ - IncorrectSetup, open_relative_file + open_relative_file from yardstick.network_services.collector.subscriber import Collector from yardstick.network_services.vnf_generic.vnf.base import \ GenericTrafficGen, GenericVNF @@ -471,7 +471,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): mock.Mock(return_value=(1, SYS_CLASS_NET + IP_ADDR_SHOW, "")) ssh.from_node.return_value = ssh_mock - with self.assertRaises(IncorrectSetup): + with self.assertRaises(IncorrectConfig): self.s.map_topology_to_infrastructure() def test_map_topology_to_infrastructure_config_invalid(self): @@ -694,11 +694,11 @@ class TestNetworkServiceTestCase(unittest.TestCase): def test_probe_missing_values(self): netdevs = self.SAMPLE_NETDEVS.copy() network = {'local_mac': '0a:de:ad:be:ef:f5'} - NetworkServiceTestCase._probe_missing_values(netdevs, network, set()) + NetworkServiceTestCase._probe_missing_values(netdevs, network) assert network['vpci'] == '0000:0b:00.0' network = {'local_mac': '0a:de:ad:be:ef:f4'} - NetworkServiceTestCase._probe_missing_values(netdevs, network, set()) + NetworkServiceTestCase._probe_missing_values(netdevs, network) assert network['vpci'] == '0000:00:19.0' def test_open_relative_path(self): diff --git a/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py b/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py index 3b9f99b08..de5bae2f3 100644 --- a/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py +++ b/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py @@ -28,8 +28,6 @@ from yardstick.benchmark.scenarios.networking import vsperf_dpdk @mock.patch('yardstick.benchmark.scenarios.networking.vsperf_dpdk.subprocess') @mock.patch('yardstick.benchmark.scenarios.networking.vsperf_dpdk.ssh') -@mock.patch("yardstick.benchmark.scenarios.networking.vsperf_dpdk.open", - mock.mock_open()) class VsperfDPDKTestCase(unittest.TestCase): def setUp(self): diff --git a/tests/unit/common/test_utils.py b/tests/unit/common/test_utils.py index 663226242..923ec4aaa 100644 --- a/tests/unit/common/test_utils.py +++ b/tests/unit/common/test_utils.py @@ -20,6 +20,7 @@ from itertools import product, chain import mock from six.moves import configparser +import yardstick from yardstick.common import utils from yardstick.common import constants @@ -45,47 +46,25 @@ class IterSubclassesTestCase(unittest.TestCase): self.assertEqual([B, C, D], list(utils.itersubclasses(A))) -class TryAppendModuleTestCase(unittest.TestCase): - - @mock.patch('yardstick.common.utils.importutils') - def test_try_append_module_not_in_modules(self, mock_importutils): - - modules = {} - name = 'foo' - utils.try_append_module(name, modules) - mock_importutils.import_module.assert_called_with(name) - - @mock.patch('yardstick.common.utils.importutils') - def test_try_append_module_already_in_modules(self, mock_importutils): - - modules = {'foo'} - name = 'foo' - utils.try_append_module(name, modules) - self.assertFalse(mock_importutils.import_module.called) - - class ImportModulesFromPackageTestCase(unittest.TestCase): @mock.patch('yardstick.common.utils.os.walk') - @mock.patch('yardstick.common.utils.try_append_module') - def test_import_modules_from_package_no_mod(self, mock_append, mock_walk): - - sep = os.sep + def test_import_modules_from_package_no_mod(self, mock_walk): + yardstick_root = os.path.dirname(os.path.dirname(yardstick.__file__)) mock_walk.return_value = ([ - ('..' + sep + 'foo', ['bar'], ['__init__.py']), - ('..' + sep + 'foo' + sep + 'bar', [], ['baz.txt', 'qux.rst']) + (os.path.join(yardstick_root, 'foo'), ['bar'], ['__init__.py']), + (os.path.join(yardstick_root, 'foo', 'bar'), [], ['baz.txt', 'qux.rst']) ]) utils.import_modules_from_package('foo.bar') - self.assertFalse(mock_append.called) @mock.patch('yardstick.common.utils.os.walk') @mock.patch('yardstick.common.utils.importutils') def test_import_modules_from_package(self, mock_importutils, mock_walk): - sep = os.sep + yardstick_root = os.path.dirname(os.path.dirname(yardstick.__file__)) mock_walk.return_value = ([ - ('foo' + sep + '..' + sep + 'bar', [], ['baz.py']) + (os.path.join(yardstick_root, 'foo', os.pardir, 'bar'), [], ['baz.py']) ]) utils.import_modules_from_package('foo.bar') diff --git a/tests/unit/common/test_yaml_loader.py b/tests/unit/common/test_yaml_loader.py new file mode 100644 index 000000000..90cbb8157 --- /dev/null +++ b/tests/unit/common/test_yaml_loader.py @@ -0,0 +1,32 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# yardstick: this file is copied from python-heatclient and slightly modified + +from __future__ import absolute_import +import unittest + +from yardstick.common import yaml_loader + + +class TemplateFormatTestCase(unittest.TestCase): + + def test_parse_to_value_exception(self): + + self.assertEquals(yaml_loader.yaml_load("string"), u"string") + + +def main(): + unittest.main() + +if __name__ == '__main__': + main() diff --git a/tests/unit/network_services/libs/ixia_libs/test_IxNet.py b/tests/unit/network_services/libs/ixia_libs/test_IxNet.py index 9114b5163..ae4c58de1 100644 --- a/tests/unit/network_services/libs/ixia_libs/test_IxNet.py +++ b/tests/unit/network_services/libs/ixia_libs/test_IxNet.py @@ -32,19 +32,14 @@ class TestIxNextgen(unittest.TestCase): ixnet_gen = IxNextgen() self.assertIsNone(ixnet_gen._bidir) - @mock.patch("yardstick.network_services.libs.ixia_libs.IxNet.IxNet.IxNetwork") @mock.patch("yardstick.network_services.libs.ixia_libs.IxNet.IxNet.sys") - def test_connect(self, mock_sys, mock_ix_network): - mock_ix_network.IxNet.return_value = mock_ixnet = mock.Mock() + def test_connect(self, mock_sys): ixnet_gen = IxNextgen() ixnet_gen.get_config = mock.MagicMock() ixnet_gen.get_ixnet = mock.MagicMock() - result = ixnet_gen._connect({"py_lib_path": "/tmp"}) - self.assertIsNotNone(result) - self.assertEqual(mock_ix_network.IxNet.call_count, 1) - self.assertEqual(mock_ixnet.connect.call_count, 1) + self.assertRaises(ImportError, ixnet_gen._connect, {"py_lib_path": "/tmp"}) def test_clear_ixia_config(self): ixnet = mock.MagicMock() @@ -263,7 +258,7 @@ class TestIxNextgen(unittest.TestCase): result = ixnet_gen.ix_get_statistics() self.assertIsNotNone(result) - self.assertEqual(ixnet.getList.call_count, 2) + self.assertEqual(ixnet.getList.call_count, 1) self.assertEqual(ixnet.execute.call_count, 20) def test_find_view_obj_no_where(self): @@ -455,7 +450,7 @@ class TestIxNextgen(unittest.TestCase): } ixnet = mock.MagicMock() - ixnet.remapIds.return_value=["0"] + ixnet.remapIds.return_value = ["0"] ixnet.setMultiAttribute.return_value = [1] ixnet.commit.return_value = [1] ixnet.getList.side_effect = [[1], [0, 1], [0], ["srcIp", "dstIp"]] @@ -865,7 +860,7 @@ class TestIxNextgen(unittest.TestCase): ixnet = mock.MagicMock() ixnet.setMultiAttribute.return_value = [1] ixnet.commit.return_value = [1] - ixnet.getList.side_effect=[ + ixnet.getList.side_effect = [ [1], [1], [1], diff --git a/tests/unit/network_services/nfvi/test_resource.py b/tests/unit/network_services/nfvi/test_resource.py index cb26fd085..072f06edf 100644 --- a/tests/unit/network_services/nfvi/test_resource.py +++ b/tests/unit/network_services/nfvi/test_resource.py @@ -108,13 +108,13 @@ class TestResourceProfile(unittest.TestCase): def test_get_cpu_data(self): reskey = ["", "cpufreq", "cpufreq-0"] value = "metric:10" - val = self.resource_profile.get_cpu_data(reskey, value) + val = self.resource_profile.get_cpu_data(reskey[1], reskey[2], value) self.assertIsNotNone(val) def test_get_cpu_data_error(self): reskey = ["", "", ""] value = "metric:10" - val = self.resource_profile.get_cpu_data(reskey, value) + val = self.resource_profile.get_cpu_data(reskey[0], reskey[1], value) self.assertEqual(val, ('error', 'Invalid', '', '')) def test__start_collectd(self): diff --git a/tests/unit/network_services/test_yang_model.py b/tests/unit/network_services/test_yang_model.py index 28367f316..0b29da701 100644 --- a/tests/unit/network_services/test_yang_model.py +++ b/tests/unit/network_services/test_yang_model.py @@ -95,7 +95,7 @@ class YangModelTestCase(unittest.TestCase): y._get_entries() self.assertEqual(y._rules, '') - @mock.patch('yaml.safe_load') + @mock.patch('yardstick.network_services.yang_model.yaml_load') @mock.patch('yardstick.network_services.yang_model.open') def test__read_config(self, mock_open, mock_safe_load): cfg = "yang.yaml" diff --git a/tests/unit/network_services/traffic_profile/test_http_ixload.py b/tests/unit/network_services/traffic_profile/test_http_ixload.py index 2e1b6f4ff..5110439fd 100644 --- a/tests/unit/network_services/traffic_profile/test_http_ixload.py +++ b/tests/unit/network_services/traffic_profile/test_http_ixload.py @@ -16,11 +16,33 @@ from __future__ import absolute_import import unittest import mock -import runpy from oslo_serialization import jsonutils from yardstick.network_services.traffic_profile import http_ixload +from yardstick.network_services.traffic_profile.http_ixload import \ + join_non_strings, validate_non_string_sequence + + +class TestJoinNonStrings(unittest.TestCase): + + def test_validate_non_string_sequence(self): + self.assertEqual(validate_non_string_sequence([1, 2, 3]), [1, 2, 3]) + self.assertIsNone(validate_non_string_sequence('123')) + self.assertIsNone(validate_non_string_sequence(1)) + + self.assertEqual(validate_non_string_sequence(1, 2), 2) + self.assertEqual(validate_non_string_sequence(1, default=2), 2) + + with self.assertRaises(RuntimeError): + validate_non_string_sequence(1, raise_exc=RuntimeError) + + def test_join_non_strings(self): + self.assertEqual(join_non_strings(':'), '') + self.assertEqual(join_non_strings(':', 'a'), 'a') + self.assertEqual(join_non_strings(':', 'a', 2, 'c'), 'a:2:c') + self.assertEqual(join_non_strings(':', ['a', 2, 'c']), 'a:2:c') + self.assertEqual(join_non_strings(':', 'abc'), 'abc') class TestIxLoadTrafficGen(unittest.TestCase): diff --git a/tests/unit/network_services/vnf_generic/test_vnfdgen.py b/tests/unit/network_services/vnf_generic/test_vnfdgen.py index be51e4a43..c2b923568 100644 --- a/tests/unit/network_services/vnf_generic/test_vnfdgen.py +++ b/tests/unit/network_services/vnf_generic/test_vnfdgen.py @@ -21,6 +21,7 @@ from __future__ import absolute_import import unittest from six.moves import range +from yardstick.common.yaml_loader import yaml_load from yardstick.network_services.vnf_generic import vnfdgen TREX_VNFD_TEMPLATE = """ @@ -65,6 +66,8 @@ vnfd:vnfd-catalog: dst_mac: '{{ interfaces.xe1.dst_mac }}' bandwidth: 10 Gbps vnfd-connection-point-ref: xe1 + routing_table: {{ routing_table }} + nd_route_tbl: {{ nd_route_tbl }} benchmark: kpi: @@ -126,6 +129,22 @@ COMPLETE_TREX_VNFD = \ 'vpci': '0000:00:10.1'}, 'vnfd-connection-point-ref': 'xe1'}], 'id': 'trexgen-baremetal', + 'nd_route_tbl': [{'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0', + 'netmask': '112', + 'network': '0064:ff9b:0:0:0:0:9810:6414'}, + {'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1', + 'netmask': '112', + 'network': '0064:ff9b:0:0:0:0:9810:2814'}], + 'routing_table': [{'gateway': '152.16.100.20', + 'if': 'xe0', + 'netmask': '255.255.255.0', + 'network': '152.16.100.20'}, + {'gateway': '152.16.40.20', + 'if': 'xe1', + 'netmask': '255.255.255.0', + 'network': '152.16.40.20'}], 'name': 'trexgen-baremetal'}]}]}} NODE_CFG = {'ip': '1.1.1.1', @@ -144,7 +163,24 @@ NODE_CFG = {'ip': '1.1.1.1', 'dst_mac': '00:01:02:03:04:06', 'local_ip': '2.1.1.2', 'local_mac': '00:01:02:03:05:06', - 'vpci': '0000:00:10.1'}}} + 'vpci': '0000:00:10.1'}}, + 'nd_route_tbl': [{u'gateway': u'0064:ff9b:0:0:0:0:9810:6414', + u'if': u'xe0', + u'netmask': u'112', + u'network': u'0064:ff9b:0:0:0:0:9810:6414'}, + {u'gateway': u'0064:ff9b:0:0:0:0:9810:2814', + u'if': u'xe1', + u'netmask': u'112', + u'network': u'0064:ff9b:0:0:0:0:9810:2814'}], + 'routing_table': [{u'gateway': u'152.16.100.20', + u'if': u'xe0', + u'netmask': u'255.255.255.0', + u'network': u'152.16.100.20'}, + {u'gateway': u'152.16.40.20', + u'if': u'xe1', + u'netmask': u'255.255.255.0', + u'network': u'152.16.40.20'}], + } TRAFFIC_PROFILE_TPL = """ @@ -169,6 +205,20 @@ TRAFFIC_PROFILE = { "1518B": '40'}}}}]} +class TestRender(unittest.TestCase): + + def test_render_none(self): + + tmpl = "{{ routing_table }}" + self.assertEqual(vnfdgen.render(tmpl, routing_table=None), u'~') + self.assertEqual(yaml_load(vnfdgen.render(tmpl, routing_table=None)), None) + + def test_render_unicode_dict(self): + + tmpl = "{{ routing_table }}" + self.assertEqual(yaml_load(vnfdgen.render(tmpl, **NODE_CFG)), NODE_CFG["routing_table"]) + + class TestVnfdGen(unittest.TestCase): """ Class to verify VNFS testcases """ @@ -193,6 +243,14 @@ class TestVnfdGen(unittest.TestCase): d = {'a': 1, 'b': 2} self.assertEqual(vnfdgen.deepgetitem(d, "a"), 1) + def test_dict_flatten_str_int_key_first(self): + d = {'0': 1, 0: 24, 'b': 2} + self.assertEqual(vnfdgen.deepgetitem(d, "0"), 1) + + def test_dict_flatten_int_key_fallback(self): + d = {0: 1, 'b': 2} + self.assertEqual(vnfdgen.deepgetitem(d, "0"), 1) + def test_dict_flatten_list(self): d = {'a': 1, 'b': list(range(2))} self.assertEqual(vnfdgen.deepgetitem(d, "b.0"), 0) @@ -201,6 +259,11 @@ class TestVnfdGen(unittest.TestCase): d = {'a': 1, 'b': {x: x for x in list(range(2))}} self.assertEqual(vnfdgen.deepgetitem(d, "b.0"), 0) + def test_dict_flatten_only_str_key(self): + d = {'0': 1, 0: 24, 'b': 2} + self.assertRaises(AttributeError, vnfdgen.deepgetitem, d, 0) + + def test_generate_tp_single_var(self): """ Function to verify traffic profile generation with imix """ diff --git a/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py b/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py index af0d2ddde..07a862a8e 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py @@ -1142,7 +1142,7 @@ class TestClientResourceHelper(unittest.TestCase): } @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.LOG') - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.STLStateError', + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.STLError', new_callable=lambda: MockError) def test_get_stats_not_connected(self, mock_state_error, mock_logger): vnfd_helper = VnfdHelper({}) diff --git a/yardstick/benchmark/contexts/node.py b/yardstick/benchmark/contexts/node.py index 35c64335d..250032efc 100644 --- a/yardstick/benchmark/contexts/node.py +++ b/yardstick/benchmark/contexts/node.py @@ -17,12 +17,12 @@ import tempfile import six import pkg_resources -import yaml from yardstick import ssh from yardstick.benchmark.contexts.base import Context from yardstick.common.constants import ANSIBLE_DIR, YARDSTICK_ROOT_PATH from yardstick.common.ansible_common import AnsibleCommon +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -55,7 +55,7 @@ class NodeContext(Context): with open(self.file_path) as stream: LOG.info("Parsing pod file: %s", self.file_path) - cfg = yaml.safe_load(stream) + cfg = yaml_load(stream) return cfg def init(self, attrs): diff --git a/yardstick/benchmark/contexts/standalone.py b/yardstick/benchmark/contexts/standalone/__init__.py index ae1046974..f0ef1d560 100644 --- a/yardstick/benchmark/contexts/standalone.py +++ b/yardstick/benchmark/contexts/standalone/__init__.py @@ -18,12 +18,12 @@ import logging import os import errno import collections -import yaml import time from yardstick.benchmark.contexts.base import Context from yardstick.common.constants import YARDSTICK_ROOT_PATH from yardstick.common.utils import import_modules_from_package, itersubclasses +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -50,7 +50,7 @@ class StandaloneContext(Context): with open(self.file_path) as stream: LOG.info("Parsing pod file: %s", self.file_path) - cfg = yaml.safe_load(stream) + cfg = yaml_load(stream) return cfg def get_nfvi_obj(self): diff --git a/yardstick/benchmark/contexts/ovsdpdk.py b/yardstick/benchmark/contexts/standalone/ovsdpdk.py index cf5529d89..cf5529d89 100644 --- a/yardstick/benchmark/contexts/ovsdpdk.py +++ b/yardstick/benchmark/contexts/standalone/ovsdpdk.py diff --git a/yardstick/benchmark/contexts/sriov.py b/yardstick/benchmark/contexts/standalone/sriov.py index fe27d2579..fe27d2579 100644 --- a/yardstick/benchmark/contexts/sriov.py +++ b/yardstick/benchmark/contexts/standalone/sriov.py diff --git a/yardstick/benchmark/core/plugin.py b/yardstick/benchmark/core/plugin.py index a741d5e74..24f1b6b25 100644 --- a/yardstick/benchmark/core/plugin.py +++ b/yardstick/benchmark/core/plugin.py @@ -13,13 +13,13 @@ from __future__ import print_function from __future__ import absolute_import import os import sys -import yaml import time import logging import pkg_resources import yardstick.ssh as ssh from yardstick.common.task_template import TaskTemplate +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -153,7 +153,7 @@ class PluginParser(object): raise e print("Input plugin is:\n%s\n" % rendered_plugin) - cfg = yaml.safe_load(rendered_plugin) + cfg = yaml_load(rendered_plugin) except IOError as ioerror: sys.exit(ioerror) diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index ea3239edf..2c67e736c 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -29,6 +29,7 @@ from jinja2 import Environment from yardstick.benchmark.contexts.base import Context from yardstick.benchmark.runners import base as base_runner +from yardstick.common.yaml_loader import yaml_load from yardstick.dispatcher.base import Base as DispatcherBase from yardstick.common.task_template import TaskTemplate from yardstick.common.utils import source_env @@ -172,6 +173,7 @@ class Task(object): # pragma: no cover log_format = '%(asctime)s %(name)s %(filename)s:%(lineno)d %(levelname)s %(message)s' log_formatter = logging.Formatter(log_format) + utils.makedirs(constants.TASK_LOG_DIR) log_path = os.path.join(constants.TASK_LOG_DIR, '{}.log'.format(self.task_id)) log_handler = logging.FileHandler(log_path) log_handler.setFormatter(log_formatter) @@ -437,7 +439,7 @@ class TaskParser(object): # pragma: no cover try: with open(self.path) as stream: - cfg = yaml.load(stream) + cfg = yaml_load(stream) except IOError as ioerror: sys.exit(ioerror) @@ -501,7 +503,7 @@ class TaskParser(object): # pragma: no cover raise e print("Input task is:\n%s\n" % rendered_task) - cfg = yaml.load(rendered_task) + cfg = yaml_load(rendered_task) except IOError as ioerror: sys.exit(ioerror) @@ -657,7 +659,7 @@ def parse_task_args(src_name, args): return args try: - kw = args and yaml.safe_load(args) + kw = args and yaml_load(args) kw = {} if kw is None else kw except yaml.parser.ParserError as e: print_invalid_header(src_name, args) diff --git a/yardstick/benchmark/core/testcase.py b/yardstick/benchmark/core/testcase.py index 7ab1b08cf..501356726 100644 --- a/yardstick/benchmark/core/testcase.py +++ b/yardstick/benchmark/core/testcase.py @@ -12,11 +12,11 @@ from __future__ import absolute_import from __future__ import print_function import os -import yaml import logging from yardstick.common.task_template import TaskTemplate from yardstick.common import constants as consts +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -69,7 +69,7 @@ class Testcase(object): def _parse_testcase(self, testcase_info): rendered_testcase = TaskTemplate.render(testcase_info) - testcase_cfg = yaml.safe_load(rendered_testcase) + testcase_cfg = yaml_load(rendered_testcase) test_precondition = testcase_cfg.get('precondition', {}) installer_type = test_precondition.get('installer_type', 'all') diff --git a/yardstick/benchmark/scenarios/availability/attacker/baseattacker.py b/yardstick/benchmark/scenarios/availability/attacker/baseattacker.py index a20b26396..61698da43 100644 --- a/yardstick/benchmark/scenarios/availability/attacker/baseattacker.py +++ b/yardstick/benchmark/scenarios/availability/attacker/baseattacker.py @@ -8,11 +8,11 @@ ############################################################################## from __future__ import absolute_import import pkg_resources -import yaml import logging import os import yardstick.common.utils as utils +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -56,7 +56,7 @@ class BaseAttacker(object): def __init__(self, config, context): if not BaseAttacker.attacker_cfgs: with open(attacker_conf_path) as stream: - BaseAttacker.attacker_cfgs = yaml.safe_load(stream) + BaseAttacker.attacker_cfgs = yaml_load(stream) self._config = config self._context = context diff --git a/yardstick/benchmark/scenarios/availability/monitor/basemonitor.py b/yardstick/benchmark/scenarios/availability/monitor/basemonitor.py index 6165aba74..0027925d6 100644 --- a/yardstick/benchmark/scenarios/availability/monitor/basemonitor.py +++ b/yardstick/benchmark/scenarios/availability/monitor/basemonitor.py @@ -13,7 +13,8 @@ import multiprocessing import time import os import yardstick.common.utils as utils -import yaml + +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -74,7 +75,7 @@ class BaseMonitor(multiprocessing.Process): def __init__(self, config, context, data): if not BaseMonitor.monitor_cfgs: with open(monitor_conf_path) as stream: - BaseMonitor.monitor_cfgs = yaml.safe_load(stream) + BaseMonitor.monitor_cfgs = yaml_load(stream) multiprocessing.Process.__init__(self) self._config = config self._context = context diff --git a/yardstick/benchmark/scenarios/availability/operation/baseoperation.py b/yardstick/benchmark/scenarios/availability/operation/baseoperation.py index 4c2ce82d9..d21b857b5 100644 --- a/yardstick/benchmark/scenarios/availability/operation/baseoperation.py +++ b/yardstick/benchmark/scenarios/availability/operation/baseoperation.py @@ -8,11 +8,11 @@ ############################################################################## from __future__ import absolute_import import pkg_resources -import yaml import logging import os import yardstick.common.utils as utils +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -54,7 +54,7 @@ class BaseOperation(object): def __init__(self, config, context): if not BaseOperation.operation_cfgs: with open(operation_conf_path) as stream: - BaseOperation.operation_cfgs = yaml.safe_load(stream) + BaseOperation.operation_cfgs = yaml_load(stream) self.key = '' self._config = config self._context = context diff --git a/yardstick/benchmark/scenarios/availability/result_checker/baseresultchecker.py b/yardstick/benchmark/scenarios/availability/result_checker/baseresultchecker.py index ce34d8be0..05b660105 100644 --- a/yardstick/benchmark/scenarios/availability/result_checker/baseresultchecker.py +++ b/yardstick/benchmark/scenarios/availability/result_checker/baseresultchecker.py @@ -8,11 +8,11 @@ ############################################################################## from __future__ import absolute_import import pkg_resources -import yaml import logging import os import yardstick.common.utils as utils +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -58,7 +58,7 @@ class BaseResultChecker(object): def __init__(self, config, context): if not BaseResultChecker.resultchecker_cfgs: with open(resultchecker_conf_path) as stream: - BaseResultChecker.resultchecker_cfgs = yaml.safe_load(stream) + BaseResultChecker.resultchecker_cfgs = yaml_load(stream) self.actualResult = object() self.expectedResult = object() self.success = False diff --git a/yardstick/benchmark/scenarios/lib/attach_volume.py b/yardstick/benchmark/scenarios/lib/attach_volume.py new file mode 100644 index 000000000..88124964b --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/attach_volume.py @@ -0,0 +1,53 @@ +############################################################################## +# 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 logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class AttachVolume(base.Scenario): + """Attach a volmeu to an instance""" + + __scenario_type__ = "AttachVolume" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.server_id = self.options.get("server_id", "TestServer") + self.volume_id = self.options.get("volume_id", None) + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + status = op_utils.attach_server_volume(self.server_id, + self.volume_id) + + if status: + LOG.info("Attach volume to server successful!") + else: + LOG.info("Attach volume to server failed!") diff --git a/yardstick/benchmark/scenarios/lib/create_floating_ip.py b/yardstick/benchmark/scenarios/lib/create_floating_ip.py new file mode 100644 index 000000000..328566d48 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_floating_ip.py @@ -0,0 +1,60 @@ +############################################################################## +# 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 logging +import os + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreateFloatingIp(base.Scenario): + """Create an OpenStack floating ip""" + + __scenario_type__ = "CreateFloatingIp" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.ext_net_id = os.getenv("EXTERNAL_NETWORK", "external") + + self.neutron_client = op_utils.get_neutron_client() + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + net_id = op_utils.get_network_id(self.neutron_client, self.ext_net_id) + floating_info = op_utils.create_floating_ip(self.neutron_client, + extnet_id=net_id) + if floating_info: + LOG.info("Creating floating ip successful!") + else: + LOG.error("Creating floating ip failed!") + + try: + keys = self.scenario_cfg.get('output', '').split() + except KeyError: + pass + else: + values = [floating_info["fip_id"], floating_info["fip_addr"]] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/create_keypair.py b/yardstick/benchmark/scenarios/lib/create_keypair.py new file mode 100644 index 000000000..5610de651 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/create_keypair.py @@ -0,0 +1,69 @@ +############################################################################## +# 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 logging +import paramiko + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class CreateKeypair(base.Scenario): + """Create an OpenStack keypair""" + + __scenario_type__ = "CreateKeypair" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + self.key_name = self.options.get("key_name", "yardstick_key") + self.key_filename = self.options.get("key_path", "/tmp/yardstick_key") + + self.setup_done = False + + def setup(self): + """scenario setup""" + + self.setup_done = True + + def run(self, result): + """execute the test""" + + if not self.setup_done: + self.setup() + + rsa_key = paramiko.RSAKey.generate(bits=2048, progress_func=None) + rsa_key.write_private_key_file(self.key_filename) + 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 + + keypair = op_utils.create_keypair(self.key_name, + self.key_filename + ".pub") + + if keypair: + LOG.info("Create keypair successful!") + else: + LOG.info("Create keypair failed!") + try: + keys = self.scenario_cfg.get('output', '').split() + except KeyError: + pass + else: + values = [keypair.id] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/get_numa_info.py b/yardstick/benchmark/scenarios/lib/get_numa_info.py index 4e4a44d95..75a9e3506 100644 --- a/yardstick/benchmark/scenarios/lib/get_numa_info.py +++ b/yardstick/benchmark/scenarios/lib/get_numa_info.py @@ -13,7 +13,6 @@ from __future__ import absolute_import import logging import os -import yaml from xml.etree import ElementTree as ET from yardstick import ssh @@ -22,6 +21,7 @@ from yardstick.common import constants as consts from yardstick.common.utils import change_obj_to_dict from yardstick.common.openstack_utils import get_nova_client from yardstick.common.task_template import TaskTemplate +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) @@ -47,7 +47,7 @@ class GetNumaInfo(base.Scenario): self.options.get('file')) with open(node_file) as f: - nodes = yaml.safe_load(TaskTemplate.render(f.read())) + nodes = yaml_load(TaskTemplate.render(f.read())) self.nodes = {a['host_name']: a for a in nodes['nodes']} def run(self, result): diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py index 092e9a067..dcc372b8d 100644 --- a/yardstick/benchmark/scenarios/networking/vnf_generic.py +++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py @@ -21,12 +21,12 @@ import os import re from itertools import chain -import yaml from operator import itemgetter from collections import defaultdict from yardstick.benchmark.scenarios import base from yardstick.common.utils import import_modules_from_package, itersubclasses +from yardstick.common.yaml_loader import yaml_load from yardstick.network_services.collector.subscriber import Collector from yardstick.network_services.vnf_generic import vnfdgen from yardstick.network_services.vnf_generic.vnf.base import GenericVNF @@ -119,7 +119,7 @@ class NetworkServiceTestCase(base.Scenario): # fixme: create schema to validate all fields have been provided with open_relative_file(scenario_cfg["topology"], scenario_cfg['task_path']) as stream: - topology_yaml = yaml.safe_load(stream) + topology_yaml = yaml_load(stream) self.topology = topology_yaml["nsd:nsd-catalog"]["nsd"][0] self.vnfs = [] @@ -129,7 +129,7 @@ class NetworkServiceTestCase(base.Scenario): def _get_traffic_flow(self): try: with open(self.scenario_cfg["traffic_options"]["flow"]) as fflow: - flow = yaml.safe_load(fflow) + flow = yaml_load(fflow) except (KeyError, IOError, OSError): flow = {} return flow @@ -137,7 +137,7 @@ class NetworkServiceTestCase(base.Scenario): def _get_traffic_imix(self): try: with open(self.scenario_cfg["traffic_options"]["imix"]) as fimix: - imix = yaml.safe_load(fimix) + imix = yaml_load(fimix) except (KeyError, IOError, OSError): imix = {} return imix @@ -265,8 +265,25 @@ class NetworkServiceTestCase(base.Scenario): for dpdk_port_num, netdev in enumerate(s): netdev['dpdk_port_num'] = dpdk_port_num + def _probe_netdevs(self, node, node_dict): + cmd = "PATH=$PATH:/sbin:/usr/sbin ip addr show" + netdevs = {} + with SshManager(node_dict) as conn: + if conn: + exit_status = conn.execute(cmd)[0] + if exit_status != 0: + raise IncorrectSetup("Node's %s lacks ip tool." % node) + exit_status, stdout, _ = conn.execute( + self.FIND_NETDEVICE_STRING) + if exit_status != 0: + raise IncorrectSetup( + "Cannot find netdev info in sysfs" % node) + netdevs = node_dict['netdevs'] = self.parse_netdev_info(stdout) + return netdevs + @classmethod - def _probe_missing_values(cls, netdevs, network, missing): + def _probe_missing_values(cls, netdevs, network): + mac_lower = network['local_mac'].lower() for netdev in netdevs.values(): if netdev['address'].lower() != mac_lower: @@ -288,36 +305,30 @@ class NetworkServiceTestCase(base.Scenario): """ for node, node_dict in self.context_cfg["nodes"].items(): - cmd = "PATH=$PATH:/sbin:/usr/sbin ip addr show" - 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) - exit_status, stdout, _ = conn.execute( - self.FIND_NETDEVICE_STRING) - if exit_status != 0: - raise IncorrectSetup( - "Cannot find netdev info in sysfs" % node) - netdevs = node_dict['netdevs'] = self.parse_netdev_info( - stdout) - - for network in node_dict["interfaces"].values(): - missing = self.TOPOLOGY_REQUIRED_KEYS.difference(network) - if not missing: - continue - - try: - self._probe_missing_values(netdevs, network, - missing) - except KeyError: - pass - else: - missing = self.TOPOLOGY_REQUIRED_KEYS.difference( - network) - if missing: - raise IncorrectConfig( - "Require interface fields '%s' not found, topology file " - "corrupted" % ', '.join(missing)) + for network in node_dict["interfaces"].values(): + missing = self.TOPOLOGY_REQUIRED_KEYS.difference(network) + if not missing: + continue + + # only ssh probe if there are missing values + # ssh probe won't work on Ixia, so we had better define all our values + try: + netdevs = self._probe_netdevs(node, node_dict) + except (SSHError, SSHTimeout): + raise IncorrectConfig( + "Unable to probe missing interface fields '%s', on node %s " + "SSH Error" % (', '.join(missing), node)) + try: + self._probe_missing_values(netdevs, network) + except KeyError: + pass + else: + missing = self.TOPOLOGY_REQUIRED_KEYS.difference( + network) + if missing: + raise IncorrectConfig( + "Require interface fields '%s' not found, topology file " + "corrupted" % ', '.join(missing)) # 3. Use topology file to find connections & resolve dest address self._resolve_topology() diff --git a/yardstick/common/html_template.py b/yardstick/common/html_template.py index f030a2f6c..e17c76637 100644 --- a/yardstick/common/html_template.py +++ b/yardstick/common/html_template.py @@ -158,7 +158,7 @@ report_template = """ <th>value</th> </tr> <tbody> - {% for key, value in result.info.iteritems() %} + {% for key, value in result.info.items() %} <tr> <td>{{ loop.index }}</td> <td>{{key}}</td> @@ -177,7 +177,7 @@ report_template = """ <th>value</th> </tr> <tbody> - {% for key, value in result.testcases.iteritems() %} + {% for key, value in result.testcases.items() %} <tr> <td>{{ loop.index }}</td> <td>{{key}}</td> diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index d86aee1cd..540d8d641 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -264,6 +264,15 @@ def create_aggregate_with_host(nova_client, aggregate_name, av_zone, return True +def create_keypair(nova_client, name, key_path=None): # pragma: no cover + try: + with open(key_path) as fpubkey: + keypair = get_nova_client().keypairs.create(name=name, public_key=fpubkey.read()) + return keypair + except Exception: + log.exception("Error [create_keypair(nova_client)]") + + def create_instance(json_body): # pragma: no cover try: return get_nova_client().servers.create(**json_body) @@ -290,6 +299,17 @@ def create_instance_and_wait_for_active(json_body): # pragma: no cover return None +def attach_server_volume(server_id, volume_id, device=None): # pragma: no cover + try: + get_nova_client().volumes.create_server_volume(server_id, volume_id, device) + except Exception: + log.exception("Error [attach_server_volume(nova_client, '%s', '%s')]", + server_id, volume_id) + return False + else: + return True + + def delete_instance(nova_client, instance_id): # pragma: no cover try: nova_client.servers.force_delete(instance_id) @@ -417,6 +437,18 @@ def get_port_id_by_ip(neutron_client, ip_address): # pragma: no cover 'fixed_ips') if j['ip_address'] == ip_address), None) +def create_floating_ip(neutron_client, extnet_id): # pragma: no cover + props = {'floating_network_id': extnet_id} + try: + ip_json = neutron_client.create_floatingip({'floatingip': props}) + fip_addr = ip_json['floatingip']['floating_ip_address'] + fip_id = ip_json['floatingip']['id'] + except Exception: + log.error("Error [create_floating_ip(neutron_client)]") + return None + return {'fip_addr': fip_addr, 'fip_id': fip_id} + + # ********************************************* # GLANCE # ********************************************* diff --git a/yardstick/common/task_template.py b/yardstick/common/task_template.py index 9acc21336..f6c128609 100755 --- a/yardstick/common/task_template.py +++ b/yardstick/common/task_template.py @@ -11,6 +11,22 @@ from __future__ import absolute_import import re import jinja2 import jinja2.meta +import yaml + + +def finalize_for_yaml(elem): + """Render Jinja2 output specifically for YAML files""" + # Jinaj2 by default converts None to 'None', we can't allow this + # we could convert to empty string '', or we can convert to null, aka ~ + if elem is None: + return '~' + # convert data structures to inline YAML + # match builtin types because we shouldn't be trying to render complex types + if isinstance(elem, (dict, list)): + # remove newlines because we are injecting back into YAML + # use block style for single line + return yaml.safe_dump(elem, default_flow_style=True).replace('\n', '') + return elem class TaskTemplate(object): @@ -38,7 +54,7 @@ class TaskTemplate(object): single_msg = ("Please specify template task argument:%s") raise TypeError((len(real_missing) > 1 and multi_msg or single_msg) % ", ".join(real_missing)) - return jinja2.Template(task_template).render(**kwargs) + return jinja2.Template(task_template, finalize=finalize_for_yaml).render(**kwargs) def is_really_missing(mis, task_template): diff --git a/yardstick/common/template_format.py b/yardstick/common/template_format.py index 98c0a0b3c..bd5d8376f 100644 --- a/yardstick/common/template_format.py +++ b/yardstick/common/template_format.py @@ -18,9 +18,10 @@ import yaml from oslo_serialization import jsonutils if hasattr(yaml, 'CSafeLoader'): - yaml_loader = yaml.CSafeLoader + # make a dynamic subclass so we don't override global yaml Loader + yaml_loader = type('HeatYamlLoader', (yaml.CSafeLoader,), {}) else: - yaml_loader = yaml.SafeLoader + yaml_loader = type('HeatYamlLoader', (yaml.SafeLoader,), {}) if hasattr(yaml, 'CSafeDumper'): yaml_dumper = yaml.CSafeDumper @@ -28,10 +29,13 @@ else: yaml_dumper = yaml.SafeDumper +# This breaks NetworkServiceTestCase yaml loading, because we need to conversion to +# native Python str() objects because we use use Trex and Trex is has broken unicode handling def _construct_yaml_str(self, node): # Override the default string handling function # to always return unicode objects return self.construct_scalar(node) + yaml_loader.add_constructor(u'tag:yaml.org,2002:str', _construct_yaml_str) # Unquoted dates like 2013-05-23 in yaml files get loaded as objects of type # datetime.data which causes problems in API layer when being processed by diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index f2455be3a..1d7ea071c 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -30,7 +30,6 @@ import random import ipaddress from contextlib import closing -import yaml import six from flask import jsonify from six.moves import configparser @@ -38,6 +37,7 @@ from oslo_utils import importutils from oslo_serialization import jsonutils import yardstick +from yardstick.common.yaml_loader import yaml_load logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -70,26 +70,26 @@ def itersubclasses(cls, _seen=None): yield sub -def try_append_module(name, modules): - if name not in modules: - modules[name] = importutils.import_module(name) - - def import_modules_from_package(package): """Import modules from package and append into sys.modules :param: package - Full package name. For example: rally.deploy.engines """ - path = [os.path.dirname(yardstick.__file__), ".."] + package.split(".") - path = os.path.join(*path) + yardstick_root = os.path.dirname(os.path.dirname(yardstick.__file__)) + path = os.path.join(yardstick_root, *package.split(".")) for root, dirs, files in os.walk(path): - for filename in files: - if filename.startswith("__") or not filename.endswith(".py"): - continue - new_package = ".".join(root.split(os.sep)).split("....")[1] - module_name = "%s.%s" % (new_package, filename[:-3]) + matches = (filename for filename in files if filename.endswith(".py") and + not filename.startswith("__")) + new_package = os.path.relpath(root, yardstick_root).replace(os.sep, ".") + module_names = set( + ("{}.{}".format(new_package, filename.rsplit(".py", 1)[0]) for filename in matches)) + # find modules which haven't already been imported + missing_modules = module_names.difference(sys.modules) + logger.debug("importing %s", missing_modules) + # we have already checked for already imported modules, so we don't need to check again + for module_name in missing_modules: try: - try_append_module(module_name, sys.modules) + sys.modules[module_name] = importutils.import_module(module_name) except ImportError: logger.exception("unable to import %s", module_name) @@ -97,7 +97,7 @@ def import_modules_from_package(package): def parse_yaml(file_path): try: with open(file_path) as f: - value = yaml.safe_load(f) + value = yaml_load(f) except IOError: return {} except OSError as e: diff --git a/yardstick/common/yaml_loader.py b/yardstick/common/yaml_loader.py new file mode 100644 index 000000000..0572bd582 --- /dev/null +++ b/yardstick/common/yaml_loader.py @@ -0,0 +1,33 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# yardstick: this file is copied from python-heatclient and slightly modified + +from __future__ import absolute_import + +import yaml + + +if hasattr(yaml, 'CSafeLoader'): + # make a dynamic subclass so we don't override global yaml Loader + yaml_loader = type('CustomLoader', (yaml.CSafeLoader,), {}) +else: + yaml_loader = type('CustomLoader', (yaml.SafeLoader,), {}) + +if hasattr(yaml, 'CSafeDumper'): + yaml_dumper = yaml.CSafeDumper +else: + yaml_dumper = yaml.SafeDumper + + +def yaml_load(tmpl_str): + return yaml.load(tmpl_str, Loader=yaml_loader) diff --git a/yardstick/network_services/helpers/samplevnf_helper.py b/yardstick/network_services/helpers/samplevnf_helper.py index 1eefc5ffa..dbaa47c19 100644 --- a/yardstick/network_services/helpers/samplevnf_helper.py +++ b/yardstick/network_services/helpers/samplevnf_helper.py @@ -90,7 +90,7 @@ class MultiPortConfig(object): def make_ip_addr(ip, mask_len): try: return ipaddress.ip_interface(six.text_type('/'.join([ip, mask_len]))) - except ValueError: + except (TypeError, ValueError): # None so we can skip later return None @@ -499,7 +499,10 @@ class MultiPortConfig(object): def get_route_data(self, src_key, data_key, port): route_list = self.vnfd['vdu'][0].get(src_key, []) - return next((route[data_key] for route in route_list if route['if'] == port), None) + try: + return next((route[data_key] for route in route_list if route['if'] == port), None) + except (TypeError, StopIteration, KeyError): + return None def get_ports_gateway(self, port): return self.get_route_data('routing_table', 'gateway', port) diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py index 815a2a21c..2b8905b4f 100644 --- a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py +++ b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py @@ -20,13 +20,6 @@ import logging import re from itertools import product -from yardstick.common.utils import ErrorClass - -try: - import IxNetwork -except ImportError: - IxNetwork = ErrorClass - log = logging.getLogger(__name__) IP_VERSION_4 = 4 @@ -203,6 +196,12 @@ class IxNextgen(object): self._cfg = self.get_config(tg_cfg) sys.path.append(self._cfg["py_lib_path"]) + # Import IxNetwork after getting ixia lib path + try: + import IxNetwork + except ImportError: + raise + self.ixnet = IxNetwork.IxNet() machine = self._cfg['machine'] @@ -322,13 +321,13 @@ class IxNextgen(object): def ix_get_statistics(self): views = self.ixnet.getList('/statistics', 'view') + stats = {} view_obj = self.find_view_obj("Traffic Item Statistics", views) stats = self.build_stats_map(view_obj, self.STATS_NAME_MAP) - self.find_view_obj("Port Statistics", views) + view_obj = self.find_view_obj("Port Statistics", views) ports_stats = self.build_stats_map(view_obj, self.PORT_STATS_NAME_MAP) - views = self.ixnet.getList('/statistics', 'view') view_obj = self.find_view_obj("Flow Statistics", views) stats["latency"] = self.build_stats_map(view_obj, self.LATENCY_NAME_MAP) diff --git a/yardstick/network_services/nfvi/resource.py b/yardstick/network_services/nfvi/resource.py index ce09b6597..2fb4a8e8e 100644 --- a/yardstick/network_services/nfvi/resource.py +++ b/yardstick/network_services/nfvi/resource.py @@ -73,18 +73,18 @@ class ResourceProfile(object): @classmethod def parse_simple_resource(cls, key, value): - return {'/'.join(key): value.split(":")[1]} + reskey = "/".join(rkey for rkey in key if "nsb_stats" not in rkey) + return {reskey: value.split(":")[1]} @classmethod - def get_cpu_data(cls, key_split, value): + def get_cpu_data(cls, res_key0, res_key1, value): """ Get cpu topology of the host """ pattern = r"-(\d+)" - if "cpufreq" in key_split[0]: - metric = key_split[0] - source = key_split[1] + + if 'cpufreq' in res_key0: + metric, source = res_key0, res_key1 else: - metric = key_split[1] - source = key_split[0] + metric, source = res_key1, res_key0 match = re.search(pattern, source, re.MULTILINE) if not match: @@ -128,7 +128,8 @@ class ResourceProfile(object): res_key1 = next(res_key_iter) if "cpu" in res_key0 or "intel_rdt" in res_key0: - cpu_key, name, metric, testcase = self.get_cpu_data(key_split, value) + cpu_key, name, metric, testcase = \ + self.get_cpu_data(res_key0, res_key1, value) if cpu_key in core_list: result["cpu"].setdefault(cpu_key, {}).update({name: metric}) @@ -136,16 +137,16 @@ class ResourceProfile(object): result["memory"].update({res_key1: value.split(":")[0]}) elif "hugepages" in res_key0: - result["hugepages"].update(self.parse_hugepages(key, value)) + result["hugepages"].update(self.parse_hugepages(key_split, value)) elif "dpdkstat" in res_key0: - result["dpdkstat"].update(self.parse_dpdkstat(key, value)) + result["dpdkstat"].update(self.parse_dpdkstat(key_split, value)) elif "virt" in res_key1: - result["virt"].update(self.parse_virt(key, value)) + result["virt"].update(self.parse_virt(key_split, value)) elif "ovs_stats" in res_key0: - result["ovs_stats"].update(self.parse_ovs_stats(key, value)) + result["ovs_stats"].update(self.parse_ovs_stats(key_split, value)) result["timestamp"] = testcase @@ -153,13 +154,16 @@ class ResourceProfile(object): def amqp_process_for_nfvi_kpi(self): """ amqp collect and return nfvi kpis """ - if self.amqp_client is None: + if self.amqp_client is None and self.enable: self.amqp_client = \ multiprocessing.Process(target=self.run_collectd_amqp) self.amqp_client.start() def amqp_collect_nfvi_kpi(self): """ amqp collect and return nfvi kpis """ + if not self.enable: + return {} + metric = {} while not self._queue.empty(): metric.update(self._queue.get()) @@ -193,8 +197,6 @@ class ResourceProfile(object): def _start_collectd(self, connection, bin_path): LOG.debug("Starting collectd to collect NFVi stats") - # temp disable - return connection.execute('sudo pkill -9 collectd') collectd = os.path.join(bin_path, "collectd.sh") provision_tool(connection, collectd) diff --git a/yardstick/network_services/traffic_profile/http_ixload.py b/yardstick/network_services/traffic_profile/http_ixload.py index 8a4f97f04..348056551 100644 --- a/yardstick/network_services/traffic_profile/http_ixload.py +++ b/yardstick/network_services/traffic_profile/http_ixload.py @@ -18,6 +18,7 @@ from __future__ import print_function import sys import os import logging +import collections # ixload uses its own py2. So importing jsonutils fails. So adding below # workaround to support call from yardstick @@ -26,8 +27,16 @@ try: except ImportError: import json as jsonutils -from yardstick.common.utils import join_non_strings -from yardstick.common.utils import ErrorClass + +class ErrorClass(object): + + def __init__(self, *args, **kwargs): + if 'test' not in kwargs: + raise RuntimeError + + def __getattr__(self, item): + raise AttributeError + try: from IxLoad import IxLoad, StatCollectorUtils @@ -80,11 +89,25 @@ Incoming stats: Time interval: %s """ +def validate_non_string_sequence(value, default=None, raise_exc=None): + if isinstance(value, collections.Sequence) and not isinstance(value, str): + return value + if raise_exc: + raise raise_exc + return default + + +def join_non_strings(separator, *non_strings): + try: + non_strings = validate_non_string_sequence(non_strings[0], raise_exc=RuntimeError) + except (IndexError, RuntimeError): + pass + return str(separator).join(str(non_string) for non_string in non_strings) + + class IXLOADHttpTest(object): def __init__(self, test_input): - self.test_input = jsonutils.loads(test_input) - self.parse_run_test() self.ix_load = None self.stat_utils = None self.remote_server = None @@ -94,6 +117,8 @@ class IXLOADHttpTest(object): self.chassis = None self.card = None self.ports_to_reassign = None + self.test_input = jsonutils.loads(test_input) + self.parse_run_test() @staticmethod def format_ports_for_reassignment(ports): @@ -291,4 +316,5 @@ def main(args): ixload_obj.start_http_test() if __name__ == '__main__': + LOG.info("Start http_ixload test") main(sys.argv) diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index 60979ebd2..0434f6aef 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -39,7 +39,7 @@ from yardstick.network_services.utils import get_nsb_option from stl.trex_stl_lib.trex_stl_client import STLClient from stl.trex_stl_lib.trex_stl_client import LoggerApi -from stl.trex_stl_lib.trex_stl_exceptions import STLError, STLStateError +from stl.trex_stl_lib.trex_stl_exceptions import STLError from yardstick.ssh import AutoConnectSSH @@ -457,7 +457,7 @@ class ClientResourceHelper(ResourceHelper): def get_stats(self, *args, **kwargs): try: return self.client.get_stats(*args, **kwargs) - except STLStateError: + except STLError: LOG.exception("TRex client not connected") return {} @@ -497,18 +497,24 @@ class ClientResourceHelper(ResourceHelper): def run_traffic(self, traffic_profile): # fixme: fix passing correct trex config file, # instead of searching the default path - self._build_ports() - self.client = self._connect() - self.client.reset(ports=self.my_ports) - self.client.remove_all_streams(self.my_ports) # remove all streams - traffic_profile.register_generator(self) - - while self._terminated.value == 0: - self._run_traffic_once(traffic_profile) - - self.client.stop(self.my_ports) - self.client.disconnect() - self._terminated.value = 0 + try: + self._build_ports() + self.client = self._connect() + self.client.reset(ports=self.my_ports) + self.client.remove_all_streams(self.my_ports) # remove all streams + traffic_profile.register_generator(self) + + while self._terminated.value == 0: + self._run_traffic_once(traffic_profile) + + self.client.stop(self.my_ports) + self.client.disconnect() + self._terminated.value = 0 + except STLError: + if self._terminated.value: + LOG.debug("traffic generator is stopped") + return # return if trex/tg server is stopped. + raise def terminate(self): self._terminated.value = 1 # stop client @@ -925,6 +931,7 @@ class SampleVNFTrafficGen(GenericTrafficGen): self._tg_process.start() def wait_for_instantiate(self): + # overridden by subclasses return self._wait_for_process() def _check_status(self): diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py index c15f7b954..353d31fc6 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py @@ -46,7 +46,7 @@ IXLOAD_CONFIG_TEMPLATE = '''\ }, "remote_server": "%s", "result_dir": "%s", - "ixload_cfg": '"C:/Results/%s" + "ixload_cfg": "C:/Results/%s" }''' IXLOAD_CMD = "{ixloadpy} {http_ixload} {args}" @@ -122,7 +122,6 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): super(IxLoadTrafficGen, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type) self._result = {} - self.done = False self.data = None def run_traffic(self, traffic_profile): @@ -131,7 +130,7 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): for interface in self.vnfd_helper.interfaces: vpci_list = interface['virtual-interface']["vpci"].split(":") card = vpci_list[0] - ports.append(vpci_list[1]) + ports.append(str(vpci_list[1])) for csv_file in glob.iglob(self.ssh_helper.join_bin_path('*.csv')): os.unlink(csv_file) @@ -143,6 +142,7 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): os.path.basename(self.resource_helper.resource_file_name)) http_ixload_path = os.path.join(VNF_PATH, "../../traffic_profile") + cmd = IXLOAD_CMD.format( ixloadpy=os.path.join(ixia_config["py_bin_path"], "ixloadpython"), http_ixload=os.path.join(http_ixload_path, "http_ixload.py"), @@ -169,7 +169,10 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): def instantiate(self, scenario_cfg, context_cfg): super(IxLoadTrafficGen, self).instantiate(scenario_cfg, context_cfg) - self.done = False + + def wait_for_instantiate(self): + # not needed for Ixload + pass def terminate(self): call(["pkill", "-9", "http_ixload.py"]) diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py index 07bbdae95..78d2bd8ba 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py @@ -23,11 +23,6 @@ from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTraff from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper -try: - from IxNet import IxNextgen -except ImportError: - IxNextgen = ErrorClass - LOG = logging.getLogger(__name__) WAIT_AFTER_CFG_LOAD = 10 @@ -36,6 +31,11 @@ IXIA_LIB = os.path.dirname(os.path.realpath(__file__)) IXNET_LIB = os.path.join(IXIA_LIB, "../../libs/ixia_libs/IxNet") sys.path.append(IXNET_LIB) +try: + from IxNet import IxNextgen +except ImportError: + IxNextgen = ErrorClass + class IxiaRfc2544Helper(Rfc2544ResourceHelper): @@ -59,12 +59,12 @@ class IxiaResourceHelper(ClientResourceHelper): self.pub_ports = None def _connect(self, client=None): - self.client.connect(self.vnfd_helper) + self.client._connect(self.vnfd_helper) def _build_ports(self): # self.generate_port_pairs(self.topology) - self.priv_ports = [int(x[0][-1]) for x in self.tg_port_pairs] - self.pub_ports = [int(x[1][-1]) for x in self.tg_port_pairs] + self.priv_ports = [int(x[0][2:]) for x in self.tg_port_pairs] + self.pub_ports = [int(x[1][2:]) for x in self.tg_port_pairs] self.my_ports = list(set(self.priv_ports).union(set(self.pub_ports))) def get_stats(self, *args, **kwargs): @@ -72,7 +72,7 @@ class IxiaResourceHelper(ClientResourceHelper): def stop_collect(self): self._terminated.value = 0 - if self.client: + if self.client and self.client.ixnet: self.client.ix_stop_traffic() def generate_samples(self, key=None, default=None): @@ -109,7 +109,7 @@ class IxiaResourceHelper(ClientResourceHelper): self.client.ix_assign_ports() mac = {} - for index, interface in enumerate(self.vnfd_helper.interfaces): + for index, interface in enumerate(self.vnfd_helper.interfaces, 1): virt_intf = interface["virtual-interface"] mac.update({ "src_mac_{}".format(index): virt_intf["local_mac"], @@ -163,3 +163,7 @@ class IxiaTrafficGen(SampleVNFTrafficGen): def terminate(self): self.resource_helper.stop_collect() super(IxiaTrafficGen, self).terminate() + + def wait_for_instantiate(self): + # not needed for IxNet + pass diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py index 79e42e0a8..d94a9a6e6 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py @@ -52,11 +52,14 @@ class TrexRfcResourceHelper(TrexResourceHelper): def _build_ports(self): self.tg_port_pairs, self.networks = MultiPortConfig.get_port_pairs( self.vnfd_helper.interfaces) - self.priv_ports = [int(x[0][-1]) for x in self.tg_port_pairs] - self.pub_ports = [int(x[1][-1]) for x in self.tg_port_pairs] + self.priv_ports = [int(x[0][2:]) for x in self.tg_port_pairs] + self.pub_ports = [int(x[1][2:]) for x in self.tg_port_pairs] self.my_ports = list(set(chain(self.priv_ports, self.pub_ports))) def _run_traffic_once(self, traffic_profile): + if self._terminated.value: + return + traffic_profile.execute(self) self.client_started.value = 1 time.sleep(self.RUN_DURATION) diff --git a/yardstick/network_services/vnf_generic/vnfdgen.py b/yardstick/network_services/vnf_generic/vnfdgen.py index 0120b493e..f42635006 100644 --- a/yardstick/network_services/vnf_generic/vnfdgen.py +++ b/yardstick/network_services/vnf_generic/vnfdgen.py @@ -14,26 +14,29 @@ """ Generic file to map and build vnf discriptor """ from __future__ import absolute_import + from functools import reduce import jinja2 import logging -import yaml +from yardstick.common.task_template import finalize_for_yaml from yardstick.common.utils import try_int +from yardstick.common.yaml_loader import yaml_load LOG = logging.getLogger(__name__) def render(vnf_model, **kwargs): """Render jinja2 VNF template + Do not check for missing arguments :param vnf_model: string that contains template :param kwargs: Dict with template arguments :returns:rendered template str """ - return jinja2.Template(vnf_model).render(**kwargs) + return jinja2.Template(vnf_model, finalize=finalize_for_yaml).render(**kwargs) def generate_vnfd(vnf_model, node): @@ -54,7 +57,7 @@ def generate_vnfd(vnf_model, node): rendered_vnfd = render(vnf_model, **node) # This is done to get rid of issues with serializing node del node["get"] - filled_vnfd = yaml.safe_load(rendered_vnfd) + filled_vnfd = yaml_load(rendered_vnfd) return filled_vnfd @@ -73,19 +76,24 @@ def deepgetitem(obj, item, default=None): add try_int to work with sequences - >>> d = {'snl_final': {'about': {'_icsd': {'icsd_id': 1, 'fr': [2, 3]}}}} + >>> d = {'snl_final': {'about': {'_icsd': {'icsd_id': 1, 'fr': [2, 3], '0': 24, 0: 4}}}} >>> deepgetitem(d, 'snl_final.about._icsd.icsd_id') 1 >>> deepgetitem(d, 'snl_final.about._sandbox.sbx_id') >>> >>> deepgetitem(d, 'snl_final.about._icsd.fr.1') 3 + >>> deepgetitem(d, 'snl_final.about._icsd.0') + 24 """ def getitem(obj, name): - # if integer then list index - name = try_int(name) + # try string then convert to int try: return obj[name] except (KeyError, TypeError, IndexError): - return default + name = try_int(name) + try: + return obj[name] + except (KeyError, TypeError, IndexError): + return default return reduce(getitem, item.split('.'), obj) diff --git a/yardstick/network_services/yang_model.py b/yardstick/network_services/yang_model.py index fbf224bd8..ec00c4513 100644 --- a/yardstick/network_services/yang_model.py +++ b/yardstick/network_services/yang_model.py @@ -1,107 +1,108 @@ -# Copyright (c) 2017 Intel Corporation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from __future__ import absolute_import
-from __future__ import print_function
-import logging
-import ipaddress
-import yaml
-import six
-
-LOG = logging.getLogger(__name__)
-
-
-class YangModel(object):
-
- RULE_TEMPLATE = "p acl add 1 {0} {1} {2} {3} {4} {5} {6} {7} 0 0 {8}"
-
- def __init__(self, config_file):
- super(YangModel, self).__init__()
- self._config_file = config_file
- self._options = {}
- self._rules = ''
-
- @property
- def config_file(self):
- return self._config_file
-
- @config_file.setter
- def config_file(self, value):
- self._config_file = value
- self._options = {}
- self._rules = ''
-
- def _read_config(self):
- # TODO: add some error handling in case of empty or non-existing file
- try:
- with open(self._config_file) as f:
- self._options = yaml.safe_load(f)
- except Exception as e:
- LOG.exception("Failed to load the yaml %s", e)
- raise
-
- def _get_entries(self):
- if not self._options:
- return ''
-
- rule_list = []
- for ace in self._options['access-list1']['acl']['access-list-entries']:
- # TODO: resolve ports using topology file and nodes'
- # ids: public or private.
- matches = ace['ace']['matches']
- dst_ipv4_net = matches['destination-ipv4-network']
- dst_ipv4_net_ip = ipaddress.ip_interface(six.text_type(dst_ipv4_net))
- port0_local_network = dst_ipv4_net_ip.network.network_address.exploded
- port0_prefix = dst_ipv4_net_ip.network.prefixlen
-
- src_ipv4_net = matches['source-ipv4-network']
- src_ipv4_net_ip = ipaddress.ip_interface(six.text_type(src_ipv4_net))
- port1_local_network = src_ipv4_net_ip.network.network_address.exploded
- port1_prefix = src_ipv4_net_ip.network.prefixlen
-
- lower_dport = matches['destination-port-range']['lower-port']
- upper_dport = matches['destination-port-range']['upper-port']
-
- lower_sport = matches['source-port-range']['lower-port']
- upper_sport = matches['source-port-range']['upper-port']
-
- # TODO: proto should be read from file also.
- # Now all rules in sample ACL file are TCP.
- rule_list.append('') # get an extra new line
- rule_list.append(self.RULE_TEMPLATE.format(port0_local_network,
- port0_prefix,
- port1_local_network,
- port1_prefix,
- lower_dport,
- upper_dport,
- lower_sport,
- upper_sport,
- 0))
- rule_list.append(self.RULE_TEMPLATE.format(port1_local_network,
- port1_prefix,
- port0_local_network,
- port0_prefix,
- lower_sport,
- upper_sport,
- lower_dport,
- upper_dport,
- 1))
-
- self._rules = '\n'.join(rule_list)
-
- def get_rules(self):
- if not self._rules:
- self._read_config()
- self._get_entries()
- return self._rules
+# Copyright (c) 2017 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +from __future__ import print_function +import logging +import ipaddress +import six + +from yardstick.common.yaml_loader import yaml_load + +LOG = logging.getLogger(__name__) + + +class YangModel(object): + + RULE_TEMPLATE = "p acl add 1 {0} {1} {2} {3} {4} {5} {6} {7} 0 0 {8}" + + def __init__(self, config_file): + super(YangModel, self).__init__() + self._config_file = config_file + self._options = {} + self._rules = '' + + @property + def config_file(self): + return self._config_file + + @config_file.setter + def config_file(self, value): + self._config_file = value + self._options = {} + self._rules = '' + + def _read_config(self): + # TODO: add some error handling in case of empty or non-existing file + try: + with open(self._config_file) as f: + self._options = yaml_load(f) + except Exception as e: + LOG.exception("Failed to load the yaml %s", e) + raise + + def _get_entries(self): + if not self._options: + return '' + + rule_list = [] + for ace in self._options['access-list1']['acl']['access-list-entries']: + # TODO: resolve ports using topology file and nodes' + # ids: public or private. + matches = ace['ace']['matches'] + dst_ipv4_net = matches['destination-ipv4-network'] + dst_ipv4_net_ip = ipaddress.ip_interface(six.text_type(dst_ipv4_net)) + port0_local_network = dst_ipv4_net_ip.network.network_address.exploded + port0_prefix = dst_ipv4_net_ip.network.prefixlen + + src_ipv4_net = matches['source-ipv4-network'] + src_ipv4_net_ip = ipaddress.ip_interface(six.text_type(src_ipv4_net)) + port1_local_network = src_ipv4_net_ip.network.network_address.exploded + port1_prefix = src_ipv4_net_ip.network.prefixlen + + lower_dport = matches['destination-port-range']['lower-port'] + upper_dport = matches['destination-port-range']['upper-port'] + + lower_sport = matches['source-port-range']['lower-port'] + upper_sport = matches['source-port-range']['upper-port'] + + # TODO: proto should be read from file also. + # Now all rules in sample ACL file are TCP. + rule_list.append('') # get an extra new line + rule_list.append(self.RULE_TEMPLATE.format(port0_local_network, + port0_prefix, + port1_local_network, + port1_prefix, + lower_dport, + upper_dport, + lower_sport, + upper_sport, + 0)) + rule_list.append(self.RULE_TEMPLATE.format(port1_local_network, + port1_prefix, + port0_local_network, + port0_prefix, + lower_sport, + upper_sport, + lower_dport, + upper_dport, + 1)) + + self._rules = '\n'.join(rule_list) + + def get_rules(self): + if not self._rules: + self._read_config() + self._get_entries() + return self._rules |