mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
loading k8s resources into stores per selected namespaces -- part 1
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
02bc210f56
commit
47bea52160
@ -182,7 +182,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
*/
|
*/
|
||||||
@observable metadata: ClusterMetadata = {};
|
@observable metadata: ClusterMetadata = {};
|
||||||
/**
|
/**
|
||||||
* List of allowed namespaces
|
* List of allowed namespaces verified via K8S::SelfSubjectAccessReview api
|
||||||
*
|
*
|
||||||
* @observable
|
* @observable
|
||||||
*/
|
*/
|
||||||
@ -195,7 +195,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
*/
|
*/
|
||||||
@observable allowedResources: string[] = [];
|
@observable allowedResources: string[] = [];
|
||||||
/**
|
/**
|
||||||
* List of accessible namespaces
|
* List of accessible namespaces provided by user in the Cluster Settings
|
||||||
*
|
*
|
||||||
* @observable
|
* @observable
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { apiPrefix, isDevelopment } from "../../common/vars";
|
|||||||
import { getHostedCluster } from "../../common/cluster-store";
|
import { getHostedCluster } from "../../common/cluster-store";
|
||||||
|
|
||||||
export interface IKubeWatchEvent<T = any> {
|
export interface IKubeWatchEvent<T = any> {
|
||||||
type: "ADDED" | "MODIFIED" | "DELETED";
|
type: "ADDED" | "MODIFIED" | "DELETED" | "ERROR";
|
||||||
object?: T;
|
object?: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +158,11 @@ export class KubeWatchApi {
|
|||||||
|
|
||||||
addListener(store: KubeObjectStore, callback: (evt: IKubeWatchEvent) => void) {
|
addListener(store: KubeObjectStore, callback: (evt: IKubeWatchEvent) => void) {
|
||||||
const listener = (evt: IKubeWatchEvent<KubeJsonApiData>) => {
|
const listener = (evt: IKubeWatchEvent<KubeJsonApiData>) => {
|
||||||
|
if (evt.type === "ERROR") {
|
||||||
|
// console.error(evt.object);
|
||||||
|
return; // fixme: too old resource version (e.g. reproduce: quickly jump btw pages)
|
||||||
|
}
|
||||||
|
|
||||||
const { namespace, resourceVersion } = evt.object.metadata;
|
const { namespace, resourceVersion } = evt.object.metadata;
|
||||||
const api = apiManager.getApiByKind(evt.object.kind, evt.object.apiVersion);
|
const api = apiManager.getApiByKind(evt.object.kind, evt.object.apiVersion);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { action, comparer, observable, reaction } from "mobx";
|
import { action, comparer, observable, reaction } from "mobx";
|
||||||
import { autobind, createStorage } from "../../utils";
|
import { autobind, createStorage } from "../../utils";
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
import { KubeObjectStore, KubeObjectStoreLoadingParams } from "../../kube-object.store";
|
||||||
import { Namespace, namespacesApi } from "../../api/endpoints";
|
import { Namespace, namespacesApi } from "../../api/endpoints/namespaces.api";
|
||||||
import { createPageParam } from "../../navigation";
|
import { createPageParam } from "../../navigation";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
import { isAllowedResource } from "../../../common/rbac";
|
import { isAllowedResource } from "../../../common/rbac";
|
||||||
@ -61,18 +61,11 @@ export class NamespaceStore extends KubeObjectStore<Namespace> {
|
|||||||
return super.subscribe(apis);
|
return super.subscribe(apis);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async loadItems(namespaces?: string[]) {
|
protected async loadItems({ isAdmin, namespaces }: KubeObjectStoreLoadingParams) {
|
||||||
if (!isAllowedResource("namespaces")) {
|
if (!isAllowedResource("namespaces")) {
|
||||||
if (namespaces) return namespaces.map(this.getDummyNamespace);
|
return namespaces.map(this.getDummyNamespace);
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (namespaces) {
|
|
||||||
return Promise.all(namespaces.map(name => this.api.get({ name })));
|
return Promise.all(namespaces.map(name => this.api.get({ name })));
|
||||||
} else {
|
|
||||||
return super.loadItems();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getDummyNamespace(name: string) {
|
protected getDummyNamespace(name: string) {
|
||||||
@ -105,12 +98,6 @@ export class NamespaceStore extends KubeObjectStore<Namespace> {
|
|||||||
else this.contextNs.push(namespace);
|
else this.contextNs.push(namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
|
||||||
reset() {
|
|
||||||
super.reset();
|
|
||||||
this.contextNs.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async remove(item: Namespace) {
|
async remove(item: Namespace) {
|
||||||
await super.remove(item);
|
await super.remove(item);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import difference from "lodash/difference";
|
import difference from "lodash/difference";
|
||||||
import uniqBy from "lodash/uniqBy";
|
import uniqBy from "lodash/uniqBy";
|
||||||
import { clusterRoleBindingApi, IRoleBindingSubject, RoleBinding, roleBindingApi } from "../../api/endpoints";
|
import { clusterRoleBindingApi, IRoleBindingSubject, RoleBinding, roleBindingApi } from "../../api/endpoints";
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
import { KubeObjectStore, KubeObjectStoreLoadingParams } from "../../kube-object.store";
|
||||||
import { autobind } from "../../utils";
|
import { autobind } from "../../utils";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
|
||||||
@ -26,15 +26,12 @@ export class RoleBindingsStore extends KubeObjectStore<RoleBinding> {
|
|||||||
return clusterRoleBindingApi.get(params);
|
return clusterRoleBindingApi.get(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadItems(namespaces?: string[]) {
|
protected async loadItems({ isAdmin, namespaces }: KubeObjectStoreLoadingParams): Promise<RoleBinding[]> {
|
||||||
if (namespaces) {
|
const items = await Promise.all([
|
||||||
return Promise.all(
|
super.loadItems({ isAdmin, namespaces, api: clusterRoleBindingApi }),
|
||||||
namespaces.map(namespace => roleBindingApi.list({ namespace }))
|
super.loadItems({ isAdmin, namespaces, api: roleBindingApi }),
|
||||||
).then(items => items.flat());
|
]);
|
||||||
} else {
|
return items.flat();
|
||||||
return Promise.all([clusterRoleBindingApi.list(), roleBindingApi.list()])
|
|
||||||
.then(items => items.flat());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async createItem(params: { name: string; namespace?: string }, data?: Partial<RoleBinding>) {
|
protected async createItem(params: { name: string; namespace?: string }, data?: Partial<RoleBinding>) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { clusterRoleApi, Role, roleApi } from "../../api/endpoints";
|
import { clusterRoleApi, Role, roleApi } from "../../api/endpoints";
|
||||||
import { autobind } from "../../utils";
|
import { autobind } from "../../utils";
|
||||||
import { KubeObjectStore } from "../../kube-object.store";
|
import { KubeObjectStore, KubeObjectStoreLoadingParams } from "../../kube-object.store";
|
||||||
import { apiManager } from "../../api/api-manager";
|
import { apiManager } from "../../api/api-manager";
|
||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
@ -24,15 +24,12 @@ export class RolesStore extends KubeObjectStore<Role> {
|
|||||||
return clusterRoleApi.get(params);
|
return clusterRoleApi.get(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadItems(namespaces?: string[]): Promise<Role[]> {
|
protected async loadItems({ isAdmin, namespaces }: KubeObjectStoreLoadingParams): Promise<Role[]> {
|
||||||
if (namespaces) {
|
const items = await Promise.all([
|
||||||
return Promise.all(
|
super.loadItems({ isAdmin, namespaces, api: clusterRoleApi }),
|
||||||
namespaces.map(namespace => roleApi.list({ namespace }))
|
super.loadItems({ isAdmin, namespaces, api: roleApi }),
|
||||||
).then(items => items.flat());
|
]);
|
||||||
} else {
|
return items.flat();
|
||||||
return Promise.all([clusterRoleApi.list(), roleApi.list()])
|
|
||||||
.then(items => items.flat());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async createItem(params: { name: string; namespace?: string }, data?: Partial<Role>) {
|
protected async createItem(params: { name: string; namespace?: string }, data?: Partial<Role>) {
|
||||||
|
|||||||
@ -8,6 +8,12 @@ import { IKubeApiQueryParams, KubeApi } from "./api/kube-api";
|
|||||||
import { KubeJsonApiData } from "./api/kube-json-api";
|
import { KubeJsonApiData } from "./api/kube-json-api";
|
||||||
import { getHostedCluster } from "../common/cluster-store";
|
import { getHostedCluster } from "../common/cluster-store";
|
||||||
|
|
||||||
|
export interface KubeObjectStoreLoadingParams {
|
||||||
|
isAdmin: boolean;
|
||||||
|
namespaces: string[];
|
||||||
|
api?: KubeApi;
|
||||||
|
}
|
||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemStore<T> {
|
export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemStore<T> {
|
||||||
abstract api: KubeApi<T>;
|
abstract api: KubeApi<T>;
|
||||||
@ -71,14 +77,15 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async loadItems(allowedNamespaces?: string[]): Promise<T[]> {
|
protected async loadItems({ isAdmin, namespaces, api }: KubeObjectStoreLoadingParams): Promise<T[]> {
|
||||||
if (!this.api.isNamespaced || !allowedNamespaces) {
|
if (!api.isNamespaced) {
|
||||||
return this.api.list({}, this.query);
|
if (isAdmin) return api.list({}, this.query);
|
||||||
} else {
|
return [];
|
||||||
return Promise
|
|
||||||
.all(allowedNamespaces.map(namespace => this.api.list({ namespace })))
|
|
||||||
.then(items => items.flat());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise
|
||||||
|
.all(namespaces.map(namespace => api.list({ namespace })))
|
||||||
|
.then(items => items.flat());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected filterItemsOnLoad(items: T[]) {
|
protected filterItemsOnLoad(items: T[]) {
|
||||||
@ -91,22 +98,16 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
|
|||||||
let items: T[];
|
let items: T[];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { allowedNamespaces, accessibleNamespaces, isAdmin } = getHostedCluster();
|
const { allowedNamespaces: namespaces, isAdmin } = getHostedCluster();
|
||||||
|
items = await this.loadItems({ isAdmin, namespaces, api: this.api });
|
||||||
if (isAdmin && accessibleNamespaces.length == 0) {
|
|
||||||
items = await this.loadItems();
|
|
||||||
} else {
|
|
||||||
items = await this.loadItems(allowedNamespaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
items = this.filterItemsOnLoad(items);
|
items = this.filterItemsOnLoad(items);
|
||||||
} finally {
|
|
||||||
if (items) {
|
|
||||||
items = this.sortItems(items);
|
items = this.sortItems(items);
|
||||||
this.items.replace(items);
|
this.items.replace(items);
|
||||||
}
|
|
||||||
this.isLoading = false;
|
|
||||||
this.isLoaded = true;
|
this.isLoaded = true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Loading store items failed", { error, store: this });
|
||||||
|
} finally {
|
||||||
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user