Support add template with parameters in Vitrage UI
Change-Id: I626fd15ba36538f1a2194041ac739b1d6cc3ecf5 Story: 2004056 Task: 29571
This commit is contained in:
parent
5f61f8dcad
commit
94ead80eb5
@ -72,7 +72,6 @@ def alarms(request, vitrage_id='all', all_tenants='false',
|
||||
next_page=True,
|
||||
marker=None
|
||||
):
|
||||
|
||||
return vitrageclient(request).alarm.list(vitrage_id=vitrage_id,
|
||||
all_tenants=all_tenants,
|
||||
limit=limit,
|
||||
@ -95,7 +94,6 @@ def history(request, all_tenants='false',
|
||||
next_page=True,
|
||||
marker=None
|
||||
):
|
||||
|
||||
return vitrageclient(request).alarm.history(all_tenants=all_tenants,
|
||||
start=start,
|
||||
end=end,
|
||||
@ -133,9 +131,24 @@ def template_delete(request, template_id):
|
||||
def template_add(request):
|
||||
template = json.loads(request.body)
|
||||
type = template.get('type')
|
||||
params = template.get('params')
|
||||
with tempfile.NamedTemporaryFile(suffix='.yaml') as temp:
|
||||
temp.write(template.get('template'))
|
||||
temp.flush()
|
||||
temp.seek(0)
|
||||
response = vitrageclient(request).template.add(temp.name, type)
|
||||
response = vitrageclient(request).template.add(temp.name, type, params)
|
||||
return response
|
||||
|
||||
|
||||
def template_validate(request):
|
||||
template = json.loads(request.body)
|
||||
type = template.get('type')
|
||||
params = template.get('params')
|
||||
with tempfile.NamedTemporaryFile(suffix='.yaml') as temp:
|
||||
temp.write(template.get('template'))
|
||||
temp.flush()
|
||||
temp.seek(0)
|
||||
response = vitrageclient(request).template.validate(temp.name,
|
||||
type,
|
||||
params)
|
||||
return response
|
||||
|
@ -13,6 +13,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from django.views import generic
|
||||
import json
|
||||
import logging
|
||||
from openstack_dashboard.api.rest import urls
|
||||
from openstack_dashboard.api.rest import utils as rest_utils
|
||||
@ -39,9 +40,6 @@ class Topolgy(generic.View):
|
||||
"""
|
||||
|
||||
''' original default is graph '''
|
||||
|
||||
LOG.info("--------- reques --------------- %s", str(request))
|
||||
|
||||
graph_type = 'tree'
|
||||
all_tenants = 'false'
|
||||
root = None
|
||||
@ -174,12 +172,14 @@ class Rca(generic.View):
|
||||
|
||||
@urls.register
|
||||
class Templates(generic.View):
|
||||
|
||||
"""API for vitrage templates."""
|
||||
|
||||
url_regex = r'vitrage/template/(?P<template_id>.+|default)/$'
|
||||
|
||||
@rest_utils.ajax()
|
||||
def get(self, request, template_id):
|
||||
|
||||
"""Get a single template with the vitrage id.
|
||||
|
||||
The following get template may be passed in the GET
|
||||
@ -200,12 +200,15 @@ class Templates(generic.View):
|
||||
|
||||
@rest_utils.ajax()
|
||||
def post(self, request, **kwargs):
|
||||
"""Add a single template.
|
||||
"""Add or validate a single template.
|
||||
|
||||
request.body holds template in format:
|
||||
{template: template_string
|
||||
type: template_type}
|
||||
type: template_type
|
||||
params: params}
|
||||
|
||||
"""
|
||||
|
||||
json_request = json.loads(request.body)
|
||||
if json_request["method"] == 'validate':
|
||||
return vitrage.template_validate(request)
|
||||
return vitrage.template_add(request)
|
||||
|
@ -20,6 +20,7 @@
|
||||
getRca: getRca,
|
||||
getTemplates: getTemplates,
|
||||
deleteTemplate: deleteTemplate,
|
||||
validateTemplate: validateTemplate,
|
||||
addTemplate: addTemplate
|
||||
};
|
||||
|
||||
@ -89,14 +90,22 @@
|
||||
});
|
||||
}
|
||||
|
||||
function addTemplate(template, type) {
|
||||
var temp = { 'template' : template, 'type': type }
|
||||
function addTemplate(template, type, parameters) {
|
||||
var temp = {'template': template, 'type': type, "params": parameters, "method": 'add'};
|
||||
return apiService.post('/api/vitrage/template/default/', temp)
|
||||
.catch(function () {
|
||||
toastService.add('error', gettext('Unable to fetch the Vitrage Templates service.'));
|
||||
});
|
||||
}
|
||||
|
||||
function validateTemplate(template, type, parameters) {
|
||||
var temp = {'template': template, 'type': type, "params": parameters, "method": 'validate'};
|
||||
return apiService.post('/api/vitrage/template/default/', temp)
|
||||
.catch(function () {
|
||||
toastService.add('error', gettext('Unable to validate the Vitrage Templates service.'));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}());
|
||||
|
@ -0,0 +1,143 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('horizon.dashboard.project.vitrage')
|
||||
.controller('AddTemplateContainerController', AddTemplateContainerController);
|
||||
|
||||
AddTemplateContainerController.$inject = ['$scope', 'modalSrv', 'vitrageTopologySrv', '$rootScope'];
|
||||
|
||||
function AddTemplateContainerController($scope, modalSrv, vitrageTopologySrv, $rootScope) {
|
||||
|
||||
$scope.STATIC_URL = STATIC_URL;
|
||||
$scope.status = {
|
||||
isopen: false
|
||||
};
|
||||
$scope.version = "";
|
||||
$scope.templateType = "";
|
||||
$scope.parameters = [];
|
||||
$scope.loading = false;
|
||||
$scope.templateContent = null;
|
||||
$scope.withParameters = false;
|
||||
$scope.uploading = false;
|
||||
|
||||
$scope.addNewParameter = function () {
|
||||
$scope.parameters.push({key: '', value: ''});
|
||||
|
||||
};
|
||||
$scope.removeParameter = function (element) {
|
||||
var index = $scope.parameters.indexOf(element);
|
||||
if (index > -1) {
|
||||
$scope.parameters.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.submitModal = function () {
|
||||
modalSrv.close();
|
||||
};
|
||||
|
||||
|
||||
$scope.closeModal = function () {
|
||||
modalSrv.close();
|
||||
};
|
||||
|
||||
|
||||
$scope.uploadFile = function (file, errFile) {
|
||||
|
||||
if (file) {
|
||||
|
||||
var ending = file.name.split('.').pop();
|
||||
if (ending !== 'yml' && ending !== 'yaml') {
|
||||
horizon.toast.add("error", gettext("Invalid file type. Templates should be YAML files"));
|
||||
delete file.name;
|
||||
return;
|
||||
}
|
||||
$scope.file = file;
|
||||
|
||||
var r = new FileReader();
|
||||
|
||||
r.onload = function (e) {
|
||||
$scope.uploading = true;
|
||||
var tempVersion = JSON.stringify(e.target.result).match(/version: (\d+)/i);
|
||||
$scope.withParameters = !!JSON.stringify(e.target.result).match("parameters:");
|
||||
$scope.version = tempVersion ? tempVersion[1] : "1";
|
||||
$scope.templateContent = e.target.result;
|
||||
|
||||
};
|
||||
|
||||
r.catch = function () {
|
||||
$scope.uploading = false;
|
||||
horizon.toast.add("error", gettext("Unable to read file"));
|
||||
delete file.name;
|
||||
}
|
||||
try {
|
||||
$scope.uploading = false;
|
||||
r.readAsText(file);
|
||||
} catch (error) {
|
||||
$scope.uploading = false;
|
||||
horizon.toast.add("error", gettext("Unable to read file"));
|
||||
delete file.name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
$scope.submit = function () {
|
||||
|
||||
$scope.loading = true;
|
||||
var file = $scope.file;
|
||||
var finalParameters = {};
|
||||
|
||||
|
||||
if ($scope.version === '1') {
|
||||
var e = document.getElementById("typeSelect");
|
||||
var type = e.options[e.selectedIndex].text.toLowerCase();
|
||||
if (type !== "standard" && type !== "definition" && type !== "equivalence") {
|
||||
horizon.toast.add("error", gettext("Invalid type entered. Type is one of: standard, definition, equivalence"));
|
||||
delete file.name;
|
||||
$scope.loading = false;
|
||||
$scope.closeModal();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.parameters.forEach(function (parameter) {
|
||||
finalParameters[parameter.key] = parameter.value;
|
||||
}
|
||||
);
|
||||
|
||||
vitrageTopologySrv.validateTemplate($scope.templateContent, type, finalParameters).then(function (result) {
|
||||
if (result.data.results[0]['status code'] !== 0) {
|
||||
horizon.toast.add("error", gettext(result.data.results[0].message));
|
||||
} else {
|
||||
vitrageTopologySrv.addTemplate($scope.templateContent, type, finalParameters).then(function (result) {
|
||||
|
||||
if (result.data[0].status === 'ERROR') {
|
||||
horizon.toast.add("error", gettext(result.data[0]['status details']));
|
||||
} else {
|
||||
$scope.loading = false;
|
||||
$rootScope.$broadcast('autoRefresh');
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
.catch(function () {
|
||||
$scope.loading = false;
|
||||
horizon.toast.add("error", gettext("Unable to add template"));
|
||||
return;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}).catch(function (reason) {
|
||||
horizon.toast.add("error", gettext(reason));
|
||||
})
|
||||
$scope.closeModal();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,66 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
|
||||
<a href="#" class="close" data-dismiss="modal" ng-click="closeModal()">
|
||||
<span class="fa fa-times"></span>
|
||||
</a>
|
||||
<h3 class="modal-title" id="modal-title">Add New Template</h3>
|
||||
</div>
|
||||
<div ng-hide="loading" class="modal-body clearfix">
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<label class="testClass">Template File:</label>
|
||||
<input class="btn btn-default "
|
||||
type="file"
|
||||
id="add-template"
|
||||
ngf-select="uploadFile($file, $invalidFiles)"
|
||||
ngf-max-height="1000"
|
||||
accept=".yaml,.yml"
|
||||
data-toggle="tooltip"
|
||||
title="File type: YAML Max Size: 2MB"
|
||||
ngf-max-size="1MB"/>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group" ng-if="version==='1'">
|
||||
<label>Type:</label>
|
||||
|
||||
<select class="type-select" id="typeSelect">
|
||||
<option selected="selected">Standard</option>
|
||||
<option>Definition</option>
|
||||
<option>Equivalence</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-if="version==='3'||version==='2'">
|
||||
<label>Parameters:</label>
|
||||
|
||||
<button ng-click="addNewParameter()"><i class="fa fa-plus"></i></button>
|
||||
|
||||
<ul>
|
||||
<li ng-repeat="parameter in parameters">
|
||||
<label>Key :</label>
|
||||
<input type="text" ng-model="parameter.key" ng-value="parameter.key">
|
||||
<label>Value :</label>
|
||||
<input type="text" ng-model="parameter.value" ng-value="parameter.value">
|
||||
<button ng-click="removeParameter(parameter)"><i class="fa fa-minus"></i></button>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<img ng-show="loading" id="spinner" ng-src="{$STATIC_URL$}dashboard/project/assets/spinner.gif"
|
||||
class="template-spinner">
|
||||
<div ng-hide="loading" class="modal-footer">
|
||||
<button ng-disabled="!uploading" class="btn btn-primary" type="button" ng-click="submit()">Done</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
@ -1,14 +1,5 @@
|
||||
/* ------ GLOBAL ------ */
|
||||
|
||||
.app-modal-window .modal-dialog{
|
||||
height: 90%;
|
||||
width: 90%;
|
||||
}
|
||||
.app-modal-window .modal-content{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
|
||||
/* ------ GLOBAL ------ */
|
||||
|
||||
|
@ -51,6 +51,12 @@
|
||||
pre {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.template-spinner {
|
||||
margin-left: 45%;
|
||||
margin-bottom: 5%;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="template-container">
|
||||
<div class="controls">
|
||||
<i title="Close" class="fa fa-times" ng-click="templateList.closeModal()"></i>
|
||||
<i title="Close" class="fa fa-times" ng-click="addTemplate.closeModal()"></i>
|
||||
</div>
|
||||
<div style="margin:15px">
|
||||
<h2>Select template type:</h2>
|
||||
@ -14,7 +14,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<div style="margin: 15px">
|
||||
<button type="button" class="btn btn-primary" ng-click="templateList.submitModal()">
|
||||
<button type="button" class="btn btn-primary" ng-click="addTemplate.submitModal()">
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
|
@ -89,10 +89,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
function addTemplate(template, type) {
|
||||
function addTemplate(template, type, parameters) {
|
||||
|
||||
if (vitrageAPI) {
|
||||
return vitrageAPI.addTemplate(template, type)
|
||||
return vitrageAPI.addTemplate(template, type, parameters)
|
||||
.then(function (data) {
|
||||
return data;
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
function validateTemplate(template, type, parameters) {
|
||||
|
||||
if (vitrageAPI) {
|
||||
return vitrageAPI.validateTemplate(template, type, parameters)
|
||||
.then(function (data) {
|
||||
return data;
|
||||
})
|
||||
@ -124,6 +137,7 @@
|
||||
getRootCauseAnalysis: getRootCauseAnalysis,
|
||||
getTemplates: getTemplates,
|
||||
deleteTemplate: deleteTemplate,
|
||||
validateTemplate: validateTemplate,
|
||||
addTemplate: addTemplate
|
||||
};
|
||||
}
|
||||
|
@ -7,8 +7,7 @@
|
||||
|
||||
TemplateListController.$inject = ['$scope', '$interval', 'modalSrv', 'timeSrv', 'vitrageTopologySrv'];
|
||||
|
||||
function TemplateListController($scope, $interval, modalSrv, timeSrv, vitrageTopologySrv)
|
||||
{
|
||||
function TemplateListController($scope, $interval, modalSrv, timeSrv, vitrageTopologySrv) {
|
||||
var templateList = this;
|
||||
templateList.templates = [];
|
||||
templateList.itemplates = [];
|
||||
@ -19,6 +18,8 @@
|
||||
templateList.templateInterval;
|
||||
templateList.timezone = timeSrv.getHorizonTimezone();
|
||||
templateList.dateFormat = timeSrv.longDateFormat;
|
||||
var path = document.location.pathname;
|
||||
$scope.admin = path.indexOf('admin') > 0;
|
||||
|
||||
getData();
|
||||
startCollectData();
|
||||
@ -34,6 +35,7 @@
|
||||
templateList.templateInterval = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
templateList.stopCollectData();
|
||||
});
|
||||
@ -62,66 +64,6 @@
|
||||
modalSrv.close();
|
||||
}
|
||||
|
||||
templateList.uploadFile = function(file, errFile) {
|
||||
if (file) {
|
||||
var ending = file.name.split('.').pop();
|
||||
if(ending !== 'yml' && ending !== 'yaml') {
|
||||
horizon.toast.add("error", gettext("Invalid file type. Templates should be YAML files"));
|
||||
delete file.name;
|
||||
return;
|
||||
}
|
||||
|
||||
var modalOptions = {
|
||||
animation: true,
|
||||
templateUrl: STATIC_URL + 'dashboard/project/components/templateAdd/templateAddOptions.html',
|
||||
controller: 'TemplateListController',
|
||||
controllerAs: 'templateList',
|
||||
windowClass: 'modal-dialog-metadata',
|
||||
resolve: {file: function() {
|
||||
return file;
|
||||
}}
|
||||
};
|
||||
templateList.file = file;
|
||||
modalSrv.show(modalOptions).result.then(() => templateList.chooseType())
|
||||
}
|
||||
}
|
||||
|
||||
templateList.chooseType = function() {
|
||||
var e = document.getElementById("typeSelect");
|
||||
var type = e.options[e.selectedIndex].text.toLowerCase();
|
||||
var file = templateList.file;
|
||||
templateList.type = type;
|
||||
if (type !== "standard" && type !== "definition" && type !== "equivalence") {
|
||||
horizon.toast.add("error", gettext("Invalid type entered. Type is one of: standard, definition, equivalence"));
|
||||
delete file.name;
|
||||
return;
|
||||
}
|
||||
var r = new FileReader();
|
||||
r.onload = function(e) {
|
||||
var content = e.target.result;
|
||||
vitrageTopologySrv.addTemplate(content, type).then(function(result){
|
||||
getData();
|
||||
})
|
||||
.catch(function(){
|
||||
horizon.toast.add("error",gettext("Unable to add template"));
|
||||
return;
|
||||
});
|
||||
}
|
||||
r.catch = function() {
|
||||
horizon.toast.add("error",gettext("Unable to read file"));
|
||||
delete file.name;
|
||||
}
|
||||
try{
|
||||
r.readAsText(file);
|
||||
}
|
||||
catch(error){
|
||||
horizon.toast.add("error",gettext("Unable to read file"));
|
||||
delete file.name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getData() {
|
||||
vitrageTopologySrv.getTemplates('all').then(function (result) {
|
||||
@ -134,9 +76,22 @@
|
||||
templateUrl: STATIC_URL + 'dashboard/project/components/template/templateContainer.html',
|
||||
controller: 'TemplateContainerController',
|
||||
windowClass: 'app-modal-window',
|
||||
resolve: {template: function() {
|
||||
resolve: {
|
||||
template: function () {
|
||||
return template;
|
||||
}}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
modalSrv.show(modalOptions);
|
||||
}
|
||||
templateList.onAddClick = function () {
|
||||
var modalOptions = {
|
||||
animation: true,
|
||||
templateUrl: STATIC_URL + 'dashboard/project/components/addTemplate/addTemplateContainer.html',
|
||||
controller: 'AddTemplateContainerController',
|
||||
windowClass: 'app-modal-window'
|
||||
|
||||
};
|
||||
|
||||
modalSrv.show(modalOptions);
|
||||
@ -151,6 +106,12 @@
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$on('autoRefresh', function () {
|
||||
templateList.autoRefreshChanged();
|
||||
console.log('inside ON');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
})();
|
||||
|
@ -1,14 +1,10 @@
|
||||
<div class="template-list" ng-controller="TemplateListController as templateList">
|
||||
<div class="add-btn">
|
||||
<button class="btn btn-primary"
|
||||
type="file"
|
||||
id="add-template"
|
||||
ngf-select="templateList.uploadFile($file, $invalidFiles)"
|
||||
ngf-max-height="1000"
|
||||
accept=".yaml,.yml"
|
||||
data-toggle="tooltip"
|
||||
title="File type: YAML Max Size: 2MB"
|
||||
ngf-max-size="1MB">
|
||||
ng-click="templateList.onAddClick()"
|
||||
ng-if="admin"
|
||||
|
||||
>
|
||||
Add Template
|
||||
</button>
|
||||
|
||||
@ -21,7 +17,8 @@
|
||||
</button>
|
||||
|
||||
<div class="themable-checkbox btn" style="float: right">
|
||||
<input type="checkbox" ng-model="templateList.checkboxAutoRefresh" id="themable-checkbox" ng-change="alarmList.autoRefreshChanged()">
|
||||
<input type="checkbox" ng-model="templateList.checkboxAutoRefresh" id="themable-checkbox"
|
||||
ng-change="alarmList.autoRefreshChanged()">
|
||||
<label for="themable-checkbox" translate>Auto Refresh</label>
|
||||
</div>
|
||||
|
||||
@ -29,7 +26,8 @@
|
||||
|
||||
<div class="panel panel-default">
|
||||
|
||||
<table st-table='templateList.itemplates' st-safe-src="templateList.templates" class="table-striped table-rsp table-detail modern"
|
||||
<table st-table='templateList.itemplates' st-safe-src="templateList.templates"
|
||||
class="table-striped table-rsp table-detail modern"
|
||||
hz-table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -39,7 +37,7 @@
|
||||
<th st-sort="details">{$ 'Details' | translate $}</th>
|
||||
<th st-sort="timestamp">{$ 'Timestamp' | translate $}</th>
|
||||
<th>{$ 'Show' | translate $}</th>
|
||||
<th>{$ 'Delete' | translate $}</th>
|
||||
<th ng-if="admin">{$ 'Delete' | translate $}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="5">
|
||||
@ -55,9 +53,11 @@
|
||||
<td>{$template.status$}</td>
|
||||
<td>{$template.type$}</td>
|
||||
<td>{$template["status details"]$}</td>
|
||||
<td><i class="fa fa-clock-o"></i> {$template.date | vitrageDate:templateList.dateFormat:templateList.timezone$}</td>
|
||||
<td><i class="fa fa-clock-o"></i> {$template.date |
|
||||
vitrageDate:templateList.dateFormat:templateList.timezone$}
|
||||
</td>
|
||||
<td ng-click="templateList.onShowClick(template)"><i class="fa fa-list"></i></td>
|
||||
<td ng-click="templateList.onDeleteClick(template)"><i class="fa fa-trash"></i></td>
|
||||
<td ng-if="admin" ng-click="templateList.onDeleteClick(template)"><i class="fa fa-trash"></i></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -12,3 +12,8 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
top: 20%;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user