/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
var App = require('app');
var dateUtils = require('utils/date');
App.AlertDefinition = DS.Model.extend({
name: DS.attr('string'),
label: DS.attr('string'),
description: DS.attr('string'),
service: DS.belongsTo('App.Service'),
serviceName: DS.attr('string'),
componentName: DS.attr('string'),
enabled: DS.attr('boolean'),
scope: DS.attr('string'),
interval: DS.attr('number'),
type: DS.attr('string'),
groups: DS.hasMany('App.AlertGroup'),
reporting: DS.hasMany('App.AlertReportDefinition'),
lastTriggered: DS.attr('number'),
/**
* Raw data from AlertDefinition/source
* used to format request content for updating alert definition
* @type {Object}
*/
rawSourceData: {},
/**
* Counts of alert grouped by their status
* Format:
*
* {
* "CRITICAL": {
* count: 1,
* maintenanceCount: 0
* },
* "OK": {
* count: 0,
* maintenanceCount: 1
* },
* "UNKNOWN": {
* count: 0,
* maintenanceCount: 0
* },
* "WARNING": {
* count: 1,
* maintenanceCount: 1
* }
* }
*
* @type {object}
*/
summary: {},
/**
* Formatted timestamp for latest alert triggering for current alertDefinition
* @type {string}
*/
lastTriggeredFormatted: function () {
return dateUtils.dateFormat(this.get('lastTriggered'));
}.property('lastTriggered'),
/**
* Formatted timestamp with $.timeago
* @type {string}
*/
lastTriggeredAgoFormatted: function () {
var lastTriggered = this.get('lastTriggered');
return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
}.property('lastTriggered'),
lastTriggeredVerboseDisplay: function () {
var lastTriggered = this.get('lastTriggered');
return Em.I18n.t('models.alert_definition.triggered.verbose').format(dateUtils.dateFormat(lastTriggered));
}.property('lastTriggered'),
/**
* Formatted timestamp in format: for 4 days
* @type {string}
*/
lastTriggeredForFormatted: function () {
var lastTriggered = this.get('lastTriggered');
var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
$.timeago.settings.strings.suffixAgo = null;
$.timeago.settings.strings.prefixAgo = 'for';
var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
$.timeago.settings.strings.suffixAgo = previousSuffixAgo;
$.timeago.settings.strings.prefixAgo = previousPrefixAgo;
return triggeredFor;
}.property('lastTriggered'),
/**
* Formatted displayName for componentName
* @type {String}
*/
componentNameFormatted: function () {
return App.format.role(this.get('componentName'));
}.property('componentName'),
/**
* Status generates from child-alerts
* Format: OK(1) WARN(2) CRIT(1) UNKN(1)
* If single host: show: OK/WARNING/CRITICAL/UNKNOWN
* If some there are no alerts with some state, this state isn't shown
* If no OK/WARN/CRIT/UNKN state, then show PENDING
* Order is equal to example
* @type {string}
*/
status: function () {
var order = this.get('order'),
summary = this.get('summary'),
hostCnt = 0,
self = this;
order.forEach(function (state) {
hostCnt += summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
});
if (hostCnt > 1) {
// multiple hosts
return order.map(function (state) {
var shortState = self.get('shortState')[state];
var result = '';
result += summary[state].count ? '' + shortState + ' (' + summary[state].count + ')' : '';
// add status with maintenance mode icon
result += summary[state].maintenanceCount ?
' ' + shortState + ' (' + summary[state].maintenanceCount + ')' : '';
return result;
}).without('').join(' ');
} else if (hostCnt == 1) {
// single host, single status
return order.map(function (state) {
var shortState = self.get('shortState')[state];
var result = '';
result += summary[state].count ? '' + shortState + '' : '';
// add status with maintenance mode icon
result += summary[state].maintenanceCount ?
' ' + shortState + '' : '';
return result;
}).without('').join(' ');
} else if (hostCnt == 0) {
// none
return 'NONE';
}
return '';
}.property('summary'),
latestText: function () {
var order = this.get('order'), summary = this.get('summary'), text = '';
order.forEach(function (state) {
var cnt = summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
if (cnt > 0) {
text = summary[state].latestText;
}
});
return text;
}.property('summary'),
isHostAlertDefinition: function () {
var serviceID = (this.get('service')._id === "AMBARI"),
component = (this.get('componentName') === "AMBARI_AGENT");
return serviceID && component;
}.property('service', 'componentName'),
typeIconClass: function () {
var typeIcons = this.get('typeIcons'),
type = this.get('type');
return typeIcons[type];
}.property('type'),
/**
* if this definition is in state: CRITICAL / WARNING, if true, will show up in alerts fast access popup
* instances with maintenance mode ON are ignored
* @type {boolean}
*/
isCriticalOrWarning: function () {
return !!(this.get('summary.CRITICAL.count') || this.get('summary.WARNING.count'));
}.property('summary'),
/**
* if this definition is in state: CRIT
* @type {boolean}
*/
isCritical: function () {
var summary = this.get('summary');
var state = 'CRITICAL';
return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
}.property('summary'),
/**
* if this definition is in state: WARNING
* @type {boolean}
*/
isWarning: function () {
var summary = this.get('summary');
var state = 'WARNING';
return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
}.property('summary'),
/**
* if this definition is in state: OK
* @type {boolean}
*/
isOK: function () {
var summary = this.get('summary');
var state = 'OK';
return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
}.property('summary'),
/**
* if this definition is in state: OK
* @type {boolean}
*/
isUnknown: function () {
var summary = this.get('summary');
var state = 'UNKNOWN';
return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
}.property('summary'),
/**
* For alerts we will have processes which are not typical
* cluster services - like Ambari-Server. This method unifies
* cluster services and other services into a common display-name.
* @see App.AlertInstance#serviceDisplayName()
*/
serviceDisplayName: function () {
var serviceName = this.get('service.displayName');
if (!serviceName) {
serviceName = this.get('serviceName');
if (serviceName) {
serviceName = serviceName.toCapital();
}
}
return serviceName;
}.property('serviceName', 'service.displayName'),
/**
* List of css-classes for alert types
* @type {object}
*/
typeIcons: {
'METRIC': 'icon-bolt',
'SCRIPT': 'icon-file-text',
'WEB': 'icon-globe',
'PORT': 'icon-signin',
'AGGREGATE': 'icon-plus'
},
/**
* Sort on load definitions by this severity order
*/
severityOrder: ['CRITICAL', 'WARNING', 'OK', 'UNKNOWN', 'PENDING'],
order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],
shortState: {
'CRITICAL': 'CRIT',
'WARNING': 'WARN',
'OK': 'OK',
'UNKNOWN': 'UNKWN',
'PENDING': 'NONE'
}
});
App.AlertDefinition.reopenClass({
/**
* Get all available AlertDefinitions
* @returns {Array|string}
* @method getAllDefinitions
*/
getAllDefinitions: function () {
return Array.prototype.concat.call(
Array.prototype, App.PortAlertDefinition.find().toArray(),
App.MetricsAlertDefinition.find().toArray(),
App.WebAlertDefinition.find().toArray(),
App.AggregateAlertDefinition.find().toArray(),
App.ScriptAlertDefinition.find().toArray()
)
},
/**
* Return function to sort list of AlertDefinitions by their status
* It sorts according to severityOrder
* @param {boolean} order true - DESC, false - ASC
* @returns {Function}
* @method getSortDefinitionsByStatus
*/
getSortDefinitionsByStatus: function (order) {
return function (a, b) {
var a_summary = a.get('summary'),
b_summary = b.get('summary'),
st_order = a.get('severityOrder'),
ret = 0;
for (var i = 0; i < st_order.length; i++) {
var a_v = Em.isNone(a_summary[st_order[i]]) ? 0 : a_summary[st_order[i]].count + a_summary[st_order[i]].maintenanceCount,
b_v = Em.isNone(b_summary[st_order[i]]) ? 0 : b_summary[st_order[i]].count + b_summary[st_order[i]].maintenanceCount;
ret = b_v - a_v;
if (ret !== 0) {
break;
}
}
return order ? ret : -ret;
};
}
});
App.AlertReportDefinition = DS.Model.extend({
type: DS.attr('string'),
text: DS.attr('string'),
value: DS.attr('number')
});
App.AlertMetricsSourceDefinition = DS.Model.extend({
propertyList: [],
value: DS.attr('string')
});
App.AlertMetricsUriDefinition = DS.Model.extend({
http: DS.attr('string'),
https: DS.attr('string'),
httpsProperty: DS.attr('string'),
httpsPropertyValue: DS.attr('string')
});
App.PortAlertDefinition = App.AlertDefinition.extend({
defaultPort: DS.attr('number'),
uri: DS.attr('string')
});
App.MetricsAlertDefinition = App.AlertDefinition.extend({
jmx: DS.belongsTo('App.AlertMetricsSourceDefinition'),
ganglia: DS.belongsTo('App.AlertMetricsSourceDefinition'),
uri: DS.belongsTo('App.AlertMetricsUriDefinition')
});
App.WebAlertDefinition = App.AlertDefinition.extend({
uri: DS.belongsTo('App.AlertMetricsUriDefinition')
});
App.AggregateAlertDefinition = App.AlertDefinition.extend({
alertName: DS.attr('string')
});
App.ScriptAlertDefinition = App.AlertDefinition.extend({
location: DS.attr('string')
});
App.AlertDefinition.FIXTURES = [];
App.AlertReportDefinition.FIXTURES = [];
App.AlertMetricsSourceDefinition.FIXTURES = [];
App.PortAlertDefinition.FIXTURES = [];
App.AlertMetricsUriDefinition.FIXTURES = [];
App.MetricsAlertDefinition.FIXTURES = [];
App.WebAlertDefinition.FIXTURES = [];
App.AggregateAlertDefinition.FIXTURES = [];
App.ScriptAlertDefinition.FIXTURES = [];