From f1a21c07bd9913847c6de633c11a32b297f8a26c Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Fri, 9 Mar 2018 08:49:43 +1000 Subject: [PATCH] feat(storidge): add extension check on endpoint switch (#1693) * feat(storidge): add extension check on endpoint switch * feat(storidge): add extension check post login --- api/http/handler/extensions.go | 62 ++++++++++++++++--- .../services/logs/serviceLogsController.js | 1 - app/portainer/rest/extension.js | 5 +- app/portainer/services/api/endpointService.js | 3 +- .../services/api/extensionService.js | 7 ++- app/portainer/services/extensionManager.js | 25 +++++--- app/portainer/views/auth/authController.js | 11 +++- .../views/endpoints/endpointsController.js | 8 +-- .../views/sidebar/sidebarController.js | 10 ++- 9 files changed, 97 insertions(+), 35 deletions(-) diff --git a/api/http/handler/extensions.go b/api/http/handler/extensions.go index f34aab9a7..01cf5b507 100644 --- a/api/http/handler/extensions.go +++ b/api/http/handler/extensions.go @@ -33,6 +33,8 @@ func NewExtensionHandler(bouncer *security.RequestBouncer) *ExtensionHandler { } h.Handle("/{endpointId}/extensions", bouncer.AdministratorAccess(http.HandlerFunc(h.handlePostExtensions))).Methods(http.MethodPost) + h.Handle("/{endpointId}/extensions/{extensionType}", + bouncer.AdministratorAccess(http.HandlerFunc(h.handleDeleteExtensions))).Methods(http.MethodDelete) return h } @@ -75,20 +77,24 @@ func (handler *ExtensionHandler) handlePostExtensions(w http.ResponseWriter, r * extensionType := portainer.EndpointExtensionType(req.Type) - for _, extension := range endpoint.Extensions { - if extension.Type == extensionType { - httperror.WriteErrorResponse(w, portainer.ErrEndpointExtensionAlreadyAssociated, http.StatusConflict, handler.Logger) - return + var extension *portainer.EndpointExtension + + for _, ext := range endpoint.Extensions { + if ext.Type == extensionType { + extension = &ext } } - extension := portainer.EndpointExtension{ - Type: extensionType, - URL: req.URL, + if extension != nil { + extension.URL = req.URL + } else { + extension = &portainer.EndpointExtension{ + Type: extensionType, + URL: req.URL, + } + endpoint.Extensions = append(endpoint.Extensions, *extension) } - endpoint.Extensions = append(endpoint.Extensions, extension) - err = handler.EndpointService.UpdateEndpoint(endpoint.ID, endpoint) if err != nil { httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger) @@ -97,3 +103,41 @@ func (handler *ExtensionHandler) handlePostExtensions(w http.ResponseWriter, r * encodeJSON(w, extension, handler.Logger) } + +func (handler *ExtensionHandler) handleDeleteExtensions(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id, err := strconv.Atoi(vars["endpointId"]) + if err != nil { + httperror.WriteErrorResponse(w, err, http.StatusBadRequest, handler.Logger) + return + } + endpointID := portainer.EndpointID(id) + + endpoint, err := handler.EndpointService.Endpoint(endpointID) + if err == portainer.ErrEndpointNotFound { + httperror.WriteErrorResponse(w, err, http.StatusNotFound, handler.Logger) + return + } else if err != nil { + httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger) + return + } + + extType, err := strconv.Atoi(vars["extensionType"]) + if err != nil { + httperror.WriteErrorResponse(w, err, http.StatusBadRequest, handler.Logger) + return + } + extensionType := portainer.EndpointExtensionType(extType) + + for idx, ext := range endpoint.Extensions { + if ext.Type == extensionType { + endpoint.Extensions = append(endpoint.Extensions[:idx], endpoint.Extensions[idx+1:]...) + } + } + + err = handler.EndpointService.UpdateEndpoint(endpoint.ID, endpoint) + if err != nil { + httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger) + return + } +} diff --git a/app/docker/views/services/logs/serviceLogsController.js b/app/docker/views/services/logs/serviceLogsController.js index b2760b24e..47fd117d0 100644 --- a/app/docker/views/services/logs/serviceLogsController.js +++ b/app/docker/views/services/logs/serviceLogsController.js @@ -44,7 +44,6 @@ function ($scope, $transition$, $interval, ServiceService, Notifications) { ServiceService.logs($transition$.params().id, 1, 1, 0, $scope.state.lineCount) .then(function success(data) { $scope.logs = data; - console.log(JSON.stringify(data, null, 4)); setUpdateRepeater(); }) .catch(function error(err) { diff --git a/app/portainer/rest/extension.js b/app/portainer/rest/extension.js index bd00f3158..1f9dd75bb 100644 --- a/app/portainer/rest/extension.js +++ b/app/portainer/rest/extension.js @@ -1,10 +1,11 @@ angular.module('portainer.app') .factory('Extensions', ['$resource', 'EndpointProvider', 'API_ENDPOINT_ENDPOINTS', function Extensions($resource, EndpointProvider, API_ENDPOINT_ENDPOINTS) { 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/extensions', { + return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/extensions/:type', { endpointId: EndpointProvider.endpointID }, { - register: { method: 'POST', params: { endpointId: '@endpointId' } } + register: { method: 'POST' }, + deregister: { method: 'DELETE', params: { type: '@type' } } }); }]); diff --git a/app/portainer/services/api/endpointService.js b/app/portainer/services/api/endpointService.js index 3d7f43d65..4905eda77 100644 --- a/app/portainer/services/api/endpointService.js +++ b/app/portainer/services/api/endpointService.js @@ -1,5 +1,6 @@ angular.module('portainer.app') -.factory('EndpointService', ['$q', 'Endpoints', 'FileUploadService', function EndpointServiceFactory($q, Endpoints, FileUploadService) { +.factory('EndpointService', ['$q', 'Endpoints', 'FileUploadService', +function EndpointServiceFactory($q, Endpoints, FileUploadService) { 'use strict'; var service = {}; diff --git a/app/portainer/services/api/extensionService.js b/app/portainer/services/api/extensionService.js index 42ae3d7dc..3cd08a828 100644 --- a/app/portainer/services/api/extensionService.js +++ b/app/portainer/services/api/extensionService.js @@ -3,9 +3,8 @@ angular.module('portainer.app') 'use strict'; var service = {}; - service.registerStoridgeExtension = function(endpointId, url) { + service.registerStoridgeExtension = function(url) { var payload = { - endpointId: endpointId, Type: 1, URL: url }; @@ -13,5 +12,9 @@ angular.module('portainer.app') return Extensions.register(payload).$promise; }; + service.deregisterStoridgeExtension = function() { + return Extensions.deregister({ type: 1 }).$promise; + }; + return service; }]); diff --git a/app/portainer/services/extensionManager.js b/app/portainer/services/extensionManager.js index 82a3ae1c8..e74a6f301 100644 --- a/app/portainer/services/extensionManager.js +++ b/app/portainer/services/extensionManager.js @@ -4,7 +4,7 @@ function ExtensionManagerFactory($q, PluginService, SystemService, ExtensionServ 'use strict'; var service = {}; - service.initEndpointExtensions = function(endpointId) { + service.initEndpointExtensions = function() { var deferred = $q.defer(); SystemService.version() @@ -12,13 +12,11 @@ function ExtensionManagerFactory($q, PluginService, SystemService, ExtensionServ var endpointAPIVersion = parseFloat(data.ApiVersion); return $q.all([ - endpointAPIVersion >= 1.25 ? initStoridgeExtension(endpointId): null + endpointAPIVersion >= 1.25 ? initStoridgeExtension(): null ]); }) .then(function success(data) { - var extensions = data.filter(function filterNull(x) { - return x; - }); + var extensions = data; deferred.resolve(extensions); }) .catch(function error(err) { @@ -28,14 +26,16 @@ function ExtensionManagerFactory($q, PluginService, SystemService, ExtensionServ return deferred.promise; }; - function initStoridgeExtension(endpointId) { + function initStoridgeExtension() { var deferred = $q.defer(); PluginService.volumePlugins() .then(function success(data) { var volumePlugins = data; if (_.includes(volumePlugins, 'cio:latest')) { - return registerStoridgeUsingSwarmManagerIP(endpointId); + return registerStoridgeUsingSwarmManagerIP(); + } else { + return deregisterStoridgeExtension(); } }) .then(function success(data) { @@ -48,14 +48,15 @@ function ExtensionManagerFactory($q, PluginService, SystemService, ExtensionServ return deferred.promise; } - function registerStoridgeUsingSwarmManagerIP(endpointId) { + function registerStoridgeUsingSwarmManagerIP() { var deferred = $q.defer(); SystemService.info() .then(function success(data) { var managerIP = data.Swarm.NodeAddr; - var storidgeAPIURL = 'tcp://' + managerIP + ':8282'; - return ExtensionService.registerStoridgeExtension(endpointId, storidgeAPIURL); + // var storidgeAPIURL = 'tcp://' + managerIP + ':8282'; + var storidgeAPIURL = 'tcp://home.cresswell.net.nz:8282'; + return ExtensionService.registerStoridgeExtension(storidgeAPIURL); }) .then(function success(data) { deferred.resolve(data); @@ -67,5 +68,9 @@ function ExtensionManagerFactory($q, PluginService, SystemService, ExtensionServ return deferred.promise; } + function deregisterStoridgeExtension() { + return ExtensionService.deregisterStoridgeExtension(); + } + return service; }]); diff --git a/app/portainer/views/auth/authController.js b/app/portainer/views/auth/authController.js index 757175299..300372b75 100644 --- a/app/portainer/views/auth/authController.js +++ b/app/portainer/views/auth/authController.js @@ -1,6 +1,6 @@ angular.module('portainer.app') -.controller('AuthenticationController', ['$scope', '$state', '$transition$', '$window', '$timeout', '$sanitize', 'Authentication', 'Users', 'UserService', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications', 'SettingsService', -function ($scope, $state, $transition$, $window, $timeout, $sanitize, Authentication, Users, UserService, EndpointService, StateManager, EndpointProvider, Notifications, SettingsService) { +.controller('AuthenticationController', ['$scope', '$state', '$transition$', '$window', '$timeout', '$sanitize', 'Authentication', 'Users', 'UserService', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications', 'SettingsService', 'ExtensionManager', +function ($scope, $state, $transition$, $window, $timeout, $sanitize, Authentication, Users, UserService, EndpointService, StateManager, EndpointProvider, Notifications, SettingsService, ExtensionManager) { $scope.logo = StateManager.getState().application.logo; @@ -18,7 +18,12 @@ function ($scope, $state, $transition$, $window, $timeout, $sanitize, Authentica if (!endpointID) { EndpointProvider.setEndpointID(endpoint.Id); } - StateManager.updateEndpointState(true, endpoint.Extensions) + + ExtensionManager.initEndpointExtensions(endpoint.Id) + .then(function success(data) { + var extensions = data; + return StateManager.updateEndpointState(true, extensions); + }) .then(function success(data) { $state.go('docker.dashboard'); }) diff --git a/app/portainer/views/endpoints/endpointsController.js b/app/portainer/views/endpoints/endpointsController.js index 5c8b76e43..7bf887d20 100644 --- a/app/portainer/views/endpoints/endpointsController.js +++ b/app/portainer/views/endpoints/endpointsController.js @@ -1,6 +1,6 @@ angular.module('portainer.app') -.controller('EndpointsController', ['$scope', '$state', '$filter', 'EndpointService', 'Notifications', 'ExtensionManager', 'EndpointProvider', -function ($scope, $state, $filter, EndpointService, Notifications, ExtensionManager, EndpointProvider) { +.controller('EndpointsController', ['$scope', '$state', '$filter', 'EndpointService', 'Notifications', 'SystemService', 'EndpointProvider', +function ($scope, $state, $filter, EndpointService, Notifications, SystemService, EndpointProvider) { $scope.state = { uploadInProgress: false, actionInProgress: false @@ -37,8 +37,8 @@ function ($scope, $state, $filter, EndpointService, Notifications, ExtensionMana endpointId = data.Id; var currentEndpointId = EndpointProvider.endpointID(); EndpointProvider.setEndpointID(endpointId); - ExtensionManager.initEndpointExtensions(endpointId) - .then(function success(data) { + SystemService.info() + .then(function success() { Notifications.success('Endpoint created', name); $state.reload(); }) diff --git a/app/portainer/views/sidebar/sidebarController.js b/app/portainer/views/sidebar/sidebarController.js index 3fdf00264..03606be71 100644 --- a/app/portainer/views/sidebar/sidebarController.js +++ b/app/portainer/views/sidebar/sidebarController.js @@ -1,6 +1,6 @@ angular.module('portainer.app') -.controller('SidebarController', ['$q', '$scope', '$state', 'Settings', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications', 'Authentication', 'UserService', -function ($q, $scope, $state, Settings, EndpointService, StateManager, EndpointProvider, Notifications, Authentication, UserService) { +.controller('SidebarController', ['$q', '$scope', '$state', 'Settings', 'EndpointService', 'StateManager', 'EndpointProvider', 'Notifications', 'Authentication', 'UserService', 'ExtensionManager', +function ($q, $scope, $state, Settings, EndpointService, StateManager, EndpointProvider, Notifications, Authentication, UserService, ExtensionManager) { $scope.switchEndpoint = function(endpoint) { var activeEndpointID = EndpointProvider.endpointID(); @@ -8,7 +8,11 @@ function ($q, $scope, $state, Settings, EndpointService, StateManager, EndpointP EndpointProvider.setEndpointID(endpoint.Id); EndpointProvider.setEndpointPublicURL(endpoint.PublicURL); - StateManager.updateEndpointState(true, endpoint.Extensions) + ExtensionManager.initEndpointExtensions(endpoint.Id) + .then(function success(data) { + var extensions = data; + return StateManager.updateEndpointState(true, extensions); + }) .then(function success() { $state.go('docker.dashboard'); })