ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From yus...@apache.org
Subject ambari git commit: AMBARI-12951. Prompt user to save checkpoint before shutdown if last checkpoint is too old. (xiwang via yusaku)
Date Tue, 01 Sep 2015 22:53:35 GMT
Repository: ambari
Updated Branches:
  refs/heads/branch-2.1 7a4ca7eb9 -> 2acaf832d


AMBARI-12951. Prompt user to save checkpoint before shutdown if last checkpoint is too old.
(xiwang via yusaku)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/2acaf832
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/2acaf832
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/2acaf832

Branch: refs/heads/branch-2.1
Commit: 2acaf832dcbb156277bdb043c9f4d611f5d5e79e
Parents: 7a4ca7e
Author: Yusaku Sako <yusaku@hortonworks.com>
Authored: Tue Sep 1 15:52:26 2015 -0700
Committer: Yusaku Sako <yusaku@hortonworks.com>
Committed: Tue Sep 1 15:53:21 2015 -0700

----------------------------------------------------------------------
 ambari-web/app/controllers/main/host.js         |  87 ++++++++++---
 ambari-web/app/controllers/main/host/details.js | 130 +++++++++++++++++--
 ambari-web/app/controllers/main/service.js      |  14 +-
 .../controllers/main/service/info/configs.js    |  27 +++-
 ambari-web/app/controllers/main/service/item.js | 119 ++++++++++++++++-
 ambari-web/app/messages.js                      |  10 ++
 ambari-web/app/utils/ajax/ajax.js               |  10 ++
 .../app/views/main/service/info/summary.js      |  27 +++-
 .../test/controllers/main/service/item_test.js  |  20 ++-
 9 files changed, 395 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/app/controllers/main/host.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host.js b/ambari-web/app/controllers/main/host.js
index 8bf9065..4a0a418 100644
--- a/ambari-web/app/controllers/main/host.js
+++ b/ambari-web/app/controllers/main/host.js
@@ -606,33 +606,76 @@ App.MainHostController = Em.ArrayController.extend(App.TableServerMixin,
{
       });
     });
 
+    var nn_hosts = [];
     for (var hostName in hostsMap) {
       var subQuery = '(HostRoles/component_name.in(%@)&HostRoles/host_name=' + hostName
+ ')';
       var components = hostsMap[hostName];
 
       if (components.length) {
+        if (components.indexOf('NAMENODE') >= 0) {
+          nn_hosts.push(hostName);
+        }
         query.push(subQuery.fmt(components.join(',')));
       }
       hostNames.push(hostName);
     }
     hostNames = hostNames.join(",");
-
     if (query.length) {
       query = query.join('|');
-      App.ajax.send({
-        name: 'common.host_components.update',
-        sender: this,
-        data: {
-          query: query,
-          HostRoles: {
-            state: operationData.action
+      var self = this;
+      // if NameNode included, check HDFS NameNode checkpoint before stop NN
+      if (nn_hosts.length == 1 && operationData.action === 'INSTALLED' &&
App.Service.find().filterProperty('serviceName', 'HDFS').someProperty('workStatus', App.HostComponentStatus.started))
{
+        var hostName = nn_hosts[0];
+        App.router.get('mainHostDetailsController').checkNnLastCheckpointTime(function ()
{
+          App.ajax.send({
+            name: 'common.host_components.update',
+            sender: self,
+            data: {
+              query: query,
+              HostRoles: {
+                state: operationData.action
+              },
+              context: operationData.message,
+              hostName: hostNames,
+              noOpsMessage: Em.I18n.t('hosts.host.maintainance.allComponents.context')
+            },
+            success: 'bulkOperationForHostComponentsSuccessCallback'
+          });
+        }, hostName);
+      } else if (nn_hosts.length == 2 && operationData.action === 'INSTALLED' &&
App.Service.find().filterProperty('serviceName', 'HDFS').someProperty('workStatus', App.HostComponentStatus.started))
{
+        // HA enabled
+        App.router.get('mainServiceItemController').checkNnLastCheckpointTime(function ()
{
+          App.ajax.send({
+            name: 'common.host_components.update',
+            sender: self,
+            data: {
+              query: query,
+              HostRoles: {
+                state: operationData.action
+              },
+              context: operationData.message,
+              hostName: hostNames,
+              noOpsMessage: Em.I18n.t('hosts.host.maintainance.allComponents.context')
+            },
+            success: 'bulkOperationForHostComponentsSuccessCallback'
+          });
+        });
+      } else {
+        App.ajax.send({
+          name: 'common.host_components.update',
+          sender: self,
+          data: {
+            query: query,
+            HostRoles: {
+              state: operationData.action
+            },
+            context: operationData.message,
+            hostName: hostNames,
+            noOpsMessage: Em.I18n.t('hosts.host.maintainance.allComponents.context')
           },
-          context: operationData.message,
-          hostName: hostNames,
-          noOpsMessage: Em.I18n.t('hosts.host.maintainance.allComponents.context')
-        },
-        success: 'bulkOperationForHostComponentsSuccessCallback'
-      });
+          success: 'bulkOperationForHostComponentsSuccessCallback'
+        });
+      }
     }
     else {
       App.ModalPopup.show({
@@ -667,7 +710,21 @@ App.MainHostController = Em.ArrayController.extend(App.TableServerMixin,
{
           }));
         })
       });
