mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(cache): introduce cache option [EE-6293] (#10641)
This commit is contained in:
parent
fffc7b364e
commit
2c032f1739
70 changed files with 418 additions and 45 deletions
|
@ -1,13 +1,52 @@
|
|||
import { EnvironmentStatus } from '@/react/portainer/environments/types';
|
||||
import { getSelfSubjectAccessReview } from '@/react/kubernetes/namespaces/getSelfSubjectAccessReview';
|
||||
|
||||
import { updateAxiosAdapter } from '@/portainer/services/axios';
|
||||
import { PortainerEndpointTypes } from 'Portainer/models/endpoint/models';
|
||||
import { CACHE_REFRESH_EVENT, CACHE_DURATION } from '../portainer/services/http-request.helper';
|
||||
import { cache } from '../portainer/services/axios';
|
||||
|
||||
import registriesModule from './registries';
|
||||
import customTemplateModule from './custom-templates';
|
||||
import { reactModule } from './react';
|
||||
import './views/kubernetes.css';
|
||||
|
||||
// The angular-cache npm package didn't have exclude options, so implement a custom cache
|
||||
// with an added check to only cache kubernetes requests
|
||||
class ExpirationCache {
|
||||
constructor() {
|
||||
this.store = new Map();
|
||||
this.timeout = CACHE_DURATION;
|
||||
}
|
||||
|
||||
get(key) {
|
||||
return this.store.get(key);
|
||||
}
|
||||
|
||||
put(key, val) {
|
||||
// only cache requests with 'kubernetes' in the url
|
||||
if (key.includes('kubernetes')) {
|
||||
this.store.set(key, val);
|
||||
// remove it once it's expired
|
||||
setTimeout(() => {
|
||||
this.remove(key);
|
||||
}, this.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
remove(key) {
|
||||
this.store.delete(key);
|
||||
}
|
||||
|
||||
removeAll() {
|
||||
this.store = new Map();
|
||||
}
|
||||
|
||||
delete() {
|
||||
// skip because this is standalone, not a part of $cacheFactory
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('portainer.kubernetes', ['portainer.app', registriesModule, customTemplateModule, reactModule]).config([
|
||||
'$stateRegistryProvider',
|
||||
function ($stateRegistryProvider) {
|
||||
|
@ -19,8 +58,31 @@ angular.module('portainer.kubernetes', ['portainer.app', registriesModule, custo
|
|||
parent: 'endpoint',
|
||||
abstract: true,
|
||||
|
||||
onEnter: /* @ngInject */ function onEnter($async, $state, endpoint, KubernetesHealthService, KubernetesNamespaceService, Notifications, StateManager) {
|
||||
onEnter: /* @ngInject */ function onEnter(
|
||||
$async,
|
||||
$state,
|
||||
endpoint,
|
||||
KubernetesHealthService,
|
||||
KubernetesNamespaceService,
|
||||
Notifications,
|
||||
StateManager,
|
||||
$http,
|
||||
Authentication,
|
||||
UserService
|
||||
) {
|
||||
return $async(async () => {
|
||||
// if the user wants to use front end cache for performance, set the angular caching settings
|
||||
const userDetails = Authentication.getUserDetails();
|
||||
const user = await UserService.user(userDetails.ID);
|
||||
updateAxiosAdapter(user.UseCache);
|
||||
if (user.UseCache) {
|
||||
$http.defaults.cache = new ExpirationCache();
|
||||
window.addEventListener(CACHE_REFRESH_EVENT, () => {
|
||||
$http.defaults.cache.removeAll();
|
||||
cache.store.clear();
|
||||
});
|
||||
}
|
||||
|
||||
const kubeTypes = [
|
||||
PortainerEndpointTypes.KubernetesLocalEnvironment,
|
||||
PortainerEndpointTypes.AgentOnKubernetesEnvironment,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<page-header title="'Create Custom template'" breadcrumbs="[{label:'Custom Templates', link:'kubernetes.templates.custom'}, 'Create Custom template']"> </page-header>
|
||||
<page-header title="'Create Custom template'" breadcrumbs="[{label:'Custom Templates', link:'kubernetes.templates.custom'}, 'Create Custom template']" reload="true"> </page-header>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<page-header title="'Registry access'" breadcrumbs="[{label:'Registries', link:'kubernetes.registries'}, $ctrl.registry.Name, 'Access management']"> </page-header>
|
||||
<page-header title="'Registry access'" breadcrumbs="[{label:'Registries', link:'kubernetes.registries'}, $ctrl.registry.Name, 'Access management']" reload="true"> </page-header>
|
||||
|
||||
<registry-details registry="$ctrl.registry" ng-if="$ctrl.registry"></registry-details>
|
||||
|
||||
|
|
|
@ -4,11 +4,13 @@ import { KubernetesCommonParams } from 'Kubernetes/models/common/params';
|
|||
import KubernetesNamespaceConverter from 'Kubernetes/converters/namespace';
|
||||
import { updateNamespaces } from 'Kubernetes/store/namespace';
|
||||
import $allSettled from 'Portainer/services/allSettled';
|
||||
import { getSelfSubjectAccessReview } from '@/react/kubernetes/namespaces/getSelfSubjectAccessReview';
|
||||
|
||||
class KubernetesNamespaceService {
|
||||
/* @ngInject */
|
||||
constructor($async, KubernetesNamespaces, LocalStorage) {
|
||||
constructor($async, KubernetesNamespaces, LocalStorage, $state) {
|
||||
this.$async = $async;
|
||||
this.$state = $state;
|
||||
this.KubernetesNamespaces = KubernetesNamespaces;
|
||||
this.LocalStorage = LocalStorage;
|
||||
|
||||
|
@ -66,8 +68,10 @@ class KubernetesNamespaceService {
|
|||
try {
|
||||
// get the list of all namespaces (RBAC allows users to see the list of namespaces)
|
||||
const data = await this.KubernetesNamespaces().get().$promise;
|
||||
// get the status of each namespace (RBAC will give permission denied for status of unauthorised namespaces)
|
||||
const promises = data.items.map((item) => this.KubernetesNamespaces().status({ id: item.metadata.name }).$promise);
|
||||
// get the status of each namespace with accessReviews (to avoid failed forbidden responses, which aren't cached)
|
||||
const accessReviews = await Promise.all(data.items.map((namespace) => getSelfSubjectAccessReview(this.$state.params.endpointId, namespace.metadata.name)));
|
||||
const allowedNamespaceNames = accessReviews.filter((ar) => ar.status.allowed).map((ar) => ar.spec.resourceAttributes.namespace);
|
||||
const promises = allowedNamespaceNames.map((name) => this.KubernetesNamespaces().status({ id: name }).$promise);
|
||||
const namespaces = await $allSettled(promises);
|
||||
// only return namespaces if the user has access to namespaces
|
||||
const allNamespaces = namespaces.fulfilled.map((item) => {
|
||||
|
|
|
@ -75,7 +75,7 @@ class KubernetesResourcePoolsController {
|
|||
|
||||
async getResourcePoolsAsync() {
|
||||
try {
|
||||
this.resourcePools = await this.KubernetesResourcePoolService.get('', { getQuota: true });
|
||||
this.resourcePools = await this.KubernetesResourcePoolService.get();
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to retreive namespaces');
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue