You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2014/07/15 16:46:15 UTC

git commit: AMBARI-6487 Wizard should pre-load data via asynchronous calls. (atkach)

Repository: ambari
Updated Branches:
  refs/heads/trunk de2ba0fc8 -> 08e235098


AMBARI-6487 Wizard should pre-load data via asynchronous calls. (atkach)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/08e23509
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/08e23509
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/08e23509

Branch: refs/heads/trunk
Commit: 08e2350989e5b7fb61a738fa7c8ae06b4373d8b9
Parents: de2ba0f
Author: atkach <at...@hortonworks.com>
Authored: Tue Jul 15 17:43:55 2014 +0300
Committer: atkach <at...@hortonworks.com>
Committed: Tue Jul 15 17:43:55 2014 +0300

----------------------------------------------------------------------
 .../controllers/global/cluster_controller.js    |   3 +-
 ambari-web/app/controllers/installer.js         | 245 +++++++++++++------
 .../controllers/main/service/add_controller.js  |  18 --
 ambari-web/app/controllers/wizard.js            |  35 ++-
 ambari-web/app/initialize.js                    |   1 +
 ambari-web/app/routes/installer.js              |  98 ++++----
 ambari-web/app/utils/action_sequence.js         | 140 +++++++++++
 ambari-web/app/utils/ajax/ajax.js               |  17 +-
 8 files changed, 402 insertions(+), 155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/08e23509/ambari-web/app/controllers/global/cluster_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js
