This is an automated email from the ASF dual-hosted git repository. ababiichuk pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push: new c635b09 AMBARI-23111 Additional fixes for service summary page to support NameNode Federation. (ababiichuk) c635b09 is described below commit c635b09e8ce153b3d50f1c929575b2f0910ed7ca Author: ababiichuk <ababiic...@hortonworks.com> AuthorDate: Wed Feb 28 20:30:24 2018 +0200 AMBARI-23111 Additional fixes for service summary page to support NameNode Federation. (ababiichuk) --- .../app/controllers/global/update_controller.js | 4 +- .../main/host/bulk_operations_controller.js | 6 +- ambari-web/app/controllers/main/host/details.js | 4 +- ambari-web/app/controllers/main/service/item.js | 149 ++++++++++++++------- ambari-web/app/mappers/hosts_mapper.js | 3 +- ambari-web/app/mappers/service_metrics_mapper.js | 112 ++++++++++------ ambari-web/app/messages.js | 12 +- ambari-web/app/models/host_component.js | 3 +- ambari-web/app/models/service/hdfs.js | 11 +- ambari-web/app/styles/alerts.less | 26 +--- ambari-web/app/styles/application.less | 7 +- ambari-web/app/styles/common.less | 10 ++ .../app/styles/enhanced_service_dashboard.less | 20 +-- ambari-web/app/styles/hosts.less | 4 +- ambari-web/app/styles/stack_versions.less | 4 +- ambari-web/app/styles/visualsearch.less | 4 +- ambari-web/app/styles/wizard.less | 15 +-- .../app/templates/main/service/info/summary.hbs | 15 +-- .../service/info/summary/master_components.hbs | 72 +++++----- ambari-web/app/templates/main/service/item.hbs | 8 +- ambari-web/app/utils/ajax/ajax.js | 2 +- ambari-web/app/views/common/chart/linear_time.js | 1 + .../app/views/common/quick_view_link_view.js | 32 +++-- .../app/views/main/dashboard/widgets/hdfs_links.js | 2 + .../views/main/dashboard/widgets/namenode_cpu.js | 1 + .../details/host_component_views/datanode_view.js | 1 + .../main/service/info/components_list_view.js | 16 +-- ambari-web/app/views/main/service/info/summary.js | 13 +- ambari-web/app/views/main/service/item.js | 3 + .../controllers/global/update_controller_test.js | 2 +- .../test/controllers/main/service/item_test.js | 20 +-- .../test/views/common/quick_link_view_test.js | 15 +-- 32 files changed, 333 insertions(+), 264 deletions(-) diff --git a/ambari-web/app/controllers/global/update_controller.js b/ambari-web/app/controllers/global/update_controller.js index 3ead4e8..22cadc9 100644 --- a/ambari-web/app/controllers/global/update_controller.js +++ b/ambari-web/app/controllers/global/update_controller.js @@ -67,7 +67,8 @@ App.UpdateController = Em.Controller.extend({ "host_components/metrics/hbase/master/MasterActiveTime," + "host_components/metrics/hbase/master/AverageLoad," + "host_components/metrics/master/AssignmentManger/ritCount", - 'STORM': 'metrics/api/v1/cluster/summary,metrics/api/v1/topology/summary,metrics/api/v1/nimbus/summary' + 'STORM': 'metrics/api/v1/cluster/summary,metrics/api/v1/topology/summary,metrics/api/v1/nimbus/summary', + 'HDFS': 'host_components/metrics/dfs/namenode/ClusterId' }, /** @@ -224,6 +225,7 @@ App.UpdateController = Em.Controller.extend({ realUrl = '/hosts?fields=Hosts/rack_info,Hosts/host_name,Hosts/maintenance_state,Hosts/public_host_name,Hosts/cpu_count,Hosts/ph_cpu_count,Hosts/last_agent_env,' + 'alerts_summary,Hosts/host_status,Hosts/host_state,Hosts/last_heartbeat_time,Hosts/ip,host_components/HostRoles/state,host_components/HostRoles/maintenance_state,' + 'host_components/HostRoles/stale_configs,host_components/HostRoles/service_name,host_components/HostRoles/display_name,host_components/HostRoles/desired_admin_state,' + + (App.Service.find().someProperty('serviceName', 'HDFS') ? 'host_components/metrics/dfs/namenode/ClusterId,host_components/metrics/dfs/FSNamesystem/HAState,' : '') + '<metrics>Hosts/total_mem<hostDetailsParams><stackVersions>&minimal_response=true', hostDetailsParams = ',Hosts/os_arch,Hosts/os_type,metrics/cpu/cpu_system,metrics/cpu/cpu_user,metrics/memory/mem_total,metrics/memory/mem_free', stackVersionInfo = ',stack_versions/HostStackVersions,' + diff --git a/ambari-web/app/controllers/main/host/bulk_operations_controller.js b/ambari-web/app/controllers/main/host/bulk_operations_controller.js index bb0cffd..90a089b 100644 --- a/ambari-web/app/controllers/main/host/bulk_operations_controller.js +++ b/ambari-web/app/controllers/main/host/bulk_operations_controller.js @@ -163,7 +163,7 @@ App.BulkOperationsController = Em.Controller.extend({ if (nn_hosts.length == 1) { return App.router.get('mainHostDetailsController').checkNnLastCheckpointTime(request, nn_hosts[0]); } - if (nn_hosts.length == 2) { + if (nn_hosts.length > 1) { // HA enabled return App.router.get('mainServiceItemController').checkNnLastCheckpointTime(request); } @@ -224,8 +224,8 @@ App.BulkOperationsController = Em.Controller.extend({ }, hostName); } else { - if (nn_count == 2 && isHDFSStarted) { - // HA enabled + if (nn_count > 1 && isHDFSStarted) { + // HA or federation enabled App.router.get('mainServiceItemController').checkNnLastCheckpointTime(function () { batchUtils.restartHostComponents(hostComponents, Em.I18n.t('rollingrestart.context.allOnSelectedHosts'), "HOST"); }); diff --git a/ambari-web/app/controllers/main/host/details.js b/ambari-web/app/controllers/main/host/details.js index ddf0a70..774d897 100644 --- a/ambari-web/app/controllers/main/host/details.js +++ b/ambari-web/app/controllers/main/host/details.js @@ -396,7 +396,9 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow self.getHdfsUser().done(function() { var msg = Em.Object.create({ confirmMsg: Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld').format(App.nnCheckpointAgeAlertThreshold) + - Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions').format(isNNCheckpointTooOld, self.get('hdfsUser')), + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.makeSure') + + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions.singleHost.login').format(isNNCheckpointTooOld) + + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions').format(self.get('hdfsUser')), confirmButton: Em.I18n.t('common.next') }); return App.showConfirmationFeedBackPopup(callback, msg); diff --git a/ambari-web/app/controllers/main/service/item.js b/ambari-web/app/controllers/main/service/item.js index a4a8ca1..d60b50a 100644 --- a/ambari-web/app/controllers/main/service/item.js +++ b/ambari-web/app/controllers/main/service/item.js @@ -88,6 +88,10 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow isRecommendationInProgress: false, + nameNodesWithOldCheckpoints: [], + + isNameNodeCheckpointUnavailable: false, + isClientsOnlyService: function() { return App.get('services.clientOnly').contains(this.get('content.serviceName')); }.property('content.serviceName'), @@ -352,7 +356,7 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow this.checkNnLastCheckpointTime(() => App.showConfirmationFeedBackPopup((query, runMmOperation) => { this.set('isPending', true); this.startStopWithMmode(serviceHealth, query, runMmOperation, components, hosts, label); - }, bodyMessage)); + }, bodyMessage), label); } else { return App.showConfirmationFeedBackPopup((query, runMmOperation) => { this.set('isPending', true); @@ -365,23 +369,46 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow /** * this function will be called from :1) stop HDFS 2) restart all for HDFS 3) restart all affected for HDFS * @param callback - callback function to continue next operation + * @param [groupName] - id of HA namespace for enabled NameNode federation */ - checkNnLastCheckpointTime: function(callback) { - var self = this; - this.pullNnCheckPointTime().complete(function () { - var isNNCheckpointTooOld = self.get('isNNCheckpointTooOld'); - self.set('isNNCheckpointTooOld', null); - if (isNNCheckpointTooOld) { + checkNnLastCheckpointTime: function (callback, groupName) { + this.pullNnCheckPointTime(groupName).complete(() => { + const nameNodesWithOldCheckpoints = this.get('nameNodesWithOldCheckpoints').slice(), + isNameNodeCheckpointUnavailable = this.get('isNameNodeCheckpointUnavailable'); + this.get('nameNodesWithOldCheckpoints').clear(); + this.set('isNameNodeCheckpointUnavailable', false); + if (nameNodesWithOldCheckpoints.length) { // too old - self.getHdfsUser().done(function() { - var msg = Em.Object.create({ - confirmMsg: Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld').format(App.nnCheckpointAgeAlertThreshold) + - Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions').format(isNNCheckpointTooOld, self.get('hdfsUser')), - confirmButton: Em.I18n.t('common.next') - }); + this.getHdfsUser().done(() => { + const maxAge = App.nnCheckpointAgeAlertThreshold, + hdfsUser = this.get('hdfsUser'), + confirmButton =Em.I18n.t('common.next'); + let msg; + if (App.get('hasNameNodeFederation') && !groupName) { + const oldCheckpointNameSpacesList = nameNodesWithOldCheckpoints.map(nn => `<li>${nn.haNameSpace}</li>`), + nameSpacesString = `<ul>${oldCheckpointNameSpacesList.join('')}</ul>`, + hostNamesList = nameNodesWithOldCheckpoints.map(nn => `<b>${nn.hostName}</b>`).join(', '); + msg = Em.Object.create({ + confirmMsg: Em.I18n.t('services.service.stop.HDFS.warningMsg.nameSpaces.checkPointTooOld').format(maxAge) + + nameSpacesString + + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.makeSure') + + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions.multipleHosts.login').format(hostNamesList) + + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions').format(hdfsUser), + confirmButton + }) + } else { + const hostName = nameNodesWithOldCheckpoints[0].hostName; + msg = Em.Object.create({ + confirmMsg: Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld').format(maxAge) + + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.makeSure') + + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions.singleHost.login').format(hostName) + + Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions').format(hdfsUser), + confirmButton + }) + } return App.showConfirmationFeedBackPopup(callback, msg); }); - } else if (isNNCheckpointTooOld == null) { + } else if (isNameNodeCheckpointUnavailable) { // not available return App.showConfirmationPopup( callback, Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointNA'), null, @@ -394,56 +421,80 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow }); }, - pullNnCheckPointTime: function () { + pullNnCheckPointTime: function (haNameSpace) { return App.ajax.send({ name: 'common.service.hdfs.getNnCheckPointTime', sender: this, + data: { + haNameSpace + }, success: 'parseNnCheckPointTime' }); }, - parseNnCheckPointTime: function (data) { - var nameNodesStatus = []; - var lastCheckpointTime, hostName; - if (data.host_components.length <= 1) { - lastCheckpointTime = Em.get(data.host_components[0], 'metrics.dfs.FSNamesystem.LastCheckpointTime'); - hostName = Em.get(data.host_components[0], 'HostRoles.host_name'); + parseNnCheckPointTime: function (data, opt, params) { + let nameNodesStatus = {}, + nameNodesWithCheckpoints = [], + hostComponents = params.haNameSpace ? + data.host_components.filterProperty('metrics.dfs.namenode.ClusterId', params.haNameSpace) : data.host_components; + if (hostComponents.length <= 1) { + nameNodesWithCheckpoints.push({ + lastCheckpointTime: Em.get(hostComponents[0], 'metrics.dfs.FSNamesystem.LastCheckpointTime'), + hostName: Em.get(hostComponents[0], 'HostRoles.host_name') + }); } else { - // HA enabled - data.host_components.forEach(function(namenode) { - nameNodesStatus.pushObject( Em.Object.create({ + // HA or federation enabled + const hostComponents = data.host_components; + hostComponents.forEach(namenode => { + const haNameSpace = Em.get(namenode, 'metrics.dfs.namenode.ClusterId'), + existingArray = nameNodesStatus[haNameSpace], + currentArray = existingArray || []; + if (!existingArray) { + nameNodesStatus[haNameSpace] = currentArray; + } + currentArray.pushObject(Em.Object.create({ LastCheckpointTime: Em.get(namenode, 'metrics.dfs.FSNamesystem.LastCheckpointTime'), HAState: Em.get(namenode, 'metrics.dfs.FSNamesystem.HAState'), hostName: Em.get(namenode, 'HostRoles.host_name') })); }); - if (nameNodesStatus.someProperty('HAState', 'active')) { - if (nameNodesStatus.findProperty('HAState', 'active').get('LastCheckpointTime')) { - lastCheckpointTime = nameNodesStatus.findProperty('HAState', 'active').get('LastCheckpointTime'); - hostName = nameNodesStatus.findProperty('HAState', 'active').get('hostName'); - } else if (nameNodesStatus.someProperty('LastCheckpointTime')) { - lastCheckpointTime = nameNodesStatus.findProperty('LastCheckpointTime').get('LastCheckpointTime'); - hostName = nameNodesStatus.findProperty('LastCheckpointTime').get('hostName'); + Object.keys(nameNodesStatus).forEach(key => { + const nameSpace = nameNodesStatus[key], + activeNameNode = nameSpace.findProperty('HAState', 'active'), + standbyNameNode = nameSpace.findProperty('HAState', 'standby'); + if (activeNameNode) { + const lastActiveNameNodeCheckpointTime = activeNameNode.get('LastCheckpointTime'), + nameNodeWithCheckpoint = nameSpace.findProperty('LastCheckpointTime'); + if (lastActiveNameNodeCheckpointTime) { + nameNodesWithCheckpoints.push({ + lastCheckpointTime: lastActiveNameNodeCheckpointTime, + hostName: activeNameNode.get('hostName'), + haNameSpace: key + }); + } else if (nameNodeWithCheckpoint) { + nameNodesWithCheckpoints.push({ + lastCheckpointTime: nameNodeWithCheckpoint.get('LastCheckpointTime'), + hostName: nameNodeWithCheckpoint.get('hostName'), + haNameSpace: key + }); + } + } else if (standbyNameNode) { + nameNodesWithCheckpoints.push({ + lastCheckpointTime: standbyNameNode.get('LastCheckpointTime'), + hostName: standbyNameNode.get('hostName'), + haNameSpace: key + }); } - } else if (nameNodesStatus.someProperty('HAState', 'standby')) { - lastCheckpointTime = nameNodesStatus.findProperty('HAState', 'standby').get('LastCheckpointTime'); - hostName = nameNodesStatus.findProperty('HAState', 'standby').get('hostName') - } + }); } + const timeCriteria = App.nnCheckpointAgeAlertThreshold, // time in hours to define how many hours ago is too old + timeAgo = (Math.round(App.dateTime() / 1000) - (timeCriteria * 3600)) * 1000, + nameNodesWithOldCheckpoints = nameNodesWithCheckpoints.filter(nameNode => nameNode.lastCheckpointTime <= timeAgo); - if (!lastCheckpointTime) { - this.set("isNNCheckpointTooOld", null); - } else { - var time_criteria = App.nnCheckpointAgeAlertThreshold; // time in hours to define how many hours ago is too old - var time_ago = (Math.round(App.dateTime() / 1000) - (time_criteria * 3600)) *1000; - if (lastCheckpointTime <= time_ago) { - // too old, set the effected hostName - this.set("isNNCheckpointTooOld", hostName); - } else { - // still young - this.set("isNNCheckpointTooOld", false); - } - } + this.setProperties({ + nameNodesWithOldCheckpoints, + isNameNodeCheckpointUnavailable: !nameNodesWithCheckpoints.length + }); }, /** @@ -947,7 +998,7 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow return App.showConfirmationFeedBackPopup(function (query, runMmOperation) { batchUtils.restartCertainServiceHostComponents(serviceName, components, hosts, label, query, runMmOperation); }, bodyMessage); - }); + }, label); } else { App.showConfirmationFeedBackPopup(function (query, runMmOperation) { batchUtils.restartCertainServiceHostComponents(serviceName, components, hosts, label, query, runMmOperation); diff --git a/ambari-web/app/mappers/hosts_mapper.js b/ambari-web/app/mappers/hosts_mapper.js index d3864b4..7f05561 100644 --- a/ambari-web/app/mappers/hosts_mapper.js +++ b/ambari-web/app/mappers/hosts_mapper.js @@ -67,7 +67,8 @@ App.hostsMapper = App.QuickDataMapper.create({ stale_configs: 'HostRoles.stale_configs', host_name: 'host_name', public_host_name: 'public_host_name', - admin_state: 'HostRoles.desired_admin_state' + admin_state: 'HostRoles.desired_admin_state', + ha_name_space: 'metrics.dfs.namenode.ClusterId' }, stackVersionConfig: { id: 'HostStackVersions.id', diff --git a/ambari-web/app/mappers/service_metrics_mapper.js b/ambari-web/app/mappers/service_metrics_mapper.js index 661e064..4d319fc 100644 --- a/ambari-web/app/mappers/service_metrics_mapper.js +++ b/ambari-web/app/mappers/service_metrics_mapper.js @@ -44,6 +44,8 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({ active_name_node_id: 'active_name_node_id', standby_name_node_id: 'standby_name_node_id', standby_name_node2_id: 'standby_name_node2_id', + active_name_nodes: 'active_name_nodes', + standby_name_nodes: 'standby_name_nodes', journal_nodes: 'journal_nodes', name_node_id: 'name_node_id', sname_node_id: 'sname_node_id', @@ -164,9 +166,8 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({ stale_configs: 'HostRoles.stale_configs', ha_status: 'HostRoles.ha_state', display_name_advanced: 'display_name_advanced', - admin_state: 'HostRoles.desired_admin_state' - // TODO add mapping for namespace property - // ha_name_space: + admin_state: 'HostRoles.desired_admin_state', + ha_name_space: 'metrics.dfs.namenode.ClusterId' }, /** @@ -349,7 +350,7 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({ hostComponents.forEach(function (hostComponent) { var service = services.findProperty('ServiceInfo.service_name', hostComponent.service_id); if (hostComponent) { - // set advanced nameNode display name for HA, Active NameNode or Standby NameNode + // set advanced nameNode display name for HA and Federation, Active NameNodes or Standby NameNodes // this is useful on three places: 1) HDFS health status hover tooltip, 2) HDFS service summary 3) NameNode component on host detail page if (hostComponent.component_name === 'NAMENODE' && !isSecondaryNamenode) { var hdfs = this.hdfsMapper(service); @@ -358,9 +359,9 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({ var standbyNNText = Em.I18n.t('services.service.summary.nameNode.standby'); if (hdfs) { // active_name_node_id format : NAMENODE_c6401.ambari.apache.org - if (hdfs.active_name_node_id && hdfs.active_name_node_id.contains(hostName)) { + if (hdfs.active_name_nodes && hdfs.active_name_nodes.contains(`NAMENODE_${hostName}`)) { hostComponent.display_name_advanced = activeNNText; - } else if ((hdfs.standby_name_node_id && hdfs.standby_name_node_id.contains(hostName)) || ( hdfs.standby_name_node2_id && hdfs.standby_name_node2_id.contains(hostName))) { + } else if (hdfs.standby_name_nodes && hdfs.standby_name_nodes.contains(`NAMENODE_${hostName}`)) { hostComponent.display_name_advanced = standbyNNText; } else { hostComponent.display_name_advanced = null; @@ -418,20 +419,55 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({ }, hdfsMapper: function (item) { - var finalConfig = jQuery.extend({}, this.config); + let finalConfig = jQuery.extend({}, this.config); // Change the JSON so that it is easy to map - var hdfsConfig = this.hdfsConfig; - var self = this; - item.components.forEach(function (component) { + const hdfsConfig = this.hdfsConfig; + item.components.forEach(component => { + const hostComponents = component.host_components, + firstHostComponent = hostComponents[0]; if (this.isHostComponentPresent(component, 'NAMENODE')) { //enabled HA - if (component.host_components.length == 2) { - var haState1 = Em.get(component.host_components[0], 'metrics.dfs.FSNamesystem.HAState'); - var haState2 = Em.get(component.host_components[1], 'metrics.dfs.FSNamesystem.HAState'); - var active_name_node = []; - var standby_name_nodes = []; - var namenodeName1 = component.host_components[0].HostRoles.host_name; - var namenodeName2 = component.host_components[1].HostRoles.host_name; + if (hostComponents.length > 1) { + let nameSpacesWithActiveNameNodes = [], + unknownNameNodes = []; + item.active_name_nodes = []; + item.standby_name_nodes = []; + hostComponents.forEach(hc => { + const haState = Em.get(hc, 'metrics.dfs.FSNamesystem.HAState'), + hostName = Em.get(hc, 'HostRoles.host_name'), + haNameSpace = Em.get(hc, 'metrics.dfs.namenode.ClusterId'), + id = `NAMENODE_${hostName}`; + switch (haState) { + case 'active': + nameSpacesWithActiveNameNodes.push(haNameSpace); + item.active_name_nodes.push(id); + break; + case 'standby': + item.standby_name_nodes.push(id); + break; + default: + unknownNameNodes.push({ + hostName, + haNameSpace + }); + break; + } + }); + unknownNameNodes.forEach(nameNode => { + if (nameSpacesWithActiveNameNodes.contains(nameNode.haNameSpace)) { + item.standby_name_nodes.push(`NAMENODE_${nameNode.hostName}`); + } + }); + } + + // TODO remove after implementing widgets changes + if (hostComponents.length === 2) { + const haState1 = Em.get(firstHostComponent, 'metrics.dfs.FSNamesystem.HAState'), + haState2 = Em.get(hostComponents[1], 'metrics.dfs.FSNamesystem.HAState'), + namenodeName1 = firstHostComponent.HostRoles.host_name, + namenodeName2 = hostComponents[1].HostRoles.host_name; + let active_name_node = [], + standby_name_nodes = []; switch (haState1) { case "active": @@ -454,31 +490,32 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({ item.standby_name_node2_id = null; switch (active_name_node.length) { case 1: - item.active_name_node_id = 'NAMENODE' + '_' + active_name_node[0]; + item.active_name_node_id = `NAMENODE_${active_name_node[0]}`; break; } switch (standby_name_nodes.length) { case 0: if (active_name_node.length === 1) { - var standbyNameNode = (active_name_node[0] === namenodeName1) ? namenodeName2 : namenodeName1; - item.standby_name_node_id = 'NAMENODE' + '_' + standbyNameNode; + const standbyNameNode = (active_name_node[0] === namenodeName1) ? namenodeName2 : namenodeName1; + item.standby_name_node_id = `NAMENODE_${standbyNameNode}`; } break; case 1: - item.standby_name_node_id = 'NAMENODE' + '_' + standby_name_nodes[0]; + item.standby_name_node_id = `NAMENODE_${standby_name_nodes[0]}`; break; case 2: - item.standby_name_node_id = 'NAMENODE' + '_' + standby_name_nodes[0]; - item.standby_name_node2_id = 'NAMENODE' + '_' + standby_name_nodes[1]; + item.standby_name_node_id = `NAMENODE_${standby_name_nodes[0]}`; + item.standby_name_node2_id = `NAMENODE_${standby_name_nodes[1]}`; break; } var activeHostComponentIndex = haState2 == "active" ? 1 : 0; - self.setActiveAsFirstHostComponent(component, activeHostComponentIndex); + this.setActiveAsFirstHostComponent(component, activeHostComponentIndex); } + item.nameNodeComponent = component; finalConfig = jQuery.extend(finalConfig, hdfsConfig); // Get the live, dead & decommission nodes from string json - if (component.host_components[0].metrics && component.host_components[0].metrics.dfs && component.host_components[0].metrics.dfs.namenode) { + if (firstHostComponent.metrics && firstHostComponent.metrics.dfs && firstHostComponent.metrics.dfs.namenode) { item.metrics_not_available = false; var decommissionNodesJson = App.parseJSON(component.host_components[0].metrics.dfs.namenode.DecomNodes); var deadNodesJson = App.parseJSON(component.host_components[0].metrics.dfs.namenode.DeadNodes); @@ -489,29 +526,26 @@ App.serviceMetricsMapper = App.QuickDataMapper.create({ item.decommission_data_nodes = []; item.dead_data_nodes = []; item.live_data_nodes = []; - for (var host in decommissionNodesJson) { - item.decommission_data_nodes.push('DATANODE' + '_' + host); + for (let host in decommissionNodesJson) { + item.decommission_data_nodes.push(`DATANODE_${host}`); } - for (var host in deadNodesJson) { - item.dead_data_nodes.push('DATANODE' + '_' + host); + for (let host in deadNodesJson) { + item.dead_data_nodes.push(`DATANODE_${host}`); } - for (var host in liveNodesJson) { - item.live_data_nodes.push('DATANODE' + '_' + host); + for (let host in liveNodesJson) { + item.live_data_nodes.push(`DATANODE_${host}`); } - item.name_node_id = "NAMENODE" + "_" + component.host_components[0].HostRoles.host_name; + item.name_node_id = `NAMENODE_${firstHostComponent.HostRoles.host_name}`; } if (this.isHostComponentPresent(component, "JOURNALNODE")) { - item.journal_nodes = []; - component.host_components.forEach(function (hc) { - item.journal_nodes.push("JOURNALNODE" + "_" + hc.HostRoles.host_name); - }); + item.journal_nodes = hostComponents.map(hc => `JOURNALNODE_${hc.HostRoles.host_name}`); } if (this.isHostComponentPresent(component, "SECONDARY_NAMENODE")) { - item.sname_node_id = "SECONDARY_NAMENODE" + "_" + component.host_components[0].HostRoles.host_name; + item.sname_node_id = `SECONDARY_NAMENODE_${firstHostComponent.HostRoles.host_name}`; } - }, this); + }); // Map - var finalJson = this.parseIt(item, finalConfig); + let finalJson = this.parseIt(item, finalConfig); finalJson.quick_links = [1, 2, 3, 4]; return finalJson; diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 1703d2d..17b5a7f 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -2340,15 +2340,17 @@ Em.I18n.translations = { 'services.service.restartCertain.warningMsg.turnOnMM': 'This will trigger alerts as components are restarted. To suppress alerts, turn on Maintenance Mode for {0} prior to running restart all', 'services.service.componentsInNameSpace': 'components in {0} namespace', 'services.service.stop.HDFS.warningMsg.checkPointNA': 'Could not determine the age of the last HDFS checkpoint. Please ensure that you have a recent checkpoint. Otherwise, the NameNode(s) can take a very long time to start up.', + 'services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions.singleHost.login': '<br><ol><li>Login to the NameNode host <b>{0}</b>.</li>', + 'services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions.multipleHosts.login': '<ol><li>Login to the NameNode hosts {0}.</li>', 'services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions': - '<br><ol>' + - '<li>Login to the NameNode host <b>{0}</b>.</li>' + '<li>Put the NameNode in Safe Mode (read-only mode):' + - '<div class="code-snippet">sudo su {1} -l -c \'hdfs dfsadmin -safemode enter\'</div></li>' + + '<div class="code-snippet">sudo su {0} -l -c \'hdfs dfsadmin -safemode enter\'</div></li>' + '<li>Once in Safe Mode, create a Checkpoint:' + - '<div class="code-snippet">sudo su {1} -l -c \'hdfs dfsadmin -saveNamespace\'</div></li>' + + '<div class="code-snippet">sudo su {0} -l -c \'hdfs dfsadmin -saveNamespace\'</div></li>' + '</ol>', - 'services.service.stop.HDFS.warningMsg.checkPointTooOld': 'The last HDFS checkpoint is older than {0} hours. Make sure that you have taken a checkpoint before proceeding. Otherwise, the NameNode(s) can take a very long time to start up.', + 'services.service.stop.HDFS.warningMsg.checkPointTooOld': 'The last HDFS checkpoint is older than {0} hours. ', + 'services.service.stop.HDFS.warningMsg.checkPointTooOld.makeSure': 'Make sure that you have taken a checkpoint before proceeding. Otherwise, the NameNode(s) can take a very long time to start up.', + 'services.service.stop.HDFS.warningMsg.nameSpaces.checkPointTooOld': 'The last HDFS checkpoint is older than {0} hours for the following namespaces:', 'services.service.config_groups_popup.header':'Manage {0} Configuration Groups', 'services.service.config_groups_popup.notice':'You can apply different sets of {{serviceName}} configurations to groups of hosts by managing {{serviceName}} Configuration Groups and their host membership. Hosts belonging to a {{serviceName}} Configuration Group have the same set of configurations for {{serviceName}}. Each host belongs to one {{serviceName}} Configuration Group.', 'services.service.config_groups_popup.rename':'Rename', diff --git a/ambari-web/app/models/host_component.js b/ambari-web/app/models/host_component.js index 7b60a27..42fcae1 100644 --- a/ambari-web/app/models/host_component.js +++ b/ambari-web/app/models/host_component.js @@ -572,7 +572,8 @@ App.HostComponentActionMap = { components: components || group.components, serviceName }, - disabled: false + disabled: false, + tooltip: group.title }; }); return [allItem, ...groupItems]; diff --git a/ambari-web/app/models/service/hdfs.js b/ambari-web/app/models/service/hdfs.js index fa279f9..08e160b 100644 --- a/ambari-web/app/models/service/hdfs.js +++ b/ambari-web/app/models/service/hdfs.js @@ -21,9 +21,18 @@ App.HDFSService = App.Service.extend({ version: DS.attr('string'), nameNode: DS.belongsTo('App.HostComponent'), snameNode: DS.belongsTo('App.HostComponent'), + + // TODO remove after implementing widgets changes activeNameNode: DS.belongsTo('App.HostComponent'), standbyNameNode: DS.belongsTo('App.HostComponent'), standbyNameNode2: DS.belongsTo('App.HostComponent'), + + activeNameNodes: DS.hasMany('App.HostComponent', { + defaultValue: [] + }), + standbyNameNodes: DS.hasMany('App.HostComponent', { + defaultValue: [] + }), isNnHaEnabled: function() { return !this.get('snameNode') && this.get('hostComponents').filterProperty('componentName', 'NAMENODE').length > 1; }.property('snameNode','hostComponents'), @@ -75,7 +84,7 @@ App.HDFSService = App.Service.extend({ } }); return result; - }.property('hostComponents') + }.property('hostComponents.length') }); App.HDFSService.FIXTURES = []; diff --git a/ambari-web/app/styles/alerts.less b/ambari-web/app/styles/alerts.less index a1d3468..efaf25d 100644 --- a/ambari-web/app/styles/alerts.less +++ b/ambari-web/app/styles/alerts.less @@ -196,10 +196,8 @@ } .alert-text { - overflow: hidden; + .ellipsis-overflow-nowrap; float: left; - text-overflow: ellipsis; - white-space: nowrap; width: 100%; } @@ -310,10 +308,8 @@ } .alert-text { - overflow: hidden; + .ellipsis-overflow-nowrap; float: left; - text-overflow: ellipsis; - white-space: nowrap; width: 100%; } } @@ -514,19 +510,15 @@ } .instance-text { + .ellipsis-overflow-nowrap; font-size: 0.8em; width: 95%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } .definition-latest-text { + .ellipsis-overflow-nowrap; font-size: 0.8em; width: 95%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } .alerts-popup-wrap { @@ -537,9 +529,8 @@ padding: 10px 5px; } .trim_hostname { + .ellipsis-overflow; display: block; - overflow: hidden; - text-overflow: ellipsis; } } } @@ -652,14 +643,11 @@ font-size: 14px; font-weight: bold; margin-bottom: 5px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + .ellipsis-overflow-nowrap; } .description-text { font-size: 12px; - overflow: hidden; - text-overflow: ellipsis; + .ellipsis-overflow; } } } diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index 7d7c268..27083a0 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -868,6 +868,9 @@ a:focus { display: inline-block; } } + .master-group-title { + .ellipsis-overflow-nowrap; + } } .faintText { @@ -1573,9 +1576,7 @@ ul.inline li { } .rack-id { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + .ellipsis-overflow-nowrap; } .advanced-header-table { diff --git a/ambari-web/app/styles/common.less b/ambari-web/app/styles/common.less index 8dfdf69..810aefb 100644 --- a/ambari-web/app/styles/common.less +++ b/ambari-web/app/styles/common.less @@ -230,3 +230,13 @@ color: white; } } + +.ellipsis-overflow { + overflow: hidden; + text-overflow: ellipsis; +} + +.ellipsis-overflow-nowrap { + .ellipsis-overflow; + white-space: nowrap; +} diff --git a/ambari-web/app/styles/enhanced_service_dashboard.less b/ambari-web/app/styles/enhanced_service_dashboard.less index bb59a8b..a930788 100644 --- a/ambari-web/app/styles/enhanced_service_dashboard.less +++ b/ambari-web/app/styles/enhanced_service_dashboard.less @@ -101,14 +101,13 @@ margin: 55px auto; } .title { + .ellipsis-overflow; padding: 4px 0 0 8px; font-size: 14px; color: #666666; line-height: 17px; text-align: left; height: 40px; - overflow: hidden; - text-overflow: ellipsis; -webkit-line-clamp: 2; -webkit-box-orient: vertical; display: block; @@ -123,11 +122,10 @@ .template-widget { .frame; .content { + .ellipsis-overflow; padding-top: 21px; height: 75px; line-height: 36px; - overflow: hidden; - text-overflow: ellipsis; -webkit-line-clamp: 2; -webkit-box-orient: vertical; display: block; @@ -137,11 +135,10 @@ .number-widget { .frame; .content { + .ellipsis-overflow; padding-top: 30px; height: 50px; box-sizing: content-box; - overflow: hidden; - text-overflow: ellipsis; } } .graph-widget { @@ -368,16 +365,13 @@ } .label-description { .label-text { + .ellipsis-overflow-nowrap; font-weight: bold; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } .description-text { + .ellipsis-overflow; font-size: 12px; color: #808080; - overflow: hidden; - text-overflow: ellipsis; } } } @@ -620,11 +614,9 @@ } .label-description { .label-text { + .ellipsis-overflow-nowrap; display: inline-block; font-weight: bold; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } .is-shared-icon { display: inline-block; diff --git a/ambari-web/app/styles/hosts.less b/ambari-web/app/styles/hosts.less index 0909a3d..6cfa33c 100644 --- a/ambari-web/app/styles/hosts.less +++ b/ambari-web/app/styles/hosts.less @@ -188,12 +188,10 @@ white-space: nowrap; } td.name .trim_hostname{ + .ellipsis-overflow-nowrap; display: block; float: left; width: 86%!important; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } td.health label { padding-top: 3px; diff --git a/ambari-web/app/styles/stack_versions.less b/ambari-web/app/styles/stack_versions.less index f47e3fc..2311acd 100644 --- a/ambari-web/app/styles/stack_versions.less +++ b/ambari-web/app/styles/stack_versions.less @@ -814,10 +814,8 @@ width: 14%; } .widest-column{ + .ellipsis-overflow-nowrap; width: 20%; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; } .accordion-group { border-right: none; diff --git a/ambari-web/app/styles/visualsearch.less b/ambari-web/app/styles/visualsearch.less index f07d319..16c3377 100644 --- a/ambari-web/app/styles/visualsearch.less +++ b/ambari-web/app/styles/visualsearch.less @@ -57,9 +57,7 @@ width: auto !important; margin-top: 15px; .ui-menu-item a { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + .ellipsis-overflow-nowrap; background: none; border: none; padding: 3px 10px 5px 5px; diff --git a/ambari-web/app/styles/wizard.less b/ambari-web/app/styles/wizard.less index 4d4eeaf..ba22fad 100644 --- a/ambari-web/app/styles/wizard.less +++ b/ambari-web/app/styles/wizard.less @@ -200,12 +200,10 @@ max-width: 290px; } td.host .trim_hostname { + .ellipsis-overflow-nowrap; max-width: 97% !important; display: block; - overflow: hidden; - text-overflow: ellipsis; float:left; - white-space: nowrap; } #display-action { visibility:visible; @@ -254,12 +252,10 @@ white-space: nowrap; } .trim_hostname { + .ellipsis-overflow-nowrap; max-width: 180px; float:left; - white-space: nowrap; display: block; - overflow: hidden; - text-overflow: ellipsis; } .checkbox { margin: 0; @@ -375,12 +371,10 @@ max-width: 290px; } td.host .trim_hostname { + .ellipsis-overflow-nowrap; max-width: 97% !important; display: block; - overflow: hidden; - text-overflow: ellipsis; float:left; - white-space: nowrap; } .progress-wrapper { width: 73%; @@ -505,11 +499,10 @@ text-align: left; padding: 10px; .selected-item { + .ellipsis-overflow; width: 95%; margin-right: 5px; float: left; - overflow: hidden; - text-overflow: ellipsis; } } } diff --git a/ambari-web/app/templates/main/service/info/summary.hbs b/ambari-web/app/templates/main/service/info/summary.hbs index 5f6219a..4b33bb8 100644 --- a/ambari-web/app/templates/main/service/info/summary.hbs +++ b/ambari-web/app/templates/main/service/info/summary.hbs @@ -46,16 +46,6 @@ {{/isAuthorized}} {{/if}} -{{#if view.hasMultipleMasterGroups}} - <ul class="nav nav-tabs"> - {{#each group in view.mastersObj}} - <li {{bindAttr class="group.isActive:active"}}> - <a href="#" {{action setActiveComponentGroup group.name target="view"}}>{{group.title}}</a> - </li> - {{/each}} - </ul> -{{/if}} - <div class="service-block"> <div class="summary-links-block"> <div class="panel panel-default summary-block"> @@ -101,7 +91,10 @@ <!--there are multiple masters eg, HBase multiple masters or HDFS HA enabled--> {{#each group in view.quickLinksArray}} {{#if group.title}} - <h5>{{group.title}}</h5> + <h5 class="ellipsis-overflow-nowrap" + {{bindAttr data-title="group.title" rel="view.tooltipAttribute"}}> + {{group.title}} + </h5> {{/if}} {{#each quickLinks in group.links}} <a href="javascript:void(null)">{{quickLinks.publicHostNameLabel}} </a> diff --git a/ambari-web/app/templates/main/service/info/summary/master_components.hbs b/ambari-web/app/templates/main/service/info/summary/master_components.hbs index 9d2f2fd..6ca36c1 100644 --- a/ambari-web/app/templates/main/service/info/summary/master_components.hbs +++ b/ambari-web/app/templates/main/service/info/summary/master_components.hbs @@ -16,45 +16,45 @@ * limitations under the License. }} -{{#if view.activeMastersComp.length}} - {{#each group in view.activeMastersComp}} - {{#if group.components.length}} - <div class="col-md-12"> - <div class="col-md-2"> - {{#if group.title}} +{{#each group in view.mastersComp}} + {{#if group.components.length}} + <div class="col-md-12"> + <div class="col-md-2"> + {{#if group.title}} + <div class="master-group-title" rel="MasterGroupTitleTooltip" {{bindAttr data-title="group.title"}}> {{group.title}} - {{else}} - {{t dashboard.services.hdfs.summary.components}} - {{/if}} - </div> - <div class="col-md-10"> - {{#each comp in group.components}} - <div {{bindAttr class="comp.isSubComponent:component-small :component :col-md-3 comp.componentName :row"}}> - <div {{bindAttr class=":summary-value comp.summaryValueClassName"}}> + </div> + {{else}} + {{t dashboard.services.hdfs.summary.components}} + {{/if}} + </div> + <div class="col-md-10"> + {{#each comp in group.components}} + <div {{bindAttr class="comp.isSubComponent:component-small :component :col-md-3 comp.componentName :row"}}> + <div {{bindAttr class=":summary-value comp.summaryValueClassName"}}> <span rel='SummaryComponentHealthTooltip' {{bindAttr class="comp.statusClass comp.statusIconClass" data-original-title="comp.passiveTooltip"}}></span> - <span class="main-info">{{comp.componentTextStatus}}</span> - {{#if comp.alertsCount}} - <span {{action "showServiceAlertsPopup" comp target="controller"}} - {{bindAttr class=":label comp.hasCriticalAlerts:alerts-crit-count:alerts-warn-count"}}> - {{comp.alertsCount}} - </span> + <span class="main-info">{{comp.componentTextStatus}}</span> + {{#if comp.alertsCount}} + <span {{action "showServiceAlertsPopup" comp target="controller"}} + {{bindAttr class=":label comp.hasCriticalAlerts:alerts-crit-count:alerts-warn-count"}}> + {{comp.alertsCount}} + </span> + {{/if}} + </div> + <div {{bindAttr class=":summary-label comp.summaryLabelClassName"}}> + <a href="#" {{action showDetails comp.host}} data-original-title="{{unbound comp.publicHostName}}" + rel="UsageTooltip"> + {{#if comp.displayNameAdvanced}} + {{comp.displayNameAdvanced}} + {{else}} + {{comp.displayName}} {{/if}} - </div> - <div {{bindAttr class=":summary-label comp.summaryLabelClassName"}}> - <a href="#" {{action showDetails comp.host}} data-original-title="{{unbound comp.publicHostName}}" - rel="UsageTooltip"> - {{#if comp.displayNameAdvanced}} - {{comp.displayNameAdvanced}} - {{else}} - {{comp.displayName}} - {{/if}} - </a> - </div> + </a> </div> - {{/each}} - </div> + </div> + {{/each}} </div> - {{/if}} - {{/each}} -{{/if}} + </div> + {{/if}} +{{/each}} diff --git a/ambari-web/app/templates/main/service/item.hbs b/ambari-web/app/templates/main/service/item.hbs index ad616e8..a7d9e8d 100644 --- a/ambari-web/app/templates/main/service/item.hbs +++ b/ambari-web/app/templates/main/service/item.hbs @@ -37,7 +37,8 @@ {{#each option in view.maintenance}} {{#unless option.isHidden}} <li {{bindAttr class="option.disabled option.hasSubmenu:dropdown-submenu option.hasSubmenu:submenu-left"}}> - <a {{action "doAction" option target="controller" href=true}} {{bindAttr data-title="option.tooltip"}} rel="HealthTooltip"> + <a {{action "doAction" option target="controller" href=true}} + {{bindAttr data-title="option.tooltip" rel="view.tooltipAttribute"}}> <i {{bindAttr class="option.cssClass"}}></i> {{option.label}} </a> @@ -46,7 +47,10 @@ <ul class="dropdown-menu"> {{#each item in option.submenuOptions}} <li> - <a {{action "doAction" item target="controller" href=true}}>{{item.context.label}}</a> + <a class="ellipsis-overflow" {{action "doAction" item target="controller" href=true}} + {{bindAttr data-title="item.tooltip" rel="view.tooltipAttribute"}}> + {{item.context.label}} + </a> </li> {{/each}} </ul> diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js index a14b8eb..6c73a84 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -93,7 +93,7 @@ var urls = { }, 'common.service.hdfs.getNnCheckPointTime': { - 'real': '/clusters/{clusterName}/services/HDFS/components/NAMENODE?fields=host_components/metrics/dfs/FSNamesystem/HAState,host_components/metrics/dfs/FSNamesystem/LastCheckpointTime', + 'real': '/clusters/{clusterName}/services/HDFS/components/NAMENODE?fields=host_components/metrics/dfs/FSNamesystem/HAState,host_components/metrics/dfs/FSNamesystem/LastCheckpointTime,host_components/metrics/dfs/namenode/ClusterId', 'mock': '' }, diff --git a/ambari-web/app/views/common/chart/linear_time.js b/ambari-web/app/views/common/chart/linear_time.js index d2a7ae1..691fda4 100644 --- a/ambari-web/app/views/common/chart/linear_time.js +++ b/ambari-web/app/views/common/chart/linear_time.js @@ -367,6 +367,7 @@ App.ChartLinearTimeView = Ember.View.extend(App.ExportMetricsMixin, { YARNService = App.YARNService.find().objectAt(0), resourceManager = YARNService ? YARNService.get('resourceManager.hostName') : ""; if (HDFSService) { + // TODO rewrite considering federation case and using activeNameNodes array nameNodeName = (HDFSService.get('activeNameNode')) ? HDFSService.get('activeNameNode.hostName') : HDFSService.get('nameNode.hostName'); } if (this.get('currentTimeIndex') === 8 && !Em.isNone(this.get('customStartTime')) && !Em.isNone(this.get('customEndTime'))) { diff --git a/ambari-web/app/views/common/quick_view_link_view.js b/ambari-web/app/views/common/quick_view_link_view.js index 0a2f3cf..2e4b61a 100644 --- a/ambari-web/app/views/common/quick_view_link_view.js +++ b/ambari-web/app/views/common/quick_view_link_view.js @@ -81,6 +81,8 @@ App.QuickLinksView = Em.View.extend({ masterGroups: [], + tooltipAttribute: 'quick-links-title-tooltip', + /** * @type {object} */ @@ -618,20 +620,18 @@ App.QuickLinksView = Em.View.extend({ * @method hostForQuickLink */ processHdfsHosts: function (hosts) { - return hosts.map(function (host) { - if (host.hostName === Em.get(this, 'content.activeNameNode.hostName')) { + return hosts.map(host => { + const {hostName} = host, + isActiveNameNode = Em.get(this, 'content.activeNameNodes').someProperty('hostName', hostName), + isStandbyNameNode = Em.get(this, 'content.standbyNameNodes').someProperty('hostName', hostName); + if (isActiveNameNode) { host.status = Em.I18n.t('quick.links.label.active'); } - else - if (host.hostName === Em.get(this, 'content.standbyNameNode.hostName')) { - host.status = Em.I18n.t('quick.links.label.standby'); - } - else - if (host.hostName === Em.get(this, 'content.standbyNameNode2.hostName')) { - host.status = Em.I18n.t('quick.links.label.standby'); - } + if (isStandbyNameNode) { + host.status = Em.I18n.t('quick.links.label.standby'); + } return host; - }, this); + }); }, /** @@ -889,5 +889,13 @@ App.QuickLinksView = Em.View.extend({ } else { return propertyValue; } - } + }, + + setTooltip: function () { + Em.run.next(() => { + if (this.get('showQuickLinks') && this.get('isLoaded') && this.get('quickLinksArray.length')) { + App.tooltip($(`[rel="${this.get('tooltipAttribute')}"]`)); + } + }); + }.observes('showQuickLinks', 'isLoaded', 'quickLinksArray.length') }); diff --git a/ambari-web/app/views/main/dashboard/widgets/hdfs_links.js b/ambari-web/app/views/main/dashboard/widgets/hdfs_links.js index 900a900..e4af3cd 100644 --- a/ambari-web/app/views/main/dashboard/widgets/hdfs_links.js +++ b/ambari-web/app/views/main/dashboard/widgets/hdfs_links.js @@ -35,6 +35,8 @@ App.HDFSLinksView = App.LinkDashboardWidgetView.extend({ isHAEnabled: Em.computed.not('model.snameNode'), + // TODO rewrite considering federation case and using activeNameNodes and standbyNameNodes arrays + isActiveNNValid: Em.computed.bool('model.activeNameNode'), isStandbyNNValid: Em.computed.bool('model.standbyNameNode'), diff --git a/ambari-web/app/views/main/dashboard/widgets/namenode_cpu.js b/ambari-web/app/views/main/dashboard/widgets/namenode_cpu.js index d6a3ebd..2916cd3 100644 --- a/ambari-web/app/views/main/dashboard/widgets/namenode_cpu.js +++ b/ambari-web/app/views/main/dashboard/widgets/namenode_cpu.js @@ -35,6 +35,7 @@ App.NameNodeCpuPieChartView = App.PieChartDashboardWidgetView.extend({ intervalId; App.router.get('mainController').isLoading.call(App.router.get('clusterController'), 'isServiceContentFullyLoaded').done(function () { if (App.get('isHaEnabled')) { + // TODO rewrite considering federation case and using activeNameNodes array self.set('nnHostName', self.get('model.activeNameNode.hostName')); } else { self.set('nnHostName', self.get('model.nameNode.hostName')); diff --git a/ambari-web/app/views/main/host/details/host_component_views/datanode_view.js b/ambari-web/app/views/main/host/details/host_component_views/datanode_view.js index f7178cc..f0fe97f 100644 --- a/ambari-web/app/views/main/host/details/host_component_views/datanode_view.js +++ b/ambari-web/app/views/main/host/details/host_component_views/datanode_view.js @@ -29,6 +29,7 @@ App.DataNodeComponentView = App.HostComponentView.extend(App.Decommissionable, { getDNDecommissionStatus: function () { // always get datanode decommission status from active namenode (if NN HA enabled) var hdfs = App.HDFSService.find().objectAt(0); + // TODO rewrite considering federation case and using activeNameNodes array var activeNNHostName = (!hdfs.get('snameNode') && hdfs.get('activeNameNode')) ? hdfs.get('activeNameNode.hostName') : hdfs.get('nameNode.hostName'); return App.ajax.send({ name: 'host.host_component.decommission_status_datanode', diff --git a/ambari-web/app/views/main/service/info/components_list_view.js b/ambari-web/app/views/main/service/info/components_list_view.js index d14e8e4..524be23 100644 --- a/ambari-web/app/views/main/service/info/components_list_view.js +++ b/ambari-web/app/views/main/service/info/components_list_view.js @@ -27,19 +27,13 @@ App.SummaryMasterComponentsView = Em.View.extend({ } ], - activeMastersComp: function () { - const mastersComp = this.get('mastersComp'), - activeGroup = mastersComp.findProperty('isActive'); - return activeGroup ? [activeGroup] : mastersComp; - }.property('mastersComp.length', 'mastersComp.@each.isActive', 'mastersComp.@each.components.length'), - mastersCompWillChange: function() { - Em.run.next(() => this.removeTooltips()); - }.observesBefore('mastersComp.length', 'mastersComp.@each.components.length'), + Em.run.next(this.removeTooltips); + }.observesBefore('mastersComp.length', 'mastersComp.@each.components'), mastersCompDidChange: function() { - Em.run.next(() => this.attachTooltip()); - }.observes('mastersComp.length', 'mastersComp.@each.components.length'), + Em.run.next(this.attachTooltip); + }.observes('mastersComp.length', 'mastersComp.@each.components'), removeTooltips: function() { $('.tooltip').remove(); @@ -60,7 +54,7 @@ App.SummaryMasterComponentsView = Em.View.extend({ }); App.SummaryMasterComponentsView.reopenClass({ - tooltipsSelector: '[rel=SummaryComponentHealthTooltip], [rel=UsageTooltip]' + tooltipsSelector: '[rel=SummaryComponentHealthTooltip], [rel=UsageTooltip], [rel=MasterGroupTitleTooltip]' }); App.SummaryClientComponentsView = Em.View.extend({ diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js index e35ca40..193f96d 100644 --- a/ambari-web/app/views/main/service/info/summary.js +++ b/ambari-web/app/views/main/service/info/summary.js @@ -29,7 +29,7 @@ App.MainServiceInfoSummaryView = Em.View.extend({ /** * Contain array with list of groups of master components from <code>App.Service.hostComponets</code> which are * <code>App.HostComponent</code> models. - * @type {{title: String, isActive: Boolean, hosts: String[], components: App.HostComponent[]}[]} + * @type {{title: String, hosts: String[], components: App.HostComponent[]}[]} */ mastersObj: [ { @@ -423,11 +423,6 @@ App.MainServiceInfoSummaryView = Em.View.extend({ hasMultipleMasterGroups: Em.computed.gt('mastersObj.length', 1), - activeMasterComponentGroup: function () { - const activeGroup = this.get('mastersObj').findProperty('isActive'); - return activeGroup ? activeGroup.title : ''; - }.property('mastersObj.@each.isActive'), - getGroupedMasterComponents: function (components) { switch (this.get('serviceName')) { case 'HDFS': @@ -447,7 +442,6 @@ App.MainServiceInfoSummaryView = Em.View.extend({ if (!existingGroup) { groups.push(currentGroup); Em.setProperties(currentGroup, { - isActive: name === this.get('activeMasterComponentGroup'), components: [] }); } @@ -479,10 +473,5 @@ App.MainServiceInfoSummaryView = Em.View.extend({ } ]; } - }, - - setActiveComponentGroup: function (event) { - const groupName = event.context; - this.get('mastersObj').forEach(group => Em.set(group, 'isActive', group.name === groupName)); } }); diff --git a/ambari-web/app/views/main/service/item.js b/ambari-web/app/views/main/service/item.js index 9240af8..1d4e5a6 100644 --- a/ambari-web/app/views/main/service/item.js +++ b/ambari-web/app/views/main/service/item.js @@ -110,6 +110,8 @@ App.MainServiceItemView = Em.View.extend({ isMaintenanceSet: false, + tooltipAttribute: 'service-actions-tooltip', + observeMaintenance: function() { if (!this.get('isMaintenanceSet') && this.get('controller.isServicesInfoLoaded') && this.get('controller.isServiceConfigsLoaded')) { this.observeMaintenanceOnce(); @@ -329,6 +331,7 @@ App.MainServiceItemView = Em.View.extend({ this.set('maintenance', options); } this.set('isMaintenanceSet', true); + App.tooltip($(`[rel="${this.get('tooltipAttribute')}"]`)); }, clearIsMaintenanceSet: function () { diff --git a/ambari-web/test/controllers/global/update_controller_test.js b/ambari-web/test/controllers/global/update_controller_test.js index a812353..6165af9 100644 --- a/ambari-web/test/controllers/global/update_controller_test.js +++ b/ambari-web/test/controllers/global/update_controller_test.js @@ -108,7 +108,7 @@ describe('App.UpdateController', function () { } } ], - result: ['metrics/1'] + result: ['metrics/1', 'host_components/metrics/dfs/namenode/ClusterId'] }, { title: 'FLUME service', diff --git a/ambari-web/test/controllers/main/service/item_test.js b/ambari-web/test/controllers/main/service/item_test.js index 2ac35a2..250b03a 100644 --- a/ambari-web/test/controllers/main/service/item_test.js +++ b/ambari-web/test/controllers/main/service/item_test.js @@ -619,7 +619,7 @@ describe('App.MainServiceItemController', function () { } ] }, - result: false + result: 0 }, { m: "NameNode has JMX data, the last checkpoint time is > 12 hours ago", @@ -649,7 +649,7 @@ describe('App.MainServiceItemController', function () { } ] }, - result: "c6401.ambari.apache.org" + result: 1 }, { m: "NameNode has no JMX data available", @@ -678,7 +678,7 @@ describe('App.MainServiceItemController', function () { } ] }, - result: null + result: 0 }, { m: "HA enabled, both active and standby NN has JMX data normally.", @@ -724,7 +724,7 @@ describe('App.MainServiceItemController', function () { } ] }, - result: false + result: 0 }, { m: "HA enabled, both NamoNodes are standby NN", @@ -770,7 +770,7 @@ describe('App.MainServiceItemController', function () { } ] }, - result: false + result: 0 }, { m: "HA enabled, active NN has no JMX data, use the standby's data", @@ -815,10 +815,10 @@ describe('App.MainServiceItemController', function () { } ] }, - result: false + result: 0 }, { - m: "HA enabled, both NamoNodes no JMX data", + m: "HA enabled, both NameNodes no JMX data", data: {"href" : "", "ServiceComponentInfo" : { @@ -859,7 +859,7 @@ describe('App.MainServiceItemController', function () { } ] }, - result: null + result: 0 } ]; @@ -874,8 +874,8 @@ describe('App.MainServiceItemController', function () { tests.forEach(function (test) { it(test.m, function () { var mainServiceItemController = App.MainServiceItemController.create({isNNCheckpointTooOld: null}); - mainServiceItemController.parseNnCheckPointTime(test.data); - expect(mainServiceItemController.get('isNNCheckpointTooOld')).to.equal(test.result); + mainServiceItemController.parseNnCheckPointTime(test.data, null, {}); + expect(mainServiceItemController.get('nameNodesWithOldCheckpoints.length')).to.equal(test.result); }); }); }); diff --git a/ambari-web/test/views/common/quick_link_view_test.js b/ambari-web/test/views/common/quick_link_view_test.js index 3100b17..8f280b6 100644 --- a/ambari-web/test/views/common/quick_link_view_test.js +++ b/ambari-web/test/views/common/quick_link_view_test.js @@ -376,24 +376,17 @@ describe('App.QuickViewLinks', function () { describe("#processHdfsHosts()", function () { beforeEach(function () { - quickViewLinks.set('content.activeNameNode', null); - quickViewLinks.set('content.standbyNameNode', null); - quickViewLinks.set('content.standbyNameNode2', null); + quickViewLinks.set('content.activeNameNodes', []); + quickViewLinks.set('content.standbyNameNodes', []); }); it("active namenode host", function () { - quickViewLinks.set('content.activeNameNode', Em.Object.create({hostName: 'host1'})); + quickViewLinks.get('content.activeNameNodes').pushObject(Em.Object.create({hostName: 'host1'})); var host = {hostName: 'host1'}; quickViewLinks.processHdfsHosts([host]); expect(host.status).to.equal(Em.I18n.t('quick.links.label.active')); }); it("standby namenode host", function () { - quickViewLinks.set('content.standbyNameNode', Em.Object.create({hostName: 'host1'})); - var host = {hostName: 'host1'}; - quickViewLinks.processHdfsHosts([host]); - expect(host.status).to.equal(Em.I18n.t('quick.links.label.standby')); - }); - it("second standby namenode host", function () { - quickViewLinks.set('content.standbyNameNode2', Em.Object.create({hostName: 'host1'})); + quickViewLinks.get('content.standbyNameNodes').pushObject(Em.Object.create({hostName: 'host1'})); var host = {hostName: 'host1'}; quickViewLinks.processHdfsHosts([host]); expect(host.status).to.equal(Em.I18n.t('quick.links.label.standby')); -- To stop receiving notification emails like this one, please contact ababiic...@apache.org.