Return-Path: X-Original-To: apmail-ambari-commits-archive@www.apache.org Delivered-To: apmail-ambari-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id AFBAE18EA8 for ; Tue, 1 Sep 2015 22:53:35 +0000 (UTC) Received: (qmail 90102 invoked by uid 500); 1 Sep 2015 22:53:35 -0000 Delivered-To: apmail-ambari-commits-archive@ambari.apache.org Received: (qmail 90073 invoked by uid 500); 1 Sep 2015 22:53:35 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 90064 invoked by uid 99); 1 Sep 2015 22:53:35 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 01 Sep 2015 22:53:35 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 35655E0615; Tue, 1 Sep 2015 22:53:35 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: yusaku@apache.org To: commits@ambari.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: ambari git commit: AMBARI-12951. Prompt user to save checkpoint before shutdown if last checkpoint is too old. (xiwang via yusaku) Date: Tue, 1 Sep 2015 22:53:35 +0000 (UTC) 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 Authored: Tue Sep 1 15:52:26 2015 -0700 Committer: Yusaku Sako 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': + '
    ' + + '
  1. Login to the NameNode host {0}.
  2. ' + + '
  3. Put the NameNode in Safe Mode (read-only mode):' + + '
    sudo su hdfs -l -c \'hdfs dfsadmin -safemode enter\'
  4. ' + + '
  5. Once in Safe Mode, create a Checkpoint:' + + '
    sudo su hdfs -l -c \'hdfs dfsadmin -saveNamespace\'
  6. ' + + '
', + '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;