support storage with WEB UI

Change-Id: Ie0f80d06886ebdea8c2071218fbb898c6de1c257
This commit is contained in:
Xin 2016-03-04 14:39:59 -08:00
parent 5ffec0c85b
commit f858288df9
15 changed files with 1897 additions and 75 deletions

View File

@ -64,7 +64,7 @@
<div class="collapse navbar-collapse" id="js-navbar-collapse">
<ul class="nav navbar-nav">
<li class="dropdown " id="scaletestnav">
<li class="dropdown forHttp" id="scaletestnav">
<a href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
<span id="scaletestname">Scale/Performance</span>
<span class="caret">&nbsp;&nbsp;</span>
@ -75,7 +75,10 @@
<li class="" id="monitoringnav"><a ng-href="#/MonitoringMode">Monitoring Mode</a></li>
</ul>
</li>
<li class="" id="confignav"><a ng-href="#/Config">Configuration</a></li>
<li class="forStorage" id="storagemodenav"><a ng-href="#/StorageMode">Storage Mode</a></li>
<li class="forStorage" id="storageconfignav"><a ng-href="#/StorageConfig">Configuration</a></li>
<li class="forHttp" id="confignav"><a ng-href="#/Config">Configuration</a></li>
<li class="" id="lognav"><a ng-href="#/Log">Log</a></li>
<li class="" id="aboutnav"><a ng-href="#/About">About</a></li>
</ul>
@ -145,6 +148,9 @@
<script src="scripts/controllers/log.js"></script>
<script src="scripts/controllers/interval.js"></script>
<script src="scripts/controllers/login.js"></script>
<script src="scripts/controllers/config_storage.js"></script>
<script src="scripts/controllers/run_storage.js"></script>
<!-- endbuild -->

View File

@ -75,6 +75,16 @@ angular
controller: 'LoginCtrl',
controllerAs: 'login'
})
.when('/StorageConfig', {
templateUrl: 'views/config_storage.html',
controller: 'StorageConfigCtrl',
controllerAs: 'config_storage'
})
.when('/StorageMode', {
templateUrl: 'views/run_storage.html',
controller: 'RunStorageCtrl',
controllerAs: 'run_storage'
})
.otherwise({
redirectTo: '/InteractiveMode'
});

View File

