diff options
31 files changed, 546 insertions, 23 deletions
diff --git a/api/resources/v2/environments.py b/api/resources/v2/environments.py index 158e98be7..7e587be85 100644 --- a/api/resources/v2/environments.py +++ b/api/resources/v2/environments.py @@ -11,6 +11,7 @@ import logging from oslo_serialization import jsonutils from docker import Client +from docker.errors import APIError from api import ApiResource from api.database.v2.handlers import V2EnvironmentHandler @@ -20,6 +21,7 @@ from api.database.v2.handlers import V2ContainerHandler from yardstick.common.utils import result_handler from yardstick.common.utils import change_obj_to_dict from yardstick.common import constants as consts +from yardstick.service.environment import Environment LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) @@ -124,10 +126,41 @@ class V2Environment(ApiResource): LOG.debug('container name: %s', container.name) try: client.remove_container(container.name, force=True) - except Exception: + except APIError: LOG.exception('remove container failed') container_handler.delete_by_uuid(v) environment_handler.delete_by_uuid(environment_id) return result_handler(consts.API_SUCCESS, {'environment': environment_id}) + + +class V2SUT(ApiResource): + + def get(self, environment_id): + try: + uuid.UUID(environment_id) + except ValueError: + return result_handler(consts.API_ERROR, 'invalid environment id') + + environment_handler = V2EnvironmentHandler() + try: + environment = environment_handler.get_by_uuid(environment_id) + except ValueError: + return result_handler(consts.API_ERROR, 'no such environment id') + + if not environment.pod_id: + return result_handler(consts.API_SUCCESS, {'sut': {}}) + + pod_handler = V2PodHandler() + try: + pod = pod_handler.get_by_uuid(environment.pod_id) + except ValueError: + return result_handler(consts.API_ERROR, 'no such pod id') + else: + pod_content = pod.content + + env = Environment(pod=pod_content) + sut_info = env.get_sut_info() + + return result_handler(consts.API_SUCCESS, {'sut': sut_info}) diff --git a/api/urls.py b/api/urls.py index 4b8e39e8f..9f0abcade 100644 --- a/api/urls.py +++ b/api/urls.py @@ -26,6 +26,7 @@ urlpatterns = [ Url('/api/v2/yardstick/environments', 'v2_environments'), Url('/api/v2/yardstick/environments/action', 'v2_environments'), Url('/api/v2/yardstick/environments/<environment_id>', 'v2_environment'), + Url('/api/v2/yardstick/environments/<environment_id>/sut', 'v2_sut'), Url('/api/v2/yardstick/openrcs', 'v2_openrcs'), Url('/api/v2/yardstick/openrcs/action', 'v2_openrcs'), diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc019.rst b/docs/testing/user/userguide/opnfv_yardstick_tc019.rst index 57e8ddf79..8d79e011a 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc019.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc019.rst @@ -125,7 +125,12 @@ Yardstick Test Case Description TC019 +--------------+--------------------------------------------------------------+ |post-action | It is the action when the test cases exist. It will check | | | the status of the specified process on the host, and restart | -| | the process if it is not running for next test cases | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc045.rst b/docs/testing/user/userguide/opnfv_yardstick_tc045.rst index 0b0993c34..378176090 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc045.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc045.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC045 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc046.rst b/docs/testing/user/userguide/opnfv_yardstick_tc046.rst index cce6c6884..5308c8e7b 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc046.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc046.rst @@ -127,9 +127,14 @@ Yardstick Test Case Description TC046 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc047.rst b/docs/testing/user/userguide/opnfv_yardstick_tc047.rst index 95158cfd6..bb8ffc6ab 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc047.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc047.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC047 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc048.rst b/docs/testing/user/userguide/opnfv_yardstick_tc048.rst index 21c00d1fe..1bf627282 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc048.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc048.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC048 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test case | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc049.rst b/docs/testing/user/userguide/opnfv_yardstick_tc049.rst index f58bb9989..12ed94b7d 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc049.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc049.rst @@ -128,9 +128,14 @@ Yardstick Test Case Description TC049 | | Result: The test case is passed or not. | | | | +--------------+--------------------------------------------------------------+ -|post-action | It is the action when the test cases exist. It will check the| -| | status of the specified process on the host, and restart the | -| | process if it is not running for next test cases | +|post-action | It is the action when the test cases exist. It will check | +| | the status of the specified process on the host, and restart | +| | the process if it is not running for next test cases. | +| | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | | | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc053.rst b/docs/testing/user/userguide/opnfv_yardstick_tc053.rst index 3c6bbc628..7308babb8 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc053.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc053.rst @@ -135,6 +135,11 @@ Yardstick Test Case Description TC053 | | the status of the specified process on the host, and restart | | | the process if it is not running for next test cases. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc056.rst b/docs/testing/user/userguide/opnfv_yardstick_tc056.rst index 09b866c34..cd8cc2f20 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc056.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc056.rst @@ -142,6 +142,11 @@ Yardstick Test Case Description TC056 | | the status of the specified process on the host, and restart | | | the process if it is not running for next test cases. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+--------------------------------------------------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc057.rst b/docs/testing/user/userguide/opnfv_yardstick_tc057.rst index bb42b2aae..1bb43c9e7 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc057.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc057.rst @@ -162,8 +162,14 @@ Yardstick Test Case Description TC057 |post-action | It is the action when the test cases exist. It will check | | | the status of the cluster messaging process(corosync) on the | | | host, and restart the process if it is not running for next | -| | test cases | +| | test cases. | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+------+----------------------------------+--------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | +| | | +--------------+--------------------------------------------------------------+ diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc058.rst b/docs/testing/user/userguide/opnfv_yardstick_tc058.rst index 7c323e913..9e8427b50 100644 --- a/docs/testing/user/userguide/opnfv_yardstick_tc058.rst +++ b/docs/testing/user/userguide/opnfv_yardstick_tc058.rst @@ -109,8 +109,9 @@ Yardstick Test Case Description TC058 |conditions | with cachestat included in the image. | | | | +--------------+--------------------------------------------------------------+ -|step 1 | Two host VMs are booted, these two hosts are in two different| -| | networks, the networks are connected by a virtual router | +|step 1 | Two host VMs are booted, these two hosts are in two | +| | different networks, the networks are connected by a virtual | +| | router. | | | | +--------------+--------------------------------------------------------------+ |step 1 | start monitors: | @@ -143,7 +144,13 @@ Yardstick Test Case Description TC058 | | Virtual machines and network created in the test case will | | | be destoryed. | | | | +| | Notice: This post-action uses 'lsb_release' command to check | +| | the host linux distribution and determine the OpenStack | +| | service name to restart the process. Lack of 'lsb_release' | +| | on the host may cause failure to restart the process. | +| | | +--------------+------+----------------------------------+--------------------+ |test verdict | Fails only if SLA is not passed, or if there is a test case | | | execution problem. | +| | | +--------------+--------------------------------------------------------------+ diff --git a/gui/app/index.html b/gui/app/index.html index d959b14d2..2ea1cabe7 100644 --- a/gui/app/index.html +++ b/gui/app/index.html @@ -93,6 +93,7 @@ <script src="scripts/controllers/detail.controller.js"></script> <script src="scripts/controllers/image.controller.js"></script> <script src="scripts/controllers/pod.controller.js"></script> + <script src="scripts/controllers/sut.controller.js"></script> <script src="scripts/controllers/container.controller.js"></script> <script src="scripts/controllers/testcase.controller.js"></script> <script src="scripts/controllers/testcasedetail.controller.js"></script> diff --git a/gui/app/scripts/controllers/container.controller.js b/gui/app/scripts/controllers/container.controller.js index 3ad200a91..a7d5f0309 100644 --- a/gui/app/scripts/controllers/container.controller.js +++ b/gui/app/scripts/controllers/container.controller.js @@ -127,10 +127,15 @@ angular.module('yardStickGui2App') function chooseResult(name) { $scope.selectContainer = name; } + $scope.goBack = function goBack() { $state.go('app.projectList'); } + $scope.goNext = function goNext() { + $state.go('app.sut', {uuid: $scope.uuid}); + } + $scope.openDeleteEnv = function openDeleteEnv(id, name) { $scope.deleteName = name; $scope.deleteId = id; diff --git a/gui/app/scripts/controllers/content.controller.js b/gui/app/scripts/controllers/content.controller.js index 0288fa540..90a3f1433 100644 --- a/gui/app/scripts/controllers/content.controller.js +++ b/gui/app/scripts/controllers/content.controller.js @@ -49,6 +49,7 @@ angular.module('yardStickGui2App') $scope.gotoOpenrcPage = gotoOpenrcPage; $scope.gotoPodPage = gotoPodPage; $scope.gotoContainerPage = gotoContainerPage; + $scope.gotoSUTPage = gotoSUTPage; $scope.gotoTestcase = gotoTestcase; $scope.gotoEnviron = gotoEnviron; $scope.gotoSuite = gotoSuite; @@ -95,6 +96,12 @@ angular.module('yardStickGui2App') $state.go('app.container', { uuid: $scope.uuid }); } + function gotoSUTPage() { + $scope.path = $location.path(); + $scope.uuid = $scope.path.split('/').pop(); + $state.go('app.sut', { uuid: $scope.uuid }); + } + function gotoTestcase() { $state.go('app.testcase'); } diff --git a/gui/app/scripts/controllers/sut.controller.js b/gui/app/scripts/controllers/sut.controller.js new file mode 100644 index 000000000..092aabc41 --- /dev/null +++ b/gui/app/scripts/controllers/sut.controller.js @@ -0,0 +1,58 @@ +'use strict'; + +angular.module('yardStickGui2App') + .controller('SUTController', ['$scope', '$state', '$stateParams', 'mainFactory', 'Upload', 'toaster', '$location', 'ngDialog', + function($scope, $state, $stateParams, mainFactory, Upload, toaster, $location, ngDialog) { + + + init(); + $scope.showloading = false; + $scope.loadingOPENrc = false; + + function init() { + + + $scope.uuid = $stateParams.uuid; + $scope.sutInfo = {}; + getItemIdDetail(); + getSUTDetail(); + + } + + function getItemIdDetail() { + mainFactory.ItemDetail().get({ + 'envId': $scope.uuid + }).$promise.then(function(response) { + if (response.status == 1) { + $scope.envName = response.result.environment.name; + }else{ + mainFactory.errorHandler1(response); + } + }, function(error) { + mainFactory.errorHandler2(error); + }) + } + + function getSUTDetail(){ + mainFactory.SUTDetail().get({ + 'envId': $scope.uuid + }).$promise.then(function(resp){ + $scope.sutInfo = resp.result.sut; + console.log($scope.sutInfo); + }, function(error){ + }) + } + + $scope.goBack = function goBack() { + $state.go('app.projectList'); + } + + + $scope.goNext = function goNext() { + $scope.path = $location.path(); + $scope.uuid = $scope.path.split('/').pop(); + $state.go('app.container', { uuid: $scope.uuid }); + } + + } + ]); diff --git a/gui/app/scripts/factory/main.factory.js b/gui/app/scripts/factory/main.factory.js index 7637a9ff3..16e9c81fe 100644 --- a/gui/app/scripts/factory/main.factory.js +++ b/gui/app/scripts/factory/main.factory.js @@ -58,6 +58,13 @@ angular.module('yardStickGui2App') } }) }, + SUTDetail: function() { + return $resource(Base_URL + '/api/v2/yardstick/environments/:envId/sut', { envId: "@envId" }, { + 'get': { + method: 'GET' + } + }) + }, ImageDetail: function() { return $resource(Base_URL + '/api/v2/yardstick/images/:image_id', { image_id: "@image_id" }, { 'get': { diff --git a/gui/app/scripts/router.config.js b/gui/app/scripts/router.config.js index da2eb086b..75d5372fb 100644 --- a/gui/app/scripts/router.config.js +++ b/gui/app/scripts/router.config.js @@ -116,6 +116,15 @@ angular.module('yardStickGui2App') label: 'Container Manage' } }) + .state('app.sut', { + url: '/envsut/:uuid', + templateUrl: 'views/sut.html', + controller: 'SUTController', + params: { uuid: null }, + ncyBreadcrumb: { + label: 'SUT Manage' + } + }) .state('app.projectList', { url: '/project', templateUrl: 'views/projectList.html', diff --git a/gui/app/views/container.html b/gui/app/views/container.html index b3d78bfb1..ea5902996 100644 --- a/gui/app/views/container.html +++ b/gui/app/views/container.html @@ -5,7 +5,7 @@ <div style="width:750px;"> <h3>{{envName}} -- Container - <!--<button class="btn btn-default" style="float:right">Go Next</button>--> + <button class="btn btn-default" ng-click="goNext()" style="float:right">Next</button> </h3> <!--<p>In this process, you can input your define openrc config or upload a openrc file</p>--> diff --git a/gui/app/views/layout/sideNav.html b/gui/app/views/layout/sideNav.html index 6c4426307..2333d22d5 100644 --- a/gui/app/views/layout/sideNav.html +++ b/gui/app/views/layout/sideNav.html @@ -42,6 +42,9 @@ <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoContainerPage()" ng-class="{active:$state.includes('app.container')}"> Container </div> + <div class="panel-body " style="border:none;text-align: right;cursor:pointer" ng-click="gotoSUTPage()" ng-class="{active:$state.includes('app.sut')}"> + SUT + </div> <div class="panel-body " style="border:none;text-align: right;"> Others </div> @@ -151,4 +154,4 @@ .active.panel-body { background-color: #dfe3e4; } -</style>
\ No newline at end of file +</style> diff --git a/gui/app/views/sut.html b/gui/app/views/sut.html new file mode 100644 index 000000000..8cf1fcd6c --- /dev/null +++ b/gui/app/views/sut.html @@ -0,0 +1,33 @@ +<!--sut management--> + +<div class="content"> + <div style="display:flex;flex-direction:row;"> + <div style="width:750px;"> + + <h3>{{envName}} -- SUT + <!--<button class="btn btn-default" style="float:right">Go Next</button>--> + + </h3> + + <h2>Hosts</h2> + <div ng-repeat="(host, info) in sutInfo"> + <hr/> + <div class="results-table" style="margin-top:30px;"> + <table class="table table-striped table-hover"> + <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> + <tr ng-repeat="record in info"> + <td>{{ record[0] }}</td> + <td>{{ record[1] }}</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div> + +</div> +<toaster-container></toaster-container> + +<style> +</style> diff --git a/samples/netperf_soak.yaml b/samples/netperf_soak.yaml new file mode 100644 index 000000000..a7344dae2 --- /dev/null +++ b/samples/netperf_soak.yaml @@ -0,0 +1,71 @@ +############################################################################## +# Copyright (c) 2018 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- +# Bottlenecks long duration test need Yardstick to create VM pairs and use netperf sending messages +# This yaml file for the above operations based on Netperf mode similiar as netperf.yaml +# UDP_STREAM is used and out_opt is customized + +schema: "yardstick:task:0.1" + +{% set tx_msg_size = tx_msg_size or "8K" %} +{% set rx_msg_size = rx_msg_size or "8K" %} +{% set test_time = test_time or "10" %} +{% set out_opt = out_opt or "THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY,LOCAL_CPU_UTIL,REMOTE_CPU_UTIL,LOCAL_BYTES_SENT,REMOTE_BYTES_RECVD" %} +{% set image_name = image_name or "yardstick-image" %} +{% set cpu_num = cpu_num or 1 %} +{% set ram_num = ram_num or 512 %} +{% set disk_num = disk_num or 7 %} + +scenarios: +- + type: Netperf + options: + testname: 'UDP_STREAM' + send_msg_size: {{tx_msg_size}} + recv_msg_size: {{rx_msg_size}} + duration: {{test_time}} + output_opt: {{out_opt}} + + host: netperf-host.demo + target: netperf-target.demo + + runner: + type: Iteration + iterations: 1 + interval: 1 + run_step: 'setup,run' + + sla: + mean_latency: 100 + action: monitor + +context: + name: demo + image: {{image_name}} + flavor: + vcpus: {{cpu_num}} + ram: {{ram_num}} + disk: {{disk_num}} + user: ubuntu + + placement_groups: + pgrp1: + policy: "availability" + + servers: + netperf-host: + floating_ip: true + placement: "pgrp1" + netperf-target: + floating_ip: false + placement: "pgrp1" + + networks: + test: + cidr: '10.0.1.0/24' diff --git a/tests/ci/load_images.sh b/tests/ci/load_images.sh index caaba9e8b..d723823ee 100755 --- a/tests/ci/load_images.sh +++ b/tests/ci/load_images.sh @@ -67,6 +67,7 @@ build_yardstick_image() cd ${ANSIBLE_SCRIPTS} &&\ ansible-playbook \ -e img_property="normal" \ + -e YARD_IMG_ARCH=${YARD_IMG_ARCH} \ -vvv -i inventory.ini build_yardstick_image.yml if [ ! -f "${QCOW_IMAGE}" ]; then diff --git a/yardstick/benchmark/scenarios/networking/netperf.py b/yardstick/benchmark/scenarios/networking/netperf.py index a8d9010ed..33c02d409 100755 --- a/yardstick/benchmark/scenarios/networking/netperf.py +++ b/yardstick/benchmark/scenarios/networking/netperf.py @@ -104,7 +104,9 @@ class Netperf(base.Scenario): cmd_args = "-H %s -l %s -t %s" % (ipaddr, testlen, testname) # get test specific options - default_args = "-O 'THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY'" + output_opt = options.get( + "output_opt", "THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY") + default_args = "-O %s" % output_opt cmd_args += " -- %s" % default_args option_pair_list = [("send_msg_size", "-m"), ("recv_msg_size", "-M"), diff --git a/yardstick/common/ansible_common.py b/yardstick/common/ansible_common.py index be262c215..38d2dd7c2 100644 --- a/yardstick/common/ansible_common.py +++ b/yardstick/common/ansible_common.py @@ -31,6 +31,7 @@ import six.moves.configparser as ConfigParser import yaml from six import StringIO from chainmap import ChainMap +from oslo_serialization import jsonutils from yardstick.common.utils import Timer from yardstick.common import constants as consts @@ -508,6 +509,58 @@ class AnsibleCommon(object): timeout = 1200.0 return timeout + def _generate_ansible_cfg(self, directory): + parser = ConfigParser.ConfigParser() + parser.add_section('defaults') + parser.set('defaults', 'host_key_checking', 'False') + + cfg_path = os.path.join(directory, 'setup.cfg') + with open(cfg_path, 'w') as f: + parser.write(f) + + def get_sut_info(self, directory, sut_dir='sut'): + if not os.path.isdir(directory): + raise OSError('No such directory: %s' % directory) + + self._generate_ansible_cfg(directory) + + prefix = 'tmp' + self.gen_inventory_ini_dict() + ini_file = self._gen_ansible_inventory_file(directory, prefix=prefix) + with ini_file as f: + inventory_path = str(f) + + self._exec_get_sut_info_cmd(directory, inventory_path, sut_dir) + + sut_dir = os.path.join(directory, sut_dir) + sut_info = self._gen_sut_info_dict(sut_dir) + + return sut_info + + def _exec_get_sut_info_cmd(self, directory, inventory_path, sut_dir): + cmd = ['ansible', 'all', '-m', 'setup', '-i', + inventory_path, '--tree', sut_dir] + + proc = Popen(cmd, stdout=PIPE, cwd=directory) + output, _ = proc.communicate() + retcode = proc.wait() + LOG.debug("exit status = %s", retcode) + if retcode != 0: + raise CalledProcessError(retcode, cmd, output) + + def _gen_sut_info_dict(self, sut_dir): + sut_info = {} + + if os.path.isdir(sut_dir): + root, _, files = next(os.walk(sut_dir)) + for filename in files: + abs_path = os.path.join(root, filename) + with open(abs_path) as f: + data = jsonutils.load(f) + sut_info[filename] = data + + return sut_info + def execute_ansible(self, playbooks, directory, timeout=None, extra_vars=None, ansible_check=False, prefix='tmp', verbose=False): diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index a0edd3ba9..633b36f91 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -112,3 +112,11 @@ class ScenarioCreateSubnetError(YardstickException): class ScenarioDeleteRouterError(YardstickException): message = 'Delete Neutron Router Scenario failed' + + +class MissingPodInfoError(YardstickException): + message = 'Missing pod args, please check' + + +class UnsupportedPodFormatError(YardstickException): + message = 'Failed to load pod info, unsupported format' diff --git a/yardstick/service/__init__.py b/yardstick/service/__init__.py new file mode 100644 index 000000000..1c3953de6 --- /dev/null +++ b/yardstick/service/__init__.py @@ -0,0 +1,12 @@ +############################################################################## +# Copyright (c) 2016 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 +############################################################################## + + +class Service(object): + pass diff --git a/yardstick/service/environment.py b/yardstick/service/environment.py new file mode 100644 index 000000000..324589f79 --- /dev/null +++ b/yardstick/service/environment.py @@ -0,0 +1,101 @@ +############################################################################## +# Copyright (c) 2016 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 tempfile +import logging +import collections + +from oslo_serialization import jsonutils + +from yardstick.service import Service +from yardstick.common.exceptions import MissingPodInfoError +from yardstick.common.exceptions import UnsupportedPodFormatError +from yardstick.common.ansible_common import AnsibleCommon + +LOG = logging.getLogger(__name__) + + +class Environment(Service): + def __init__(self, pod=None): + super(Environment, self).__init__() + # pod can be a dict or a json format string + self.pod = pod + + def get_sut_info(self): + temdir = tempfile.mkdtemp(prefix='sut') + + nodes = self._load_pod_info() + ansible = AnsibleCommon(nodes=nodes) + ansible.gen_inventory_ini_dict() + sut_info = ansible.get_sut_info(temdir) + + return self._format_sut_info(sut_info) + + def _load_pod_info(self): + if self.pod is None: + raise MissingPodInfoError + + if isinstance(self.pod, collections.Mapping): + try: + return self.pod['nodes'] + except KeyError: + raise UnsupportedPodFormatError + + try: + return jsonutils.loads(self.pod)['nodes'] + except (ValueError, KeyError): + raise UnsupportedPodFormatError + + def _format_sut_info(self, sut_info): + return {k: self._format_node_info(v) for k, v in sut_info.items()} + + def _format_node_info(self, node_info): + info = [] + facts = node_info.get('ansible_facts', {}) + + info.append(['hostname', facts.get('ansible_hostname')]) + + info.append(['product_name', facts.get('ansible_product_name')]) + info.append(['product_version', facts.get('ansible_product_version')]) + + processors = facts.get('ansible_processor', []) + try: + processor_type = '{} {}'.format(processors[0], processors[1]) + except IndexError: + LOG.exception('No Processor in SUT data') + processor_type = None + + info.append(['processor_type', processor_type]) + info.append(['architecture', facts.get('ansible_architecture')]) + info.append(['processor_cores', facts.get('ansible_processor_cores')]) + info.append(['processor_vcpus', facts.get('ansible_processor_vcpus')]) + + memory = facts.get('ansible_memtotal_mb') + memory = round(memory * 1.0 / 1024, 2) if memory else None + info.append(['memory', '{} GB'.format(memory)]) + + devices = facts.get('ansible_devices', {}) + info.extend([self._get_device_info(k, v) for k, v in devices.items()]) + + lsb_description = facts.get('ansible_lsb', {}).get('description') + info.append(['OS', lsb_description]) + + interfaces = facts.get('ansible_interfaces') + info.append(['interfaces', interfaces]) + if isinstance(interfaces, collections.Sequence): + info.extend([self._get_interface_info(facts, i) for i in interfaces]) + info = [i for i in info if i] + + return info + + def _get_interface_info(self, facts, name): + mac = facts.get('ansible_{}'.format(name), {}).get('macaddress') + return [name, mac] if mac else [] + + def _get_device_info(self, name, info): + return ['disk_{}'.format(name), info.get('size')] diff --git a/yardstick/tests/unit/common/test_ansible_common.py b/yardstick/tests/unit/common/test_ansible_common.py index b01195fcc..48d8a60c8 100644 --- a/yardstick/tests/unit/common/test_ansible_common.py +++ b/yardstick/tests/unit/common/test_ansible_common.py @@ -17,6 +17,7 @@ from __future__ import absolute_import import os import tempfile +import shutil from collections import defaultdict import mock @@ -246,3 +247,18 @@ class AnsibleCommonTestCase(unittest.TestCase): a.execute_ansible('', d, ansible_check=True, verbose=True) finally: os.rmdir(d) + + def test_get_sut_info(self): + d = tempfile.mkdtemp() + a = ansible_common.AnsibleCommon({}) + try: + a.get_sut_info(d) + finally: + shutil.rmtree(d) + + def test_get_sut_info_not_exist(self): + a = ansible_common.AnsibleCommon({}) + try: + a.get_sut_info('/hello/world') + except OSError: + pass diff --git a/yardstick/tests/unit/service/__init__.py b/yardstick/tests/unit/service/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/unit/service/__init__.py diff --git a/yardstick/tests/unit/service/test_environment.py b/yardstick/tests/unit/service/test_environment.py new file mode 100644 index 000000000..4af9a3958 --- /dev/null +++ b/yardstick/tests/unit/service/test_environment.py @@ -0,0 +1,49 @@ +############################################################################## +# Copyright (c) 2016 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.service.environment import Environment +from yardstick.service.environment import AnsibleCommon +from yardstick.common.exceptions import UnsupportedPodFormatError + + +class EnvironmentTestCase(unittest.TestCase): + + def test_get_sut_info(self): + pod_info = { + 'nodes': [ + { + 'name': 'node1', + 'host_name': 'host1', + 'role': 'Controller', + 'ip': '10.1.0.50', + 'user': 'root', + 'passward': 'root' + } + ] + } + + AnsibleCommon.gen_inventory_ini_dict = mock.MagicMock() + AnsibleCommon.get_sut_info = mock.MagicMock(return_value={'node1': {}}) + + env = Environment(pod=pod_info) + env.get_sut_info() + + def test_get_sut_info_pod_str(self): + pod_info = 'nodes' + + env = Environment(pod=pod_info) + with self.assertRaises(UnsupportedPodFormatError): + env.get_sut_info() + + +if __name__ == '__main__': + unittest.main() |