From 7b34d63703d2c22fc8fa6a127601fcddd76f2b9f Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 1 Jun 2021 10:37:18 -0400 Subject: [PATCH] Move requesting isGlobalWatchAllowed to renderer - Check accessibleNamespaces in globalWatch handler Signed-off-by: Sebastian Malton --- src/common/ipc/cluster.ipc.ts | 1 + src/main/cluster.ts | 10 ---------- src/main/initializers/ipc.ts | 20 +++++++++++++++++++- src/renderer/api/allowed-resources.ts | 20 ++++++++++++++++++-- src/renderer/kube-object.store.ts | 7 +++++-- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/common/ipc/cluster.ipc.ts b/src/common/ipc/cluster.ipc.ts index af9542fbb7..555b02aecd 100644 --- a/src/common/ipc/cluster.ipc.ts +++ b/src/common/ipc/cluster.ipc.ts @@ -26,6 +26,7 @@ export const ClusterListNamespaceForbiddenChannel = "cluster:list-namespace-forbidden"; export const ClusterGetResourcesChannel = "cluster:resources"; export const ClusterResourceIsAllowedChannel = "cluster:resource:is-allowed"; +export const ClusterGlobalWatchChannel = "cluster:resource:global-watch-allowed"; export type ListNamespaceForbiddenArgs = [clusterId: string]; diff --git a/src/main/cluster.ts b/src/main/cluster.ts index f5feaf8f27..04170565cb 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -77,7 +77,6 @@ export interface ClusterState { ready: boolean; failureReason: string; allowedNamespaces: string[] - isGlobalWatchEnabled: boolean; } /** @@ -167,12 +166,6 @@ export class Cluster implements ClusterModel, ClusterState { */ @observable failureReason: string; - /** - * Global watch-api accessibility , e.g. "/api/v1/services?watch=1" - * - * @observable - */ - @observable isGlobalWatchEnabled = false; /** * Preferences * @@ -427,8 +420,6 @@ export class Cluster implements ClusterModel, ClusterState { * @internal */ private async refreshAccessibility(): Promise { - this.isGlobalWatchEnabled = await this.canUseWatchApi({ resource: "*" }); - this.allowedNamespaces = await this.getAllowedNamespaces(); this.ready = true; @@ -635,7 +626,6 @@ export class Cluster implements ClusterModel, ClusterState { accessible: this.accessible, failureReason: this.failureReason, allowedNamespaces: this.allowedNamespaces, - isGlobalWatchEnabled: this.isGlobalWatchEnabled, }; return toJS(state); diff --git a/src/main/initializers/ipc.ts b/src/main/initializers/ipc.ts index 3b2fb1b729..ce387cf855 100644 --- a/src/main/initializers/ipc.ts +++ b/src/main/initializers/ipc.ts @@ -25,7 +25,7 @@ import { clusterFrameMap } from "../../common/cluster-frames"; import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../common/cluster-ipc"; import { ClusterId, ClusterStore } from "../../common/cluster-store"; 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 { ResourceApplier } from "../resource-applier"; @@ -138,4 +138,22 @@ export function initIpcMainHandlers() { return Array.from(isAllowed); }); + + ipcMainHandle(ClusterGlobalWatchChannel, async (event, clusterId: ClusterId): Promise => { + 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: "*" }); + }); } diff --git a/src/renderer/api/allowed-resources.ts b/src/renderer/api/allowed-resources.ts index 42569ba797..e1621374be 100644 --- a/src/renderer/api/allowed-resources.ts +++ b/src/renderer/api/allowed-resources.ts @@ -21,7 +21,7 @@ import { action, makeObservable, observable, reaction } from "mobx"; 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 type { ApiResourceMap } from "../../main/utils/api-resources"; import { ObservableTimer } from "../../common/utils/observable-timer"; @@ -44,6 +44,13 @@ export class AllowedResources extends Singleton { protected timer = new ObservableTimer(60 * 1000); 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[]) { super(); @@ -71,13 +78,18 @@ export class AllowedResources extends Singleton { @action private async refresh(namespaces: NamespaceName[]) { 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) { console.error("[ALLOWED-RESOURCES]: failed to refresh", error, { namespaces }); Notifications.error("Failed to refresh allowed resources"); } } + /** * Get the permissive list permissions of `name` over `namespaces` * @param obj The name of the resource @@ -87,6 +99,10 @@ export class AllowedResources extends Singleton { isAllowed(obj: KubeObject): boolean { return this.allowedResources.has(obj.apiBase); } + + isGlobalWatchAllowed(): boolean { + return this.globalWatchAllowed; + } } /** diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index cece2e0575..e313a36a28 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -31,7 +31,7 @@ import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi } from "./api/kube-a import { parseKubeApi } from "./api/kube-api-parse"; import type { KubeJsonApiData } from "./api/kube-json-api"; import { Notifications } from "./components/notifications"; -import { isAllowedResource } from "./api/allowed-resources"; +import { AllowedResources, isAllowedResource } from "./api/allowed-resources"; export interface KubeObjectStoreLoadingParams { namespaces: string[]; @@ -317,7 +317,10 @@ export abstract class KubeObjectStore extends ItemSt if (this.api.isNamespaced) { Promise.race([rejectPromiseBy(abortController.signal), Promise.all([this.contextReady, this.namespacesReady])]) .then(() => { - if (this.context.cluster.isGlobalWatchEnabled && this.loadedNamespaces.length === 0) { + if ( + AllowedResources.getInstance().isGlobalWatchAllowed() + && this.loadedNamespaces.length === 0 + ) { return this.watchNamespace("", abortController); }