@ -79,15 +79,28 @@ angular.module('kbWebApp')
activeNav("lognav");
break;
case "#/Login":
//alert("login");
activeNav("loginnav");
$("#loginname").text('Log In');
break;
case "#/About":
//alert("about");
activeNav("aboutnav");
break;
case "#/StorageConfig":
//alert("about");
activeNav("storageconfignav");
break;
case "#/StorageMode":
//alert("about");
activeNav("storagemodenav");
break;
default:
break;
}
@ -104,6 +117,9 @@ angular.module('kbWebApp')
$("#" + "lognav").removeClass("active");
$("#" + "loginnav").removeClass("active");
$("#" + "aboutnav").removeClass("active");
$("#" + "storageconfignav").removeClass("active");
$("#" + "storagemodenav").removeClass("active");
}
})
@ -140,7 +156,7 @@ angular.module('kbWebApp')
this.putMethod = function (url, arg) {
var deferred = $q.defer(); // declaration
$http.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
$http.put(backendUrl + url, "arg=" + encodeURIComponent(JSON.stringify(arg)))
$http.put(backendUrl + url, "arg=" + encodeURIComponent(angular.toJson(arg)))
.then(function (data) {
deferred.resolve(data); // success
},
@ -154,7 +170,7 @@ angular.module('kbWebApp')
var deferred = $q.defer(); // declaration
if (arg) {
$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
$http.post(backendUrl + url, "arg=" + encodeURIComponent(JSON.stringify(arg)))
$http.post(backendUrl + url, "arg=" + encodeURIComponent(angular.toJson(arg)))
.then(function (data) {
deferred.resolve(data); // success
},
@ -190,7 +206,7 @@ angular.module('kbWebApp')
})
.service('kbCookie', function () {
.service('kbCookie', function ($location) {
//var self = this;
this.init = function () {
sessionID = "";
@ -203,6 +219,7 @@ angular.module('kbWebApp')
topology = "";
logOffset = 0;
logNum=0;
mode = "";
};
var sessionID = "";
@ -215,6 +232,35 @@ angular.module('kbWebApp')
return sessionID;
};
var mode = "";
this.getMode = function () {
return mode;
};
this.setMode = function (sto) {
mode = sto;
return mode;
};
this.checkMode = function(thisPage){
if(thisPage == "")
{
$(".forHttp").show();
$(".forStorage").hide();
}
else if (mode=='storage')
{
$(".forHttp").hide();
$(".forStorage").show();
if(mode != thisPage) $location.path('/');
}
else if(mode=='http'){
$(".forHttp").show();
$(".forStorage").hide();
if(mode != thisPage) $location.path('/StorageMode');
}
};
var status = "";
this.getStatus = function () {
return status;

View File

@ -30,6 +30,8 @@ angular.module('kbWebApp')
];
if(kbCookie.getSessionID()==="") $location.path('/Login');
else kbCookie.checkMode('http');
//---------------------------------top navigation bar---------------------------------
$(window).on('hashchange', locationChange.change());

View File

@ -0,0 +1,253 @@
//Copyright 2016 Cisco Systems, Inc. All rights reserved.
//
// 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.
/**
* Created by xiyu3 on 9/8/15.
*/
'use strict';
angular.module('kbWebApp')
.controller('StorageConfigCtrl', function ($scope, $http, $location, showAlert, kbHttp, kbCookie, locationChange) {
this.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
if (kbCookie.getSessionID() === "") $location.path('/Login');
else kbCookie.checkMode('storage');
//---------------------------------top navigation bar---------------------------------
$(window).on('hashchange', locationChange.change());
$scope.sessionID = kbCookie.getSessionID();
$scope.status = kbCookie.getStatus();
//------------------------------------------------------
$scope.dash1status1 = "active";
$scope.dash1status1vis = true;
$scope.dash1status2 = "";
$scope.dash1status2vis = false;
//$scope.dash1status3 = "";
//$scope.dash1status3vis = false;
$scope.setDash1Status = function (dashNum) {
if (dashNum === 1) {
$scope.dash1status2 = "";
$scope.dash1status2vis = false;
//$scope.dash1status3 = "";
//$scope.dash1status3vis = false;
$scope.dash1status1 = "active";
$scope.dash1status1vis = true;
}
else if (dashNum === 2) {
$scope.dash1status1 = "";
$scope.dash1status1vis = false;
//$scope.dash1status3 = "";
//$scope.dash1status3vis = false;
$scope.dash1status2 = "active";
$scope.dash1status2vis = true;
}
//else if (dashNum === 3) {
// $scope.dash1status1 = "";
// $scope.dash1status1vis = false;
// $scope.dash1status2 = "";
// $scope.dash1status2vis = false;
// $scope.dash1status3 = "active";
// $scope.dash1status3vis = true;
//}
};
$scope.checkStatus = function () {
if ($scope.sessionID) {
kbHttp.getMethod2("/kloudbuster/status/" + $scope.sessionID)
.then(
function (response) { // .resolve
$scope.status = response.data.status;
kbCookie.setStatus($scope.status);
$scope.configStatus();
},
function (response) { // .reject
console.log("status error");
//console.log(response);
}
);
}
else {
$scope.status = "NO SESSION ID";
kbCookie.setStatus("");
}
};
$scope.checkStatus();
var disabledStagingConfig = false;
$scope.disableConfig = function (disableId) {
$("#" + disableId).find("input,button,a").each(function () {//show Config
$(this).attr("disabled", "disabled");
//$(this).removeAttr("disabled");
});
};
$scope.enableConfig = function (enableId) {
$("#" + enableId).find("input,button,a").each(function () {//disable Config
//$(this).attr("disabled", "disabled");
$(this).removeAttr("disabled");
});
};
$scope.configStatus = function () {
if ($scope.status === "READY")//show all config
{
if (disabledStagingConfig === true) {
disabledStagingConfig = false;
$scope.enableConfig("stagingConfig3");
$scope.enableConfig("getButton");
$("md-radio-button").removeAttr("disabled");
}
}
else//no config can be modified
{
if (disabledStagingConfig === false) {
disabledStagingConfig = true;
$scope.disableConfig("stagingConfig3");
$scope.disableConfig("getButton");
$("md-radio-button").attr("disabled", "disabled");
}
}
};
$("#dropdownrandrw").append('<li class="divider"></li>');
$scope.storageMode = {
"randread":{"name":"Random Read","type":"panel-randread","para":["block_size","description","iodepth","runtime","rate_iops","extra_opts"]},
"randwrite":{"name":"Random Write","type":"panel-randwrite","para":["block_size","description","iodepth","runtime","rate_iops","extra_opts"]},
"randrw":{"name":"Random Read/Write","type":"panel-randrw","para":["block_size","description","iodepth","runtime","rate","rwmixread","extra_opts"]},
"read":{"name":"Seq Read","type":"panel-read","para":["block_size","description","iodepth","runtime","rate","extra_opts"]},
"write":{"name":"Seq Write","type":"panel-write","para":["block_size","description","iodepth","runtime","rate","extra_opts"]},
"rw":{"name":"Seq Read/Write","type":"panel-rw","para":["block_size","description","iodepth","runtime","rate","rwmixread","extra_opts"]}
};
$scope.options = {
"description":{"name":"Description","default":""},
"mode":{"name":"Mode"},
"runtime":{"name":"Run Time","default":30},
"block_size":{"name":"Block Size","default":"4k"},
"iodepth":{"name":"IO Depth","default":"1"},
"rate_iops":{"name":"IOPS","default":100},
"rate":{"name":"BW","default":"60M"},
"rwmixread":{"name":"Read Percentage(%)","default":70},
"extra_opts":{"name":"Extra Options","default":""}
};
$scope.switchIndex = function (index, order) {//order = 0 delete; order = 1 move up; order = -1 move down
var tem = $scope.config.client.storage_tool_configs[index];
$scope.config.client.storage_tool_configs.splice(index, 1);//delete
if (order == 1) {
$scope.config.client.storage_tool_configs.splice(index - 1, 0, tem);
}
else if (order == -1) {
$scope.config.client.storage_tool_configs.splice(index + 1, 0, tem);
}
};
$scope.addMode = function (adding) {
var newmode= {};
for(var opt in $scope.storageMode[adding]["para"]){
var newOpt = $scope.storageMode[adding]["para"][opt];
newmode[newOpt] = $scope.options[newOpt]["default"];
}
newmode["mode"] = adding;
$scope.config.client.storage_tool_configs.splice(0,0,newmode)
};
$scope.getDefaultConfig = function () {
kbHttp.getMethod("/config/default_config")
.then(
function (response) { // .resolve
kbCookie.setConfig(response.data);
$scope.config = response.data;
console.log("get & save default config");
},
function (response) { // .reject
//console.log("get default config error:");
//console.log(response);
showAlert.showAlert("Cannot get the Default Configuration!");
}
);
//$scope.config =JSON.stringify(response);
};
$scope.getRunConfig = function () {
kbHttp.getMethod("/config/running_config/" + $scope.sessionID)
.then(
function (response) { // .resolve
kbCookie.setConfig(response.data);
$scope.config = response.data;
console.log("get & save running config");
},
function (response) { // .reject
console.log("get running config error:");
console.log(response);
}
);
};
$scope.getRunConfig();
$scope.changeConfig = function () {
if ($scope.status === "READY" || $scope.status === "") {
kbCookie.setConfig($scope.config);
$scope.chaCon = {"kb_cfg": {}, "topo_cfg": {}};
$scope.chaCon.kb_cfg = kbCookie.getConfig();
kbCookie.setTopology({"servers_rack": "", "clients_rack": ""});
$scope.chaCon.topo_cfg = kbCookie.getTopology();
$scope.config.server.availability_zone = "";
$scope.config.client.availability_zone = "";
console.log($scope.chaCon);
kbHttp.putMethod("/config/running_config/" + $scope.sessionID, $scope.chaCon)
.then(
function (response) { // .resolve
console.log("change running config");
//showAlert.showAlert("Configuration updated successfully!");
},
function (response) { // .reject
//console.log("change running config error:");
//console.log(response);
showAlert.showAlert("Failed to update configuration!");
}
)
}
else {
//console.log("config not allow to change now!");
showAlert.showAlert("Configuration cannot be changed now!");
}
};
});

View File

@ -26,6 +26,7 @@ angular.module('kbWebApp')
];
if (kbCookie.getSessionID() === "") $location.path('/Login');
else kbCookie.checkMode('http');
//---------------------------------top navigation bar---------------------------------
$(window).on('hashchange', locationChange.change());

View File

@ -27,6 +27,7 @@ angular.module('kbWebApp')
'Karma'
];
//if(kbCookie.getSessionID()!="") $location.path('/');
kbCookie.checkMode("");
//---------------------------------top navigation bar---------------------------------
$(window).on('hashchange', locationChange.change());
@ -173,25 +174,38 @@ angular.module('kbWebApp')
$scope.setConfig = function () {
if ($scope.samecloud === true) {
if ($scope.mode == "storage") {
kbCookie.setIsOneCloud(true);
$scope.credentials = { "tested-passwd": $scope.inputPassword1, "tested-rc": test_rc};
$scope.credentials = {"tested-passwd": $scope.inputPassword1, "tested-rc": test_rc};
$scope.storage_mode = true;
}
else {
kbCookie.setIsOneCloud(false);
$scope.credentials = {
"tested-passwd": $scope.inputPassword1,
"tested-rc": test_rc,
"testing-passwd": inputPassword2,
"testing-rc": test_rc2
};
else {//mode = http
$scope.storage_mode = false;
if ($scope.samecloud === true) {
kbCookie.setIsOneCloud(true);
$scope.credentials = {"tested-passwd": $scope.inputPassword1, "tested-rc": test_rc};
}
else {
kbCookie.setIsOneCloud(false);
$scope.credentials = {
"tested-passwd": $scope.inputPassword1,
"tested-rc": test_rc,
"testing-passwd": inputPassword2,
"testing-rc": test_rc2
};
}
}
//no sessionID but have cred
$scope.runCon = {"credentials": {}, kb_cfg: ""};
//$scope.runCon = {"credentials": {}, kb_cfg: ""};
$scope.runCon = {"credentials": {}, kb_cfg: "", "storage_mode": $scope.storage_mode};
//console.log($scope.credentials);
$scope.runCon.credentials = $scope.credentials;
kbCookie.setCredentials($scope.credentials);
kbCookie.setMode($scope.mode);
kbHttp.postMethod("/config/running_config", $scope.runCon)
.then(
@ -199,7 +213,14 @@ angular.module('kbWebApp')
kbCookie.setSessionID(response.data);
$scope.sessionID = kbCookie.getSessionID();
console.log("set config & get sesID:" + $scope.sessionID);
$location.path('/');
if ($scope.mode == "storage") {
$location.path('/StorageMode');
}
else {
$location.path('/');
}
},
function (response) { // .reject
//console.log("set config error:");
@ -211,7 +232,9 @@ angular.module('kbWebApp')
showAlert.showAlert("Error while connecting kloudbuster server!");
}
);
)
;
}
});
})
;

