Support for (non)deterministic alarms

Adding possibility of marking alarm as
deterministic or non-deterministic.
Expression widget was extended with checkbox.
If checkbox's state is changed, underlying
expression is modified to reflect the change.
By default checkbox is not checked - all expressions
are non-deterministic by default.

Deterministic property of alarm's expression
is displayed in alarm definition details.
Value is computed at server side.

Depends-On: I506fcd0b9861e902a2bfcfa768d402c568b85cea
Change-Id: I480afe3259b6063e99a96798f14e646f830fcbd8
This commit is contained in:
Tomasz Trębski
2016-05-10 08:02:53 +02:00
parent 30780bf37a
commit e6bc510971
6 changed files with 124 additions and 26 deletions

View File

@@ -18,6 +18,10 @@
<p>{% blocktrans %}
The Notifications field contains the list of Notifications that should be sent when transitioning to another ALARM state.
{% endblocktrans %}</p>
<p>{% blocktrans %}
The deterministic alarms never enter UNDETERMINED state.
Use them for metrics that are received sporadically.
{% endblocktrans %}</p>
<fieldset>
<div ng-controller="alarmEditController" ng-init="init('{{ service }}')">
{% include "horizon/common/_form_fields.html" %}

View File

@@ -10,6 +10,8 @@
<dd>{{ alarm.description }}</dd>
<dt>{% trans "Expression" %}</dt>
<dd>{{ alarm.expression }}</dd>
<dt>{% trans "Deterministic" %}</dt>
<dd>{{ alarm.deterministic }}</dd>
<dt>{% trans "Severity" %}</dt>
<dd>{{ alarm.severity }}</dd>
<dt>{% trans "Notifications Enabled" %}</dt>

View File

@@ -1,17 +1,43 @@
{% load i18n %}
<div>
<input type="hidden" name="{{ name }}" id="dimension"/>
<div class="alarm-expression">
<input type="hidden" name="{{ name }}" id="expression"/>
<div style="margin-bottom:5px;">
<select id="function" class="form-control"
ng-model="currentFunction" ng-options="f[0] as f[1] for f in {{func}}" ng-change="saveExpression()"></select>
<select id="metric-chooser" class="form-control"
<select id="function"
class="form-control"
ng-model="currentFunction"
ng-options="f[0] as f[1] for f in {{func}}"
ng-change="saveExpression()"></select>
<select id="metric-chooser"
class="form-control"
ng-model="currentMetric"
ng-options="metric for metric in metricNames"
ng-change="metricChanged()">
</select>
<select id="comparators" class="form-control"
ng-model="currentComparator" ng-options="f[0] as f[1] for f in {{comparators}}" ng-change="saveExpression()"></select>
<input type="number" step="any" id="threshold" class="form-control" ng-model="currentThreshold" ng-change="saveExpression()"/>
ng-change="metricChanged()"></select>
<div class="expression-details">
<select class="form-control"
ng-model="currentComparator"
aria-label="{% trans 'Comparator' %}"
ng-options="f[0] as f[1] for f in {{comparators}}"
ng-change="saveExpression()"></select>
<input type="number"
step="any"
class="form-control"
aria-label="{% trans 'Threshold' %}"
ng-model="currentThreshold"
ng-change="saveExpression()"/>
<div class="checkbox">
<label>
<input type="checkbox"
data-toggle="tooltip"
data-placement="left"
title="{% trans 'Deterministic' %}"
data-original-title="{% trans 'Deterministic' %}"
aria-label="{% trans 'Deterministic' %}"
ng-model="currentIsDeterministic"
ng-change="saveExpression()">
<span>{% trans 'Deterministic' %}</span>
</label>
</div>
</div>
</div>
<tags-input id="dimension-chooser" ng-model="tags"
placeholder="{% trans 'Add a dimension' %}"

View File

@@ -32,7 +32,7 @@
<input type="hidden" name="ok_actions" value="{$ notify.id $}" ng-if="notify.ok"/>
</td>
<td class="undetermined">
<input type="checkbox" ng-model="notify.undetermined">
<input type="checkbox" ng-model="notify.undetermined" ng-disabled="ctrl.isDeterministic">
<input type="hidden" name="undetermined_actions" value="{$ notify.id $}" ng-if="notify.undetermined"/>
</td>
<td>

