1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Move requesting isGlobalWatchAllowed to renderer

- Check accessibleNamespaces in globalWatch handler

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2021-06-01 10:37:18 -04:00
parent a72ac1cb3c
commit 7b34d63703
5 changed files with 43 additions and 15 deletions

View File

@ -26,6 +26,7 @@
export const ClusterListNamespaceForbiddenChannel = "cluster:list-namespace-forbidden"; export const ClusterListNamespaceForbiddenChannel = "cluster:list-namespace-forbidden";
export const ClusterGetResourcesChannel = "cluster:resources"; export const ClusterGetResourcesChannel = "cluster:resources";
export const ClusterResourceIsAllowedChannel = "cluster:resource:is-allowed"; export const ClusterResourceIsAllowedChannel = "cluster:resource:is-allowed";
export const ClusterGlobalWatchChannel = "cluster:resource:global-watch-allowed";
export type ListNamespaceForbiddenArgs = [clusterId: string]; export type ListNamespaceForbiddenArgs = [clusterId: string];

View File

@ -77,7 +77,6 @@ export interface ClusterState {
ready: boolean; ready: boolean;
failureReason: string; failureReason: string;
allowedNamespaces: string[] allowedNamespaces: string[]
isGlobalWatchEnabled: boolean;
} }
/** /**
@ -167,12 +166,6 @@ export class Cluster implements ClusterModel, ClusterState {
*/ */
@observable failureReason: string; @observable failureReason: string;
/**
* Global watch-api accessibility , e.g. "/api/v1/services?watch=1"
*
* @observable
*/
@observable isGlobalWatchEnabled = false;
/** /**
* Preferences * Preferences
* *
@ -427,8 +420,6 @@ export class Cluster implements ClusterModel, ClusterState {
* @internal * @internal
*/ */
private async refreshAccessibility(): Promise<void> { private async refreshAccessibility(): Promise<void> {
this.isGlobalWatchEnabled = await this.canUseWatchApi({ resource: "*" });
this.allowedNamespaces = await this.getAllowedNamespaces(); this.allowedNamespaces = await this.getAllowedNamespaces();
this.ready = true; this.ready = true;
@ -635,7 +626,6 @@ export class Cluster implements ClusterModel, ClusterState {
accessible: this.accessible, accessible: this.accessible,
failureReason: this.failureReason, failureReason: this.failureReason,
allowedNamespaces: this.allowedNamespaces, allowedNamespaces: this.allowedNamespaces,
isGlobalWatchEnabled: this.isGlobalWatchEnabled,
}; };
return toJS(state); return toJS(state);

View File

@ -25,7 +25,7 @@ import { clusterFrameMap } from "../../common/cluster-frames";
import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../common/cluster-ipc"; import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../common/cluster-ipc";
import { ClusterId, ClusterStore } from "../../common/cluster-store"; import { ClusterId, ClusterStore } from "../../common/cluster-store";
import { appEventBus } from "../../common/event-bus"; import { appEventBus } from "../../common/event-bus";
import { ClusterGetResourcesChannel, ClusterResourceIsAllowedChannel, ipcMainHandle } from "../../common/ipc"; import { ClusterGetResourcesChannel, ClusterGlobalWatchChannel, ClusterResourceIsAllowedChannel, ipcMainHandle } from "../../common/ipc";
import { catalogEntityRegistry } from "../catalog"; import { catalogEntityRegistry } from "../catalog";
import { ResourceApplier } from "../resource-applier"; import { ResourceApplier } from "../resource-applier";
@ -138,4 +138,22 @@ export function initIpcMainHandlers() {
return Array.from(isAllowed); return Array.from(isAllowed);
}); });
ipcMainHandle(ClusterGlobalWatchChannel, async (event, clusterId: ClusterId): Promise<boolean> => {
const cluster = ClusterStore.getInstance().getById(clusterId);
if (!cluster) {
throw `${clusterId} is not a valid cluster id`;
}
if (cluster.accessibleNamespaces.length > 0) {
/**
* Don't allow global watching when the user has specified namespaces.
* Assume that the cluster can't even list namespaces
*/
return false;
}
return cluster.canUseWatchApi({ resource: "*" });
});
} }

View File