View File

@ -27,6 +27,7 @@ angular.module('kbWebApp')
if(kbCookie.getSessionID()==="") $location.path('/Login');
else kbCookie.checkMode('http');
//---------------------------------top navigation bar---------------------------------
$(window).on('hashchange', locationChange.change());

File diff suppressed because one or more lines are too long

View File

@ -134,6 +134,63 @@ td.ng-binding.ng-scope {
padding:3px;
}
.panel-randread {
border-color: #a6bddb;
}
.panel-randread>.panel-heading {
color: #ffffff;
background-color: #a6bddb;
border-color: #a6bddb;
}
.panel-randwrite {
border-color: #74a9cf;
}
.panel-randwrite>.panel-heading {
color: #ffffff;
background-color: #74a9cf;
border-color: #74a9cf;
}
.panel-randrw {
border-color: #3690c0;
}
.panel-randrw>.panel-heading {
color: #ffffff;
background-color: #3690c0;
border-color: #3690c0;
}
.panel-read {
border-color: #feb24c;
}
.panel-read>.panel-heading {
color: #ffffff;
background-color: #feb24c;
border-color: #feb24c;
}
.panel-write {
border-color: #fd8d3c;
}
.panel-write>.panel-heading {
color: #ffffff;
background-color: #fd8d3c;
border-color: #fd8d3c;
}
.panel-rw {
border-color: #fc4e2a;
}
.panel-rw>.panel-heading {
color: #ffffff;
background-color: #fc4e2a;
border-color: #fc4e2a;
}
input,button,select,textarea{outline:none}
*:focus { outline: none; }
/*--------------------------top loading bar----------------------------*/
#loading-bar-spinner {
top: 70px;

View File

