ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From alexantone...@apache.org
Subject ambari git commit: AMBARI-18339. Persist UI console errors from Admin View. (alexantonenko)
Date Thu, 08 Sep 2016 14:07:41 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk f18851698 -> 4e4f67ae8


AMBARI-18339. Persist UI console errors from Admin View. (alexantonenko)


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

Branch: refs/heads/trunk
Commit: 4e4f67ae87778ab487c766be9476e7a4445276ff
Parents: f188516
Author: Alex Antonenko <hiveww@gmail.com>
Authored: Thu Sep 8 14:08:31 2016 +0300
Committer: Alex Antonenko <hiveww@gmail.com>
Committed: Thu Sep 8 17:07:36 2016 +0300

----------------------------------------------------------------------
 .../resources/ui/admin-web/app/scripts/app.js   |  44 +++++-
 .../app/scripts/controllers/mainCtrl.js         |  20 ++-
 .../app/scripts/services/PermissionLoader.js    |   2 +-
 .../admin-web/app/scripts/services/Utility.js   |  24 ++-
 .../test/unit/controllers/mainCtrl_test.js      | 141 +++++++++++++----
 .../test/unit/services/Utility_test.js          | 153 +++++++++++++++++++
 .../global/errors_handler_controller.js         |   5 +-
 7 files changed, 350 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4e4f67ae/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js