@ -21,7 +21,7 @@
import { action, makeObservable, observable, reaction } from "mobx"; import { action, makeObservable, observable, reaction } from "mobx";
import type { ClusterId } from "../../common/cluster-store"; import type { ClusterId } from "../../common/cluster-store";
import { ClusterResourceIsAllowedChannel, ClusterGetResourcesChannel, requestMain } from "../../common/ipc"; import { ClusterResourceIsAllowedChannel, ClusterGetResourcesChannel, ClusterGlobalWatchChannel, requestMain } from "../../common/ipc";
import { Disposer, Singleton } from "../utils"; import { Disposer, Singleton } from "../utils";
import type { ApiResourceMap } from "../../main/utils/api-resources"; import type { ApiResourceMap } from "../../main/utils/api-resources";
import { ObservableTimer } from "../../common/utils/observable-timer"; import { ObservableTimer } from "../../common/utils/observable-timer";
@ -44,6 +44,13 @@ export class AllowedResources extends Singleton {
protected timer = new ObservableTimer(60 * 1000); protected timer = new ObservableTimer(60 * 1000);
disposer: Disposer; disposer: Disposer;
/**
* Global watch-api accessibility , e.g. "/api/v1/services?watch=1"
*
* @observable
*/
@observable private globalWatchAllowed = false;
constructor(protected clusterId: ClusterId, protected getNamespaces: () => NamespaceName[]) { constructor(protected clusterId: ClusterId, protected getNamespaces: () => NamespaceName[]) {
super(); super();
@ -71,13 +78,18 @@ export class AllowedResources extends Singleton {
@action @action
private async refresh(namespaces: NamespaceName[]) { private async refresh(namespaces: NamespaceName[]) {
try { try {
this.allowedResources.replace(await requestMain(ClusterResourceIsAllowedChannel, this.clusterId, namespaces)); const allowedResourcesP = requestMain(ClusterResourceIsAllowedChannel, this.clusterId, namespaces);
const globalWatchAllowedP = requestMain(ClusterGlobalWatchChannel, this.clusterId);
this.allowedResources.replace(await allowedResourcesP);
this.globalWatchAllowed = await globalWatchAllowedP;
} catch (error) { } catch (error) {
console.error("[ALLOWED-RESOURCES]: failed to refresh", error, { namespaces }); console.error("[ALLOWED-RESOURCES]: failed to refresh", error, { namespaces });
Notifications.error("Failed to refresh allowed resources"); Notifications.error("Failed to refresh allowed resources");
} }
} }
/** /**
* Get the permissive list permissions of `name` over `namespaces` * Get the permissive list permissions of `name` over `namespaces`
* @param obj The name of the resource * @param obj The name of the resource
@ -87,6 +99,10 @@ export class AllowedResources extends Singleton {
isAllowed(obj: KubeObject): boolean { isAllowed(obj: KubeObject): boolean {
return this.allowedResources.has(obj.apiBase); return this.allowedResources.has(obj.apiBase);
} }
isGlobalWatchAllowed(): boolean {
return this.globalWatchAllowed;
}
} }
/** /**

View File

@ -31,7 +31,7 @@ import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi } from "./api/kube-a
import { parseKubeApi } from "./api/kube-api-parse"; import { parseKubeApi } from "./api/kube-api-parse";
import type { KubeJsonApiData } from "./api/kube-json-api"; import type { KubeJsonApiData } from "./api/kube-json-api";
import { Notifications } from "./components/notifications"; import { Notifications } from "./components/notifications";
import { isAllowedResource } from "./api/allowed-resources"; import { AllowedResources, isAllowedResource } from "./api/allowed-resources";
export interface KubeObjectStoreLoadingParams { export interface KubeObjectStoreLoadingParams {
namespaces: string[]; namespaces: string[];
@ -317,7 +317,10 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
if (this.api.isNamespaced) { if (this.api.isNamespaced) {
Promise.race([rejectPromiseBy(abortController.signal), Promise.all([this.contextReady, this.namespacesReady])]) Promise.race([rejectPromiseBy(abortController.signal), Promise.all([this.contextReady, this.namespacesReady])])
.then(() => { .then(() => {
if (this.context.cluster.isGlobalWatchEnabled && this.loadedNamespaces.length === 0) { if (
AllowedResources.getInstance().isGlobalWatchAllowed()
&& this.loadedNamespaces.length === 0
) {
return this.watchNamespace("", abortController); return this.watchNamespace("", abortController);
} }