Updated Branches: refs/heads/trunk 2e34a088b -> 386330fde
AMBARI-4392. Storm: Add widget for Supervisor's live/dead nodes count. (Denys Buzhor via akovalenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/386330fd Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/386330fd Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/386330fd Branch: refs/heads/trunk Commit: 386330fde96666c33efa7028dee6182538d40a3d Parents: 2e34a08 Author: Aleksandr Kovalenko <[email protected]> Authored: Thu Jan 23 15:22:43 2014 +0200 Committer: Aleksandr Kovalenko <[email protected]> Committed: Thu Jan 23 15:24:51 2014 +0200 ---------------------------------------------------------------------- ambari-web/app/messages.js | 1 + ambari-web/app/views.js | 1 + ambari-web/app/views/main/dashboard.js | 35 +++- ambari-web/app/views/main/dashboard/widget.js | 21 ++- .../main/dashboard/widgets/supervisor_live.js | 177 +++++++++++++++++++ 5 files changed, 220 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/386330fd/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 2f2ea10..e41b8df 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -1514,6 +1514,7 @@ Em.I18n.translations = { 'dashboard.widgets.JobTrackerCapacity': 'JobTracker Capacity', 'dashboard.widgets.DataNodeUp': 'DataNodes Live', 'dashboard.widgets.TaskTrackerUp': 'TaskTrackers Live', + 'dashboard.widgets.SuperVisorUp': 'Supervisors Live', 'dashboard.widgets.NameNodeRpc': 'NameNode RPC', 'dashboard.widgets.JobTrackerRpc': 'JobTracker RPC', 'dashboard.widgets.MapReduceSlots': 'MapReduce Slots', http://git-wip-us.apache.org/repos/asf/ambari/blob/386330fd/ambari-web/app/views.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js index 6c1be82..b02c3f8 100644 --- a/ambari-web/app/views.js +++ b/ambari-web/app/views.js @@ -145,6 +145,7 @@ require('views/main/dashboard/widgets/resource_manager_heap'); require('views/main/dashboard/widgets/resource_manager_uptime'); require('views/main/dashboard/widgets/node_managers_live'); require('views/main/dashboard/widgets/yarn_memory'); +require('views/main/dashboard/widgets/supervisor_live'); require('views/main/service'); http://git-wip-us.apache.org/repos/asf/ambari/blob/386330fd/ambari-web/app/views/main/dashboard.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/dashboard.js b/ambari-web/app/views/main/dashboard.js index 61853cb..c5a78b8 100644 --- a/ambari-web/app/views/main/dashboard.js +++ b/ambari-web/app/views/main/dashboard.js @@ -82,9 +82,13 @@ App.MainDashboardView = Em.View.extend({ case "HBASE": self.set('hbase_model', App.HBaseService.find(item.get('id')) || item); break; + case "STORM": + self.set('storm_model', item); + break; } }, this); }, + setInitPrefObject: function() { //in case of some service not installed var visibleFull = [ @@ -93,7 +97,8 @@ App.MainDashboardView = Em.View.extend({ '18', '1', '6', '5', '9', '3', '7', '15', '16', '20', '19', '21', '23', - '24', '25', '26', '27'// all yarn + '24', '25', '26', '27',// all yarn + '28' // storm ]; // all in order var hiddenFull = [['22','Region In Transition']]; if (this.get('hdfs_model') == null) { @@ -114,12 +119,19 @@ App.MainDashboardView = Em.View.extend({ visibleFull = visibleFull.without(item); }, this); hiddenFull = []; - }if (this.get('yarn_model') == null) { + } + if (this.get('yarn_model') == null) { var yarn = ['24', '25', '26', '27']; yarn.forEach ( function (item) { visibleFull = visibleFull.without(item); }, this); } + if (this.get('storm_model') == null) { + var storm = ['28']; + storm.forEach(function(item) { + visibleFull = visibleFull.without(item); + }, this); + } var obj = this.get('initPrefObject'); obj.set('visible', visibleFull); obj.set('hidden', hiddenFull); @@ -130,6 +142,7 @@ App.MainDashboardView = Em.View.extend({ mapreduce2_model: null, yarn_model: null, hbase_model: null, + storm_model: null, visibleWidgets: [], hiddenWidgets: [], // widget child view will push object in this array if deleted @@ -313,6 +326,18 @@ App.MainDashboardView = Em.View.extend({ toAdd = toAdd.concat(yarn); } } + if (this.get('storm_model') != null) { + var storm = ['28']; + var flag = self.containsWidget(toDelete, storm[0]); + var self = this; + if (flag) { + storm.forEach ( function (item) { + toDelete = self.removeWidget(toDelete, item); + }, this); + } else { + toAdd = toAdd.concat(storm); + } + } var value = currentPrefObject; if (toDelete.visible.length || toDelete.hidden.length) { toDelete.visible.forEach ( function (item) { @@ -362,6 +387,7 @@ App.MainDashboardView = Em.View.extend({ case '25': return App.ResourceManagerUptimeView; case '26': return App.NodeManagersLiveView; case '27': return App.YARNMemoryPieChartView; + case '28': return App.SuperVisorUpView; } }, @@ -372,7 +398,7 @@ App.MainDashboardView = Em.View.extend({ hidden: [], threshold: {1: [80, 90], 2: [85, 95], 3: [90, 95], 4: [80, 90], 5: [1000, 3000], 6: [70, 90], 7: [90, 95], 8: [50, 75], 9: [30000, 120000], 10: [], 11: [], 12: [], 13: [], 14: [], 15: [], 16: [], 17: [], 18: [], 19: [], 20: [70, 90], 21: [10, 19.2], 22: [3, 10], 23: [], - 24: [70, 90], 25: [], 26: [50, 75], 27: [50, 75]} // id:[thresh1, thresh2] + 24: [70, 90], 25: [], 26: [50, 75], 27: [50, 75], 28: [85, 95]} // id:[thresh1, thresh2] }), persistKey: function () { var loginName = App.router.get('loginName'); @@ -413,7 +439,6 @@ App.MainDashboardView = Em.View.extend({ * post persist key/value to server, value is object */ postUserPref: function (key, value) { - var url = App.apiPrefix + '/persist/'; var keyValuePair = {}; keyValuePair[key] = JSON.stringify(value); @@ -453,6 +478,7 @@ App.MainDashboardView = Em.View.extend({ } this.translateToReal(oldValue); }, + switchToNew: function () { if(!App.testMode){ this.getUserPref(this.get('persistKey')); @@ -486,6 +512,7 @@ App.MainDashboardView = Em.View.extend({ } }, this); }.observes('App.router.updateController.isUpdate'), + services: function () { var services = App.Service.find(); if (this.get('content').length > 0) { http://git-wip-us.apache.org/repos/asf/ambari/blob/386330fd/ambari-web/app/views/main/dashboard/widget.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/dashboard/widget.js b/ambari-web/app/views/main/dashboard/widget.js index 07751a7..8c55598 100644 --- a/ambari-web/app/views/main/dashboard/widget.js +++ b/ambari-web/app/views/main/dashboard/widget.js @@ -23,16 +23,15 @@ App.DashboardWidgetView = Em.View.extend({ title: null, templateName: null, // each has specific template + /** + * Setup model for widget by `model_type`. Usually `model_type` is a lowercase service name, + * for example `hdfs`, `yarn`, etc. You need to set `model_type` in extended object View, for example + * look App.DataNodeUpView. + * @return {Object} - model that set up in App.MainDashboardView.setWidgetsDataModel() + */ model : function () { - if (this.get('model_type') == 'hdfs') { - return this.get('parentView').get('hdfs_model'); - } else if (this.get('model_type') == 'mapreduce') { - return this.get('parentView').get('mapreduce_model'); - } else if (this.get('model_type') == 'hbase') { - return this.get('parentView').get('hbase_model'); - } else if (this.get('model_type') == 'yarn') { - return this.get('parentView').get('yarn_model'); - } + if (!this.get('model_type')) return {}; + return this.get('parentView').get(this.get('model_type') + '_model'); }.property(), //data bind from parent view id: null, // id 1-10 used to identify @@ -49,8 +48,8 @@ App.DashboardWidgetView = Em.View.extend({ hiddenInfo: null, // more info details hiddenInfoClass: "hidden-info-two-line", - thresh1: null, //num not string - thresh2: null, + thresh1: null, //@type {Number} + thresh2: null, //@type {Number} didInsertElement: function () { App.tooltip(this.$("[rel='ZoomInTooltip']"), {placement : 'left'}); http://git-wip-us.apache.org/repos/asf/ambari/blob/386330fd/ambari-web/app/views/main/dashboard/widgets/supervisor_live.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/dashboard/widgets/supervisor_live.js b/ambari-web/app/views/main/dashboard/widgets/supervisor_live.js new file mode 100644 index 0000000..597cb7f --- /dev/null +++ b/ambari-web/app/views/main/dashboard/widgets/supervisor_live.js @@ -0,0 +1,177 @@ +/** + * 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. + */ + +var App = require('app'); + +App.SuperVisorUpView = App.TextDashboardWidgetView.extend({ + + title: Em.I18n.t('dashboard.widgets.SuperVisorUp'), + id: '28', + + isPieChart: false, + isText: true, + isProgressBar: false, + model_type: 'storm', + + hiddenInfo: function () { + var result = []; + result.pushObject(this.get('superVisorsLive').length + ' ' + Em.I18n.t('dashboard.services.hdfs.nodes.live')); + result.pushObject(this.get('superVisorsDead').length + ' ' + Em.I18n.t('dashboard.services.hdfs.nodes.dead')); + return result; + }.property('superVisorsLive', 'superVisorsDead'), + hiddenInfoClass: "hidden-info-two-line", + + thresh1: 40, + thresh2: 70, + maxValue: 100, + + superVisorComponents: function() { + return this.get('model.hostComponents').filterProperty('componentName', 'SUPERVISOR'); + }.property('model.hostComponents.length'), + + superVisorsLive: function () { + return this.get('superVisorComponents').filterProperty("workStatus", "STARTED"); + }.property('[email protected]'), + + superVisorsDead: function () { + return this.get('superVisorComponents').filterProperty("workStatus", "INSTALLED"); + }.property('[email protected]'), + + + data: function () { + if ( !this.get('superVisorComponents.length')) { + return -1; + } else { + return ((this.get('superVisorsLive').length / this.get('model.hostComponents').filterProperty('componentName', 'SUPERVISOR').length).toFixed(2)) * 100; + } + }.property('model.hostComponents.length', 'superVisorsLive'), + + content: function () { + return this.get('superVisorsLive').length + "/" + this.get('superVisorComponents').length; + }.property('superVisorComponents.length', 'superVisorsLive'), + + editWidget: function (event) { + var parent = this; + var max_tmp = parseFloat(parent.get('maxValue')); + var configObj = Ember.Object.create({ + thresh1: parent.get('thresh1') + '', + thresh2: parent.get('thresh2') + '', + hintInfo: Em.I18n.t('dashboard.widgets.hintInfo.hint1').format(max_tmp), + isThresh1Error: false, + isThresh2Error: false, + errorMessage1: "", + errorMessage2: "", + maxValue: max_tmp, + observeNewThresholdValue: function () { + var thresh1 = this.get('thresh1'); + var thresh2 = this.get('thresh2'); + if (thresh1.trim() != "") { + if (isNaN(thresh1) || thresh1 > max_tmp || thresh1 < 0){ + this.set('isThresh1Error', true); + this.set('errorMessage1', 'Invalid! Enter a number between 0 - ' + max_tmp); + } else if ( this.get('isThresh2Error') === false && parseFloat(thresh2)<= parseFloat(thresh1)) { + this.set('isThresh1Error', true); + this.set('errorMessage1', 'Threshold 1 should be smaller than threshold 2 !'); + } else { + this.set('isThresh1Error', false); + this.set('errorMessage1', ''); + } + } else { + this.set('isThresh1Error', true); + this.set('errorMessage1', 'This is required'); + } + + if (thresh2.trim() != "") { + if (isNaN(thresh2) || thresh2 > max_tmp || thresh2 < 0) { + this.set('isThresh2Error', true); + this.set('errorMessage2', 'Invalid! Enter a number between 0 - ' + max_tmp); + } else { + this.set('isThresh2Error', false); + this.set('errorMessage2', ''); + } + } else { + this.set('isThresh2Error', true); + this.set('errorMessage2', 'This is required'); + } + + // update the slider handles and color + if (this.get('isThresh1Error') === false && this.get('isThresh2Error') === false) { + $("#slider-range").slider('values', 0 , parseFloat(thresh1)); + $("#slider-range").slider('values', 1 , parseFloat(thresh2)); + } + }.observes('thresh1', 'thresh2') + + }); + + var browserVerion = this.getInternetExplorerVersion(); + App.ModalPopup.show({ + header: Em.I18n.t('dashboard.widgets.popupHeader'), + classNames: [ 'sixty-percent-width-modal-edit-widget'], + bodyClass: Ember.View.extend({ + templateName: require('templates/main/dashboard/edit_widget_popup'), + configPropertyObj: configObj + }), + primary: Em.I18n.t('common.apply'), + onPrimary: function () { + configObj.observeNewThresholdValue(); + if (!configObj.isThresh1Error && !configObj.isThresh2Error) { + parent.set('thresh1', parseFloat(configObj.get('thresh1')) ); + parent.set('thresh2', parseFloat(configObj.get('thresh2')) ); + if (!App.testMode) { + var big_parent = parent.get('parentView'); + big_parent.getUserPref(big_parent.get('persistKey')); + var oldValue = big_parent.get('currentPrefObject'); + oldValue.threshold[parseInt(parent.id)] = [configObj.get('thresh1'), configObj.get('thresh2')]; + big_parent.postUserPref(big_parent.get('persistKey'),oldValue); + } + this.hide(); + } + }, + + didInsertElement: function () { + var handlers = [configObj.get('thresh1'), configObj.get('thresh2')]; + var colors = ['#B80000', '#FF8E00', '#95A800']; //color red, orange, green + + if (browserVerion == -1 || browserVerion > 9) { + configObj.set('isIE9', false); + configObj.set('isGreenOrangeRed', false); + $("#slider-range").slider({ + range: true, + min: 0, + max: max_tmp, + values: handlers, + create: function (event, ui) { + parent.updateColors(handlers, colors); + }, + slide: function (event, ui) { + parent.updateColors(ui.values, colors); + configObj.set('thresh1', ui.values[0] + ''); + configObj.set('thresh2', ui.values[1] + ''); + }, + change: function (event, ui) { + parent.updateColors(ui.values, colors); + } + }); + } else { + configObj.set('isIE9', true); + configObj.set('isGreenOrangeRed', false); + } + } + }); + } +});
