mirror of https://github.com/portainer/portainer
feat(app): toggle features based on agent API version (#2378)
* feat(agent): get agent's version from ping * feat(agent): add version to api url * feat(agent): query agent with api version * feat(agent): rename agent api version name on state * feat(agent): disable feature based on agent's api version * style(agent): rename ping rest service + remove whitespaces * style(state): remove whitespace * style(agent): add whitespace * fix(agent): remove check for error status 403 * refactor(agent): rename ping file name * refactor(agent): move old services to v1 folder * refactor(agent): turn ping service to usual pattern * refactor(agent): change version to a global variable * refactor(agent): move ping to version2 * refactor(agent): restore ping to use root ping * fix(volumes): add volumeID to browse api path * feat(volume): add upload button to volume browserpull/2401/head
parent
cca378b2e8
commit
9813099aa4
|
@ -3,6 +3,7 @@ angular.module('portainer.agent').component('volumeBrowser', {
|
|||
controller: 'VolumeBrowserController',
|
||||
bindings: {
|
||||
volumeId: '<',
|
||||
nodeName: '<'
|
||||
nodeName: '<',
|
||||
isUploadEnabled: '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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"
|
||||
></files-datatable>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}]);
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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' } }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
]);
|
|
@ -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 }
|
||||
});
|
||||
}]);
|
|
@ -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' }
|
||||
}
|
||||
});
|
||||
}]);
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
]);
|
|
@ -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;
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
|
||||
<host-details-panel
|
||||
host="$ctrl.hostDetails"
|
||||
is-agent="$ctrl.isAgent"
|
||||
is-browse-enabled="$ctrl.isAgent && $ctrl.agentApiVersion > 1"
|
||||
browse-url="{{$ctrl.browseUrl}}"></host-details-panel>
|
||||
|
||||
<engine-details-panel engine="$ctrl.engineDetails"></engine-details-panel>
|
||||
|
||||
<devices-panel ng-if="$ctrl.isAgent" devices="$ctrl.devices"></devices-panel>
|
||||
<disks-panel ng-if="$ctrl.isAgent" disks="$ctrl.disks"></disks-panel>
|
||||
<devices-panel ng-if="$ctrl.isAgent && $ctrl.agentApiVersion > 1" devices="$ctrl.devices"></devices-panel>
|
||||
<disks-panel ng-if="$ctrl.isAgent && $ctrl.agentApiVersion > 1" disks="$ctrl.disks"></disks-panel>
|
||||
|
||||
<ng-transclude></ng-transclude>
|
|
@ -6,6 +6,7 @@ angular.module('portainer.docker').component('hostOverview', {
|
|||
devices: '<',
|
||||
disks: '<',
|
||||
isAgent: '<',
|
||||
agentApiVersion: '<',
|
||||
refreshUrl: '@',
|
||||
browseUrl: '@'
|
||||
},
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<td>Total memory</td>
|
||||
<td>{{ $ctrl.host.totalMemory | humansize }}</td>
|
||||
</tr>
|
||||
<tr ng-if="$ctrl.isAgent">
|
||||
<tr ng-if="$ctrl.isBrowseEnabled">
|
||||
<td colspan="2">
|
||||
<button
|
||||
class="btn btn-primary btn-sm"
|
||||
|
|
|
@ -3,7 +3,7 @@ angular.module('portainer.docker').component('hostDetailsPanel', {
|
|||
'app/docker/components/host-view-panels/host-details-panel/host-details-panel.html',
|
||||
bindings: {
|
||||
host: '<',
|
||||
isAgent: '<',
|
||||
isBrowseEnabled: '<',
|
||||
browseUrl: '@'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,10 +10,14 @@ angular.module('portainer.docker').controller('HostViewController', [
|
|||
|
||||
this.engineDetails = {};
|
||||
this.hostDetails = {};
|
||||
this.devices = null;
|
||||
this.disks = null;
|
||||
|
||||
function initView() {
|
||||
var applicationState = StateManager.getState();
|
||||
ctrl.state.isAgent = applicationState.endpoint.mode.agentProxy;
|
||||
var agentApiVersion = applicationState.endpoint.agentApiVersion;
|
||||
ctrl.state.agentApiVersion = agentApiVersion;
|
||||
|
||||
$q.all({
|
||||
version: SystemService.version(),
|
||||
|
@ -23,7 +27,7 @@ angular.module('portainer.docker').controller('HostViewController', [
|
|||
ctrl.engineDetails = buildEngineDetails(data);
|
||||
ctrl.hostDetails = buildHostDetails(data.info);
|
||||
|
||||
if (ctrl.state.isAgent) {
|
||||
if (ctrl.state.isAgent && agentApiVersion > 1) {
|
||||
return AgentService.hostInfo(data.info.Hostname).then(function onHostInfoLoad(agentHostInfo) {
|
||||
ctrl.devices = agentHostInfo.PCIDevices;
|
||||
ctrl.disks = agentHostInfo.PhysicalDisks;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
engine-details="$ctrl.engineDetails"
|
||||
host-details="$ctrl.hostDetails"
|
||||
is-agent="$ctrl.state.isAgent"
|
||||
agent-api-version="$ctrl.state.agentApiVersion"
|
||||
disks="$ctrl.disks"
|
||||
devices="$ctrl.devices"
|
||||
|
||||
|
|
|
@ -20,12 +20,16 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [
|
|||
ctrl.engineDetails = buildEngineDetails(node);
|
||||
ctrl.nodeDetails = buildNodeDetails(node);
|
||||
if (ctrl.state.isAgent) {
|
||||
AgentService.hostInfo(node.Hostname).then(function onHostInfoLoad(
|
||||
agentHostInfo
|
||||
) {
|
||||
ctrl.devices = agentHostInfo.PCIDevices;
|
||||
ctrl.disks = agentHostInfo.PhysicalDisks;
|
||||
});
|
||||
var agentApiVersion = applicationState.endpoint.agentApiVersion;
|
||||
ctrl.state.agentApiVersion = agentApiVersion;
|
||||
if (agentApiVersion < 2) {
|
||||
return;
|
||||
}
|
||||
AgentService.hostInfo(node.Hostname)
|
||||
.then(function onHostInfoLoad(agentHostInfo) {
|
||||
ctrl.devices = agentHostInfo.PCIDevices;
|
||||
ctrl.disks = agentHostInfo.PhysicalDisks;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<host-overview
|
||||
agent-api-version="$ctrl.state.agentApiVersion"
|
||||
is-agent="$ctrl.state.isAgent"
|
||||
host-details="$ctrl.hostDetails"
|
||||
engine-details="$ctrl.engineDetails"
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
angular.module('portainer.docker')
|
||||
.controller('BrowseVolumeController', ['$scope', '$transition$',
|
||||
function ($scope, $transition$) {
|
||||
.controller('BrowseVolumeController', ['$scope', '$transition$', 'StateManager',
|
||||
function ($scope, $transition$, StateManager) {
|
||||
|
||||
function initView() {
|
||||
$scope.volumeId = $transition$.params().id;
|
||||
$scope.nodeName = $transition$.params().nodeName;
|
||||
$scope.agentApiVersion = StateManager.getAgentApiVersion();
|
||||
}
|
||||
|
||||
initView();
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
<volume-browser
|
||||
volume-id="volumeId"
|
||||
node-name="nodeName"
|
||||
|
||||
is-upload-enabled="agentApiVersion > 1"
|
||||
></volume-browser>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
angular.module('portainer.app')
|
||||
.factory('StateManager', ['$q', 'SystemService', 'InfoHelper', 'LocalStorage', 'SettingsService', 'StatusService', 'APPLICATION_CACHE_VALIDITY',
|
||||
function StateManagerFactory($q, SystemService, InfoHelper, LocalStorage, SettingsService, StatusService, APPLICATION_CACHE_VALIDITY) {
|
||||
.factory('StateManager', ['$q', 'SystemService', 'InfoHelper', 'LocalStorage', 'SettingsService', 'StatusService', 'APPLICATION_CACHE_VALIDITY', 'AgentPingService',
|
||||
function StateManagerFactory($q, SystemService, InfoHelper, LocalStorage, SettingsService, StatusService, APPLICATION_CACHE_VALIDITY, AgentPingService) {
|
||||
'use strict';
|
||||
|
||||
var manager = {};
|
||||
|
@ -157,6 +157,14 @@ function StateManagerFactory($q, SystemService, InfoHelper, LocalStorage, Settin
|
|||
state.endpoint.name = name;
|
||||
state.endpoint.apiVersion = endpointAPIVersion;
|
||||
state.endpoint.extensions = assignExtensions(extensions);
|
||||
|
||||
if (endpointMode.agentProxy) {
|
||||
return AgentPingService.ping().then(function onPingSuccess(data) {
|
||||
state.endpoint.agentApiVersion = data.version;
|
||||
});
|
||||
}
|
||||
|
||||
}).then(function () {
|
||||
LocalStorage.storeEndpointState(state.endpoint);
|
||||
deferred.resolve();
|
||||
})
|
||||
|
@ -170,5 +178,9 @@ function StateManagerFactory($q, SystemService, InfoHelper, LocalStorage, Settin
|
|||
return deferred.promise;
|
||||
};
|
||||
|
||||
manager.getAgentApiVersion = function getAgentApiVersion() {
|
||||
return state.endpoint.agentApiVersion;
|
||||
};
|
||||
|
||||
return manager;
|
||||
}]);
|
||||
|
|
Loading…
Reference in New Issue