@ -0,0 +1,183 @@
<!--Copyright 2016 Cisco Systems, Inc. All rights reserved.-->
<!--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.-->
<div class="md-padding dialogdemoBasicUsage" id="popupContainer" ng-cloak=""></div>
<div class="row">
<div style="float:right;padding:1px 30px" id="getButton">
<input type="button" value="Default/Reset" class="btn btn-default btn-sm" ng-click="getDefaultConfig()"
style="width:110px"/>
<!--<button type="submit" class="btn btn-default btn-sm" ng-click="getRunConfig()">Get Current Config</button>-->
<input type="button" value="Save" class="btn btn-primary btn-sm" ng-click="changeConfig()" style="width:80px"/>
</div>
</div>
<br/>
<div class="row-fluid" id="stagingConfig3">
<div id="dashboard_links" class="col-md-3">
<ul class="nav nav-pills nav-stacked">
<li class="{{dash1status1}}" ng-click="setDash1Status(1)"><a href="" class="tab-link">GENERAL CONFIGURATION</a>
</li>
<li class="{{dash1status2}}" ng-click="setDash1Status(2)"><a href="" class="tab-link">STORAGE WORKLOADS</a>
</li>
<!--<li class="{{dash1status3}}" ng-click="setDash1Status(3)"><a href="" class="tab-link">CLIENT SIDE CONFIG-->
<!--OPTIONS</a>-->
</li>
</ul>
</div>
<div id="dashboard_tabs" class="col-md-8">
<!--Start Dashboard Tab 1-->
<div id="dashboard-general" class="row" ng-show="dash1status1vis">
<h4 class="page-header" style="margin-top: 5px">GENERAL CONFIGURATION</h4>
<form name="general">
<div class="form-group">
<md-content layout-padding>
<md-input-container class="col-md-12">
<label>VM Creation Concurrency</label>
<input type="number" min="1" max="1000" step="1" name="vm_creation_concurrency"
id="vm_creation_concurrency" ng-model="config.vm_creation_concurrency"
ng-pattern="/^[1-9][0-9]{0,2}$/i" required style="text-align:left;"/>
<div ng-messages="general.vm_creation_concurrency.$error" ng-if="general.vm_creation_concurrency.$dirty">
<div ng-message="required" style="padding-right: 0;">This field is required</div>
<div ng-message="pattern" style="padding-right: 0;">Must be a number between 1 and 999</div>
</div>
</md-input-container>
</md-content>
<md-content layout-padding>
<md-input-container class="col-md-12">
<label>Volume Size (GB)</label>
<input type="number" min="1" max="1000" step="1" name="volume_size"
id="volume_size" ng-model="config.client.volume_size"
ng-pattern="/^[1-9][0-9]{0,2}$/i" required style="text-align:left;"/>
<div ng-messages="general.volume_size.$error" ng-if="general.volume_size.$dirty">
<div ng-message="required" style="padding-right: 0;">This field is required</div>
<div ng-message="pattern" style="padding-right: 0;">Must be a number between 1 and 999</div>
</div>
</md-input-container>
</md-content>
<div class="panel panel-default">
<div class="panel-heading">Flavor (per instance)</div>
<div class="panel-body">
<md-content layout-padding>
<md-input-container class="col-md-4">
<label>vCPUs</label>
<input type="number" min="1" max="999" step="1" name="client_vcpus"
id="client_vcpus" ng-model="config.client.flavor.vcpus" ng-pattern="/^[1-9][0-9]{0,2}$/i"
required style="text-align:left;"/>
<div ng-messages="client.client_vcpus.$error" ng-if="client.client_vcpus.$dirty">
<div ng-message="required" style="padding-right: 0;">This field is required</div>
<div ng-message="pattern" style="padding-right: 0;">Must be a number between 1 and 999</div>
</div>
</md-input-container>
<md-input-container class="col-md-4">
<label>RAM (MB)</label>
<input type="number" min="0" max="" step="128" name="client_ram" id="client_ram"
ng-model="config.client.flavor.ram" ng-pattern="/^[1-9][0-9]*$/i" required
style="text-align:left;"/>
<div ng-messages="client.client_ram.$error" ng-if="client.client_ram.$dirty">
<div ng-message="required" style="padding-right: 0;">This field is required</div>
<div ng-message="pattern" style="padding-right: 0;">Must be a number no less than 1</div>
</div>
</md-input-container>
<md-input-container class="col-md-4">
<label>DISK (GB)</label>
<input type="number" min="0" max="" step="" name="client_disk" id="client_disk"
ng-model="config.client.flavor.disk" ng-pattern="/^[1-9][0-9]*$/i" required
style="text-align:left;"/>
<div ng-messages="client.client_disk.$error" ng-if="client.client_disk.$dirty" role="alert">
<div ng-message="required" style="padding-right: 0;">This field is required</div>
<div ng-message="pattern" style="padding-right: 0;">Must be a number no less than 1</div>
</div>
</md-input-container>
</md-content>
</div>
</div>
</div>
</form>
</div>
<!--End Dashboard Tab 1-->
<!--Start Dashboard Tab 2-->
<div id="dashboard-server" class="row" ng-show="dash1status2vis" style="margin-bottom: 2%">
<h4 class="page-header" style="margin-top: 5px;">LIST OF STORAGE WORKLOADS TO EXECUTE IN SEQUENCE
<div class="btn-group" style="text-align: center;float:right">
<a href="" class="btn btn-xs btn-primary dropdown-toggle" style="width:150px; text-align: center"
data-toggle="dropdown" aria-expanded="false">
Add&nbsp;&nbsp;Workload&nbsp;&nbsp;<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li id="dropdown{{mode}}" ng-repeat="(mode,detail) in storageMode"><a ng-click="addMode(mode)">{{detail.name}}</a></li>
</ul>
</div>
</h4>
<form name="server">
<div>
<div ng-repeat="item in config.client.storage_tool_configs"
class="panel panel-primary {{storageMode[item['mode']]['type']}}">
<div class="panel-heading">
<h3 class="panel-title">{{$index+1}}. {{item['description']}} -- {{storageMode[item['mode']]['name']}}&nbsp;
<a style="float:right;text-decoration: none;cursor: pointer; margin-left: 4%"
ng-click="switchIndex($index,0)">×
</a>
<a style="float:right;text-decoration: none;cursor: pointer; margin-left: 2%"
ng-show="$index<config.client.storage_tool_configs.length-1" ng-click="switchIndex($index,-1)">
<span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>
</a>
<a style="float:right;text-decoration: none;cursor: pointer;"
ng-show="$index>0" ng-click="switchIndex($index,1)">
<span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>
</a>
</h3>
</div>
<div class="panel-body">
<md-content layout-gt-sm="row" layout-padding layout-wrap>
<md-input-container ng-repeat="(option,result) in item" flex="33%">
<label>{{options[option]['name']}}</label>
<input id=$parent.$index+{{option}}"
ng-model="config.client.storage_tool_configs[$parent.$index][option]" required
style="text-align:left;" ng-disabled="option == 'mode'"/>
</md-input-container>
</md-content>
</div>
</div>
</div>
</form>
</div>
<!--End Dashboard Tab 2-->
</div>
</div>

