refactor(environments): remove endpoints cache [DTD-100] (#6408)

pull/7994/head
Chaim Lev-Ari 2022-11-02 13:29:26 +02:00 committed by GitHub
parent 9ef2e27aae
commit 37d4a80769
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 155 additions and 353 deletions

View File

@ -52,7 +52,7 @@ export class HostBrowserController {
}
async getFilesForPathAsync(path) {
try {
const files = await this.HostBrowserService.ls(path);
const files = await this.HostBrowserService.ls(this.endpointId, path);
this.state.path = path;
this.files = files;
} catch (err) {
@ -67,9 +67,9 @@ export class HostBrowserController {
const filePath = this.buildPath(this.state.path, name);
const newFilePath = this.buildPath(this.state.path, newName);
try {
await this.HostBrowserService.rename(filePath, newFilePath);
await this.HostBrowserService.rename(this.endpointId, filePath, newFilePath);
this.Notifications.success('File successfully renamed', this.getRelativePath(newFilePath));
const files = await this.HostBrowserService.ls(this.state.path);
const files = await this.HostBrowserService.ls(this.endpointId, this.state.path);
this.files = files;
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to rename file');
@ -82,7 +82,7 @@ export class HostBrowserController {
async downloadFileAsync(fileName) {
const filePath = this.buildPath(this.state.path, fileName);
try {
const { file } = await this.HostBrowserService.get(filePath);
const { file } = await this.HostBrowserService.get(this.endpointId, filePath);
const downloadData = new Blob([file], {
type: 'text/plain;charset=utf-8',
});
@ -108,9 +108,9 @@ export class HostBrowserController {
}
async deleteFileAsync(path) {
try {
await this.HostBrowserService.delete(path);
await this.HostBrowserService.delete(this.endpointId, path);
this.Notifications.success('File successfully deleted', this.getRelativePath(path));
const files = await this.HostBrowserService.ls(this.state.path);
const files = await this.HostBrowserService.ls(this.endpointId, this.state.path);
this.files = files;
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to delete file');

View File

@ -7,5 +7,6 @@ angular.module('portainer.agent').component('nodeSelector', {
controller: NodeSelectorController,
bindings: {
model: '=',
endpointId: '<',
},
});

View File

@ -6,7 +6,7 @@ export class NodeSelectorController {
async $onInit() {
try {
const agents = await this.AgentService.agents();
const agents = await this.AgentService.agents(this.endpointId);
this.agents = agents;
if (!this.model) {
this.model = agents[0].NodeName;

View File

@ -36,9 +36,9 @@ export class VolumeBrowserController {
const newFilePath = this.state.path === '/' ? newName : `${this.state.path}/${newName}`;
try {
await this.VolumeBrowserService.rename(this.volumeId, filePath, newFilePath);
await this.VolumeBrowserService.rename(this.endpointId, this.volumeId, filePath, newFilePath);
this.Notifications.success('File successfully renamed', newFilePath);
this.files = await this.VolumeBrowserService.ls(this.volumeId, this.state.path);
this.files = await this.VolumeBrowserService.ls(this.endpointId, this.volumeId, this.state.path);
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to rename file');
}
@ -62,7 +62,7 @@ export class VolumeBrowserController {
const filePath = this.state.path === '/' ? file : `${this.state.path}/${file}`;
try {
const data = await this.VolumeBrowserService.get(this.volumeId, filePath);
const data = await this.VolumeBrowserService.get(this.endpointId, this.volumeId, filePath);
const downloadData = new Blob([data.file]);
this.FileSaver.saveAs(downloadData, file);
} catch (err) {
@ -85,9 +85,9 @@ export class VolumeBrowserController {
}
async deleteFileAsync(file) {
try {
await this.VolumeBrowserService.delete(this.volumeId, file);
await this.VolumeBrowserService.delete(this.endpointId, this.volumeId, file);
this.Notifications.success('File successfully deleted', file);
this.files = await this.VolumeBrowserService.ls(this.volumeId, this.state.path);
this.files = await this.VolumeBrowserService.ls(this.endpointId, this.volumeId, this.state.path);
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to delete file');
}
@ -98,7 +98,7 @@ export class VolumeBrowserController {
}
async getFilesForPathAsync(path) {
try {
const files = await this.VolumeBrowserService.ls(this.volumeId, path);
const files = await this.VolumeBrowserService.ls(this.endpointId, this.volumeId, path);
this.state.path = path;
this.files = files;
} catch (err) {
@ -145,7 +145,7 @@ export class VolumeBrowserController {
async $onInit() {
this.HttpRequestHelper.setPortainerAgentTargetHeader(this.nodeName);
try {
this.files = await this.VolumeBrowserService.ls(this.volumeId, this.state.path);
this.files = await this.VolumeBrowserService.ls(this.endpointId, this.volumeId, this.state.path);
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to browse volume');
}

View File

@ -2,11 +2,10 @@ import angular from 'angular';
angular.module('portainer.agent').factory('Agent', AgentFactory);
function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) {
function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, StateManager) {
return $resource(
`${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/v:version/agents`,
{
endpointId: EndpointProvider.endpointID,
version: StateManager.getAgentApiVersion,
},
{

View File

@ -4,11 +4,10 @@ import { browseGetResponse } from './response/browse';
angular.module('portainer.agent').factory('Browse', BrowseFactory);
function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) {
function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, StateManager) {
return $resource(
`${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/v:version/browse/:action`,
{
endpointId: EndpointProvider.endpointID,
version: StateManager.getAgentApiVersion,
},
{

View File

@ -2,11 +2,10 @@ import angular from 'angular';
angular.module('portainer.agent').factory('Host', HostFactory);
function HostFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, StateManager) {
function HostFactory($resource, API_ENDPOINT_ENDPOINTS, StateManager) {
return $resource(
`${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/v:version/host/:action`,
{
endpointId: EndpointProvider.endpointID,
version: StateManager.getAgentApiVersion,
},
{

View File

@ -2,12 +2,10 @@ import angular from 'angular';
angular.module('portainer.agent').factory('AgentPing', AgentPingFactory);
function AgentPingFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, $q) {
function AgentPingFactory($resource, API_ENDPOINT_ENDPOINTS, $q) {
return $resource(
`${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/ping`,
{
endpointId: EndpointProvider.endpointID,
},
{},
{
ping: {
method: 'GET',

View File

@ -2,12 +2,10 @@ import angular from 'angular';
angular.module('portainer.agent').factory('AgentVersion1', AgentFactory);
function AgentFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) {
function AgentFactory($resource, API_ENDPOINT_ENDPOINTS) {
return $resource(
`${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/agents`,
{
endpointId: EndpointProvider.endpointID,
},
{},
{
query: { method: 'GET', isArray: true },
}

View File

@ -4,12 +4,10 @@ import { browseGetResponse } from '../response/browse';
angular.module('portainer.agent').factory('BrowseVersion1', BrowseFactory);
function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) {
function BrowseFactory($resource, API_ENDPOINT_ENDPOINTS) {
return $resource(
`${API_ENDPOINT_ENDPOINTS}/:endpointId/docker/browse/:volumeID/:action`,
{
endpointId: EndpointProvider.endpointID,
},
{},
{
ls: {
method: 'GET',

View File

@ -15,16 +15,16 @@ function AgentServiceFactory(Agent, AgentVersion1, HttpRequestHelper, Host, Stat
return state.endpoint.agentApiVersion;
}
function hostInfo(nodeName) {
function hostInfo(endpointId, nodeName) {
HttpRequestHelper.setPortainerAgentTargetHeader(nodeName);
return Host.info().$promise;
return Host.info({ endpointId }).$promise;
}
async function agents() {
async function agents(endpointId) {
const agentVersion = getAgentApiVersion();
const service = agentVersion > 1 ? Agent : AgentVersion1;
try {
const agents = await service.query({ version: agentVersion }).$promise;
const agents = await service.query({ version: agentVersion, endpointId }).$promise;
return agents.map(function (item) {
return new AgentViewModel(item);
});

View File

@ -6,24 +6,24 @@ angular.module('portainer.agent').factory('HostBrowserService', HostBrowserServi
function HostBrowserServiceFactory(Browse, Upload, API_ENDPOINT_ENDPOINTS, StateManager) {
return { ls, get, delete: deletePath, rename, upload };
function ls(path) {
return Browse.ls({ path: path }).$promise;
function ls(endpointId, path) {
return Browse.ls({ endpointId, path: path }).$promise;
}
function get(path) {
return Browse.get({ path: path }).$promise;
function get(endpointId, path) {
return Browse.get({ endpointId, path: path }).$promise;
}
function deletePath(path) {
return Browse.delete({ path: path }).$promise;
function deletePath(endpointId, path) {
return Browse.delete({ endpointId, path: path }).$promise;
}
function rename(path, newPath) {
function rename(endpointId, path, newPath) {
const payload = {
CurrentFilePath: path,
NewFilePath: newPath,
};
return Browse.rename({}, payload).$promise;
return Browse.rename({ endpointId }, payload).$promise;
}
function upload(endpointId, Path, file, onProgress) {

View File

@ -5,7 +5,7 @@ angular.module('portainer.agent').service('AgentPingService', AgentPingService);
function AgentPingService(AgentPing) {
return { ping };
function ping() {
return AgentPing.ping().$promise;
function ping(endpointId) {
return AgentPing.ping({ endpointId }).$promise;
}
}

View File

@ -22,24 +22,24 @@ function VolumeBrowserServiceFactory(StateManager, Browse, BrowseVersion1, API_E
return agentVersion > 1 ? Browse : BrowseVersion1;
}
function ls(volumeId, path) {
return getBrowseService().ls({ volumeID: volumeId, path, version: getAgentApiVersion() }).$promise;
function ls(endpointId, volumeId, path) {
return getBrowseService().ls({ endpointId, volumeID: volumeId, path, version: getAgentApiVersion() }).$promise;
}
function get(volumeId, path) {
return getBrowseService().get({ volumeID: volumeId, path, version: getAgentApiVersion() }).$promise;
function get(endpointId, volumeId, path) {
return getBrowseService().get({ endpointId, volumeID: volumeId, path, version: getAgentApiVersion() }).$promise;
}
function deletePath(volumeId, path) {
return getBrowseService().delete({ volumeID: volumeId, path, version: getAgentApiVersion() }).$promise;
function deletePath(endpointId, volumeId, path) {
return getBrowseService().delete({ endpointId, volumeID: volumeId, path, version: getAgentApiVersion() }).$promise;
}
function rename(volumeId, path, newPath) {
function rename(endpointId, volumeId, path, newPath) {
const payload = {
CurrentFilePath: path,
NewFilePath: newPath,
};
return getBrowseService().rename({ volumeID: volumeId, version: getAgentApiVersion() }, payload).$promise;
return getBrowseService().rename({ endpointId, volumeID: volumeId, version: getAgentApiVersion() }, payload).$promise;
}
function upload(endpointId, path, file, volumeId, onProgress) {

View File

@ -1,10 +1,7 @@
import $ from 'jquery';
import { PortainerEndpointTypes } from 'Portainer/models/endpoint/models';
/* @ngInject */
export function onStartupAngular($rootScope, $state, $interval, LocalStorage, EndpointProvider, SystemService, cfpLoadingBar, $transitions, HttpRequestHelper) {
EndpointProvider.initialize();
export function onStartupAngular($rootScope, $state, LocalStorage, cfpLoadingBar, $transitions, HttpRequestHelper, EndpointProvider) {
$rootScope.$state = $state;
const defaultTitle = document.title;
@ -26,11 +23,6 @@ export function onStartupAngular($rootScope, $state, $interval, LocalStorage, En
HttpRequestHelper.resetAgentHeaders();
});
// Keep-alive Edge endpoints by sending a ping request every minute
$interval(() => {
ping(EndpointProvider, SystemService);
}, 60 * 1000);
$(document).ajaxSend((event, jqXhr, jqOpts) => {
const type = jqOpts.type === 'POST' || jqOpts.type === 'PUT' || jqOpts.type === 'PATCH';
const hasNoContentType = jqOpts.contentType !== 'application/json' && jqOpts.headers && !jqOpts.headers['Content-Type'];
@ -40,10 +32,3 @@ export function onStartupAngular($rootScope, $state, $interval, LocalStorage, En
jqXhr.setRequestHeader('Authorization', 'Bearer ' + LocalStorage.getJWT());
});
}
function ping(EndpointProvider, SystemService) {
const endpoint = EndpointProvider.currentEndpoint();
if (endpoint && endpoint.Type == PortainerEndpointTypes.EdgeAgentOnDockerEnvironment) {
SystemService.ping(endpoint.Id);
}
}

View File

@ -3,7 +3,7 @@ import { StateRegistry, StateService } from '@uirouter/angularjs';
import { Environment } from '@/react/portainer/environments/types';
import { notifyError } from '@/portainer/services/notifications';
import { EndpointProvider, StateManager } from '@/portainer/services/types';
import { StateManager } from '@/portainer/services/types';
import { reactModule } from './react';
@ -22,7 +22,6 @@ function config($stateRegistryProvider: StateRegistry) {
$async: (fn: () => Promise<void>) => Promise<void>,
$state: StateService,
endpoint: Environment,
EndpointProvider: EndpointProvider,
StateManager: StateManager
) {
return $async(async () => {
@ -31,9 +30,6 @@ function config($stateRegistryProvider: StateRegistry) {
return;
}
try {
EndpointProvider.setEndpointID(endpoint.Id);
EndpointProvider.setEndpointPublicURL(endpoint.PublicURL);
EndpointProvider.setOfflineModeFromStatus(endpoint.Status);
await StateManager.updateEndpointState(endpoint);
} catch (e) {
notifyError('Failed loading environment', e as Error);

View File

@ -18,7 +18,7 @@ export function configApp($urlRouterProvider, $httpProvider, localStorageService
});
$httpProvider.interceptors.push('jwtInterceptor');
$httpProvider.interceptors.push('EndpointStatusInterceptor');
$httpProvider.defaults.headers.post['Content-Type'] = 'application/json';
$httpProvider.defaults.headers.put['Content-Type'] = 'application/json';
$httpProvider.defaults.headers.patch['Content-Type'] = 'application/json';

View File

@ -14,7 +14,7 @@ angular.module('portainer.docker', ['portainer.app', reactModule]).config([
parent: 'endpoint',
url: '/docker',
abstract: true,
onEnter: /* @ngInject */ function onEnter(endpoint, $async, $state, EndpointService, EndpointProvider, Notifications, StateManager, SystemService) {
onEnter: /* @ngInject */ function onEnter(endpoint, $async, $state, EndpointService, Notifications, StateManager, SystemService) {
return $async(async () => {
if (![1, 2, 4].includes(endpoint.Type)) {
$state.go('portainer.home');
@ -32,10 +32,6 @@ angular.module('portainer.docker', ['portainer.app', reactModule]).config([
throw new Error('Environment is unreachable.');
}
EndpointProvider.setEndpointID(endpoint.Id);
EndpointProvider.setEndpointPublicURL(endpoint.PublicURL);
EndpointProvider.setOfflineModeFromStatus(endpoint.Status);
await StateManager.updateEndpointState(endpoint);
} catch (e) {
Notifications.error('Failed loading environment', e);

View File

@ -1,4 +1,7 @@
angular.module('portainer.docker').component('dashboardClusterAgentInfo', {
templateUrl: './dashboardClusterAgentInfo.html',
controller: 'DashboardClusterAgentInfoController',
bindings: {
endpointId: '<',
},
});

View File

@ -5,7 +5,7 @@ angular.module('portainer.docker').controller('DashboardClusterAgentInfoControll
var ctrl = this;
this.$onInit = function () {
AgentService.agents()
AgentService.agents(ctrl.endpointId)
.then(function success(data) {
ctrl.agentCount = data.length;
})

View File

@ -1,19 +0,0 @@
angular.module('portainer.docker').factory('SystemEndpoint', [
'$resource',
'API_ENDPOINT_ENDPOINTS',
function SystemEndpointFactory($resource, API_ENDPOINT_ENDPOINTS) {
'use strict';
return $resource(
API_ENDPOINT_ENDPOINTS + '/:endpointId/docker/:action/:subAction',
{
name: '@name',
},
{
ping: {
method: 'GET',
params: { action: '_ping', endpointId: '@endpointId' },
},
}
);
},
]);

View File

@ -0,0 +1,10 @@
import axios, { parseAxiosError } from '@/portainer/services/axios';
import { EnvironmentId } from '@/react/portainer/environments/types';
export async function ping(environmentId: EnvironmentId) {
try {
await axios.get(`/endpoints/${environmentId}/docker/_ping`);
} catch (error) {
throw parseAxiosError(error as Error);
}
}

View File

@ -1,10 +1,10 @@
import { EventViewModel } from '../models/event';
import { ping } from './ping';
angular.module('portainer.docker').factory('SystemService', [
'$q',
'System',
'SystemEndpoint',
function SystemServiceFactory($q, System, SystemEndpoint) {
function SystemServiceFactory($q, System) {
'use strict';
var service = {};
@ -26,7 +26,7 @@ angular.module('portainer.docker').factory('SystemService', [
};
service.ping = function (endpointId) {
return SystemEndpoint.ping({ endpointId: endpointId }).$promise;
return ping(endpointId);
};
service.version = function () {

View File

@ -144,7 +144,7 @@
<div ng-if="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'">
<div class="col-sm-12 form-section-title"> Deployment </div>
<!-- node-selection -->
<node-selector model="formValues.NodeName"> </node-selector>
<node-selector model="formValues.NodeName" endpoint-id="endpoint.Id"> </node-selector>
<!-- !node-selection -->
</div>
<!-- access-control -->

View File

@ -2,7 +2,7 @@
<div class="row" ng-if="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'">
<div class="col-sm-12">
<dashboard-cluster-agent-info></dashboard-cluster-agent-info>
<dashboard-cluster-agent-info endpoint-id="endpoint.Id"></dashboard-cluster-agent-info>
</div>
</div>
<information-panel-offline ng-if="offlineMode"></information-panel-offline>

View File

@ -1,7 +1,9 @@
angular.module('portainer.docker').controller('BuildImageController', BuildImageController);
/* @ngInject */
function BuildImageController($scope, $async, $window, ModalService, BuildService, Notifications, HttpRequestHelper) {
function BuildImageController($scope, $async, $window, ModalService, BuildService, Notifications, HttpRequestHelper, endpoint) {
$scope.endpoint = endpoint;
$scope.state = {
BuildType: 'editor',
actionInProgress: false,

View File

@ -220,7 +220,7 @@
<div ng-if="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'">
<div class="col-sm-12 form-section-title"> Deployment </div>
<!-- node-selection -->
<node-selector model="formValues.NodeName"> </node-selector>
<node-selector model="formValues.NodeName" endpoint-id="endpoint.Id"> </node-selector>
<!-- !node-selection -->
</div>
<!-- actions -->

View File

@ -20,7 +20,7 @@
<div ng-if="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'">
<div class="col-sm-12 form-section-title"> Deployment </div>
<!-- node-selection -->
<node-selector model="formValues.NodeName"> </node-selector>
<node-selector model="formValues.NodeName" endpoint-id="endpoint.Id"> </node-selector>
<!-- !node-selection -->
</div>
<div class="form-group">

View File

@ -23,7 +23,7 @@
<div ng-if="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'">
<div class="col-sm-12 form-section-title"> Deployment </div>
<!-- node-selection -->
<node-selector model="formValues.NodeName"> </node-selector>
<node-selector model="formValues.NodeName" endpoint-id="endpoint.Id"> </node-selector>
<!-- !node-selection -->
</div>
<div class="row" authorization="DockerImageCreate">

View File

@ -14,7 +14,10 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
'ResourceControlService',
'FormValidator',
'HttpRequestHelper',
function ($q, $scope, $state, PluginService, Notifications, NetworkService, LabelHelper, Authentication, ResourceControlService, FormValidator, HttpRequestHelper) {
'endpoint',
function ($q, $scope, $state, PluginService, Notifications, NetworkService, LabelHelper, Authentication, ResourceControlService, FormValidator, HttpRequestHelper, endpoint) {
$scope.endpoint = endpoint;
$scope.formValues = {
DriverOptions: [],
IPV4: {

View File

@ -216,7 +216,7 @@
>
<div class="col-sm-12 form-section-title"> Deployment </div>
<!-- node-selection -->
<node-selector model="formValues.NodeName"> </node-selector>
<node-selector model="formValues.NodeName" endpoint-id="endpoint.Id"> </node-selector>
<!-- !node-selection -->
</div>
<!-- access-control -->

View File

@ -66,7 +66,7 @@ angular.module('portainer.docker').controller('NetworksController', [
};
if ($scope.applicationState.endpoint.mode.agentProxy && $scope.applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE') {
req.agents = AgentService.agents();
req.agents = AgentService.agents(endpoint.Id);
}
$q.all(req)

View File

@ -42,7 +42,7 @@ angular.module('portainer.docker').controller('NodeDetailsViewController', [
return;
}
AgentService.hostInfo(node.Hostname).then(function onHostInfoLoad(agentHostInfo) {
AgentService.hostInfo(ctrl.endpoint.Id, node.Hostname).then(function onHostInfoLoad(agentHostInfo) {
ctrl.devices = agentHostInfo.PCIDevices;
ctrl.disks = agentHostInfo.PhysicalDisks;
});

View File

@ -13,7 +13,10 @@ angular.module('portainer.docker').controller('CreateVolumeController', [
'Notifications',
'FormValidator',
'HttpRequestHelper',
function ($q, $scope, $state, VolumeService, PluginService, ResourceControlService, Authentication, Notifications, FormValidator, HttpRequestHelper) {
'endpoint',
function ($q, $scope, $state, VolumeService, PluginService, ResourceControlService, Authentication, Notifications, FormValidator, HttpRequestHelper, endpoint) {
$scope.endpoint = endpoint;
$scope.formValues = {
Driver: 'local',
DriverOptions: [],

View File

@ -72,7 +72,7 @@
<div ng-if="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && formValues.Driver === 'local'">
<div class="col-sm-12 form-section-title"> Deployment </div>
<!-- node-selection -->
<node-selector model="formValues.NodeName"> </node-selector>
<node-selector model="formValues.NodeName" endpoint-id="endpoint.Id"> </node-selector>
<!-- !node-selection -->
</div>
<!-- access-control -->

View File

@ -14,7 +14,7 @@ angular.module('portainer.kubernetes', ['portainer.app', registriesModule, custo
parent: 'endpoint',
abstract: true,
onEnter: /* @ngInject */ function onEnter($async, $state, endpoint, EndpointProvider, KubernetesHealthService, KubernetesNamespaceService, Notifications, StateManager) {
onEnter: /* @ngInject */ function onEnter($async, $state, endpoint, KubernetesHealthService, KubernetesNamespaceService, Notifications, StateManager) {
return $async(async () => {
if (![5, 6, 7].includes(endpoint.Type)) {
$state.go('portainer.home');
@ -31,7 +31,6 @@ angular.module('portainer.kubernetes', ['portainer.app', registriesModule, custo
}
}
EndpointProvider.setEndpointID(endpoint.Id);
await StateManager.updateEndpointState(endpoint);
if (endpoint.Type === 7 && endpoint.Status === 2) {

View File

@ -2,7 +2,7 @@ angular.module('portainer.kubernetes').component('kubernetesResourcePoolsDatatab
templateUrl: './resourcePoolsDatatable.html',
controller: 'KubernetesResourcePoolsDatatableController',
bindings: {
endpoint: '<',
restrictDefaultNamespace: '<',
titleText: '@',
titleIcon: '@',
dataset: '<',

View File

@ -19,7 +19,7 @@ angular.module('portainer.docker').controller('KubernetesResourcePoolsDatatableC
};
this.canManageAccess = function (item) {
if (!this.endpoint.Kubernetes.Configuration.RestrictDefaultNamespace) {
if (!this.restrictDefaultNamespace) {
return !KubernetesNamespaceHelper.isDefaultNamespace(item.Namespace.Name) && !this.isSystemNamespace(item);
} else {
return !this.isSystemNamespace(item);

View File

@ -154,8 +154,8 @@ class KubernetesConfigureController {
return;
}
const promises = [];
const oldEndpointID = this.EndpointProvider.endpointID();
this.EndpointProvider.setEndpointID(this.endpoint.Id);
const oldEndpoint = this.EndpointProvider.currentEndpoint();
this.EndpointProvider.setCurrentEndpoint(this.endpoint);
try {
const allResourcePools = await this.KubernetesResourcePoolService.get();
@ -170,7 +170,7 @@ class KubernetesConfigureController {
});
});
} finally {
this.EndpointProvider.setEndpointID(oldEndpointID);
this.EndpointProvider.setCurrentEndpoint(oldEndpoint);
}
const responses = await Promise.allSettled(promises);
@ -222,13 +222,8 @@ class KubernetesConfigureController {
});
await Promise.all(storagePromises);
const endpoints = this.EndpointProvider.endpoints();
const modifiedEndpoint = _.find(endpoints, (item) => item.Id === this.endpoint.Id);
if (modifiedEndpoint) {
this.assignFormValuesToEndpoint(modifiedEndpoint, storageClasses, ingressClasses);
this.EndpointProvider.setEndpoints(endpoints);
}
this.Notifications.success('Success', 'Configuration successfully applied');
this.$state.go('portainer.home');
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to apply configuration');

View File

@ -6,7 +6,7 @@
<div class="row">
<div class="col-sm-12">
<kubernetes-resource-pools-datatable
endpoint="ctrl.endpoint"
restrict-default-namespace="ctrl.endpoint.Kubernetes.Configuration.RestrictDefaultNamespace"
dataset="ctrl.resourcePools"
table-key="kubernetes.resourcePools"
order-by="Name"

View File

@ -1,45 +0,0 @@
import _ from 'lodash-es';
angular.module('portainer.app').factory('EndpointStatusInterceptor', [
'$q',
'EndpointProvider',
function ($q, EndpointProvider) {
'use strict';
var interceptor = {};
interceptor.response = responseInterceptor;
interceptor.responseError = responseErrorInterceptor;
function canBeOffline(url) {
return (
_.startsWith(url, 'api/') &&
(_.includes(url, '/containers') ||
_.includes(url, '/images') ||
_.includes(url, '/volumes') ||
_.includes(url, '/networks') ||
_.includes(url, '/info') ||
_.includes(url, '/version'))
);
}
function responseInterceptor(response) {
var url = response.config.url;
if (response.status === 200 && canBeOffline(url) && EndpointProvider.offlineMode()) {
EndpointProvider.setOfflineMode(false);
}
return response || $q.when(response);
}
function responseErrorInterceptor(rejection) {
if (rejection.config) {
var url = rejection.config.url;
if ((rejection.status === 502 || rejection.status === 503 || rejection.status === -1) && canBeOffline(url) && !EndpointProvider.offlineMode()) {
EndpointProvider.setOfflineMode(true);
}
}
return $q.reject(rejection);
}
return interceptor;
},
]);

View File

@ -11,8 +11,7 @@ angular.module('portainer.app').factory('StackService', [
'ServiceService',
'ContainerService',
'SwarmService',
'EndpointProvider',
function StackServiceFactory($q, $async, Stack, FileUploadService, StackHelper, ServiceService, ContainerService, SwarmService, EndpointProvider) {
function StackServiceFactory($q, $async, Stack, FileUploadService, StackHelper, ServiceService, ContainerService, SwarmService) {
'use strict';
var service = {
updateGit,
@ -51,8 +50,6 @@ angular.module('portainer.app').factory('StackService', [
service.migrateSwarmStack = function (stack, targetEndpointId, newName) {
var deferred = $q.defer();
EndpointProvider.setEndpointID(targetEndpointId);
SwarmService.swarm()
.then(function success(data) {
var swarm = data;
@ -67,9 +64,6 @@ angular.module('portainer.app').factory('StackService', [
})
.catch(function error(err) {
deferred.reject({ msg: 'Unable to migrate stack', err: err });
})
.finally(function final() {
EndpointProvider.setEndpointID(stack.EndpointId);
});
return deferred.promise;
@ -78,14 +72,11 @@ angular.module('portainer.app').factory('StackService', [
service.migrateComposeStack = function (stack, targetEndpointId, newName) {
var deferred = $q.defer();
EndpointProvider.setEndpointID(targetEndpointId);
Stack.migrate({ id: stack.Id, endpointId: stack.EndpointId }, { EndpointID: targetEndpointId, Name: newName })
.$promise.then(function success() {
deferred.resolve();
})
.catch(function error(err) {
EndpointProvider.setEndpointID(stack.EndpointId);
deferred.reject({ msg: 'Unable to migrate stack', err: err });
});

View File

@ -5,7 +5,6 @@ const DEFAULT_PASSWORD = 'K7yJPP5qNK4hf1QsRnfV';
angular.module('portainer.app').factory('Authentication', [
'$async',
'$state',
'Auth',
'OAuth',
'jwtHelper',
@ -14,7 +13,7 @@ angular.module('portainer.app').factory('Authentication', [
'EndpointProvider',
'UserService',
'ThemeManager',
function AuthenticationFactory($async, $state, Auth, OAuth, jwtHelper, LocalStorage, StateManager, EndpointProvider, UserService, ThemeManager) {
function AuthenticationFactory($async, Auth, OAuth, jwtHelper, LocalStorage, StateManager, EndpointProvider, UserService, ThemeManager) {
'use strict';
var service = {};
@ -50,7 +49,6 @@ angular.module('portainer.app').factory('Authentication', [
clearSessionStorage();
StateManager.clean();
EndpointProvider.clean();
EndpointProvider.setCurrentEndpoint(null);
LocalStorage.cleanAuthData();
LocalStorage.storeLoginStateUUID('');
tryAutoLoginExtension();

View File

@ -1,120 +0,0 @@
angular.module('portainer.app').factory(
'EndpointProvider',
/* @ngInject */
function EndpointProviderFactory(LocalStorage, $uiRouterGlobals) {
const state = {
currentEndpoint: null,
};
var service = {};
var endpoint = {};
service.initialize = function () {
var endpointID = LocalStorage.getEndpointID();
var endpointPublicURL = LocalStorage.getEndpointPublicURL();
var offlineMode = LocalStorage.getOfflineMode();
if (endpointID) {
endpoint.ID = endpointID;
}
if (endpointPublicURL) {
endpoint.PublicURL = endpointPublicURL;
}
if (offlineMode) {
endpoint.OfflineMode = offlineMode;
}
};
service.clean = function () {
LocalStorage.cleanEndpointData();
endpoint = {};
};
service.endpoint = function () {
return endpoint;
};
service.endpointID = function () {
if (endpoint.ID === undefined) {
endpoint.ID = LocalStorage.getEndpointID();
}
if (endpoint.ID === null || endpoint.ID === undefined) {
return service.getUrlEndpointID();
}
return endpoint.ID;
};
// TODO: technical debt
// Reference issue: JIRA CE-463
// Documentation (https://ui-router.github.io/ng1/docs/latest/modules/injectables.html) show the usage of either
// * $stateParams
// * $transition$
// * $uiRouterGlobals
// to retrieve the URL params
//
// * $stateParams: is deprecated and will cause a circular dependency injection error
// because EndpointProvider is used by EndpointStatusInterceptor which is injected inside $httpProvider
// >> [$injector:cdep] Circular dependency found: $uiRouter <- $stateParams <- EndpointProvider <- EndpointStatusInterceptor <- $http <- $uiRouter
// For more details, see https://stackoverflow.com/questions/20230691/injecting-state-ui-router-into-http-interceptor-causes-circular-dependency#20230786
//
// * $transition$: mentionned as the replacement of $stateParams (https://ui-router.github.io/guide/ng1/migrate-to-1_0#stateparams-deprecation)
// but is not injectable without tweaks inside a service
//
// * $uiRouterGlobal: per https://github.com/angular-ui/ui-router/issues/3237#issuecomment-271979688
// seems the recommanded way to retrieve params inside a service/factory
//
// We need this function to fallback on URL endpoint ID when no endpoint has been selected
service.getUrlEndpointID = () => {
return $uiRouterGlobals.params.id;
};
service.setEndpointID = function (id) {
endpoint.ID = id;
LocalStorage.storeEndpointID(id);
};
service.endpointPublicURL = function () {
if (endpoint.PublicURL === undefined) {
endpoint.PublicURL = LocalStorage.getEndpointPublicURL();
}
return endpoint.PublicURL;
};
service.setEndpointPublicURL = function (publicURL) {
endpoint.PublicURL = publicURL;
LocalStorage.storeEndpointPublicURL(publicURL);
};
service.endpoints = function () {
return LocalStorage.getEndpoints();
};
service.setEndpoints = function (data) {
LocalStorage.storeEndpoints(data);
};
service.offlineMode = function () {
return endpoint.OfflineMode;
};
service.setOfflineMode = function (isOffline) {
endpoint.OfflineMode = isOffline;
LocalStorage.storeOfflineMode(isOffline);
};
service.setOfflineModeFromStatus = function (status) {
var isOffline = status !== 1;
endpoint.OfflineMode = isOffline;
LocalStorage.storeOfflineMode(isOffline);
};
service.currentEndpoint = function () {
return state.currentEndpoint;
};
service.setCurrentEndpoint = function (endpoint) {
state.currentEndpoint = endpoint;
};
return service;
}
);

View File

@ -0,0 +1,47 @@
import { ping } from '@/docker/services/ping';
import {
Environment,
EnvironmentType,
} from '@/react/portainer/environments/types';
interface State {
currentEndpoint: Environment | null;
pingInterval: NodeJS.Timer | null;
}
/* @ngInject */
export function EndpointProvider() {
const state: State = {
currentEndpoint: null,
pingInterval: null,
};
return { endpointID, setCurrentEndpoint, currentEndpoint, clean };
function endpointID() {
return state.currentEndpoint?.Id;
}
function setCurrentEndpoint(endpoint: Environment | null) {
state.currentEndpoint = endpoint;
if (state.pingInterval) {
clearInterval(state.pingInterval);
state.pingInterval = null;
}
if (endpoint && endpoint.Type === EnvironmentType.EdgeAgentOnDocker) {
state.pingInterval = setInterval(() => ping(endpoint.Id), 60 * 1000);
}
}
function currentEndpoint() {
return state.currentEndpoint;
}
function clean() {
setCurrentEndpoint(null);
}
}
export type EndpointProviderInterface = ReturnType<typeof EndpointProvider>;

View File

@ -4,9 +4,11 @@ import { apiServicesModule } from './api';
import { Notifications } from './notifications';
import { ModalServiceAngular } from './modal.service';
import { HttpRequestHelperAngular } from './http-request.helper';
import { EndpointProvider } from './endpointProvider';
export default angular
.module('portainer.app.services', [apiServicesModule])
.factory('Notifications', Notifications)
.factory('ModalService', ModalServiceAngular)
.factory('EndpointProvider', EndpointProvider)
.factory('HttpRequestHelper', HttpRequestHelperAngular).name;

View File

@ -2,42 +2,21 @@ angular.module('portainer.app').factory('LocalStorage', [
'localStorageService',
function LocalStorageFactory(localStorageService) {
return {
storeEndpointID: function (id) {
localStorageService.set('ENDPOINT_ID', id);
},
getEndpointID: function () {
return localStorageService.get('ENDPOINT_ID');
},
storeEndpointPublicURL: function (publicURL) {
localStorageService.set('ENDPOINT_PUBLIC_URL', publicURL);
},
getEndpointPublicURL: function () {
return localStorageService.get('ENDPOINT_PUBLIC_URL');
},
storeLoginStateUUID: function (uuid) {
localStorageService.set('LOGIN_STATE_UUID', uuid);
},
getLoginStateUUID: function () {
return localStorageService.get('LOGIN_STATE_UUID');
},
storeOfflineMode: function (isOffline) {
localStorageService.set('ENDPOINT_OFFLINE_MODE', isOffline);
},
getOfflineMode: function () {
return localStorageService.get('ENDPOINT_OFFLINE_MODE');
},
storeEndpoints: function (data) {
localStorageService.set('ENDPOINTS_DATA', data);
},
getEndpoints: function () {
return localStorageService.get('ENDPOINTS_DATA');
},
storeEndpointState: function (state) {
localStorageService.set('ENDPOINT_STATE', state);
},
getEndpointState: function () {
return localStorageService.get('ENDPOINT_STATE');
},
cleanEndpointState() {
localStorageService.remove('ENDPOINT_STATE');
},
storeApplicationState: function (state) {
localStorageService.set('APPLICATION_STATE', state);
},
@ -135,9 +114,6 @@ angular.module('portainer.app').factory('LocalStorage', [
cleanAuthData() {
localStorageService.remove('JWT', 'APPLICATION_STATE', 'LOGIN_STATE_UUID');
},
cleanEndpointData() {
localStorageService.remove('ENDPOINT_ID', 'ENDPOINT_PUBLIC_URL', 'ENDPOINT_OFFLINE_MODE', 'ENDPOINTS_DATA', 'ENDPOINT_STATE');
},
storeKubernetesSummaryToggle(value) {
localStorageService.set('kubernetes_summary_expanded', value);
},

View File

@ -66,13 +66,14 @@ function StateManagerFactory(
};
manager.clean = function () {
state.endpoint = {};
manager.cleanEndpoint();
state.application = {};
};
manager.cleanEndpoint = function () {
state.endpoint = {};
EndpointProvider.clean();
LocalStorage.cleanEndpointState();
};
manager.updateLogo = function (logoURL) {
@ -208,7 +209,7 @@ function StateManagerFactory(
state.endpoint.apiVersion = endpointAPIVersion;
if (endpointMode.agentProxy && endpoint.Status === 1) {
return AgentPingService.ping().then(function onPingSuccess(data) {
return AgentPingService.ping(endpoint.Id).then(function onPingSuccess(data) {
state.endpoint.agentApiVersion = data.version;
});
}

View File

@ -1,12 +1,5 @@
import { Environment } from '@/react/portainer/environments/types';
export interface EndpointProvider {
setEndpointID(id: Environment['Id']): void;
setEndpointPublicURL(url?: string): void;
setOfflineModeFromStatus(status: Environment['Status']): void;
setCurrentEndpoint(endpoint: Environment | undefined): void;
}
export interface StateManager {
updateEndpointState(endpoint: Environment): Promise<void>;
}

View File

@ -21,7 +21,6 @@ angular.module('portainer.app').controller('StackController', [
'TaskHelper',
'Notifications',
'FormHelper',
'EndpointProvider',
'GroupService',
'ModalService',
'StackHelper',
@ -46,7 +45,6 @@ angular.module('portainer.app').controller('StackController', [
TaskHelper,
Notifications,
FormHelper,
EndpointProvider,
GroupService,
ModalService,
StackHelper,
@ -112,16 +110,12 @@ angular.module('portainer.app').controller('StackController', [
$scope.duplicateStack = function duplicateStack(name, targetEndpointId) {
var stack = $scope.stack;
var env = FormHelper.removeInvalidEnvVars($scope.formValues.Env);
// sets the targetEndpointID as global for interceptors
EndpointProvider.setEndpointID(targetEndpointId);
return StackService.duplicateStack(name, $scope.stackFileContent, env, targetEndpointId, stack.Type).then(onDuplicationSuccess).catch(notifyOnError);
function onDuplicationSuccess() {
Notifications.success('Success', 'Stack successfully duplicated');
$state.go('docker.stacks', {}, { reload: true });
// sets back the original endpointID as global for interceptors
EndpointProvider.setEndpointID(stack.EndpointId);
}
function notifyOnError(err) {

View File

@ -12,7 +12,7 @@ import {
import { getPlatformType } from '@/react/portainer/environments/utils';
import { useEnvironment } from '@/react/portainer/environments/queries/useEnvironment';
import { useLocalStorage } from '@/portainer/hooks/useLocalStorage';
import { EndpointProvider } from '@/portainer/services/types';
import { EndpointProviderInterface } from '@/portainer/services/endpointProvider';
import { getPlatformIcon } from '../portainer/environments/utils/get-platform-icon';
@ -107,8 +107,8 @@ function useCurrentEnvironment() {
function clearEnvironment() {
const $injector = angular.element(document).injector();
$injector.invoke(
/* @ngInject */ (EndpointProvider: EndpointProvider) => {
EndpointProvider.setCurrentEndpoint(undefined);
/* @ngInject */ (EndpointProvider: EndpointProviderInterface) => {
EndpointProvider.setCurrentEndpoint(null);
if (!params.endpointId) {
document.title = 'Portainer';
}