Repository: ambari Updated Branches: refs/heads/trunk 10f824bee -> b4adae5cc
AMBARI-15855.Create a new alert type that is based on timeseries metrics (UI Task) (onechiporenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b4adae5c Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b4adae5c Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b4adae5c Branch: refs/heads/trunk Commit: b4adae5cc5912cab6d6992efb944138487823ca3 Parents: 10f824b Author: Oleg Nechiporenko <onechipore...@apache.org> Authored: Wed Apr 13 12:48:45 2016 +0300 Committer: Oleg Nechiporenko <onechipore...@apache.org> Committed: Wed Apr 13 17:20:20 2016 +0300 ---------------------------------------------------------------------- .../alerts/definition_configs_controller.js | 74 ++++++++++++ .../app/mappers/alert_definitions_mapper.js | 20 ++++ .../app/models/alerts/alert_definition.js | 11 +- ambari-web/test/controllers/installer_test.js | 12 -- .../mappers/alert_definitions_mapper_test.js | 114 ++++++++++++++++++- 5 files changed, 215 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/b4adae5c/ambari-web/app/controllers/main/alerts/definition_configs_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/alerts/definition_configs_controller.js b/ambari-web/app/controllers/main/alerts/definition_configs_controller.js index 82263f7..9dc4f92 100644 --- a/ambari-web/app/controllers/main/alerts/definition_configs_controller.js +++ b/ambari-web/app/controllers/main/alerts/definition_configs_controller.js @@ -161,6 +161,9 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({ case 'RECOVERY': configs = this.renderWebConfigs(); break; + case 'AMS': + configs = this.renderAmsConfigs(); + break; default: } @@ -312,6 +315,74 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({ return result; }, + renderAmsConfigs: function () { + var result = []; + var alertDefinition = this.get('content'); + var isWizard = this.get('isWizard'); + var units = this.get('content.reporting').findProperty('type','units') ? + this.get('content.reporting').findProperty('type','units').get('text'): null; + if (this.get('isWizard')) { + result = result.concat(this.renderCommonWizardConfigs()); + } + + result = result.concat([ + App.AlertConfigProperties.Description.create({ + value: isWizard ? '' : alertDefinition.get('description') + }), + App.AlertConfigProperties.Interval.create({ + value: isWizard ? '' : alertDefinition.get('interval') + }), + App.AlertConfigProperties.Interval.create({ + value: isWizard ? '' : alertDefinition.get('ams.interval'), + label: 'AMS Interval', + apiProperty: 'source.ams.interval' + }), + App.AlertConfigProperty.create({ + value: isWizard ? '' : alertDefinition.get('ams.value'), + label: 'AMS Value', + displayType: 'textField', + apiProperty: 'source.ams.value', + isValid: function () { + return (this.get('value') || '').trim().length > 0; + }.property('value') + }), + App.AlertConfigProperties.Parameter.create({ + value: isWizard ? '' : alertDefinition.get('ams.minimalValue'), + label: 'AMS Minimal Value', + apiProperty: 'source.ams.minimal_value' + }), + App.AlertConfigProperties.Thresholds.OkThreshold.create({ + label: 'Thresholds', + showInputForValue: false, + text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'), + value: isWizard ? '' : this.getThresholdsProperty('ok', 'value') + }), + App.AlertConfigProperties.Thresholds.WarningThreshold.create(App.AlertConfigProperties.Thresholds.PercentageMixin, { + text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'), + value: isWizard ? '' : this.getThresholdsProperty('warning', 'value'), + valueMetric: units + }), + App.AlertConfigProperties.Thresholds.CriticalThreshold.create(App.AlertConfigProperties.Thresholds.PercentageMixin, { + text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'), + value: isWizard ? '' : this.getThresholdsProperty('critical', 'value'), + valueMetric: units + }), + App.AlertConfigProperties.Parameter.create({ + value: alertDefinition.get('uri.connectionTimeout'), + name: 'connection_timeout', + label: 'Connection Timeout', + displayType: 'parameter', + apiProperty: 'source.uri.connection_timeout', + units: 'Seconds', + isValid: function () { + var value = this.get('value'); + return numericUtils.isPositiveNumber(value); + }.property('value') + }) + ]); + return result; + }, + /** * Render config properties for script-type alert definition * @method renderScriptConfigs @@ -581,6 +652,9 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({ if (Em.get(propertiesToUpdate, 'AlertDefinition/source.uri.id')) { delete propertiesToUpdate['AlertDefinition/source'].uri.id; } + if (Em.get(propertiesToUpdate, 'AlertDefinition/source.ams.id')) { + delete propertiesToUpdate['AlertDefinition/source'].ams.id; + } // `source.parameters` is an array and should be updated separately from other configs if (this.get('content.parameters.length')) { http://git-wip-us.apache.org/repos/asf/ambari/blob/b4adae5c/ambari-web/app/mappers/alert_definitions_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/alert_definitions_mapper.js b/ambari-web/app/mappers/alert_definitions_mapper.js index 64c8c16..0b5e3a7 100644 --- a/ambari-web/app/mappers/alert_definitions_mapper.js +++ b/ambari-web/app/mappers/alert_definitions_mapper.js @@ -23,6 +23,7 @@ App.alertDefinitionsMapper = App.QuickDataMapper.create({ reportModel: App.AlertReportDefinition, metricsSourceModel: App.AlertMetricsSourceDefinition, metricsUriModel: App.AlertMetricsUriDefinition, + metricsAmsModel: App.AlertMetricsAmsDefinition, parameterModel: App.AlertDefinitionParameter, config: { @@ -77,6 +78,13 @@ App.alertDefinitionsMapper = App.QuickDataMapper.create({ connection_timeout: 'AlertDefinition.source.uri.connection_timeout' }, + amsConfig: { + id: 'AlertDefinition.source.ams.id', + value: 'AlertDefinition.source.ams.value', + minimal_value: 'AlertDefinition.source.ams.minimum_value', + interval: 'AlertDefinition.source.ams.interval' + }, + map: function (json) { console.time('App.alertDefinitionsMapper execution time'); if (json && json.items) { @@ -86,6 +94,7 @@ App.alertDefinitionsMapper = App.QuickDataMapper.create({ alertReportDefinitions = [], alertMetricsSourceDefinitions = [], alertMetricsUriDefinitions = [], + alertMetricsAmsDefinitions = [], alertGroupsMap = App.cache.previousAlertGroupsMap, existingAlertDefinitions = App.AlertDefinition.find(), existingAlertDefinitionsMap = existingAlertDefinitions.toArray().toMapByProperty('id'), @@ -207,6 +216,16 @@ App.alertDefinitionsMapper = App.QuickDataMapper.create({ case 'RECOVERY': alertDefinitions.push($.extend(alertDefinition, this.parseIt(item, this.get('uriConfig')))); break; + case 'AMS': + // map App.AlertMetricsUriDefinition + alertDefinition.uri_id = item.AlertDefinition.id + 'uri'; + alertDefinition.ams_id = item.AlertDefinition.id + 'ams'; + item.AlertDefinition.source.uri.id = alertDefinition.uri_id; + item.AlertDefinition.source.ams.id = alertDefinition.ams_id; + alertMetricsUriDefinitions.push(this.parseIt(item, this.get('uriConfig'))); + alertMetricsAmsDefinitions.push(this.parseIt(item, this.get('amsConfig'))); + alertDefinitions.push(alertDefinition); + break; default: console.error('Incorrect Alert Definition type:', item.AlertDefinition); } @@ -222,6 +241,7 @@ App.alertDefinitionsMapper = App.QuickDataMapper.create({ App.store.loadMany(this.get('metricsSourceModel'), alertMetricsSourceDefinitions); this.setMetricsSourcePropertyLists(this.get('metricsSourceModel'), alertMetricsSourceDefinitions); App.store.loadMany(this.get('metricsUriModel'), alertMetricsUriDefinitions); + App.store.loadMany(this.get('metricsAmsModel'), alertMetricsAmsDefinitions); // this loadMany takes too much time App.store.loadMany(this.get('model'), alertDefinitions); this.setAlertDefinitionsRawSourceData(rawSourceData); http://git-wip-us.apache.org/repos/asf/ambari/blob/b4adae5c/ambari-web/app/models/alerts/alert_definition.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/alerts/alert_definition.js b/ambari-web/app/models/alerts/alert_definition.js index 5cdec61..245771e 100644 --- a/ambari-web/app/models/alerts/alert_definition.js +++ b/ambari-web/app/models/alerts/alert_definition.js @@ -56,6 +56,7 @@ App.AlertDefinition = DS.Model.extend({ //relates only METRIC-type alert definition jmx: DS.belongsTo('App.AlertMetricsSourceDefinition'), ganglia: DS.belongsTo('App.AlertMetricsSourceDefinition'), + ams: DS.belongsTo('App.AlertMetricsAmsDefinition'), //relates only PORT-type alert definition defaultPort: DS.attr('number'), portUri: DS.attr('string'), @@ -234,7 +235,8 @@ App.AlertDefinition = DS.Model.extend({ 'PORT': 'icon-signin', 'AGGREGATE': 'icon-plus', 'SERVER': 'icon-desktop', - 'RECOVERY': 'icon-desktop' + 'RECOVERY': 'icon-desktop', + 'AMS': 'icon-rocket' }, /** @@ -311,8 +313,15 @@ App.AlertMetricsUriDefinition = DS.Model.extend({ connectionTimeout: DS.attr('number') }); +App.AlertMetricsAmsDefinition = DS.Model.extend({ + value: DS.attr('string'), + minimalValue: DS.attr('number'), + interval: DS.attr('number') +}); + App.AlertDefinition.FIXTURES = []; App.AlertReportDefinition.FIXTURES = []; App.AlertMetricsSourceDefinition.FIXTURES = []; App.AlertMetricsUriDefinition.FIXTURES = []; +App.AlertMetricsAmsDefinition.FIXTURES = []; App.AlertDefinitionParameter.FIXTURES = []; http://git-wip-us.apache.org/repos/asf/ambari/blob/b4adae5c/ambari-web/test/controllers/installer_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/installer_test.js b/ambari-web/test/controllers/installer_test.js index 85f5613..303c8a4 100644 --- a/ambari-web/test/controllers/installer_test.js +++ b/ambari-web/test/controllers/installer_test.js @@ -41,18 +41,6 @@ describe('App.InstallerController', function () { }); }); - describe('#loadStacksVersionsDefinitionsSuccessCallback', function() { - beforeEach(function () { - sinon.stub(App.store, 'commit', Em.K); - }); - afterEach(function () { - App.store.commit.restore(); - }); - it ('Correct data', function() { - installerController.set('loadStacksRequestsCounter', 1); - }); - }); - describe('#getCluster', function() { it ('Should return merged clusterStatusTemplate', function() { installerController.set('clusterStatusTemplate', { http://git-wip-us.apache.org/repos/asf/ambari/blob/b4adae5c/ambari-web/test/mappers/alert_definitions_mapper_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/mappers/alert_definitions_mapper_test.js b/ambari-web/test/mappers/alert_definitions_mapper_test.js index 564bf1d..1c3ff60 100644 --- a/ambari-web/test/mappers/alert_definitions_mapper_test.js +++ b/ambari-web/test/mappers/alert_definitions_mapper_test.js @@ -100,6 +100,7 @@ describe('App.alertDefinitionsMapper', function () { "https" : "{{yarn-site/yarn.resourcemanager.webapp.https.address}}", "https_property" : "{{yarn-site/yarn.http.policy}}", "https_property_value" : "HTTPS_ONLY", + "connection_timeout" : 5.0, "default_port" : 0.0 } } @@ -191,6 +192,59 @@ describe('App.alertDefinitionsMapper', function () { "uri" : "{{zookeeper-env/clientPort}}" } } + }, + { + "AlertDefinition" : { + "component_name" : "NAMENODE", + "description" : "This service-level alert is triggered if the NN heap usage deviation has grown beyond the specified threshold within a given time interval.", + "enabled" : true, + "help_url" : null, + "id" : 6, + "ignore_host" : false, + "interval" : 1, + "label" : "NameNode Heap Usage (Hourly)", + "name" : "namenode_free_heap_size_deviation_percentage", + "repeat_tolerance" : 1, + "repeat_tolerance_enabled" : true, + "scope" : "SERVICE", + "service_name" : "HDFS", + "source" : { + "ams" : { + "metric_list" : [ + "jvm.JvmMetrics.MemHeapUsedM", + "jvm.JvmMetrics.MemHeapMaxM" + ], + "value" : "{1} - {0}", + "interval" : 60.0, + "compute" : "sample_standard_deviation_percentage", + "app_id" : "NAMENODE", + "minimum_value" : 1.0 + }, + "reporting" : { + "ok" : { + "text" : "The sample standard deviation percentage is {0}%" + }, + "warning" : { + "text" : "The sample standard deviation percentage is {0}%", + "value" : 20.0 + }, + "critical" : { + "text" : "The sample standard deviation percentage is {0}%", + "value" : 50.0 + }, + "units" : "%" + }, + "type" : "AMS", + "uri" : { + "http" : "{{ams-site/timeline.metrics.service.webapp.address}}", + "https" : "{{ams-site/timeline.metrics.service.webapp.address}}", + "https_property" : "{{ams-site/timeline.metrics.service.http.policy}}", + "https_property_value" : "HTTPS_ONLY", + "default_port" : 0.0, + "connection_timeout" : 5.0 + } + } + } } ] }; @@ -202,7 +256,8 @@ describe('App.alertDefinitionsMapper', function () { 'parameterModel': {}, 'reportModel': {}, 'metricsSourceModel': {}, - 'metricsUriModel': {} + 'metricsUriModel': {}, + 'metricsAmsModel': {} }); sinon.stub(App.alertDefinitionsMapper, 'deleteRecord', Em.K); @@ -230,7 +285,8 @@ describe('App.alertDefinitionsMapper', function () { 'reportModel': App.AlertReportDefinition, 'metricsSourceModel': App.AlertMetricsSourceDefinition, - 'metricsUriModel': App.AlertMetricsUriDefinition + 'metricsUriModel': App.AlertMetricsUriDefinition, + 'metricsAmsModel': App.AlertMetricsAmsDefinition }); App.alertDefinitionsMapper.deleteRecord.restore(); @@ -320,7 +376,8 @@ describe('App.alertDefinitionsMapper', function () { "http":"{{yarn-site/yarn.resourcemanager.webapp.address}}", "https":"{{yarn-site/yarn.resourcemanager.webapp.https.address}}", "https_property":"{{yarn-site/yarn.http.policy}}", - "https_property_value":"HTTPS_ONLY" + "https_property_value":"HTTPS_ONLY", + "connection_timeout" : 5.0 }]; beforeEach(function () { @@ -433,6 +490,57 @@ describe('App.alertDefinitionsMapper', function () { }); + describe('should parse AMS alertDefinitions', function () { + + var data = {items: [json.items[5]]}; + var expected = [ + { + "id" : 6, + "interval" : 1, + "label" : "NameNode Heap Usage (Hourly)", + "name" : "namenode_free_heap_size_deviation_percentage", + "repeat_tolerance" : 1, + "repeat_tolerance_enabled" : true, + "scope" : "SERVICE", + "service_name" : "HDFS", + "component_name" : "NAMENODE", + } + ]; + + var expectedMetricsUri = [{ + "id":"6uri", + "http" : "{{ams-site/timeline.metrics.service.webapp.address}}", + "https" : "{{ams-site/timeline.metrics.service.webapp.address}}", + "https_property" : "{{ams-site/timeline.metrics.service.http.policy}}", + "https_property_value" : "HTTPS_ONLY", + "connection_timeout" : 5.0 + }]; + + var expectedAms = [{ + "id": "6ams", + "value": "{1} - {0}", + "minimal_value": 1, + "interval": 60 + }]; + + beforeEach(function () { + App.alertDefinitionsMapper.map(data); + }); + + it('should map definition', function () { + testHelpers.nestedExpect(expected, App.alertDefinitionsMapper.get('model.content')); + }); + + it('parse metrics uri', function() { + testHelpers.nestedExpect(expectedMetricsUri, App.alertDefinitionsMapper.get('metricsUriModel.content')); + }); + + it('parse ams parameters', function () { + testHelpers.nestedExpect(expectedAms, App.alertDefinitionsMapper.get('metricsAmsModel.content')); + }); + + }); + /*eslint-disable mocha-cleanup/complexity-it */ it('should set groups from App.cache.previousAlertGroupsMap', function () {