alert_config.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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. * Array of a group of configs, that current config property relates to
  137. * Should be set in controller in rendering configs function
  138. * Used to get access to other configs properties of one group
  139. * @type {App.AlertConfigProperty[]}
  140. */
  141. allConfigs: []
  142. });
  143. App.AlertConfigProperties = {
  144. AlertName: App.AlertConfigProperty.extend({
  145. name: 'alert_name',
  146. label: 'Alert Name',
  147. displayType: 'textField',
  148. classNames: 'alert-text-input',
  149. apiProperty: 'name'
  150. }),
  151. AlertNameSelected: App.AlertConfigProperty.extend({
  152. name: 'alert_name',
  153. label: 'Alert Name',
  154. displayType: 'select',
  155. apiProperty: 'name'
  156. }),
  157. ServiceAlertType: App.AlertConfigProperty.extend({
  158. name: 'alert_type_service',
  159. label: 'Service Alert Definition',
  160. displayType: 'radioButton',
  161. group: 'alert_type'
  162. }),
  163. HostAlertType: App.AlertConfigProperty.extend({
  164. name: 'alert_type_host',
  165. label: 'Host Alert Definition',
  166. displayType: 'radioButton',
  167. group: 'alert_type'
  168. }),
  169. Service: App.AlertConfigProperty.extend({
  170. name: 'service',
  171. label: 'Service',
  172. displayType: 'select',
  173. apiProperty: 'service_name',
  174. apiFormattedValue: function () {
  175. return App.StackService.find().findProperty('displayName', this.get('value')).get('serviceName');
  176. }.property('value')
  177. }),
  178. Component: App.AlertConfigProperty.extend({
  179. name: 'component',
  180. label: 'Component',
  181. displayType: 'select',
  182. apiProperty: 'component_name',
  183. apiFormattedValue: function () {
  184. return App.StackServiceComponent.find().findProperty('displayName', this.get('value')).get('componentName');
  185. }.property('value')
  186. }),
  187. Scope: App.AlertConfigProperty.extend({
  188. name: 'scope',
  189. label: 'Scope',
  190. displayType: 'select',
  191. apiProperty: 'scope',
  192. apiFormattedValue: function () {
  193. return this.get('value').toUpperCase();
  194. }.property('value')
  195. }),
  196. Description: App.AlertConfigProperty.extend({
  197. name: 'description',
  198. label: 'Description',
  199. displayType: 'textArea',
  200. classNames: 'alert-config-text-area',
  201. // todo: check value after API will be provided
  202. apiProperty: 'description'
  203. }),
  204. Interval: App.AlertConfigProperty.extend({
  205. name: 'interval',
  206. label: 'Interval',
  207. displayType: 'textField',
  208. unit: 'Minute',
  209. classNames: 'alert-interval-input',
  210. apiProperty: 'interval',
  211. isValid: function () {
  212. var value = this.get('value');
  213. if (!value) return false;
  214. value = ('' + value).trim();
  215. return !isNaN(value) && value >= 1;
  216. }.property('value')
  217. }),
  218. /**
  219. * Implements threshold
  220. * Main difference from other alertConfigProperties:
  221. * it has two editable parts - <code>value</code> and <code>text</code>
  222. * User may configure it to edit only one of them (use flags <code>showInputForValue</code> and <code>showInputForText</code>)
  223. * This flags also determines update value and text in the API-request or not (see <code>App.AlertConfigProperties.Thresholds</code> for more examples)
  224. *
  225. * @type {App.AlertConfigProperty.Threshold}
  226. */
  227. Threshold: App.AlertConfigProperty.extend({
  228. name: 'threshold',
  229. /**
  230. * Property text cache to realise undo function
  231. * @type {*}
  232. */
  233. previousText: null,
  234. label: '',
  235. /**
  236. * OK|WARNING|CRITICAL
  237. * @type {string}
  238. */
  239. badge: '',
  240. /**
  241. * threshold-value
  242. * @type {string}
  243. */
  244. value: '',
  245. /**
  246. * Type of value. This will be a fixed set of types (like %).
  247. */
  248. valueMetric: null,
  249. /**
  250. * Value actually displayed to the user. This value is transformed
  251. * based on the limited types of 'valueMetric's. Mappings from
  252. * 'value' to 'displayValue' is handled by observers.
  253. */
  254. displayValue: '',
  255. /**
  256. * threshold-text
  257. * @type {string}
  258. */
  259. text: '',
  260. displayType: 'threshold',
  261. classNames: 'alert-thresholds-input',
  262. apiProperty: [],
  263. init: function () {
  264. this.valueWasChanged();
  265. this._super();
  266. },
  267. /**
  268. * @type {string[]}
  269. */
  270. apiFormattedValue: function () {
  271. var ret = [];
  272. if (this.get('showInputForValue')) {
  273. ret.push(this.get('value'));
  274. }
  275. if (this.get('showInputForText')) {
  276. ret.push(this.get('text'));
  277. }
  278. return ret;
  279. }.property('value', 'text', 'showInputForValue', 'showInputForText'),
  280. /**
  281. * Determines if <code>value</code> should be visible and editable (if not - won't update API-value)
  282. * @type {bool}
  283. */
  284. showInputForValue: true,
  285. /**
  286. * Determines if <code>text</code> should be visible and editable (if not - won't update API-text)
  287. * @type {bool}
  288. */
  289. showInputForText: true,
  290. /**
  291. * Custom css-class for different badges
  292. * type {string}
  293. */
  294. badgeCssClass: function () {
  295. return 'alert-state-' + this.get('badge');
  296. }.property('badge'),
  297. /**
  298. * Determines if <code>value</code> or <code>text</code> were changed
  299. * @type {bool}
  300. */
  301. wasChanged: function () {
  302. return (this.get('previousValue') !== null && this.get('value') !== this.get('previousValue')) ||
  303. (this.get('previousText') !== null && this.get('text') !== this.get('previousText'));
  304. }.property('value', 'text', 'previousValue', 'previousText'),
  305. valueWasChanged: function () {
  306. var value = this.get('value');
  307. var valueMetric = this.get('valueMetric');
  308. var displayValue = this.get('displayValue');
  309. var newDisplayValue = value;
  310. if (value && '%' == valueMetric && !isNaN(value)) {
  311. newDisplayValue = (Number(value) * 100) + '';
  312. }
  313. if (newDisplayValue != displayValue) {
  314. this.set('displayValue', newDisplayValue);
  315. }
  316. }.observes('value', 'valueMetric'),
  317. displayValueWasChanged: function () {
  318. var value = this.get('value');
  319. var valueMetric = this.get('valueMetric');
  320. var displayValue = this.get('displayValue');
  321. var newValue = displayValue;
  322. if (displayValue && '%' == valueMetric && !isNaN(displayValue)) {
  323. newValue = (Number(displayValue) / 100) + '';
  324. }
  325. if (newValue != value) {
  326. this.set('value', newValue);
  327. }
  328. }.observes('displayValue', 'valueMetric')
  329. }),
  330. URI: App.AlertConfigProperty.extend({
  331. name: 'uri',
  332. label: 'URI',
  333. displayType: 'textField',
  334. classNames: 'alert-text-input',
  335. apiProperty: 'source.uri'
  336. }),
  337. URIExtended: App.AlertConfigProperty.extend({
  338. name: 'uri',
  339. label: 'URI',
  340. displayType: 'textArea',
  341. classNames: 'alert-config-text-area',
  342. apiProperty: 'source.uri',
  343. apiFormattedValue: function () {
  344. var result = {};
  345. try {
  346. result = JSON.parse(this.get('value'));
  347. } catch (e) {
  348. console.error('Wrong format of URI');
  349. }
  350. return result;
  351. }.property('value')
  352. }),
  353. DefaultPort: App.AlertConfigProperty.extend({
  354. name: 'default_port',
  355. label: 'Default Port',
  356. displayType: 'textField',
  357. classNames: 'alert-port-input',
  358. apiProperty: 'source.default_port'
  359. }),
  360. Path: App.AlertConfigProperty.extend({
  361. name: 'path',
  362. label: 'Path',
  363. displayType: 'textField',
  364. classNames: 'alert-text-input',
  365. apiProperty: 'source.path'
  366. }),
  367. Metrics: App.AlertConfigProperty.extend({
  368. name: 'metrics',
  369. label: 'JMX/Ganglia Metrics',
  370. displayType: 'textArea',
  371. classNames: 'alert-config-text-area',
  372. apiProperty: function () {
  373. return this.get('isJMXMetric') ? 'source.jmx.property_list' : 'source.ganglia.property_list'
  374. }.property('isJMXMetric'),
  375. apiFormattedValue: function () {
  376. return this.get('value').split(',\n');
  377. }.property('value')
  378. }),
  379. FormatString: App.AlertConfigProperty.extend({
  380. name: 'metrics_string',
  381. label: 'Format String',
  382. displayType: 'textArea',
  383. classNames: 'alert-config-text-area',
  384. apiProperty: function () {
  385. return this.get('isJMXMetric') ? 'source.jmx.value' : 'source.ganglia.value'
  386. }.property('isJMXMetric')
  387. })
  388. };
  389. App.AlertConfigProperties.Thresholds = {
  390. OkThreshold: App.AlertConfigProperties.Threshold.extend({
  391. badge: 'OK',
  392. name: 'ok_threshold',
  393. apiProperty: function () {
  394. var ret = [];
  395. if (this.get('showInputForValue')) {
  396. ret.push('source.reporting.ok.value');
  397. }
  398. if (this.get('showInputForText')) {
  399. ret.push('source.reporting.ok.text');
  400. }
  401. return ret;
  402. }.property('showInputForValue', 'showInputForText')
  403. }),
  404. WarningThreshold: App.AlertConfigProperties.Threshold.extend({
  405. badge: 'WARNING',
  406. name: 'warning_threshold',
  407. apiProperty: function () {
  408. var ret = [];
  409. if (this.get('showInputForValue')) {
  410. ret.push('source.reporting.warning.value');
  411. }
  412. if (this.get('showInputForText')) {
  413. ret.push('source.reporting.warning.text');
  414. }
  415. return ret;
  416. }.property('showInputForValue', 'showInputForText'),
  417. isValid: function () {
  418. var value = this.get('value');
  419. if (!value) return false;
  420. value = ('' + value).trim();
  421. if (this.get('showInputForValue') && this.get('valueMetric') == '%') {
  422. return !isNaN(value) && value > 0 && value <= 1.0;
  423. } else if (this.get('showInputForValue')) {
  424. return !isNaN(value) && value > 0;
  425. } else {
  426. return true;
  427. }
  428. }.property('value', 'showInputForValue')
  429. }),
  430. CriticalThreshold: App.AlertConfigProperties.Threshold.extend({
  431. badge: 'CRITICAL',
  432. name: 'critical_threshold',
  433. apiProperty: function () {
  434. var ret = [];
  435. if (this.get('showInputForValue')) {
  436. ret.push('source.reporting.critical.value');
  437. }
  438. if (this.get('showInputForText')) {
  439. ret.push('source.reporting.critical.text');
  440. }
  441. return ret;
  442. }.property('showInputForValue', 'showInputForText'),
  443. isValid: function () {
  444. var value = this.get('value');
  445. if (!value) return false;
  446. value = ('' + value).trim();
  447. if (this.get('showInputForValue') && this.get('valueMetric') == '%') {
  448. return !isNaN(value) && value > 0 && value <= 1.0;
  449. } else if (this.get('showInputForValue')) {
  450. return !isNaN(value) && value > 0;
  451. } else {
  452. return true;
  453. }
  454. }.property('value', 'showInputForValue')
  455. })
  456. };