View File

@ -18,14 +18,23 @@
<div id="page-login" class="row">
<div class="col-xs-12 col-md-6 col-md-offset-3 col-sm-6 col-sm-offset-3"
style="background:rgb(236,240,241);padding:1px 20px 30px 20px;border-radius: 20px;border: 10px solid rgb(44,62,80);">
style="background:rgb(236,240,241);padding:1px 20px 20px 20px;border-radius: 20px;border: 10px solid rgb(44,62,80);">
<div class="box">
<div class="box-content">
<div class="text-center">
<h3 class="page-header">LOGIN</h3>
</div>
<hr style="margin: 10px;border-top-color:rgb(44,62,80)"/>
<h4>Server Cloud</h4>
<md-radio-group ng-model="mode" ng-init="mode='storage'">
<md-radio-button value="http" class="md-primary" style="display: inline;margin-left: 10">HTTP Mode
</md-radio-button>
<md-radio-button value="storage" class="md-primary" style="display: inline;margin-left: 10">Storage Mode
</md-radio-button>
</md-radio-group>
<hr style="margin: 10px;border-top-color:rgb(44,62,80)"/>
<h4 ng-show="mode=='http'">Server Cloud</h4>
<h4 ng-show="mode=='storage'">Client Cloud</h4>
<div class="form-group">
<!--<div>-->
@ -53,43 +62,48 @@
</div>
<hr/>
<div ng-show="mode=='http'">
<h4>Client Cloud</h4>
<hr/>
<div class="checkbox">
<h5>
<label>
<input type="checkbox" ng-model="samecloud" ng-click="clouds()"> Same as Server Cloud
</label>
</h5>
</div>
<div class="form-group">
<h4>Client Cloud</h4>
<!--<div>-->
<!--<label>admin_openrc.sh:</label>-->
<!--<input class="btn" type="file" id="file2" name="file2" enctype="multipart/form-data" disabled/>-->
<!--</div>-->
<div class="checkbox">
<h5>
<label>
<input type="checkbox" ng-model="samecloud" ng-click="clouds()"> Same as Server Cloud
</label>
</h5>
</div>
<div class="form-group">
<div class="input-group" style="margin:0 auto">
<span class="input-group-addon">openrc.sh</span>
<button class="form-control no-js" id="rcfile2" disabled></button>
<!--<div>-->
<!--<label>admin_openrc.sh:</label>-->
<!--<input class="btn" type="file" id="file2" name="file2" enctype="multipart/form-data" disabled/>-->
<!--</div>-->
<div class="box js" style="position: absolute;z-index: 3;width: 100%;height:100%;left:50%;top:25%;">
<input type="file" name="file2" id="file2" class="inputfile inputfile-3" enctype="multipart/form-data"
disabled/>
<label for="file2"><span>Choose openrc.sh file&hellip;</span></label>
<div class="input-group" style="margin:0 auto">
<span class="input-group-addon">openrc.sh</span>
<button class="form-control no-js" id="rcfile2" disabled></button>
<div class="box js" style="position: absolute;z-index: 3;width: 100%;height:100%;left:50%;top:25%;">
<input type="file" name="file2" id="file2" class="inputfile inputfile-3" enctype="multipart/form-data"
disabled/>
<label for="file2"><span>Choose openrc.sh file&hellip;</span></label>
</div>
</div>
<br/>
<div class="input-group" style="margin:0 auto">
<span class="input-group-addon">Password</span>
<input type="password" class="form-control" id="inputPassword2" ng-model="inputPassword2"
placeholder="Input Your Client Cloud's Password" disabled>
</div>
</div>
<br/>
<div class="input-group" style="margin:0 auto">
<span class="input-group-addon">Password</span>
<input type="password" class="form-control" id="inputPassword2" ng-model="inputPassword2"
placeholder="Input Your Client Cloud's Password" disabled>
</div>
</div>
<div class="text-center">
<a href="" class="btn btn-primary" ng-click="setConfig()" style="width: 150px"> Sign In </a>
</div>

View File

