definition_configs_controller.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  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 numericUtils = require('utils/number_utils');
  19. App.MainAlertDefinitionConfigsController = Em.Controller.extend({
  20. name: 'mainAlertDefinitionConfigsController',
  21. /**
  22. * All configurable properties of alert definition
  23. * @type {Array}
  24. */
  25. configs: [],
  26. /**
  27. * Define whether configs are editable
  28. * binds to property populated in template
  29. * @type {Boolean}
  30. */
  31. canEdit: true,
  32. /**
  33. * Define configs view mode (Wizard or Definition Details page)
  34. * @type {Boolean}
  35. */
  36. isWizard: false,
  37. /**
  38. * Alert Definition type
  39. * binding is set in template
  40. * @type {String}
  41. */
  42. alertDefinitionType: '',
  43. /**
  44. * Array of displayNames of all services
  45. * is used for "Service" config options
  46. * @type {Array}
  47. */
  48. allServices: function () {
  49. return App.Service.find().mapProperty('displayName');
  50. }.property(),
  51. /**
  52. * All possible values for scope propery
  53. * @type {Array}
  54. */
  55. allScopes: ['Any', 'Host', 'Service'],
  56. /**
  57. * Array of all aggregate-alerts names
  58. * @type {Array}
  59. */
  60. aggregateAlertNames: function () {
  61. return App.AggregateAlertDefinition.find().mapProperty('name');
  62. }.property(),
  63. /**
  64. * Change options of "Component", after changing value of "Service" config
  65. * @method onServiceSelect
  66. */
  67. onServiceSelect: function () {
  68. var serviceProperty = this.get('configs').findProperty('name', 'service');
  69. if (serviceProperty && serviceProperty.get('value') !== 'Ambari') {
  70. var componentsProperty = this.get('configs').findProperty('name', 'component');
  71. componentsProperty.set('options', ['No component'].concat(App.HostComponent.find().filterProperty('service.displayName', serviceProperty.get('value')).mapProperty('displayName').uniq()));
  72. }
  73. }.observes('configs.@each.value'),
  74. /**
  75. * OnSelect handler for <code>select_type</code> property
  76. * disable fields related to definition type and set options to select lists
  77. */
  78. changeType: function (selectedType) {
  79. if (selectedType === 'alert_type_service') {
  80. this.get('configs').findProperty('name', 'service').setProperties({
  81. isDisabled: false,
  82. options: this.get('allServices'),
  83. value: this.get('allServices')[0]
  84. });
  85. this.get('configs').findProperty('name', 'component').setProperties({
  86. isDisabled: false,
  87. value: 'No component'
  88. });
  89. this.get('configs').findProperty('name', 'scope').setProperties({
  90. isDisabled: false,
  91. options: this.get('allScopes'),
  92. value: this.get('allScopes')[0]
  93. });
  94. } else {
  95. this.get('configs').findProperty('name', 'service').setProperties({
  96. isDisabled: true,
  97. options: ['Ambari'],
  98. value: 'Ambari'
  99. });
  100. this.get('configs').findProperty('name', 'component').setProperties({
  101. isDisabled: true,
  102. options: ['Ambari Agent'],
  103. value: 'Ambari Agent'
  104. });
  105. this.get('configs').findProperty('name', 'scope').setProperties({
  106. isDisabled: true,
  107. options: ['Host'],
  108. value: 'Host'
  109. });
  110. }
  111. },
  112. /**
  113. * @return {string|Null}
  114. * @method getThresholdsProperty
  115. */
  116. getThresholdsProperty: function (type, property) {
  117. var warning = this.get('content.reporting').findProperty('type', type);
  118. return warning && !Ember.isEmpty(warning.get(property)) ? warning.get(property) : null;
  119. },
  120. /**
  121. * Render array of configs for appropriate alert definition type
  122. * @method renderConfigs
  123. */
  124. renderConfigs: function () {
  125. var self = this;
  126. var alertDefinitionType = this.get('alertDefinitionType');
  127. var configs = [];
  128. switch (alertDefinitionType) {
  129. case 'PORT':
  130. configs = this.renderPortConfigs();
  131. break;
  132. case 'METRIC':
  133. configs = this.renderMetricConfigs();
  134. break;
  135. case 'WEB':
  136. configs = this.renderWebConfigs();
  137. break;
  138. case 'SCRIPT':
  139. configs = this.renderScriptConfigs();
  140. break;
  141. case 'AGGREGATE':
  142. configs = this.renderAggregateConfigs();
  143. break;
  144. case 'SERVER':
  145. configs = this.renderServerConfigs();
  146. break;
  147. case 'RECOVERY':
  148. configs = this.renderWebConfigs();
  149. break;
  150. default:
  151. }
  152. configs.forEach(function (config) {
  153. config.set('isDisabled', !self.get('canEdit') || config.get('readonly'));
  154. });
  155. this.set('configs', configs);
  156. },
  157. /**
  158. * Render config properties for port-type alert definition
  159. * @method renderPortConfigs
  160. * @returns {App.AlertConfigProperty[]}
  161. */
  162. renderPortConfigs: function () {
  163. var result = [];
  164. var alertDefinition = this.get('content');
  165. var isWizard = this.get('isWizard');
  166. if (this.get('isWizard')) {
  167. result = result.concat(this.renderCommonWizardConfigs());
  168. }
  169. result = result.concat([
  170. App.AlertConfigProperties.Description.create({
  171. value: isWizard ? '' : alertDefinition.get('description')
  172. }),
  173. App.AlertConfigProperties.Interval.create({
  174. value: isWizard ? '' : alertDefinition.get('interval')
  175. }),
  176. App.AlertConfigProperties.Thresholds.OkThreshold.create({
  177. label: 'Thresholds',
  178. showInputForValue: false,
  179. text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
  180. value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
  181. }),
  182. App.AlertConfigProperties.Thresholds.WarningThreshold.create(App.AlertConfigProperties.Thresholds.PositiveMixin, {
  183. valueMetric: 'Seconds',
  184. text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'),
  185. value: isWizard ? '' : this.getThresholdsProperty('warning', 'value')
  186. }),
  187. App.AlertConfigProperties.Thresholds.CriticalThreshold.create(App.AlertConfigProperties.Thresholds.PositiveMixin, {
  188. valueMetric: 'Seconds',
  189. text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
  190. value: isWizard ? '' : this.getThresholdsProperty('critical', 'value')
  191. })
  192. ]);
  193. return result;
  194. },
  195. /**
  196. * Render config properties for metric-type alert definition
  197. * @method renderMetricConfigs
  198. * @returns {App.AlertConfigProperty[]}
  199. */
  200. renderMetricConfigs: function () {
  201. var result = [];
  202. var alertDefinition = this.get('content');
  203. var isWizard = this.get('isWizard');
  204. var units = this.get('content.reporting').findProperty('type','units') ?
  205. this.get('content.reporting').findProperty('type','units').get('text'): null;
  206. if (this.get('isWizard')) {
  207. result = result.concat(this.renderCommonWizardConfigs());
  208. }
  209. result = result.concat([
  210. App.AlertConfigProperties.Description.create({
  211. value: isWizard ? '' : alertDefinition.get('description')
  212. }),
  213. App.AlertConfigProperties.Interval.create({
  214. value: isWizard ? '' : alertDefinition.get('interval')
  215. }),
  216. App.AlertConfigProperties.Thresholds.OkThreshold.create({
  217. label: 'Thresholds',
  218. showInputForValue: false,
  219. text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
  220. value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
  221. }),
  222. App.AlertConfigProperties.Thresholds.WarningThreshold.create({
  223. valueMetric: units,
  224. text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'),
  225. value: isWizard ? '' : this.getThresholdsProperty('warning', 'value')
  226. }),
  227. App.AlertConfigProperties.Thresholds.CriticalThreshold.create({
  228. valueMetric: units,
  229. text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
  230. value: isWizard ? '' : this.getThresholdsProperty('critical', 'value')
  231. })
  232. ]);
  233. return result;
  234. },
  235. /**
  236. * Render config properties for web-type alert definition
  237. * @method renderWebConfigs
  238. * @returns {App.AlertConfigProperty[]}
  239. */
  240. renderWebConfigs: function () {
  241. var result = [];
  242. var alertDefinition = this.get('content');
  243. var isWizard = this.get('isWizard');
  244. if (this.get('isWizard')) {
  245. result = result.concat(this.renderCommonWizardConfigs());
  246. }
  247. result = result.concat([
  248. App.AlertConfigProperties.Description.create({
  249. value: isWizard ? '' : alertDefinition.get('description')
  250. }),
  251. App.AlertConfigProperties.Interval.create({
  252. value: isWizard ? '' : alertDefinition.get('interval')
  253. }),
  254. App.AlertConfigProperties.Thresholds.OkThreshold.create({
  255. label: 'Thresholds',
  256. showInputForValue: false,
  257. text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
  258. value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
  259. }),
  260. App.AlertConfigProperties.Thresholds.WarningThreshold.create({
  261. showInputForValue: false,
  262. text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'),
  263. value: isWizard ? '' : this.getThresholdsProperty('warning', 'value')
  264. }),
  265. App.AlertConfigProperties.Thresholds.CriticalThreshold.create({
  266. showInputForValue: false,
  267. text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
  268. value: isWizard ? '' : this.getThresholdsProperty('critical', 'value')
  269. }),
  270. App.AlertConfigProperties.Parameter.create({
  271. value: alertDefinition.get('uri.connectionTimeout'),
  272. threshold: "CRITICAL",
  273. name: 'connection_timeout',
  274. label: 'Connection Timeout',
  275. displayType: 'parameter',
  276. apiProperty: 'source.uri.connection_timeout',
  277. units: 'Seconds',
  278. isValid: function () {
  279. var value = this.get('value');
  280. return numericUtils.isPositiveNumber(value);
  281. }.property('value')
  282. })
  283. ]);
  284. return result;
  285. },
  286. /**
  287. * Render config properties for script-type alert definition
  288. * @method renderScriptConfigs
  289. * @returns {App.AlertConfigProperty[]}
  290. */
  291. renderScriptConfigs: function () {
  292. var result = [];
  293. var alertDefinition = this.get('content');
  294. var isWizard = this.get('isWizard');
  295. if (this.get('isWizard')) {
  296. result = result.concat(this.renderCommonWizardConfigs());
  297. }
  298. result = result.concat([
  299. App.AlertConfigProperties.Description.create({
  300. value: isWizard ? '' : alertDefinition.get('description')
  301. }),
  302. App.AlertConfigProperties.Interval.create({
  303. value: isWizard ? '' : alertDefinition.get('interval')
  304. })
  305. ]);
  306. var mixins = {
  307. STRING: App.AlertConfigProperties.Parameters.StringMixin,
  308. NUMERIC: App.AlertConfigProperties.Parameters.NumericMixin,
  309. PERCENT: App.AlertConfigProperties.Parameters.PercentageMixin
  310. };
  311. alertDefinition.get('parameters').forEach(function (parameter) {
  312. var mixin = mixins[parameter.get('type')] || {}; // validation depends on parameter-type
  313. result.push(App.AlertConfigProperties.Parameter.create(mixin, {
  314. value: isWizard ? '' : parameter.get('value'),
  315. apiProperty: parameter.get('name'),
  316. description: parameter.get('description'),
  317. label: isWizard ? '' : parameter.get('displayName'),
  318. threshold: isWizard ? '' : parameter.get('threshold'),
  319. units: isWizard ? '' : parameter.get('units'),
  320. type: isWizard ? '' : parameter.get('type'),
  321. hidden: parameter.get('visibility') === "HIDDEN",
  322. readonly: parameter.get('visibility') === "READ_ONLY"
  323. }));
  324. });
  325. return result;
  326. },
  327. /**
  328. * Render config properties for aggregate-type alert definition
  329. * @method renderAggregateConfigs
  330. * @returns {App.AlertConfigProperty[]}
  331. */
  332. renderAggregateConfigs: function () {
  333. var isWizard = this.get('isWizard');
  334. var alertDefinition = this.get('content');
  335. var units = this.get('content.reporting').findProperty('type','units') ?
  336. this.get('content.reporting').findProperty('type','units').get('text'): null;
  337. return [
  338. App.AlertConfigProperties.Description.create({
  339. value: isWizard ? '' : alertDefinition.get('description')
  340. }),
  341. App.AlertConfigProperties.Interval.create({
  342. value: isWizard ? '' : alertDefinition.get('interval')
  343. }),
  344. App.AlertConfigProperties.Thresholds.OkThreshold.create({
  345. label: 'Thresholds',
  346. showInputForValue: false,
  347. text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
  348. value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
  349. }),
  350. App.AlertConfigProperties.Thresholds.WarningThreshold.create(App.AlertConfigProperties.Thresholds.PercentageMixin, {
  351. text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'),
  352. value: isWizard ? '' : this.getThresholdsProperty('warning', 'value'),
  353. valueMetric: units
  354. }),
  355. App.AlertConfigProperties.Thresholds.CriticalThreshold.create(App.AlertConfigProperties.Thresholds.PercentageMixin, {
  356. text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
  357. value: isWizard ? '' : this.getThresholdsProperty('critical', 'value'),
  358. valueMetric: units
  359. })
  360. ];
  361. },
  362. /**
  363. * Render config properties for server-type alert definition
  364. * @method renderScriptConfigs
  365. * @returns {App.AlertConfigProperty[]}
  366. */
  367. renderServerConfigs: function () {
  368. var result = [];
  369. var alertDefinition = this.get('content');
  370. var isWizard = this.get('isWizard');
  371. if (this.get('isWizard')) {
  372. result = result.concat(this.renderCommonWizardConfigs());
  373. }
  374. result = result.concat([
  375. App.AlertConfigProperties.Description.create({
  376. value: isWizard ? '' : alertDefinition.get('description')
  377. }),
  378. App.AlertConfigProperties.Interval.create({
  379. value: isWizard ? '' : alertDefinition.get('interval')
  380. })
  381. ]);
  382. return result;
  383. },
  384. /**
  385. * Render common list of configs used in almost all alert types in wizard
  386. * @returns {App.AlertConfigProperty[]}
  387. */
  388. renderCommonWizardConfigs: function () {
  389. return [
  390. App.AlertConfigProperties.AlertName.create({
  391. value: ''
  392. }),
  393. App.AlertConfigProperties.ServiceAlertType.create({
  394. value: true
  395. }),
  396. App.AlertConfigProperties.Service.create({
  397. options: this.get('allServices'),
  398. value: this.get('allServices')[0],
  399. isShifted: true
  400. }),
  401. App.AlertConfigProperties.Component.create({
  402. options: this.get('allComponents'),
  403. value: 'No component',
  404. isShifted: true
  405. }),
  406. App.AlertConfigProperties.Scope.create({
  407. options: this.get('allScopes'),
  408. isShifted: true
  409. }),
  410. App.AlertConfigProperties.HostAlertType.create({
  411. value: false
  412. })
  413. ];
  414. },
  415. /**
  416. * Edit configs button handler
  417. * @method editConfigs
  418. */
  419. editConfigs: function () {
  420. this.get('configs').forEach(function (property) {
  421. property.set('previousValue', property.get('value'));
  422. property.set('previousText', property.get('text'));
  423. });
  424. this.get('configs').forEach(function (config) {
  425. config.set('isDisabled', config.get('readonly'));
  426. });
  427. this.set('canEdit', true);
  428. },
  429. /**
  430. * Cancel edit configs button handler
  431. * @method cancelEditConfigs
  432. */
  433. cancelEditConfigs: function () {
  434. this.get('configs').forEach(function (property) {
  435. property.set('value', property.get('previousValue'));
  436. property.set('text', property.get('previousText'));
  437. });
  438. this.get('configs').setEach('isDisabled', true);
  439. this.set('canEdit', false);
  440. },
  441. /**
  442. * Save edit configs button handler
  443. * @method saveConfigs
  444. * @return {$.ajax}
  445. */
  446. saveConfigs: function () {
  447. this.get('configs').setEach('isDisabled', true);
  448. this.set('canEdit', false);
  449. return App.ajax.send({
  450. name: 'alerts.update_alert_definition',
  451. sender: this,
  452. data: {
  453. id: this.get('content.id'),
  454. data: this.getPropertiesToUpdate(true)
  455. },
  456. success: 'saveConfigsSuccessCallback'
  457. });
  458. },
  459. /**
  460. * Success-callback for saveConfigs-request
  461. * @method saveConfigsSuccessCallback
  462. */
  463. saveConfigsSuccessCallback: function () {
  464. App.router.get('updateController').updateAlertDefinitions(Em.K);
  465. },
  466. /**
  467. * Create object with new values to put it on server
  468. * @param {boolean} onlyChanged
  469. * @method getPropertiesToUpdate
  470. * @returns {Object}
  471. */
  472. getPropertiesToUpdate: function (onlyChanged) {
  473. var propertiesToUpdate = {};
  474. var configs = onlyChanged ? this.get('configs').filterProperty('wasChanged') : this.get('configs');
  475. configs = configs.filter(function (c) {
  476. return c.get('name') !== 'parameter';
  477. });
  478. configs.forEach(function (property) {
  479. var apiProperties = Em.makeArray(property.get('apiProperty'));
  480. var apiFormattedValues = Em.makeArray(property.get('apiFormattedValue'));
  481. apiProperties.forEach(function (apiProperty, i) {
  482. if (apiProperty.contains('source.')) {
  483. if (!propertiesToUpdate['AlertDefinition/source']) {
  484. if (this.get('content.rawSourceData')) {
  485. propertiesToUpdate['AlertDefinition/source'] = this.get('content.rawSourceData');
  486. }
  487. }
  488. if (this.get('content.rawSourceData')) {
  489. // use rawSourceData to populate propertiesToUpdate
  490. var sourcePath = propertiesToUpdate['AlertDefinition/source'];
  491. apiProperty.replace('source.', '').split('.').forEach(function (path, index, array) {
  492. // check if it is last path
  493. if (array.length - index === 1) {
  494. sourcePath[path] = apiFormattedValues[i];
  495. } else {
  496. sourcePath = sourcePath[path];
  497. }
  498. });
  499. }
  500. else {
  501. if (!propertiesToUpdate['AlertDefinition/source']) {
  502. propertiesToUpdate['AlertDefinition/source'] = {};
  503. }
  504. Ember.setFullPath(propertiesToUpdate['AlertDefinition/source'], apiProperty.replace('source.', ''), apiFormattedValues[i]);
  505. }
  506. }
  507. else {
  508. if (apiProperty) {
  509. propertiesToUpdate['AlertDefinition/' + apiProperty] = apiFormattedValues[i];
  510. }
  511. }
  512. }, this);
  513. }, this);
  514. if (Em.get(propertiesToUpdate, 'AlertDefinition/source.uri.id')) {
  515. delete propertiesToUpdate['AlertDefinition/source'].uri.id;
  516. }
  517. // `source.parameters` is an array and should be updated separately from other configs
  518. if (this.get('content.parameters.length')) {
  519. propertiesToUpdate['AlertDefinition/source'] = this.get('content.rawSourceData');
  520. var parameterConfigs = this.get('configs').filterProperty('name', 'parameter');
  521. parameterConfigs.forEach(function (parameter) {
  522. propertiesToUpdate['AlertDefinition/source'].parameters.findProperty('name', parameter.get('apiProperty')).value = parameter.get('apiFormattedValue');
  523. });
  524. }
  525. return propertiesToUpdate;
  526. },
  527. /**
  528. * Return array of all config values
  529. * used to save configs to local db in wizard
  530. * @method getConfigsValues
  531. * @returns {Array}
  532. */
  533. getConfigsValues: function () {
  534. return this.get('configs').map(function (property) {
  535. return {
  536. name: property.get('name'),
  537. value: property.get('value')
  538. }
  539. });
  540. },
  541. /**
  542. * Define whether critical threshold >= critical threshold
  543. * @type {Boolean}
  544. */
  545. hasThresholdsError: function () {
  546. var smallValue, smallValid, largeValue, largeValid;
  547. if (this.get('configs').findProperty('name', 'warning_threshold')) {
  548. smallValue = Em.get(this.get('configs').findProperty('name', 'warning_threshold'), 'value');
  549. smallValid = Em.get(this.get('configs').findProperty('name', 'warning_threshold'), 'isValid');
  550. }
  551. if (this.get('configs').findProperty('name', 'critical_threshold')) {
  552. largeValue = Em.get(this.get('configs').findProperty('name', 'critical_threshold'), 'value');
  553. largeValid = Em.get(this.get('configs').findProperty('name', 'critical_threshold'), 'isValid');
  554. }
  555. return smallValid && largeValid ? Number(smallValue) > Number(largeValue) : false;
  556. }.property('configs.@each.value'),
  557. someConfigIsInvalid: Em.computed.someBy('configs', 'isValid', false),
  558. /**
  559. * Define whether all configs are valid
  560. * @type {Boolean}
  561. */
  562. hasErrors: Em.computed.or('someConfigIsInvalid', 'hasThresholdsError')
  563. });