瀏覽代碼

AMBARI-1193. If Install fails, allow user to go back to any previous step so that the user can retry install with different configuration parameters. (yusaku via srimanth)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/trunk@1439615 13f79535-47bb-0310-9956-ffa450edef68
Srimanth 12 年之前
父節點
當前提交
d6a47c9761

+ 4 - 0
CHANGES.txt

@@ -34,6 +34,10 @@ Trunk (unreleased changes):
 
  IMPROVEMENTS
 
+ AMBARI-1193. If Install fails, allow user to go back to any previous step so 
+ that the user can retry install with different configuration parameters.
+ (yusaku via srimanth)
+
  AMBARI-1265. Job Browser - Filter by Input, output and duration. (yusaku)
 
  AMBARI-1263. Refactoring of User Management code. (yusaku)

+ 10 - 0
ambari-web/app/controllers/wizard.js

@@ -134,6 +134,16 @@ App.WizardController = Em.Controller.extend({
     if (this.get('isStepDisabled').findProperty('step', step).get('value') !== false) {
       return;
     }
+    // if going back from Step 9 in Install Wizard, delete the checkpoint so that the user is not redirected
+    // to Step 9
+    if (this.get('content.controllerName') == 'installerController' && this.get('currentStep') === '9' && step < 9) {
+      App.clusterStatus.setClusterStatus({
+        clusterName: this.get('clusterName'),
+        clusterState: 'CLUSTER_NOT_CREATED_1',
+        wizardControllerName: 'installerController',
+        localdb: App.db.data
+      });
+    }
     if ((this.get('currentStep') - step) > 1) {
       App.ModalPopup.show({
         header: Em.I18n.t('installer.navigation.warning.header'),

+ 90 - 43
ambari-web/app/controllers/wizard/step8_controller.js

@@ -754,49 +754,50 @@ App.WizardStep8Controller = Em.Controller.extend({
 
     this.set('isSubmitDisabled', true);
 
-    if (App.testMode || !this.get('content.cluster.requestId')) {
-      // For recovery : set the cluster status
-
-      // We need to do recovery based on whether we are in Add Host or Installer wizard
-      switch (this.get('content.controllerName')) {
-        case 'installerController' :
-          App.clusterStatus.setClusterStatus({
-            clusterName: this.get('clusterName'),
-            clusterState: 'CLUSTER_DEPLOY_PREP_2',
-            wizardControllerName: this.get('content.controllerName'),
-            localdb: App.db.data
-          });
-          break;
+    // checkpoint the cluster status on the server so that the user can resume from where they left off
+    switch (this.get('content.controllerName')) {
+      case 'installerController':
+        App.clusterStatus.setClusterStatus({
+          clusterName: this.get('clusterName'),
+          clusterState: 'CLUSTER_DEPLOY_PREP_2',
+          wizardControllerName: this.get('content.controllerName'),
+          localdb: App.db.data
+        });
+        break;
+      case 'addHostController':
+        App.clusterStatus.setClusterStatus({
+          clusterName: this.get('clusterName'),
+          clusterState: 'ADD_HOSTS_DEPLOY_PREP_2',
+          wizardControllerName: this.get('content.controllerName'),
+          localdb: App.db.data
+        });
+        break;
+      default:
+        break;
+    }
 
-        case 'addHostController' :
-          App.clusterStatus.setClusterStatus({
-            clusterName: this.get('clusterName'),
-            clusterState: 'ADD_HOSTS_DEPLOY_PREP_2',
-            wizardControllerName: this.get('content.controllerName'),
-            localdb: App.db.data
-          });
-          break;
-        default :
-          break;
-      }
+    // delete any existing clusters to start from a clean slate
+    // before creating a new cluster in install wizard
+    // TODO: modify for multi-cluster support
+    if (this.get('content.controllerName') == 'installerController') {
+      var clusterNames = this.getExistingClusterNames();
+      this.deleteClusters(clusterNames);
+    }
 
-      this.createCluster();
-      this.createSelectedServices();
-      //this.setAmbariUIDb();
-      this.createConfigurations();
-      this.applyCreatedConfToServices();
-      this.createComponents();
-      this.registerHostsToCluster();
-      this.createAllHostComponents();
-      //this.applyCreatedConfToSlaveGroups();
-      this.ajaxQueueFinished = function () {
-        console.log('everything is loaded')
-        App.router.send('next');
-      };
-      this.doNextAjaxCall();
-    } else {
+    this.createCluster();
+    this.createSelectedServices();
+    this.createConfigurations();
+    this.applyCreatedConfToServices();
+    this.createComponents();
+    this.registerHostsToCluster();
+    this.createAllHostComponents();
+
+    this.ajaxQueueFinished = function () {
+      console.log('everything is loaded')
       App.router.send('next');
-    }
+    };
+    this.doNextAjaxCall();
+
   },
 
   /**
@@ -837,6 +838,49 @@ App.WizardStep8Controller = Em.Controller.extend({
     return this.get('content.cluster.name');
   }.property('content.cluster.name'),
 
+  // returns an array of existing cluster names.
+  // returns an empty array if there are no existing clusters.
+  getExistingClusterNames: function () {
+    var url = App.apiPrefix + '/clusters';
+
+    var clusterNames = [];
+
+    $.ajax({
+      type: 'GET',
+      url: url,
+      async: false,
+      success: function(data) {
+        var jsonData = jQuery.parseJSON(data);
+        clusterNames = jsonData.items.mapProperty('Clusters.cluster_name');
+        console.log("Got existing cluster names: " + clusterNames);
+      },
+      error: function () {
+        console.log("Failed to get existing cluster names");
+      }
+    });
+
+    return clusterNames;
+  },
+
+  deleteClusters: function (clusterNames) {
+    clusterNames.forEach(function(clusterName) {
+
+      var url = App.apiPrefix + '/clusters/' + clusterName;
+
+      $.ajax({
+        type: 'DELETE',
+        url: url,
+        async: false,
+        success: function () {
+          console.log('DELETE cluster ' + clusterName + ' succeeded');
+        },
+        error: function () {
+          console.log('DELETE cluster ' + clusterName + ' failed');
+        }
+      });
+    });
+  },
+
   /**
    *  The following create* functions are called upon submitting Step 8.
    */
@@ -1444,8 +1488,8 @@ App.WizardStep8Controller = Em.Controller.extend({
   },
 
   /**
-   * We need to do a lot of ajax calls(about 10 or more) async in special order.
-   * To do this i generate array of ajax objects and then send requests step by step.
+   * We need to do a lot of ajax calls async in special order.
+   * To do this, generate array of ajax objects and then send requests step by step.
    * All ajax objects are stored in <code>ajaxQueue</code>
    * @param params
    */
@@ -1487,8 +1531,11 @@ App.WizardStep8Controller = Em.Controller.extend({
       var responseText = JSON.parse(xhr.responseText);
       var controller = App.router.get(App.clusterStatus.wizardControllerName);
       controller.registerErrPopup("Error", responseText.message);
-      self.set('isSubmitDisabled', true);
       self.set('hasErrorOccurred', true);
+      // an error will break the ajax call chain and allow submission again
+      self.set('isSubmitDisabled', false);
+      self.get('ajaxQueue').clear();
+      self.set('ajaxBusy', false);
     }
     this.get('ajaxQueue').pushObject(params);
   }

+ 9 - 0
ambari-web/app/controllers/wizard/step9_controller.js

@@ -29,6 +29,15 @@ App.WizardStep9Controller = Em.Controller.extend({
     return !['STARTED','START FAILED'].contains(this.get('content.cluster.status'));
   }.property('content.cluster.status'),
 
+  // links to previous steps are enabled iff install failed in installer
+  togglePreviousSteps: function () {
+    if ('INSTALL FAILED' === this.get('content.cluster.status') && this.get('content.controllerName') == 'installerController') {
+      App.router.get('installerController').setStepsEnable();
+    } else {
+      App.router.get('installerController').setLowerStepsDisable(9);
+    }
+  }.observes('content.cluster.status', 'content.controllerName'),
+
   mockHostData: require('data/mock/step9_hosts'),
   mockDataPrefix: '/data/wizard/deploy/5_hosts',
   pollDataCounter: 0,

+ 6 - 11
ambari-web/app/router.js

@@ -80,8 +80,6 @@ App.Router = Em.Router.extend({
   loggedIn: false,
 
   getAuthenticated: function () {
-    // TODO: this needs to be hooked up with server authentication
-//    this.authenticated();
     var auth = App.db.getAuthenticated();
     var authResp = (auth && auth === true);
     this.set('loggedIn', authResp);
@@ -89,20 +87,16 @@ App.Router = Em.Router.extend({
   },
 
   setAuthenticated: function (authenticated) {
-    // TODO: this needs to be hooked up with server authentication
     console.log("TRACE: Entering router:setAuthenticated function");
     App.db.setAuthenticated(authenticated);
     this.set('loggedIn', authenticated);
   },
 
   getLoginName: function () {
-    // TODO: this needs to be hooked up with server authentication
     return App.db.getLoginName();
-
   },
 
   setLoginName: function (loginName) {
-    // TODO: this needs to be hooked up with server authentication
     App.db.setLoginName(loginName);
   },
 
@@ -141,11 +135,12 @@ App.Router = Em.Router.extend({
     var router = this;
     var url = '';
 
-    if(loginName === "admin" && controller.get('password') === 'admin')
-    {
-      url = '/data/users/user_admin.json';
-    }else if(loginName === 'user' && controller.get('password') === 'user'){
-      url = '/data/users/user_user.json';
+    if (App.testMode) {
+      if (loginName === "admin" && controller.get('password') === 'admin') {
+        url = '/data/users/user_admin.json';
+      } else if (loginName === 'user' && controller.get('password') === 'user') {
+        url = '/data/users/user_user.json';
+      }
     }
 
     $.ajax({

+ 1 - 0
ambari-web/app/views/common/modal_popup.js

@@ -104,6 +104,7 @@ App.ModalPopup.reopenClass({
   show: function(options) {
     var popup = this.create(options);
     popup.appendTo('#wrapper');
+    return popup;
   }
 
 })

+ 15 - 6
ambari-web/app/views/wizard/step8_view.js

@@ -27,6 +27,7 @@ App.WizardStep8View = Em.View.extend({
     var controller = this.get('controller');
     controller.loadStep();
   },
+
   spinner : null,
 
   printReview: function() {
@@ -42,15 +43,22 @@ App.WizardStep8View = Em.View.extend({
     return this.get('controller.ajaxQueueLeft');
   }.property('controller.ajaxQueueLeft'),
 
+  // reference to modalPopup to make sure only one instance is created
+  modalPopup: null,
+
   showLoadingIndicator: function() {
-    if(this.get('controller.hasErrorOccurred')){
+    if (!this.get('controller.isSubmitDisabled')) {
+      if (this.get('modalPopup')) {
+        this.get('modalPopup').hide();
+        this.set('modalPopup', null);
+      }
       return;
     }
-    if(!this.get('controller.isSubmitDisabled')){
+    // don't create popup if it already exists
+    if (this.get('modalPopup')) {
       return;
     }
-
-    App.ModalPopup.show({
+    this.set('modalPopup', App.ModalPopup.show({
       header: '',
 
       showFooter: false,
@@ -80,6 +88,7 @@ App.WizardStep8View = Em.View.extend({
           }
         }.observes('ajaxQueueComplete', 'ajaxQueueLength')
       })
-    });
-  }.observes('controller.isSubmitDisabled','controller.hasErrorOccurred')
+    }));
+  }.observes('controller.isSubmitDisabled')
 });
+