index 78e538d..80e2813 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/app.js
@@ -31,7 +31,9 @@ angular.module('ambariAdminConsole', [
   testMode: (window.location.port == 8000),
   mockDataPrefix: 'assets/data/',
   isLDAPConfigurationSupported: false,
-  isLoginActivitiesSupported: false
+  isLoginActivitiesSupported: false,
+  maxStackTraceLength: 1000,
+  errorStorageSize: 500000
 })
 .config(['RestangularProvider', '$httpProvider', '$provide', 'Settings', function(RestangularProvider,
$httpProvider, $provide, Settings) {
   // Config Ajax-module
@@ -133,6 +135,46 @@ angular.module('ambariAdminConsole', [
     return $delegate;
   }]);
 
+  $provide.decorator('$exceptionHandler', ['$delegate', 'Utility', '$window', function ($delegate,
Utility, $window) {
+    return function (error, cause) {
+      var ls = JSON.parse($window.localStorage.getItem('errors')) || {},
+        key = new Date().getTime(),
+        origin = $window.location.origin || ($window.location.protocol + '//' + $window.location.host),
+        pattern = new RegExp(origin + '/.*scripts', 'g'),
+        stackTrace = error && error.stack && error.stack.replace(pattern,
'').substr(0, Settings.maxStackTraceLength),
+        file = error && error.fileName,
+        line = error && error.lineNumber,
+        col = error && error.columnNumber;
+
+      if (error && error.stack && (!file || !line || !col)) {
+        var patternText = '(' + $window.location.protocol + '//.*\\.js):(\\d+):(\\d+)',
+          details = error.stack.match(new RegExp(patternText));
+        file = file || (details && details [1]);
+        line = line || (details && Number(details [2]));
+        col = col || (details && Number(details [3]));
+      }
+
+      var val = {
+        file: file,
+        line: line,
+        col: col,
+        error: error.toString(),
+        stackTrace: stackTrace
+      };
+
+      //overwrite errors if storage full
+      if (JSON.stringify(ls).length > Settings.errorStorageSize) {
+        delete ls[Object.keys(ls).sort()[0]];
+      }
+
+      ls[key] = val;
+      var lsString = JSON.stringify(ls);
+      $window.localStorage.setItem('errors', lsString);
+      Utility.postUserPref('errors', ls);
+      $delegate(error, cause);
+    };
+  }]);
+
   if (!Array.prototype.find) {
     Array.prototype.find = function (callback, context) {
       if (this == null) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/4e4f67ae/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/mainCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/mainCtrl.js
b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/mainCtrl.js
index 7937658..c945644 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/mainCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/mainCtrl.js
@@ -18,7 +18,7 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('MainCtrl',['$scope','$rootScope','$window','Auth', 'Alert', '$modal', 'Cluster',
'View', '$translate', '$http', 'Settings', function($scope, $rootScope, $window, Auth, Alert,
$modal, Cluster, View, $translate, $http, Settings) {
+.controller('MainCtrl',['$scope','$rootScope','$window','Auth', 'Alert', '$modal', 'Cluster',
'View', '$translate', '$http', 'Settings', 'Utility', '$q', function($scope, $rootScope, $window,
Auth, Alert, $modal, Cluster, View, $translate, $http, Settings, Utility, $q) {
   var $t = $translate.instant;
   $scope.signOut = function() {
     Auth.signout().finally(function() {
@@ -28,16 +28,20 @@ angular.module('ambariAdminConsole')
 
   $scope.ambariVersion = null;
   $rootScope.supports = {};
+  $rootScope.authDataLoad = $q.defer();
 
-  $http.get(Settings.baseUrl + "/persist/user-pref-" + Auth.getCurrentUser() + "-supports")
-      .then(function(data) {
-        $rootScope.supports = data.data ? data.data : {};
-      });
+  Utility.getUserPref('user-pref-' + Auth.getCurrentUser() + '-supports').then(function(data)
{
+    $rootScope.supports = data.data ? data.data : {};
+  });
 
-  $http.get(Settings.baseUrl + "/users/"  + Auth.getCurrentUser() +  "/authorizations?fields=*")
+  $http.get(Settings.baseUrl + '/users/' + Auth.getCurrentUser() + '/authorizations?fields=*')
     .then(function(data) {
-      var auth = !!data.data && !!data.data.items ? data.data.items.map(function
(a){return a.AuthorizationInfo.authorization_id}) : [];
-      if(auth.indexOf('AMBARI.RENAME_CLUSTER') == -1){
+      var auth = !!data.data && !!data.data.items ? data.data.items.map(function
(a) {
+          return a.AuthorizationInfo.authorization_id;
+        }) : [],
+        canPersistData = auth.indexOf('CLUSTER.MANAGE_USER_PERSISTED_DATA') > -1;
+      $rootScope.authDataLoad.resolve(canPersistData);
+      if(auth.indexOf('AMBARI.RENAME_CLUSTER') == -1) {
         $window.location = $rootScope.fromSiteRoot("/#/main/dashboard");
       }
     });

http://git-wip-us.apache.org/repos/asf/ambari/blob/4e4f67ae/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js
b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js
index 13db1e6..988986b 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js
@@ -24,7 +24,7 @@ angular.module('ambariAdminConsole')
     var deferred = $q.defer();
 
     resource.getPermissions(params).then(function(permissions) {
-      var permissionsInner = {}; // Save object into closure, until it completely fills to
prevent blinkong
+      var permissionsInner = {}; // Save object into closure, until it completely fills to
prevent blinking
       angular.forEach(permissions, function(permission) {
         permission.GROUP = [];
         permission.USER = [];

http://git-wip-us.apache.org/repos/asf/ambari/blob/4e4f67ae/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Utility.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Utility.js
b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Utility.js
index 9439ba9..7ff10f8 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Utility.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Utility.js
@@ -20,7 +20,7 @@
  * This service should be used to keep all utility functions in one place that can be used
in any controller
  */
 angular.module('ambariAdminConsole')
-  .factory('Utility', [function() {
+  .factory('Utility', ['$injector', 'Settings', function ($injector, Settings) {
     return {
       /**
        *  if version1>= version2 then return true
@@ -64,6 +64,28 @@ angular.module('ambariAdminConsole')
           }
         }
         return result;
+      },
+
+      getUserPref: function (key) {
+        return $injector.get('$http').get(Settings.baseUrl + '/persist/' + key);
+      },
+
+      postUserPref: function (key, value) {
+        var deferred = $injector.get('$q').defer();
+        $injector.get('$rootScope').authDataLoad.promise.then(function (canPersistData) {
+          if (canPersistData) {
+            var keyValuePair = {};
+            keyValuePair[key] = JSON.stringify(value);
+            $injector.get('$http').post(Settings.baseUrl + '/persist/', JSON.stringify(keyValuePair)).then(function
() {
+              deferred.resolve();
+            }, function () {
+              deferred.reject();
+            });
+          } else {
+            deferred.reject();
+          }
+        });
+        return deferred.promise;
       }
     };
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/4e4f67ae/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/mainCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/mainCtrl_test.js
b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/mainCtrl_test.js
index 12c914e..f03dcb5 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/mainCtrl_test.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/mainCtrl_test.js
@@ -16,20 +16,33 @@
  * limitations under the License.
  */
 
-describe('#Auth', function () {
+describe('#MainCtrl', function () {
 
-  describe('signout', function () {
-    var scope, ctrl, $httpBackend, $window, clusterService,deferred;
-    beforeEach(module('ambariAdminConsole', function($provide){
-      $provide.value('$window', {location: {pathname: 'http://c6401.ambari.apache.org:8080/views/ADMIN_VIEW/2.0.0/INSTANCE/#/'}});
-      localStorage.ambari = JSON.stringify({app: {authenticated: true, loginName: 'admin',
user: 'user'}});
-    }));
-    afterEach(function() {
-      $httpBackend.verifyNoOutstandingExpectation();
-      $httpBackend.verifyNoOutstandingRequest();
+  var scope, ctrl, $httpBackend, $window, clusterService, deferred;
+
+  beforeEach(function () {
+    module('ambariAdminConsole', function ($provide) {
+      $provide.value('$window', {
+        location: {
+          pathname: 'http://c6401.ambari.apache.org:8080/views/ADMIN_VIEW/2.0.0/INSTANCE/#/'
+        },
+        localStorage: {
+          getItem: function () {
+            return null;
+          },
+          setItem: angular.noop
+        }
+      });
+      localStorage.ambari = JSON.stringify({
+        app: {
+          authenticated: true,
+          loginName: 'admin',
+          user: 'user'
+        }
+      });
     });
-    beforeEach(inject(function (_$httpBackend_, $rootScope, $controller, _$window_, _Cluster_,_$q_)
{
-      clusterService =  _Cluster_;
+    inject(function (_$httpBackend_, $rootScope, $controller, _$window_, _Cluster_, _$q_)
{
+      clusterService = _Cluster_;
       deferred = _$q_.defer();
       spyOn(clusterService, 'getStatus').andReturn(deferred.promise);
       deferred.resolve({
@@ -39,18 +52,15 @@ describe('#Auth', function () {
       });
       $window = _$window_;
       $httpBackend = _$httpBackend_;
-      var re = /api\/v1\/services\/AMBARI\/components\/AMBARI_SERVER.+/;
-      $httpBackend.whenGET(re).respond(200, {
-          RootServiceComponents: {
-            component_version: 2.2,
-            properties: {
-              'user.inactivity.timeout.default': 20
-            }
+      $httpBackend.whenGET(/api\/v1\/services\/AMBARI\/components\/AMBARI_SERVER.+/).respond(200,
{
+        RootServiceComponents: {
+          component_version: 2.2,
+          properties: {
+            'user.inactivity.timeout.default': 20
           }
+        }
       });
-      $httpBackend.whenGET(/\/api\/v1\/logout\?_=\d+/).respond(200,{message: "successfully
logged out"});
-      $httpBackend.whenGET(/\/api\/v1\/views.+/)
-        .respond(200,{
+      $httpBackend.whenGET(/\/api\/v1\/views.+/).respond(200, {
           "href": "http://c6401.ambari.apache.org:8080/api/v1/views?fields=versions/instances/ViewInstanceInfo&versions/ViewVersionInfo/system=false&versions/instances/ViewInstanceInfo/visible=true",
           "items": [
             {
@@ -97,18 +107,48 @@ describe('#Auth', function () {
             }
           ]
         });
-      $httpBackend.whenGET(/\/persist\/user-pref-.*/).respond(200, {data: {data: {addingNewRepository:
true}}});
-      $httpBackend.whenGET(/\/api\/v1\/users\/admin\/authorizations.*/).respond(200, {data:
{data: {items: [{AuthorizationInfo : {authorization_id : "AMBARI.RENAME_CLUSTER"}}]}}});
+      $httpBackend.whenGET(/\/persist\/user-pref-.*/).respond(200, {
+        data: {
+          data: {
+            addingNewRepository: true
+          }
+        }
+      });
       scope = $rootScope.$new();
       scope.$apply();
-      ctrl = $controller('MainCtrl', {$scope: scope});
-    }));
+      ctrl = $controller('MainCtrl', {
+        $scope: scope
+      });
+    });
+  });
+
+  afterEach(function() {
+    $httpBackend.verifyNoOutstandingExpectation();
+    $httpBackend.verifyNoOutstandingRequest();
+  });
+
+  describe('signout', function () {
+
+    beforeEach(function () {
+      $httpBackend.whenGET(/\/api\/v1\/logout\?_=\d+/).respond(200,{
+        message: "successfully logged out"
+      });
+      $httpBackend.whenGET(/\/api\/v1\/users\/admin\/authorizations.*/).respond(200, {
+        items: [
+          {
+            AuthorizationInfo: {
+              authorization_id: "AMBARI.RENAME_CLUSTER"
+            }
+          }
+        ]
+      });
+    });
 
     it('should reset window.location and ambari localstorage', function () {
       scope.signOut();
 
       runs(function() {
-        chai.expect($window.location.pathname).to.be.empty;
+        chai.expect($window.location.pathname).to.equal('/');
       });
 
       var data = JSON.parse(localStorage.ambari);
@@ -125,4 +165,51 @@ describe('#Auth', function () {
       chai.expect(scope.viewInstances[0].instance_name).to.equal('VisibleInstance');
     });
   });
+
+  describe('roles loading', function () {
+
+    var mock = {
+        callback: angular.noop
+      },
+      cases = [
+        {
+          canPersistData: true,
+          items: [
+            {
+              AuthorizationInfo: {
+                authorization_id: 'CLUSTER.MANAGE_USER_PERSISTED_DATA'
+              }
+            }
+          ],
+          title: 'user can persist data'
+        },
+        {
+          canPersistData: false,
+          items: [],
+          title: 'user can\'t persist data'
+        }
+      ];
+
+    angular.forEach(cases, function (item) {
+
+      describe(item.title, function () {
+
+        beforeEach(function () {
+          $httpBackend.whenGET(/\/api\/v1\/users\/admin\/authorizations.*/).respond(200,
{
+            items: item.items
+          });
+          spyOn(mock, 'callback');
+          scope.authDataLoad.promise.then(mock.callback);
+          $httpBackend.flush();
+        });
+
+        it('authDataLoad should be resolved with the correct argument', function () {
+          expect(mock.callback).toHaveBeenCalledWith(item.canPersistData);
+        });
+
+      });
+
+    });
+
+  });
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/4e4f67ae/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js
b/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js
new file mode 100644
index 0000000..6b0b17f
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/services/Utility_test.js
@@ -0,0 +1,153 @@
+/**
+ * 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.
+ */
+
+describe('Utility Service', function () {
+
+  var Utility, httpBackend, scope, ctrl, deferred,
+    obj = {
+      property: 'value'
+    };
+
+  beforeEach(function () {
+    module('ambariAdminConsole', function ($provide) {
+      $provide.value('$window', {});
+    });
+    inject(function (_Utility_, _$httpBackend_, $rootScope, $controller, _Cluster_, _$q_)
{
+      Utility = _Utility_;
+      httpBackend = _$httpBackend_;
+      deferred = _$q_.defer();
+      spyOn(_Cluster_, 'getStatus').andReturn(deferred.promise);
+      deferred.resolve({
+        Clusters: {
+          provisioning_state: 'INIT'
+        }
+      });
+      scope = $rootScope.$new();
+      scope.$apply();
+      ctrl = $controller('MainCtrl', {
+        $scope: scope
+      });
+      httpBackend.whenGET(/\/persist\/user-pref-.*/).respond(200, {});
+      httpBackend.whenGET(/api\/v1\/services\/AMBARI\/components\/AMBARI_SERVER.+/).respond(200,
{
+        RootServiceComponents: {
+          component_version: 2.2,
+          properties: {
+            'user.inactivity.timeout.default': 20
+          }
+        }
+      });
+      httpBackend.whenGET(/\/api\/v1\/views.+/).respond(200, {
+        items: []
+      });
+    });
+  });
+
+  describe('#getUserPref', function () {
+
+    var mock = {
+      callback: angular.noop
+    };
+
+    beforeEach(function () {
+      spyOn(mock, 'callback');
+      httpBackend.whenGET(/api\/v1\/persist\/key/).respond(200, obj);
+      httpBackend.whenGET(/\/api\/v1\/users\/.*\/authorizations.*/).respond(200, {
+        items: []
+      });
+      Utility.getUserPref('key').then(mock.callback);
+      httpBackend.flush();
+    });
+
+    it('should pass the received value', function () {
+      expect(mock.callback.mostRecentCall.args[0].data).toEqual(obj);
+    });
+
+  });
+
+  describe('#postUserPref', function () {
+
+    var mock = {
+        successCallback: angular.noop,
+        errorCallback: angular.noop
+      },
+      cases = [
+        {
+          status: 200,
+          items: [],
+          successCallbackCallCount: 0,
+          errorCallbackCallCount: 1,
+          title: 'user can\'t persist data'
+        },
+        {
+          status: 200,
+          items: [
+            {
+              AuthorizationInfo: {
+                authorization_id: 'CLUSTER.MANAGE_USER_PERSISTED_DATA'
+              }
+            }
+          ],
+          successCallbackCallCount: 1,
+          errorCallbackCallCount: 0,
+          title: 'user can persist data, POST request succeeds'
+        },
+        {
+          status: 500,
+          items: [
+            {
+              AuthorizationInfo: {
+                authorization_id: 'CLUSTER.MANAGE_USER_PERSISTED_DATA'
+              }
+            }
+          ],
+          successCallbackCallCount: 0,
+          errorCallbackCallCount: 1,
+          title: 'user can persist data, POST request fails'
+        }
+      ];
+
+    angular.forEach(cases, function (item) {
+
+      describe(item.title, function () {
+
+        beforeEach(function () {
+          httpBackend.whenGET(/\/api\/v1\/users\/.*\/authorizations.*/).respond(200, {
+            items: item.items
+          });
+          httpBackend.whenPOST(/api\/v1\/persist/).respond(item.status);
+          spyOn(mock, 'successCallback');
+          spyOn(mock, 'errorCallback');
+          Utility.postUserPref('key', obj).then(mock.successCallback, mock.errorCallback);
+          httpBackend.flush();
+        });
+
+        it('success callback', function () {
+          expect(mock.successCallback.callCount).toEqual(item.successCallbackCallCount);
+        });
+
+        it('error callback', function () {
+          expect(mock.errorCallback.callCount).toEqual(item.errorCallbackCallCount);
+        });
+
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4e4f67ae/ambari-web/app/controllers/global/errors_handler_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/errors_handler_controller.js b/ambari-web/app/controllers/global/errors_handler_controller.js
index 5774862..c5b1067 100644
--- a/ambari-web/app/controllers/global/errors_handler_controller.js
+++ b/ambari-web/app/controllers/global/errors_handler_controller.js
@@ -73,7 +73,10 @@ App.ErrorsHandlerController = Em.Controller.extend(App.UserPref, {
     var stackTrace = Em.get(Err || {}, 'stack');
 
     if (stackTrace) {
-      stackTrace = stackTrace.replace(/http:\/\/.*:8080\/javascripts/g, "").substr(0, this.MAX_TRACE_LENGTH);
+      var origin = location.origin || (location.protocol + '//' + location.host),
+        path = origin + location.pathname + 'javascripts',
+        pattern = new RegExp(path, 'g');
+      stackTrace = stackTrace.replace(pattern, '').substr(0, this.MAX_TRACE_LENGTH);
     }
 
     var val = {


Mime
View raw message