瀏覽代碼

AMBARI-8572. Kerberos Wizard: Implement "Kerberize Cluster" page and "Test Services" page. (jaimin)

Jaimin Jetly 10 年之前
父節點
當前提交
8eb500e603
共有 30 個文件被更改,包括 661 次插入352 次删除
  1. 0 38
      ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/metainfo.xml
  2. 0 15
      ambari-server/src/test/java/org/apache/ambari/server/api/services/KerberosServiceMetaInfoTest.java
  3. 55 0
      ambari-web/app/assets/data/wizard/kerberos/kerberize_cluster.json
  4. 55 4
      ambari-web/app/controllers/main/admin/kerberos/step2_controller.js
  5. 28 11
      ambari-web/app/controllers/main/admin/kerberos/step3_controller.js
  6. 13 2
      ambari-web/app/controllers/main/admin/kerberos/step5_controller.js
  7. 32 1
      ambari-web/app/controllers/main/admin/kerberos/step6_controller.js
  8. 7 7
      ambari-web/app/data/HDP2/site_properties.js
  9. 11 2
      ambari-web/app/messages.js
  10. 154 12
      ambari-web/app/mixins/wizard/wizardProgressPageController.js
  11. 4 2
      ambari-web/app/mixins/wizard/wizardProgressPageView.js
  12. 6 3
      ambari-web/app/models/cluster_states.js
  13. 2 1
      ambari-web/app/routes/add_kerberos_routes.js
  14. 1 1
      ambari-web/app/templates.js
  15. 74 0
      ambari-web/app/templates/common/progress.hbs
  16. 1 1
      ambari-web/app/templates/main/admin/highAvailability/nameNode/rollback.hbs
  17. 1 1
      ambari-web/app/templates/main/admin/highAvailability/nameNode/step5.hbs
  18. 1 1
      ambari-web/app/templates/main/admin/highAvailability/nameNode/step7.hbs
  19. 1 1
      ambari-web/app/templates/main/admin/highAvailability/nameNode/step9.hbs
  20. 0 67
      ambari-web/app/templates/main/admin/highAvailability/progress.hbs
  21. 1 1
      ambari-web/app/templates/main/admin/highAvailability/resourceManager/step4.hbs
  22. 1 1
      ambari-web/app/templates/main/admin/kerberos/step3.hbs
  23. 1 1
      ambari-web/app/templates/main/admin/kerberos/step5.hbs
  24. 1 1
      ambari-web/app/templates/main/admin/kerberos/step6.hbs
  25. 1 1
      ambari-web/app/templates/main/service/reassign/step4.hbs
  26. 1 1
      ambari-web/app/templates/main/service/reassign/step6.hbs
  27. 1 1
      ambari-web/app/templates/main/service/reassign/step7.hbs
  28. 200 169
      ambari-web/app/utils/ajax/ajax.js
  29. 8 2
      ambari-web/app/views/main/admin/kerberos/step5_view.js
  30. 0 4
      ambari-web/app/views/main/admin/kerberos/wizard_view.js

+ 0 - 38
ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/metainfo.xml

@@ -29,44 +29,6 @@
       <version>1.10.3-10</version>
 
       <components>
-        <component>
-          <name>KDC_SERVER</name>
-          <displayName>Kerberos KDC</displayName>
-          <category>MASTER</category>
-          <cardinality>0-1</cardinality>
-          <dependencies>
-            <dependency>
-              <name>KERBEROS/KERBEROS_CLIENT</name>
-              <scope>cluster</scope>
-              <auto-deploy>
-                <enabled>true</enabled>
-              </auto-deploy>
-            </dependency>
-          </dependencies>
-          <commandScript>
-            <script>scripts/kerberos_server.py</script>
-            <scriptType>PYTHON</scriptType>
-            <timeout>900</timeout>
-          </commandScript>
-          <configFiles>
-            <configFile>
-              <type>env</type>
-              <fileName>krb5.conf</fileName>
-              <dictionaryName>krb5-conf</dictionaryName>
-            </configFile>
-            <configFile>
-              <type>env</type>
-              <fileName>kdc.conf</fileName>
-              <dictionaryName>kdc-conf</dictionaryName>
-            </configFile>
-            <configFile>
-              <type>env</type>
-              <fileName>kadm5.acl</fileName>
-              <dictionaryName>kadm5-acl</dictionaryName>
-            </configFile>
-          </configFiles>
-        </component>
-
         <component>
           <name>KERBEROS_CLIENT</name>
           <displayName>Kerberos Client</displayName>

+ 0 - 15
ambari-server/src/test/java/org/apache/ambari/server/api/services/KerberosServiceMetaInfoTest.java

