Repository: ambari Updated Branches: refs/heads/trunk 6c0f9acef -> 4e7a135ed
AMBARI-11518. All Yarn NodeManager widgets not getting displayed. (jaimin) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4e7a135e Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4e7a135e Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4e7a135e Branch: refs/heads/trunk Commit: 4e7a135edf02ee49088b7523b22f1a428511df8f Parents: 6c0f9ac Author: Jaimin Jetly <[email protected]> Authored: Thu May 28 19:51:19 2015 -0700 Committer: Jaimin Jetly <[email protected]> Committed: Thu May 28 19:51:25 2015 -0700 ---------------------------------------------------------------------- .../app/mixins/common/widgets/widget_mixin.js | 44 ++++++-- ambari-web/app/utils/array_utils.js | 36 +++++++ .../views/common/widget/graph_widget_view.js | 42 ++------ .../test/mixins/common/widget_mixin_test.js | 102 ++++++++++++++----- 4 files changed, 154 insertions(+), 70 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/4e7a135e/ambari-web/app/mixins/common/widgets/widget_mixin.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/common/widgets/widget_mixin.js b/ambari-web/app/mixins/common/widgets/widget_mixin.js index 264d19f..7fa4936 100644 --- a/ambari-web/app/mixins/common/widgets/widget_mixin.js +++ b/ambari-web/app/mixins/common/widgets/widget_mixin.js @@ -21,6 +21,11 @@ var App = require('app'); App.WidgetMixin = Ember.Mixin.create({ /** + * type of metric query from which the widget is comprised + */ + + metricType: 'POINT_IN_TIME', + /** * @type {RegExp} * @const */ @@ -152,9 +157,18 @@ App.WidgetMixin = Ember.Mixin.create({ var requestMetric = $.extend({}, metric); if (requestsData[key]) { - requestsData[key]["metric_paths"].push(requestMetric["metric_path"]); + requestsData[key]["metric_paths"].push({ + metric_path: requestMetric["metric_path"], + metric_type: this.get('metricType'), + id: requestMetric["metric_path"] + "_" + this.get('metricType'), + context: this + }); } else { - requestMetric["metric_paths"] = [requestMetric["metric_path"]]; + requestMetric["metric_paths"] = [{ + metric_path: requestMetric["metric_path"], + metric_type: this.get('metricType'), + id: requestMetric["metric_path"] + "_" + this.get('metricType'), + context: this}]; delete requestMetric["metric_path"]; requestsData[key] = requestMetric; } @@ -202,12 +216,28 @@ App.WidgetMixin = Ember.Mixin.create({ data: { serviceName: request.service_name, componentName: request.component_name, - metricPaths: request.metric_paths.join(',') + metricPaths: this.prepareMetricPaths(request.metric_paths) } }); }, /** + * aggregate all metric names in the query. Add time range and step to temporal queries + */ + prepareMetricPaths: function(metricPaths) { + var temporalMetrics = metricPaths.filterProperty('metric_type', 'TEMPORAL'); + var pointInTimeMetrics = metricPaths.filterProperty('metric_type', 'POINT_IN_TIME'); + var result = temporalMetrics.length ? temporalMetrics[0].context.addTimeProperties(temporalMetrics.mapProperty('metric_path')) : []; + + if (pointInTimeMetrics.length) { + result = result.concat(pointInTimeMetrics.mapProperty('metric_path')); + } + + return result.join(','); + }, + + + /** * make GET call to server in order to fetch specific host-component metrics * @param {object} request * @returns {$.ajax} @@ -218,7 +248,7 @@ App.WidgetMixin = Ember.Mixin.create({ sender: this, data: { componentName: request.component_name, - metricPaths: request.metric_paths.join(','), + metricPaths: this.prepareMetricPaths(request.metric_paths), hostComponentCriteria: this.computeHostComponentCriteria(request) } }); @@ -639,6 +669,8 @@ App.WidgetLoadAggregator = Em.Object.create({ */ BULK_INTERVAL: 1000, + arrayUtils: require('utils/array_utils'), + /** * add request * every {{BULK_INTERVAL}} requests get collected, aggregated and sent to server @@ -699,10 +731,10 @@ App.WidgetLoadAggregator = Em.Object.create({ */ runRequests: function (requests) { var bulks = this.groupRequests(requests); - + var self = this; for (var id in bulks) { (function (_request) { - _request.data.metric_paths = _request.data.metric_paths.uniq(); + _request.data.metric_paths = self.arrayUtils.uniqObjectsbyId(_request.data.metric_paths, "id"); _request.context[_request.startCallName].call(_request.context, _request.data).done(function (response) { _request.subRequests.forEach(function (subRequest) { subRequest.successCallback.call(subRequest.context, response); http://git-wip-us.apache.org/repos/asf/ambari/blob/4e7a135e/ambari-web/app/utils/array_utils.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/array_utils.js b/ambari-web/app/utils/array_utils.js new file mode 100644 index 0000000..be727ab --- /dev/null +++ b/ambari-web/app/utils/array_utils.js @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module.exports = { + /** + * + * @param arr {Array} + * @param id + * @return result {Array} + */ + uniqObjectsbyId: function (arr, id) { + var result = []; + arr.forEach(function (item) { + var isIdPresent = result.someProperty('id', item.id); + if (!isIdPresent) { + result.pushObject(item); + } + }); + return result; + } +}; http://git-wip-us.apache.org/repos/asf/ambari/blob/4e7a135e/ambari-web/app/views/common/widget/graph_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/widget/graph_widget_view.js b/ambari-web/app/views/common/widget/graph_widget_view.js index 26dafff..29934c6 100644 --- a/ambari-web/app/views/common/widget/graph_widget_view.js +++ b/ambari-web/app/views/common/widget/graph_widget_view.js @@ -22,6 +22,12 @@ App.GraphWidgetView = Em.View.extend(App.WidgetMixin, { templateName: require('templates/common/widget/graph_widget'), /** + * type of metric query from which the widget is comprised + */ + + metricType: 'TEMPORAL', + + /** * common metrics container * @type {Array} */ @@ -185,42 +191,6 @@ App.GraphWidgetView = Em.View.extend(App.WidgetMixin, { }, /** - * make GET call to server in order to fetch service-component metrics - * @param {object} request - * @returns {$.ajax} - */ - getServiceComponentMetrics: function (request) { - return App.ajax.send({ - name: 'widgets.serviceComponent.metrics.get', - sender: this, - data: { - serviceName: request.service_name, - componentName: request.component_name, - metricPaths: this.addTimeProperties(request.metric_paths).join(',') - }, - success: 'getMetricsSuccessCallback' - }); - }, - - /** - * make GET call to server in order to fetch host-component metrics - * @param {object} request - * @returns {$.ajax} - */ - getHostComponentMetrics: function (request) { - return App.ajax.send({ - name: 'widgets.hostComponent.metrics.get', - sender: this, - data: { - componentName: request.component_name, - metricPaths: this.addTimeProperties(request.metric_paths).join(','), - hostComponentCriteria: this.computeHostComponentCriteria(request) - }, - success: 'getHostComponentMetricsSuccessCallback' - }); - }, - - /** * add time properties * @param {Array} metricPaths * @returns {Array} result http://git-wip-us.apache.org/repos/asf/ambari/blob/4e7a135e/ambari-web/test/mixins/common/widget_mixin_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/mixins/common/widget_mixin_test.js b/ambari-web/test/mixins/common/widget_mixin_test.js index 01fb277..1881d98 100644 --- a/ambari-web/test/mixins/common/widget_mixin_test.js +++ b/ambari-web/test/mixins/common/widget_mixin_test.js @@ -18,7 +18,7 @@ var App = require('app'); -describe('App.WidgetMixin', function() { +describe('App.WidgetMixin', function () { var mixinClass = Em.Object.extend(App.WidgetMixin, {metrics: [], content: {}}); describe('#loadMetrics()', function () { @@ -47,7 +47,7 @@ describe('App.WidgetMixin', function() { }); }); - describe("#extractExpressions()", function() { + describe("#extractExpressions()", function () { var mixinObject = mixinClass.create(); var testCases = [ { @@ -79,9 +79,9 @@ describe('App.WidgetMixin', function() { }); }); - describe("#getRequestData()", function() { + describe("#getRequestData()", function () { var mixinObject = mixinClass.create(); - it("", function() { + it("", function () { var data = [ { "name": "regionserver.Server.percentFilesLocal", @@ -111,14 +111,24 @@ describe('App.WidgetMixin', function() { } ]; - expect(mixinObject.getRequestData(data)).to.eql({ + expect(JSON.stringify(mixinObject.getRequestData(data))).to.eql(JSON.stringify({ "HBASE_HBASE_REGIONSERVER": { "name": "regionserver.Server.percentFilesLocal", "service_name": "HBASE", "component_name": "HBASE_REGIONSERVER", "metric_paths": [ - "metrics/hbase/regionserver/percentFilesLocal", - "w2" + { + "metric_path": "metrics/hbase/regionserver/percentFilesLocal", + "metric_type": "POINT_IN_TIME", + "id": "metrics/hbase/regionserver/percentFilesLocal_POINT_IN_TIME", + "context": {} + }, + { + "metric_path": "w2", + "metric_type": "POINT_IN_TIME", + "id": "w2_POINT_IN_TIME", + "context": {} + } ] }, "HBASE_HBASE_REGIONSERVER_c1": { @@ -127,7 +137,12 @@ describe('App.WidgetMixin', function() { "component_name": "HBASE_REGIONSERVER", "host_component_criteria": "c1", "metric_paths": [ - "metrics/hbase/regionserver/percentFilesLocal" + { + "metric_path": "metrics/hbase/regionserver/percentFilesLocal", + "metric_type": "POINT_IN_TIME", + "id": "metrics/hbase/regionserver/percentFilesLocal_POINT_IN_TIME", + "context": {} + } ] }, "HDFS_DATANODE_c1": { @@ -136,10 +151,15 @@ describe('App.WidgetMixin', function() { "component_name": "DATANODE", "host_component_criteria": "c1", "metric_paths": [ - "metrics/hbase/regionserver/percentFilesLocal" + { + "metric_path": "metrics/hbase/regionserver/percentFilesLocal", + "metric_type": "POINT_IN_TIME", + "id": "metrics/hbase/regionserver/percentFilesLocal_POINT_IN_TIME", + "context": {} + } ] } - }); + })); }); }); @@ -155,7 +175,20 @@ describe('App.WidgetMixin', function() { var request = { service_name: 'S1', component_name: 'C1', - metric_paths: ['w1', 'w2'] + metric_paths: [ + { + "metric_path": "w1", + "metric_type": "POINT_IN_TIME", + "id": "w1_POINT_IN_TIME", + "context": {} + }, + { + "metric_path": "w2", + "metric_type": "POINT_IN_TIME", + "id": "w2_POINT_IN_TIME", + "context": {} + } + ] }; mixinObject.getServiceComponentMetrics(request); expect(App.ajax.send.getCall(0).args[0]).to.eql({ @@ -207,7 +240,20 @@ describe('App.WidgetMixin', function() { it("", function () { var request = { component_name: 'C1', - metric_paths: ['w1', 'w2'], + metric_paths: [ + { + "metric_path": "w1", + "metric_type": "POINT_IN_TIME", + "id": "w1_POINT_IN_TIME", + "context": {} + }, + { + "metric_path": "w2", + "metric_type": "POINT_IN_TIME", + "id": "w2_POINT_IN_TIME", + "context": {} + } + ], host_component_criteria: 'c1' }; mixinObject.getHostComponentMetrics(request); @@ -223,7 +269,7 @@ describe('App.WidgetMixin', function() { }); }); - describe("#calculateValues()", function() { + describe("#calculateValues()", function () { var mixinObject = mixinClass.create(); beforeEach(function () { @@ -234,7 +280,7 @@ describe('App.WidgetMixin', function() { mixinObject.extractExpressions.restore(); this.mock.restore(); }); - it("value compute correctly", function() { + it("value compute correctly", function () { this.mock.returns({'${a}': 1}); mixinObject.set('content.values', [{ value: '${a}' @@ -242,7 +288,7 @@ describe('App.WidgetMixin', function() { mixinObject.calculateValues(); expect(mixinObject.get('content.values')[0].computedValue).to.equal('1'); }); - it("value not available", function() { + it("value not available", function () { this.mock.returns({}); mixinObject.set('content.values', [{ value: '${a}' @@ -250,7 +296,7 @@ describe('App.WidgetMixin', function() { mixinObject.calculateValues(); expect(mixinObject.get('content.values')[0].computedValue).to.be.empty; }); - it("value is null", function() { + it("value is null", function () { this.mock.returns({'${a}': null}); mixinObject.set('content.values', [{ value: '${a}' @@ -260,17 +306,17 @@ describe('App.WidgetMixin', function() { }); }); - describe("#computeExpression()", function() { + describe("#computeExpression()", function () { var mixinObject = mixinClass.create(); - it("expression missing metrics", function() { + it("expression missing metrics", function () { var expressions = ['e.m1']; var metrics = []; expect(mixinObject.computeExpression(expressions, metrics)).to.eql({ "${e.m1}": "" }); }); - it("Value is not correct mathematical expression", function() { + it("Value is not correct mathematical expression", function () { var expressions = ['e.m1']; var metrics = [{ name: 'e.m1', @@ -280,7 +326,7 @@ describe('App.WidgetMixin', function() { "${e.m1}": "" }); }); - it("correct expression", function() { + it("correct expression", function () { var expressions = ['e.m1+e.m1']; var metrics = [{ name: 'e.m1', @@ -292,7 +338,7 @@ describe('App.WidgetMixin', function() { }); }); - describe("#cloneWidget()", function() { + describe("#cloneWidget()", function () { var mixinObject = mixinClass.create(); before(function () { @@ -303,7 +349,7 @@ describe('App.WidgetMixin', function() { App.showConfirmationPopup.restore(); mixinObject.postWidgetDefinition.restore(); }); - it("", function() { + it("", function () { var popup = mixinObject.cloneWidget(); expect(App.showConfirmationPopup.calledOnce).to.be.true; popup.onPrimary(); @@ -311,7 +357,7 @@ describe('App.WidgetMixin', function() { }); }); - describe("#postWidgetDefinition()", function() { + describe("#postWidgetDefinition()", function () { var mixinObject = mixinClass.create(); before(function () { @@ -322,7 +368,7 @@ describe('App.WidgetMixin', function() { App.ajax.send.restore(); mixinObject.collectWidgetData.restore(); }); - it("", function() { + it("", function () { mixinObject.postWidgetDefinition(); expect(App.ajax.send.getCall(0).args[0]).to.eql({ name: 'widgets.wizard.add', @@ -337,7 +383,7 @@ describe('App.WidgetMixin', function() { }); -describe('App.WidgetLoadAggregator', function() { +describe('App.WidgetLoadAggregator', function () { var aggregator = App.WidgetLoadAggregator; describe("#add()", function () { @@ -411,7 +457,7 @@ describe('App.WidgetLoadAggregator', function() { }); }); - describe("#runRequests()", function() { + describe("#runRequests()", function () { var mock = { f1: function () { return { @@ -421,7 +467,7 @@ describe('App.WidgetLoadAggregator', function() { } }; beforeEach(function () { - sinon.stub(aggregator, 'groupRequests', function(requests){ + sinon.stub(aggregator, 'groupRequests', function (requests) { return requests; }); sinon.spy(mock, 'f1'); @@ -430,7 +476,7 @@ describe('App.WidgetLoadAggregator', function() { aggregator.groupRequests.restore(); mock.f1.restore(); }); - it("", function() { + it("", function () { var requests = { 'r1': { data: {
