diff --git a/app/agent/components/volume-browser/volume-browser.js b/app/agent/components/volume-browser/volume-browser.js index 964803da0..78e963604 100644 --- a/app/agent/components/volume-browser/volume-browser.js +++ b/app/agent/components/volume-browser/volume-browser.js @@ -3,6 +3,7 @@ angular.module('portainer.agent').component('volumeBrowser', { controller: 'VolumeBrowserController', bindings: { volumeId: '<', - nodeName: '<' + nodeName: '<', + isUploadEnabled: '<' } }); diff --git a/app/agent/components/volume-browser/volumeBrowser.html b/app/agent/components/volume-browser/volumeBrowser.html index 3759f22d2..97c8a4da6 100644 --- a/app/agent/components/volume-browser/volumeBrowser.html +++ b/app/agent/components/volume-browser/volumeBrowser.html @@ -8,4 +8,7 @@ rename="$ctrl.rename(name, newName)" download="$ctrl.download(name)" delete="$ctrl.delete(name)" + + is-upload-allowed="$ctrl.isUploadEnabled" + on-file-selected-for-upload="$ctrl.onFileSelectedForUpload" > diff --git a/app/agent/components/volume-browser/volumeBrowserController.js b/app/agent/components/volume-browser/volumeBrowserController.js index 2fa4426b9..8db735a3b 100644 --- a/app/agent/components/volume-browser/volumeBrowserController.js +++ b/app/agent/components/volume-browser/volumeBrowserController.js @@ -84,6 +84,16 @@ function (HttpRequestHelper, VolumeBrowserService, FileSaver, Blob, ModalService }); } + this.onFileSelectedForUpload = function onFileSelectedForUpload(file) { + VolumeBrowserService.upload(ctrl.state.path, file, ctrl.volumeId) + .then(function onFileUpload() { + onFileUploaded(); + }) + .catch(function onFileUpload(err) { + Notifications.error('Failure', err, 'Unable to upload file'); + }); + }; + function parentPath(path) { if (path.lastIndexOf('/') === 0) { return '/'; @@ -112,4 +122,14 @@ function (HttpRequestHelper, VolumeBrowserService, FileSaver, Blob, ModalService }); }; + function onFileUploaded() { + refreshList(); + } + + function refreshList() { + browse(ctrl.state.path); + } + + + }]); diff --git a/app/agent/rest/agent.js b/app/agent/rest/agent.js index a7800717c..522296c3a 100644 --- a/app/agent/rest/agent.js +++ b/app/agent/rest/agent.js @@ -1,8 +1,10 @@ angular.module('portainer.agent') -.factory('Agent', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { +.factory('Agent', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'StateManager', + function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/agents', { - endpointId: EndpointProvider.endpointID + return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/v:version/agents', { + endpointId: EndpointProvider.endpointID, + version: StateManager.getAgentApiVersion }, { query: { method: 'GET', isArray: true } diff --git a/app/agent/rest/browse.js b/app/agent/rest/browse.js index 9496768eb..e78cd3206 100644 --- a/app/agent/rest/browse.js +++ b/app/agent/rest/browse.js @@ -1,8 +1,10 @@ angular.module('portainer.agent') -.factory('Browse', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { +.factory('Browse', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'StateManager', + function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { 'use strict'; - return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/browse/:action', { - endpointId: EndpointProvider.endpointID + return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/v:version/browse/:action', { + endpointId: EndpointProvider.endpointID, + version: StateManager.getAgentApiVersion }, { ls: { diff --git a/app/agent/rest/host.js b/app/agent/rest/host.js index a717def30..f184d2544 100644 --- a/app/agent/rest/host.js +++ b/app/agent/rest/host.js @@ -1,11 +1,12 @@ angular.module('portainer.agent').factory('Host', [ - '$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', - function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + '$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'StateManager', + function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) { 'use strict'; return $resource( - API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/host/:action', + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/v:version/host/:action', { - endpointId: EndpointProvider.endpointID + endpointId: EndpointProvider.endpointID, + version: StateManager.getAgentApiVersion }, { info: { method: 'GET', params: { action: 'info' } } diff --git a/app/agent/rest/ping.js b/app/agent/rest/ping.js new file mode 100644 index 000000000..7eeb93f2e --- /dev/null +++ b/app/agent/rest/ping.js @@ -0,0 +1,33 @@ +angular.module('portainer.agent').factory('AgentPing', [ + '$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', '$q', + function AgentPingFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, $q) { + 'use strict'; + return $resource( + API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/ping', + { + endpointId: EndpointProvider.endpointID + }, + { + ping: { + method: 'GET', + interceptor: { + response: function versionInterceptor(response) { + var instance = response.resource; + var version = + response.headers('Portainer-Agent-Api-Version') || 1; + instance.version = Number(version); + return instance; + }, + responseError: function versionResponseError(error) { + // 404 - agent is up - set version to 1 + if (error.status === 404) { + return { version: 1 }; + } + return $q.reject(error); + } + } + } + } + ); + } +]); diff --git a/app/agent/rest/v1/agent.js b/app/agent/rest/v1/agent.js new file mode 100644 index 000000000..a78755b35 --- /dev/null +++ b/app/agent/rest/v1/agent.js @@ -0,0 +1,10 @@ +angular.module('portainer.agent') +.factory('AgentVersion1', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/agents', { + endpointId: EndpointProvider.endpointID + }, + { + query: { method: 'GET', isArray: true } + }); +}]); diff --git a/app/agent/rest/v1/browse.js b/app/agent/rest/v1/browse.js new file mode 100644 index 000000000..d576433fa --- /dev/null +++ b/app/agent/rest/v1/browse.js @@ -0,0 +1,22 @@ +angular.module('portainer.agent') +.factory('BrowseVersion1', ['$resource', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) { + 'use strict'; + return $resource(API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/browse/:volumeID/:action', { + endpointId: EndpointProvider.endpointID + }, + { + ls: { + method: 'GET', isArray: true, params: { action: 'ls' } + }, + get: { + method: 'GET', params: { action: 'get' }, + transformResponse: browseGetResponse + }, + delete: { + method: 'DELETE', params: { action: 'delete' } + }, + rename: { + method: 'PUT', params: { action: 'rename' } + } + }); +}]); diff --git a/app/agent/services/agentService.js b/app/agent/services/agentService.js index 7143e1e0f..17a2c3166 100644 --- a/app/agent/services/agentService.js +++ b/app/agent/services/agentService.js @@ -1,12 +1,17 @@ angular.module('portainer.agent').factory('AgentService', [ - '$q', 'Agent','HttpRequestHelper', 'Host', - function AgentServiceFactory($q, Agent, HttpRequestHelper, Host) { + '$q', 'Agent', 'AgentVersion1', 'HttpRequestHelper', 'Host', 'StateManager', + function AgentServiceFactory($q, Agent, AgentVersion1, HttpRequestHelper, Host, StateManager) { 'use strict'; var service = {}; service.agents = agents; service.hostInfo = hostInfo; + function getAgentApiVersion() { + var state = StateManager.getState(); + return state.endpoint.agentApiVersion; + } + function hostInfo(nodeName) { HttpRequestHelper.setPortainerAgentTargetHeader(nodeName); return Host.info().$promise; @@ -15,7 +20,10 @@ angular.module('portainer.agent').factory('AgentService', [ function agents() { var deferred = $q.defer(); - Agent.query({}) + var agentVersion = getAgentApiVersion(); + var service = agentVersion > 1 ? Agent : AgentVersion1; + + service.query({ version: agentVersion }) .$promise.then(function success(data) { var agents = data.map(function(item) { return new AgentViewModel(item); diff --git a/app/agent/services/hostBrowserService.js b/app/agent/services/hostBrowserService.js index 935d34be4..6f292c36a 100644 --- a/app/agent/services/hostBrowserService.js +++ b/app/agent/services/hostBrowserService.js @@ -1,6 +1,6 @@ angular.module('portainer.agent').factory('HostBrowserService', [ - 'Browse', 'Upload', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', '$q', - function HostBrowserServiceFactory(Browse, Upload, API_ENDPOINT_ENDPOINTS, EndpointProvider, $q) { + 'Browse', 'Upload', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', '$q', 'StateManager', + function HostBrowserServiceFactory(Browse, Upload, API_ENDPOINT_ENDPOINTS, EndpointProvider, $q, StateManager) { var service = {}; service.ls = ls; @@ -31,9 +31,17 @@ angular.module('portainer.agent').factory('HostBrowserService', [ function upload(path, file, onProgress) { var deferred = $q.defer(); - var url = API_ENDPOINT_ENDPOINTS + '/' + EndpointProvider.endpointID() + '/docker/browse/put'; + var agentVersion = StateManager.getAgentApiVersion(); + var url = + API_ENDPOINT_ENDPOINTS + + '/' + + EndpointProvider.endpointID() + + '/docker' + + (agentVersion > 1 ? '/v' + agentVersion : '') + + '/browse/put'; + Upload.upload({ - url: url, + url: url, data: { file: file, Path: path } }).then(deferred.resolve, deferred.reject, onProgress); return deferred.promise; diff --git a/app/agent/services/pingService.js b/app/agent/services/pingService.js new file mode 100644 index 000000000..765d47a5f --- /dev/null +++ b/app/agent/services/pingService.js @@ -0,0 +1,14 @@ +angular.module('portainer.agent').service('AgentPingService', [ + 'AgentPing', + function AgentPingService(AgentPing) { + var service = {}; + + service.ping = ping; + + function ping() { + return AgentPing.ping().$promise; + } + + return service; + } +]); diff --git a/app/agent/services/volumeBrowserService.js b/app/agent/services/volumeBrowserService.js index 1da020c38..a4ffdbf9d 100644 --- a/app/agent/services/volumeBrowserService.js +++ b/app/agent/services/volumeBrowserService.js @@ -1,27 +1,60 @@ angular.module('portainer.agent').factory('VolumeBrowserService', [ - '$q', 'Browse', - function VolumeBrowserServiceFactory($q, Browse) { + 'StateManager', 'Browse', 'BrowseVersion1', '$q', 'API_ENDPOINT_ENDPOINTS', 'EndpointProvider', 'Upload', + function VolumeBrowserServiceFactory(StateManager, Browse, BrowseVersion1, $q, API_ENDPOINT_ENDPOINTS, EndpointProvider, Upload) { 'use strict'; var service = {}; + function getAgentApiVersion() { + var state = StateManager.getState(); + return state.endpoint.agentApiVersion; + } + + function getBrowseService() { + var agentVersion = getAgentApiVersion(); + return agentVersion > 1 ? Browse : BrowseVersion1; + } + service.ls = function(volumeId, path) { - return Browse.ls({ volumeID: volumeId, path: path }).$promise; + return getBrowseService().ls({ volumeID: volumeId, path: path, version: getAgentApiVersion() }).$promise; }; service.get = function(volumeId, path) { - return Browse.get({ volumeID: volumeId, path: path }).$promise; + return getBrowseService().get({ volumeID: volumeId, path: path, version: getAgentApiVersion() }).$promise; }; service.delete = function(volumeId, path) { - return Browse.delete({ volumeID: volumeId, path: path }).$promise; + return getBrowseService().delete({ volumeID: volumeId, path: path, version: getAgentApiVersion() }).$promise; }; service.rename = function(volumeId, path, newPath) { var payload = { - CurrentFilePath: path, + CurrentFilePath: path, NewFilePath: newPath }; - return Browse.rename({ volumeID: volumeId }, payload).$promise; + return getBrowseService().rename({ volumeID: volumeId, version: getAgentApiVersion() }, payload).$promise; + }; + + service.upload = function upload(path, file, volumeId, onProgress) { + var deferred = $q.defer(); + var agentVersion = StateManager.getAgentApiVersion(); + if (agentVersion <2) { + deferred.reject('upload is not supported on this agent version'); + return; + } + var url = + API_ENDPOINT_ENDPOINTS + + '/' + + EndpointProvider.endpointID() + + '/docker' + + '/v' + agentVersion + + '/browse/put?volumeID=' + + volumeId; + + Upload.upload({ + url: url, + data: { file: file, Path: path } + }).then(deferred.resolve, deferred.reject, onProgress); + return deferred.promise; }; return service; diff --git a/app/docker/components/host-overview/host-overview.html b/app/docker/components/host-overview/host-overview.html index 81ac13c62..e38ccabb0 100644 --- a/app/docker/components/host-overview/host-overview.html +++ b/app/docker/components/host-overview/host-overview.html @@ -10,12 +10,12 @@ - - + + \ No newline at end of file diff --git a/app/docker/components/host-overview/host-overview.js b/app/docker/components/host-overview/host-overview.js index 78883e4e8..36ab4087a 100644 --- a/app/docker/components/host-overview/host-overview.js +++ b/app/docker/components/host-overview/host-overview.js @@ -6,6 +6,7 @@ angular.module('portainer.docker').component('hostOverview', { devices: '<', disks: '<', isAgent: '<', + agentApiVersion: '<', refreshUrl: '@', browseUrl: '@' }, diff --git a/app/docker/components/host-view-panels/host-details-panel/host-details-panel.html b/app/docker/components/host-view-panels/host-details-panel/host-details-panel.html index 9bb9b7f85..8b46f466f 100644 --- a/app/docker/components/host-view-panels/host-details-panel/host-details-panel.html +++ b/app/docker/components/host-view-panels/host-details-panel/host-details-panel.html @@ -26,7 +26,7 @@ Total memory {{ $ctrl.host.totalMemory | humansize }} - +