index 6a48028..fd8ed2c 100644
--- a/ambari-web/app/controllers/global/cluster_controller.js
+++ b/ambari-web/app/controllers/global/cluster_controller.js
@@ -403,8 +403,7 @@ App.ClusterController = Em.Controller.extend({
       name: 'wizard.service_components',
       data: {
         stackUrl: App.get('stackVersionURL'),
-        stackVersion: App.get('currentStackVersionNumber'),
-        async: true
+        stackVersion: App.get('currentStackVersionNumber')
       },
       sender: callbackObj,
       success: 'loadStackServiceComponentsSuccess'

http://git-wip-us.apache.org/repos/asf/ambari/blob/08e23509/ambari-web/app/controllers/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/installer.js b/ambari-web/app/controllers/installer.js
index 940cf77..00f186a 100644
--- a/ambari-web/app/controllers/installer.js
+++ b/ambari-web/app/controllers/installer.js
@@ -79,21 +79,21 @@ App.InstallerController = App.WizardController.extend({
    * @param view
    * @param content
    */
-  connectOutlet: function(view, content) {
-    if(App.db.getAuthenticated()) {
+  connectOutlet: function (view, content) {
+    if (App.db.getAuthenticated()) {
       this._super(view, content);
     }
   },
 
-  getCluster: function(){
+  getCluster: function () {
     return jQuery.extend({}, this.get('clusterStatusTemplate'));
   },
 
-  getInstallOptions: function(){
+  getInstallOptions: function () {
     return jQuery.extend({}, this.get('installOptionsTemplate'));
   },
 
-  getHosts: function(){
+  getHosts: function () {
     return [];
   },
 
@@ -122,11 +122,18 @@ App.InstallerController = App.WizardController.extend({
    * Load services data. Will be used at <code>Select services(step4)</code> step
    */
   loadServices: function () {
+    var dfd = $.Deferred();
+    var self = this;
     var stackServices = App.StackService.find().mapProperty('serviceName');
     if (!(stackServices && !!stackServices.length && App.StackService.find().objectAt(0).get('stackVersion') == App.get('currentStackVersionNumber'))) {
-      this.loadServiceComponents();
-      this.set('content.services', App.StackService.find());
+      this.loadServiceComponents().complete(function () {
+        self.set('content.services', App.StackService.find());
+        dfd.resolve();
+      });
+    } else {
+      dfd.resolve();
     }
+    return dfd.promise();
   },
 
   /**
@@ -203,10 +210,16 @@ App.InstallerController = App.WizardController.extend({
   stacks: [],
 
   /**
+   * stack names used as auxiliary data to query stacks by name
+   */
+  stackNames: [],
+
+  /**
    * Load stacks data from server or take exist data from local db
    */
   loadStacks: function () {
     var stacks = App.db.getStacks();
+    var dfd = $.Deferred();
     if (stacks && stacks.length) {
       var convertedStacks = [];
       stacks.forEach(function (stack) {
@@ -214,37 +227,35 @@ App.InstallerController = App.WizardController.extend({
       });
       App.set('currentStackVersion', convertedStacks.findProperty('isSelected').get('name'));
       this.set('content.stacks', convertedStacks);
+      dfd.resolve(true);
     } else {
       App.ajax.send({
         name: 'wizard.stacks',
         sender: this,
         success: 'loadStacksSuccessCallback',
         error: 'loadStacksErrorCallback'
-      });
+      }).complete(function () {
+          dfd.resolve(false);
+        });
     }
+    return dfd.promise();
   },
 
   /**
    * Send queries to load versions for each stack
    */
   loadStacksSuccessCallback: function (data) {
-    var stacks = data.items;
-    var result;
     this.get('stacks').clear();
-    stacks.forEach(function (stack) {
-      App.ajax.send({
-        name: 'wizard.stacks_versions',
-        sender: this,
-        data: {
-          stackName: stack.Stacks.stack_name
-        },
-        success: 'loadStacksVersionsSuccessCallback',
-        error: 'loadStacksVersionsErrorCallback'
-      });
-    }, this);
-    result = this.get('stacks');
+    this.set('stackNames', data.items.mapProperty('Stacks.stack_name'));
+  },
+
+  /**
+   * set stacks from server to content and local DB
+   */
+  setStacks: function() {
+    var result = this.get('stacks');
     if (!result.length) {
-      console.log('Error: therea are no active stacks');
+      console.log('Error: there are no active stacks');
     } else {
       var defaultStackVersion = result.findProperty('name', App.defaultStackVersion);
       if (defaultStackVersion) {
@@ -265,6 +276,26 @@ App.InstallerController = App.WizardController.extend({
   },
 
   /**
+   * query every stack names from server
+   * @return {Array}
+   */
+  loadStacksVersions: function () {
+    var requests = [];
+    this.get('stackNames').forEach(function (stackName) {
+      requests.push(App.ajax.send({
+        name: 'wizard.stacks_versions',
+        sender: this,
+        data: {
+          stackName: stackName
+        },
+        success: 'loadStacksVersionsSuccessCallback',
+        error: 'loadStacksVersionsErrorCallback'
+      }));
+    }, this);
+    return requests;
+  },
+
+  /**
    * Parse loaded data and create array of stacks objects
    */
   loadStacksVersionsSuccessCallback: function (data) {
@@ -316,11 +347,11 @@ App.InstallerController = App.WizardController.extend({
         });
       }
       result.push(
-          Em.Object.create({
-            name: version.Versions.stack_name + "-" + version.Versions.stack_version,
-            isSelected: false,
-            operatingSystems: oses
-          })
+        Em.Object.create({
+          name: version.Versions.stack_name + "-" + version.Versions.stack_version,
+          isSelected: false,
+          operatingSystems: oses
+        })
       );
     }, this);
     this.get('stacks').pushObjects(result);
@@ -344,7 +375,7 @@ App.InstallerController = App.WizardController.extend({
     });
     return dfd.promise();
   },
-  getServerVersion: function(){
+  getServerVersion: function () {
     return App.ajax.send({
       name: 'ambari.service.load_server_version',
       sender: this,
@@ -423,7 +454,7 @@ App.InstallerController = App.WizardController.extend({
       masterComponentHosts = [];
     }
     else {
-      masterComponentHosts.forEach(function(component) {
+      masterComponentHosts.forEach(function (component) {
         for (var i = 0; i < host_names.length; i++) {
           if (hosts[host_names[i]].id === component.host_id) {
             component.hostName = host_names[i];
@@ -443,8 +474,8 @@ App.InstallerController = App.WizardController.extend({
       hosts = this.getDBProperty('hosts'),
       host_names = Em.keys(hosts);
     if (!Em.isNone(slaveComponentHosts)) {
-      slaveComponentHosts.forEach(function(component) {
-        component.hosts.forEach(function(host) {
+      slaveComponentHosts.forEach(function (component) {
+        component.hosts.forEach(function (host) {
           for (var i = 0; i < host_names.length; i++) {
             if (hosts[host_names[i]].id === host.host_id) {
               host.hostName = host_names[i];
@@ -476,16 +507,16 @@ App.InstallerController = App.WizardController.extend({
     var clients = [];
     var serviceComponents = App.StackServiceComponent.find();
     var services =
-    stepController.get('content').filterProperty('isSelected', true).forEach(function (_service) {
-      var client = _service.get('serviceComponents').filterProperty('isClient', true);
-      client.forEach(function(clientComponent){
-        clients.pushObject({
-          component_name: clientComponent.get('componentName'),
-          display_name: clientComponent.get('displayName'),
-          isInstalled: false
-        });
-      },this);
-    }, this);
+      stepController.get('content').filterProperty('isSelected', true).forEach(function (_service) {
+        var client = _service.get('serviceComponents').filterProperty('isClient', true);
+        client.forEach(function (clientComponent) {
+          clients.pushObject({
+            component_name: clientComponent.get('componentName'),
+            display_name: clientComponent.get('displayName'),
+            isInstalled: false
+          });
+        }, this);
+      }, this);
     this.setDBProperty('clientInfo', clients);
     this.set('content.clients', clients);
   },
@@ -520,8 +551,8 @@ App.InstallerController = App.WizardController.extend({
       selectedStack.operatingSystems.forEach(function (os) {
         os.errorTitle = null;
         os.errorContent = null;
-        var verifyBaseUrl = os.skipValidation ? false: true;
-        if (os.selected ) {
+        var verifyBaseUrl = os.skipValidation ? false : true;
+        if (os.selected) {
           os.validation = 'icon-repeat';
           selectedStack.set('reload', !selectedStack.get('reload'));
           App.ajax.send({
@@ -555,7 +586,7 @@ App.InstallerController = App.WizardController.extend({
    * onSuccess callback for check Repo URL.
    */
   checkRepoURLSuccessCallback: function (response, request, data) {
-    console.log('Success in check Repo URL. data osType: ' + data.osType );
+    console.log('Success in check Repo URL. data osType: ' + data.osType);
     var selectedStack = this.get('content.stacks').findProperty('isSelected', true);
     if (selectedStack && selectedStack.operatingSystems) {
       var os = selectedStack.operatingSystems.findProperty('id', data.osId);
@@ -582,36 +613,98 @@ App.InstallerController = App.WizardController.extend({
     }
   },
 
-  /**
-   * Load data for all steps until <code>current step</code>
-   */
-  loadAllPriorSteps: function () {
-    var step = this.get('currentStep');
-    switch (step) {
-      case '10':
-      case '9':
-      case '8':
-      case '7':
-        this.loadServiceConfigGroups();
-        this.loadServiceConfigProperties();
-      case '6':
-        this.loadSlaveComponentHosts();
-        this.loadClients();
-      case '5':
-        this.loadMasterComponentHosts();
-        this.loadConfirmedHosts();
-      case '4':
-        this.loadStacks();
-        this.loadServices();
-      case '3':
-        this.loadConfirmedHosts();
-      case '2':
-        this.load('installOptions');
-      case '1':
-        this.loadStacks();
-      case '0':
-        this.load('cluster');
-    }
+  loadMap: {
+    '0': [
+      {
+        type: 'sync',
+        callback: function () {
+          this.load('cluster');
+        }
+      }
+    ],
+    '1': [
+      {
+        type: 'async',
+        callback: function () {
+          return this.loadStacks();
+        }
+      },
+      {
+        type: 'async',
+        callback: function (stacksLoaded) {
+          var dfd = $.Deferred();
+
+          if (!stacksLoaded) {
+            $.when.apply(this, this.loadStacksVersions()).done(function () {
+              dfd.resolve(stacksLoaded);
+            });
+          } else {
+            dfd.resolve(stacksLoaded);
+          }
+
+          return dfd.promise();
+        }
+      },
+      {
+        type: 'sync',
+        callback: function (stacksLoaded) {
+          if (!stacksLoaded) {
+            this.setStacks();
+          }
+        }
+      }
+    ],
+    '2': [
+      {
+        type: 'sync',
+        callback: function () {
+          this.load('installOptions');
+        }
+      }
+    ],
+    '3': [
+      {
+        type: 'sync',
+        callback: function () {
+          this.loadConfirmedHosts();
+        }
+      }
+    ],
+    '4': [
+      {
+        type: 'async',
+        callback: function () {
+          return this.loadServices();
+        }
+      }
+    ],
+    '5': [
+      {
+        type: 'sync',
+        callback: function () {
+          this.loadMasterComponentHosts();
+          this.loadConfirmedHosts();
+        }
+      }
+    ],
+    '6': [
+      {
+        type: 'sync',
+        callback: function () {
+          this.loadSlaveComponentHosts();
+          this.loadClients();
+        }
+      }
+    ],
+    '7': [
+      {
+        type: 'sync',
+        callback: function () {
+          this.loadServiceConfigGroups();
+          this.loadServiceConfigProperties();
+        }
+      }
+    ]
   },
   /**
    * Clear all temporary data
@@ -620,7 +713,7 @@ App.InstallerController = App.WizardController.extend({
     this.setCurrentStep('0');
     this.clearStorageData();
     var persists = App.router.get('applicationController').persistKey();
-    App.router.get('applicationController').postUserPref(persists,true);
+    App.router.get('applicationController').postUserPref(persists, true);
   },
 
   setStepsEnable: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/08e23509/ambari-web/app/controllers/main/service/add_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/add_controller.js b/ambari-web/app/controllers/main/service/add_controller.js
index 1e764ca..5d6ef0d 100644
--- a/ambari-web/app/controllers/main/service/add_controller.js
+++ b/ambari-web/app/controllers/main/service/add_controller.js
@@ -69,24 +69,6 @@ App.AddServiceController = App.WizardController.extend({
   getCluster: function(){
     return jQuery.extend({}, this.get('clusterStatusTemplate'), {name: App.router.getClusterName()});
   },
-
-  /**
-   * Load services data from server.
-   */
-  loadServicesFromServer: function() {
-    if(this.getDBProperty('service')){
-      return;
-    }
-    var apiService = this.loadServiceComponents();
-    apiService.forEach(function(item, index){
-      apiService[index].isSelected = App.Service.find().someProperty('id', item.serviceName);
-      apiService[index].isDisabled = apiService[index].isSelected;
-      apiService[index].isInstalled = apiService[index].isSelected;
-    });
-    this.set('content.services', apiService);
-    this.setDBProperty('service', apiService);
-  },
-
   /**
    * Load services data. Will be used at <code>Select services(step4)</code> step
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/08e23509/ambari-web/app/controllers/wizard.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard.js b/ambari-web/app/controllers/wizard.js
index c21ee96..09988b9 100644
--- a/ambari-web/app/controllers/wizard.js
+++ b/ambari-web/app/controllers/wizard.js
@@ -25,6 +25,12 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
   isStepDisabled: null,
 
   /**
+   * map of actions which load data required by which step
+   * used by <code>loadAllPriorSteps</code>
+   */
+  loadMap: {},
+
+  /**
    * Wizard properties in local storage, which should be cleaned right after wizard has been finished
    */
   dbPropertiesToClean: [
@@ -525,7 +531,7 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
    */
   loadServiceComponents: function () {
     this.clearStackModels();
-    App.ajax.send({
+    return App.ajax.send({
       name: 'wizard.service_components',
       sender: this,
       data: {
@@ -981,5 +987,30 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, {
     var clients = this.getDBProperty('clientInfo');
     this.set('content.clients', clients);
     console.log(this.get('content.controllerName') + ".loadClients: loaded list ", clients);
+  },
+
+  /**
+   * load methods assigned to each step
+   * methods executed in exact order as they described in map
+   * @return {object}
+   */
+  loadAllPriorSteps: function () {
+    var currentStep = this.get('currentStep');
+    var loadMap = this.get('loadMap');
+    var operationStack = [];
+    var dfd = $.Deferred();
+
+    for (var s in loadMap) {
+      if (parseInt(s) <= parseInt(currentStep)) {
+        operationStack.pushObjects(loadMap[s]);
+      }
+    }
+
+    var sequence = App.actionSequence.create({context: this});
+    sequence.setSequence(operationStack).onFinish(function () {
+      dfd.resolve();
+    }).start();
+
+    return dfd.promise();
   }
-});
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/08e23509/ambari-web/app/initialize.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/initialize.js b/ambari-web/app/initialize.js
index eda51e2..14473eb 100644
--- a/ambari-web/app/initialize.js
+++ b/ambari-web/app/initialize.js
@@ -36,6 +36,7 @@ require('router');
 require('utils/ajax/ajax');
 require('utils/ajax/ajax_queue');
 require('utils/updater');
+require('utils/action_sequence');
 
 require('mappers');
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/08e23509/ambari-web/app/routes/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/installer.js b/ambari-web/app/routes/installer.js
index 79db3f8..d4fda3c 100644
--- a/ambari-web/app/routes/installer.js
+++ b/ambari-web/app/routes/installer.js
@@ -25,11 +25,11 @@ module.exports = Em.Route.extend({
   enter: function (router) {
     console.log('in /installer:enter');
 
-    App.clusterStatus.set('wizardControllerName',App.router.get('installerController.name'));
+    App.clusterStatus.set('wizardControllerName', App.router.get('installerController.name'));
 
     if (router.getAuthenticated()) {
       // check server/web client versions match
-      App.router.get('installerController').checkServerClientVersion().done(function() {
+      App.router.get('installerController').checkServerClientVersion().done(function () {
 
         var name = 'Cluster Install Wizard';
         $('title').text('Ambari - ' + name);
@@ -117,8 +117,9 @@ module.exports = Em.Route.extend({
       console.log('in installer.step0:connectOutlets');
       var controller = router.get('installerController');
       controller.setCurrentStep('0');
-      controller.loadAllPriorSteps();
-      controller.connectOutlet('wizardStep0', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        controller.connectOutlet('wizardStep0', controller.get('content'));
+      });
     },
 
     next: function (router) {
@@ -134,8 +135,9 @@ module.exports = Em.Route.extend({
       console.log('in installer.step1:connectOutlets');
       var controller = router.get('installerController');
       controller.setCurrentStep('1');
-      controller.loadAllPriorSteps();
-      controller.connectOutlet('wizardStep1', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        controller.connectOutlet('wizardStep1', controller.get('content'));
+      });
     },
     back: Em.Router.transitionTo('step0'),
     next: function (router) {
@@ -149,7 +151,7 @@ module.exports = Em.Route.extend({
       }
       // make sure got all validations feedback and no invalid url, then proceed
       var myVar = setInterval(
-        function(){
+        function () {
           var cnt = installerController.get('validationCnt');
           var invalidCnt = installerController.get('invalidCnt');
           if (cnt == 0 && invalidCnt == 0) { // all feedback exist and no invalid url
@@ -158,11 +160,11 @@ module.exports = Em.Route.extend({
             installerController.clearInstallOptions();
             router.transitionTo('step2');
             clearInterval(myVar);
-          } else if ( cnt == 0 && invalidCnt != 0) {
+          } else if (cnt == 0 && invalidCnt != 0) {
             clearInterval(myVar);
           }
         },
-      1000);
+        1000);
     }
   }),
 
@@ -173,8 +175,9 @@ module.exports = Em.Route.extend({
 
       var controller = router.get('installerController');
       controller.setCurrentStep('2');
-      controller.loadAllPriorSteps();
-      controller.connectOutlet('wizardStep2', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        controller.connectOutlet('wizardStep2', controller.get('content'));
+      });
     },
     back: Em.Router.transitionTo('step1'),
     next: function (router) {
@@ -192,13 +195,14 @@ module.exports = Em.Route.extend({
       console.log('in installer.step3:connectOutlets');
       var controller = router.get('installerController');
       controller.setCurrentStep('3');
-      controller.loadAllPriorSteps();
-      var wizardStep3Controller = router.get('wizardStep3Controller');
-      wizardStep3Controller.set('wizardController', controller);
-      controller.connectOutlet('wizardStep3', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        var wizardStep3Controller = router.get('wizardStep3Controller');
+        wizardStep3Controller.set('wizardController', controller);
+        controller.connectOutlet('wizardStep3', controller.get('content'));
+      });
     },
-    back: function(router){
-        router.transitionTo('step2');
+    back: function (router) {
+      router.transitionTo('step2');
     },
     next: function (router, context) {
       var installerController = router.get('installerController');
@@ -231,8 +235,9 @@ module.exports = Em.Route.extend({
       router.setNavigationFlow('step4');
       var controller = router.get('installerController');
       controller.setCurrentStep('4');
-      controller.loadAllPriorSteps();
-      controller.connectOutlet('wizardStep4', App.StackService.find());
+      controller.loadAllPriorSteps().done(function () {
+        controller.connectOutlet('wizardStep4', App.StackService.find());
+      });
     },
     back: Em.Router.transitionTo('step3'),
 
@@ -255,8 +260,9 @@ module.exports = Em.Route.extend({
       var controller = router.get('installerController');
       router.get('wizardStep5Controller').set('servicesMasters', []);
       controller.setCurrentStep('5');
-      controller.loadAllPriorSteps();
-      controller.connectOutlet('wizardStep5', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        controller.connectOutlet('wizardStep5', controller.get('content'));
+      });
     },
     back: Em.Router.transitionTo('step4'),
     next: function (router) {
@@ -276,8 +282,9 @@ module.exports = Em.Route.extend({
       var controller = router.get('installerController');
       router.get('wizardStep6Controller').set('hosts', []);
       controller.setCurrentStep('6');
-      controller.loadAllPriorSteps();
-      controller.connectOutlet('wizardStep6', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        controller.connectOutlet('wizardStep6', controller.get('content'));
+      });
     },
     back: Em.Router.transitionTo('step5'),
 
@@ -304,13 +311,15 @@ module.exports = Em.Route.extend({
       console.log('in /wizardStep7Controller:enter');
       var controller = router.get('installerController');
       controller.setCurrentStep('7');
-      controller.loadAllPriorSteps();
     },
     connectOutlets: function (router, context) {
       var controller = router.get('installerController');
-      var wizardStep7Controller = router.get('wizardStep7Controller');
-      wizardStep7Controller.set('wizardController', controller);
-      controller.connectOutlet('wizardStep7', controller.get('content'));
+
+      controller.loadAllPriorSteps().done(function () {
+        var wizardStep7Controller = router.get('wizardStep7Controller');
+        wizardStep7Controller.set('wizardController', controller);
+        controller.connectOutlet('wizardStep7', controller.get('content'));
+      });
     },
     back: Em.Router.transitionTo('step6'),
     next: function (router) {
@@ -330,10 +339,11 @@ module.exports = Em.Route.extend({
       console.log('in installer.step8:connectOutlets');
       var controller = router.get('installerController');
       controller.setCurrentStep('8');
-      controller.loadAllPriorSteps();
-      var wizardStep8Controller = router.get('wizardStep8Controller');
-      wizardStep8Controller.set('wizardController', controller);
-      controller.connectOutlet('wizardStep8', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        var wizardStep8Controller = router.get('wizardStep8Controller');
+        wizardStep8Controller.set('wizardController', controller);
+        controller.connectOutlet('wizardStep8', controller.get('content'));
+      });
     },
     back: Em.Router.transitionTo('step7'),
     next: function (router) {
@@ -356,13 +366,14 @@ module.exports = Em.Route.extend({
       console.log('in installer.step9:connectOutlets');
       var controller = router.get('installerController');
       controller.setCurrentStep('9');
-      controller.loadAllPriorSteps();
-      if (!App.testMode) {
-        controller.setLowerStepsDisable(9);
-      }
-      var wizardStep9Controller = router.get('wizardStep9Controller');
-      wizardStep9Controller.set('wizardController', controller);
-      controller.connectOutlet('wizardStep9', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        if (!App.testMode) {
+          controller.setLowerStepsDisable(9);
+        }
+        var wizardStep9Controller = router.get('wizardStep9Controller');
+        wizardStep9Controller.set('wizardController', controller);
+        controller.connectOutlet('wizardStep9', controller.get('content'));
+      });
     },
     back: Em.Router.transitionTo('step8'),
     retry: function (router) {
@@ -402,11 +413,12 @@ module.exports = Em.Route.extend({
       console.log('in installer.step10:connectOutlets');
       var controller = router.get('installerController');
       controller.setCurrentStep('10');
-      controller.loadAllPriorSteps();
-      if (!App.testMode) {
-        controller.setLowerStepsDisable(10);
-      }
-      controller.connectOutlet('wizardStep10', controller.get('content'));
+      controller.loadAllPriorSteps().done(function () {
+        if (!App.testMode) {
+          controller.setLowerStepsDisable(10);
+        }
+        controller.connectOutlet('wizardStep10', controller.get('content'));
+      });
     },
     back: Em.Router.transitionTo('step9'),
     complete: function (router, context) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/08e23509/ambari-web/app/utils/action_sequence.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/action_sequence.js b/ambari-web/app/utils/action_sequence.js
new file mode 100644
index 0000000..507f6fc
--- /dev/null
+++ b/ambari-web/app/utils/action_sequence.js
@@ -0,0 +1,140 @@
+/**
+ * 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.
+ */
+
+
+/**
+ * Utility to define sequence of actions (sync or async either) and execute them in exact order
+ * methods executed in order that described in sequence
+ * each action obtain result of previous action <code>previousResponse</code>
+ * For example:
+ * loadMap: {
+ *  '0': {
+ *   type: 'async',
+ *   callback: function (previousResponse) {
+ *     //method1
+ *   }
+ *  },
+ *  '1': {
+ *    type: 'sync',
+ *    callback: function (previousResponse) {
+ *      //method2
+ *    }
+ *  }
+ * }
+ * However method1 is async, method2 will be executed only after method1 is completed
+ * @type {*}
+ */
+App.actionSequence = Em.Object.extend({
+  /**
+   * List of actions which will be executed
+   * format:
+   * [
+   *   {
+   *     type: 'async',
+   *     callback: function(previousResponse) {
+   *       //async method should return Deferred object to continue sequence
+   *     }
+   *   },
+   *   {
+   *     type: 'sync',
+   *     callback: function(previousResponse) {
+   *       //code
+   *     }
+   *   }
+   * ]
+   * @type {Object[]}
+   */
+  sequence: [],
+  /**
+   * specific context for methods executed in actions
+   */
+  context: this,
+  /**
+   * Function called after sequence is completed
+   * @type {callback}
+   */
+  finishedCallback: Em.K,
+  /**
+   * counter of actions
+   */
+  actionCounter: 0,
+  /**
+   * set sequence
+   * @param sequence
+   * @return {object}
+   */
+  setSequence: function (sequence) {
+    if (Array.isArray(sequence)) {
+      this.set('sequence', sequence);
+    } else {
+      console.log('ERROR: passed sequence has incorrect type');
+    }
+    return this;
+  },
+  /**
+   * start executing sequence of actions
+   */
+  start: function () {
+    this.set('actionCounter', this.get('sequence.length'));
+    this.runNextAction(0, null);
+  },
+  /**
+   * set <code>finishedCallback</code>
+   * @param callback
+   * @return {object}
+   */
+  onFinish: function (callback) {
+    if (typeof(callback) === 'function') {
+      this.set('finishedCallback', callback);
+    }
+    return this;
+  },
+  /**
+   * run next action in sequence
+   * @param index
+   * @param previousResponse
+   * @return {Boolean}
+   */
+  runNextAction: function (index, previousResponse) {
+    var action = this.get('sequence')[index];
+    var context = this.get('context');
+    var self = this;
+
+    index++;
+    this.decrementProperty('actionCounter');
+
+    if (this.get('actionCounter') >= 0 && !Em.isNone(action)) {
+      if (action.type === 'sync') {
+        this.runNextAction(index, action.callback.call(context, previousResponse));
+        return true;
+      } else if (action.type === 'async') {
+        action.callback.call(context, previousResponse).done(function (response) {
+          self.runNextAction(index, response);
+        });
+        return true;
+      } else {
+        console.log('WARNING: action has incorrect type, action skipped');
+      }
+    } else {
+      //if no more actions left then finish sequence
+      this.finishedCallback();
+    }
+    return false;
+  }
+});
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/08e23509/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index 8139e15..67d1689 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -955,8 +955,7 @@ var urls = {
     'mock': '/data/stacks/HDP-2.1/service_components.json',
     'format': function(data) {
       return {
-        timeout: 10000,
-        async: !!data.async
+        timeout: 10000
       };
     }
   },
@@ -1150,21 +1149,11 @@ var urls = {
   },
   'wizard.stacks': {
     'real': '/stacks',
-    'mock': '/data/wizard/stack/stacks2.json',
-    'format': function() {
-      return {
-        async: false
-      };
-    }
+    'mock': '/data/wizard/stack/stacks2.json'
   },
   'wizard.stacks_versions': {
     'real': '/stacks/{stackName}/versions?fields=Versions,operatingSystems/repositories/Repositories',
-    'mock': '/data/wizard/stack/{stackName}_versions.json',
-    'format': function() {
-      return {
-        async: false
-      };
-    }
+    'mock': '/data/wizard/stack/{stackName}_versions.json'
   },
   'wizard.launch_bootstrap': {
     'real': '/bootstrap',