Browse Source

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

Jaimin Jetly 10 năm trước cách đây
mục cha
commit
8eb500e603
30 tập tin đã thay đổi với 661 bổ sung352 xóa
  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>());
       }
     });

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 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 () {

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác