Ver código fonte

AMBARI-5199. Replace $.ajax with App.ajax anywhere where it's possible. (onechiporenko)

Oleg Nechiporenko 11 anos atrás
pai
commit
cf332bb382

+ 2 - 1
ambari-web/app/assets/test/tests.js

@@ -68,7 +68,8 @@ require('test/utils/configs/defaults_providers/yarn_defaults_provider_test');
 require('test/utils/configs/defaults_providers/tez_defaults_provider_test');
 require('test/utils/configs/defaults_providers/hive_defaults_provider_test');
 require('test/utils/configs/validators/service_configs_validator_test');
-require('test/utils/ajax_test');
+require('test/utils/ajax/ajax_test');
+require('test/utils/ajax/ajax_queue_test');
 require('test/utils/batch_scheduled_requests_test');
 require('test/utils/config_test');
 require('test/utils/date_test');

+ 15 - 58
ambari-web/app/controllers/main/admin/user.js

@@ -23,7 +23,7 @@ App.MainAdminUserController = Em.Controller.extend({
 
   /**
    * send request to the server to delete user if selected user is not current user
-   * @param event
+   * @param {object} event
    */
   deleteRecord:function (event) {
     var self = this;
@@ -31,12 +31,8 @@ App.MainAdminUserController = Em.Controller.extend({
       App.ModalPopup.show({
         header:Em.I18n.t('admin.users.delete.yourself.header'),
         body:Em.I18n.t('admin.users.delete.yourself.message'),
-        onPrimary:function (event) {
-          this.hide();
-        },
         secondary:false
       });
-
       return;
     }
 
@@ -47,63 +43,24 @@ App.MainAdminUserController = Em.Controller.extend({
       secondary:Em.I18n.t('no'),
 
       onPrimary:function () {
-        self.sendCommandToServer('/users/' +  event.context.get("userName"), "DELETE" ,{},
-          function (success) {
-
-            if (!success) {
-              return;
-            }
-
-            event.context.deleteRecord();
-
-            try {
-              App.store.commit();
-            } catch (err) {
-
-            }
-          });
-        this.hide();
-      },
-      onSecondary:function () {
+        App.ajax.send({
+          name: 'admin.user.delete',
+          sender: self,
+          data: {
+            user: event.context.get("userName"),
+            event: event
+          },
+          success: 'deleteUserSuccessCallback'
+        });
         this.hide();
       }
     });
   },
 
-  /**
-   * send request to the server and call callback function with true if request was success or false if request was failed
-   * @param url
-   * @param method
-   * @param postData
-   * @param callback
-   */
-  sendCommandToServer : function(url, method, postData, callback){
-    if (App.testMode) {
-      url = '/data/users/users.json';
-      method = 'GET';
-      postData = undefined;
-    } else {
-      url = App.apiPrefix + url;
-    }
-
-    $.ajax({
-      type: method,
-      url: url,
-      data: JSON.stringify(postData),
-      dataType: 'json',
-      timeout: App.timeout,
-      success: function(data){
-          callback(true, '');
-      },
-
-      error: function (request, ajaxOptions, error) {
-        var message = $.parseJSON(request.responseText).message;
-        message = message.substr(message.lastIndexOf(':') + 1);
-        callback(false, message);
-        console.log(message);
-      },
-
-      statusCode: require('data/statusCodes')
-    });
+  deleteUserSuccessCallback: function(data, opt, params) {
+    params.event.context.deleteRecord();
+    try {
+      App.store.commit();
+    } catch (err) {}
   }
 });

+ 305 - 248
ambari-web/app/controllers/main/host/details.js

@@ -52,44 +52,9 @@ App.MainHostDetailsController = Em.Controller.extend({
     return this.get('serviceActiveComponents').filterProperty('isClient',false);
   }.property('serviceActiveComponents'),
 
-
-  /**
-   * Send specific command to server
-   * @param url
-   * @param _method
-   * @param postData
-   * @param callback
-   */
-  sendCommandToServer : function(url, postData, _method, callback){
-    var url =  (App.testMode) ?
-      '/data/wizard/deploy/poll_1.json' : //content is the same as ours
-      App.apiPrefix + '/clusters/' + App.router.getClusterName() + url;
-
-    var method = App.testMode ? 'GET' : _method;
-
-    $.ajax({
-      type: method,
-      url: url,
-      data: JSON.stringify(postData),
-      dataType: 'json',
-      timeout: App.timeout,
-      success: function(data){
-        if(data && data.Requests){
-          callback(data.Requests.id);
-        } else{
-          callback(null);
-          console.log('cannot get request id from ', data);
-        }
-      },
-
-      error: function (request, ajaxOptions, error) {
-        //do something
-        console.log('error on change component host status');
-        App.ajax.defaultErrorHandler(request, url, method);
-      },
-
-      statusCode: require('data/statusCodes')
-    });
+  ajaxErrorCallback: function (request, ajaxOptions, error, opt, params) {
+    console.log('error on change component host status');
+    App.ajax.defaultErrorHandler(request, opt.url, opt.method);
   },
 
   /**
@@ -111,57 +76,74 @@ App.MainHostDetailsController = Em.Controller.extend({
    * @param component  When <code>null</code> all startable components are started. 
    * @param context  Context under which this command is beign sent. 
    */
-  sendStartComponentCommand: function(components, context) {
-    var url = Em.isArray(components) ?
-        '/hosts/' + this.get('content.hostName') + '/host_components' :
-        '/hosts/' + this.get('content.hostName') + '/host_components/' + components.get('componentName').toUpperCase();
+  sendStartComponentCommand: function(component, context) {
+
     var dataToSend = {
       RequestInfo : {
         "context" : context
       },
       Body:{
-        HostRoles:{
+        HostRoles: {
           state: 'STARTED'
         }
       }
     };
-    if (Em.isArray(components)) {
-      dataToSend.RequestInfo.query = "HostRoles/component_name.in(" + components.mapProperty('componentName').join(',') + ")";
+    if (Em.isArray(component)) {
+      dataToSend.RequestInfo.query = "HostRoles/component_name.in(" + component.mapProperty('componentName').join(',') + ")";
+      App.ajax.send({
+        name: 'host.host_components.stop',
+        sender: this,
+        data: {
+          data: JSON.stringify(dataToSend),
+          hostName: this.get('content.hostName'),
+          component: component
+        },
+        success: 'stopComponentSuccessCallback',
+        error: 'ajaxErrorCallback'
+      });
     }
-    this.sendCommandToServer(url, dataToSend, 'PUT',
-      function(requestId){
-
-      if(!requestId){
-        return;
-      }
+    else {
+      App.ajax.send({
+        name: 'host.host_component.stop',
+        sender: this,
+        data: {
+          data: JSON.stringify(dataToSend),
+          hostName: this.get('content.hostName'),
+          componentName: component.get('componentName').toUpperCase(),
+          component: component
+        },
+        success: 'startComponentSuccessCallback',
+        error: 'ajaxErrorCallback'
+      });
+    }
+  },
 
-      console.log('Send request for STARTING successfully');
+  startComponentSuccessCallback: function(data, opt, params) {
+    console.log('Send request for STARTING successfully');
 
-      if (App.testMode) {
-        if(Em.isArray(components)){
-          var allComponents = this.get('content.hostComponents');
-          allComponents.forEach(function(component){
-            component.set('workStatus', App.HostComponentStatus.stopping);
-            setTimeout(function(){
-              component.set('workStatus', App.HostComponentStatus.stopped);
-            },App.testModeDelayForActions);
-          });
-        } else {
-          components.set('workStatus', App.HostComponentStatus.starting);
+    if (App.testMode) {
+      if(Em.isArray(params.component)){
+        var allComponents = this.get('content.hostComponents');
+        allComponents.forEach(function(c){
+          c.set('workStatus', App.HostComponentStatus.stopping);
           setTimeout(function(){
-            components.set('workStatus', App.HostComponentStatus.started);
+            c.set('workStatus', App.HostComponentStatus.stopped);
           },App.testModeDelayForActions);
-        }
+        });
       } else {
-        App.router.get('clusterController').loadUpdatedStatusDelayed(500);
+        params.component.set('workStatus', App.HostComponentStatus.starting);
+        setTimeout(function(){
+          params.component.set('workStatus', App.HostComponentStatus.started);
+        },App.testModeDelayForActions);
+      }
+    } else {
+      App.router.get('clusterController').loadUpdatedStatusDelayed(500);
+    }
+    // load data (if we need to show this background operations popup) from persist
+    App.router.get('applicationController').dataLoading().done(function (initValue) {
+      if (initValue) {
+        App.router.get('backgroundOperationsController').showPopup();
       }
-      // load data (if we need to show this background operations popup) from persist
-      App.router.get('applicationController').dataLoading().done(function (initValue) {
-        if (initValue) {
-          App.router.get('backgroundOperationsController').showPopup();
-        }
-      });
-
     });
   },
 
@@ -227,28 +209,46 @@ App.MainHostDetailsController = Em.Controller.extend({
    *          when components failed to get deleted. 
    */
   _doDeleteHostComponent: function(component) {
-    var url = component !== null ? 
-        '/hosts/' + this.get('content.hostName') + '/host_components/' + component.get('componentName').toUpperCase() : 
-        '/hosts/' + this.get('content.hostName') + '/host_components';
-    url = App.apiPrefix + '/clusters/' + App.router.getClusterName() + url;
-    var deleted = null;
-    $.ajax({
-      type: 'DELETE',
-      url: url,
-      timeout: App.timeout,
-      async: false,
-      success: function (data) {
-        deleted = null;
-      },
-      error: function (xhr, textStatus, errorThrown) {
-        console.log('Error deleting host component');
-        console.log(textStatus);
-        console.log(errorThrown);
-        deleted = {xhr: xhr, url: url, method: 'DELETE'};
-      },
-      statusCode: require('data/statusCodes')
+    if (component === null) {
+      App.ajax.send({
+        name: 'host.host_components.delete',
+        sender: this,
+        data: {
+          hostName:  this.get('content.hostName')
+        },
+        success: '_doDeleteHostComponentSuccessCallback',
+        error: '_doDeleteHostComponentErrorCallback'
       });
-    return deleted;
+    }
+    else {
+      App.ajax.send({
+        name: 'host.host_component.delete',
+        sender: this,
+        data: {
+          componentName: component.get('componentName').toUpperCase(),
+          hostName:  this.get('content.hostName')
+        },
+        success: '_doDeleteHostComponentSuccessCallback',
+        error: '_doDeleteHostComponentErrorCallback'
+      });
+    }
+    return this.get('_deletedHostComponentResult');
+  },
+
+  /**
+   * @type {object}
+   */
+  _deletedHostComponentResult: null,
+
+  _doDeleteHostComponentSuccessCallback: function() {
+    this.set('_deletedHostComponentResult', null);
+  },
+
+  _doDeleteHostComponentErrorCallback: function(xhr, textStatus, errorThrown) {
+    console.log('Error deleting host component');
+    console.log(textStatus);
+    console.log(errorThrown);
+    this.set('_deletedHostComponentResult', {xhr: xhr, url: url, method: 'DELETE'});
   },
 
   /**
@@ -259,7 +259,15 @@ App.MainHostDetailsController = Em.Controller.extend({
     var self = this;
     var component = event.context;
     App.showConfirmationPopup(function() {
-      self.sendCommandToServer('/hosts/' + self.get('content.hostName') + '/host_components/' + component.get('componentName').toUpperCase(),{
+
+      App.ajax.send({
+        name: 'host.host_component.upgrade',
+        sender: self,
+        data: {
+          component: component,
+          hostName: self.get('content.hostName'),
+          componentName: component.get('componentName').toUpperCase(),
+          data: JSON.stringify({
             RequestInfo : {
               "context" : Em.I18n.t('requestInfo.upgradeHostComponent') + " " + component.get('displayName')
             },
@@ -269,33 +277,34 @@ App.MainHostDetailsController = Em.Controller.extend({
                 state: 'INSTALLED'
               }
             }
-          }, 'PUT',
-          function(requestId){
-            if(!requestId){
-              return;
-            }
-
-            console.log('Send request for UPGRADE successfully');
+          })
+        },
+        success: 'upgradeComponentSuccessCallback',
+        error: 'ajaxErrorCallback'
+      });
+    });
+  },
 
-            if (App.testMode) {
-              component.set('workStatus', App.HostComponentStatus.starting);
-              setTimeout(function(){
-                component.set('workStatus', App.HostComponentStatus.started);
-              },App.testModeDelayForActions);
-            } else {
-              App.router.get('clusterController').loadUpdatedStatusDelayed(500);
-            }
+  upgradeComponentSuccessCallback: function(data, opt, params) {
+    console.log('Send request for UPGRADE successfully');
 
-            // load data (if we need to show this background operations popup) from persist
-            App.router.get('applicationController').dataLoading().done(function (initValue) {
-              if (initValue) {
-                App.router.get('backgroundOperationsController').showPopup();
-              }
-            });
+    if (App.testMode) {
+      params.component.set('workStatus', App.HostComponentStatus.starting);
+      setTimeout(function(){
+        params.component.set('workStatus', App.HostComponentStatus.started);
+      },App.testModeDelayForActions);
+    } else {
+      App.router.get('clusterController').loadUpdatedStatusDelayed(500);
+    }
 
-          });
+    // load data (if we need to show this background operations popup) from persist
+    App.router.get('applicationController').dataLoading().done(function (initValue) {
+      if (initValue) {
+        App.router.get('backgroundOperationsController').showPopup();
+      }
     });
   },
+
   /**
    * send command to server to stop selected host component
    * @param event
@@ -312,59 +321,76 @@ App.MainHostDetailsController = Em.Controller.extend({
   /**
    * PUTs a command to server to stop a component. If no 
    * specific component is provided, all components are stopped.
-   * @param component  When <code>null</code> all components are stopped. 
+   * @param component  When <code>null</code> all components are stopped.
    * @param context  Context under which this command is beign sent. 
    */
-  sendStopComponentCommand: function(components, context){
-    var url = Em.isArray(components) ?
-        '/hosts/' + this.get('content.hostName') + '/host_components' :
-        '/hosts/' + this.get('content.hostName') + '/host_components/' + components.get('componentName').toUpperCase();
+  sendStopComponentCommand: function(component, context) {
     var dataToSend = {
       RequestInfo : {
         "context" : context
       },
       Body:{
-        HostRoles:{
+        HostRoles: {
           state: 'INSTALLED'
         }
       }
     };
-    if (Em.isArray(components)) {
-      dataToSend.RequestInfo.query = "HostRoles/component_name.in(" + components.mapProperty('componentName').join(',') + ")";
+    if (Em.isArray(component)) {
+      dataToSend.RequestInfo.query = "HostRoles/component_name.in(" + component.mapProperty('componentName').join(',') + ")";
+      App.ajax.send({
+        name: 'host.host_components.stop',
+        sender: this,
+        data: {
+          data: JSON.stringify(dataToSend),
+          hostName: this.get('content.hostName'),
+          component: component
+        },
+        success: 'stopComponentSuccessCallback'
+      });
     }
-    this.sendCommandToServer( url, dataToSend, 'PUT',
-      function(requestId){
-      if(!requestId){
-        return;
-      }
+    else {
+      App.ajax.send({
+        name: 'host.host_component.stop',
+        sender: this,
+        data: {
+          data: JSON.stringify(dataToSend),
+          hostName: this.get('content.hostName'),
+          componentName: component.get('componentName').toUpperCase(),
+          component: component
+        },
+        success: 'stopComponentSuccessCallback',
+        error: 'ajaxErrorCallback'
+      });
+    }
+  },
 
-      console.log('Send request for STOPPING successfully');
+  stopComponentSuccessCallback: function(data, opt, params) {
+    console.log('Send request for STOPPING successfully');
 
-      if (App.testMode) {
-        if(Em.isArray(components)){
-          components.forEach(function(component){
-            component.set('workStatus', App.HostComponentStatus.stopping);
-            setTimeout(function(){
-              component.set('workStatus', App.HostComponentStatus.stopped);
-            },App.testModeDelayForActions);
-          });
-        } else {
-          components.set('workStatus', App.HostComponentStatus.stopping);
+    if (App.testMode) {
+      if(Em.isArray(params.component)) {
+        params.component.forEach(function(c){
+          c.set('workStatus', App.HostComponentStatus.stopping);
           setTimeout(function(){
-            components.set('workStatus', App.HostComponentStatus.stopped);
+            c.set('workStatus', App.HostComponentStatus.stopped);
           },App.testModeDelayForActions);
-        }
-
-      } else {
-        App.router.get('clusterController').loadUpdatedStatusDelayed(500);
+        });
+      }
+      else {
+        params.component.set('workStatus', App.HostComponentStatus.stopping);
+        setTimeout(function() {
+          params.component.set('workStatus', App.HostComponentStatus.stopped);
+        },App.testModeDelayForActions);
+      }
+    }
+    else {
+      App.router.get('clusterController').loadUpdatedStatusDelayed(500);
+    }
+    // load data (if we need to show this background operations popup) from persist
+    App.router.get('applicationController').dataLoading().done(function (initValue) {
+      if (initValue) {
+        App.router.get('backgroundOperationsController').showPopup();
       }
-
-      // load data (if we need to show this background operations popup) from persist
-      App.router.get('applicationController').dataLoading().done(function (initValue) {
-        if (initValue) {
-          App.router.get('backgroundOperationsController').showPopup();
-        }
-      });
     });
   },
 
@@ -411,15 +437,19 @@ App.MainHostDetailsController = Em.Controller.extend({
         App.ModalPopup.show({
           primary: Em.I18n.t('hosts.host.addComponent.popup.confirm'),
           header: Em.I18n.t('popup.confirmation.commonHeader'),
+
           addComponentMsg: function() {
             return Em.I18n.t('hosts.host.addComponent.msg').format(dn);
           }.property(),
-          bodyClass: Ember.View.extend({
+
+          bodyClass: Em.View.extend({
             templateName: require('templates/main/host/details/addComponentPopup')
           }),
-          restartNagiosMsg : Em.View.extend({
-            template: Ember.Handlebars.compile(Em.I18n.t('hosts.host.addComponent.note').format(dn))
+
+          restartNagiosMsg: Em.View.extend({
+            template: Em.Handlebars.compile(Em.I18n.t('hosts.host.addComponent.note').format(dn))
           }),
+
           onPrimary: function () {
             this.hide();
             if (component.get('componentName') === 'CLIENTS') {
@@ -431,10 +461,11 @@ App.MainHostDetailsController = Em.Controller.extend({
                   displayName: App.format.role(sc),
                   componentName: sc
                 });
-                self.primary(c, scs.length - index === 1);
+                self.primary(c);
               });
-            } else {
-              self.primary(component, true);
+            }
+            else {
+              self.primary(component);
             }
           }
         });
@@ -442,71 +473,92 @@ App.MainHostDetailsController = Em.Controller.extend({
     }
   },
 
-  primary: function(component, showPopup) {
+  primary: function(component) {
     var self = this;
-    var componentName = component.get('componentName').toUpperCase().toString();
+    var componentName = component.get('componentName').toUpperCase();
     var displayName = component.get('displayName');
 
-    self.sendCommandToServer('/hosts?Hosts/host_name=' + self.get('content.hostName'), {
-        RequestInfo: {
-          "context": Em.I18n.t('requestInfo.installHostComponent') + " " + displayName
-        },
-        Body: {
-          host_components: [
-            {
-              HostRoles: {
-                component_name: componentName
+    App.ajax.send({
+      name: 'host.host_component.add_new_component',
+      sender: self,
+      data: {
+        hostName: self.get('content.hostName'),
+        component: component,
+        data: JSON.stringify({
+          RequestInfo: {
+            "context": Em.I18n.t('requestInfo.installHostComponent') + " " + displayName
+          },
+          Body: {
+            host_components: [
+              {
+                HostRoles: {
+                  component_name: componentName
+                }
               }
-            }
-          ]
-        }
+            ]
+          }
+        })
       },
-      'POST',
-      function (requestId) {
-
-        console.log('Send request for ADDING NEW COMPONENT successfully');
+      success: 'addNewComponentSuccessCallback',
+      error: 'ajaxErrorCallback'
+    });
+  },
 
-        self.sendCommandToServer('/host_components?HostRoles/host_name=' + self.get('content.hostName') + '\&HostRoles/component_name=' + componentName + '\&HostRoles/state=INIT', {
-            RequestInfo: {
-              "context": Em.I18n.t('requestInfo.installNewHostComponent') + " " + displayName
-            },
-            Body: {
-              HostRoles: {
-                state: 'INSTALLED'
-              }
-            }
+  addNewComponentSuccessCallback: function(data, opt, params) {
+    console.log('Send request for ADDING NEW COMPONENT successfully');
+    App.ajax.send({
+      name: 'host.host_component.install_new_component',
+      sender: this,
+      data: {
+        hostName: this.get('content.hostName'),
+        componentName: params.componentName,
+        component: params.component,
+        data: JSON.stringify({
+          RequestInfo: {
+            "context": Em.I18n.t('requestInfo.installNewHostComponent') + " " + params.displayName
           },
-          'PUT',
-          function (requestId) {
-            if (!requestId) {
-              return;
+          Body: {
+            HostRoles: {
+              state: 'INSTALLED'
             }
+          }
+        })
+      },
+      success: 'installNewComponentSuccessCallback',
+      error: 'ajaxErrorCallback'
+    });
+  },
 
-            console.log('Send request for INSTALLING NEW COMPONENT successfully');
+  installNewComponentSuccessCallback: function(data, opt, params) {
+    if (!data.Requests || !data.Requests.id) {
+      return;
+    }
+    var self = this;
+    console.log('Send request for INSTALLING NEW COMPONENT successfully');
 
-            if (App.testMode) {
-              component.set('workStatus', App.HostComponentStatus.installing);
-              setTimeout(function () {
-                component.set('workStatus', App.HostComponentStatus.stopped);
-              }, App.testModeDelayForActions);
-            } else {
-              App.router.get('clusterController').loadUpdatedStatusDelayed(500);
-            }
+    if (App.testMode) {
+      params.component.set('workStatus', App.HostComponentStatus.installing);
+      setTimeout(function () {
+        params.component.set('workStatus', App.HostComponentStatus.stopped);
+      }, App.testModeDelayForActions);
+    }
+    else {
+      App.router.get('clusterController').loadUpdatedStatusDelayed(500);
+    }
 
-            // load data (if we need to show this background operations popup) from persist
-            App.router.get('applicationController').dataLoading().done(function (initValue) {
-              if (initValue) {
-                App.router.get('backgroundOperationsController').showPopup();
-              }
-              if (componentName === 'ZOOKEEPER_SERVER') {
-                self.set('zkRequestId', requestId);
-                self.addObserver('App.router.backgroundOperationsController.serviceTimestamp', self, self.checkZkConfigs);
-                self.checkZkConfigs();
-              }
-            });
-          });
-      });
+    // load data (if we need to show this background operations popup) from persist
+    App.router.get('applicationController').dataLoading().done(function (initValue) {
+      if (initValue) {
+        App.router.get('backgroundOperationsController').showPopup();
+      }
+      if (params.componentName === 'ZOOKEEPER_SERVER') {
+        self.set('zkRequestId', data.Requests.id);
+        self.addObserver('App.router.backgroundOperationsController.serviceTimestamp', self, self.checkZkConfigs);
+        self.checkZkConfigs();
+      }
+    });
   },
+
   /**
    * Load tags
    */
@@ -608,13 +660,12 @@ App.MainHostDetailsController = Em.Controller.extend({
 
   /**
    * send command to server to install selected host component
-   * @param event
-   * @param context
+   * @param {Object} event
    */
-  installComponent: function (event, context) {
+  installComponent: function (event) {
     var self = this;
     var component = event.context;
-    var componentName = component.get('componentName').toUpperCase().toString();
+    var componentName = component.get('componentName').toUpperCase();
     var displayName = component.get('displayName');
 
     App.ModalPopup.show({
@@ -624,47 +675,53 @@ App.MainHostDetailsController = Em.Controller.extend({
         return Em.I18n.t('hosts.host.installComponent.msg').format(displayName);
       }.property(),
       restartNagiosMsg : Em.View.extend({
-        template: Ember.Handlebars.compile(Em.I18n.t('hosts.host.addComponent.note').format(displayName))
+        template: Em.Handlebars.compile(Em.I18n.t('hosts.host.addComponent.note').format(displayName))
       }),
-      bodyClass: Ember.View.extend({
+      bodyClass: Em.View.extend({
         templateName: require('templates/main/host/details/installComponentPopup')
       }),
       onPrimary: function () {
         this.hide();
-        self.sendCommandToServer('/hosts/' + self.get('content.hostName') + '/host_components/' + component.get('componentName').toUpperCase(), {
-            RequestInfo: {
-              "context": Em.I18n.t('requestInfo.installHostComponent') + " " + displayName
-            },
-            Body: {
-              HostRoles: {
-                state: 'INSTALLED'
+
+        App.ajax.send({
+          name: 'host.host_component.install',
+          sender: self,
+          data: {
+            componentName: componentName,
+            component: component,
+            data: JSON.stringify({
+              RequestInfo: {
+                "context": Em.I18n.t('requestInfo.installHostComponent') + " " + displayName
+              },
+              Body: {
+                HostRoles: {
+                  state: 'INSTALLED'
+                }
               }
-            }
+            })
           },
-          'PUT',
-          function (requestId) {
-            if (!requestId) {
-              return;
-            }
-
-            console.log('Send request for REINSTALL COMPONENT successfully');
+          success: 'installComponentSuccessCallback',
+          error: 'ajaxErrorCallback'
+        });
+      }
+    });
+  },
 
-            if (App.testMode) {
-              component.set('workStatus', App.HostComponentStatus.installing);
-              setTimeout(function () {
-                component.set('workStatus', App.HostComponentStatus.stopped);
-              }, App.testModeDelayForActions);
-            } else {
-              App.router.get('clusterController').loadUpdatedStatusDelayed(500);
-            }
+  installComponentSuccessCallback: function(data, opt, params) {
+    console.log('Send request for REINSTALL COMPONENT successfully');
+    if (App.testMode) {
+      params.component.set('workStatus', App.HostComponentStatus.installing);
+      setTimeout(function () {
+        params.component.set('workStatus', App.HostComponentStatus.stopped);
+      }, App.testModeDelayForActions);
+    } else {
+      App.router.get('clusterController').loadUpdatedStatusDelayed(500);
+    }
 
-            // load data (if we need to show this background operations popup) from persist
-            App.router.get('applicationController').dataLoading().done(function (initValue) {
-              if (initValue) {
-                App.router.get('backgroundOperationsController').showPopup();
-              }
-            });
-          });
+    // load data (if we need to show this background operations popup) from persist
+    App.router.get('applicationController').dataLoading().done(function (initValue) {
+      if (initValue) {
+        App.router.get('backgroundOperationsController').showPopup();
       }
     });
   },

+ 1 - 1
ambari-web/app/controllers/main/service/reassign_controller.js

@@ -143,7 +143,7 @@ App.ReassignMasterController = App.WizardController.extend({
   loadConfirmedHosts: function () {
     var hosts = App.db.getHosts();
     if (!hosts || !hosts.length) {
-      var hosts = {};
+      hosts = {};
 
       App.Host.find().forEach(function (item) {
         hosts[item.get('id')] = {

+ 146 - 157
ambari-web/app/controllers/wizard/step8_controller.js

@@ -55,12 +55,6 @@ App.WizardStep8Controller = Em.Controller.extend({
    */
   globals: [],
 
-  /**
-   * List of ajax-request to be executed
-   * @type {Array}
-   */
-  ajaxQueue: [],
-
   /**
    * All configs
    * @type {Array}
@@ -105,6 +99,12 @@ App.WizardStep8Controller = Em.Controller.extend({
    */
   serviceConfigTags: [],
 
+  /**
+   * Ajax-requests queue
+   * @type {App.ajaxQueue}
+   */
+  ajaxRequestsQueue: null,
+
   /**
    * Is cluster security enabled
    * @type {bool}
@@ -164,6 +164,9 @@ App.WizardStep8Controller = Em.Controller.extend({
     this.get('clusterInfo').clear();
     this.get('serviceConfigTags').clear();
     this.set('servicesInstalled', false);
+    this.set('ajaxQueueLength', 0);
+    this.set('ajaxRequestsQueue', App.ajaxQueue.create());
+    this.set('ajaxRequestsQueue.finishedCallback', this.ajaxQueueFinished);
   },
 
   /**
@@ -205,80 +208,96 @@ App.WizardStep8Controller = Em.Controller.extend({
   loadGlobals: function () {
     var globals = this.get('content.serviceConfigProperties').filterProperty('id', 'puppet var');
     if (globals.someProperty('name', 'hive_database')) {
-      var hiveDb = globals.findProperty('name', 'hive_database');
-      var hiveDbType = {name: 'hive_database_type', value: 'mysql'};
-      var hiveJdbcDriver = {name: 'hive_jdbc_driver'};
-
-      if (hiveDb.value === 'New MySQL Database') {
-        if (globals.someProperty('name', 'hive_ambari_host')) {
-          globals.findProperty('name', 'hive_hostname').value = globals.findProperty('name', 'hive_ambari_host').value;
-          hiveDbType.value = 'mysql';
-          hiveJdbcDriver.value = 'com.mysql.jdbc.Driver';
-        }
-        globals = globals.without(globals.findProperty('name', 'hive_existing_mysql_host'));
-        globals = globals.without(globals.findProperty('name', 'hive_existing_mysql_database'));
-        globals = globals.without(globals.findProperty('name', 'hive_existing_oracle_host'));
-        globals = globals.without(globals.findProperty('name', 'hive_existing_oracle_database'));
-      } else if (hiveDb.value === 'Existing MySQL Database'){
+      globals = this.removeHiveConfigs(globals);
+    }
+    if (globals.someProperty('name', 'oozie_database')) {
+      globals = this.removeOozieConfigs(globals);
+    }
+    this.set('globals', globals);
+  },
+
+  /**
+   * Remove unused Hive configs
+   * @param {Ember.Enumerable} globals
+   * @returns {Ember.Enumerable}
+   */
+  removeHiveConfigs: function(globals) {
+    var hiveDb = globals.findProperty('name', 'hive_database');
+    var hiveDbType = {name: 'hive_database_type', value: 'mysql'};
+    var hiveJdbcDriver = {name: 'hive_jdbc_driver'};
+
+    var hive_properties = Em.A([]);
+
+    if (hiveDb.value === 'New MySQL Database') {
+      if (globals.someProperty('name', 'hive_ambari_host')) {
+        globals.findProperty('name', 'hive_hostname').value = globals.findProperty('name', 'hive_ambari_host').value;
+        hiveDbType.value = 'mysql';
+        hiveJdbcDriver.value = 'com.mysql.jdbc.Driver';
+      }
+      hive_properties.pushObjects(Em.A(['hive_existing_mysql_host','hive_existing_mysql_database','hive_existing_oracle_host','hive_existing_oracle_database']));
+    }
+    else {
+      if (hiveDb.value === 'Existing MySQL Database') {
         globals.findProperty('name', 'hive_hostname').value = globals.findProperty('name', 'hive_existing_mysql_host').value;
         hiveDbType.value = 'mysql';
         hiveJdbcDriver.value = 'com.mysql.jdbc.Driver';
-        globals = globals.without(globals.findProperty('name', 'hive_ambari_host'));
-        globals = globals.without(globals.findProperty('name', 'hive_ambari_database'));
-        globals = globals.without(globals.findProperty('name', 'hive_existing_oracle_host'));
-        globals = globals.without(globals.findProperty('name', 'hive_existing_oracle_database'));
-      } else { //existing oracle database
+        hive_properties.pushObjects(Em.A(['hive_ambari_host','hive_ambari_database','hive_existing_oracle_host','hive_existing_oracle_database']));
+      }
+      else { //existing oracle database
         globals.findProperty('name', 'hive_hostname').value = globals.findProperty('name', 'hive_existing_oracle_host').value;
         hiveDbType.value = 'oracle';
         hiveJdbcDriver.value = 'oracle.jdbc.driver.OracleDriver';
-        globals = globals.without(globals.findProperty('name', 'hive_ambari_host'));
-        globals = globals.without(globals.findProperty('name', 'hive_ambari_database'));
-        globals = globals.without(globals.findProperty('name', 'hive_existing_mysql_host'));
-        globals = globals.without(globals.findProperty('name', 'hive_existing_mysql_database'));
+        hive_properties.pushObjects(Em.A(['hive_ambari_host','hive_ambari_database','hive_existing_mysql_host','hive_existing_mysql_database']));
       }
-      globals.push(hiveDbType);
-      globals.push(hiveJdbcDriver);
     }
 
-    if (globals.someProperty('name', 'oozie_database')) {
-      var oozieDb = globals.findProperty('name', 'oozie_database');
-      var oozieDbType = {name:'oozie_database_type'};
-      var oozieJdbcDriver = {name: 'oozie_jdbc_driver'};
-
-      if (oozieDb.value === 'New Derby Database') {
-        globals.findProperty('name', 'oozie_hostname').value = globals.findProperty('name', 'oozie_ambari_host').value;
-        oozieDbType.value = 'derby';
-        oozieJdbcDriver.value = 'org.apache.derby.jdbc.EmbeddedDriver';
-        globals = globals.without(globals.findProperty('name', 'oozie_ambari_host'));
-        globals = globals.without(globals.findProperty('name', 'oozie_ambari_database'));
-        globals = globals.without(globals.findProperty('name', 'oozie_existing_mysql_host'));
-        globals = globals.without(globals.findProperty('name', 'oozie_existing_mysql_database'));
-        globals = globals.without(globals.findProperty('name', 'oozie_existing_oracle_host'));
-        globals = globals.without(globals.findProperty('name', 'oozie_existing_oracle_database'));
-      } else if (oozieDb.value === 'Existing MySQL Database') {
+    hive_properties.forEach(function(property) {
+      globals = globals.without(globals.findProperty('name', property));
+    });
+
+    globals.pushObjects([hiveDbType, hiveJdbcDriver]);
+    return globals;
+  },
+
+  /**
+   * Remove unused Oozie configs
+   * @param {Ember.Enumerable} globals
+   * @returns {Ember.Enumerable}
+   */
+  removeOozieConfigs: function(globals) {
+    var oozieDb = globals.findProperty('name', 'oozie_database');
+    var oozieDbType = {name:'oozie_database_type'};
+    var oozieJdbcDriver = {name: 'oozie_jdbc_driver'};
+
+    var oozie_properties = Em.A(['oozie_ambari_host','oozie_ambari_database']);
+
+    if (oozieDb.value === 'New Derby Database') {
+      globals.findProperty('name', 'oozie_hostname').value = globals.findProperty('name', 'oozie_ambari_host').value;
+      oozieDbType.value = 'derby';
+      oozieJdbcDriver.value = 'org.apache.derby.jdbc.EmbeddedDriver';
+      oozie_properties.pushObjects(Em.A(['oozie_existing_mysql_host','oozie_existing_mysql_database','oozie_existing_oracle_host','oozie_existing_oracle_database']));
+    }
+    else {
+      if (oozieDb.value === 'Existing MySQL Database') {
         globals.findProperty('name', 'oozie_hostname').value = globals.findProperty('name', 'oozie_existing_mysql_host').value;
         oozieDbType.value = 'mysql';
         oozieJdbcDriver.value = 'com.mysql.jdbc.Driver';
-        globals = globals.without(globals.findProperty('name', 'oozie_ambari_host'));
-        globals = globals.without(globals.findProperty('name', 'oozie_ambari_database'));
-        globals = globals.without(globals.findProperty('name', 'oozie_existing_oracle_host'));
-        globals = globals.without(globals.findProperty('name', 'oozie_existing_oracle_database'));
-        globals = globals.without(globals.findProperty('name', 'oozie_derby_database'));
-      } else { // existing oracle database
+        oozie_properties.pushObjects(Em.A(['oozie_existing_oracle_host','oozie_existing_oracle_database','oozie_derby_database']));
+      }
+      else { // existing oracle database
         globals.findProperty('name', 'oozie_hostname').value = globals.findProperty('name', 'oozie_existing_oracle_host').value;
         oozieDbType.value = 'oracle';
         oozieJdbcDriver.value = 'oracle.jdbc.driver.OracleDriver';
-        globals = globals.without(globals.findProperty('name', 'oozie_ambari_host'));
-        globals = globals.without(globals.findProperty('name', 'oozie_ambari_database'));
-        globals = globals.without(globals.findProperty('name', 'oozie_existing_mysql_host'));
-        globals = globals.without(globals.findProperty('name', 'oozie_existing_mysql_database'));
-        globals = globals.without(globals.findProperty('name', 'oozie_derby_database'));
+        oozie_properties.pushObjects(Em.A(['oozie_existing_mysql_host','oozie_existing_mysql_database','oozie_derby_database']));
       }
-      globals.push(oozieDbType);
-      globals.push(oozieJdbcDriver);
     }
 
-    this.set('globals', globals);
+    oozie_properties.forEach(function(property) {
+      globals = globals.without(globals.findProperty('name', property));
+    });
+
+    globals.pushObjects([oozieDbType, oozieJdbcDriver]);
+    return globals;
   },
 
   /**
@@ -530,7 +549,7 @@ App.WizardStep8Controller = Em.Controller.extend({
         stackVersion: stackVersion
       },
       success: 'loadRepoInfoSuccessCallback',
-      error: 'loadRepositoriesErrorCallback'
+      error: 'loadRepoInfoErrorCallback'
     });
   },
 
@@ -773,25 +792,27 @@ App.WizardStep8Controller = Em.Controller.extend({
     this.createSlaveAndClientsHostComponents();
     this.createAdditionalHostComponents();
 
-    this.doNextAjaxCall();
+    this.set('ajaxQueueLength', this.get('ajaxRequestsQueue.queue.length'));
+    this.get('ajaxRequestsQueue').start();
   },
 
   /**
    * Used in progress bar
    */
-  ajaxQueueLength: function () {
-    return this.get('ajaxQueue').length;
-  }.property('ajaxQueue.length'),
+  ajaxQueueLength: 0,
 
   /**
-   * Used in progress bar
+   * Current cluster name
+   * @type {string}
    */
-  ajaxQueueLeft: 0,
-
   clusterName: function () {
     return this.get('content.cluster.name');
   }.property('content.cluster.name'),
 
+  /**
+   * List of existing cluster names
+   * @type {string[]}
+   */
   clusterNames: [],
 
   /**
@@ -858,13 +879,17 @@ App.WizardStep8Controller = Em.Controller.extend({
         if (os.baseUrl !== os.originalBaseUrl) {
           console.log("Updating local repository URL from " + os.originalBaseUrl + " -> " + os.baseUrl + ". ", os);
           self.addRequestToAjaxQueue({
-            type: 'PUT',
-            url: App.apiPrefix + App.get('stack2VersionURL') + "/operatingSystems/" + os.osType + "/repositories/" + stack.name,
-            data: JSON.stringify({
-              "Repositories": {
-                "base_url": os.baseUrl
-              }
-            })
+            name: 'wizard.step8.set_local_repos',
+            data: {
+              osType: os.osType,
+              name: stack.name,
+              stack2VersionURL: App.get('stack2VersionURL'),
+              data: JSON.stringify({
+                "Repositories": {
+                  "base_url": os.baseUrl
+                }
+              })
+            }
           });
         }
       });
@@ -886,9 +911,10 @@ App.WizardStep8Controller = Em.Controller.extend({
     if (this.get('content.controllerName') !== 'installerController') return;
     var stackVersion = (this.get('content.installOptions.localRepo')) ? App.currentStackVersion.replace(/(-\d+(\.\d)*)/ig, "Local$&") : App.currentStackVersion;
     this.addRequestToAjaxQueue({
-      type: 'POST',
-      url: App.apiPrefix + '/clusters/' + this.get('clusterName'),
-      data: JSON.stringify({ "Clusters": {"version": stackVersion }})
+      name: 'wizard.step8.create_cluster',
+      data: {
+        data: JSON.stringify({ "Clusters": {"version": stackVersion }})
+      }
     });
 
   },
@@ -902,9 +928,10 @@ App.WizardStep8Controller = Em.Controller.extend({
     var data = this.createSelectedServicesData();
     if (!data.length) return;
     this.addRequestToAjaxQueue({
-      type: 'POST',
-      url: App.apiPrefix + '/clusters/' + this.get('clusterName') + '/services',
-      data: JSON.stringify(data)
+      name: 'wizard.step8.create_selected_services',
+      data: {
+        data:JSON.stringify(data)
+      }
     });
   },
 
@@ -934,9 +961,11 @@ App.WizardStep8Controller = Em.Controller.extend({
       // Service must be specified in terms of a query for creating multiple components at the same time.
       // See AMBARI-1018.
       this.addRequestToAjaxQueue({
-        type: 'POST',
-        url: App.apiPrefix + '/clusters/' + this.get('clusterName') + '/services?ServiceInfo/service_name=' + serviceName,
-        data: JSON.stringify({"components": componentsData})
+        name: 'wizard.step8.create_components',
+        data: {
+          data: JSON.stringify({"components": componentsData}),
+          serviceName: serviceName
+        }
       });
     }, this);
 
@@ -950,9 +979,10 @@ App.WizardStep8Controller = Em.Controller.extend({
     var data = this.createRegisterHostData();
     if (!data.length) return;
     this.addRequestToAjaxQueue({
-      type: 'POST',
-      url: App.apiPrefix + '/clusters/' + this.get('clusterName') + '/hosts',
-      data: JSON.stringify(data)
+      name: 'wizard.step8.register_host_to_cluster',
+      data: {
+        data: JSON.stringify(data)
+      }
     });
   },
 
@@ -1105,9 +1135,10 @@ App.WizardStep8Controller = Em.Controller.extend({
     };
 
     this.addRequestToAjaxQueue({
-      type: 'POST',
-      url: App.apiPrefix + '/clusters/' + this.get('clusterName') + '/hosts',
-      data: JSON.stringify(data)
+      name: 'wizard.step8.register_host_to_component',
+      data: {
+        data: JSON.stringify(data)
+      }
     });
   },
 
@@ -1190,9 +1221,10 @@ App.WizardStep8Controller = Em.Controller.extend({
     }, this).toString();
 
     this.addRequestToAjaxQueue({
-      type: 'PUT',
-      url: App.apiPrefix + '/clusters/' + this.get('clusterName'),
-      data: '[' + configData + ']'
+      name: 'wizard.step8.apply_configuration_to_cluster',
+      data: {
+        data: '[' + configData + ']'
+      }
     });
   },
 
@@ -1259,9 +1291,10 @@ App.WizardStep8Controller = Em.Controller.extend({
    */
   applyConfigurationGroups: function (sendData) {
     this.addRequestToAjaxQueue({
-      type: 'POST',
-      url: App.apiPrefix + '/clusters/' + this.get('clusterName') + '/config_groups',
-      data: JSON.stringify(sendData)
+      name: 'wizard.step8.apply_configuration_groups',
+      data: {
+        data: JSON.stringify(sendData)
+      }
     });
   },
 
@@ -1428,78 +1461,34 @@ App.WizardStep8Controller = Em.Controller.extend({
     App.router.send('next');
   },
 
-  /**
-   * Do ajax-call with data in <code>ajaxQueue[0]</code> and shift <code>ajaxQueue</code>
-   */
-  doNextAjaxCall: function () {
-    if (this.get('ajaxBusy')) return;
-
-    var queue = this.get('ajaxQueue');
-    if (!queue.length) {
-      this.ajaxQueueFinished();
-      return;
-    }
-
-    var first = queue[0];
-    this.set('ajaxQueue', queue.slice(1));
-    this.set('ajaxQueueLeft', this.get('ajaxQueue').length);
-    this.set('ajaxBusy', true);
-
-    $.ajax(first);
-  },
-
   /**
    * 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>
-   *
-   * Each ajax-request success callback contains call of <code>doNextAjaxCall</code>
+   * ajax objects are stored in <code>ajaxRequestsQueue</code>
    *
    * @param {Object} params object with ajax-request parameters like url, type, data etc
    */
   addRequestToAjaxQueue: function (params) {
     if (App.testMode) return;
 
-    var self = this;
     params = jQuery.extend({
-      async: true,
-      dataType: 'text',
-      statusCode: require('data/statusCodes'),
-      timeout: App.timeout,
-      error: function () {
-        console.log('Step8: In Error ');
-      },
-      success: function () {
-        console.log("TRACE: Step8 -> In success function");
-      }
+      sender: this,
+      error: 'ajaxQueueRequestErrorCallback'
     }, params);
+    params.data['cluster'] = this.get('clusterName');
 
-    var success = params.success;
-    var error = params.error;
-
-    params.success = function () {
-      if (success) {
-        success();
-      }
-
-      self.set('ajaxBusy', false);
-      self.doNextAjaxCall();
-    };
-
-    params.error = function (xhr, status, error) {
-      var responseText = JSON.parse(xhr.responseText);
-      var controller = App.router.get(App.clusterStatus.wizardControllerName);
-      controller.registerErrPopup(Em.I18n.t('common.error'), responseText.message);
-      self.set('hasErrorOccurred', true);
-      // an error will break the ajax call chain and allow submission again
-      self.set('isSubmitDisabled', false);
-      self.set('isBackBtnDisabled', false);
-      App.router.get(self.get('content.controllerName')).setStepsEnable();
-      self.get('ajaxQueue').clear();
-      self.set('ajaxBusy', false);
-    };
+    this.get('ajaxRequestsQueue').addRequest(params);
+  },
 
-    this.get('ajaxQueue').pushObject(params);
+  ajaxQueueRequestErrorCallback: function(xhr, status, error) {
+    var responseText = JSON.parse(xhr.responseText);
+    var controller = App.router.get(App.clusterStatus.wizardControllerName);
+    controller.registerErrPopup(Em.I18n.t('common.error'), responseText.message);
+    this.set('hasErrorOccurred', true);
+    // an error will break the ajax call chain and allow submission again
+    this.set('isSubmitDisabled', false);
+    this.set('isBackBtnDisabled', false);
+    App.router.get(this.get('content.controllerName')).setStepsEnable();
   }
 
 });

+ 66 - 93
ambari-web/app/controllers/wizard/step9_controller.js

@@ -125,12 +125,13 @@ App.WizardStep9Controller = Em.Controller.extend({
    * Observer function: Enables previous steps link if install task failed in installer wizard.
    */
   togglePreviousSteps: function () {
-    if (App.testMode) {
-      return;
-    } else 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);
+    if (!App.testMode) {
+      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'),
 
@@ -317,14 +318,17 @@ App.WizardStep9Controller = Em.Controller.extend({
       if (clusterStatus === 'INSTALL FAILED') {
         this.loadStep();
         this.loadLogData(this.get('content.cluster.requestId'));
-      } else if (clusterStatus === 'START FAILED') {
-        this.loadStep();
-        this.loadLogData(this.get('content.cluster.requestId'));
       } else {
-        // handle PENDING, INSTALLED
-        this.loadStep();
-        this.loadLogData(this.get('content.cluster.requestId'));
-        this.startPolling();
+        if (clusterStatus === 'START FAILED') {
+          this.loadStep();
+          this.loadLogData(this.get('content.cluster.requestId'));
+        }
+        else {
+          // handle PENDING, INSTALLED
+          this.loadStep();
+          this.loadLogData(this.get('content.cluster.requestId'));
+          this.startPolling();
+        }
       }
     } else {
       // handle STARTED
@@ -606,7 +610,7 @@ App.WizardStep9Controller = Em.Controller.extend({
   /**
    * Error callback function for start services task.
    */
-  launchStartServicesErrorCallback: function (jqXHR) {
+  launchStartServicesErrorCallback: function (jqXHR, ajaxOptions, error, opt) {
     console.log("ERROR");
     this.set('startCallFailed',true);
     var clusterStatus = {
@@ -620,18 +624,7 @@ App.WizardStep9Controller = Em.Controller.extend({
     });
     this.set('progress','100');
 
-    var params = {
-      cluster: this.get('content.cluster.name')
-    };
-
-    if (this.get('content.controllerName') === 'addHostController') {
-      params.name = 'wizard.step9.add_host.launch_start_services';
-    } else {
-      params.name = 'wizard.step9.installer.launch_start_services';
-    }
-
-    var opt = App.formatRequest.call(App.urls[params.name], params);
-    App.ajax.defaultErrorHandler(jqXHR,opt.url,opt.type);
+    App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status);
   },
 
   /**
@@ -952,37 +945,16 @@ App.WizardStep9Controller = Em.Controller.extend({
     this.doPolling();
   },
 
-  /**
-   *
-   * @param requestId {Int} Request Id received on triggering install/start command successfully
-   * @returns {string} URL to poll to track the result of the triggered command
-   */
-  getUrl: function (requestId) {
-    var clusterName = this.get('content.cluster.name');
-    var requestId = requestId || this.get('content.cluster.requestId');
-    var url = App.apiPrefix + '/clusters/' + clusterName + '/requests/' + requestId + '?fields=tasks/Tasks/command,tasks/Tasks/exit_code,tasks/Tasks/start_time,tasks/Tasks/end_time,tasks/Tasks/host_name,tasks/Tasks/id,tasks/Tasks/role,tasks/Tasks/status&minimal_response=true';
-    console.log("URL for step9 is: " + url);
-    return url;
-  },
-
   /**
    * This function calls API just once to fetch log data of all tasks.
-   * @param requestId {Int} Request Id received on triggering install/start command successfully
    */
-  loadLogData: function (requestId) {
-    var url = this.getUrl(requestId);
+  loadLogData: function () {
     var requestsId = this.get('wizardController').getDBProperty('cluster').oldRequestsId;
-    if (App.testMode) {
-      this.POLL_INTERVAL = 1;
-    }
-
     requestsId.forEach(function (requestId) {
-      url = this.getUrl(requestId);
       if (App.testMode) {
         this.POLL_INTERVAL = 1;
-        url = this.get('mockDataPrefix') + '/poll_' + this.numPolls + '.json';
       }
-      this.getLogsByRequest(url, false);
+      this.getLogsByRequest(false, requestId);
     }, this);
   },
   /**
@@ -1047,65 +1019,66 @@ App.WizardStep9Controller = Em.Controller.extend({
 
   /**
    * Function polls the API to retrieve data for the request.
-   * @param url {string} url to poll
-   * @param polling  {Boolean} whether to continue polling for status or not
+   * @param {bool} polling whether to continue polling for status or not
+   * @param {number} requestId
    */
-  getLogsByRequest: function (url, polling) {
-    var self = this;
-    $.ajax({
-      type: 'GET',
-      url: url,
-      async: true,
-      timeout: App.timeout,
-      dataType: 'text',
-      success: function (data) {
-        var parsedData = jQuery.parseJSON(data);
-        console.log("TRACE: In success function for the GET logs data");
-        console.log("TRACE: Step9 -> The value is: ", parsedData);
-        var result = self.parseHostInfo(parsedData);
-        if (!polling) {
-          if (self.get('content.cluster.status') === 'INSTALL FAILED') {
-            self.isAllComponentsInstalled();
-          }
-          return;
-        }
-        if (result !== true) {
-          window.setTimeout(function () {
-            if (self.get('currentOpenTaskId')) {
-              self.loadCurrentTaskLog();
-            }
-            self.doPolling();
-          }, self.POLL_INTERVAL);
-        }
-      },
-
-      error: function (request, ajaxOptions, error) {
-        console.log("TRACE: STep9 -> In error function for the GET logs data");
-        console.log("TRACE: STep9 -> value of the url is: " + url);
-        console.log("TRACE: STep9 -> error code status is: " + request.status);
+  getLogsByRequest: function (polling, requestId) {
+    App.ajax.send({
+      name: 'wizard.step9.load_log',
+      sender: this,
+      data: {
+        polling: polling,
+        cluster: this.get('content.cluster.name'),
+        requestId: requestId,
+        numPolls: this.get('numPolls')
       },
-
-      statusCode: require('data/statusCodes')
+      success: 'getLogsByRequestSuccessCallback',
+      error: 'getLogsByRequestErrorCallback'
     }).retry({times: App.maxRetries, timeout: App.timeout}).then(null,
-      function () {
+      function() {
         App.showReloadPopup();
         console.log('Install services all retries failed');
       }
     );
   },
 
+  getLogsByRequestSuccessCallback: function(data, opt, params) {
+    var self = this;
+    var parsedData = jQuery.parseJSON(data);
+    console.log("TRACE: In success function for the GET logs data");
+    console.log("TRACE: Step9 -> The value is: ", parsedData);
+    var result = this.parseHostInfo(parsedData);
+    if (!params.polling) {
+      if (this.get('content.cluster.status') === 'INSTALL FAILED') {
+        this.isAllComponentsInstalled();
+      }
+      return;
+    }
+    if (result !== true) {
+      window.setTimeout(function () {
+        if (self.get('currentOpenTaskId')) {
+          self.loadCurrentTaskLog();
+        }
+        self.doPolling();
+      }, this.POLL_INTERVAL);
+    }
+  },
+
+  getLogsByRequestErrorCallback: function(request, ajaxOptions, error) {
+    console.log("TRACE: STep9 -> In error function for the GET logs data");
+    console.log("TRACE: STep9 -> value of the url is: " + url);
+    console.log("TRACE: STep9 -> error code status is: " + request.status);
+  },
+
   /**
    * Delegates the function call to {getLogsByRequest} with appropriate params
    */
   doPolling: function () {
-    var url = this.getUrl();
-
+    var requestId = this.get('content.cluster.requestId');
     if (App.testMode) {
-      this.numPolls++;
-      url = this.get('mockDataPrefix') + '/poll_' + this.get('numPolls') + '.json';
-
+      this.incrementProperty('numPolls');
     }
-    this.getLogsByRequest(url, true);
+    this.getLogsByRequest(true, requestId);
   },
 
   /**

+ 2 - 1
ambari-web/app/initialize.js

@@ -33,7 +33,8 @@ require('templates');
 require('views');
 require('router');
 
-require('utils/ajax');
+require('utils/ajax/ajax');
+require('utils/ajax/ajax_queue');
 require('utils/updater');
 
 require('mappers/server_data_mapper');

+ 30 - 2
ambari-web/app/mixins/common/userPref.js

@@ -25,6 +25,8 @@ var App = require('app');
  * <ul>
  *   <li>getUserPrefSuccessCallback</li>
  *   <li>getUserPrefErrorCallback</li>
+ *   <li>postuserPrefSuccessCallback</li>
+ *   <li>postuserPrefErrorCallback</li>
  * </ul>
  * @type {Em.Mixin}
  */
@@ -36,6 +38,12 @@ App.UserPref = Em.Mixin.create({
    */
   makeRequestAsync: true,
 
+  /**
+   * Additional to request data
+   * @type {object}
+   */
+  additionalData: {},
+
   /**
    * Get persist value from server with persistKey
    * @param {String} key
@@ -46,7 +54,8 @@ App.UserPref = Em.Mixin.create({
       sender: this,
       data: {
         key: key,
-        async: this.get('makeRequestAsync')
+        async: this.get('makeRequestAsync'),
+        data: this.get('additionalData')
       },
       success: 'getUserPrefSuccessCallback',
       error: 'getUserPrefErrorCallback'
@@ -85,10 +94,29 @@ App.UserPref = Em.Mixin.create({
       'data': {
         'async': this.get('makeRequestAsync'),
         'keyValuePair': keyValuePair
-      }
+      },
+      'success': 'postUserPrefSuccessCallback',
+      'error': 'postUserPrefErrorCallback'
     });
   },
 
+  /**
+   * Should be redeclared in objects that use this mixin
+   * @param {*} response
+   * @param {Object} request
+   * @param {Object} data
+   * @returns {*}
+   */
+  postUserPrefSuccessCallback: function (response, request, data) {},
+
+  /**
+   * Should be redeclared in objects that use this mixin
+   * @param {Object} request
+   * @param {Object} ajaxOptions
+   * @param {String} error
+   */
+  postUserPrefErrorCallback: function(request, ajaxOptions, error) {},
+
   /**
    * Little log before post request
    * @param {Object} request

+ 60 - 80
ambari-web/app/models/cluster_states.js

@@ -16,8 +16,9 @@
  * limitations under the License.
  */
 var App = require('app');
+require('mixins/common/userPref');
 
-App.clusterStatus = Ember.Object.create({
+App.clusterStatus = Em.Object.create(App.UserPref, {
   clusterName: '',
   validStates: [
     'DEFAULT',
@@ -59,68 +60,60 @@ App.clusterStatus = Ember.Object.create({
    */
   updateFromServer: function(isAsync, overrideLocaldb) {
     // if isAsync is undefined, set it to false
-    isAsync = isAsync || false;
+    this.set('makeRequestAsync', isAsync || false);
     // if overrideLocaldb is undefined, set it to true
-    if(typeof overrideLocaldb == "undefined"){
-      overrideLocaldb =  true;
-    }
-    var user = App.db.getUser();
-    var login = App.db.getLoginName();
-    var url = App.apiPrefix + '/persist/' + this.get('key');
-    return jQuery.ajax(
-      {
-        url: url,
-        context: this,
-        async: isAsync,
-        success: function (response) {
-          if (response) {
-            var newValue = jQuery.parseJSON(response);
-            if (newValue.clusterState) {
-              this.set('clusterState', newValue.clusterState);
-            }
-            if (newValue.clusterName) {
-              this.set('clusterName', newValue.clusterName);
-            }
-            if (newValue.wizardControllerName) {
-              this.set('wizardControllerName', newValue.wizardControllerName);
-            }
-            if (newValue.localdb) {
-              this.set('localdb', newValue.localdb);
-              // restore HAWizard data if process was started
-              var isHAWizardStarted = App.get('isAdmin') && !App.isEmptyObject(newValue.localdb.HighAvailabilityWizard);
-              if (overrideLocaldb || isHAWizardStarted) {
-                App.db.data = newValue.localdb;
-                App.db.setLocalStorage();
-                App.db.setUser(user);
-                App.db.setLoginName(login);
-              }
-            }
-          } else {
-            // default status already set
-          }
-          // this is to ensure that the local storage namespaces are initialized with all expected namespaces.
-          // after upgrading ambari, loading local storage data from the "persist" data saved via an older version of
-          // Ambari can result in missing namespaces that are defined in the new version of Ambari.
-          App.db.mergeStorage();
-        },
-        error: function (xhr) {
-          if (xhr.status == 404) {
-            // default status already set
-            console.log('Persist API did NOT find the key CLUSTER_CURRENT_STATUS');
-            return;
-          }
-          App.ModalPopup.show({
-            header: Em.I18n.t('common.error'),
-            secondary: false,
-            bodyClass: Ember.View.extend({
-              template: Ember.Handlebars.compile('<p>{{t common.update.error}}</p>')
-            })
-          });
-        },
-        statusCode: require('data/statusCodes')
+    this.set('additionalData', {
+      user: App.db.getUser(),
+      login: App.db.getLoginName(),
+      overrideLocaldb: overrideLocaldb || true
+    });
+    return this.getUserPref(this.get('key'));
+  },
+
+  getUserPrefSuccessCallback: function (response, opt, params) {
+    if (response) {
+      if (response.clusterState) {
+        this.set('clusterState', response.clusterState);
       }
-    );
+      if (response.clusterName) {
+        this.set('clusterName', response.clusterName);
+      }
+      if (response.wizardControllerName) {
+        this.set('wizardControllerName', response.wizardControllerName);
+      }
+      if (response.localdb) {
+        this.set('localdb', response.localdb);
+        // restore HAWizard data if process was started
+        var isHAWizardStarted = App.get('isAdmin') && !App.isEmptyObject(response.localdb.HighAvailabilityWizard);
+        if (params.overrideLocaldb || isHAWizardStarted) {
+          App.db.data = response.localdb;
+          App.db.setLocalStorage();
+          App.db.setUser(params.user);
+          App.db.setLoginName(params.login);
+        }
+      }
+    }
+    // this is to ensure that the local storage namespaces are initialized with all expected namespaces.
+    // after upgrading ambari, loading local storage data from the "persist" data saved via an older version of
+    // Ambari can result in missing namespaces that are defined in the new version of Ambari.
+    App.db.mergeStorage();
   },
+
+  getUserPrefErrorCallback: function (request, ajaxOptions, error) {
+    if (request.status == 404) {
+      // default status already set
+      console.log('Persist API did NOT find the key CLUSTER_CURRENT_STATUS');
+      return;
+    }
+    App.ModalPopup.show({
+      header: Em.I18n.t('common.error'),
+      secondary: false,
+      bodyClass: Em.View.extend({
+        template: Em.Handlebars.compile('<p>{{t common.update.error}}</p>')
+      })
+    });
+  },
+
   /**
    * update cluster status and post it on server
    * @param newValue
@@ -161,28 +154,15 @@ App.clusterStatus = Ember.Object.create({
         App.db.setLoginName(login);
       }
 
-      var keyValuePair = {};
-
-      keyValuePair[this.get('key')] = JSON.stringify(val);
-
-      App.ajax.send({
-        name: 'cluster.state',
-        sender: this,
-        data: {
-          keyValuePair: keyValuePair
-        },
-        beforeSend: 'clusterStatusBeforeSend',
-        error: 'clusterStatusErrorCallBack'
-      });
+      this.set('makeRequestAsync', false);
+      this.postUserPref(this.get('key'), val);
       return newValue;
     }
   },
-  clusterStatusBeforeSend: function (keyValuePair) {
-    console.log('BeforeSend: persistKeyValues', keyValuePair);
-  },
-  clusterStatusErrorCallBack: function(request, ajaxOptions, error, opt) {
+
+  postUserPrefErrorCallback: function(request, ajaxOptions, error) {
     console.log("ERROR");
-    var msg, doc;
+    var msg = '', doc;
     try {
       msg = 'Error ' + (request.status) + ' ';
       doc = $.parseXML(request.responseText);
@@ -195,8 +175,8 @@ App.clusterStatus = Ember.Object.create({
       header: Em.I18n.t('common.error'),
       secondary: false,
       response: msg,
-      bodyClass: Ember.View.extend({
-        template: Ember.Handlebars.compile('<p>{{t common.persist.error}} {{response}}</p>')
+      bodyClass: Em.View.extend({
+        template: Em.Handlebars.compile('<p>{{t common.persist.error}} {{response}}</p>')
       })
     });
   },

+ 268 - 6
ambari-web/app/utils/ajax.js → ambari-web/app/utils/ajax/ajax.js

@@ -397,6 +397,119 @@ var urls = {
       }
     }
   },
+
+  'host.host_component.delete': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}',
+    'mock': '',
+    'format': function() {
+      return {
+        type: 'DELETE',
+        async: false
+      }
+    }
+  },
+
+  'host.host_components.delete': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}',
+    'mock': '',
+    'format': function() {
+      return {
+        type: 'DELETE',
+        async: false
+      }
+    }
+  },
+
+  'host.host_component.stop': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}',
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        data: data.data
+      }
+    }
+  },
+
+  'host.host_components.stop': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}/host_components',
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        async: false,
+        data: data.data
+      }
+    }
+  },
+
+  'host.host_component.start': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}',
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        data: data.data
+      }
+    }
+  },
+
+  'host.host_components.start': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}/host_components',
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        async: false,
+        data: data.data
+      }
+    }
+  },
+
+  'host.host_component.install': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}',
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        data: data.data
+      }
+    }
+  },
+
+  'host.host_component.update': {
+    'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}',
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        data: data.data
+      }
+    }
+  },
+
+  'host.host_component.add_new_component': {
+    'real': '/clusters/{clusterName}/hosts?Hosts/host_name={hostName}',
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'format': function(data) {
+      return {
+        type: 'POST',
+        data: data.data
+      }
+    }
+  },
+
+  'host.host_component.install_new_component': {
+    'real': '/clusters/{clusterName}/host_components?HostRoles/host_name={hostName}\&HostRoles/component_name={componentName}\&HostRoles/state=INIT',
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        data: data.data
+      }
+    }
+  },
+
   'host.host_component.slave_desired_admin_state': {
     'real': '/clusters/{clusterName}/hosts/{hostName}/host_components/{componentName}/?fields=HostRoles/desired_admin_state',
     'mock': ''
@@ -1162,6 +1275,39 @@ var urls = {
       };
     }
   },
+
+  'admin.user.create': {
+    'real': '/users/{user}',
+    'mock': '/data/users/users.json',
+    'format': function(data) {
+      return {
+        type: 'POST',
+        data: JSON.stringify(data.data)
+      }
+    }
+  },
+
+  'admin.user.delete': {
+    'real': '/users/{user}',
+    'mock': '/data/users/users.json',
+    'format': function() {
+      return {
+        type: 'DELETE'
+      }
+    }
+  },
+
+  'admin.user.edit': {
+    'real': '/users/{user}',
+    'mock':'/data/users/users.json',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        data: data.data
+      }
+    }
+  },
+
   'admin.stack_upgrade.do_poll': {
     'real': '/clusters/{cluster}/requests/{requestId}?fields=tasks/*',
     'mock': '/data/wizard/{mock}'
@@ -1275,6 +1421,19 @@ var urls = {
       };
     }
   },
+
+  'wizard.step9.load_log': {
+    'real': '/clusters/{cluster}/requests/{requestId}?fields=tasks/Tasks/command,tasks/Tasks/exit_code,tasks/Tasks/start_time,tasks/Tasks/end_time,tasks/Tasks/host_name,tasks/Tasks/id,tasks/Tasks/role,tasks/Tasks/status&minimal_response=true',
+    'mock': '/data/wizard/deploy/5_hosts/poll_{numPolls}.json',
+    'format': function () {
+      return {
+        type: 'GET',
+        async: true,
+        dataType: 'text'
+      };
+    }
+  },
+
   'wizard.step8.delete_cluster': {
     'real': '/clusters/{name}',
     'mock': '',
@@ -1294,6 +1453,111 @@ var urls = {
       };
     }
   },
+
+  'wizard.step8.create_cluster': {
+    'real':'/clusters/{cluster}',
+    'mock':'',
+    'format': function(data) {
+      return {
+        type: 'POST',
+        async: true,
+        dataType: 'text',
+        data: data.data
+      }
+    }
+  },
+
+  'wizard.step8.create_selected_services': {
+    'real':'/clusters/{cluster}/services',
+    'mock':'',
+    'format': function(data) {
+      return {
+        type: 'POST',
+        async: true,
+        dataType: 'text',
+        data: data.data
+      }
+    }
+  },
+
+  'wizard.step8.create_components': {
+    'real':'/clusters/{cluster}/services?ServiceInfo/service_name={serviceName}',
+    'mock':'',
+    'format': function(data) {
+      return {
+        type: 'POST',
+        async: true,
+        dataType: 'text',
+        data: data.data
+      }
+    }
+  },
+
+  'wizard.step8.register_host_to_cluster': {
+    'real':'/clusters/{cluster}/hosts',
+    'mock':'',
+    'format': function(data) {
+      return {
+        type: 'POST',
+        async: true,
+        dataType: 'text',
+        data: data.data
+      }
+    }
+  },
+
+  'wizard.step8.register_host_to_component': {
+    'real':'/clusters/{cluster}/hosts',
+    'mock':'',
+    'format': function(data) {
+      return {
+        type: 'POST',
+        async: true,
+        dataType: 'text',
+        data: data.data
+      }
+    }
+  },
+
+  'wizard.step8.apply_configuration_to_cluster': {
+    'real':'/clusters/{cluster}',
+    'mock':'',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        async: true,
+        dataType: 'text',
+        data: data.data
+      }
+    }
+  },
+
+  'wizard.step8.apply_configuration_groups': {
+    'real':'/clusters/{cluster}/config_groups',
+    'mock':'',
+    'format': function(data) {
+      return {
+        type: 'POST',
+        async: true,
+        dataType: 'text',
+        data: data.data
+      }
+    }
+  },
+
+  'wizard.step8.set_local_repos': {
+    'real':'{stack2VersionURL}/operatingSystems/{osType}/repositories/{name}',
+    'mock':'',
+    'format': function(data) {
+      return {
+        type: 'PUT',
+        async: true,
+        dataType: 'text',
+        data: data.data
+      }
+    }
+  },
+
   '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',
@@ -1557,9 +1821,9 @@ var urls = {
         contentType: 'text/xml',
         dataType: 'xml',
         data: data.entity,
-          headers: {
-        'AmbariProxy-Content-Type': 'text/xml'
-      }
+        headers: {
+          'AmbariProxy-Content-Type': 'text/xml'
+        }
       }
     }
   },
@@ -1960,6 +2224,4 @@ if ($.mocho) {
   });
 }
 
-App.ajax = ajax.create({});
-App.formatRequest = formatRequest;
-App.urls = urls;
+App.ajax = ajax.create({});

+ 182 - 0
ambari-web/app/utils/ajax/ajax_queue.js

@@ -0,0 +1,182 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+/**
+ * Simple util for executing ajax-requests queue
+ *
+ * @uses App.ajax
+ * @type {Em.Object}
+ *
+ * Don't add requests directly to <code>queue</code>!
+ * Bad example:
+ * <code>
+ *  var q = App.ajax.Queue.create();
+ *  q.get('queue').pushObject({...}); // Don't do this!!!!
+ * </code>
+ *
+ * Don't call <code>runNextRequest</code> directly!
+ * Bad example:
+ * <code>
+ *  var q = App.ajax.Queue.create();
+ *  q.runNextRequest(); // Don't do this!!!!
+ * </code>
+ *
+ * Usage example 1:
+ * <code>
+ *  var q = App.ajax.Queue.create();
+ *  q.addRequest({
+ *    name: 'some_request',
+ *    sender: this,
+ *    success: 'someFunc'
+ *  }).addRequest({
+ *    name: 'some_request2',
+ *    sender: this,
+ *    success: 'someFunc2'
+ *  }).start();
+ * </code>
+ *
+ * Usage example 2:
+ * <code>
+ *  var q = App.ajax.Queue.create();
+ *  q.addRequest({
+ *    name: 'some_request',
+ *    sender: this,
+ *    success: 'someFunc'
+ *  });
+ *  q.addRequest({
+ *    name: 'some_request2',
+ *    sender: this,
+ *    success: 'someFunc2'
+ *  });
+ *  q.start();
+ * </code>
+ *
+ * Usage example 3:
+ * <code>
+ *  var q = App.ajax.Queue.create();
+ *  q.addRequests(Em.A([{
+ *    name: 'some_request',
+ *    sender: this,
+ *    success: 'someFunc'
+ *  },
+ *  {
+ *    name: 'some_request2',
+ *    sender: this,
+ *    success: 'someFunc2'
+ *  }]));
+ *  q.start();
+ * </code>
+ */
+App.ajaxQueue = Em.Object.extend({
+
+  /**
+   * List of requests
+   * @type {Object[]}
+   */
+  queue: Em.A([]),
+
+  /**
+   * About query executing if some request failed
+   * @type {bool}
+   */
+  abortOnError: true,
+
+  /**
+   * Function called after queue is complete
+   * @type {callback}
+   */
+  finishedCallback: Em.K,
+
+  /**
+   * Add request to the <code>queue</code>
+   * @param {Object} request object that uses in <code>App.ajax.send</code>
+   * @return {App.ajaxQueue}
+   */
+  addRequest: function(request) {
+    Em.assert('Each ajax-request should has non-blank `name`', !Em.isBlank(Em.get(request, 'name')));
+    Em.assert('Each ajax-request should has object `sender`', Em.typeOf(Em.get(request, 'sender')) !== 'object');
+    this.get('queue').pushObject(request);
+    return this;
+  },
+
+  /**
+   * Add requests to the <code>queue</code>
+   * @param {Object[]} requests list of objects that uses in <code>App.ajax.send</code>
+   * @return {App.ajaxQueue}
+   */
+  addRequests: function(requests) {
+    requests.map(function(request) {
+      this.addRequest(request);
+    }, this);
+    return this;
+  },
+
+  /**
+   * Enter point to start requests executing
+   */
+  start: function() {
+    this.runNextRequest();
+  },
+
+  /**
+   * Execute first request from the <code>queue</code>
+   */
+  runNextRequest: function() {
+    var self = this;
+    var queue = this.get('queue');
+    if (queue.length === 0) {
+      this.finishedCallback();
+      return;
+    }
+    var r = App.ajax.send(queue.shift());
+    this.propertyDidChange('queue');
+    if (r) {
+      r.complete(function(xhr) {
+        if(xhr.status>=200 && xhr.status <= 299) {
+          self.runNextRequest();
+        }
+        else {
+          if (self.get('abortOnError')) {
+            self.clear();
+          }
+          else {
+            self.runNextRequest();
+          }
+        }
+      });
+    }
+    else {
+      if (this.get('abortOnError')) {
+        this.clear();
+      }
+      else {
+        this.runNextRequest();
+      }
+    }
+  },
+
+  /**
+   * Remove all requests from <code>queue</code>
+   */
+  clear: function() {
+    this.get('queue').clear();
+  }
+
+});

+ 3 - 3
ambari-web/app/utils/helper.js

@@ -186,15 +186,15 @@ App.parseJSON = function (value) {
  * Check for empty <code>Object</code>, built in Em.isEmpty()
  * doesn't support <code>Object</code> type
  *
- * @params obj {Object}
+ * @param {Object} obj
  *
- * @return {Boolean}
+ * @return {bool}
  */
 App.isEmptyObject = function(obj) {
   var empty = true;
   for (var prop in obj) { if (obj.hasOwnProperty(prop)) {empty = false; break;} }
   return empty;
-}
+};
 
 App.format = {
 

+ 1 - 1
ambari-web/app/utils/polling.js

@@ -51,7 +51,7 @@ App.Poll = Em.Object.extend({
   }.property('isPolling', 'isStarted'),
 
   start: function () {
-    if (this.get('requestId') === undefined) {
+    if (Em.isNone(this.get('requestId'))) {
       this.setRequestId();
     } else {
       this.startPolling();

+ 36 - 34
ambari-web/app/views/main/admin/user/create.js

@@ -23,53 +23,55 @@ App.MainAdminUserCreateView = Em.View.extend({
   userId: false,
   isPasswordDirty: false,
 
-  create: function(event){
-    var parent_controller=this.get("controller").controllers.mainAdminUserController;
+  create: function() {
     var form = this.get("userForm");
     if(form.isValid()) {
       form.getField("userName").set('value', form.getField("userName").get('value').toLowerCase());
       if(form.getField("admin").get('value') === "" || form.getField("admin").get('value') == true) {
         form.getField("roles").set("value","admin,user");
         form.getField("admin").set("value","true");
-      } else{
+      }
+      else {
         form.getField("roles").set("value","user");
       }
-      parent_controller.sendCommandToServer('/users/' + form.getField("userName").get('value'), "POST" , {
-        Users: {
-          password: form.getField("password").get('value'),
-          roles: form.getField("roles").get('value')
-        }
-      }, function (success) {
 
-        if (!success) {
-          App.ModalPopup.show({
-            header: Em.I18n.t('admin.users.addButton'),
-            body: Em.I18n.t('admin.users.createError'),
-            primary: Em.I18n.t('ok'),
-            secondary: null,
-            onPrimary: function() {
-              this.hide();
+      App.ajax.send({
+        name: 'admin.user.create',
+        sender: this,
+        data: {
+          user: form.getField("userName").get('value'),
+          form: form,
+          data: {
+            Users: {
+              password: form.getField("password").get('value'),
+              roles: form.getField("roles").get('value')
             }
-          });
-          return;
-        }
-        App.ModalPopup.show({
-          header: Em.I18n.t('admin.users.addButton'),
-          body: Em.I18n.t('admin.users.createSuccess'),
-          primary: Em.I18n.t('ok'),
-          secondary: null,
-          onPrimary: function() {
-            this.hide();
           }
-        });
-        var persists = App.router.get('applicationController').persistKey(form.getField("userName").get('value'));
-        App.router.get('applicationController').postUserPref(persists,true);
+        },
+        success: 'createUserSuccessCallback',
+        error: 'createUserErrorCallback'
+      });
+    }
+  },
 
-        form.save();
+  createUserSuccessCallback: function(data, opts, params) {
+    App.ModalPopup.show({
+      header: Em.I18n.t('admin.users.addButton'),
+      body: Em.I18n.t('admin.users.createSuccess'),
+      secondary: null
+    });
+    var persists = App.router.get('applicationController').persistKey(params.form.getField("userName").get('value'));
+    App.router.get('applicationController').postUserPref(persists, true);
+    params.form.save();
+    App.router.transitionTo("allUsers");
+  },
 
-        App.router.transitionTo("allUsers");
-      })
-    }
+  createUserErrorCallback: function () {
+    App.ModalPopup.show({
+      header: Em.I18n.t('admin.users.addButton'),
+      body: Em.I18n.t('admin.users.createError'),
+      secondary: null
+    });
   },
 
   userForm: App.CreateUserForm.create({}),

+ 43 - 33
ambari-web/app/views/main/admin/user/edit.js

@@ -21,45 +21,55 @@ var App = require('app');
 App.MainAdminUserEditView = Em.View.extend({
   templateName: require('templates/main/admin/user/edit'),
   userId: false,
-  edit: function(event){
+  edit: function() {
     var form = this.get("userForm");
-    if(form.isValid()) {
-      var Users={};
-      if(form.getField("admin").get('value') === "" || form.getField("admin").get('value') == true) {
-        form.getField("roles").set("value","admin,user");
-        form.getField("admin").set("value", true);
-      } else{
-        form.getField("roles").set("value","user");
-      }
+    if(!form.isValid()) return;
 
-      Users.roles = form.getField("roles").get('value');
+    var Users={};
+    if(form.getField("admin").get('value') === "" || form.getField("admin").get('value') == true) {
+      form.getField("roles").set("value", "admin,user");
+      form.getField("admin").set("value", true);
+    }
+    else {
+      form.getField("roles").set("value", "user");
+    }
 
-      if(form.getField("new_password").get('value') != "" && form.getField("old_password").get('value') != "") {
-        Users.password = form.getField("new_password").get('value');
-        Users.old_password = form.getField("old_password").get('value');
-      }
+    Users.roles = form.getField("roles").get('value');
 
-      this.get("controller").sendCommandToServer('/users/' + form.getField("userName").get('value'), "PUT" , {
-       Users:Users
-      }, function (success, message) {
-        if (!success) {
-          App.ModalPopup.show({
-            header: Em.I18n.t('admin.users.editButton'),
-            body: message,
-            primary: Em.I18n.t('ok'),
-            secondary: null,
-            onPrimary: function() {
-              this.hide();
-            }
-          });
-          return;
-        }
+    if(form.getField("new_password").get('value') != "" && form.getField("old_password").get('value') != "") {
+      Users.password = form.getField("new_password").get('value');
+      Users.old_password = form.getField("old_password").get('value');
+    }
 
-        form.save();
+    App.ajax.send({
+      name: 'admin.user.edit',
+      sender: this,
+      data: {
+        form: form,
+        user: form.getField("userName").get('value'),
+        data: JSON.stringify({
+          Users:Users
+        })
+      },
+      success: 'editUserSuccessCallback',
+      error: 'editUserErrorCallback'
+    });
+  },
 
-        App.router.transitionTo("allUsers");
-      })
-    }
+  editUserSuccessCallback: function(data, opt, params) {
+    params.form.save();
+    App.router.transitionTo("allUsers");
+  },
+
+  editUserErrorCallback: function (request) {
+    var message = $.parseJSON(request.responseText).message;
+    message = message.substr(message.lastIndexOf(':') + 1);
+    App.ModalPopup.show({
+      header: Em.I18n.t('admin.users.editButton'),
+      body: message,
+      secondary: null
+    });
+    console.log(message);
   },
 
   keyPress: function(event) {

+ 21 - 27
ambari-web/app/views/wizard/step8_view.js

@@ -24,8 +24,7 @@ App.WizardStep8View = Em.View.extend({
   templateName: require('templates/wizard/step8'),
 
   didInsertElement: function () {
-    var controller = this.get('controller');
-    controller.loadStep();
+    this.get('controller').loadStep();
   },
 
   spinner : null,
@@ -35,14 +34,6 @@ App.WizardStep8View = Em.View.extend({
     o.jqprint();
   },
 
-  ajaxQueueLength: function() {
-    return this.get('controller.ajaxQueueLength');
-  }.property('controller.ajaxQueueLength'),
-
-  ajaxQueueLeft: function() {
-    return this.get('controller.ajaxQueueLeft');
-  }.property('controller.ajaxQueueLeft'),
-
   // reference to modalPopup to make sure only one instance is created
   modalPopup: null,
 
@@ -59,32 +50,34 @@ App.WizardStep8View = Em.View.extend({
       return;
     }
     this.set('modalPopup', App.ModalPopup.show({
-      header: '',
 
+      header: '',
       showFooter: false,
-
       showCloseButton: false,
 
       bodyClass: Ember.View.extend({
         templateName: require('templates/wizard/step8_log_popup'),
 
-        message: function() {
-          return Em.I18n.t('installer.step8.deployPopup.message').format(this.get('ajaxQueueComplete'), this.get('ajaxQueueLength'));
-        }.property('ajaxQueueComplete', 'ajaxQueueLength'),
-
         controllerBinding: 'App.router.wizardStep8Controller',
 
-        ajaxQueueLength: function() {
-          return this.get('controller.ajaxQueueLength');
-        }.property(),
-
-        ajaxQueueComplete: function() {
-          return this.get('ajaxQueueLength') - this.get('controller.ajaxQueueLeft');
-        }.property('controller.ajaxQueueLeft', 'ajaxQueueLength'),
-
-        barWidth: function () {
-          return 'width: ' + (this.get('ajaxQueueComplete') / this.get('ajaxQueueLength') * 100) + '%;';
-        }.property('ajaxQueueComplete', 'ajaxQueueLength'),
+        /**
+         * Css-property for progress-bar
+         * @type {string}
+         */
+        barWidth: '',
+
+        /**
+         * Popup-message
+         * @type {string}
+         */
+        message: '',
+
+        ajaxQueueChangeObs: function() {
+          var length = this.get('controller.ajaxQueueLength');
+          var left = this.get('controller.ajaxRequestsQueue.queue.length');
+          this.set('barWidth', 'width: ' + ((length - left) / length * 100) + '%;');
+          this.set('message', Em.I18n.t('installer.step8.deployPopup.message').format((length - left), length));
+        }.observes('controller.ajaxQueueLength', 'controller.ajaxRequestsQueue.queue.length'),
 
         autoHide: function() {
           if (this.get('controller.servicesInstalled')) {
@@ -92,6 +85,7 @@ App.WizardStep8View = Em.View.extend({
           }
         }.observes('controller.servicesInstalled')
       })
+
     }));
   }.observes('controller.isSubmitDisabled')
 });

+ 1 - 1
ambari-web/test/controllers/global/background_operations_test.js

@@ -21,7 +21,7 @@ var App = require('app');
 
 require('config');
 require('utils/updater');
-require('utils/ajax');
+require('utils/ajax/ajax');
 
 require('models/host_component');
 

+ 1 - 0
ambari-web/test/installer/step8_test.js

@@ -17,6 +17,7 @@
  */
 
 var App = require('app');
+require('utils/ajax/ajax_queue');
 require('controllers/wizard/step8_controller');
 
 var installerStep8Controller;

+ 1 - 13
ambari-web/test/installer/step9_test.js

@@ -717,18 +717,6 @@ describe('App.InstallerStep9Controller', function () {
     });
   });
 
-  describe('#getUrl', function () {
-    var clusterName = 'tdk';
-    var cluster = App.WizardStep9Controller.create({content: {cluster: {name: clusterName, requestId: null}}});
-    it('check requestId priority', function () {
-      cluster.set('content.cluster.requestId', 123);
-      var url = cluster.getUrl(321);
-      expect(url).to.equal(App.apiPrefix + '/clusters/' + clusterName + '/requests/' + '321' + '?fields=tasks/Tasks/command,tasks/Tasks/exit_code,tasks/Tasks/start_time,tasks/Tasks/end_time,tasks/Tasks/host_name,tasks/Tasks/id,tasks/Tasks/role,tasks/Tasks/status&minimal_response=true');
-      url = cluster.getUrl();
-      expect(url).to.equal(App.apiPrefix + '/clusters/' + clusterName + '/requests/' + '123' + '?fields=tasks/Tasks/command,tasks/Tasks/exit_code,tasks/Tasks/start_time,tasks/Tasks/end_time,tasks/Tasks/host_name,tasks/Tasks/id,tasks/Tasks/role,tasks/Tasks/status&minimal_response=true');
-    });
-  });
-
   describe('#finishState', function () {
     var statuses = Em.A(['INSTALL FAILED', 'START FAILED', 'STARTED']);
     it('Installer is finished', function () {
@@ -1173,7 +1161,7 @@ describe('App.InstallerStep9Controller', function () {
     var controller = App.WizardStep9Controller.create({hosts: hosts, content: {controllerName: 'installerController', cluster: {status: 'PENDING',name: 'c1'}},togglePreviousSteps: function(){}});
 
     //Action
-    controller.launchStartServicesErrorCallback({status:500, statusTesxt: 'Server Error'});
+    controller.launchStartServicesErrorCallback({status:500, statusTesxt: 'Server Error'}, {}, '', {});
     it('Cluster Status should be INSTALL FAILED', function () {
       expect(controller.get('content.cluster.status')).to.equal('INSTALL FAILED');
     });

+ 111 - 0
ambari-web/test/utils/ajax/ajax_queue_test.js

@@ -0,0 +1,111 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+var ajaxQueue;
+
+describe('App.ajaxQueue', function () {
+
+  beforeEach(function() {
+    ajaxQueue = App.ajaxQueue.create();
+    sinon.spy(ajaxQueue, 'runNextRequest');
+    sinon.spy(ajaxQueue, 'finishedCallback');
+    sinon.spy(App.ajax, 'send');
+  });
+
+  afterEach(function() {
+    ajaxQueue.clear();
+    ajaxQueue.runNextRequest.restore();
+    ajaxQueue.finishedCallback.restore();
+    App.ajax.send.restore();
+  });
+
+  describe('#clear', function() {
+    it('should clear queue', function() {
+      ajaxQueue.addRequest({name:'some', sender: Em.Object.create()});
+      ajaxQueue.clear();
+      expect(ajaxQueue.get('queue.length')).to.equal(0);
+    });
+  });
+
+  describe('#addRequest', function() {
+    it('should add request', function() {
+      ajaxQueue.addRequest({name:'some', sender: Em.Object.create()});
+      expect(ajaxQueue.get('queue.length')).to.equal(1);
+    });
+    it('should throw `name` error', function() {
+      expect(function() {ajaxQueue.addRequest({name:'', sender: Em.Object.create()})}).to.throw(Error);
+    });
+    it('should throw `sender` error', function() {
+      expect(function() {ajaxQueue.addRequest({name:'some', sender: {}})}).to.throw(Error);
+    });
+  });
+
+  describe('#addRequests', function() {
+    it('should add requests', function() {
+      ajaxQueue.addRequests(Em.A([
+        {name:'some', sender: Em.Object.create()},
+        {name:'some2', sender: Em.Object.create()}
+      ]));
+      expect(ajaxQueue.get('queue.length')).to.equal(2);
+    });
+
+    it('should throw `name` error', function() {
+      expect(function() {ajaxQueue.addRequests(Em.A([
+        {name:'some', sender: Em.Object.create()},
+        {name:'', sender: Em.Object.create()}
+      ]));}).to.throw(Error);
+    });
+
+    it('should throw `sender` error', function() {
+      expect(function() {ajaxQueue.addRequests(Em.A([
+        {name:'some', sender: Em.Object.create()},
+        {name:'some2', sender: {}}
+      ]));}).to.throw(Error);
+    });
+
+  });
+
+  describe('#start', function() {
+    it('should call runNextRequest', function() {
+      ajaxQueue.start();
+      expect(ajaxQueue.runNextRequest.called).to.equal(true);
+    });
+  });
+
+  describe('#runNextRequest', function() {
+    it('for empty queue App.ajax.send shouldn\'t be called', function() {
+      ajaxQueue.clear();
+      ajaxQueue.runNextRequest();
+      expect(App.ajax.send.called).to.equal(false);
+    });
+    it('when queue is empty finishedCallback should be called', function() {
+      ajaxQueue.clear();
+      ajaxQueue.runNextRequest();
+      expect(ajaxQueue.finishedCallback.called).to.equal(true);
+    });
+    it('if abortOnError is false queue shouldn\'t be interrupted', function() {
+      ajaxQueue.clear();
+      ajaxQueue.set('abortOnError', false);
+      ajaxQueue.addRequest({name:'some_fake', sender: Em.Object.create()}).addRequest({name: 'some_fake2', sender: Em.Object.create()}).start();
+      expect(ajaxQueue.runNextRequest.callCount).to.equal(3); // One for empty-queue
+    });
+  });
+
+});

+ 1 - 1
ambari-web/test/utils/ajax_test.js → ambari-web/test/utils/ajax/ajax_test.js

@@ -17,7 +17,7 @@
  */
 
 var App = require('app');
-require('utils/ajax');
+require('utils/ajax/ajax');
 
 describe('App.ajax', function() {