alert_definition.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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/date');
  20. function computedOnSummaryState(state) {
  21. return Em.computed('summary.' + state, 'summary.' + state + '.count', 'summary.' + state + '.maintenanceCount', function () {
  22. var summary = Em.get(this, 'summary');
  23. return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
  24. });
  25. }
  26. App.AlertDefinition = DS.Model.extend({
  27. name: DS.attr('string'),
  28. label: DS.attr('string'),
  29. description: DS.attr('string'),
  30. service: DS.belongsTo('App.Service'),
  31. serviceName: DS.attr('string'),
  32. componentName: DS.attr('string'),
  33. enabled: DS.attr('boolean'),
  34. scope: DS.attr('string'),
  35. interval: DS.attr('number'),
  36. type: DS.attr('string'),
  37. groups: DS.hasMany('App.AlertGroup'),
  38. reporting: DS.hasMany('App.AlertReportDefinition'),
  39. parameters: DS.hasMany('App.AlertDefinitionParameter'),
  40. lastTriggered: DS.attr('number'),
  41. lastTriggeredRaw: DS.attr('number'),
  42. //relates only to SCRIPT-type alert definition
  43. location: DS.attr('string'),
  44. //relates only to AGGREGATE-type alert definition
  45. alertName: DS.attr('string'),
  46. //relates only to WEB and METRIC types of alert definition
  47. uri: DS.belongsTo('App.AlertMetricsUriDefinition'),
  48. //relates only METRIC-type alert definition
  49. jmx: DS.belongsTo('App.AlertMetricsSourceDefinition'),
  50. ganglia: DS.belongsTo('App.AlertMetricsSourceDefinition'),
  51. //relates only PORT-type alert definition
  52. defaultPort: DS.attr('number'),
  53. portUri: DS.attr('string'),
  54. /**
  55. * Raw data from AlertDefinition/source
  56. * used to format request content for updating alert definition
  57. * @type {Object}
  58. */
  59. rawSourceData: {},
  60. /**
  61. * Counts of alert grouped by their status
  62. * Format:
  63. * <code>
  64. * {
  65. * "CRITICAL": {
  66. * count: 1,
  67. * maintenanceCount: 0
  68. * },
  69. * "OK": {
  70. * count: 0,
  71. * maintenanceCount: 1
  72. * },
  73. * "UNKNOWN": {
  74. * count: 0,
  75. * maintenanceCount: 0
  76. * },
  77. * "WARNING": {
  78. * count: 1,
  79. * maintenanceCount: 1
  80. * }
  81. * }
  82. * </code>
  83. * @type {object}
  84. */
  85. summary: {},
  86. /**
  87. * Formatted timestamp for latest alert triggering for current alertDefinition
  88. * @type {string}
  89. */
  90. lastTriggeredFormatted: function () {
  91. return dateUtils.dateFormat(this.get('lastTriggered'));
  92. }.property('lastTriggered'),
  93. /**
  94. * Formatted timestamp with <code>$.timeago</code>
  95. * @type {string}
  96. */
  97. lastTriggeredAgoFormatted: function () {
  98. var lastTriggered = this.get('lastTriggeredRaw');
  99. return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
  100. }.property('lastTriggeredRaw'),
  101. lastTriggeredVerboseDisplay: function () {
  102. var lastTriggered = this.get('lastTriggered');
  103. return Em.I18n.t('models.alert_definition.triggered.verbose').format(dateUtils.dateFormat(lastTriggered));
  104. }.property('lastTriggered'),
  105. /**
  106. * Formatted timestamp in format: for 4 days
  107. * @type {string}
  108. */
  109. lastTriggeredForFormatted: function () {
  110. var lastTriggered = this.get('lastTriggeredRaw');
  111. var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
  112. var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
  113. $.timeago.settings.strings.suffixAgo = null;
  114. $.timeago.settings.strings.prefixAgo = 'for';
  115. var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
  116. $.timeago.settings.strings.suffixAgo = previousSuffixAgo;
  117. $.timeago.settings.strings.prefixAgo = previousPrefixAgo;
  118. return triggeredFor;
  119. }.property('lastTriggeredRaw'),
  120. /**
  121. * Formatted displayName for <code>componentName</code>
  122. * @type {String}
  123. */
  124. componentNameFormatted: Em.computed.formatRole('componentName'),
  125. /**
  126. * Status generates from child-alerts
  127. * Format: OK(1) WARN(2) CRIT(1) UNKN(1)
  128. * If single host: show: OK/WARNING/CRITICAL/UNKNOWN
  129. * If some there are no alerts with some state, this state isn't shown
  130. * If no OK/WARN/CRIT/UNKN state, then show PENDING
  131. * Order is equal to example
  132. * @type {string}
  133. */
  134. status: function () {
  135. var order = this.get('order'),
  136. summary = this.get('summary'),
  137. hostCnt = 0,
  138. self = this;
  139. order.forEach(function (state) {
  140. hostCnt += summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
  141. });
  142. if (hostCnt > 1) {
  143. // multiple hosts
  144. return order.map(function (state) {
  145. var shortState = self.get('shortState')[state];
  146. var result = '';
  147. result += summary[state].count ? '<span class="alert-state-single-host label alert-state-' + state + '">' + shortState + ' (' + summary[state].count + ')</span>' : '';
  148. // add status with maintenance mode icon
  149. result += summary[state].maintenanceCount ?
  150. '<span class="alert-state-single-host label alert-state-PENDING"><span class="icon-medkit"></span> ' + shortState + ' (' + summary[state].maintenanceCount + ')</span>' : '';
  151. return result;
  152. }).without('').join(' ');
  153. } else if (hostCnt === 1) {
  154. // single host, single status
  155. return order.map(function (state) {
  156. var shortState = self.get('shortState')[state];
  157. var result = '';
  158. result += summary[state].count ? '<span class="alert-state-single-host label alert-state-' + state + '">' + shortState + '</span>' : '';
  159. // add status with maintenance mode icon
  160. result += summary[state].maintenanceCount ?
  161. '<span class="alert-state-single-host label alert-state-PENDING"><span class="icon-medkit"></span> ' + shortState + '</span>' : '';
  162. return result;
  163. }).without('').join(' ');
  164. } else if (!hostCnt) {
  165. // none
  166. return '<span class="alert-state-single-host label alert-state-PENDING">NONE</span>';
  167. }
  168. return '';
  169. }.property('summary'),
  170. latestText: function () {
  171. var order = this.get('order'), summary = this.get('summary'), text = '';
  172. order.forEach(function (state) {
  173. var cnt = summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
  174. if (cnt > 0) {
  175. text = summary[state].latestText;
  176. }
  177. });
  178. return text;
  179. }.property('summary'),
  180. isAmbariService: Em.computed.equal('service._id', 'AMBARI'),
  181. isAmbariAgentComponent: Em.computed.equal('componentName', 'AMBARI_AGENT'),
  182. isHostAlertDefinition: Em.computed.and('isAmbariService', 'isAmbariAgentComponent'),
  183. typeIconClass: function () {
  184. var typeIcons = this.get('typeIcons'),
  185. type = this.get('type');
  186. return typeIcons[type];
  187. }.property('type'),
  188. /**
  189. * if this definition is in state: CRITICAL / WARNING, if true, will show up in alerts fast access popup
  190. * instances with maintenance mode ON are ignored
  191. * @type {boolean}
  192. */
  193. isCriticalOrWarning: function () {
  194. return !!(this.get('summary.CRITICAL.count') || this.get('summary.WARNING.count'));
  195. }.property('summary'),
  196. /**
  197. * if this definition is in state: CRITICAL
  198. * @type {boolean}
  199. */
  200. isCritical: computedOnSummaryState('CRITICAL'),
  201. /**
  202. * if this definition is in state: WARNING
  203. * @type {boolean}
  204. */
  205. isWarning: computedOnSummaryState('WARNING'),
  206. /**
  207. * if this definition is in state: OK
  208. * @type {boolean}
  209. */
  210. isOK: computedOnSummaryState('OK'),
  211. /**
  212. * if this definition is in state: UNKNOWN
  213. * @type {boolean}
  214. */
  215. isUnknown: computedOnSummaryState('UNKNOWN'),
  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. 'SERVER': 'icon-desktop',
  243. 'RECOVERY': 'icon-desktop'
  244. },
  245. /**
  246. * Sort on load definitions by this severity order
  247. */
  248. severityOrder: ['CRITICAL', 'WARNING', 'OK', 'UNKNOWN', 'PENDING'],
  249. order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],
  250. shortState: {
  251. 'CRITICAL': 'CRIT',
  252. 'WARNING': 'WARN',
  253. 'OK': 'OK',
  254. 'UNKNOWN': 'UNKWN',
  255. 'PENDING': 'NONE'
  256. }
  257. });
  258. App.AlertDefinition.reopenClass({
  259. /**
  260. * Return function to sort list of AlertDefinitions by their status
  261. * It sorts according to <code>severityOrder</code>
  262. * @param {boolean} order true - DESC, false - ASC
  263. * @returns {Function}
  264. * @method getSortDefinitionsByStatus
  265. */
  266. getSortDefinitionsByStatus: function (order) {
  267. return function (a, b) {
  268. var aSummary = a.get('summary'),
  269. bSummary = b.get('summary'),
  270. stOrder = a.get('severityOrder'),
  271. ret = 0;
  272. for (var i = 0; i < stOrder.length; i++) {
  273. var aV = Em.isNone(aSummary[stOrder[i]]) ? 0 : aSummary[stOrder[i]].count + aSummary[stOrder[i]].maintenanceCount,
  274. bV = Em.isNone(bSummary[stOrder[i]]) ? 0 : bSummary[stOrder[i]].count + bSummary[stOrder[i]].maintenanceCount;
  275. ret = bV - aV;
  276. if (ret !== 0) {
  277. break;
  278. }
  279. }
  280. return order ? ret : -ret;
  281. };
  282. }
  283. });
  284. App.AlertDefinitionParameter = DS.Model.extend({
  285. name: DS.attr('string'),
  286. displayName: DS.attr('string'),
  287. units: DS.attr('string'),
  288. value: DS.attr('string'),
  289. description: DS.attr('string'),
  290. type: DS.attr('string'),
  291. threshold: DS.attr('string')
  292. });
  293. App.AlertReportDefinition = DS.Model.extend({
  294. type: DS.attr('string'),
  295. text: DS.attr('string'),
  296. value: DS.attr('number')
  297. });
  298. App.AlertMetricsSourceDefinition = DS.Model.extend({
  299. propertyList: [],
  300. value: DS.attr('string')
  301. });
  302. App.AlertMetricsUriDefinition = DS.Model.extend({
  303. http: DS.attr('string'),
  304. https: DS.attr('string'),
  305. httpsProperty: DS.attr('string'),
  306. httpsPropertyValue: DS.attr('string'),
  307. connectionTimeout: DS.attr('number')
  308. });
  309. App.AlertDefinition.FIXTURES = [];
  310. App.AlertReportDefinition.FIXTURES = [];
  311. App.AlertMetricsSourceDefinition.FIXTURES = [];
  312. App.AlertMetricsUriDefinition.FIXTURES = [];
  313. App.AlertDefinitionParameter.FIXTURES = [];