diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index c2896309f41f..e1474a43323a 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -390,6 +390,12 @@ const scenarios = [ sidebarItemTestId: "sidebar-item-link-for-service-accounts", }, + { + expectedSelector: "h5.title", + parentSidebarItemTestId: "sidebar-item-link-for-user-management", + sidebarItemTestId: "sidebar-item-link-for-roles", + }, + { expectedSelector: "h5.title", parentSidebarItemTestId: "sidebar-item-link-for-user-management", @@ -399,7 +405,7 @@ const scenarios = [ { expectedSelector: "h5.title", parentSidebarItemTestId: "sidebar-item-link-for-user-management", - sidebarItemTestId: "sidebar-item-link-for-roles", + sidebarItemTestId: "sidebar-item-link-for-role-bindings", }, { @@ -411,7 +417,7 @@ const scenarios = [ { expectedSelector: "h5.title", parentSidebarItemTestId: "sidebar-item-link-for-user-management", - sidebarItemTestId: "sidebar-item-link-for-role-bindings", + sidebarItemTestId: "sidebar-item-link-for-pod-security-policies", }, { diff --git a/package.json b/package.json index f4daef57ac4b..ccb93f01d61f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "6.2.2", + "version": "6.2.3", "main": "static/build/main.js", "copyright": "© 2022 OpenLens Authors", "license": "MIT", diff --git a/src/common/cluster-types.ts b/src/common/cluster-types.ts index 0cd447f0e207..faf6debbabad 100644 --- a/src/common/cluster-types.ts +++ b/src/common/cluster-types.ts @@ -195,6 +195,13 @@ export enum ClusterMetricsResourceType { */ export const initialNodeShellImage = "docker.io/alpine:3.13"; +/** + * The arguments for requesting to refresh a cluster's metadata + */ +export interface ClusterRefreshOptions { + refreshMetadata?: boolean; +} + /** * The data representing a cluster's state, for passing between main and renderer */ diff --git a/src/common/cluster/authorization-namespace-review.injectable.ts b/src/common/cluster/authorization-namespace-review.injectable.ts deleted file mode 100644 index aa7845356967..000000000000 --- a/src/common/cluster/authorization-namespace-review.injectable.ts +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeConfig } from "@kubernetes/client-node"; -import { AuthorizationV1Api } from "@kubernetes/client-node"; -import { getInjectable } from "@ogre-tools/injectable"; -import type { Logger } from "../logger"; -import loggerInjectable from "../logger.injectable"; -import type { KubeApiResource } from "../rbac"; - -/** - * Requests the permissions for actions on the kube cluster - * @param namespace The namespace of the resources - * @param availableResources List of available resources in the cluster to resolve glob values fir api groups - * @returns list of allowed resources names - */ -export type RequestNamespaceResources = (namespace: string, availableResources: KubeApiResource[]) => Promise; - -/** - * @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster - */ -export type AuthorizationNamespaceReview = (proxyConfig: KubeConfig) => RequestNamespaceResources; - -interface Dependencies { - logger: Logger; -} - -const authorizationNamespaceReview = ({ logger }: Dependencies): AuthorizationNamespaceReview => { - return (proxyConfig) => { - - const api = proxyConfig.makeApiClient(AuthorizationV1Api); - - return async (namespace, availableResources) => { - try { - const { body } = await api.createSelfSubjectRulesReview({ - apiVersion: "authorization.k8s.io/v1", - kind: "SelfSubjectRulesReview", - spec: { namespace }, - }); - - const resources = new Set(); - - body.status?.resourceRules.forEach(resourceRule => { - if (!resourceRule.verbs.some(verb => ["*", "list"].includes(verb)) || !resourceRule.resources) { - return; - } - - const apiGroups = resourceRule.apiGroups; - - if (resourceRule.resources.length === 1 && resourceRule.resources[0] === "*" && apiGroups) { - if (apiGroups[0] === "*") { - availableResources.forEach(resource => resources.add(resource.apiName)); - } else { - availableResources.forEach((apiResource)=> { - if (apiGroups.includes(apiResource.group || "")) { - resources.add(apiResource.apiName); - } - }); - } - } else { - resourceRule.resources.forEach(resource => resources.add(resource)); - } - - }); - - return [...resources]; - } catch (error) { - logger.error(`[AUTHORIZATION-NAMESPACE-REVIEW]: failed to create subject rules review: ${error}`, { namespace }); - - return []; - } - }; - }; -}; - -const authorizationNamespaceReviewInjectable = getInjectable({ - id: "authorization-namespace-review", - instantiate: (di) => { - const logger = di.inject(loggerInjectable); - - return authorizationNamespaceReview({ logger }); - }, -}); - -export default authorizationNamespaceReviewInjectable; diff --git a/src/common/cluster/authorization-review.injectable.ts b/src/common/cluster/authorization-review.injectable.ts index 4c9b83330d8b..c622893b63f7 100644 --- a/src/common/cluster/authorization-review.injectable.ts +++ b/src/common/cluster/authorization-review.injectable.ts @@ -5,55 +5,42 @@ import type { KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"; import { AuthorizationV1Api } from "@kubernetes/client-node"; +import logger from "../logger"; import { getInjectable } from "@ogre-tools/injectable"; -import type { Logger } from "../logger"; -import loggerInjectable from "../logger.injectable"; -/** - * Requests the permissions for actions on the kube cluster - * @param resourceAttributes The descriptor of the action that is desired to be known if it is allowed - * @returns `true` if the actions described are allowed - */ export type CanI = (resourceAttributes: V1ResourceAttributes) => Promise; /** * @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster - */ -export type AuthorizationReview = (proxyConfig: KubeConfig) => CanI; - -interface Dependencies { - logger: Logger; -} - -const authorizationReview = ({ logger }: Dependencies): AuthorizationReview => { - return (proxyConfig) => { - const api = proxyConfig.makeApiClient(AuthorizationV1Api); - - return async (resourceAttributes: V1ResourceAttributes): Promise => { - try { - const { body } = await api.createSelfSubjectAccessReview({ - apiVersion: "authorization.k8s.io/v1", - kind: "SelfSubjectAccessReview", - spec: { resourceAttributes }, - }); - - return body.status?.allowed ?? false; - } catch (error) { - logger.error(`[AUTHORIZATION-REVIEW]: failed to create access review: ${error}`, { resourceAttributes }); - - return false; - } - }; + */ +export function authorizationReview(proxyConfig: KubeConfig): CanI { + const api = proxyConfig.makeApiClient(AuthorizationV1Api); + + /** + * Requests the permissions for actions on the kube cluster + * @param resourceAttributes The descriptor of the action that is desired to be known if it is allowed + * @returns `true` if the actions described are allowed + */ + return async (resourceAttributes: V1ResourceAttributes): Promise => { + try { + const { body } = await api.createSelfSubjectAccessReview({ + apiVersion: "authorization.k8s.io/v1", + kind: "SelfSubjectAccessReview", + spec: { resourceAttributes }, + }); + + return body.status?.allowed ?? false; + } catch (error) { + logger.error(`[AUTHORIZATION-REVIEW]: failed to create access review: ${error}`, { resourceAttributes }); + + return false; + } }; -}; +} const authorizationReviewInjectable = getInjectable({ id: "authorization-review", - instantiate: (di) => { - const logger = di.inject(loggerInjectable); - - return authorizationReview({ logger }); - }, + instantiate: () => authorizationReview, }); export default authorizationReviewInjectable; diff --git a/src/common/cluster/cluster.ts b/src/common/cluster/cluster.ts index 7f2702519026..b0d7fbfbc3f3 100644 --- a/src/common/cluster/cluster.ts +++ b/src/common/cluster/cluster.ts @@ -14,7 +14,7 @@ import { apiResourceRecord, apiResources } from "../rbac"; import type { VersionDetector } from "../../main/cluster-detectors/version-detector"; import type { DetectorRegistry } from "../../main/cluster-detectors/detector-registry"; import plimit from "p-limit"; -import type { ClusterState, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate, ClusterConfigData } from "../cluster-types"; +import type { ClusterState, ClusterRefreshOptions, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate, ClusterConfigData } from "../cluster-types"; import { ClusterMetadataKey, initialNodeShellImage, ClusterStatus, clusterModelIdChecker, updateClusterModelChecker } from "../cluster-types"; import { disposer, isDefined, isRequestError, toJS } from "../utils"; import type { Response } from "request"; @@ -25,8 +25,6 @@ import assert from "assert"; import type { Logger } from "../logger"; import type { BroadcastMessage } from "../ipc/broadcast-message.injectable"; import type { LoadConfigfromFile } from "../kube-helpers/load-config-from-file.injectable"; -import type { RequestNamespaceResources } from "./authorization-namespace-review.injectable"; -import type { RequestListApiResources } from "./list-api-resources.injectable"; export interface ClusterDependencies { readonly directoryForKubeConfigs: string; @@ -36,8 +34,6 @@ export interface ClusterDependencies { createContextHandler: (cluster: Cluster) => ClusterContextHandler; createKubectl: (clusterVersion: string) => Kubectl; createAuthorizationReview: (config: KubeConfig) => CanI; - createAuthorizationNamespaceReview: (config: KubeConfig) => RequestNamespaceResources; - createListApiResources: (cluster: Cluster) => RequestListApiResources; createListNamespaces: (config: KubeConfig) => ListNamespaces; createVersionDetector: (cluster: Cluster) => VersionDetector; broadcastMessage: BroadcastMessage; @@ -313,7 +309,7 @@ export class Cluster implements ClusterModel, ClusterState { protected bindEvents() { this.dependencies.logger.info(`[CLUSTER]: bind events`, this.getMeta()); const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s - const refreshMetadataTimer = setInterval(() => this.available && this.refreshAccessibilityAndMetadata(), 900000); // every 15 minutes + const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes this.eventsDisposer.push( reaction(() => this.getState(), state => this.pushState(state)), @@ -443,68 +439,66 @@ export class Cluster implements ClusterModel, ClusterState { /** * @internal + * @param opts refresh options */ @action - async refresh() { + async refresh(opts: ClusterRefreshOptions = {}) { this.dependencies.logger.info(`[CLUSTER]: refresh`, this.getMeta()); await this.refreshConnectionStatus(); + + if (this.accessible) { + await this.refreshAccessibility(); + + if (opts.refreshMetadata) { + this.refreshMetadata(); + } + } this.pushState(); } /** * @internal */ - @action - async refreshAccessibilityAndMetadata() { - await this.refreshAccessibility(); - await this.refreshMetadata(); + @action + async refreshMetadata() { + this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); + const metadata = await this.dependencies.detectorRegistry.detectForCluster(this); + const existingMetadata = this.metadata; + + this.metadata = Object.assign(existingMetadata, metadata); } - /** + /** * @internal */ - async refreshMetadata() { - this.dependencies.logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); - const metadata = await this.dependencies.detectorRegistry.detectForCluster(this); - const existingMetadata = this.metadata; - - this.metadata = Object.assign(existingMetadata, metadata); - } + private async refreshAccessibility(): Promise { + const proxyConfig = await this.getProxyKubeconfig(); + const canI = this.dependencies.createAuthorizationReview(proxyConfig); - /** - * @internal - */ - private async refreshAccessibility(): Promise { - this.dependencies.logger.info(`[CLUSTER]: refreshAccessibility`, this.getMeta()); - const proxyConfig = await this.getProxyKubeconfig(); - const canI = this.dependencies.createAuthorizationReview(proxyConfig); - const requestNamespaceResources = this.dependencies.createAuthorizationNamespaceReview(proxyConfig); - const listApiResources = this.dependencies.createListApiResources(this); - - this.isAdmin = await canI({ - namespace: "kube-system", - resource: "*", - verb: "create", - }); - this.isGlobalWatchEnabled = await canI({ - verb: "watch", - resource: "*", - }); - this.allowedNamespaces = await this.getAllowedNamespaces(proxyConfig); - this.allowedResources = await this.getAllowedResources(listApiResources, requestNamespaceResources); - this.ready = true; - } + this.isAdmin = await canI({ + namespace: "kube-system", + resource: "*", + verb: "create", + }); + this.isGlobalWatchEnabled = await canI({ + verb: "watch", + resource: "*", + }); + this.allowedNamespaces = await this.getAllowedNamespaces(proxyConfig); + this.allowedResources = await this.getAllowedResources(canI); + this.ready = true; + } /** * @internal */ @action - async refreshConnectionStatus() { - const connectionStatus = await this.getConnectionStatus(); + async refreshConnectionStatus() { + const connectionStatus = await this.getConnectionStatus(); - this.online = connectionStatus > ClusterStatus.Offline; - this.accessible = connectionStatus == ClusterStatus.AccessGranted; - } + this.online = connectionStatus > ClusterStatus.Offline; + this.accessible = connectionStatus == ClusterStatus.AccessGranted; + } async getKubeconfig(): Promise { const { config } = await this.dependencies.loadConfigfromFile(this.kubeConfigPath); @@ -673,48 +667,32 @@ export class Cluster implements ClusterModel, ClusterState { } } - protected async getAllowedResources(listApiResources:RequestListApiResources, requestNamespaceResources: RequestNamespaceResources) { + protected async getAllowedResources(canI: CanI) { try { if (!this.allowedNamespaces.length) { return []; } - - const unknownResources = new Map(apiResources.map(resource => ([resource.apiName, resource]))); - - const availableResources = await listApiResources(); - const availableResourcesNames = new Set(availableResources.map(apiResource => apiResource.apiName)); - - [...unknownResources.values()].map(unknownResource => { - if (!availableResourcesNames.has(unknownResource.apiName)) { - this.resourceAccessStatuses.set(unknownResource, false); - unknownResources.delete(unknownResource.apiName); - } - }); - - if (unknownResources.size > 0) { - const apiLimit = plimit(5); // 5 concurrent api requests - - await Promise.all(this.allowedNamespaces.map(namespace => apiLimit(async () => { - if (unknownResources.size === 0) { - return; - } - - const namespaceResources = await requestNamespaceResources(namespace, availableResources); - - for (const resourceName of namespaceResources) { - const unknownResource = unknownResources.get(resourceName); - - if (unknownResource) { - this.resourceAccessStatuses.set(unknownResource, true); - unknownResources.delete(resourceName); + const resources = apiResources.filter((resource) => this.resourceAccessStatuses.get(resource) === undefined); + const apiLimit = plimit(5); // 5 concurrent api requests + const requests = []; + + for (const apiResource of resources) { + requests.push(apiLimit(async () => { + for (const namespace of this.allowedNamespaces.slice(0, 10)) { + if (!this.resourceAccessStatuses.get(apiResource)) { + const result = await canI({ + resource: apiResource.apiName, + group: apiResource.group, + verb: "list", + namespace, + }); + + this.resourceAccessStatuses.set(apiResource, result); } } - }))); - - for (const forbiddenResource of unknownResources.values()) { - this.resourceAccessStatuses.set(forbiddenResource, false); - } + })); } + await Promise.all(requests); return apiResources .filter((resource) => this.resourceAccessStatuses.get(resource)) diff --git a/src/common/cluster/list-api-resources.injectable.ts b/src/common/cluster/list-api-resources.injectable.ts deleted file mode 100644 index ed9d5c9c39c7..000000000000 --- a/src/common/cluster/list-api-resources.injectable.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { - V1APIGroupList, - V1APIResourceList, - V1APIVersions, -} from "@kubernetes/client-node"; -import { getInjectable } from "@ogre-tools/injectable"; -import type { K8sRequest } from "../../main/k8s-request.injectable"; -import k8SRequestInjectable from "../../main/k8s-request.injectable"; -import type { Logger } from "../logger"; -import loggerInjectable from "../logger.injectable"; -import type { KubeApiResource, KubeResource } from "../rbac"; -import type { Cluster } from "./cluster"; -import plimit from "p-limit"; - -export type RequestListApiResources = () => Promise; - -/** - * @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster - */ -export type ListApiResources = (cluster: Cluster) => RequestListApiResources; - -interface Dependencies { - logger: Logger; - k8sRequest: K8sRequest; -} - -const listApiResources = ({ k8sRequest, logger }: Dependencies): ListApiResources => { - return (cluster) => { - const clusterRequest = (path: string) => k8sRequest(cluster, path); - const apiLimit = plimit(5); - - return async () => { - const resources: KubeApiResource[] = []; - - try { - const resourceListGroups:{ group:string;path:string }[] = []; - - await Promise.all( - [ - clusterRequest("/api").then((response:V1APIVersions)=>response.versions.forEach(version => resourceListGroups.push({ group:version, path:`/api/${version}` }))), - clusterRequest("/apis").then((response:V1APIGroupList) => response.groups.forEach(group => { - const preferredVersion = group.preferredVersion?.groupVersion; - - if (preferredVersion) { - resourceListGroups.push({ group:group.name, path:`/apis/${preferredVersion}` }); - } - })), - ], - ); - - await Promise.all( - resourceListGroups.map(({ group, path }) => apiLimit(async () => { - const apiResources:V1APIResourceList = await clusterRequest(path); - - if (apiResources.resources) { - resources.push( - ...apiResources.resources.filter(resource => resource.verbs.includes("list")).map((resource) => ({ - apiName: resource.name as KubeResource, - kind: resource.kind, - group, - })), - ); - } - }), - ), - ); - } catch (error) { - logger.error(`[LIST-API-RESOURCES]: failed to list api resources: ${error}`); - } - - return resources; - }; - }; -}; - -const listApiResourcesInjectable = getInjectable({ - id: "list-api-resources", - instantiate: (di) => { - const k8sRequest = di.inject(k8SRequestInjectable); - const logger = di.inject(loggerInjectable); - - return listApiResources({ k8sRequest, logger }); - }, -}); - -export default listApiResourcesInjectable; diff --git a/src/common/ipc/cluster.ts b/src/common/ipc/cluster.ts index 803069c00e4e..c89e2f501035 100644 --- a/src/common/ipc/cluster.ts +++ b/src/common/ipc/cluster.ts @@ -5,7 +5,7 @@ export const clusterActivateHandler = "cluster:activate"; export const clusterSetFrameIdHandler = "cluster:set-frame-id"; -export const clusterVisibilityHandler = "cluster:visibility"; +export const clusterRefreshHandler = "cluster:refresh"; export const clusterDisconnectHandler = "cluster:disconnect"; export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all"; export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all"; diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index 980b63c767bd..0244141ab387 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -10,7 +10,6 @@ import { getDiForUnitTesting } from "../getDiForUnitTesting"; import type { CreateCluster } from "../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token"; import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; -import authorizationNamespaceReviewInjectable from "../../common/cluster/authorization-namespace-review.injectable"; import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable"; import type { ClusterContextHandler } from "../context-handler/context-handler"; @@ -20,8 +19,6 @@ import directoryForTempInjectable from "../../common/app-paths/directory-for-tem import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable"; import kubectlBinaryNameInjectable from "../kubectl/binary-name.injectable"; import kubectlDownloadingNormalizedArchInjectable from "../kubectl/normalized-arch.injectable"; -import { apiResourceRecord, apiResources } from "../../common/rbac"; -import listApiResourcesInjectable from "../../common/cluster/list-api-resources.injectable"; console = new Console(process.stdout, process.stderr); // fix mockFS @@ -42,8 +39,6 @@ describe("create clusters", () => { di.override(normalizedPlatformInjectable, () => "darwin"); di.override(broadcastMessageInjectable, () => async () => {}); di.override(authorizationReviewInjectable, () => () => () => Promise.resolve(true)); - di.override(authorizationNamespaceReviewInjectable, () => () => () => Promise.resolve(Object.keys(apiResourceRecord))); - di.override(listApiResourcesInjectable, () => () => () => Promise.resolve(apiResources)); di.override(listNamespacesInjectable, () => () => () => Promise.resolve([ "default" ])); di.override(createContextHandlerInjectable, () => (cluster) => ({ restartServer: jest.fn(), diff --git a/src/main/create-cluster/create-cluster.injectable.ts b/src/main/create-cluster/create-cluster.injectable.ts index e1782ec6c9c4..5290e92db3ec 100644 --- a/src/main/create-cluster/create-cluster.injectable.ts +++ b/src/main/create-cluster/create-cluster.injectable.ts @@ -11,9 +11,7 @@ import createKubectlInjectable from "../kubectl/create-kubectl.injectable"; import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable"; import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token"; import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; -import createAuthorizationNamespaceReview from "../../common/cluster/authorization-namespace-review.injectable"; import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; -import createListApiResourcesInjectable from "../../common/cluster/list-api-resources.injectable"; import loggerInjectable from "../../common/logger.injectable"; import detectorRegistryInjectable from "../cluster-detectors/detector-registry.injectable"; import createVersionDetectorInjectable from "../cluster-detectors/create-version-detector.injectable"; @@ -30,8 +28,6 @@ const createClusterInjectable = getInjectable({ createKubectl: di.inject(createKubectlInjectable), createContextHandler: di.inject(createContextHandlerInjectable), createAuthorizationReview: di.inject(authorizationReviewInjectable), - createAuthorizationNamespaceReview: di.inject(createAuthorizationNamespaceReview), - createListApiResources: di.inject(createListApiResourcesInjectable), createListNamespaces: di.inject(listNamespacesInjectable), logger: di.inject(loggerInjectable), detectorRegistry: di.inject(detectorRegistryInjectable), diff --git a/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts b/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts index a78ae3a588bb..d11fe0de3c98 100644 --- a/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts +++ b/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts @@ -5,7 +5,7 @@ import type { IpcMainInvokeEvent } from "electron"; import { BrowserWindow, Menu } from "electron"; import { clusterFrameMap } from "../../../../common/cluster-frames"; -import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../../../common/ipc/cluster"; +import { clusterActivateHandler, clusterSetFrameIdHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../../../common/ipc/cluster"; import type { ClusterId } from "../../../../common/cluster-types"; import { ClusterStore } from "../../../../common/cluster-store/cluster-store"; import { broadcastMainChannel, broadcastMessage, ipcMainHandle, ipcMainOn } from "../../../../common/ipc"; @@ -39,7 +39,6 @@ interface Dependencies { export const setupIpcMainHandlers = ({ applicationMenuItemComposite, - clusterManager, catalogEntityRegistry, clusterStore, operatingSystemTheme, @@ -64,8 +63,10 @@ export const setupIpcMainHandlers = ({ } }); - ipcMainOn(clusterVisibilityHandler, (event, clusterId?: ClusterId) => { - clusterManager.visibleCluster = clusterId; + ipcMainHandle(clusterRefreshHandler, (event, clusterId: ClusterId) => { + return ClusterStore.getInstance() + .getById(clusterId) + ?.refresh({ refreshMetadata: true }); }); ipcMainHandle(clusterDisconnectHandler, (event, clusterId: ClusterId) => { diff --git a/src/renderer/components/cluster-manager/cluster-frame-handler.ts b/src/renderer/components/cluster-manager/cluster-frame-handler.ts index 7791837e0d93..e9db1ba54501 100644 --- a/src/renderer/components/cluster-manager/cluster-frame-handler.ts +++ b/src/renderer/components/cluster-manager/cluster-frame-handler.ts @@ -5,7 +5,7 @@ import { action, makeObservable, observable, when } from "mobx"; import logger from "../../../main/logger"; -import { clusterVisibilityHandler } from "../../../common/ipc/cluster"; +import { clusterRefreshHandler } from "../../../common/ipc/cluster"; import { ClusterStore } from "../../../common/cluster-store/cluster-store"; import type { ClusterId } from "../../../common/cluster-types"; import type { Disposer } from "../../utils"; @@ -91,7 +91,7 @@ export class ClusterFrameHandler { this.prevVisibleClusterChange?.(); logger.info(`[LENS-VIEW]: refreshing iframe views, visible cluster id=${clusterId}`); - ipcRenderer.send(clusterVisibilityHandler); + ipcRenderer.send(clusterRefreshHandler); for (const { frame: view } of this.views.values()) { view.classList.add("hidden"); @@ -116,7 +116,7 @@ export class ClusterFrameHandler { logger.info(`[LENS-VIEW]: cluster id=${clusterId} should now be visible`); view.frame.classList.remove("hidden"); view.frame.focus(); - ipcRenderer.send(clusterVisibilityHandler, clusterId); + ipcRenderer.send(clusterRefreshHandler, clusterId); }, ); } diff --git a/src/renderer/create-cluster/create-cluster.injectable.ts b/src/renderer/create-cluster/create-cluster.injectable.ts index e0a9f5165671..0c73eb82fa81 100644 --- a/src/renderer/create-cluster/create-cluster.injectable.ts +++ b/src/renderer/create-cluster/create-cluster.injectable.ts @@ -27,9 +27,7 @@ const createClusterInjectable = getInjectable({ createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");}, createContextHandler: () => undefined as never, createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); }, - createAuthorizationNamespaceReview: () => { throw new Error("Tried to access back-end feature in front-end."); }, createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); }, - createListApiResources: ()=> { throw new Error("Tried to access back-end feature in front-end."); }, detectorRegistry: undefined as never, createVersionDetector: () => { throw new Error("Tried to access back-end feature in front-end."); }, };