diff options
author | grakiss <grakiss.wanglei@huawei.com> | 2017-10-30 07:26:37 +0000 |
---|---|---|
committer | Leo wang <grakiss.wanglei@huawei.com> | 2017-11-01 08:44:36 +0000 |
commit | 55bb29b1d7b977b387a74f754b4baea94274141c (patch) | |
tree | 74ef8f67b87213ad1eacd9d681c05490c000003a | |
parent | 62562458e6fd007f4240b669f509f772dd883ca5 (diff) |
[cvp-web] Show some SUT hardware info in 'My Results'
[cvp-web] Show SUT endpoint in web page
JIRA: DOVETAIL-541
JIRA: DOVETAIL-547
Show some SUT hardware info that dovetail concern in 'My Results' web page.
Show the info of all endpoints get from Dovetail tool in the web page.
Change-Id: Ibc465396e17b7c22678e3948fa2f659cbff6f323
Signed-off-by: grakiss <grakiss.wanglei@huawei.com>
-rw-r--r-- | cvp/3rd_party/static/testapi-ui/app.js | 7 | ||||
-rw-r--r-- | cvp/3rd_party/static/testapi-ui/components/results/results.html | 6 | ||||
-rw-r--r-- | cvp/3rd_party/static/testapi-ui/components/results/resultsController.js | 5 | ||||
-rw-r--r-- | cvp/3rd_party/static/testapi-ui/components/sut/sut.html | 40 | ||||
-rw-r--r-- | cvp/3rd_party/static/testapi-ui/components/sut/sutController.js | 48 | ||||
-rw-r--r-- | cvp/3rd_party/static/testapi-ui/index.html | 3 | ||||
-rw-r--r-- | cvp/docker/nginx/sites-enabled/default | 6 | ||||
-rw-r--r-- | cvp/opnfv_testapi/resources/sut_handlers.py | 112 | ||||
-rw-r--r-- | cvp/opnfv_testapi/resources/sut_models.py | 31 | ||||
-rw-r--r-- | cvp/opnfv_testapi/router/url_mappings.py | 2 |
10 files changed, 256 insertions, 4 deletions
diff --git a/cvp/3rd_party/static/testapi-ui/app.js b/cvp/3rd_party/static/testapi-ui/app.js index 5a3cc069..eea8e38e 100644 --- a/cvp/3rd_party/static/testapi-ui/app.js +++ b/cvp/3rd_party/static/testapi-ui/app.js @@ -115,7 +115,12 @@ templateUrl: '/testapi-ui/components/products/cloud.html', controller: 'ProductController as ctrl' }). - state('application', { + state('sut', { + url: '/suts/:testID', + templateUrl: '/testapi-ui/components/sut/sut.html', + controller: 'SutController as ctrl' + }). + state('application', { url: '/application', templateUrl: '/testapi-ui/components/application/application.html', controller: 'ApplicationController as ctrl' diff --git a/cvp/3rd_party/static/testapi-ui/components/results/results.html b/cvp/3rd_party/static/testapi-ui/components/results/results.html index e1d05b2d..cd38ad75 100644 --- a/cvp/3rd_party/static/testapi-ui/components/results/results.html +++ b/cvp/3rd_party/static/testapi-ui/components/results/results.html @@ -25,6 +25,7 @@ <th>Label</th> <th>Status</th> <th>Log</th> + <th>SUT</th> <th class="col-md-2">Operation</th> <th class="col-md-2">Share List</th> </tr> @@ -32,13 +33,14 @@ <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> <tr ng-repeat="(index, result) in ctrl.data.tests"> - <td>{{ result.upload_date }}</td> + <td>{{ result.upload_date | limitTo:19}}</td> <td><a ng-click="ctrl.gotoResultDetail(result.id, result._id)">{{ result.id }}</a></td> <td>{{ result.filename || "None"}}</td> <td><div class="popover-wrapper"><a editable-theme="bs3" onbeforesave="ctrl.toggleCheck(result, 'label', $data)" editable-text="result.label"> {{ result.label || "None" }}</a></div></td> <td>{{ result.status }}</td> <td><a ng-click="ctrl.downloadLogs(result.id)">logs</a></td> - <td> + <td><a ng-click="ctrl.gotoSUT(result.id)">info</a></td> + <td> <div class="btn-group" uib-dropdown> <a id="single-button" type="button" class="nectar-button medium accent-color regular-button" uib-dropdown-toggle> Operation<span class="caret"></span> diff --git a/cvp/3rd_party/static/testapi-ui/components/results/resultsController.js b/cvp/3rd_party/static/testapi-ui/components/results/resultsController.js index 2ece86fb..86f7c5d6 100644 --- a/cvp/3rd_party/static/testapi-ui/components/results/resultsController.js +++ b/cvp/3rd_party/static/testapi-ui/components/results/resultsController.js @@ -59,6 +59,7 @@ ctrl.associateProductVersion = associateProductVersion; ctrl.getProductVersions = getProductVersions; ctrl.prepVersionEdit = prepVersionEdit; + ctrl.gotoSUT = gotoSUT; ctrl.gotoResultDetail = gotoResultDetail; ctrl.toggleCheck = toggleCheck; ctrl.toReview = toReview; @@ -496,5 +497,9 @@ $state.go('resultsDetail', {'testID': testId, 'innerID': innerID}); } + function gotoSUT(testId) { + $state.go('sut', {'testID': testId}); + } + } })(); diff --git a/cvp/3rd_party/static/testapi-ui/components/sut/sut.html b/cvp/3rd_party/static/testapi-ui/components/sut/sut.html new file mode 100644 index 00000000..d9692b87 --- /dev/null +++ b/cvp/3rd_party/static/testapi-ui/components/sut/sut.html @@ -0,0 +1,40 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" + <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> + +<link rel="stylesheet" href="testapi-ui/assets/css/combine.css" /> + +<h2>Endpoints</h2> +<div class="results-table" style="margin-top:30px;overflow:scroll"> + <table class="table table-striped table-hover"> + <thead> + <tr> + <th>Service Name</th> + <th>Service Type</th> + <th>URL</th> + <th>Enabled</th> + </tr> + </thead> + <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"> + <tr ng-repeat="endpoint in ctrl.sutData.endpoint_info"> + <td>{{ endpoint['Service Name'] }}</td> + <td>{{ endpoint['Service Type'] }}</td> + <td>{{ endpoint['URL'] }}</td> + <td>{{ endpoint['Enabled'] }}</td> + </tr> + </tbody> + </table> +</div> + +<h2>Hosts</h2> +<div ng-repeat="(host, info) in ctrl.sutData.hardware_info"> + <div class="results-table" style="margin-top:30px;overflow:scroll"> + <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> diff --git a/cvp/3rd_party/static/testapi-ui/components/sut/sutController.js b/cvp/3rd_party/static/testapi-ui/components/sut/sutController.js new file mode 100644 index 00000000..3d662ffa --- /dev/null +++ b/cvp/3rd_party/static/testapi-ui/components/sut/sutController.js @@ -0,0 +1,48 @@ +/* + * 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. + */ + +(function () { + 'use strict'; + + angular + .module('testapiApp') + .controller('SutController', SutController); + + SutController.$inject = [ + '$http', '$stateParams', 'testapiApiUrl' + ]; + + /** + */ + function SutController($http, $stateParams, testapiApiUrl) { + + var ctrl = this; + + function init(){ + ctrl.sutData = {"hardware_info": {}, "endpoint_info": {}}; + ctrl.testID = $stateParams.testID; + ctrl.getSutData(); + } + + ctrl.getSutData = function(){ + $http.get(testapiApiUrl + "/suts/hardware/" + ctrl.testID).then(function(resp){ + ctrl.sutData = resp.data; + }, function(error){ + alert('Error when get SUT data'); + }); + } + + init(); + } +})(); diff --git a/cvp/3rd_party/static/testapi-ui/index.html b/cvp/3rd_party/static/testapi-ui/index.html index b6bdb5a1..8ca6e631 100644 --- a/cvp/3rd_party/static/testapi-ui/index.html +++ b/cvp/3rd_party/static/testapi-ui/index.html @@ -51,7 +51,8 @@ <script src="testapi-ui/components/guidelines/guidelinesController.js"></script> <script src="testapi-ui/components/results/resultsController.js"></script> <script src="testapi-ui/components/results-report/resultsReportController.js"></script> - <script src="testapi-ui/components/application/applicationController.js"></script> + <script src="testapi-ui/components/sut/sutController.js"></script> + <script src="testapi-ui/components/application/applicationController.js"></script> <script src="testapi-ui/components/profile/profileController.js"></script> <script src="testapi-ui/components/auth-failure/authFailureController.js"></script> <script src="testapi-ui/components/logout/logoutController.js"></script> diff --git a/cvp/docker/nginx/sites-enabled/default b/cvp/docker/nginx/sites-enabled/default index b6b6a7ed..e2e718ce 100644 --- a/cvp/docker/nginx/sites-enabled/default +++ b/cvp/docker/nginx/sites-enabled/default @@ -101,6 +101,12 @@ server { proxy_set_header Host $host; } + location ~* /api/v1/suts/hardware/([a-zA-Z0-9\-]+) { + proxy_pass http://cvpapi/api/v1/suts/hardware/$1; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + } + location /api/v1/ { proxy_pass http://testapi/api/v1/; proxy_set_header X-Real-IP $remote_addr; diff --git a/cvp/opnfv_testapi/resources/sut_handlers.py b/cvp/opnfv_testapi/resources/sut_handlers.py new file mode 100644 index 00000000..16c50b83 --- /dev/null +++ b/cvp/opnfv_testapi/resources/sut_handlers.py @@ -0,0 +1,112 @@ +############################################################################## +# Copyright (c) 2017 +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import logging +import json +import os + +from opnfv_testapi.resources import handlers +from opnfv_testapi.resources import sut_models +from opnfv_testapi.tornado_swagger import swagger + +LOG = logging.getLogger(__name__) +LOG.setLevel(logging.DEBUG) + +RESULT_PATH = '/home/testapi/logs/{}/results' + + +class GenericSutHandler(handlers.GenericApiHandler): + def __init__(self, application, request, **kwargs): + super(GenericSutHandler, self).__init__(application, + request, + **kwargs) + self.table = "suts" + self.table_cls = sut_models.Sut + + +class HardwareHandler(GenericSutHandler): + @swagger.operation(nickname="getHardwareById") + def get(self, id): + endpoint_info = self._read_endpoint_info(id) + LOG.debug('Endpoint info: %s', endpoint_info) + + all_info = self._read_sut_info(id) + LOG.debug('All SUT info: %s', all_info) + + hardware_info = {k: self._get_single_host_info(v) + for k, v in all_info.items()} + LOG.debug('SUT info: %s', hardware_info) + + data = { + 'endpoint_info': endpoint_info, + 'hardware_info': hardware_info + } + + self.write(data) + + def _read_endpoint_info(self, id): + path = os.path.join(RESULT_PATH.format(id), 'endpoint_info.json') + try: + with open(path) as f: + endpoint_info = json.load(f) + except Exception: + endpoint_info = [] + + return endpoint_info + + def _read_sut_info(self, id): + path = os.path.join(RESULT_PATH.format(id), 'all_hosts_info.json') + try: + with open(path) as f: + all_info = json.load(f) + except Exception: + all_info = {} + return all_info + + def _get_single_host_info(self, single_info): + info = [] + facts = single_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]) + 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/cvp/opnfv_testapi/resources/sut_models.py b/cvp/opnfv_testapi/resources/sut_models.py new file mode 100644 index 00000000..b4a869b6 --- /dev/null +++ b/cvp/opnfv_testapi/resources/sut_models.py @@ -0,0 +1,31 @@ +############################################################################## +# Copyright (c) 2017 +# 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 opnfv_testapi.resources import models +from opnfv_testapi.tornado_swagger import swagger + + +@swagger.model() +class Sut(models.ModelBase): + """ + """ + def __init__(self): + pass + + +@swagger.model() +class Suts(models.ModelBase): + """ + @property suts: + @ptype tests: C{list} of L{Sut} + """ + def __init__(self): + self.suts = list() + + @staticmethod + def attr_parser(): + return {'suts': Sut} diff --git a/cvp/opnfv_testapi/router/url_mappings.py b/cvp/opnfv_testapi/router/url_mappings.py index 73c771fe..83190ee4 100644 --- a/cvp/opnfv_testapi/router/url_mappings.py +++ b/cvp/opnfv_testapi/router/url_mappings.py @@ -11,6 +11,7 @@ from opnfv_testapi.resources import handlers from opnfv_testapi.resources import result_handlers from opnfv_testapi.resources import test_handlers from opnfv_testapi.resources import application_handlers +from opnfv_testapi.resources import sut_handlers from opnfv_testapi.ui.auth import sign from opnfv_testapi.ui.auth import user @@ -27,6 +28,7 @@ mappings = [ (r"/api/v1/cvp/applications/([^/]+)", application_handlers.ApplicationsGURHandler), + (r"/api/v1/suts/hardware/([^/]+)", sut_handlers.HardwareHandler), (r'/api/v1/auth/signin', sign.SigninHandler), |