diff --git a/api/http/handler/endpoints/endpoint_inspect.go b/api/http/handler/endpoints/endpoint_inspect.go index 82d2cb7b9..e382b3f16 100644 --- a/api/http/handler/endpoints/endpoint_inspect.go +++ b/api/http/handler/endpoints/endpoint_inspect.go @@ -23,5 +23,12 @@ func (handler *Handler) endpointInspect(w http.ResponseWriter, r *http.Request) return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find an endpoint with the specified identifier inside the database", err} } + err = handler.requestBouncer.EndpointAccess(r, endpoint) + if err != nil { + return &httperror.HandlerError{http.StatusForbidden, "Permission denied to access endpoint", portainer.ErrEndpointAccessDenied} + } + + hideFields(endpoint) + return response.JSON(w, endpoint) } diff --git a/api/http/handler/endpoints/handler.go b/api/http/handler/endpoints/handler.go index 69440037e..1c6e79cc4 100644 --- a/api/http/handler/endpoints/handler.go +++ b/api/http/handler/endpoints/handler.go @@ -25,6 +25,7 @@ func hideFields(endpoint *portainer.Endpoint) { type Handler struct { *mux.Router authorizeEndpointManagement bool + requestBouncer *security.RequestBouncer EndpointService portainer.EndpointService EndpointGroupService portainer.EndpointGroupService FileService portainer.FileService @@ -37,6 +38,7 @@ func NewHandler(bouncer *security.RequestBouncer, authorizeEndpointManagement bo h := &Handler{ Router: mux.NewRouter(), authorizeEndpointManagement: authorizeEndpointManagement, + requestBouncer: bouncer, } h.Handle("/endpoints", @@ -44,7 +46,7 @@ func NewHandler(bouncer *security.RequestBouncer, authorizeEndpointManagement bo h.Handle("/endpoints", bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointList))).Methods(http.MethodGet) h.Handle("/endpoints/{id}", - bouncer.AdministratorAccess(httperror.LoggerHandler(h.endpointInspect))).Methods(http.MethodGet) + bouncer.RestrictedAccess(httperror.LoggerHandler(h.endpointInspect))).Methods(http.MethodGet) h.Handle("/endpoints/{id}", bouncer.AdministratorAccess(httperror.LoggerHandler(h.endpointUpdate))).Methods(http.MethodPut) h.Handle("/endpoints/{id}/access", diff --git a/api/swagger.yaml b/api/swagger.yaml index 07c5a9f45..fec94d1dd 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -320,7 +320,7 @@ paths: summary: "Inspect an endpoint" description: | Retrieve details abount an endpoint. - **Access policy**: administrator + **Access policy**: restricted operationId: "EndpointInspect" produces: - "application/json" diff --git a/app/docker/filters/filters.js b/app/docker/filters/filters.js index 9b0ba8c0b..b6f9a71dd 100644 --- a/app/docker/filters/filters.js +++ b/app/docker/filters/filters.js @@ -218,6 +218,30 @@ angular.module('portainer.docker') return runningTasks; }; }) +.filter('containerswithstatus', function () { + 'use strict'; + return function (containers, status) { + var containersWithStatus = 0; + for (var i = 0; i < containers.length; i++) { + var container = containers[i]; + if (container.Status === status) { + containersWithStatus++; + } + } + return containersWithStatus; + }; +}) +.filter('imagestotalsize', function () { + 'use strict'; + return function (images) { + var totalImageSize = 0; + for (var i = 0; i < images.length; i++) { + var item = images[i]; + totalImageSize += item.VirtualSize; + } + return totalImageSize; + }; +}) .filter('tasknodename', function () { 'use strict'; return function (nodeId, nodes) { diff --git a/app/docker/views/dashboard/dashboard.html b/app/docker/views/dashboard/dashboard.html index 26c22be3c..86950c43e 100644 --- a/app/docker/views/dashboard/dashboard.html +++ b/app/docker/views/dashboard/dashboard.html @@ -34,32 +34,37 @@ -
+
- + - - + + - - + + - - - - - - - - - - + +
Name{{ infoData.Name }}Endpoint + {{ endpoint.Name }} + {{ info.NCPU }} {{ info.MemTotal | humansize }} + - {{ info.Swarm && info.Swarm.NodeID !== '' ? 'Swarm' : 'Standalone' }} {{ info.ServerVersion }} + Agent +
Docker version{{ infoData.ServerVersion }}URL{{ endpoint.URL | stripprotocol }}
CPU{{ infoData.NCPU }}
Memory{{ infoData.MemTotal|humansize }}
Node role{{ infoData.Swarm.ControlAvailable ? 'Manager' : 'Worker' }}Tags + + - + + + + {{ tag }}{{ $last? '' : ', ' }} + + +
@@ -102,7 +107,7 @@ - -
+
-
{{ imageData.size|humansize }}
+
{{ images | imagestotalsize | humansize }}
-
{{ imageData.total }}
+
{{ images.length }}
Images
@@ -142,7 +147,7 @@
-
{{ volumeData.total }}
+
{{ volumeCount }}
Volumes
@@ -155,7 +160,7 @@
-
{{ networkData.total }}
+
{{ networkCount }}
Networks
diff --git a/app/docker/views/dashboard/dashboardController.js b/app/docker/views/dashboard/dashboardController.js index 4f478bc60..d9bf1b2c4 100644 --- a/app/docker/views/dashboard/dashboardController.js +++ b/app/docker/views/dashboard/dashboardController.js @@ -1,95 +1,33 @@ angular.module('portainer.docker') -.controller('DashboardController', ['$scope', '$q', 'Container', 'ContainerHelper', 'Image', 'Network', 'Volume', 'SystemService', 'ServiceService', 'StackService', 'Notifications', 'EndpointProvider', -function ($scope, $q, Container, ContainerHelper, Image, Network, Volume, SystemService, ServiceService, StackService, Notifications, EndpointProvider) { - - $scope.containerData = { - total: 0 - }; - $scope.imageData = { - total: 0 - }; - $scope.networkData = { - total: 0 - }; - $scope.volumeData = { - total: 0 - }; - - $scope.serviceCount = 0; - $scope.stackCount = 0; - - function prepareContainerData(d) { - var running = 0; - var stopped = 0; - var containers = d; - - for (var i = 0; i < containers.length; i++) { - var item = containers[i]; - if (item.Status.indexOf('Up') !== -1) { - running += 1; - } else if (item.Status.indexOf('Exit') !== -1) { - stopped += 1; - } - } - $scope.containerData.running = running; - $scope.containerData.stopped = stopped; - $scope.containerData.total = containers.length; - } - - function prepareImageData(d) { - var images = d; - var totalImageSize = 0; - for (var i = 0; i < images.length; i++) { - var item = images[i]; - totalImageSize += item.VirtualSize; - } - $scope.imageData.total = images.length; - $scope.imageData.size = totalImageSize; - } - - function prepareVolumeData(d) { - var volumes = d.Volumes; - if (volumes) { - $scope.volumeData.total = volumes.length; - } - } - - function prepareNetworkData(d) { - var networks = d; - $scope.networkData.total = networks.length; - } - - function prepareInfoData(d) { - var info = d; - $scope.infoData = info; - } +.controller('DashboardController', ['$scope', '$q', 'ContainerService', 'ImageService', 'NetworkService', 'VolumeService', 'SystemService', 'ServiceService', 'StackService', 'EndpointService', 'Notifications', 'EndpointProvider', +function ($scope, $q, ContainerService, ImageService, NetworkService, VolumeService, SystemService, ServiceService, StackService, EndpointService, Notifications, EndpointProvider) { function initView() { var endpointMode = $scope.applicationState.endpoint.mode; var endpointId = EndpointProvider.endpointID(); - $q.all([ - Container.query({all: 1}).$promise, - Image.query({}).$promise, - Volume.query({}).$promise, - Network.query({}).$promise, - SystemService.info(), - endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER' ? ServiceService.services() : [], - StackService.stacks( - true, - endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER', - endpointId - ) - ]).then(function (d) { - prepareContainerData(d[0]); - prepareImageData(d[1]); - prepareVolumeData(d[2]); - prepareNetworkData(d[3]); - prepareInfoData(d[4]); - $scope.serviceCount = d[5].length; - $scope.stackCount = d[6].length; - }, function(e) { - Notifications.error('Failure', e, 'Unable to load dashboard data'); + $q.all({ + containers: ContainerService.containers(1), + images: ImageService.images(false), + volumes: VolumeService.volumes(), + networks: NetworkService.networks(true, true, true), + services: endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER' ? ServiceService.services() : [], + stacks: StackService.stacks(true, endpointMode.provider === 'DOCKER_SWARM_MODE' && endpointMode.role === 'MANAGER', endpointId), + info: SystemService.info(), + endpoint: EndpointService.endpoint(endpointId) + }) + .then(function success(data) { + $scope.containers = data.containers; + $scope.images = data.images; + $scope.volumeCount = data.volumes.length; + $scope.networkCount = data.networks.length; + $scope.serviceCount = data.services.length; + $scope.stackCount = data.stacks.length; + $scope.info = data.info; + $scope.endpoint = data.endpoint; + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to load dashboard data'); }); }