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}} &nbsp;</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.

Reply via email to