alert_config.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  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. App.AlertConfigProperty = Ember.Object.extend({
  20. /**
  21. * label to be shown for config property
  22. * @type {String}
  23. */
  24. label: '',
  25. /**
  26. * config property value
  27. * @type {*}
  28. */
  29. value: null,
  30. /**
  31. * property value cache to realise undo function
  32. * @type {*}
  33. */
  34. previousValue: null,
  35. /**
  36. * define either input is disabled or enabled
  37. * @type {Boolean}
  38. */
  39. isDisabled: false,
  40. /**
  41. * options that Select list will have
  42. * @type {Array}
  43. */
  44. options: [],
  45. /**
  46. * input displayType
  47. * one of 'textFields', 'textArea', 'select' or 'threshold'
  48. * @type {String}
  49. */
  50. displayType: '',
  51. /**
  52. * unit to be shown with value
  53. * @type {String}
  54. */
  55. unit: null,
  56. /**
  57. * space separated list of css class names to use
  58. * @type {String}
  59. */
  60. classNames: '',
  61. /**
  62. * define whether row with property should be shifted right
  63. * @type {Boolean}
  64. */
  65. isShifted: false,
  66. /**
  67. * name or names of properties related to config
  68. * may be either string for one property or array of strings for multiple properties
  69. * if this property is array, then <code>apiFormattedValue</code> should also be an array
  70. * example: <code>apiProperty[0]</code> relates to <code>apiFormattedValue[0]</code>
  71. * @type {String|Array}
  72. */
  73. apiProperty: '',
  74. /**
  75. * for some metrics properties may be set true or false
  76. * depending on what property is related to (JMX or Ganglia)
  77. */
  78. isJMXMetric: null,
  79. /**
  80. * define place to show label
  81. * if true - label is shown before input
  82. * if false - label is shown after input
  83. * @type {Boolean}
  84. */
  85. isPreLabeled: function () {
  86. var afterLabeledTypes = ['radioButton'];
  87. return !afterLabeledTypes.contains(this.get('displayType'));
  88. }.property('displayType'),
  89. /**
  90. * value converted to appropriate format for sending to server
  91. * should be computed property
  92. * should be defined in child class
  93. * @type {*}
  94. */
  95. apiFormattedValue: function () {
  96. return this.get('value');
  97. }.property('value'),
  98. /**
  99. * define if property was changed by user
  100. * @type {Boolean}
  101. */
  102. wasChanged: function () {
  103. return this.get('previousValue') !== null && this.get('value') !== this.get('previousValue');
  104. }.property('value', 'previousValue'),
  105. /**
  106. * view class according to <code>displayType</code>
  107. * @type {Em.View}
  108. */
  109. viewClass: function () {
  110. var displayType = this.get('displayType');
  111. switch (displayType) {
  112. case 'textField':
  113. return App.AlertConfigTextFieldView;
  114. case 'textArea':
  115. return App.AlertConfigTextAreaView;
  116. case 'select':
  117. return App.AlertConfigSelectView;
  118. case 'threshold':
  119. return App.AlertConfigThresholdView;
  120. case 'radioButton':
  121. return App.AlertConfigRadioButtonView;
  122. default:
  123. console.error('Unable to find viewClass for displayType ', displayType);
  124. }
  125. }.property('displayType'),
  126. /**
  127. * Define whether property is valid
  128. * Computed property
  129. * Should be defined in child class
  130. * @type {Boolean}
  131. */
  132. isValid: function () {
  133. return true;
  134. }.property()
  135. });
  136. App.AlertConfigProperties = {
  137. AlertName: App.AlertConfigProperty.extend({
  138. name: 'alert_name',
  139. label: 'Alert Name',
  140. displayType: 'textField',
  141. classNames: 'alert-text-input',
  142. apiProperty: 'name'
  143. }),
  144. AlertNameSelected: App.AlertConfigProperty.extend({
  145. name: 'alert_name',
  146. label: 'Alert Name',
  147. displayType: 'select',
  148. apiProperty: 'name'
  149. }),
  150. ServiceAlertType: App.AlertConfigProperty.extend({
  151. name: 'alert_type_service',
  152. label: 'Service Alert Definition',
  153. displayType: 'radioButton',
  154. group: 'alert_type'
  155. }),
  156. HostAlertType: App.AlertConfigProperty.extend({
  157. name: 'alert_type_host',
  158. label: 'Host Alert Definition',
  159. displayType: 'radioButton',
  160. group: 'alert_type'
  161. }),
  162. Service: App.AlertConfigProperty.extend({
  163. name: 'service',
  164. label: 'Service',
  165. displayType: 'select',
  166. apiProperty: 'service_name',
  167. apiFormattedValue: function () {
  168. return App.StackService.find().findProperty('displayName', this.get('value')).get('serviceName');
  169. }.property('value')
  170. }),
  171. Component: App.AlertConfigProperty.extend({
  172. name: 'component',
  173. label: 'Component',
  174. displayType: 'select',
  175. apiProperty: 'component_name',
  176. apiFormattedValue: function () {
  177. return App.StackServiceComponent.find().findProperty('displayName', this.get('value')).get('componentName');
  178. }.property('value')
  179. }),
  180. Scope: App.AlertConfigProperty.extend({
  181. name: 'scope',
  182. label: 'Scope',
  183. displayType: 'select',
  184. apiProperty: 'scope',
  185. apiFormattedValue: function () {
  186. return this.get('value').toUpperCase();
  187. }.property('value')
  188. }),
  189. Description: App.AlertConfigProperty.extend({
  190. name: 'description',
  191. label: 'Description',
  192. displayType: 'textArea',
  193. classNames: 'alert-config-text-area',
  194. // todo: check value after API will be provided
  195. apiProperty: 'description'
  196. }),
  197. Interval: App.AlertConfigProperty.extend({
  198. name: 'interval',
  199. label: 'Interval',
  200. displayType: 'textField',
  201. unit: 'Minute',
  202. classNames: 'alert-interval-input',
  203. apiProperty: 'interval',
  204. isValid: function () {
  205. var value = this.get('value');
  206. if (!value) return false;
  207. value = ('' + value).trim();
  208. return !isNaN(value) && value >= 1;
  209. }.property('value')
  210. }),
  211. /**
  212. * Implements threshold
  213. * Main difference from other alertConfigProperties:
  214. * it has two editable parts - <code>value</code> and <code>text</code>
  215. * User may configure it to edit only one of them (use flags <code>showInputForValue</code> and <code>showInputForText</code>)
  216. * This flags also determines update value and text in the API-request or not (see <code>App.AlertConfigProperties.Thresholds</code> for more examples)
  217. *
  218. * @type {App.AlertConfigProperty.Threshold}
  219. */
  220. Threshold: App.AlertConfigProperty.extend({
  221. name: 'threshold',
  222. /**
  223. * Property text cache to realise undo function
  224. * @type {*}
  225. */
  226. previousText: null,
  227. label: '',
  228. /**
  229. * OK|WARNING|CRITICAL
  230. * @type {string}
  231. */
  232. badge: '',
  233. /**
  234. * threshold-value
  235. * @type {string}
  236. */
  237. value: '',
  238. /**
  239. * Type of value. This will be a fixed set of types (like %).
  240. */
  241. valueMetric: null,
  242. /**
  243. * Value actually displayed to the user. This value is transformed
  244. * based on the limited types of 'valueMetric's. Mappings from
  245. * 'value' to 'displayValue' is handled by observers.
  246. */
  247. displayValue: '',
  248. /**
  249. * threshold-text
  250. * @type {string}
  251. */
  252. text: '',
  253. displayType: 'threshold',
  254. classNames: 'alert-thresholds-input',
  255. apiProperty: [],
  256. init: function () {
  257. this.valueWasChanged();
  258. this._super();
  259. },
  260. /**
  261. * @type {string[]}
  262. */
  263. apiFormattedValue: function () {
  264. var ret = [];
  265. if (this.get('showInputForValue')) {
  266. ret.push(this.get('value'));
  267. }
  268. if (this.get('showInputForText')) {
  269. ret.push(this.get('text'));
  270. }
  271. return ret;
  272. }.property('value', 'text', 'showInputForValue', 'showInputForText'),
  273. /**
  274. * Determines if <code>value</code> should be visible and editable (if not - won't update API-value)
  275. * @type {bool}
  276. */
  277. showInputForValue: true,
  278. /**
  279. * Determines if <code>text</code> should be visible and editable (if not - won't update API-text)
  280. * @type {bool}
  281. */
  282. showInputForText: true,
  283. /**
  284. * Custom css-class for different badges
  285. * type {string}
  286. */
  287. badgeCssClass: function () {
  288. return 'alert-state-' + this.get('badge');
  289. }.property('badge'),
  290. /**
  291. * Determines if <code>value</code> or <code>text</code> were changed
  292. * @type {bool}
  293. */
  294. wasChanged: function () {
  295. return (this.get('previousValue') !== null && this.get('value') !== this.get('previousValue')) ||
  296. (this.get('previousText') !== null && this.get('text') !== this.get('previousText'));
  297. }.property('value', 'text', 'previousValue', 'previousText'),
  298. /**
  299. * May be redefined in child-models, mixins etc
  300. * @method getValue
  301. * @returns {string}
  302. */
  303. getNewValue: function () {
  304. return this.get('value');
  305. },
  306. valueWasChanged: function () {
  307. var displayValue = this.get('displayValue');
  308. var newDisplayValue = this.getNewValue();
  309. if (Math.abs(newDisplayValue - displayValue) > 0.000001) {
  310. this.set('displayValue', newDisplayValue);
  311. }
  312. }.observes('value'),
  313. /**
  314. * May be redefined in child-models, mixins etc
  315. * @method getDisplayValue
  316. * @returns {string}
  317. */
  318. getNewDisplayValue: function () {
  319. return this.get('displayValue');
  320. },
  321. displayValueWasChanged: function () {
  322. var value = this.get('value');
  323. var newValue = this.getNewDisplayValue();
  324. if (Math.abs(newValue - value) > 0.000001) {
  325. this.set('value', newValue);
  326. }
  327. }.observes('displayValue')
  328. }),
  329. URI: App.AlertConfigProperty.extend({
  330. name: 'uri',
  331. label: 'URI',
  332. displayType: 'textField',
  333. classNames: 'alert-text-input',
  334. apiProperty: 'source.uri'
  335. }),
  336. URIExtended: App.AlertConfigProperty.extend({
  337. name: 'uri',
  338. label: 'URI',
  339. displayType: 'textArea',
  340. classNames: 'alert-config-text-area',
  341. apiProperty: 'source.uri',
  342. apiFormattedValue: function () {
  343. var result = {};
  344. try {
  345. result = JSON.parse(this.get('value'));
  346. } catch (e) {
  347. console.error('Wrong format of URI');
  348. }
  349. return result;
  350. }.property('value')
  351. }),
  352. DefaultPort: App.AlertConfigProperty.extend({
  353. name: 'default_port',
  354. label: 'Default Port',
  355. displayType: 'textField',
  356. classNames: 'alert-port-input',
  357. apiProperty: 'source.default_port'
  358. }),
  359. Path: App.AlertConfigProperty.extend({
  360. name: 'path',
  361. label: 'Path',
  362. displayType: 'textField',
  363. classNames: 'alert-text-input',
  364. apiProperty: 'source.path'
  365. }),
  366. Metrics: App.AlertConfigProperty.extend({
  367. name: 'metrics',
  368. label: 'JMX/Ganglia Metrics',
  369. displayType: 'textArea',
  370. classNames: 'alert-config-text-area',
  371. apiProperty: function () {
  372. return this.get('isJMXMetric') ? 'source.jmx.property_list' : 'source.ganglia.property_list'
  373. }.property('isJMXMetric'),
  374. apiFormattedValue: function () {
  375. return this.get('value').split(',\n');
  376. }.property('value')
  377. }),
  378. FormatString: App.AlertConfigProperty.extend({
  379. name: 'metrics_string',
  380. label: 'Format String',
  381. displayType: 'textArea',
  382. classNames: 'alert-config-text-area',
  383. apiProperty: function () {
  384. return this.get('isJMXMetric') ? 'source.jmx.value' : 'source.ganglia.value'
  385. }.property('isJMXMetric')
  386. })
  387. };
  388. App.AlertConfigProperties.Thresholds = {
  389. OkThreshold: App.AlertConfigProperties.Threshold.extend({
  390. badge: 'OK',
  391. name: 'ok_threshold',
  392. apiProperty: function () {
  393. var ret = [];
  394. if (this.get('showInputForValue')) {
  395. ret.push('source.reporting.ok.value');
  396. }
  397. if (this.get('showInputForText')) {
  398. ret.push('source.reporting.ok.text');
  399. }
  400. return ret;
  401. }.property('showInputForValue', 'showInputForText')
  402. }),
  403. WarningThreshold: App.AlertConfigProperties.Threshold.extend({
  404. badge: 'WARNING',
  405. name: 'warning_threshold',
  406. apiProperty: function () {
  407. var ret = [];
  408. if (this.get('showInputForValue')) {
  409. ret.push('source.reporting.warning.value');
  410. }
  411. if (this.get('showInputForText')) {
  412. ret.push('source.reporting.warning.text');
  413. }
  414. return ret;
  415. }.property('showInputForValue', 'showInputForText'),
  416. isValid: function () {
  417. var value = this.get('value');
  418. if (!value) return false;
  419. value = ('' + value).trim();
  420. return this.get('showInputForValue') ? !isNaN(value) && value > 0 : true;
  421. }.property('value', 'showInputForValue')
  422. }),
  423. CriticalThreshold: App.AlertConfigProperties.Threshold.extend({
  424. badge: 'CRITICAL',
  425. name: 'critical_threshold',
  426. apiProperty: function () {
  427. var ret = [];
  428. if (this.get('showInputForValue')) {
  429. ret.push('source.reporting.critical.value');
  430. }
  431. if (this.get('showInputForText')) {
  432. ret.push('source.reporting.critical.text');
  433. }
  434. return ret;
  435. }.property('showInputForValue', 'showInputForText'),
  436. isValid: function () {
  437. var value = this.get('value');
  438. if (!value) return false;
  439. value = ('' + value).trim();
  440. return this.get('showInputForValue') ? !isNaN(value) && value > 0 : true;
  441. }.property('value', 'showInputForValue')
  442. }),
  443. /**
  444. * Mixin for <code>App.AlertConfigProperties.Threshold</code>
  445. * Used to validate values in percentage range (0..1]
  446. * @type {Em.Mixin}
  447. */
  448. PercentageMixin: Em.Mixin.create({
  449. isValid: function () {
  450. var value = this.get('value');
  451. if (!value) return false;
  452. value = ('' + value).trim();
  453. return this.get('showInputForValue') ? !isNaN(value) && value > 0 && value <= 1.0 : true;
  454. }.property('value', 'showInputForValue'),
  455. /**
  456. * Return <code>value * 100</code>
  457. * @returns {string}
  458. */
  459. getNewValue: function () {
  460. var value = this.get('value');
  461. return (value && !isNaN(value)) ? (Number(value) * 100) + '' : value;
  462. },
  463. /**
  464. * Return <code>displayValue / 100</code>
  465. * @returns {string}
  466. */
  467. getNewDisplayValue: function () {
  468. var displayValue = this.get('displayValue');
  469. return (displayValue && !isNaN(displayValue)) ? (Number(displayValue) / 100) + '' : displayValue;
  470. }
  471. })
  472. };