@ -203,35 +203,31 @@
</md-checkbox>
</div>
<!--<br/>-->
<md-content layout-padding style="padding:0">
<md-input-container class="col-md-12" style="padding-top:0">
<label>VM Count Start</label>
<input type="number" min="1" step="1" id="client_progression_vm_start"
ng-model="config.client.progression.vm_start"
ng-disabled="!config.client.progression.enabled" name="client_progression_vm_start"
ng-pattern="/^[1-9][0-9]*$/i" required style="text-align:left;"/>
<div ng-messages="interactive_progression_settings.client_progression_vm_start.$error"
ng-if="interactive_progression_settings.client_progression_vm_start.$dirty">
<div ng-message="required">This field is required</div>
<div ng-message="pattern">Must be a number no less than 1</div>
</div>
</md-input-container>
<md-input-container class="col-md-12">
<label>VM Increment Step</label>
<input type="number" min="1" step="1" id="client_progression_vm_step"
ng-model="config.client.progression.vm_step" ng-disabled="!config.client.progression.enabled"
name="client_progression_vm_step" ng-pattern="/^[1-9][0-9]*$/i" required style="text-align:left;"/>
<label>Series VM multiple</label>
<input type="number" min="1" step="1" id="client_progression_vm_multiple"
ng-model="config.client.progression.vm_multiple"
ng-disabled="!config.client.progression.enabled"
name="client_progression_vm_multiple" ng-pattern="/^[1-9][0-9]*$/i" required
style="text-align:left;"/>
<div ng-messages="interactive_progression_settings.client_progression_vm_step.$error"
ng-if="interactive_progression_settings.client_progression_vm_step.$dirty">
<div ng-messages="interactive_progression_settings.client_progression_vm_multiple.$error"
ng-if="interactive_progression_settings.client_progression_vm_multiple.$dirty">
<div ng-message="required">This field is required</div>
<div ng-message="pattern">Must be a number no less than 1</div>
</div>
</md-input-container>
<div class="input-group col-sm-12" style="margin:0 auto;padding-left: 7px">
<md-checkbox id="client_progression_vm_start" ng-checked="config.client.progression.vm_start==1"
ng-click="config.client.progression.vm_start==1? config.client.progression.vm_start=0:config.client.progression.vm_start=1"
class="md-primary" ng-disabled="!config.client.progression.enabled">
Start series with 1 VM
</md-checkbox>
</div>
<md-input-container class="col-md-12">
<label>Stop When Num of Err Packets ></label>
<input type="number" min="1" step="1" id="client_progression_http_stop_limit0"
@ -246,7 +242,8 @@
</div>
</md-input-container>
</md-content>
<span class="label col-md-12" style="color:grey;text-align: left">VM count series: {{config.client.progression.vm_start==1?1:''}} {{config.client.progression.vm_multiple}} {{config.client.progression.vm_multiple*2}} {{config.client.progression.vm_multiple*3}} {{config.client.progression.vm_multiple*4}} {{config.client.progression.vm_multiple*5}}...
</span>
<!--<div class="input-group col-sm-12" style="margin:0 auto" popover="The starting count of VMs"-->
<!--popover-trigger="mouseenter" popover-placement="right">-->
<!--<span class="input-group-addon">VM Count Start</span>-->

View File

