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 2013/08/02 23:41:00 UTC

git commit: AMBARI-2797. NameNode HA Wizard: progress page after "Create Checkpoint" page. (Aleksandr Kovalenko via yusaku)

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 <yu...@hortonworks.com>
Authored: Fri Aug 2 14:40:40 2013 -0700
Committer: Yusaku Sako <yu...@hortonworks.com>
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('tasks.@each.status', 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}}>&larr; {{t common.back}}</a>
   <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action submit target="controller"}}>{{t common.next}} &rarr;</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}}>&larr; {{t common.back}}</a>
    <a class="btn btn-success pull-right" {{action next}}>{{t common.next}} &rarr;</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}}&#37;</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')
+  })
 });