-      batchUtils.restartHostComponents(hostComponents, Em.I18n.t('rollingrestart.context.allOnSelectedHosts'),
"HOST");
+      // if NameNode included, check HDFS NameNode checkpoint before restart NN
+      var nn_count = hostComponents.filterProperty('componentName', 'NAMENODE').get('length');
+      if (nn_count == 1 && App.Service.find().filterProperty('serviceName', 'HDFS').someProperty('workStatus',
App.HostComponentStatus.started)) {
+        var hostName = hostComponents.findProperty('componentName', 'NAMENODE').get('hostName');
+        App.router.get('mainHostDetailsController').checkNnLastCheckpointTime(function ()
{
+          batchUtils.restartHostComponents(hostComponents, Em.I18n.t('rollingrestart.context.allOnSelectedHosts'),
"HOST");
+        }, hostName);
+      } else if (nn_count == 2 && App.Service.find().filterProperty('serviceName',
'HDFS').someProperty('workStatus', App.HostComponentStatus.started)) {
+        // HA enabled
+        App.router.get('mainServiceItemController').checkNnLastCheckpointTime(function ()
{
+          batchUtils.restartHostComponents(hostComponents, Em.I18n.t('rollingrestart.context.allOnSelectedHosts'),
"HOST");
+        });
+      } else {
+        batchUtils.restartHostComponents(hostComponents, Em.I18n.t('rollingrestart.context.allOnSelectedHosts'),
"HOST");
+      }
     });
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/app/controllers/main/host/details.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host/details.js b/ambari-web/app/controllers/main/host/details.js
index 6947456..f3e1489 100644
--- a/ambari-web/app/controllers/main/host/details.js
+++ b/ambari-web/app/controllers/main/host/details.js
@@ -112,11 +112,21 @@ App.MainHostDetailsController = Em.Controller.extend({
    */
   stopComponent: function (event) {
     var self = this;
-    return App.showConfirmationPopup(function () {
-      var component = event.context;
-      var context = Em.I18n.t('requestInfo.stopHostComponent') + " " + component.get('displayName');
-      self.sendComponentCommand(component, context, App.HostComponentStatus.stopped);
-    });
+    if (event.context.get('componentName') == 'NAMENODE' ) {
+      this.checkNnLastCheckpointTime(function () {
+        return App.showConfirmationPopup(function () {
+          var component = event.context;
+          var context = Em.I18n.t('requestInfo.stopHostComponent') + " " + component.get('displayName');
+          self.sendComponentCommand(component, context, App.HostComponentStatus.stopped);
+        });
+      });
+    } else {
+      return App.showConfirmationPopup(function () {
+        var component = event.context;
+        var context = Em.I18n.t('requestInfo.stopHostComponent') + " " + component.get('displayName');
+        self.sendComponentCommand(component, context, App.HostComponentStatus.stopped);
+      });
+    }
   },
   /**
    * PUTs a command to server to start/stop a component. If no
@@ -179,6 +189,72 @@ App.MainHostDetailsController = Em.Controller.extend({
   ajaxErrorCallback: function (request, ajaxOptions, error, opt, params) {
     return componentsUtils.ajaxErrorCallback(request, ajaxOptions, error, opt, params);
   },
+
+  /**
+   * this function will be called from :1) stop NN 2) restart NN 3) stop all components
+   * @param callback - callback function to continue next operation
+   * @param hostname - namenode host (by default is current host)
+   */
+  checkNnLastCheckpointTime: function(callback, hostName) {
+    var self = this;
+    this.pullNnCheckPointTime(hostName).complete(function () {
+      var isNNCheckpointTooOld = self.get('isNNCheckpointTooOld');
+      self.set('isNNCheckpointTooOld', null);
+      if (isNNCheckpointTooOld) {
+        // too old
+        var msg = Em.Object.create({
+          confirmMsg: Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld')
+
+            Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions').format(isNNCheckpointTooOld),
+          confirmButton: Em.I18n.t('common.next')
+        });
+        return App.showConfirmationFeedBackPopup(callback, msg);
+      } else if (isNNCheckpointTooOld == null) {
+        // not available
+        return App.showConfirmationPopup(
+          callback, Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointNA'), null,
+          Em.I18n.t('common.warning'), Em.I18n.t('common.proceedAnyway'), true
+        );
+      } else {
+        // still young
+        callback();
+      }
+    });
+  },
+
+  pullNnCheckPointTime: function (hostName) {
+    return App.ajax.send({
+      name: 'common.host_component.getNnCheckPointTime',
+      sender: this,
+      data: {
+        host: hostName || this.get('content.hostName')
+      },
+      success: 'parseNnCheckPointTime'
+    });
+  },
+
+  parseNnCheckPointTime: function (data) {
+    var lastCheckpointTime = Em.get(data, 'metrics.dfs.FSNamesystem.LastCheckpointTime');
+    var hostName = Em.get(data, 'HostRoles.host_name');
+
+    if (Em.get(data, 'metrics.dfs.FSNamesystem.HAState') == 'active') {
+      if (!lastCheckpointTime) {
+        this.set("isNNCheckpointTooOld", null);
+      } else {
+        var time_criteria = 12; // 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);
+        }
+      }
+    } else if (Em.get(data, 'metrics.dfs.FSNamesystem.HAState') == 'standby') {
+      this.set("isNNCheckpointTooOld", false);
+    }
+  },
+
   /**
    * mimic status transition in test mode
    * @param entity
@@ -448,9 +524,17 @@ App.MainHostDetailsController = Em.Controller.extend({
    */
   restartComponent: function (event) {
     var component = event.context;
-    return App.showConfirmationPopup(function () {
-      batchUtils.restartHostComponents([component], Em.I18n.t('rollingrestart.context.selectedComponentOnSelectedHost').format(component.get('displayName')),
"HOST_COMPONENT");
-    });
+    if (event.context.get('componentName') == 'NAMENODE') {
+      this.checkNnLastCheckpointTime(function () {
+        return App.showConfirmationPopup(function () {
+          batchUtils.restartHostComponents([component], Em.I18n.t('rollingrestart.context.selectedComponentOnSelectedHost').format(component.get('displayName')),
"HOST_COMPONENT");
+        });
+      });
+    } else {
+      return App.showConfirmationPopup(function () {
+        batchUtils.restartHostComponents([component], Em.I18n.t('rollingrestart.context.selectedComponentOnSelectedHost').format(component.get('displayName')),
"HOST_COMPONENT");
+      });
+    }
   },
   /**
    * get current status of security settings,
@@ -1849,9 +1933,18 @@ App.MainHostDetailsController = Em.Controller.extend({
     var components = this.get('serviceNonClientActiveComponents');
     var componentsLength = Em.isNone(components) ? 0 : components.get('length');
     if (componentsLength > 0) {
-      return App.showConfirmationPopup(function () {
-        self.sendComponentCommand(components, Em.I18n.t('hosts.host.maintainance.stopAllComponents.context'),
App.HostComponentStatus.stopped);
-      });
+      if (components.someProperty('componentName', 'NAMENODE') &&
+        this.get('content.hostComponents').filterProperty('componentName', 'NAMENODE').someProperty('workStatus',
App.HostComponentStatus.started)) {
+        this.checkNnLastCheckpointTime(function () {
+          return App.showConfirmationPopup(function () {
+            self.sendComponentCommand(components, Em.I18n.t('hosts.host.maintainance.stopAllComponents.context'),
App.HostComponentStatus.stopped);
+          });
+        });
+      } else {
+        return App.showConfirmationPopup(function () {
+          self.sendComponentCommand(components, Em.I18n.t('hosts.host.maintainance.stopAllComponents.context'),
App.HostComponentStatus.stopped);
+        });
+      }
     }
   },
 
@@ -1864,9 +1957,18 @@ App.MainHostDetailsController = Em.Controller.extend({
     var components = this.get('serviceActiveComponents');
     var componentsLength = Em.isNone(components) ? 0 : components.get('length');
     if (componentsLength > 0) {
-      return App.showConfirmationPopup(function () {
-        batchUtils.restartHostComponents(components, Em.I18n.t('rollingrestart.context.allOnSelectedHost').format(self.get('content.hostName')),
"HOST");
-      });
+      if (components.someProperty('componentName', 'NAMENODE') &&
+        this.get('content.hostComponents').filterProperty('componentName', 'NAMENODE').someProperty('workStatus',
App.HostComponentStatus.started)) {
+        this.checkNnLastCheckpointTime(function () {
+          return App.showConfirmationPopup(function () {
+            batchUtils.restartHostComponents(components, Em.I18n.t('rollingrestart.context.allOnSelectedHost').format(self.get('content.hostName')),
"HOST");
+          });
+        });
+      } else {
+        return App.showConfirmationPopup(function () {
+          batchUtils.restartHostComponents(components, Em.I18n.t('rollingrestart.context.allOnSelectedHost').format(self.get('content.hostName')),
"HOST");
+        });
+      }
     }
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/app/controllers/main/service.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service.js b/ambari-web/app/controllers/main/service.js
index d1346e4..c589286 100644
--- a/ambari-web/app/controllers/main/service.js
+++ b/ambari-web/app/controllers/main/service.js
@@ -122,9 +122,17 @@ App.MainServiceController = Em.ArrayController.extend({
       confirmButton: state == 'INSTALLED' ? Em.I18n.t('services.service.stop.confirmButton')
: Em.I18n.t('services.service.start.confirmButton')
     });
 
-    return App.showConfirmationFeedBackPopup(function (query) {
-      self.allServicesCall(state, query);
-    }, bodyMessage);
+    if (state == 'INSTALLED' && App.Service.find().filterProperty('serviceName',
'HDFS').someProperty('workStatus', App.HostComponentStatus.started)) {
+      App.router.get('mainServiceItemController').checkNnLastCheckpointTime(function () {
+        return App.showConfirmationFeedBackPopup(function (query) {
+          self.allServicesCall(state, query);
+        }, bodyMessage);
+      });
+    } else {
+      return App.showConfirmationFeedBackPopup(function (query) {
+        self.allServicesCall(state, query);
+      }, bodyMessage);
+    }
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/app/controllers/main/service/info/configs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js
index da2be95..b899252 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -713,10 +713,29 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader,
A
       confirmButton: Em.I18n.t('services.service.restartAll.confirmButton'),
       additionalWarningMsg: this.get('content.passiveState') === 'OFF' ? Em.I18n.t('services.service.restartAll.warningMsg.turnOnMM').format(serviceDisplayName)
: null
     });
-    return App.showConfirmationFeedBackPopup(function (query) {
-      var selectedService = self.get('content.id');
-      batchUtils.restartAllServiceHostComponents(selectedService, true, query);
-    }, bodyMessage);
+
+    var isNNAffected = false;
+    var restartRequiredHostsAndComponents = this.get('content.restartRequiredHostsAndComponents');
+    for (var hostName in restartRequiredHostsAndComponents) {
+      restartRequiredHostsAndComponents[hostName].forEach(function (hostComponent) {
+        if (hostComponent == 'NameNode')
+         isNNAffected = true;
+      })
+    }
+    if (this.get('content.serviceName') == 'HDFS' && isNNAffected &&
+      this.get('content.hostComponents').filterProperty('componentName', 'NAMENODE').someProperty('workStatus',
App.HostComponentStatus.started)) {
+      App.router.get('mainServiceItemController').checkNnLastCheckpointTime(function () {
+        return App.showConfirmationFeedBackPopup(function (query) {
+          var selectedService = self.get('content.id');
+          batchUtils.restartAllServiceHostComponents(selectedService, true, query);
+        }, bodyMessage);
+      });
+    } else {
+      return App.showConfirmationFeedBackPopup(function (query) {
+        var selectedService = self.get('content.id');
+        batchUtils.restartAllServiceHostComponents(selectedService, true, query);
+      }, bodyMessage);
+    }
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/app/controllers/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/item.js b/ambari-web/app/controllers/main/service/item.js
index d12164a..af6ca36 100644
--- a/ambari-web/app/controllers/main/service/item.js
+++ b/ambari-web/app/controllers/main/service/item.js
@@ -171,10 +171,104 @@ App.MainServiceItemController = Em.Controller.extend({
       additionalWarningMsg:  msg
     });
 
-    return App.showConfirmationFeedBackPopup(function(query, runMmOperation) {
-      self.set('isPending', true);
-      self.startStopWithMmode(serviceHealth, query, runMmOperation);
-    }, bodyMessage);
+    // check HDFS NameNode checkpoint before stop service
+    if (this.get('content.serviceName') == 'HDFS' && serviceHealth == 'INSTALLED'
&&
+      this.get('content.hostComponents').filterProperty('componentName', 'NAMENODE').someProperty('workStatus',
App.HostComponentStatus.started)) {
+      this.checkNnLastCheckpointTime(function () {
+        return App.showConfirmationFeedBackPopup(function(query, runMmOperation) {
+          self.set('isPending', true);
+          self.startStopWithMmode(serviceHealth, query, runMmOperation);
+        }, bodyMessage);
+      });
+    } else {
+      return App.showConfirmationFeedBackPopup(function(query, runMmOperation) {
+        self.set('isPending', true);
+        self.startStopWithMmode(serviceHealth, query, runMmOperation);
+      }, bodyMessage);
+    }
+  },
+
+
+  /**
+   * 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
+   */
+  checkNnLastCheckpointTime: function(callback) {
+    var self = this;
+    this.pullNnCheckPointTime().complete(function () {
+      var isNNCheckpointTooOld = self.get('isNNCheckpointTooOld');
+      self.set('isNNCheckpointTooOld', null);
+      if (isNNCheckpointTooOld) {
+        // too old
+        var msg = Em.Object.create({
+          confirmMsg: Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld')
+
+            Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointTooOld.instructions').format(isNNCheckpointTooOld),
+          confirmButton: Em.I18n.t('common.next')
+        });
+        return App.showConfirmationFeedBackPopup(callback, msg);
+      } else if (isNNCheckpointTooOld == null) {
+        // not available
+        return App.showConfirmationPopup(
+          callback, Em.I18n.t('services.service.stop.HDFS.warningMsg.checkPointNA'), null,
+          Em.I18n.t('common.warning'), Em.I18n.t('common.proceedAnyway'), true
+        );
+      } else {
+        // still young
+        callback();
+      }
+    });
+  },
+
+  pullNnCheckPointTime: function () {
+    return App.ajax.send({
+      name: 'common.service.hdfs.getNnCheckPointTime',
+      sender: this,
+      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');
+    } else {
+      // HA enabled
+      data.host_components.forEach(function(namenode) {
+        nameNodesStatus.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');
+        }
+      } else if (nameNodesStatus.someProperty('HAState', 'standby')) {
+        lastCheckpointTime = nameNodesStatus.findProperty('HAState', 'standby').get('LastCheckpointTime');
+        hostName = nameNodesStatus.findProperty('HAState', 'standby').get('hostName')
+      }
+    }
+
+    if (!lastCheckpointTime) {
+      this.set("isNNCheckpointTooOld", null);
+    } else {
+      var time_criteria = 12; // 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);
+      }
+    }
   },
 
   addAdditionalWarningMessage: function(serviceHealth, msg, serviceDisplayName){
@@ -494,9 +588,20 @@ App.MainServiceItemController = Em.Controller.extend({
       confirmButton: Em.I18n.t('services.service.restartAll.confirmButton'),
       additionalWarningMsg: this.get('content.passiveState') === 'OFF' ? Em.I18n.t('services.service.restartAll.warningMsg.turnOnMM').format(serviceDisplayName):
null
      });
-    return App.showConfirmationFeedBackPopup(function(query, runMmOperation) {
-      batchUtils.restartAllServiceHostComponents(serviceName, false, query, runMmOperation);
-    }, bodyMessage);
+
+    // check HDFS NameNode checkpoint before stop service
+    if (this.get('content.serviceName') == 'HDFS' &&
+      this.get('content.hostComponents').filterProperty('componentName', 'NAMENODE').someProperty('workStatus',
App.HostComponentStatus.started)) {
+      this.checkNnLastCheckpointTime(function () {
+        return App.showConfirmationFeedBackPopup(function(query, runMmOperation) {
+          batchUtils.restartAllServiceHostComponents(serviceName, false, query, runMmOperation);
+        }, bodyMessage);
+      });
+    } else {
+      return App.showConfirmationFeedBackPopup(function(query, runMmOperation) {
+        batchUtils.restartAllServiceHostComponents(serviceName, false, query, runMmOperation);
+      }, bodyMessage);
+    }
   },
 
   turnOnOffPassive: function(label) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 77eec76..9b81c66 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1833,6 +1833,16 @@ Em.I18n.translations = {
   'services.service.restartAll.confirmButton': 'Confirm Restart All',
   'services.service.restartAll.confirmMsg': 'You are about to restart {0}',
   'services.service.restartAll.warningMsg.turnOnMM': 'This will trigger alerts as the service
is restarted. To suppress alerts, turn on Maintenance Mode for {0} prior to running restart
all',
+  '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':
+    '<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 hdfs -l -c \'hdfs dfsadmin -safemode enter\'</div></li>'
+
+    '<li>Once in Safe Mode, create a Checkpoint:' +
+    '<div class="code-snippet">sudo su hdfs -l -c \'hdfs dfsadmin -saveNamespace\'</div></li>'
+
+    '</ol>',
+  'services.service.stop.HDFS.warningMsg.checkPointTooOld': 'The last HDFS checkpoint is
older than 12 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.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',

http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 4b27157..10c7d89 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -92,6 +92,16 @@ var urls = {
     'mock': '/data/wizard/deploy/poll_1.json'
   },
 
+  'common.service.hdfs.getNnCheckPointTime': {
+    'real': '/clusters/{clusterName}/services/HDFS/components/NAMENODE?fields=host_components/metrics/dfs/FSNamesystem/HAState,host_components/metrics/dfs/FSNamesystem/LastCheckpointTime',
+    'mock': ''
+  },
+
+  'common.host_component.getNnCheckPointTime': {
+    'real': '/clusters/{clusterName}/hosts/{host}/host_components/NAMENODE?fields=metrics/dfs/FSNamesystem/HAState,metrics/dfs/FSNamesystem/LastCheckpointTime',
+    'mock': ''
+  },
+
   'common.host_component.update': {
     'real': '/clusters/{clusterName}/host_components',
     'mock': '',

http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/app/views/main/service/info/summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/info/summary.js b/ambari-web/app/views/main/service/info/summary.js
index 4e58bda..78855c0 100644
--- a/ambari-web/app/views/main/service/info/summary.js
+++ b/ambari-web/app/views/main/service/info/summary.js
@@ -334,10 +334,29 @@ App.MainServiceInfoSummaryView = Em.View.extend(App.UserPref, {
       confirmButton: Em.I18n.t('services.service.restartAll.confirmButton'),
       additionalWarningMsg: this.get('service.passiveState') === 'OFF' ? Em.I18n.t('services.service.restartAll.warningMsg.turnOnMM').format(serviceDisplayName)
: null
     });
-    return App.showConfirmationFeedBackPopup(function (query) {
-      var selectedService = self.get('service.id');
-      batchUtils.restartAllServiceHostComponents(selectedService, true, query);
-    }, bodyMessage);
+
+    var isNNAffected = false;
+    var restartRequiredHostsAndComponents = this.get('controller.content.restartRequiredHostsAndComponents');
+    for (var hostName in restartRequiredHostsAndComponents) {
+      restartRequiredHostsAndComponents[hostName].forEach(function (hostComponent) {
+        if (hostComponent == 'NameNode')
+          isNNAffected = true;
+      })
+    }
+    if (serviceDisplayName == 'HDFS' && isNNAffected &&
+      this.get('controller.content.hostComponents').filterProperty('componentName', 'NAMENODE').someProperty('workStatus',
App.HostComponentStatus.started)) {
+      App.router.get('mainServiceItemController').checkNnLastCheckpointTime(function () {
+        return App.showConfirmationFeedBackPopup(function (query) {
+          var selectedService = self.get('service.id');
+          batchUtils.restartAllServiceHostComponents(selectedService, true, query);
+        }, bodyMessage);
+      });
+    } else {
+      return App.showConfirmationFeedBackPopup(function (query) {
+        var selectedService = self.get('service.id');
+        batchUtils.restartAllServiceHostComponents(selectedService, true, query);
+      }, bodyMessage);
+    }
   },
   rollingRestartStaleConfigSlaveComponents: function (componentName) {
     batchUtils.launchHostComponentRollingRestart(componentName.context, this.get('service.displayName'),
this.get('service.passiveState') === "ON", true);

http://git-wip-us.apache.org/repos/asf/ambari/blob/2acaf832/ambari-web/test/controllers/main/service/item_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/item_test.js b/ambari-web/test/controllers/main/service/item_test.js
index 46e7512..d80d3ff 100644
--- a/ambari-web/test/controllers/main/service/item_test.js
+++ b/ambari-web/test/controllers/main/service/item_test.js
@@ -389,7 +389,15 @@ describe('App.MainServiceItemController', function () {
     var event = {
       target: el
     };
-    var mainServiceItemController = App.MainServiceItemController.create({content: {serviceName:
"HDFS"}});
+    var mainServiceItemController = App.MainServiceItemController.create({
+      content: {
+        serviceName: "HDFS",
+        hostComponents: [ {
+          componentName: 'NAMENODE',
+          workStatus: 'INSTALLED'
+        }]
+      }
+    });
     beforeEach(function () {
       sinon.spy(mainServiceItemController, "startStopPopupPrimary");
       sinon.spy(Em.I18n, "t");
@@ -465,7 +473,15 @@ describe('App.MainServiceItemController', function () {
       
       it ("should display dependent list if other services depend on the one to be stopped",
function() {
         var mainServiceItemController = App.MainServiceItemController.create(
-            {content: {serviceName: "HDFS", passiveState:'OFF'}});
+          {content: {
+            serviceName: "HDFS",
+            passiveState:'OFF',
+            hostComponents: [{
+              componentName: 'NAMENODE',
+              workStatus: 'INSTALLED'
+            }]
+          }}
+        );
         mainServiceItemController.startStopPopup(event, "INSTALLED");
         expect(Em.I18n.t.calledWith('services.service.stop.warningMsg.turnOnMM')).to.be.ok;
         expect(Em.I18n.t.calledWith('services.service.stop.warningMsg.dependent.services')).to.be.ok;


Mime
View raw message