@ -0,0 +1,298 @@
<!--Copyright 2016 Cisco Systems, Inc. All rights reserved.-->
<!--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.-->
<div class="row">
<!--<div class="col-md-2">-->
<!--<h3>{{current_mode["title"]}}</h3>-->
<!--</div>-->
<div class="col-md-9">
<!--<a class="btn btn-primary btn-xs" style="margin: 1%;" ng-repeat="mode in modes" ng-class="{active: current_index==$index}"-->
<!--ng-click="handleEvent($event, $index)">{{mode.title}}-->
<!--</a>-->
<!--<ul class="nav nav-tabs">-->
<!--<li ng-repeat="mode in modes" ng-class="{active: current_index==$index}" ng-click="handleEvent($event, $index)">-->
<!--<a href="" data-toggle="tab" aria-expanded="true">{{mode.title}}</a>-->
<!--</li>-->
<!--</ul>-->
<ul class="nav nav-tabs">
<li ng-repeat="tag in config.client.storage_tool_configs" ng-class="{active: current_index==$index}" ng-click="handleEvent($event, $index,'')">
<a data-toggle="tab" aria-expanded="true">
{{tag.description}} <span class="{{modes[tag.mode]['span']}}"></span>
</a>
</li>
</ul>
<div style="margin:1% 1%">
<a style="font-weight:bold;text-decoration: none;cursor: pointer;color:black"
ng-show="current_mode['name']==current_mode_name">| {{current_mode['title']}} |</a>
<a style="text-decoration: none;cursor: pointer;color:black" ng-click="handleEvent($event, current_index,'read')"
ng-show="current_mode['name']!=current_mode_name && current_mode_name =='rw'" ng-style="current_mode['name']=='read'?{'font-weight':'bold'}:{};">| Seq Read </a>
<a style="text-decoration: none;cursor: pointer;color:black" ng-click="handleEvent($event, current_index,'write')"
ng-show="current_mode['name']!=current_mode_name && current_mode_name =='rw'" ng-style="current_mode['name']=='write'?{'font-weight':'bold'}:{};">| Seq Write |</a>
<a style="text-decoration: none;cursor: pointer;color:black" ng-click="handleEvent($event, current_index,'read')"
ng-show="current_mode['name']!=current_mode_name && current_mode_name =='randrw'" ng-style="current_mode['name']=='randread'?{'font-weight':'bold'}:{};">| Rand Read </a>
<a style="text-decoration: none;cursor: pointer;color:black" ng-click="handleEvent($event, current_index,'write')"
ng-show="current_mode['name']!=current_mode_name && current_mode_name =='randrw'" ng-style="current_mode['name']=='randwrite'?{'font-weight':'bold'}:{};">| Rand Write |</a>
</div>
</div>
<div class="col-md-3">
<div style="text-align:right;">
<div class="btn-group">
<a href="" class="btn btn-default" ng-click="stage()" ng-disabled="setUnstage" style="width:100px">{{stageButton}}</a>
<a href="" class="btn btn-default" ng-click="scaleTest()" ng-disabled="runStatus" style="width:100px">{{runButton}}</a>
</div>
</div>
</div>
</div>
<div class="supercontainer">
<div class="container">
<div id="sidebar">
<div class="">
<!--Staging-->
<accordion close-others="oneAtATime">
<accordion-group heading="" is-open="status1.open">
<accordion-heading>
Settings
<!--(VM-->
<!--Count:{{config.server.number_tenants*config.server.routers_per_tenant*config.server.networks_per_router*config.server.vms_per_network*config.server.secgroups_per_network}})-->
<i class="pull-right glyphicon"
ng-class="{'glyphicon-chevron-down': !status1.open, 'glyphicon-chevron-up': status1.open}"></i>
</accordion-heading>
<div class="col-lg-14" id="stagingConfig">
<form class="bs-component" name="interactive_staging_settings">
<md-content layout-padding style="padding:0">
<md-input-container class="col-md-12">
<label>Max VM</label>
<input type="number" min="1" max="999" step="1" id="server_vms_per_network"
ng-model="config.server.vms_per_network" name="server_vms_per_network"
ng-pattern="/^[1-9][0-9]{0,2}$/i" required style="text-align:left;"/>
<div ng-messages="interactive_staging_settings.server_vms_per_network.$error"
ng-if="interactive_staging_settings.server_vms_per_network.$dirty">
<div ng-message="required" style="text-align:left;">This field is required</div>
<div ng-message="pattern" style="text-align:left;">Must be a number between 1 and 999</div>
</div>
</md-input-container>
</md-content>
</form>
</div>
</accordion-group>
<!--Run-->
<accordion-group heading="" is-open="status2.open">
<accordion-heading>
Progression Test <i class="pull-right glyphicon"
ng-class="{'glyphicon-chevron-down': !status2.open, 'glyphicon-chevron-up': status2.open}"></i>
</accordion-heading>
<div class="col-lg-14" id="stagingConfig1">
<form class="bs-component" name="interactive_progression_settings">
<div class="input-group col-sm-12" style="margin:0 auto"
popover="If enabled, KloudBuster will give multiple runs (progression) on the cloud, unless it reaches the scale defined in the upper sections, or the stop limit."
popover-trigger="mouseenter" popover-placement="right">
<md-checkbox id="client_progression_enabled" ng-model="config.client.progression.enabled"
class="md-primary">
Progression Test
</md-checkbox>
</div>
<!--<br/>-->
<md-content layout-padding style="padding:0">
<!--<md-input-container class="col-md-12" style="padding-top:0">-->
<!--<label>VM Count Start</label>-->
<!--<input type="number" min="1" step="1" id="client_progression_vm_start"-->
<!--ng-model="config.client.progression.vm_start"-->
<!--ng-disabled="!config.client.progression.enabled" name="client_progression_vm_start"-->
<!--ng-pattern="/^[1-9][0-9]*$/i" required style="text-align:left;"/>-->
<!--<div ng-messages="interactive_progression_settings.client_progression_vm_start.$error"-->
<!--ng-if="interactive_progression_settings.client_progression_vm_start.$dirty">-->
<!--<div ng-message="required">This field is required</div>-->
<!--<div ng-message="pattern">Must be a number no less than 1</div>-->
<!--</div>-->
<!--</md-input-container>-->
<md-input-container class="col-md-12">
<label>Series VM multiple</label>
<input type="number" min="1" step="1" id="client_progression_vm_multiple"
ng-model="config.client.progression.vm_multiple" ng-disabled="!config.client.progression.enabled"
name="client_progression_vm_multiple" ng-pattern="/^[1-9][0-9]*$/i" required
style="text-align:left;"/>
<div ng-messages="interactive_progression_settings.client_progression_vm_multiple.$error"
ng-if="interactive_progression_settings.client_progression_vm_multiple.$dirty">
<div ng-message="required">This field is required</div>
<div ng-message="pattern">Must be a number no less than 1</div>
</div>
</md-input-container>
<div class="input-group col-sm-12" style="margin:0 auto;padding-left: 7px">
<md-checkbox id="client_progression_vm_start" ng-checked="config.client.progression.vm_start==1" ng-click="config.client.progression.vm_start==1? config.client.progression.vm_start=0:config.client.progression.vm_start=1"
class="md-primary" ng-disabled="!config.client.progression.enabled">
Start series with 1 VM
</md-checkbox>
</div>
<md-input-container class="col-md-12">
<label>Stop Limit (%)</label>
<input type="number" min="1" step="1" id="client_progression_storage_stop_limit"
ng-model="config.client.progression.storage_stop_limit"
ng-disabled="!config.client.progression.enabled" name="client_progression_http_stop_limit"
ng-pattern="/^[1-9][0-9]*$/i" required style="text-align:left;"/>
<div ng-messages="interactive_progression_settings.client_progression_http_stop_limit0.$error"
ng-if="interactive_progression_settings.client_progression_http_stop_limit0.$dirty">
<div ng-message="required">This field is required</div>
<div ng-message="pattern">Must be a number no less than 1</div>
</div>
</md-input-container>
<span class="label col-md-12" style="color:grey;text-align: left">VM count series: {{config.client.progression.vm_start==1?1:''}} {{config.client.progression.vm_multiple}} {{config.client.progression.vm_multiple*2}} {{config.client.progression.vm_multiple*3}} {{config.client.progression.vm_multiple*4}} {{config.client.progression.vm_multiple*5}}...
</span>
</md-content>
</form>
</div>
<!--Run-->
</accordion-group>
</accordion>
</div>
</div>
<div class="main-content">
<div class="swipe-area"></div>
<a href="" data-toggle=".container" id="sidebar-toggle" style="text-decoration:none">
<!--<span class="bar"></span>-->
<!--<span class="bar"></span>-->
<!--<span class="bar"></span>-->
<span id="littleglyph" class="bar glyphicon glyphicon-triangle-right" style="color:white"></span>
</a>
<div class="content" id="content">
<div class="row">
<div class="my-chart" style="height: 500px;">
<h6 style="margin-bottom:0"><span>{{current_mode["y_axis"]}}</span><span
style="float:right">Latency(ms)</span></h6>
<linechart data="data" options="options"></linechart>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" style="text-align:right;margin: 0 1%">
<button type="submit" class="btn btn-default btn-xs" ng-click="saveResult()">Save Result</button>
</div>
<br/>
<table ng-table="tableParams" class="table table-responsive table-condensed table-bordered table-striped">
<tr ng-repeat="row in tableParams.data" style="text-align:center;">
<!--<td title="cols[0].title" ng-if="cols[0].show" style="margin:0 auto;padding:0;">-->
<!--<button class="btn btn-default btn-xs {{row.seq}}" ng-click=""-->
<!--style="height: 22px;width: 24px;"></button>-->
<!--</td>-->
<!--<td title="cols[1].title" data-sortable="cols[1].field">{{row.mode}}</td>-->
<td title="cols[2].title" data-sortable="cols[2].field">{{row.total_client_vms}}</td>
<td title="cols[3].title" data-sortable="cols[3].field">{{row.block_size}}b</td>
<td title="cols[4].title" data-sortable="cols[4].field">{{row.iodepth}}</td>
<td title="cols[5].title" data-sortable="cols[5].field" ng-if="current_mode.group[0] == 'rand'">
{{row.rate_iops}}
</td>
<td title="cols[6].title" data-sortable="cols[6].field" ng-if="current_mode.group[1] == 'read'">
{{row.read_iops}}
</td>
<td title="cols[7].title" data-sortable="cols[7].field" ng-if="current_mode.group[1] == 'write'">
{{row.write_iops}}
</td>
<td title="cols[8].title" data-sortable="cols[8].field" ng-if="current_mode.group[0] == 'seq'">
{{row.rate}} KB/s
</td>
<td title="cols[9].title" data-sortable="cols[9].field" ng-if="current_mode.group[1] == 'read'">
{{row.read_bw}} KB/s
</td>
<td title="cols[10].title" data-sortable="cols[10].field" ng-if="current_mode.group[1] == 'write'">
{{row.write_bw}} KB/s
</td>
</tr>
</table>
<h6 style="margin-bottom: 3%">&nbsp;</h6>
<div class="navbar navbar-default navbar-fixed-bottom" role="navigation"
style="min-height: 48px;background: transparent">
<div style="height: 12px;background-color: transparent;width: 100%;margin:0;border:0;padding:0;"></div>
<div
style="background: white; width: 52px; height: 52px;border-radius: 50%;position:absolute;z-index: 10;top:0;left:60px;">
<div class='loading spin-1'>
<div class='loading spin-2'>
<div class='loading spin-3'>
<div class='loading spin-4'>
<div class='loading spin-5'>
<div class='loading spin-6'></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="background: rgb(44,62,80);width: 100%;height: 36px;margin:0;border:0;padding:0;">
<div style="margin: 0 80px 0 120px;vertical-align: middle;">
<h5>
<div class="row">
<div class="col-md-2 col-xs-2" style="line-height:33px; height:20px; color:white;">
<!--Status:-->
<button class="btn {{statusButton}} btn-xs" ng-click="checkStatus()" style="height:24px;">{{status}}
</button>
</div>
<div class="col-md-6 col-xs-6" style="line-height:35px; height:20px; color:white;">Created&nbsp;
<!--<button class="btn btn-primary btn-xs" ng-click="checkStatus()" style="height:24px;">{{server_vm_count}}-->
<!--</button>-->
<!--&nbsp;Server VM(s),&nbsp;-->
<button class="btn btn-primary btn-xs" ng-click="checkStatus()" style="height:24px;">{{client_vm_count}}
</button>
&nbsp;Client VM(s).
</div>
<div class="col-md-4 col-xs-4" style="line-height:33px; height:20px; color:white;" ng-show="info">
<button class="btn btn-xs btn-info" style="width:220px;text-align: left;">{{info}}</button>
</div>
</div>
<!--sessionID: <button class="btn btn-info btn-xs" disabled>{{sessionID}}</button>-->
<!--<button style="float:right;" type="submit" class="btn btn-default btn-xs" ng-click="deleteSession()" popover="Session can be destroyed only if it is at READY." popover-trigger="mouseenter">Del Ses</button>-->
</h5>
</div>
</div>
</div>

View File

@ -238,38 +238,38 @@ client:
# extra_opts: (Optional, default=None)
# Extra options that will be added to the FIO client
storage_tool_configs:
- description: 'Random Read Test Case'
- description: 'Random Read'
mode: 'randread'
runtime: 30
block_size: '4k'
iodepth: 4
rate_iops: 100
- description: 'Random Write Test Case'
- description: 'Random Write'
mode: 'randwrite'
runtime: 30
block_size: '4k'
iodepth: 4
rate_iops: 100
- description: 'Random Read/Write Test Case'
- description: 'Random Read/Write'
mode: 'randrw'
runtime: 30
block_size: '4k'
iodepth: 4
rate_iops: 100
rwmixread: 70
- description: 'Sequential Read Test Case'
- description: 'Sequential Read'
mode: 'read'
runtime: 30
block_size: '64k'
iodepth: 64
rate: '60M'
- description: 'Sequential Write Test Case'
- description: 'Sequential Write'
mode: 'write'
runtime: 30
block_size: '64k'
iodepth: 64
rate: '60M'
- description: 'Sequential Read/Write Test Case'
- description: 'Sequential Read/Write'
mode: 'rw'
runtime: 30
block_size: '64k'