You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2015/09/02 00:53:05 UTC
ambari git commit: AMBARI-12951. Prompt user to save checkpoint
before shutdown if last checkpoint is too old. (xiwang via yusaku)
Repository: ambari
Updated Branches:
refs/heads/trunk c85f044ff -> 5cdf4e911
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/5cdf4e91
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/5cdf4e91
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/5cdf4e91
Branch: refs/heads/trunk
Commit: 5cdf4e911b668648f167655ee2cc187ead0b62a8
Parents: c85f044
Author: Yusaku Sako <yu...@hortonworks.com>
Authored: Tue Sep 1 15:52:26 2015 -0700
Committer: Yusaku Sako <yu...@hortonworks.com>
Committed: Tue Sep 1 15:52:26 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/5cdf4e91/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/5cdf4e91/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 adf0c40..0d309ff 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");
+ });
+ }
},
/**
@@ -1840,9 +1924,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);
+ });
+ }
}
},
@@ -1855,9 +1948,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/5cdf4e91/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/5cdf4e91/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/5cdf4e91/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/5cdf4e91/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 78f51f8..f661fb9 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1807,6 +1807,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/5cdf4e91/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 b1542c9..1e389aa 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/5cdf4e91/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/5cdf4e91/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;