View File

@@ -6,16 +6,30 @@
white-space: normal;
word-wrap:break-word;
}
#comparators {
width: auto;
float: none;
}
#threshold {
width: 100%
}
#notification_table td.address{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width:100px;
}
}
.alarm-expression .expression-details {
display: inline-flex;
width: 100%;
}
.alarm-expression .expression-details > * {
float: left;
width: 100%
}
.alarm-expression .expression-details .checkbox {
margin-left: 10px;
font-weight: bold;
overflow: hidden;
}
.alarm-expression .expression-details .checkbox span {
font-weight: bold;
}

View File

@@ -152,6 +152,7 @@ angular.module('monitoring.controllers', [])
$scope.currentFunction = "max";
$scope.currentComparator = ">";
$scope.currentThreshold = 0;
$scope.currentIsDeterministic = false;
$scope.matchingMetrics= [];
$scope.tags = [];
$scope.matchByTags = [];
@@ -197,7 +198,7 @@ angular.module('monitoring.controllers', [])
$scope.saveDimension();
}
$scope.saveExpression = function() {
$('#dimension').val($scope.formatDimension());
$('#expression').val($scope.formatDimension());
}
$scope.saveDimension = function() {
$scope.saveExpression();
@@ -230,14 +231,22 @@ angular.module('monitoring.controllers', [])
$('#id_match_by').val(matchByTags.join(','));
}
$scope.formatDimension = function() {
var dim = ''
var dim = '';
angular.forEach($scope.tags, function(value, key) {
if (dim.length) {
dim += ','
dim += ',';
}
dim += value['text']
dim += value['text'];
})
return $scope.currentFunction + '(' + $scope.currentMetric + '{' + dim + '}) ' + $scope.currentComparator + ' ' + $scope.currentThreshold;
return $scope.currentFunction
+ '('
+ $scope.currentMetric
+ '{' + dim + '}'
+ ($scope.currentIsDeterministic ? ',deterministic' : '')
+ ') '
+ $scope.currentComparator
+ ' '
+ $scope.currentThreshold;
}
$scope.formatMatchBy = function() {
var dimNames = {}
@@ -256,6 +265,18 @@ angular.module('monitoring.controllers', [])
$scope.saveDimension();
}
$scope.$on('$destroy', (function() {
var detWatcher = $scope.$watch('currentIsDeterministic', function detWatcher(newValue, oldValue) {
if(newValue != oldValue){
$scope.$emit('mon_deterministic_changed', newValue);
}
});
return function() {
// destroy watchers
detWatcher();
}
}()));
function uniqueNames(input, key) {
var unique = {};
var uniqueList = [];
@@ -270,10 +291,11 @@ angular.module('monitoring.controllers', [])
}])
.controller('alarmNotificationFieldController', NotificationField);
function NotificationField(){
function NotificationField($rootScope) {
var vm = this;
var allOptions = {};
var oldUndetermined = {};
vm.empty = true;
vm.list = [];
@@ -281,6 +303,7 @@ function NotificationField(){
model:null,
options:[]
};
vm.isDeterministic = false;
vm.init = function(data){
@@ -305,8 +328,13 @@ function NotificationField(){
}
}
vm.select.model = null;
if (id in oldUndetermined) {
delete oldUndetermined[id];
}
};
$rootScope.$on('mon_deterministic_changed', onDeterministicChange)
function prepareNotify(item){
var selected = item[7]
var notify = {
@@ -336,9 +364,33 @@ function NotificationField(){
}
}
}
function onDeterministicChange(event, isDeterministic) {
if (!(vm.list && vm.list.length)) {
return;
} else if (isDeterministic === vm.isDeterministic) {
return;
}
vm.isDeterministic = isDeterministic;
angular.forEach(vm.list, function(item) {
if(!(item.id in oldUndetermined)){
oldUndetermined[item.id] = [];
}
if (isDeterministic) {
oldUndetermined[item.id] = item.undetermined;
item.undetermined = !isDeterministic;
} else {
item.undetermined = oldUndetermined[item.id];
delete oldUndetermined[item.id];
}
});
}
}
NotificationField.$inject = [];
NotificationField.$inject = ['$rootScope'];
angular.module('monitoring.filters', [])
.filter('spacedim', function () {