Updated Branches: refs/heads/trunk ff6ff6d0c -> 6ea5458bd
AMBARI-2797. NameNode HA Wizard: progress page after "Create Checkpoint" page. (Aleksandr Kovalenko via yusaku) Project: http://git-wip-us.apache.org/repos/asf/incubator-ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ambari/commit/6ea5458b Tree: http://git-wip-us.apache.org/repos/asf/incubator-ambari/tree/6ea5458b Diff: http://git-wip-us.apache.org/repos/asf/incubator-ambari/diff/6ea5458b Branch: refs/heads/trunk Commit: 6ea5458bd95d606b3b6082985fdd891317205258 Parents: ff6ff6d Author: Yusaku Sako <[email protected]> Authored: Fri Aug 2 14:40:40 2013 -0700 Committer: Yusaku Sako <[email protected]> Committed: Fri Aug 2 14:40:46 2013 -0700 ---------------------------------------------------------------------- ambari-web/app/controllers.js | 1 + .../highAvailability/progress_controller.js | 210 +++++++++++++++++++ .../admin/highAvailability/step4_controller.js | 54 ++++- .../main/admin/highAvailability_controller.js | 9 +- ambari-web/app/messages.js | 9 +- .../app/routes/high_availability_routes.js | 7 +- ambari-web/app/styles/application.less | 2 +- .../main/admin/highAvailability/step2.hbs | 2 +- .../main/admin/highAvailability/step3.hbs | 2 +- .../main/admin/highAvailability/step4.hbs | 25 ++- ambari-web/app/utils/ajax.js | 91 ++++++++ .../main/admin/highAvailability/step4_view.js | 38 +++- 12 files changed, 434 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/controllers.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js index 5cb8dea..e4fbbf5 100644 --- a/ambari-web/app/controllers.js +++ b/ambari-web/app/controllers.js @@ -28,6 +28,7 @@ require('controllers/main'); require('controllers/main/admin'); require('controllers/main/admin/highAvailability_controller'); require('controllers/main/admin/highAvailability/wizard_controller'); +require('controllers/main/admin/highAvailability/progress_controller'); require('controllers/main/admin/highAvailability/step1_controller'); require('controllers/main/admin/highAvailability/step2_controller'); require('controllers/main/admin/highAvailability/step3_controller'); http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/controllers/main/admin/highAvailability/progress_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/highAvailability/progress_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/progress_controller.js new file mode 100644 index 0000000..6cb1048 --- /dev/null +++ b/ambari-web/app/controllers/main/admin/highAvailability/progress_controller.js @@ -0,0 +1,210 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); + +App.HighAvailabilityProgressPageController = Em.Controller.extend({ + + tasks: [], + commands: [], + currentRequestIds: [], + logs: [], + currentTaskId: null, + POLL_INTERVAL: 4000, + isSubmitDisabled: true, + + loadStep: function () { + this.clearStep(); + this.loadTasks(); + this.addObserver('[email protected]', this, 'onTaskStatusChange'); + this.onTaskStatusChange(); + }, + + clearStep: function () { + this.set('isSubmitDisabled', true); + this.get('tasks').clear(); + this.get('logs').clear(); + var commands = this.get('commands'); + for (var i = 0; i < commands.length; i++) { + this.get('tasks').pushObject(Ember.Object.create({ + title: Em.I18n.t('admin.highAvailability.wizard.step4.task' + i + '.title'), + status: 'PENDING', + id: i, + command: commands[i] + })); + } + }, + + loadTasks: function () { + //load and set tasks statuses form server + }, + + setTaskStatus: function (taskId, status) { + this.get('tasks').findProperty('id', taskId).set('status', status) + }, + + showRetry: function (taskId) { + //show retry button for selected task + }, + + onTaskStatusChange: function () { + if (!this.get('tasks').someProperty('status', 'IN_PROGRESS') && !this.get('tasks').someProperty('status', 'QUEUED') && !this.get('tasks').someProperty('status', 'FAILED')) { + var nextTask = this.get('tasks').findProperty('status', 'PENDING'); + if (nextTask) { + this.setTaskStatus(nextTask.get('id'), 'QUEUED'); + this.set('currentTaskId', nextTask.get('id')); + this.runTask(nextTask.get('id')); + } else { + this.set('isSubmitDisabled', false); + } + } + }, + + /* + run command of appropriate task + */ + runTask: function (taskId) { + this[this.get('tasks').findProperty('id', taskId).get('command')](); + }, + + onTaskError: function () { + this.setTaskStatus(this.get('currentTaskId'), 'FAILED'); + this.showRetry(this.get('currentTaskId')); + }, + + onTaskCompleted: function () { + this.setTaskStatus(this.get('currentTaskId'), 'COMPLETED'); + }, + + createComponent: function (componentName, hostName) { + if (!(hostName instanceof Array)) { + hostName = [hostName]; + } + for (var i = 0; i < hostName.length; i++) { + App.ajax.send({ + name: 'admin.high_availability.create_component', + sender: this, + data: { + hostName: hostName[i], + componentName: componentName, + taskNum: hostName.length + }, + success: 'installComponent', + error: 'onTaskError' + }); + } + }, + + installComponent: function (data, params) { + var hostName = params.data.hostName; + if (!(hostName instanceof Array)) { + hostName = [hostName]; + } + for (var i = 0; i < hostName.length; i++) { + App.ajax.send({ + name: 'admin.high_availability.install_component', + sender: this, + data: { + hostName: hostName[i], + componentName: params.data.componentName, + displayName: App.format.role(params.data.componentName), + taskNum: params.data.taskNum || hostName.length + }, + success: 'startPolling', + error: 'onTaskError' + }); + } + }, + + startComponent: function (componentName, hostName) { + if (!(hostName instanceof Array)) { + hostName = [hostName]; + } + for (var i = 0; i < hostName.length; i++) { + App.ajax.send({ + name: 'admin.high_availability.start_component', + sender: this, + data: { + hostName: hostName[i], + componentName: componentName, + displayName: App.format.role(componentName) + }, + success: 'startPolling', + error: 'onTaskError' + }); + } + }, + + startPolling: function (data, params) { + if (data) { + this.get('currentRequestIds').push(data.Requests.id); + var tasksCount = params.data.taskNum || 1; + if (tasksCount === this.get('currentRequestIds').length) { + this.doPolling(); + } + } else { + this.onTaskError(); + } + }, + + doPolling: function () { + var requestIds = this.get('currentRequestIds'); + for (var i = 0; i < requestIds.length; i++) { + App.ajax.send({ + name: 'admin.high_availability.polling', + sender: this, + data: { + requestId: requestIds[i] + }, + success: 'parseLogs', + error: 'onTaskError' + }); + } + }, + + parseLogs: function (logs) { + this.get('logs').push(logs.tasks); + if (this.get('currentRequestIds').length === this.get('logs').length) { + var tasks = this.get('logs'); + var self = this; + var currentTaskId = this.get('currentTaskId'); + if (!tasks.someProperty('Tasks.status', 'PENDING') && !tasks.someProperty('Tasks.status', 'QUEUED') && !tasks.someProperty('Tasks.status', 'IN_PROGRESS')) { + if (tasks.someProperty('Tasks.status', 'FAILED')) { + this.setTaskStatus(currentTaskId, 'FAILED'); + } else { + this.setTaskStatus(currentTaskId, 'COMPLETED'); + } + } else { + var progress = Math.round(tasks.filterProperty('Tasks.status', 'COMPLETED').length / tasks.length * 100); + this.get('tasks').findProperty('id', currentTaskId).set('progress', progress); + this.setTaskStatus(currentTaskId, 'IN_PROGRESS'); + window.setTimeout(function () { + self.doPolling() + }, self.POLL_INTERVAL); + } + this.get('logs').clear(); + } + }, + + done: function () { + if (!this.get('isSubmitDisabled')) { + App.router.send('next'); + } + } +}); + http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/controllers/main/admin/highAvailability/step4_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/highAvailability/step4_controller.js b/ambari-web/app/controllers/main/admin/highAvailability/step4_controller.js index 48dbc75..1fa3e48 100644 --- a/ambari-web/app/controllers/main/admin/highAvailability/step4_controller.js +++ b/ambari-web/app/controllers/main/admin/highAvailability/step4_controller.js @@ -18,5 +18,57 @@ var App = require('app'); -App.HighAvailabilityWizardStep4Controller = Em.Controller.extend(); +App.HighAvailabilityWizardStep4Controller = App.HighAvailabilityProgressPageController.extend({ + + commands: ['stopAllServices', 'installNameNode', 'installJournalNode', 'startJournalNode', 'disableSNameNode', 'reconfigureHDFS'], + + stopAllServices: function () { + App.ajax.send({ + name: 'admin.high_availability.stop_all_services', + sender: this, + success: 'startPolling', + error: 'onTaskError' + }); + }, + + installNameNode: function () { + var hostName = this.get('content.masterComponentHosts').findProperty('isAddNameNode').hostName; + this.createComponent('NAMENODE', hostName); + }, + + installJournalNode: function () { + var hostNames = this.get('content.masterComponentHosts').filterProperty('component', 'JOURNALNODE').mapProperty('hostName'); + this.createComponent('JOURNALNODE', hostNames); + }, + + startJournalNode: function () { + var hostNames = this.get('content.masterComponentHosts').filterProperty('component', 'JOURNALNODE').mapProperty('hostName'); + this.startComponent('JOURNALNODE', hostNames); + }, + + disableSNameNode: function () { + var hostName = this.get('content.masterComponentHosts').findProperty('component', 'SECONDARY_NAMENODE').hostName; + App.ajax.send({ + name: 'admin.high_availability.maintenance_mode', + sender: this, + data: { + hostName: hostName, + componentName: 'SECONDARY_NAMENODE' + }, + success: 'onTaskCompleted', + error: 'onTaskError' + }); + }, + + reconfigureHDFS: function () { + var hostNames = this.get('content.masterComponentHosts').filterProperty('component', 'NAMENODE').mapProperty('hostName'); + var params = { + data: { + hostName: hostNames, + componentName: 'HDFS_CLIENT' + } + }; + this.installComponent(null, params); + } +}); http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/controllers/main/admin/highAvailability_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/highAvailability_controller.js b/ambari-web/app/controllers/main/admin/highAvailability_controller.js index f081a0a..81bd54e 100644 --- a/ambari-web/app/controllers/main/admin/highAvailability_controller.js +++ b/ambari-web/app/controllers/main/admin/highAvailability_controller.js @@ -23,6 +23,8 @@ App.MainAdminHighAvailabilityController = Em.Controller.extend({ securityEnabled: false, + tag: null, + dataIsLoaded: false, enableHighAvailability: function () { @@ -64,20 +66,21 @@ App.MainAdminHighAvailabilityController = Em.Controller.extend({ getSecurityStatusFromServerSuccessCallback: function (data) { var configs = data.Clusters.desired_configs; if ('global' in configs) { - this.getServiceConfigsFromServer(configs['global'].tag); + this.set('tag', configs['global'].tag); + this.getServiceConfigsFromServer(); } else { this.showErrorPopup(Em.I18n.t('admin.security.status.error')); } }, - getServiceConfigsFromServer: function (tag) { + getServiceConfigsFromServer: function () { App.ajax.send({ name: 'admin.service_config', sender: this, data: { siteName: 'global', - tagName: tag + tagName: this.get('tag') }, success: 'getServiceConfigsFromServerSuccessCallback', error: 'errorCallback' http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 4f24640..2dd2667 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -643,7 +643,14 @@ Em.I18n.translations = { 'admin.highAvailability.wizard.step1.header':'Get Started', 'admin.highAvailability.wizard.step2.header':'Select Hosts', 'admin.highAvailability.wizard.step3.header':'Review', - 'admin.highAvailability.wizard.step4.header':'Apply', + 'admin.highAvailability.wizard.step4.header':'Deploy', + 'admin.highAvailability.wizard.step4.notice':'Please wait while NameNode HA is being deployed.', + 'admin.highAvailability.wizard.step4.task0.title':'Stop all services', + 'admin.highAvailability.wizard.step4.task1.title':'Install Additional NameNode', + 'admin.highAvailability.wizard.step4.task2.title':'Install JournalNodes', + 'admin.highAvailability.wizard.step4.task3.title':'Start JournalNodes', + 'admin.highAvailability.wizard.step4.task4.title':'Disable Secondary NameNode', + 'admin.highAvailability.wizard.step4.task5.title':'Reconfigure HDFS', 'admin.highAvailability.wizard.step3.nn1':'Current NameNode is on {0}.', 'admin.highAvailability.wizard.step3.nn2':'Additional NameNode will be installed on {0}.', http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/routes/high_availability_routes.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/routes/high_availability_routes.js b/ambari-web/app/routes/high_availability_routes.js index 2fb5521..0d53fad 100644 --- a/ambari-web/app/routes/high_availability_routes.js +++ b/ambari-web/app/routes/high_availability_routes.js @@ -103,8 +103,10 @@ module.exports = Em.Route.extend({ step4: Em.Route.extend({ route: '/step4', connectOutlets: function (router) { + $('a.close').hide(); var controller = router.get('highAvailabilityWizardController'); controller.setCurrentStep('4'); + controller.setLowerStepsDisable(4); controller.dataLoading().done(function () { controller.loadAllPriorSteps(); controller.connectOutlet('highAvailabilityWizardStep4', controller.get('content')); @@ -113,10 +115,7 @@ module.exports = Em.Route.extend({ back: function (router) { router.transitionTo('step3'); }, - complete: function (router, context) { - $(context.currentTarget).parents("#modal").find(".close").trigger('click'); - router.transitionTo('main.admin.adminHighAvailability'); - } + next: function (router) {} }), gotoStep1: Em.Router.transitionTo('step1'), http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/styles/application.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index 92da960..d8438cd 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -442,7 +442,7 @@ h1 { } } } - #step14 { + #step14, #ha-step4 { .item { line-height: 30px; i { http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/templates/main/admin/highAvailability/step2.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/highAvailability/step2.hbs b/ambari-web/app/templates/main/admin/highAvailability/step2.hbs index 94dd804..edd1d6f 100644 --- a/ambari-web/app/templates/main/admin/highAvailability/step2.hbs +++ b/ambari-web/app/templates/main/admin/highAvailability/step2.hbs @@ -75,6 +75,6 @@ <div style="clear: both;"></div> </div> <div class="btn-area"> - + <a class="btn" {{action back}}>← {{t common.back}}</a> <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action submit target="controller"}}>{{t common.next}} →</a> </div> http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/templates/main/admin/highAvailability/step3.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/highAvailability/step3.hbs b/ambari-web/app/templates/main/admin/highAvailability/step3.hbs index cd43342..c13213d 100644 --- a/ambari-web/app/templates/main/admin/highAvailability/step3.hbs +++ b/ambari-web/app/templates/main/admin/highAvailability/step3.hbs @@ -37,7 +37,7 @@ </div> </div> - <div class="btn-area"> + <a class="btn" {{action back}}>← {{t common.back}}</a> <a class="btn btn-success pull-right" {{action next}}>{{t common.next}} →</a> </div> http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/templates/main/admin/highAvailability/step4.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/highAvailability/step4.hbs b/ambari-web/app/templates/main/admin/highAvailability/step4.hbs index e2558e4..5fefd4f 100644 --- a/ambari-web/app/templates/main/admin/highAvailability/step4.hbs +++ b/ambari-web/app/templates/main/admin/highAvailability/step4.hbs @@ -15,8 +15,27 @@ * See the License for the specific language governing permissions and * limitations under the License. }} +<div id="ha-step4"> + <h2>{{t admin.highAvailability.wizard.step4.header}}</h2> -<h2>{{t admin.highAvailability.wizard.step4.header}}</h2> -<div class="btn-area"> - <a class="btn btn-success pull-right" {{action complete}}>{{t common.complete}}</a> + <div class="alert alert-info">{{t admin.highAvailability.wizard.step4.notice}}</div> + {{#each task in controller.tasks}} + {{#view view.taskView contentBinding="task"}} + <div class="item"> + <i {{bindAttr class="view.icon view.iconColor"}}></i> + <a href="javascript:void(0)">{{task.title}}</a> + </div> + <div {{bindAttr class="view.showProgressBar::hide :row :span12" }}> + <div class="progress-bar span4"> + <div class="progress-striped active progress-info progress"> + <div class="bar" {{bindAttr style="view.barWidth"}}></div> + </div> + </div> + <div class="span1">{{task.progress}}%</div> + </div> + {{/view}} + {{/each}} + <div class="btn-area"> + <a {{bindAttr class=":btn controller.isSubmitDisabled:disabled :btn-success :pull-right"}} {{action done target="controller"}}>{{t common.done}}</a> + </div> </div> http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/utils/ajax.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ajax.js b/ambari-web/app/utils/ajax.js index b36343a..2dda903 100644 --- a/ambari-web/app/utils/ajax.js +++ b/ambari-web/app/utils/ajax.js @@ -552,6 +552,97 @@ var urls = { }; } }, + 'admin.high_availability.stop_all_services': { + 'real': '/clusters/{clusterName}/services?ServiceInfo/state=STARTED', + 'mock': 'fsdfs', + 'format': function (data, opt) { + return { + type: 'PUT', + data: { + "RequestInfo": { + "context": "Stop all services" + }, + "Body": { + "ServiceInfo": { + "state": "INSTALLED" + } + } + } + } + } + }, + 'admin.high_availability.polling': { + 'real': '/clusters/{clusterName}/requests/{requestId}?fields=tasks/*', + 'mock': '', + 'type': 'GET' + }, + 'admin.high_availability.create_component': { + 'real': '/clusters/{clusterName}/hosts?Hosts/host_name={hostName}', + 'mock': '', + 'type': 'POST', + 'format': function (data) { + return { + data: JSON.stringify({ + "host_components": [ + { + "HostRoles": { + "component_name": data.componentName + } + } + ] + }) + } + } + }, + 'admin.high_availability.install_component': { + 'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}', + 'type': 'PUT', + 'format': function (data) { + return { + data: JSON.stringify({ + RequestInfo: { + "context": "Install " + data.displayName + }, + Body: { + "HostRoles": { + "state": "INSTALLED" + } + } + }) + } + } + }, + 'admin.high_availability.start_component': { + 'real': '/clusters/{clusterName}/services/{serviceName}', + 'type': 'PUT', + 'format': function (data) { + return { + data: JSON.stringify({ + RequestInfo: { + "context": "Start service " + data.displayName + }, + Body: { + ServiceInfo: { + "state": "STARTED" + } + } + }) + } + } + }, + 'admin.high_availability.maintenance_mode': { + 'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}', + 'type': 'PUT', + 'format': function () { + return { + data: { + "HostRoles": { + "state": "MAINTENANCE" + } + } + } + } + }, 'admin.security.cluster_configs': { 'real': '/clusters/{clusterName}', 'format': function (data, opt) { http://git-wip-us.apache.org/repos/asf/incubator-ambari/blob/6ea5458b/ambari-web/app/views/main/admin/highAvailability/step4_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin/highAvailability/step4_view.js b/ambari-web/app/views/main/admin/highAvailability/step4_view.js index 8a23018..b3ed648 100644 --- a/ambari-web/app/views/main/admin/highAvailability/step4_view.js +++ b/ambari-web/app/views/main/admin/highAvailability/step4_view.js @@ -21,6 +21,42 @@ var App = require('app'); App.HighAvailabilityWizardStep4View = Em.View.extend({ - templateName: require('templates/main/admin/highAvailability/step4') + templateName: require('templates/main/admin/highAvailability/step4'), + didInsertElement: function () { + this.get('controller').loadStep(); + }, + + taskView: Em.View.extend({ + icon: '', + iconColor: '', + + didInsertElement: function () { + this.onStatus(); + }, + + barWidth: function () { + return 'width: ' + this.get('content.progress') + '%;'; + }.property('content.progress'), + + onStatus: function () { + if (this.get('content.status') === 'IN_PROGRESS') { + this.set('icon', 'icon-cog'); + this.set('iconColor', 'text-info'); + } else if (this.get('content.status') === 'FAILED') { + this.set('icon', 'icon-exclamation-sign'); + this.set('iconColor', 'text-error'); + } else if (this.get('content.status') === 'COMPLETED') { + this.set('icon', 'icon-ok'); + this.set('iconColor', 'text-success'); + } else { + this.set('icon', 'icon-cog'); + this.set('iconColor', ''); + } + }.observes('content.status'), + + showProgressBar: function () { + return this.get('content.status') === "IN_PROGRESS"; + }.property('content.status') + }) });