@@ -152,7 +152,6 @@ public class KerberosServiceMetaInfoTest {
   public void test220Cardinality() throws Exception {
     testCardinality(new HashMap<String, String>() {
       {
-        put("KDC_SERVER", "0-1");
         put("KERBEROS_CLIENT", "ALL");
       }
     });
@@ -162,7 +161,6 @@ public class KerberosServiceMetaInfoTest {
   public void test220AutoDeploy() throws Exception {
     testAutoDeploy(new HashMap<String, AutoDeployInfo>() {
       {
-        put("KDC_SERVER", null);
         put("KERBEROS_CLIENT", new AutoDeployInfo() {{
           setEnabled(true);
           setCoLocate(null);
@@ -175,19 +173,6 @@ public class KerberosServiceMetaInfoTest {
   public void test220Dependencies() throws Exception {
     testDependencies(new HashMap<String, Map<String, DependencyInfo>>() {
       {
-        put("KDC_SERVER", new HashMap<String, DependencyInfo>() {{
-              put("KERBEROS_CLIENT",
-                  new DependencyInfo() {{
-                    setName("KERBEROS/KERBEROS_CLIENT");
-                    setAutoDeploy(new AutoDeployInfo() {{
-                      setEnabled(true);
-                      setCoLocate(null);
-                    }});
-                    setScope("cluster");
-                  }});
-            }}
-        );
-
         put("KERBEROS_CLIENT", new HashMap<String, DependencyInfo>());
       }
     });

文件差異過大導致無法顯示
+ 55 - 0
ambari-web/app/assets/data/wizard/kerberos/kerberize_cluster.json


+ 55 - 4
ambari-web/app/controllers/main/admin/kerberos/step2_controller.js

@@ -27,13 +27,15 @@ App.KerberosWizardStep2Controller = App.WizardStep7Controller.extend({
 
   allSelectedServiceNames: ['KERBEROS'],
 
+  componentName: 'KERBEROS_CLIENT',
+
   installedServiceNames: [],
 
   servicesInstalled: false,
 
   addMiscTabToPage: false,
 
-  hostNames: function() {
+  hostNames: function () {
     return this.get('content.hosts');
   }.property('content.hosts'),
 
@@ -81,9 +83,13 @@ App.KerberosWizardStep2Controller = App.WizardStep7Controller.extend({
 
   createKerberosResources: function () {
     var self = this;
-    this.createKerberosService().done(function() {
-      self.createConfigurations().done(function() {
-        App.router.send('next');
+    this.createKerberosService().done(function () {
+      self.createKerberosComponent().done(function () {
+        self.createKerberosHostComponents().done(function () {
+          self.createConfigurations().done(function () {
+            App.router.send('next');
+          });
+        });
       });
     });
   },
@@ -113,6 +119,51 @@ App.KerberosWizardStep2Controller = App.WizardStep7Controller.extend({
     });
   },
 
+  createKerberosComponent: function () {
+    return App.ajax.send({
+      name: 'common.create_component',
+      sender: this,
+      data: {
+        serviceName: this.selectedServiceNames[0],
+        componentName: this.componentName
+      }
+    });
+  },
+
+  createKerberosHostComponents: function() {
+    var hostNames = this.get('content.hosts');
+    var queryStr = '';
+    hostNames.forEach(function (hostName) {
+      queryStr += 'Hosts/host_name=' + hostName + '|';
+    });
+    //slice off last symbol '|'
+    queryStr = queryStr.slice(0, -1);
+
+    var data = {
+      "RequestInfo": {
+        "query": queryStr
+      },
+      "Body": {
+        "host_components": [
+          {
+            "HostRoles": {
+              "component_name": this.componentName
+            }
+          }
+        ]
+      }
+    };
+
+    return App.ajax.send({
+      name: 'wizard.step8.register_host_to_component',
+      sender: this,
+      data: {
+        cluster: App.router.getClusterName(),
+        data: JSON.stringify(data)
+      }
+    });
+  },
+
   createConfigurations: function () {
     var service = App.StackService.find().findProperty('serviceName', 'KERBEROS');
     var serviceConfigTags = [];

+ 28 - 11
ambari-web/app/controllers/main/admin/kerberos/step3_controller.js

@@ -25,23 +25,40 @@ App.KerberosWizardStep3Controller = App.KerberosProgressPageController.extend({
   commands: ['installKerberos', 'testKerberos'],
 
   installKerberos: function() {
-    App.ajax.send({
-      name: 'common.create_component',
+    var self = this;
+    this.getKerberosClientState().done(function(data) {
+      if (data.ServiceComponentInfo.state === 'INIT') {
+        App.ajax.send({
+          name: 'common.services.update',
+          sender: self,
+          data: {
+            context: Em.I18n.t('requestInfo.kerberosService'),
+            ServiceInfo: {"state": "INSTALLED"},
+            urlParams: "ServiceInfo/state=INSTALLED&ServiceInfo/service_name=KERBEROS"
+          },
+          success: 'startPolling',
+          error: 'onTaskError'
+        });
+      } else {
+        var hostNames = self.get('content.hosts');
+        self.updateComponent('KERBEROS_CLIENT', hostNames, "KERBEROS", "Install");
+      }
+    });
+  },
+
+
+  getKerberosClientState: function() {
+    return App.ajax.send({
+      name: 'common.service_component.info',
       sender: this,
       data: {
         serviceName: this.serviceName,
-        componentName: this.componentName
-      },
-      success: 'onKerberosCreate',
-      error: 'onKerberosCreate'
+        componentName: this.componentName,
+        urlParams: "fields=ServiceComponentInfo/state"
+      }
     });
   },
 
-  onKerberosCreate: function() {
-    var hostNames = this.get('content.hosts');
-    this.createComponent(this.componentName, hostNames, this.serviceName);
-  },
-
   testKerberos: function() {
     App.ajax.send({
       'name': 'service.item.smoke',

+ 13 - 2
ambari-web/app/controllers/main/admin/kerberos/step5_controller.js

@@ -16,6 +16,17 @@
  * limitations under the License.
  */
 
-App.KerberosWizardStep5Controller = Em.Controller.extend({
-  name: 'kerberosWizardStep5Controller'
+App.KerberosWizardStep5Controller = App.KerberosProgressPageController.extend({
+  name: 'kerberosWizardStep5Controller',
+  clusterDeployState: 'KERBEROS_DEPLOY',
+  isSingleRequestPage: true,
+  request: {
+    name: 'KERBERIZE_CLUSTER',
+    ajaxName: 'kerberize.cluster',
+    //Placeholder for the data that needs to be send with the kerberize cluster API call
+    ajaxData: {
+      context: Em.I18n.t('requestInfo.kerberizeCluster')
+    }
+  },
+  commands: []
 });

+ 32 - 1
ambari-web/app/controllers/main/admin/kerberos/step6_controller.js

@@ -19,7 +19,38 @@
 App.KerberosWizardStep6Controller = App.KerberosProgressPageController.extend({
   name: 'kerberosWizardStep6Controller',
   clusterDeployState: 'KERBEROS_DEPLOY',
-  commands: ['stopServices','startServices']
+  commands: ['stopServices','startServices'],
+
+  stopServices: function () {
+    App.ajax.send({
+      name: 'common.services.update',
+      data: {
+        context: "Stop services",
+        "ServiceInfo": {
+          "state": "INSTALLED"
+        }
+      },
+      sender: this,
+      success: 'startPolling',
+      error: 'onTaskError'
+    });
+  },
+
+  startServices: function () {
+    App.ajax.send({
+      name: 'common.services.update',
+      sender: this,
+      data: {
+        "context": "Start services",
+        "ServiceInfo": {
+          "state": "STARTED"
+        },
+        urlParams: "params/run_smoke_test=true"
+      },
+      success: 'startPolling',
+      error: 'onTaskError'
+    });
+  }
 });
 
 

+ 7 - 7
ambari-web/app/data/HDP2/site_properties.js

@@ -2194,7 +2194,7 @@ module.exports =
       "serviceName": "KERBEROS",
       "filename": "krb5-conf.xml",
       "category": "KDC",
-      "index": 0
+      "index": 1
     },
     {
       "id": "puppet var",
@@ -2206,7 +2206,7 @@ module.exports =
       "serviceName": "KERBEROS",
       "filename": "krb5-conf.xml",
       "category": "KDC",
-      "index": 1
+      "index": 2
     },
     {
       "id": "puppet var",
@@ -2218,7 +2218,7 @@ module.exports =
       "serviceName": "KERBEROS",
       "filename": "krb5-conf.xml",
       "category": "KDC",
-      "index": 2
+      "index": 3
     },
     {
       "id": "puppet var",
@@ -2231,7 +2231,7 @@ module.exports =
       "serviceName": "KERBEROS",
       "filename": "krb5-conf.xml",
       "category": "KDC",
-      "index": 3
+      "index": 4
     },
     {
       "id": "puppet var",
@@ -2244,7 +2244,7 @@ module.exports =
       "serviceName": "KERBEROS",
       "filename": "krb5-conf.xml",
       "category": "KDC",
-      "index": 4
+      "index": 5
     },
     {
       "id": "puppet var",
@@ -2257,7 +2257,7 @@ module.exports =
       "serviceName": "KERBEROS",
       "filename": "krb5-conf.xml",
       "category": "KDC",
-      "index": 5
+      "index": 6
     },
     {
       "id": "puppet var",
@@ -2270,7 +2270,7 @@ module.exports =
       "serviceName": "KERBEROS",
       "filename": "krb5-conf.xml",
       "category": "KDC",
-      "index": 5
+      "index": 7
     },
     {
       "id": "puppet var",

+ 11 - 2
ambari-web/app/messages.js

@@ -249,7 +249,9 @@ Em.I18n.translations = {
   'passiveState.turnOffFor':'Turn Off Maintenance Mode for {0}',
 
   'requestInfo.installComponents':'Install Components',
+  'requestInfo.installKerbeorosComponents':'Install Kerberos Components',
   'requestInfo.installServices':'Install Services',
+  'requestInfo.kerberosService': 'Install Kerberos Service',
   'requestInfo.startServices':'Start Services',
   'requestInfo.startAddedServices':'Start Added Services',
   'requestInfo.stopAllServices':'Stop All Services',
@@ -267,6 +269,7 @@ Em.I18n.translations = {
   'requestInfo.stop':'Stop {0}',
   'requestInfo.start':'Start {0}',
   'requestInfo.unspecified':'Request name not specified',
+  'requestInfo.kerberizeCluster': 'Kerberize Cluster',
 
   'hostPopup.noServicesToShow':'No services to show',
   'hostPopup.noHostsToShow':'No hosts to show',
@@ -891,6 +894,7 @@ Em.I18n.translations = {
 
   'wizard.progressPage.notice.completed':'Please proceed to the next step.',
   'wizard.progressPage.notice.failed':'You can click on the Retry button to retry failed tasks.',
+  'wizard.singleRequest.progressPage.notice.failed': 'Please click on the Retry link to retry the failed request.',
 
   'admin.advanced.caution':'This section is for advanced user only.<br/>Proceed with caution.',
   'admin.advanced.button.uninstallIncludingData':'Uninstall cluster including all data.',
@@ -946,11 +950,16 @@ Em.I18n.translations = {
   'admin.kerberos.wizard.step2.info.body': 'Please configure kerberos related properties.',
   'admin.kerberos.wizard.step3.task0.title': 'Install Kerberos',
   'admin.kerberos.wizard.step3.task1.title': 'Test Kerberos',
-  'admin.kerberos.wizard.step3.notice.inProgress': 'Please wait while kerberos service is being installed and tested.',
+  'admin.kerberos.wizard.step3.notice.inProgress': 'Please wait while kerberos is being installed and tested.',
   'admin.kerberos.wizard.step3.notice.completed': 'Kerberos service has been installed and tested successfully.',
   'admin.kerberos.wizard.progressPage.notice.inProgress': 'Please wait while cluster is being kerberized',
   'admin.kerberos.wizard.step4.info.body': 'Configure principal name and keytab location for service users and hadoop service components.',
-  'admin.kerberos.wizard.step6.notice.completed': 'Cluster has been successfully kerberized.',
+  'admin.kerberos.wizard.step5.notice.inProgress': 'Please wait while cluster is being kerberized.',
+  'admin.kerberos.wizard.step5.notice.completed': 'Cluster has been successfully kerberized.',
+  'admin.kerberos.wizard.step6.notice.inProgress': 'Please wait while services are being restarted and tested.',
+  'admin.kerberos.wizard.step6.notice.completed': 'Services have been successfully tested with kerberos environment.',
+  'admin.kerberos.wizard.step6.task0.title' : 'Stop Services',
+  'admin.kerberos.wizard.step6.task1.title' : 'Start Services',
 
   'admin.highAvailability':' High Availability',
   'admin.highAvailability.button.enable':'Enable NameNode HA',

+ 154 - 12
ambari-web/app/mixins/wizard/wizardProgressPageController.js

@@ -35,40 +35,169 @@ App.wizardProgressPageControllerMixin = Em.Mixin.create({
   POLL_INTERVAL: 4000,
   isSubmitDisabled: true,
   isBackButtonDisabled: true,
+  stages: [],
+  currentPageRequestId: null,
+  isSingleRequestPage: false,
+  isCommandLevelRetry: function () {
+    return !this.get('isSingleRequestPage');
+  }.property('isSingleRequestPage'),
+  showRetry: false,
+
+  k: Em.K,
   /**
    *  tasksMessagesPrefix should be overloaded by any controller including the mixin
    */
   tasksMessagesPrefix: '',
 
   loadStep: function () {
+    var self = this;
+    if (!self.isSingleRequestPage) {
+      this.initStep();
+    } else {
+      var runningOperations = App.router.get('backgroundOperationsController.services').filterProperty('isRunning');
+      var currentOperation = runningOperations.findProperty('name', this.request.ajaxData.context);
+      if (!currentOperation) {
+        this.submitRequest().done(function (data) {
+          if (data) {
+            self.set('currentPageRequestId', data.Requests.id);
+            self.doPollingForPageRequest();
+          } else {
+            //Step has been successfully completed
+          }
+        });
+      } else {
+        self.set('currentPageRequestId',currentOperation.get('id'));
+        self.doPollingForPageRequest();
+      }
+    }
+  },
+
+  initStep: function () {
     this.clearStep();
     this.initializeTasks();
-    this.loadTasks();
+    if (!this.isSingleRequestPage) {
+      this.loadTasks();
+    }
     this.addObserver('tasks.@each.status', this, 'onTaskStatusChange');
-    this.onTaskStatusChange();
+    if (this.isSingleRequestPage) {
+      var dfd = $.Deferred();
+      var dfdObject = {
+        deferred: dfd,
+        isJqueryPromise: true
+      };
+      this.onTaskStatusChange(dfdObject);
+      return dfd.promise();
+    } else {
+      this.onTaskStatusChange();
+    }
   },
 
   clearStep: function () {
+    this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
     this.set('isSubmitDisabled', true);
     this.set('isBackButtonDisabled', true);
     this.set('tasks', []);
     this.set('currentRequestIds', []);
   },
 
+  retry: function () {
+    this.set('showRetry', false);
+    this.get('tasks').setEach('status','PENDING');
+    this.loadStep();
+  },
+
+  submitRequest: function () {
+    var dfd;
+    var self = this;
+    dfd = App.ajax.send({
+      name: self.request.ajaxName,
+      data: self.request.ajaxData,
+      sender: this
+    });
+    return dfd.promise();
+  },
+
+  doPollingForPageRequest: function () {
+    App.ajax.send({
+      name: 'admin.poll.kerberize.cluster.request',
+      sender: this,
+      data: {
+        requestId: this.get('currentPageRequestId')
+      },
+      success: 'initializeStages'
+    });
+  },
+
+  initializeStages: function (data) {
+    var self = this;
+    var stages = [];
+    this.set('logs', []);
+    data.stages.forEach(function (_stage) {
+      stages.pushObject(Em.Object.create(_stage.Stage));
+    }, this);
+    if (!this.get('stages').length) {
+      this.get('stages').pushObjects(stages);
+      this.initStep().done(function(){
+        self.updatePageWithPolledData(data);
+      });
+    } else {
+      this.updatePageWithPolledData(data);
+    }
+  },
+
+  updatePageWithPolledData: function(data) {
+    var self = this;
+    var tasks = [];
+    var currentPageRequestId = this.get('currentPageRequestId');
+    var currentTaskId = this.get('currentTaskId');
+    var currentTask = this.get('tasks').findProperty('id', currentTaskId);
+    var currentStage =  data.stages.findProperty('Stage.stage_id', currentTask.get('stageId'));
+    var tasksInCurrentStage =  currentStage.tasks;
+    this.set('logs',tasksInCurrentStage);
+
+    this.setRequestIds(this.get('currentTaskId'), [this.get('currentPageRequestId')]);
+
+    if (!tasksInCurrentStage.someProperty('Tasks.status', 'PENDING') && !tasksInCurrentStage.someProperty('Tasks.status', 'QUEUED') && !tasksInCurrentStage.someProperty('Tasks.status', 'IN_PROGRESS')) {
+      this.set('currentRequestIds', []);
+      if (tasksInCurrentStage.someProperty('Tasks.status', 'FAILED') || tasksInCurrentStage.someProperty('Tasks.status', 'TIMEDOUT') || tasksInCurrentStage.someProperty('Tasks.status', 'ABORTED')) {
+        this.setTaskStatus(currentTaskId, 'FAILED');
+      } else {
+        this.setTaskStatus(currentTaskId, 'COMPLETED');
+      }
+    } else {
+      var completedActions = tasksInCurrentStage.filterProperty('Tasks.status', 'COMPLETED').length
+        + tasksInCurrentStage.filterProperty('Tasks.status', 'FAILED').length
+        + tasksInCurrentStage.filterProperty('Tasks.status', 'ABORTED').length
+        + tasksInCurrentStage.filterProperty('Tasks.status', 'TIMEDOUT').length;
+      var queuedActions = tasksInCurrentStage.filterProperty('Tasks.status', 'QUEUED').length;
+      var inProgressActions = tasksInCurrentStage.filterProperty('Tasks.status', 'IN_PROGRESS').length;
+      var progress = Math.ceil(((queuedActions * 0.09) + (inProgressActions * 0.35) + completedActions ) / tasksInCurrentStage.length * 100);
+      this.get('tasks').findProperty('id', currentTaskId).set('progress', progress);
+    }
+
+    if (!(this.get('status') === 'COMPLETED')) {
+      window.setTimeout(function () {
+        self.doPollingForPageRequest();
+      }, self.POLL_INTERVAL);
+    }
+  },
+
   initializeTasks: function () {
-    var commands = this.get('commands');
+    var self = this;
+    var commands = this.isSingleRequestPage ? this.get('stages') : this.get('commands');
     var currentStep = App.router.get(this.get('content.controllerName') + '.currentStep');
     var tasksMessagesPrefix = this.get('tasksMessagesPrefix');
     for (var i = 0; i < commands.length; i++) {
       this.get('tasks').pushObject(Ember.Object.create({
-        title: Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
+        title: self.isSingleRequestPage ? commands[i].get('context') : Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
         status: 'PENDING',
         id: i,
-        command: commands[i],
+        stageId: self.isSingleRequestPage ? commands[i].get('stage_id') : null,
+        command: self.isSingleRequestPage ? 'k' : commands[i],
         showRetry: false,
         showRollback: false,
-        name: Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
-        displayName: Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
+        name: self.isSingleRequestPage ? commands[i].get('context') : Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
+        displayName: self.isSingleRequestPage ? commands[i].get('context') : Em.I18n.t(tasksMessagesPrefix + currentStep + '.task' + i + '.title'),
         progress: 0,
         isRunning: false,
         requestIds: []
@@ -113,7 +242,7 @@ App.wizardProgressPageControllerMixin = Em.Mixin.create({
     task.set('status', 'PENDING');
   },
 
-  onTaskStatusChange: function () {
+  onTaskStatusChange: function (dfdObject) {
     var statuses = this.get('tasks').mapProperty('status');
     var tasksRequestIds = this.get('tasks').mapProperty('requestIds');
     var requestIds = this.get('currentRequestIds');
@@ -123,24 +252,29 @@ App.wizardProgressPageControllerMixin = Em.Mixin.create({
     App.router.get(this.get('content.controllerName')).saveRequestIds(requestIds);
     // call saving of cluster status asynchronous
     // synchronous executing cause problems in Firefox
+    var successCallbackData;
+    if (dfdObject && dfdObject.isJqueryPromise) {
+      successCallbackData =  {deferred: dfdObject.deferred};
+    }
     App.clusterStatus.setClusterStatus({
       clusterName: App.router.getClusterName(),
       clusterState: this.get('clusterDeployState'),
       wizardControllerName: this.get('content.controllerName'),
       localdb: App.db.data
-    }, {successCallback: this.statusChangeCallback, sender: this});
+    }, {successCallback: this.statusChangeCallback, sender: this, successCallbackData: successCallbackData});
   },
 
   /**
    * Method that called after saving persist data to server.
    * Switch task according its status.
    */
-  statusChangeCallback: function () {
+  statusChangeCallback: function (data) {
     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.set('status', 'IN_PROGRESS');
-        this.setTaskStatus(nextTask.get('id'), 'QUEUED');
+        var taskStatus = this.isSingleRequestPage ? 'IN_PROGRESS' : 'QUEUED';
+        this.setTaskStatus(nextTask.get('id'), taskStatus);
         this.set('currentTaskId', nextTask.get('id'));
         this.runTask(nextTask.get('id'));
       } else {
@@ -151,13 +285,21 @@ App.wizardProgressPageControllerMixin = Em.Mixin.create({
     } else if (this.get('tasks').someProperty('status', 'FAILED')) {
       this.set('status', 'FAILED');
       this.set('isBackButtonDisabled', false);
-      this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
+      if (this.get('isCommandLevelRetry')) {
+        this.get('tasks').findProperty('status', 'FAILED').set('showRetry', true);
+      } else {
+        this.set('showRetry', true);
+      }
       if (App.supports.autoRollbackHA) {
         this.get('tasks').findProperty('status', 'FAILED').set('showRollback', true);
       }
     }
     this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showRetry', false);
     this.get('tasks').filterProperty('status', 'COMPLETED').setEach('showRollback', false);
+
+    if (data && data.deferred) {
+      data.deferred.resolve();
+    }
   },
 
   /**

+ 4 - 2
ambari-web/app/mixins/wizard/wizardProgressPageView.js

@@ -43,7 +43,9 @@ App.wizardProgressPageViewMixin = Em.Mixin.create({
 
   noticeCompleted: Em.I18n.t('wizard.progressPage.notice.completed'),
 
-  noticeFailed: Em.I18n.t('wizard.progressPage.notice.failed'),
+  noticeFailed: function() {
+    return (this.get('controller.isSingleRequestPage') ? Em.I18n.t('wizard.singleRequest.progressPage.notice.failed') : Em.I18n.t('wizard.progressPage.notice.failed'))
+  }.property('controller.isSingleRequestPage'),
 
   /**
    * @noticeInProgress: Following computed property needs to be overridden to show the label text while the commands
@@ -109,7 +111,7 @@ App.wizardProgressPageViewMixin = Em.Mixin.create({
         this.set('iconColor', '');
         this.set('linkClass', 'not-active-link');
       }
-    }.observes('content.status', 'content.hosts.length'),
+    }.observes('content.status', 'content.hosts.length','content.requestIds'),
 
     showProgressBar: function () {
       return this.get('content.status') === "IN_PROGRESS";

+ 6 - 3
ambari-web/app/models/cluster_states.js

@@ -182,8 +182,11 @@ App.clusterStatus = Em.Object.create(App.UserPref, {
    * @param {object} newValue
    * @param {object} opt - Can have additional params for ajax callBacks and sender
    *                 opt.successCallback
+   *                 opt.successCallbackData
    *                 opt.errorCallback
+   *                 opt.errorCallbackData
    *                 opt.alwaysCallback
+   *                 opt.alwaysCallbackData
    *                 opt.sender
    * @method setClusterStatus
    * @return {*}
@@ -232,13 +235,13 @@ App.clusterStatus = Em.Object.create(App.UserPref, {
       }
       this.postUserPref(this.get('key'), val)
           .done(function () {
-            !!opt && Em.typeOf(opt.successCallback) === 'function' && opt.successCallback.call(opt.sender || this);
+            !!opt && Em.typeOf(opt.successCallback) === 'function' && opt.successCallback.call(opt.sender || this, opt.successCallbackData);
           })
           .fail(function () {
-            !!opt && Em.typeOf(opt.errorCallback) === 'function' && opt.errorCallback.call(opt.sender || this);
+            !!opt && Em.typeOf(opt.errorCallback) === 'function' && opt.errorCallback.call(opt.sender || this, opt.errorCallbackData);
           })
           .always(function () {
-            !!opt && Em.typeOf(opt.alwaysCallback) === 'function' && opt.alwaysCallback.call(opt.sender || this);
+            !!opt && Em.typeOf(opt.alwaysCallback) === 'function' && opt.alwaysCallback.call(opt.sender || this, opt.alwaysCallbackData);
           });
       return newValue;
     }

+ 2 - 1
ambari-web/app/routes/add_kerberos_routes.js

@@ -216,9 +216,10 @@ module.exports = App.WizardRoute.extend({
     connectOutlets: function (router) {
       console.log('in kerberosWizardController.step6:connectOutlets');
       var controller = router.get('kerberosWizardController');
+      controller.setLowerStepsDisable(6);
       controller.dataLoading().done(function () {
         controller.loadAllPriorSteps();
-        controller.connectOutlet('kerberosWizardStep5', controller.get('content'));
+        controller.connectOutlet('kerberosWizardStep6', controller.get('content'));
       })
     },
     unroutePath: function () {

+ 1 - 1
ambari-web/app/templates.js

@@ -21,4 +21,4 @@
 // load templates here
 
 require('templates/main/service/info/summary/base');
-require('templates/main/admin/highAvailability/progress');
+require('templates/common/progress');

+ 74 - 0
ambari-web/app/templates/common/progress.hbs

@@ -0,0 +1,74 @@
+{{!
+* 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.
+}}
+<div id="ha-progress-page">
+  <h2>{{view.headerTitle}}</h2>
+
+  <div {{bindAttr class="view.noticeClass"}}>{{{view.notice}}}
+    {{#if controller.showRetry}}
+      <a href="#" {{action retry target="controller"}}>
+        {{t common.retry}}
+      </a>
+    {{/if}}
+  </div>
+  {{#each task in controller.tasks}}
+    {{#view view.taskView contentBinding="task"}}
+      <div class="item">
+        <div {{bindAttr class=":pull-left view.linkClass isKerberosWizard:span4 controller.isHA:span4 controller.isRMHA:span5 controller.isRollback:span3 controller.isReassign:span5"}}>
+          <i {{bindAttr class="view.icon view.iconColor"}}></i>
+          <a {{action "showHostProgressPopup" task target="controller"}} >{{task.title}}</a>
+        </div>
+        <div {{bindAttr class="view.showProgressBar::hide :row :span5 :pull-left" }}>
+          <div {{bindAttr class=":progress-bar controller.isRollback::span8 controller.isRollback:span3"}}>
+            <div class="progress-striped active progress-info progress">
+              <div class="bar" {{bindAttr style="view.barWidth"}}></div>
+            </div>
+          </div>
+          <div {{bindAttr class=":span1 view.hidePercent:noDisplay"}}>{{task.progress}}&#37;</div>
+        </div>
+        <div>
+          {{#if task.showRetry}}
+            <a {{action retryTask target="controller"}} class="btn btn-primary retry"
+                                                        rel="tooltip"
+                                                        data-trigger="click" {{bindAttr title="view.showDBTooltip:testDBRetryTooltip"}}>
+              <i class="icon-repeat icon-white"></i>
+              {{t common.retry}}
+            </a>
+          {{/if}}
+          {{#if task.showRollback}}
+            <a {{action rollback target="controller"}} class="btn btn-primary retry">
+              <i class="icon-repeat icon-white"></i>
+              {{t common.rollBack}}
+            </a>
+          {{/if}}
+          {{#if task.showSkip}}
+            <a {{action skipTask target="controller"}} class="btn btn-primary retry">
+              <i class="icon-step-forward icon-white"></i>
+              {{t common.skip}}
+            </a>
+          {{/if}}
+        </div>
+      </div>
+    {{/view}}
+  {{/each}}
+  <div class="btn-area">
+    {{#if view.showBackButton}}
+      <button class="btn pull-left" {{bindAttr disabled="controller.isBackButtonDisabled"}} {{action back target="controller"}}>&larr; {{t common.back}}</button>
+    {{/if}}
+    <button class="btn btn-success pull-right" {{bindAttr disabled="controller.isSubmitDisabled"}} {{action done target="controller"}}>{{view.submitButtonText}}</button>
+  </div>
+</div>

+ 1 - 1
ambari-web/app/templates/main/admin/highAvailability/nameNode/rollback.hbs

@@ -16,6 +16,6 @@
 * limitations under the License.
 }}
 <div class="wizard">
-  {{template "templates/main/admin/highAvailability/progress"}}
+  {{template "templates/common/progress"}}
 </div>
 

+ 1 - 1
ambari-web/app/templates/main/admin/highAvailability/nameNode/step5.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 1 - 1
ambari-web/app/templates/main/admin/highAvailability/nameNode/step7.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 1 - 1
ambari-web/app/templates/main/admin/highAvailability/nameNode/step9.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 0 - 67
ambari-web/app/templates/main/admin/highAvailability/progress.hbs

@@ -1,67 +0,0 @@
-{{!
-* 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.
-}}
-<div id="ha-progress-page">
-  <h2>{{view.headerTitle}}</h2>
-
-  <div {{bindAttr class="view.noticeClass"}}>{{{view.notice}}}</div>
-  {{#each task in controller.tasks}}
-  {{#view view.taskView contentBinding="task"}}
-    <div class="item">
-      <div {{bindAttr class=":pull-left view.linkClass isKerberosWizard:span4 controller.isHA:span4 controller.isRMHA:span5 controller.isRollback:span3 controller.isReassign:span5"}}>
-        <i {{bindAttr class="view.icon view.iconColor"}}></i>
-        <a {{action "showHostProgressPopup" task target="controller"}} >{{task.title}}</a>
-      </div>
-      <div {{bindAttr class="view.showProgressBar::hide :row :span5 :pull-left" }}>
-        <div {{bindAttr class=":progress-bar controller.isRollback::span8 controller.isRollback:span3"}}>
-          <div class="progress-striped active progress-info progress">
-            <div class="bar" {{bindAttr style="view.barWidth"}}></div>
-          </div>
-        </div>
-        <div {{bindAttr class=":span1 view.hidePercent:noDisplay"}}>{{task.progress}}&#37;</div>
-      </div>
-      <div>
-      {{#if task.showRetry}}
-        <a {{action retryTask target="controller"}} class="btn btn-primary retry"
-           rel="tooltip" data-trigger="click" {{bindAttr title="view.showDBTooltip:testDBRetryTooltip"}}>
-          <i class="icon-repeat icon-white"></i>
-          {{t common.retry}}
-        </a>
-      {{/if}}
-      {{#if task.showRollback}}
-        <a {{action rollback target="controller"}} class="btn btn-primary retry">
-          <i class="icon-repeat icon-white"></i>
-          {{t common.rollBack}}
-        </a>
-      {{/if}}
-      {{#if task.showSkip}}
-        <a {{action skipTask target="controller"}} class="btn btn-primary retry">
-          <i class="icon-step-forward icon-white"></i>
-          {{t common.skip}}
-        </a>
-      {{/if}}
-      </div>
-    </div>
-  {{/view}}
-  {{/each}}
-  <div class="btn-area">
-    {{#if view.showBackButton}}
-       <button class="btn pull-left" {{bindAttr disabled="controller.isBackButtonDisabled"}} {{action back target="controller"}}>&larr; {{t common.back}}</button>
-    {{/if}}
-    <button class="btn btn-success pull-right" {{bindAttr disabled="controller.isSubmitDisabled"}} {{action done target="controller"}}>{{view.submitButtonText}}</button>
-  </div>
-</div>

+ 1 - 1
ambari-web/app/templates/main/admin/highAvailability/resourceManager/step4.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 1 - 1
ambari-web/app/templates/main/admin/kerberos/step3.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 1 - 1
ambari-web/app/templates/main/admin/kerberos/step5.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-<h2>{{t admin.kerberos.wizard.step5.header}}</h2>
+{{template "templates/common/progress"}}

+ 1 - 1
ambari-web/app/templates/main/admin/kerberos/step6.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 1 - 1
ambari-web/app/templates/main/service/reassign/step4.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 1 - 1
ambari-web/app/templates/main/service/reassign/step6.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 1 - 1
ambari-web/app/templates/main/service/reassign/step7.hbs

@@ -15,4 +15,4 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{template "templates/main/admin/highAvailability/progress"}}
+{{template "templates/common/progress"}}

+ 200 - 169
ambari-web/app/utils/ajax/ajax.js

@@ -76,6 +76,11 @@ var urls = {
     }
   },
 
+  'common.service_component.info' : {
+    'real': '/clusters/{clusterName}/services/{serviceName}/components/{componentName}?{urlParams}',
+    'mock': '/data/wizard/deploy/poll_1.json'
+  },
+
   'common.host_component.update': {
     'real': '/clusters/{clusterName}/host_components',
     'mock': '',
@@ -249,7 +254,7 @@ var urls = {
     'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}',
     'mock': '',
     'type': 'PUT',
-    'format': function(data) {
+    'format': function (data) {
       return {
         data: JSON.stringify({
           RequestInfo: {
@@ -466,49 +471,49 @@ var urls = {
         data: JSON.stringify({
           "RequestInfo": {
             "context": data.displayName + " Service Check",
-            "command" : data.actionName
+            "command": data.actionName
           },
-          "Requests/resource_filters": [{"service_name" : data.serviceName}]
+          "Requests/resource_filters": [{"service_name": data.serviceName}]
         })
       };
     }
   },
-  'service.item.rebalanceHdfsNodes' : {
-    'real' : '/clusters/{clusterName}/requests',
-    'mock' : '',
-    'format' : function(data) {
+  'service.item.rebalanceHdfsNodes': {
+    'real': '/clusters/{clusterName}/requests',
+    'mock': '',
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify({
-          RequestInfo : {
-            'context' : Em.I18n.t('services.service.actions.run.rebalanceHdfsNodes.context'),
-            'command' : 'REBALANCEHDFS',
-            'namenode' : JSON.stringify({threshold: data.threshold})
+        type: 'POST',
+        data: JSON.stringify({
+          RequestInfo: {
+            'context': Em.I18n.t('services.service.actions.run.rebalanceHdfsNodes.context'),
+            'command': 'REBALANCEHDFS',
+            'namenode': JSON.stringify({threshold: data.threshold})
           },
-          "Requests/resource_filters" : [ {
-            'service_name' : 'HDFS',
-            'component_name' : 'NAMENODE',
-            'hosts' : data.hosts
-          } ]
+          "Requests/resource_filters": [{
+            'service_name': 'HDFS',
+            'component_name': 'NAMENODE',
+            'hosts': data.hosts
+          }]
         })
       }
     }
   },
 
-  'cancel.background.operation' : {
-    'real' : '/clusters/{clusterName}/requests/{requestId}',
-    'mock' : '',
-    'format' : function(data) {
+  'cancel.background.operation': {
+    'real': '/clusters/{clusterName}/requests/{requestId}',
+    'mock': '',
+    'format': function (data) {
       return {
-        type : 'PUT',
-        data : JSON.stringify({
-          RequestInfo : {
-            'context' : 'Cancel operation',
-            "parameters" : {
-              "cancel_policy"   : "SIGKILL"
+        type: 'PUT',
+        data: JSON.stringify({
+          RequestInfo: {
+            'context': 'Cancel operation',
+            "parameters": {
+              "cancel_policy": "SIGKILL"
             }
           },
-          "Requests/request_status":'ABORTED',
+          "Requests/request_status": 'ABORTED',
           "Requests/abort_reason": "Cancel background operation"
         })
       }
@@ -516,53 +521,65 @@ var urls = {
   },
 
 
-  'service.item.refreshQueueYarnRequest':{
+  'service.item.refreshQueueYarnRequest': {
     'real': '/clusters/{clusterName}/requests',
     'mock': '',
-    'format' : function(data) {
-        return {
-          type : 'POST',
-          data : JSON.stringify({
-            RequestInfo: {
-              'context': data.context,
-              'command': data.command,
-              'parameters/forceRefreshConfigTags' : data.forceRefreshConfigTags
-            },
-            "Requests/resource_filters": [{"service_name" : data.serviceName, "component_name" : data.componentName, 'hosts': data.hosts}]
-          })
-        }
+    'format': function (data) {
+      return {
+        type: 'POST',
+        data: JSON.stringify({
+          RequestInfo: {
+            'context': data.context,
+            'command': data.command,
+            'parameters/forceRefreshConfigTags': data.forceRefreshConfigTags
+          },
+          "Requests/resource_filters": [{
+            "service_name": data.serviceName,
+            "component_name": data.componentName,
+            'hosts': data.hosts
+          }]
+        })
       }
+    }
   },
 
-  'service.item.startStopLdapKnox':{
+  'service.item.startStopLdapKnox': {
     'real': '/clusters/{clusterName}/requests',
     'mock': '',
-    'format' : function(data) {
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify({
+        type: 'POST',
+        data: JSON.stringify({
           RequestInfo: {
             'context': data.context,
             'command': data.command
           },
-          "Requests/resource_filters": [{"service_name" : data.serviceName, "component_name" : data.componentName, 'hosts': data.host}]
+          "Requests/resource_filters": [{
+            "service_name": data.serviceName,
+            "component_name": data.componentName,
+            'hosts': data.host
+          }]
         })
       }
     }
   },
 
-  'service.item.executeCustomCommand':{
+  'service.item.executeCustomCommand': {
     'real': '/clusters/{clusterName}/requests',
     'mock': '',
-    'format' : function(data) {
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify({
+        type: 'POST',
+        data: JSON.stringify({
           RequestInfo: {
             'context': data.context,
             'command': data.command
           },
-          "Requests/resource_filters": [{"service_name" : data.serviceName, "component_name" : data.componentName, 'hosts': data.hosts}]
+          "Requests/resource_filters": [{
+            "service_name": data.serviceName,
+            "component_name": data.componentName,
+            'hosts': data.hosts
+          }]
         })
       }
     }
@@ -664,7 +681,7 @@ var urls = {
   'host.host_component.add_new_component': {
     'real': '/clusters/{clusterName}/hosts?Hosts/host_name={hostName}',
     'mock': '/data/wizard/deploy/poll_1.json',
-    'format': function(data) {
+    'format': function (data) {
       return {
         type: 'POST',
         data: data.data
@@ -693,12 +710,12 @@ var urls = {
     'mock': ''
   },
   'host.host_component.decommission_slave': {
-    'real' : '/clusters/{clusterName}/requests',
-    'mock' : '',
-    'format' : function(data) {
+    'real': '/clusters/{clusterName}/requests',
+    'mock': '',
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify({
+        type: 'POST',
+        data: JSON.stringify({
           RequestInfo: {
             'context': data.context,
             'command': data.command,
@@ -713,7 +730,7 @@ var urls = {
               service_name: data.serviceName
             }
           },
-          "Requests/resource_filters": [{"service_name" : data.serviceName, "component_name" : data.componentName}]
+          "Requests/resource_filters": [{"service_name": data.serviceName, "component_name": data.componentName}]
         })
       }
     }
@@ -721,32 +738,32 @@ var urls = {
   'host.host_component.recommission_and_restart': {
     'real': '/clusters/{clusterName}/request_schedules',
     'mock': '',
-    'format' : function(data) {
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify([ {
-          "RequestSchedule" : {
-            "batch" : [ {
-              "requests" : data.batches
+        type: 'POST',
+        data: JSON.stringify([{
+          "RequestSchedule": {
+            "batch": [{
+              "requests": data.batches
             }, {
-              "batch_settings" : {
-                "batch_separation_in_seconds" : data.intervalTimeSeconds,
-                "task_failure_tolerance" : data.tolerateSize
+              "batch_settings": {
+                "batch_separation_in_seconds": data.intervalTimeSeconds,
+                "task_failure_tolerance": data.tolerateSize
               }
-            } ]
+            }]
           }
-        } ])
+        }])
       }
     }
   },
 
   'host.host_component.refresh_configs': {
-    'real':'/clusters/{clusterName}/requests',
-    'mock':'',
-    'format': function(data) {
+    'real': '/clusters/{clusterName}/requests',
+    'mock': '',
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify({
+        type: 'POST',
+        data: JSON.stringify({
           "RequestInfo": {
             "command": "CONFIGURE",
             "context": data.context
@@ -993,27 +1010,27 @@ var urls = {
     'mock': '',
     'testInProduction': true
   },
-  'service.metrics.kafka.broker.topic' : {
+  'service.metrics.kafka.broker.topic': {
     'real': '/clusters/{clusterName}/services/KAFKA/components/KAFKA_BROKER?fields=metrics/kafka/server/BrokerTopicMetrics/AllTopicsBytesInPerSec/1MinuteRate[{fromSeconds},{toSeconds},{stepSeconds}],metrics/kafka/server/BrokerTopicMetrics/AllTopicsBytesOutPerSec/1MinuteRate[{fromSeconds},{toSeconds},{stepSeconds}],metrics/kafka/server/BrokerTopicMetrics/AllTopicsMessagesInPerSec/1MinuteRate[{fromSeconds},{toSeconds},{stepSeconds}]',
     'mock': ''
   },
-  'service.metrics.kafka.controller.KafkaController' : {
+  'service.metrics.kafka.controller.KafkaController': {
     'real': '/clusters/{clusterName}/services/KAFKA/components/KAFKA_BROKER?fields=metrics/kafka/controller/KafkaController/ActiveControllerCount[{fromSeconds},{toSeconds},{stepSeconds}]',
     'mock': ''
   },
-  'service.metrics.kafka.controller.ControllerStats' : {
+  'service.metrics.kafka.controller.ControllerStats': {
     'real': '/clusters/{clusterName}/services/KAFKA/components/KAFKA_BROKER?fields=metrics/kafka/controller/ControllerStats/LeaderElectionRateAndTimeMs/1MinuteRate[{fromSeconds},{toSeconds},{stepSeconds}],metrics/kafka/controller/ControllerStats/UncleanLeaderElectionsPerSec/1MinuteRate[{fromSeconds},{toSeconds},{stepSeconds}]',
     'mock': ''
   },
-  'service.metrics.kafka.log.LogFlushStats' : {
+  'service.metrics.kafka.log.LogFlushStats': {
     'real': '/clusters/{clusterName}/services/KAFKA/components/KAFKA_BROKER?fields=metrics/kafka/log/LogFlushStats/LogFlushRateAndTimeMs/1MinuteRate[{fromSeconds},{toSeconds},{stepSeconds}]',
     'mock': ''
   },
-  'service.metrics.kafka.server.ReplicaManager' : {
+  'service.metrics.kafka.server.ReplicaManager': {
     'real': '/clusters/{clusterName}/services/KAFKA/components/KAFKA_BROKER?fields=metrics/kafka/server/ReplicaManager/PartitionCount[{fromSeconds},{toSeconds},{stepSeconds}],metrics/kafka/server/ReplicaManager/UnderReplicatedPartitions[{fromSeconds},{toSeconds},{stepSeconds}],metrics/kafka/server/BrokerTopicMetrics/ReplicaManager/LeaderCount[{fromSeconds},{toSeconds},{stepSeconds}]',
     'mock': ''
   },
-  'service.metrics.kafka.server.ReplicaFetcherManager' : {
+  'service.metrics.kafka.server.ReplicaFetcherManager': {
     'real': '/clusters/{clusterName}/services/KAFKA/components/KAFKA_BROKER?fields=metrics/kafka/server/ReplicaFetcherManager/Replica-MaxLag[{fromSeconds},{toSeconds},{stepSeconds}]',
     'mock': ''
   },
@@ -1074,7 +1091,7 @@ var urls = {
   'admin.security_status': {
     'real': '/clusters/{clusterName}?fields=Clusters/desired_configs',
     'mock': '',
-    'format': function() {
+    'format': function () {
       return {
         timeout: 10000
       };
@@ -1167,7 +1184,7 @@ var urls = {
     'real': '/clusters/{clusterName}/services?ServiceInfo/service_name=HDFS',
     'mock': '',
     'type': 'POST',
-    'format': function() {
+    'format': function () {
       return {
         data: JSON.stringify({
           "components": [
@@ -1185,7 +1202,7 @@ var urls = {
     'real': '/clusters/{clusterName}/services?ServiceInfo/service_name={serviceName}',
     'mock': '',
     'type': 'POST',
-    'format': function(data) {
+    'format': function (data) {
       return {
         data: JSON.stringify({
           "components": [
@@ -1203,7 +1220,7 @@ var urls = {
     'real': '/clusters/{clusterName}/services?ServiceInfo/service_name=HDFS',
     'mock': '',
     'type': 'POST',
-    'format': function() {
+    'format': function () {
       return {
         data: JSON.stringify({
           "components": [
@@ -1246,7 +1263,7 @@ var urls = {
   'admin.security.cluster_configs': {
     'real': '/clusters/{clusterName}',
     'mock': '',
-    'format': function() {
+    'format': function () {
       return {
         timeout: 10000
       };
@@ -1255,7 +1272,7 @@ var urls = {
   'admin.get.all_configurations': {
     'real': '/clusters/{clusterName}/configurations?{urlParams}',
     'mock': '',
-    'format': function() {
+    'format': function () {
       return {
         timeout: 10000
       };
@@ -1264,12 +1281,26 @@ var urls = {
   'admin.security.add.cluster_configs': {
     'real': '/clusters/{clusterName}' + '?fields=Clusters/desired_configs',
     'mock': '',
-    'format': function() {
+    'format': function () {
       return {
         timeout: 10000
       };
     }
   },
+  'admin.kerberize.cluster': {
+    'type': 'POST',
+    'real': '/clusters/{clusterName}',
+    'mock': '/data/wizard/kerberos/kerberize_cluster.json',
+    'format' : function () {
+      return {
+        data: '{"RequestInfo": {"context" :"' + Em.I18n.t('requestInfo.kerberizeCluster') + '"}'
+      }
+    }
+  },
+  'admin.poll.kerberize.cluster.request': {
+    'real': '/clusters/{clusterName}/requests/{requestId}?fields=stages/Stage/context,stages/Stage/status,stages/Stage/progress_percent,stages/tasks/*,Requests/*',
+    'mock': '/data/wizard/kerberos/kerberize_cluster.json'
+  },
   'admin.stack_upgrade.run_upgrade': {
     'real': '/clusters/{clusterName}',
     'mock': '',
@@ -1283,7 +1314,7 @@ var urls = {
   'admin.user.create': {
     'real': '/users/{user}',
     'mock': '/data/users/users.json',
-    'format': function(data) {
+    'format': function (data) {
       return {
         type: 'POST',
         data: JSON.stringify(data.data)
@@ -1293,8 +1324,8 @@ var urls = {
 
   'admin.user.edit': {
     'real': '/users/{user}',
-    'mock':'/data/users/users.json',
-    'format': function(data) {
+    'mock': '/data/users/users.json',
+    'format': function (data) {
       return {
         type: 'PUT',
         data: data.data
@@ -1317,7 +1348,7 @@ var urls = {
   'admin.stack_version.install.repo_version': {
     'type': 'POST',
     'real': 'clusters/{clusterName}/requests',
-    'format': function(data) {
+    'format': function (data) {
       return {
         type: 'POST',
         dataType: 'text',
@@ -1341,7 +1372,7 @@ var urls = {
   'wizard.service_components': {
     'real': '{stackUrl}/services?fields=StackServices/*,serviceComponents/*,serviceComponents/dependencies/Dependencies/scope',
     'mock': '/data/stacks/HDP-2.1/service_components.json',
-    'format': function(data) {
+    'format': function (data) {
       return {
         timeout: 10000
       };
@@ -1367,9 +1398,9 @@ var urls = {
   },
 
   'wizard.step8.create_cluster': {
-    'real':'/clusters/{cluster}',
-    'mock':'',
-    'format': function(data) {
+    'real': '/clusters/{cluster}',
+    'mock': '',
+    'format': function (data) {
       return {
         type: 'POST',
         dataType: 'text',
@@ -1380,9 +1411,9 @@ var urls = {
 
   'wizard.step8.create_selected_services': {
     'type': 'POST',
-    'real':'/clusters/{cluster}/services',
-    'mock':'/data/stacks/HDP-2.1/recommendations.json',
-    'format': function(data) {
+    'real': '/clusters/{cluster}/services',
+    'mock': '/data/stacks/HDP-2.1/recommendations.json',
+    'format': function (data) {
       return {
         dataType: 'text',
         data: data.data
@@ -1391,9 +1422,9 @@ var urls = {
   },
 
   'wizard.step8.create_components': {
-    'real':'/clusters/{cluster}/services?ServiceInfo/service_name={serviceName}',
-    'mock':'',
-    'format': function(data) {
+    'real': '/clusters/{cluster}/services?ServiceInfo/service_name={serviceName}',
+    'mock': '',
+    'format': function (data) {
       return {
         type: 'POST',
         dataType: 'text',
@@ -1403,9 +1434,9 @@ var urls = {
   },
 
   'wizard.step8.register_host_to_cluster': {
-    'real':'/clusters/{cluster}/hosts',
-    'mock':'',
-    'format': function(data) {
+    'real': '/clusters/{cluster}/hosts',
+    'mock': '',
+    'format': function (data) {
       return {
         type: 'POST',
         dataType: 'text',
@@ -1415,9 +1446,9 @@ var urls = {
   },
 
   'wizard.step8.register_host_to_component': {
-    'real':'/clusters/{cluster}/hosts',
-    'mock':'',
-    'format': function(data) {
+    'real': '/clusters/{cluster}/hosts',
+    'mock': '',
+    'format': function (data) {
       return {
         type: 'POST',
         dataType: 'text',
@@ -1427,9 +1458,9 @@ var urls = {
   },
 
   'wizard.step8.apply_configuration_groups': {
-    'real':'/clusters/{cluster}/config_groups',
-    'mock':'',
-    'format': function(data) {
+    'real': '/clusters/{cluster}/config_groups',
+    'mock': '',
+    'format': function (data) {
       return {
         type: 'POST',
         dataType: 'text',
@@ -1439,9 +1470,9 @@ var urls = {
   },
 
   'wizard.step8.set_local_repos': {
-    'real':'{stackVersionURL}/operating_systems/{osType}/repositories/{repoId}',
-    'mock':'',
-    'format': function(data) {
+    'real': '{stackVersionURL}/operating_systems/{osType}/repositories/{repoId}',
+    'mock': '',
+    'format': function (data) {
       return {
         type: 'PUT',
         dataType: 'text',
@@ -1459,11 +1490,11 @@ var urls = {
           "RequestInfo": {
             "context": "Check hosts",
             "action": "check_host",
-            "parameters" : {
-              "threshold" : "60",
-              "java_home" : data.java_home,
+            "parameters": {
+              "threshold": "60",
+              "java_home": data.java_home,
               "jdk_location": data.jdk_location,
-              "check_execute_list" : "java_home_check"
+              "check_execute_list": "java_home_check"
             }
           },
           "Requests/resource_filters": [{
@@ -1480,7 +1511,7 @@ var urls = {
   'wizard.step3.host_info': {
     'real': '/hosts?fields=Hosts/total_mem,Hosts/cpu_count,Hosts/disk_info,Hosts/last_agent_env,Hosts/host_name,Hosts/os_type,Hosts/os_arch,Hosts/ip',
     'mock': '/data/wizard/bootstrap/two_hosts_information.json',
-    'format': function() {
+    'format': function () {
       return {
         contentType: 'application/json'
       };
@@ -1533,11 +1564,11 @@ var urls = {
     'type': 'POST',
     'format': function (data) {
       return {
-          data: JSON.stringify({
-            hosts: data.hosts,
-            services: data.services,
-            validate: data.validate,
-            recommendations: data.recommendations
+        data: JSON.stringify({
+          hosts: data.hosts,
+          services: data.services,
+          validate: data.validate,
+          recommendations: data.recommendations
         })
       }
     }
@@ -1545,12 +1576,12 @@ var urls = {
 
 
   'preinstalled.checks': {
-    'real':'/requests',
-    'mock':'',
-    'format': function(data) {
+    'real': '/requests',
+    'mock': '',
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify({
+        type: 'POST',
+        data: JSON.stringify({
           "RequestInfo": data.RequestInfo,
           "Requests/resource_filters": [data.resource_filters]
         })
@@ -1559,14 +1590,14 @@ var urls = {
   },
 
   'preinstalled.checks.tasks': {
-    'real':'/requests/{requestId}?fields=tasks/Tasks',
-    'mock':'/data/requests/host_check/1.json'
+    'real': '/requests/{requestId}?fields=tasks/Tasks',
+    'mock': '/data/requests/host_check/1.json'
   },
 
   'wizard.step3.rerun_checks': {
     'real': '/hosts?fields=Hosts/last_agent_env',
     'mock': '/data/wizard/bootstrap/two_hosts_information.json',
-    'format': function() {
+    'format': function () {
       return {
         contentType: 'application/json'
       };
@@ -1681,21 +1712,21 @@ var urls = {
   'rolling_restart.post': {
     'real': '/clusters/{clusterName}/request_schedules',
     'mock': '',
-    'format' : function(data) {
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify([ {
-          "RequestSchedule" : {
-            "batch" : [ {
-              "requests" : data.batches
+        type: 'POST',
+        data: JSON.stringify([{
+          "RequestSchedule": {
+            "batch": [{
+              "requests": data.batches
             }, {
-              "batch_settings" : {
-                "batch_separation_in_seconds" : data.intervalTimeSeconds,
-                "task_failure_tolerance" : data.tolerateSize
+              "batch_settings": {
+                "batch_separation_in_seconds": data.intervalTimeSeconds,
+                "task_failure_tolerance": data.tolerateSize
               }
-            } ]
+            }]
           }
-        } ])
+        }])
       }
     }
   },
@@ -1704,12 +1735,12 @@ var urls = {
     'mock': ''
   },
   'restart.hostComponents': {
-    'real':'/clusters/{clusterName}/requests',
-    'mock':'',
-    'format': function(data) {
+    'real': '/clusters/{clusterName}/requests',
+    'mock': '',
+    'format': function (data) {
       return {
-        type : 'POST',
-        data : JSON.stringify({
+        type: 'POST',
+        data: JSON.stringify({
           "RequestInfo": {
             "command": "RESTART",
             "context": data.context,
@@ -1872,9 +1903,9 @@ var urls = {
   },
 
   'bulk_request.decommission': {
-    'real' : '/clusters/{clusterName}/requests',
-    'mock' : '',
-    'format': function(data) {
+    'real': '/clusters/{clusterName}/requests',
+    'mock': '',
+    'format': function (data) {
       return {
         type: 'POST',
         data: JSON.stringify({
@@ -1887,7 +1918,7 @@ var urls = {
               'cluster_name': data.clusterName
             }
           },
-          "Requests/resource_filters": [{"service_name" : data.serviceName, "component_name" : data.componentName}]
+          "Requests/resource_filters": [{"service_name": data.serviceName, "component_name": data.componentName}]
         })
       }
     }
@@ -1896,7 +1927,7 @@ var urls = {
   'bulk_request.hosts.passive_state': {
     'real': '/clusters/{clusterName}/hosts',
     'mock': '',
-    'format': function(data) {
+    'format': function (data) {
       return {
         type: 'PUT',
         data: JSON.stringify({
@@ -1917,7 +1948,7 @@ var urls = {
   'bulk_request.hosts.all_components.passive_state': {
     'real': '/clusters/{clusterName}/host_components',
     'mock': '',
-    'format': function(data) {
+    'format': function (data) {
       return {
         type: 'PUT',
         data: JSON.stringify({
@@ -1961,14 +1992,14 @@ var urls = {
   'host.host_components.filtered': {
     'real': '/clusters/{clusterName}/hosts?{fields}',
     'mock': '',
-    format: function(data) {
+    format: function (data) {
       return {
         headers: {
           'X-Http-Method-Override': 'GET'
         },
         type: 'POST',
         data: JSON.stringify({
-          "RequestInfo": {"query" : data.parameters}
+          "RequestInfo": {"query": data.parameters}
         })
       };
     }
@@ -2029,11 +2060,11 @@ var urls = {
   'custom_action.create': {
     'real': '/requests',
     'mock': '',
-    'format': function(data) {
+    'format': function (data) {
       var requestInfo = {
         context: 'Check host',
         action: 'check_host',
-        parameters: { }
+        parameters: {}
       };
       $.extend(true, requestInfo, data.requestInfo);
       return {
@@ -2050,7 +2081,7 @@ var urls = {
   'custom_action.request': {
     'real': '/requests/{requestId}/tasks/{taskId}',
     'mock': '',
-    'format': function(data) {
+    'format': function (data) {
       return {
         requestId: data.requestId,
         taskId: data.taskId || ''
@@ -2084,7 +2115,7 @@ var urls = {
   'hosts.host_components.pre_load': {
     real: '',
     mock: '/data/hosts/HDP2/hosts.json',
-    format: function(data) {
+    format: function (data) {
       return {
         url: data.url
       }
@@ -2092,17 +2123,17 @@ var urls = {
   },
   'hosts.bulk.operations': {
     real: '/clusters/{clusterName}/hosts?fields=Hosts/host_name,Hosts/maintenance_state,' +
-      'host_components/HostRoles/state,host_components/HostRoles/maintenance_state,' +
-      'host_components/HostRoles/stale_configs&minimal_response=true',
+    'host_components/HostRoles/state,host_components/HostRoles/maintenance_state,' +
+    'host_components/HostRoles/stale_configs&minimal_response=true',
     mock: '',
-    format: function(data) {
+    format: function (data) {
       return {
         headers: {
           'X-Http-Method-Override': 'GET'
         },
         type: 'POST',
         data: JSON.stringify({
-          "RequestInfo": {"query" : data.parameters }
+          "RequestInfo": {"query": data.parameters}
         })
       }
     }
@@ -2126,7 +2157,7 @@ var urls = {
   'service.serviceConfigVersions.get.multiple': {
     real: '/clusters/{clusterName}/configurations/service_config_versions?service_name={serviceName}&service_config_version.in({serviceConfigVersions})',
     mock: '/data/configurations/service_version.json',
-    format: function(data) {
+    format: function (data) {
       return {
         serviceConfigVersions: data.serviceConfigVersions.join(',')
       }
@@ -2394,7 +2425,7 @@ if ($.mocho) {
      * Don't use it anywhere except tests!
      * @returns {Array}
      */
-    fakeGetUrlNames: function() {
+    fakeGetUrlNames: function () {
       return Em.keys(urls);
     },
 
@@ -2403,7 +2434,7 @@ if ($.mocho) {
      * @param name
      * @returns {*}
      */
-    fakeGetUrl: function(name) {
+    fakeGetUrl: function (name) {
       return urls[name];
     },
 
@@ -2413,7 +2444,7 @@ if ($.mocho) {
      * @param data
      * @returns {String}
      */
-    fakeFormatUrl: function(url, data) {
+    fakeFormatUrl: function (url, data) {
       return formatUrl(url, data);
     },
 
@@ -2423,7 +2454,7 @@ if ($.mocho) {
      * @param data
      * @returns {Object}
      */
-    fakeFormatRequest: function(urlObj, data) {
+    fakeFormatRequest: function (urlObj, data) {
       return formatRequest.call(urlObj, data);
     }
   });

+ 8 - 2
ambari-web/app/views/main/admin/kerberos/step5_view.js

@@ -18,8 +18,14 @@
 
 var App = require('app');
 
-App.KerberosWizardStep5View = Em.View.extend({
+App.KerberosWizardStep5View = App.KerberosProgressPageView.extend({
 
-  templateName: require('templates/main/admin/kerberos/step5')
+  templateName: require('templates/main/admin/kerberos/step5'),
+
+  noticeCompleted: Em.I18n.t('admin.kerberos.wizard.step5.notice.completed'),
+
+  submitButtonText: Em.I18n.t('common.next'),
+
+  showBackButton: true
 
 });

+ 0 - 4
ambari-web/app/views/main/admin/kerberos/wizard_view.js

@@ -22,10 +22,6 @@ App.KerberosWizardView = Em.View.extend(App.WizardMenuMixin, {
 
   templateName: require('templates/main/admin/kerberos/wizard'),
 
-  isStep5Disabled: true,
-
-  isStep6Disabled: true,
-
   isLoaded: false,
 
   willInsertElement: function () {

部分文件因文件數量過多而無法顯示