alert_definition.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. var dateUtils = require('utils/date');
  20. App.AlertDefinition = DS.Model.extend({
  21. name: DS.attr('string'),
  22. label: DS.attr('string'),
  23. description: DS.attr('string'),
  24. service: DS.belongsTo('App.Service'),
  25. serviceName: DS.attr('string'),
  26. componentName: DS.attr('string'),
  27. enabled: DS.attr('boolean'),
  28. scope: DS.attr('string'),
  29. interval: DS.attr('number'),
  30. type: DS.attr('string'),
  31. groups: DS.hasMany('App.AlertGroup'),
  32. reporting: DS.hasMany('App.AlertReportDefinition'),
  33. lastTriggered: DS.attr('number'),
  34. /**
  35. * Raw data from AlertDefinition/source
  36. * used to format request content for updating alert definition
  37. * @type {Object}
  38. */
  39. rawSourceData: {},
  40. /**
  41. * Counts of alert grouped by their status
  42. * Format:
  43. * <code>
  44. * {
  45. * "CRITICAL": {
  46. * count: 1,
  47. * maintenanceCount: 0
  48. * },
  49. * "OK": {
  50. * count: 0,
  51. * maintenanceCount: 1
  52. * },
  53. * "UNKNOWN": {
  54. * count: 0,
  55. * maintenanceCount: 0
  56. * },
  57. * "WARNING": {
  58. * count: 1,
  59. * maintenanceCount: 1
  60. * }
  61. * }
  62. * </code>
  63. * @type {object}
  64. */
  65. summary: {},
  66. /**
  67. * Formatted timestamp for latest alert triggering for current alertDefinition
  68. * @type {string}
  69. */
  70. lastTriggeredFormatted: function () {
  71. return dateUtils.dateFormat(this.get('lastTriggered'));
  72. }.property('lastTriggered'),
  73. /**
  74. * Formatted timestamp with <code>$.timeago</code>
  75. * @type {string}
  76. */
  77. lastTriggeredAgoFormatted: function () {
  78. var lastTriggered = this.get('lastTriggered');
  79. return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
  80. }.property('lastTriggered'),
  81. lastTriggeredVerboseDisplay: function () {
  82. var lastTriggered = this.get('lastTriggered');
  83. return Em.I18n.t('models.alert_definition.triggered.verbose').format(dateUtils.dateFormat(lastTriggered));
  84. }.property('lastTriggered'),
  85. /**
  86. * Formatted timestamp in format: for 4 days
  87. * @type {string}
  88. */
  89. lastTriggeredForFormatted: function () {
  90. var lastTriggered = this.get('lastTriggered');
  91. var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
  92. var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
  93. $.timeago.settings.strings.suffixAgo = null;
  94. $.timeago.settings.strings.prefixAgo = 'for';
  95. var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
  96. $.timeago.settings.strings.suffixAgo = previousSuffixAgo;
  97. $.timeago.settings.strings.prefixAgo = previousPrefixAgo;
  98. return triggeredFor;
  99. }.property('lastTriggered'),
  100. /**
  101. * Formatted displayName for <code>componentName</code>
  102. * @type {String}
  103. */
  104. componentNameFormatted: function () {
  105. return App.format.role(this.get('componentName'));
  106. }.property('componentName'),
  107. /**
  108. * Status generates from child-alerts
  109. * Format: OK(1) WARN(2) CRIT(1) UNKN(1)
  110. * If single host: show: OK/WARNING/CRITICAL/UNKNOWN
  111. * If some there are no alerts with some state, this state isn't shown
  112. * If no OK/WARN/CRIT/UNKN state, then show PENDING
  113. * Order is equal to example
  114. * @type {string}
  115. */
  116. status: function () {
  117. var order = this.get('order'),
  118. summary = this.get('summary'),
  119. hostCnt = 0,
  120. self = this;
  121. order.forEach(function (state) {
  122. hostCnt += summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
  123. });
  124. if (hostCnt > 1) {
  125. // multiple hosts
  126. return order.map(function (state) {
  127. var shortState = self.get('shortState')[state];
  128. var result = '';
  129. result += summary[state].count ? '<span class="alert-state-single-host label alert-state-' + state + '">' + shortState + ' (' + summary[state].count + ')</span>' : '';
  130. // add status with maintenance mode icon
  131. result += summary[state].maintenanceCount ?
  132. '<span class="alert-state-single-host label alert-state-PENDING"><span class="icon-medkit"></span> ' + shortState + ' (' + summary[state].maintenanceCount + ')</span>' : '';
  133. return result;
  134. }).without('').join(' ');
  135. } else if (hostCnt == 1) {
  136. // single host, single status
  137. return order.map(function (state) {
  138. var shortState = self.get('shortState')[state];
  139. var result = '';
  140. result += summary[state].count ? '<span class="alert-state-single-host label alert-state-' + state + '">' + shortState + '</span>' : '';
  141. // add status with maintenance mode icon
  142. result += summary[state].maintenanceCount ?
  143. '<span class="alert-state-single-host label alert-state-PENDING"><span class="icon-medkit"></span> ' + shortState + '</span>' : '';
  144. return result;
  145. }).without('').join(' ');
  146. } else if (hostCnt == 0) {
  147. // none
  148. return '<span class="alert-state-single-host label alert-state-PENDING">NONE</span>';
  149. }
  150. return '';
  151. }.property('summary'),
  152. latestText: function () {
  153. var order = this.get('order'), summary = this.get('summary'), text = '';
  154. order.forEach(function (state) {
  155. var cnt = summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
  156. if (cnt > 0) {
  157. text = summary[state].latestText;
  158. }
  159. });
  160. return text;
  161. }.property('summary'),
  162. isHostAlertDefinition: function () {
  163. var serviceID = (this.get('service')._id === "AMBARI"),
  164. component = (this.get('componentName') === "AMBARI_AGENT");
  165. return serviceID && component;
  166. }.property('service', 'componentName'),
  167. typeIconClass: function () {
  168. var typeIcons = this.get('typeIcons'),
  169. type = this.get('type');
  170. return typeIcons[type];
  171. }.property('type'),
  172. /**
  173. * if this definition is in state: CRITICAL / WARNING, if true, will show up in alerts fast access popup
  174. * instances with maintenance mode ON are ignored
  175. * @type {boolean}
  176. */
  177. isCriticalOrWarning: function () {
  178. return !!(this.get('summary.CRITICAL.count') || this.get('summary.WARNING.count'));
  179. }.property('summary'),
  180. /**
  181. * if this definition is in state: CRIT
  182. * @type {boolean}
  183. */
  184. isCritical: function () {
  185. var summary = this.get('summary');
  186. var state = 'CRITICAL';
  187. return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
  188. }.property('summary'),
  189. /**
  190. * if this definition is in state: WARNING
  191. * @type {boolean}
  192. */
  193. isWarning: function () {
  194. var summary = this.get('summary');
  195. var state = 'WARNING';
  196. return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
  197. }.property('summary'),
  198. /**
  199. * if this definition is in state: OK
  200. * @type {boolean}
  201. */
  202. isOK: function () {
  203. var summary = this.get('summary');
  204. var state = 'OK';
  205. return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
  206. }.property('summary'),
  207. /**
  208. * if this definition is in state: OK
  209. * @type {boolean}
  210. */
  211. isUnknown: function () {
  212. var summary = this.get('summary');
  213. var state = 'UNKNOWN';
  214. return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
  215. }.property('summary'),
  216. /**
  217. * For alerts we will have processes which are not typical
  218. * cluster services - like Ambari-Server. This method unifies
  219. * cluster services and other services into a common display-name.
  220. * @see App.AlertInstance#serviceDisplayName()
  221. */
  222. serviceDisplayName: function () {
  223. var serviceName = this.get('service.displayName');
  224. if (!serviceName) {
  225. serviceName = this.get('serviceName');
  226. if (serviceName) {
  227. serviceName = serviceName.toCapital();
  228. }
  229. }
  230. return serviceName;
  231. }.property('serviceName', 'service.displayName'),
  232. /**
  233. * List of css-classes for alert types
  234. * @type {object}
  235. */
  236. typeIcons: {
  237. 'METRIC': 'icon-bolt',
  238. 'SCRIPT': 'icon-file-text',
  239. 'WEB': 'icon-globe',
  240. 'PORT': 'icon-signin',
  241. 'AGGREGATE': 'icon-plus'
  242. },
  243. /**
  244. * Sort on load definitions by this severity order
  245. */
  246. severityOrder: ['CRITICAL', 'WARNING', 'OK', 'UNKNOWN', 'PENDING'],
  247. order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],
  248. shortState: {
  249. 'CRITICAL': 'CRIT',
  250. 'WARNING': 'WARN',
  251. 'OK': 'OK',
  252. 'UNKNOWN': 'UNKWN',
  253. 'PENDING': 'NONE'
  254. }
  255. });
  256. App.AlertDefinition.reopenClass({
  257. /**
  258. * Get all available AlertDefinitions
  259. * @returns {Array|string}
  260. * @method getAllDefinitions
  261. */
  262. getAllDefinitions: function () {
  263. return Array.prototype.concat.call(
  264. Array.prototype, App.PortAlertDefinition.find().toArray(),
  265. App.MetricsAlertDefinition.find().toArray(),
  266. App.WebAlertDefinition.find().toArray(),
  267. App.AggregateAlertDefinition.find().toArray(),
  268. App.ScriptAlertDefinition.find().toArray()
  269. )
  270. },
  271. /**
  272. * Return function to sort list of AlertDefinitions by their status
  273. * It sorts according to <code>severityOrder</code>
  274. * @param {boolean} order true - DESC, false - ASC
  275. * @returns {Function}
  276. * @method getSortDefinitionsByStatus
  277. */
  278. getSortDefinitionsByStatus: function (order) {
  279. return function (a, b) {
  280. var a_summary = a.get('summary'),
  281. b_summary = b.get('summary'),
  282. st_order = a.get('severityOrder'),
  283. ret = 0;
  284. for (var i = 0; i < st_order.length; i++) {
  285. var a_v = Em.isNone(a_summary[st_order[i]]) ? 0 : a_summary[st_order[i]].count + a_summary[st_order[i]].maintenanceCount,
  286. b_v = Em.isNone(b_summary[st_order[i]]) ? 0 : b_summary[st_order[i]].count + b_summary[st_order[i]].maintenanceCount;
  287. ret = b_v - a_v;
  288. if (ret !== 0) {
  289. break;
  290. }
  291. }
  292. return order ? ret : -ret;
  293. };
  294. }
  295. });
  296. App.AlertReportDefinition = DS.Model.extend({
  297. type: DS.attr('string'),
  298. text: DS.attr('string'),
  299. value: DS.attr('number')
  300. });
  301. App.AlertMetricsSourceDefinition = DS.Model.extend({
  302. propertyList: [],
  303. value: DS.attr('string')
  304. });
  305. App.AlertMetricsUriDefinition = DS.Model.extend({
  306. http: DS.attr('string'),
  307. https: DS.attr('string'),
  308. httpsProperty: DS.attr('string'),
  309. httpsPropertyValue: DS.attr('string')
  310. });
  311. App.PortAlertDefinition = App.AlertDefinition.extend({
  312. defaultPort: DS.attr('number'),
  313. uri: DS.attr('string')
  314. });
  315. App.MetricsAlertDefinition = App.AlertDefinition.extend({
  316. jmx: DS.belongsTo('App.AlertMetricsSourceDefinition'),
  317. ganglia: DS.belongsTo('App.AlertMetricsSourceDefinition'),
  318. uri: DS.belongsTo('App.AlertMetricsUriDefinition')
  319. });
  320. App.WebAlertDefinition = App.AlertDefinition.extend({
  321. uri: DS.belongsTo('App.AlertMetricsUriDefinition')
  322. });
  323. App.AggregateAlertDefinition = App.AlertDefinition.extend({
  324. alertName: DS.attr('string')
  325. });
  326. App.ScriptAlertDefinition = App.AlertDefinition.extend({
  327. location: DS.attr('string')
  328. });
  329. App.AlertDefinition.FIXTURES = [];
  330. App.AlertReportDefinition.FIXTURES = [];
  331. App.AlertMetricsSourceDefinition.FIXTURES = [];
  332. App.PortAlertDefinition.FIXTURES = [];
  333. App.AlertMetricsUriDefinition.FIXTURES = [];
  334. App.MetricsAlertDefinition.FIXTURES = [];
  335. App.WebAlertDefinition.FIXTURES = [];
  336. App.AggregateAlertDefinition.FIXTURES = [];
  337. App.ScriptAlertDefinition.FIXTURES = [];