diff --git a/src/common/__tests__/cluster-store.test.ts b/src/common/__tests__/cluster-store.test.ts index 6d4198d8d7..620debbb0b 100644 --- a/src/common/__tests__/cluster-store.test.ts +++ b/src/common/__tests__/cluster-store.test.ts @@ -25,9 +25,11 @@ import yaml from "js-yaml"; import path from "path"; import fse from "fs-extra"; import { Cluster } from "../../main/cluster"; -import { ClusterId, ClusterStore, getClusterIdFromHost } from "../cluster-store"; +import { ClusterStore } from "../cluster-store"; import { Console } from "console"; import { stdout, stderr } from "process"; +import type { ClusterId } from "../cluster-types"; +import { getCustomKubeConfigPath } from "../utils"; console = new Console(stdout, stderr); @@ -57,7 +59,7 @@ users: `; function embed(clusterId: ClusterId, contents: any): string { - const absPath = ClusterStore.getCustomKubeConfigPath(clusterId); + const absPath = getCustomKubeConfigPath(clusterId); fse.ensureDirSync(path.dirname(absPath)); fse.writeFileSync(absPath, contents, { encoding: "utf-8", mode: 0o600 }); @@ -550,27 +552,3 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => { expect(icon.startsWith("data:;base64,")).toBe(true); }); }); - -describe("getClusterIdFromHost", () => { - const clusterFakeId = "fe540901-0bd6-4f6c-b472-bce1559d7c4a"; - - it("should return undefined for non cluster frame hosts", () => { - expect(getClusterIdFromHost("localhost:45345")).toBeUndefined(); - }); - - it("should return ClusterId for cluster frame hosts", () => { - expect(getClusterIdFromHost(`${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - }); - - it("should return ClusterId for cluster frame hosts with additional subdomains", () => { - expect(getClusterIdFromHost(`abc.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - expect(getClusterIdFromHost(`abc.def.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - expect(getClusterIdFromHost(`abc.def.ghi.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - expect(getClusterIdFromHost(`abc.def.ghi.jkl.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.vwx.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.vwx.yz.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); - }); -}); diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index b6e198a213..8e8940c644 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -19,119 +19,26 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import path from "path"; -import { app, ipcMain, ipcRenderer, remote, webFrame } from "electron"; +import { ipcMain, ipcRenderer, webFrame } from "electron"; import { action, comparer, computed, makeObservable, observable, reaction } from "mobx"; import { BaseStore } from "./base-store"; -import { Cluster, ClusterState } from "../main/cluster"; +import { Cluster } from "../main/cluster"; import migrations from "../migrations/cluster-store"; -import * as uuid from "uuid"; import logger from "../main/logger"; import { appEventBus } from "./event-bus"; import { ipcMainHandle, ipcMainOn, ipcRendererOn, requestMain } from "./ipc"; import { disposer, toJS } from "./utils"; - -export interface ClusterIconUpload { - clusterId: string; - name: string; - path: string; -} - -export interface ClusterMetadata { - [key: string]: string | number | boolean | object; -} - -export type ClusterPrometheusMetadata = { - success?: boolean; - provider?: string; - autoDetected?: boolean; -}; +import type { ClusterModel, ClusterId, ClusterState } from "./cluster-types"; export interface ClusterStoreModel { clusters?: ClusterModel[]; } -export type ClusterId = string; - -export interface UpdateClusterModel extends Omit { - id?: ClusterId; -} - -export interface ClusterModel { - /** Unique id for a cluster */ - id: ClusterId; - - /** Path to cluster kubeconfig */ - kubeConfigPath: string; - - /** - * Workspace id - * - * @deprecated - */ - workspace?: string; - - /** - * @deprecated this is used only for hotbar migrations from 4.2.X - */ - workspaces?: string[]; - - /** User context in kubeconfig */ - contextName: string; - - /** Preferences */ - preferences?: ClusterPreferences; - - /** Metadata */ - metadata?: ClusterMetadata; - - /** - * Labels for the catalog entity - */ - labels?: Record; - - /** List of accessible namespaces */ - accessibleNamespaces?: string[]; -} - -export interface ClusterPreferences extends ClusterPrometheusPreferences { - terminalCWD?: string; - clusterName?: string; - iconOrder?: number; - icon?: string; - httpsProxy?: string; - hiddenMetrics?: string[]; - nodeShellImage?: string; - imagePullSecret?: string; -} - -export interface ClusterPrometheusPreferences { - prometheus?: { - namespace: string; - service: string; - port: number; - prefix: string; - }; - prometheusProvider?: { - type: string; - }; -} - const initialStates = "cluster:states"; -export const initialNodeShellImage = "docker.io/alpine:3.13"; - export class ClusterStore extends BaseStore { private static StateChannel = "cluster:state"; - static get storedKubeConfigFolder(): string { - return path.resolve((app ?? remote.app).getPath("userData"), "kubeconfigs"); - } - - static getCustomKubeConfigPath(clusterId: ClusterId = uuid.v4()): string { - return path.resolve(ClusterStore.storedKubeConfigFolder, clusterId); - } - clusters = observable.map(); removedClusters = observable.map(); @@ -272,22 +179,3 @@ export class ClusterStore extends BaseStore { }); } } - -export function getClusterIdFromHost(host: string): ClusterId | undefined { - // e.g host == "%clusterId.localhost:45345" - const subDomains = host.split(":")[0].split("."); - - return subDomains.slice(-2, -1)[0]; // ClusterId or undefined -} - -export function getClusterFrameUrl(clusterId: ClusterId) { - return `//${clusterId}.${location.host}`; -} - -export function getHostedClusterId() { - return getClusterIdFromHost(location.host); -} - -export function getHostedCluster(): Cluster { - return ClusterStore.getInstance().getById(getHostedClusterId()); -} diff --git a/src/common/cluster-types.ts b/src/common/cluster-types.ts new file mode 100644 index 0000000000..705110b895 --- /dev/null +++ b/src/common/cluster-types.ts @@ -0,0 +1,180 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * JSON serializable metadata type + */ +export type ClusterMetadata = Record; + +/** + * Metadata for cluster's prometheus settings + */ +export interface ClusterPrometheusMetadata { + success?: boolean; + provider?: string; + autoDetected?: boolean; +} + +/** + * A ClusterId is an opaque string + */ +export type ClusterId = string; + +/** + * The fields that are used for updating a cluster instance + */ +export type UpdateClusterModel = Omit; + +/** + * The model for passing cluster data around, including to disk + */ +export interface ClusterModel { + /** Unique id for a cluster */ + id: ClusterId; + + /** Path to cluster kubeconfig */ + kubeConfigPath: string; + + /** + * Workspace id + * + * @deprecated + */ + workspace?: string; + + /** + * @deprecated this is used only for hotbar migrations from 4.2.X + */ + workspaces?: string[]; + + /** User context in kubeconfig */ + contextName: string; + + /** Preferences */ + preferences?: ClusterPreferences; + + /** Metadata */ + metadata?: ClusterMetadata; + + /** List of accessible namespaces */ + accessibleNamespaces?: string[]; + + /** + * Labels for the catalog entity + */ + labels?: Record; +} + +/** + * The complete set of cluster settings or preferences + */ +export interface ClusterPreferences extends ClusterPrometheusPreferences { + terminalCWD?: string; + clusterName?: string; + iconOrder?: number; + icon?: string; + httpsProxy?: string; + hiddenMetrics?: string[]; + nodeShellImage?: string; + imagePullSecret?: string; +} + +/** + * A cluster's prometheus settings (a subset of cluster settings) + */ +export interface ClusterPrometheusPreferences { + prometheus?: { + namespace: string; + service: string; + port: number; + prefix: string; + }; + prometheusProvider?: { + type: string; + }; +} + +/** + * The options for the status of connection attempts to a cluster + */ +export enum ClusterStatus { + AccessGranted = 2, + AccessDenied = 1, + Offline = 0 +} + +/** + * The OpenLens known static metadata keys + */ +export enum ClusterMetadataKey { + VERSION = "version", + CLUSTER_ID = "id", + DISTRIBUTION = "distribution", + NODES_COUNT = "nodes", + LAST_SEEN = "lastSeen", + PROMETHEUS = "prometheus" +} + +/** + * A shorthand enum for resource types that have metrics attached to them via OpenLens metrics stack + */ +export enum ClusterMetricsResourceType { + Cluster = "Cluster", + Node = "Node", + Pod = "Pod", + Deployment = "Deployment", + StatefulSet = "StatefulSet", + Container = "Container", + Ingress = "Ingress", + VolumeClaim = "VolumeClaim", + ReplicaSet = "ReplicaSet", + DaemonSet = "DaemonSet", + Job = "Job", + Namespace = "Namespace", +} + +/** + * The default node shell image + */ +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 + */ +export interface ClusterState { + apiUrl: string; + online: boolean; + disconnected: boolean; + accessible: boolean; + ready: boolean; + failureReason: string; + isAdmin: boolean; + allowedNamespaces: string[] + allowedResources: string[] + isGlobalWatchEnabled: boolean; +} diff --git a/src/common/rbac.ts b/src/common/rbac.ts index 9d8242cd42..1562d1915a 100644 --- a/src/common/rbac.ts +++ b/src/common/rbac.ts @@ -19,7 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { getHostedCluster } from "./cluster-store"; +import { ClusterStore } from "./cluster-store"; +import { getHostedClusterId } from "./utils"; export type KubeResource = "namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | @@ -78,7 +79,7 @@ export function isAllowedResource(resources: KubeResource | KubeResource[]) { if (!Array.isArray(resources)) { resources = [resources]; } - const { allowedResources = [] } = getHostedCluster() || {}; + const { allowedResources = [] } = ClusterStore.getInstance().getById(getHostedClusterId()) || {}; for (const resource of resources) { if (!allowedResources.includes(resource)) { diff --git a/src/common/utils/__tests__/cluster-id-url-parsing.test.ts b/src/common/utils/__tests__/cluster-id-url-parsing.test.ts new file mode 100644 index 0000000000..7b65fb27fa --- /dev/null +++ b/src/common/utils/__tests__/cluster-id-url-parsing.test.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { getClusterIdFromHost } from "../cluster-id-url-parsing"; + +describe("getClusterIdFromHost", () => { + const clusterFakeId = "fe540901-0bd6-4f6c-b472-bce1559d7c4a"; + + it("should return undefined for non cluster frame hosts", () => { + expect(getClusterIdFromHost("localhost:45345")).toBeUndefined(); + }); + + it("should return ClusterId for cluster frame hosts", () => { + expect(getClusterIdFromHost(`${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + }); + + it("should return ClusterId for cluster frame hosts with additional subdomains", () => { + expect(getClusterIdFromHost(`abc.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + expect(getClusterIdFromHost(`abc.def.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + expect(getClusterIdFromHost(`abc.def.ghi.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + expect(getClusterIdFromHost(`abc.def.ghi.jkl.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.vwx.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + expect(getClusterIdFromHost(`abc.def.ghi.jkl.mno.pqr.stu.vwx.yz.${clusterFakeId}.localhost:59110`)).toBe(clusterFakeId); + }); +}); diff --git a/src/common/utils/cluster-id-url-parsing.ts b/src/common/utils/cluster-id-url-parsing.ts new file mode 100644 index 0000000000..e9517dce1d --- /dev/null +++ b/src/common/utils/cluster-id-url-parsing.ts @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import type { ClusterId } from "../cluster-types"; + +/** + * Grab the `ClusterId` out of a host that was generated by `getClusterFrameUrl`, or nothing + * @param host The host section of a URL + * @returns The `ClusterId` part of the host, or `undefined` + */ +export function getClusterIdFromHost(host: string): ClusterId | undefined { + // e.g host == "%clusterId.localhost:45345" + const subDomains = host.split(":")[0].split("."); + + return subDomains.slice(-2, -1)[0]; // ClusterId or undefined +} + +/** + * Get the OpenLens backend routing host for a given `ClusterId` + * @param clusterId The ID to put in front of the current host + * @returns a new URL host section + */ +export function getClusterFrameUrl(clusterId: ClusterId) { + return `//${clusterId}.${location.host}`; +} + +/** + * Get the result of `getClusterIdFromHost` from the current `location.host` + */ +export function getHostedClusterId(): ClusterId | undefined { + return getClusterIdFromHost(location.host); +} diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 1644c07f36..140ceaea2c 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -31,6 +31,7 @@ export * from "./autobind"; export * from "./base64"; export * from "./camelCase"; export * from "./cloneJson"; +export * from "./cluster-id-url-parsing"; export * from "./debouncePromise"; export * from "./defineGlobal"; export * from "./delay"; @@ -40,6 +41,7 @@ export * from "./escapeRegExp"; export * from "./extended-map"; export * from "./getRandId"; export * from "./hash-set"; +export * from "./local-kubeconfig"; export * from "./n-fircate"; export * from "./openExternal"; export * from "./paths"; @@ -51,6 +53,7 @@ export * from "./tar"; export * from "./toggle-set"; export * from "./toJS"; export * from "./type-narrowing"; +export * from "./types"; import * as iter from "./iter"; diff --git a/src/common/utils/local-kubeconfig.ts b/src/common/utils/local-kubeconfig.ts new file mode 100644 index 0000000000..04ab27bfa4 --- /dev/null +++ b/src/common/utils/local-kubeconfig.ts @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { app, remote } from "electron"; +import path from "path"; +import * as uuid from "uuid"; +import type { ClusterId } from "../cluster-types"; + +export function storedKubeConfigFolder(): string { + return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs"); +} + +export function getCustomKubeConfigPath(clusterId: ClusterId = uuid.v4()): string { + return path.resolve(storedKubeConfigFolder(), clusterId); +} diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts new file mode 100644 index 0000000000..9fa3c580b9 --- /dev/null +++ b/src/common/utils/types.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * An N length tuple of T + */ +export type Tuple = N extends N ? number extends N ? T[] : _TupleOf : never; +type _TupleOf = R["length"] extends N ? R : _TupleOf; diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index af69a6bef8..321ab80259 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -24,9 +24,9 @@ import { EventEmitter } from "events"; import { isEqual } from "lodash"; import { action, computed, makeObservable, observable, observe, reaction, when } from "mobx"; import path from "path"; -import { getHostedCluster } from "../common/cluster-store"; +import { ClusterStore } from "../common/cluster-store"; import { broadcastMessage, ipcMainOn, ipcRendererOn, requestMain, ipcMainHandle } from "../common/ipc"; -import { Disposer, Singleton, toJS } from "../common/utils"; +import { Disposer, getHostedClusterId, Singleton, toJS } from "../common/utils"; import logger from "../main/logger"; import type { InstalledExtension } from "./extension-discovery"; import { ExtensionsStore } from "./extensions-store"; @@ -296,7 +296,7 @@ export class ExtensionLoader extends Singleton { loadOnClusterRenderer() { logger.debug(`${logModule}: load on cluster renderer (dashboard)`); - const cluster = getHostedCluster(); + const cluster = ClusterStore.getInstance().getById(getHostedClusterId()); this.autoInitExtensions(async (extension: LensRendererExtension) => { if ((await extension.isEnabledForCluster(cluster)) === false) { diff --git a/src/main/catalog-sources/kubeconfig-sync.ts b/src/main/catalog-sources/kubeconfig-sync.ts index 8e3c3b1cf7..8a628e97e6 100644 --- a/src/main/catalog-sources/kubeconfig-sync.ts +++ b/src/main/catalog-sources/kubeconfig-sync.ts @@ -27,18 +27,19 @@ import fs from "fs"; import path from "path"; import fse from "fs-extra"; import type stream from "stream"; -import { Disposer, ExtendedObservableMap, iter, Singleton } from "../../common/utils"; +import { Disposer, ExtendedObservableMap, iter, Singleton, storedKubeConfigFolder } from "../../common/utils"; import logger from "../logger"; import type { KubeConfig } from "@kubernetes/client-node"; import { loadConfigFromString, splitConfig } from "../../common/kube-helpers"; import { Cluster } from "../cluster"; import { catalogEntityFromCluster, ClusterManager } from "../cluster-manager"; import { UserStore } from "../../common/user-store"; -import { ClusterStore, UpdateClusterModel } from "../../common/cluster-store"; +import { ClusterStore } from "../../common/cluster-store"; import { createHash } from "crypto"; import { homedir } from "os"; import globToRegExp from "glob-to-regexp"; import { inspect } from "util"; +import type { UpdateClusterModel } from "../../common/cluster-types"; const logPrefix = "[KUBECONFIG-SYNC]:"; @@ -85,7 +86,7 @@ export class KubeconfigSyncManager extends Singleton { ))); // This must be done so that c&p-ed clusters are visible - this.startNewSync(ClusterStore.storedKubeConfigFolder); + this.startNewSync(storedKubeConfigFolder()); for (const filePath of UserStore.getInstance().syncKubeconfigEntries.keys()) { this.startNewSync(filePath); @@ -216,7 +217,7 @@ export function computeDiff(contents: string, source: RootSource, filePath: stri const entity = catalogEntityFromCluster(cluster); - if (!filePath.startsWith(ClusterStore.storedKubeConfigFolder)) { + if (!filePath.startsWith(storedKubeConfigFolder())) { entity.metadata.labels.file = filePath.replace(homedir(), "~"); } source.set(contextName, [cluster, entity]); diff --git a/src/main/cluster-detectors/cluster-id-detector.ts b/src/main/cluster-detectors/cluster-id-detector.ts index 9818b0d990..21d7a005b3 100644 --- a/src/main/cluster-detectors/cluster-id-detector.ts +++ b/src/main/cluster-detectors/cluster-id-detector.ts @@ -21,7 +21,7 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { createHash } from "crypto"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class ClusterIdDetector extends BaseClusterDetector { key = ClusterMetadataKey.CLUSTER_ID; diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index 82a09059e3..40b4fa6949 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -20,7 +20,7 @@ */ import { observable } from "mobx"; -import type { ClusterMetadata } from "../../common/cluster-store"; +import type { ClusterMetadata } from "../../common/cluster-types"; import type { Cluster } from "../cluster"; import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector"; import { ClusterIdDetector } from "./cluster-id-detector"; diff --git a/src/main/cluster-detectors/distribution-detector.ts b/src/main/cluster-detectors/distribution-detector.ts index c7f2791cee..0deb598b39 100644 --- a/src/main/cluster-detectors/distribution-detector.ts +++ b/src/main/cluster-detectors/distribution-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class DistributionDetector extends BaseClusterDetector { key = ClusterMetadataKey.DISTRIBUTION; @@ -60,7 +60,7 @@ export class DistributionDetector extends BaseClusterDetector { if (this.isK0s()) { return { value: "k0s", accuracy: 80}; } - + if (this.isVMWare()) { return { value: "vmware", accuracy: 90}; } @@ -179,7 +179,7 @@ export class DistributionDetector extends BaseClusterDetector { protected isK0s() { return this.version.includes("-k0s"); } - + protected isAlibaba() { return this.version.includes("-aliyun"); } diff --git a/src/main/cluster-detectors/last-seen-detector.ts b/src/main/cluster-detectors/last-seen-detector.ts index 537fef96cb..2aed3d0640 100644 --- a/src/main/cluster-detectors/last-seen-detector.ts +++ b/src/main/cluster-detectors/last-seen-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class LastSeenDetector extends BaseClusterDetector { key = ClusterMetadataKey.LAST_SEEN; diff --git a/src/main/cluster-detectors/nodes-count-detector.ts b/src/main/cluster-detectors/nodes-count-detector.ts index f30f5e6c70..2cb224b46a 100644 --- a/src/main/cluster-detectors/nodes-count-detector.ts +++ b/src/main/cluster-detectors/nodes-count-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class NodesCountDetector extends BaseClusterDetector { key = ClusterMetadataKey.NODES_COUNT; diff --git a/src/main/cluster-detectors/version-detector.ts b/src/main/cluster-detectors/version-detector.ts index f7240ab3ea..36d7e06dd1 100644 --- a/src/main/cluster-detectors/version-detector.ts +++ b/src/main/cluster-detectors/version-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class VersionDetector extends BaseClusterDetector { key = ClusterMetadataKey.VERSION; diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 5338bbad14..fdc3bf3e1a 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -22,15 +22,16 @@ import "../common/cluster-ipc"; import type http from "http"; import { action, autorun, makeObservable, observable, observe, reaction, toJS } from "mobx"; -import { ClusterId, ClusterStore, getClusterIdFromHost } from "../common/cluster-store"; import { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; -import { Singleton } from "../common/utils"; +import { getClusterIdFromHost, Singleton } from "../common/utils"; import { catalogEntityRegistry } from "./catalog"; import { KubernetesCluster, KubernetesClusterPrometheusMetrics, KubernetesClusterStatusPhase } from "../common/catalog-entities/kubernetes-cluster"; import { ipcMainOn } from "../common/ipc"; import { once } from "lodash"; +import { ClusterStore } from "../common/cluster-store"; +import type { ClusterId } from "../common/cluster-types"; const logPrefix = "[CLUSTER-MANAGER]:"; diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 6d3331c447..bd09c1fad4 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -20,7 +20,6 @@ */ import { ipcMain } from "electron"; -import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-store"; import { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx"; import { broadcastMessage, ClusterListNamespaceForbiddenChannel } from "../common/ipc"; import { ContextHandler } from "./context-handler"; @@ -34,54 +33,7 @@ import { VersionDetector } from "./cluster-detectors/version-detector"; import { detectorRegistry } from "./cluster-detectors/detector-registry"; import plimit from "p-limit"; import { toJS } from "../common/utils"; -import { initialNodeShellImage } from "../common/cluster-store"; - -export enum ClusterStatus { - AccessGranted = 2, - AccessDenied = 1, - Offline = 0 -} - -export enum ClusterMetadataKey { - VERSION = "version", - CLUSTER_ID = "id", - DISTRIBUTION = "distribution", - NODES_COUNT = "nodes", - LAST_SEEN = "lastSeen", - PROMETHEUS = "prometheus" -} - -export enum ClusterMetricsResourceType { - Cluster = "Cluster", - Node = "Node", - Pod = "Pod", - Deployment = "Deployment", - StatefulSet = "StatefulSet", - Container = "Container", - Ingress = "Ingress", - VolumeClaim = "VolumeClaim", - ReplicaSet = "ReplicaSet", - DaemonSet = "DaemonSet", - Job = "Job", - Namespace = "Namespace" -} - -export type ClusterRefreshOptions = { - refreshMetadata?: boolean -}; - -export interface ClusterState { - apiUrl: string; - online: boolean; - disconnected: boolean; - accessible: boolean; - ready: boolean; - failureReason: string; - isAdmin: boolean; - allowedNamespaces: string[] - allowedResources: string[] - isGlobalWatchEnabled: boolean; -} +import { initialNodeShellImage, ClusterState, ClusterMetadataKey, ClusterRefreshOptions, ClusterStatus, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-types"; /** * Cluster diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index 7e09d29f5c..82c365e821 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -21,7 +21,7 @@ import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"; import { PrometheusProviderRegistry } from "./prometheus/provider-registry"; -import type { ClusterPrometheusPreferences } from "../common/cluster-store"; +import type { ClusterPrometheusPreferences } from "../common/cluster-types"; import type { Cluster } from "./cluster"; import type httpProxy from "http-proxy"; import url, { UrlWithStringQuery } from "url"; diff --git a/src/main/initializers/ipc.ts b/src/main/initializers/ipc.ts index 3614c602d7..efcd52a5a4 100644 --- a/src/main/initializers/ipc.ts +++ b/src/main/initializers/ipc.ts @@ -23,7 +23,8 @@ import type { IpcMainInvokeEvent } from "electron"; import { KubernetesCluster } from "../../common/catalog-entities"; import { clusterFrameMap } from "../../common/cluster-frames"; import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler, clusterDeleteHandler } from "../../common/cluster-ipc"; -import { ClusterId, ClusterStore } from "../../common/cluster-store"; +import { ClusterStore } from "../../common/cluster-store"; +import type { ClusterId } from "../../common/cluster-types"; import { appEventBus } from "../../common/event-bus"; import { ipcMainHandle } from "../../common/ipc"; import { catalogEntityRegistry } from "../catalog"; diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index c309b42ccf..2b8aa0f921 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -22,8 +22,8 @@ import _ from "lodash"; import type { LensApiRequest } from "../router"; import { respondJson } from "../utils/http-responses"; -import { Cluster, ClusterMetadataKey } from "../cluster"; -import type { ClusterPrometheusMetadata } from "../../common/cluster-store"; +import type { Cluster } from "../cluster"; +import { ClusterMetadataKey, ClusterPrometheusMetadata } from "../../common/cluster-types"; import logger from "../logger"; import { getMetrics } from "../k8s-request"; import { PrometheusProviderRegistry } from "../prometheus"; diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 9a56aaafb8..d1b0f5da2a 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { ClusterId } from "../common/cluster-store"; +import type { ClusterId } from "../common/cluster-types"; import { makeObservable, observable } from "mobx"; import { app, BrowserWindow, dialog, ipcMain, shell, webContents } from "electron"; import windowStateKeeper from "electron-window-state"; diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index 2599005332..7ef4b042ec 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -25,9 +25,10 @@ import path from "path"; import { app } from "electron"; import fse from "fs-extra"; -import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { loadConfigFromFileSync } from "../../common/kube-helpers"; import { MigrationDeclaration, migrationLog } from "../helpers"; +import type { ClusterModel } from "../../common/cluster-types"; +import { getCustomKubeConfigPath, storedKubeConfigFolder } from "../../common/utils"; interface Pre360ClusterModel extends ClusterModel { kubeConfig: string; @@ -40,7 +41,7 @@ export default { const storedClusters: Pre360ClusterModel[] = store.get("clusters") ?? []; const migratedClusters: ClusterModel[] = []; - fse.ensureDirSync(ClusterStore.storedKubeConfigFolder); + fse.ensureDirSync(storedKubeConfigFolder()); migrationLog("Number of clusters to migrate: ", storedClusters.length); @@ -49,7 +50,7 @@ export default { * migrate kubeconfig */ try { - const absPath = ClusterStore.getCustomKubeConfigPath(clusterModel.id); + const absPath = getCustomKubeConfigPath(clusterModel.id); // take the embedded kubeconfig and dump it into a file fse.writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 }); diff --git a/src/migrations/cluster-store/5.0.0-beta.10.ts b/src/migrations/cluster-store/5.0.0-beta.10.ts index 4b7fa9f3bd..a26f0ed662 100644 --- a/src/migrations/cluster-store/5.0.0-beta.10.ts +++ b/src/migrations/cluster-store/5.0.0-beta.10.ts @@ -22,7 +22,7 @@ import path from "path"; import { app } from "electron"; import fse from "fs-extra"; -import type { ClusterModel } from "../../common/cluster-store"; +import type { ClusterModel } from "../../common/cluster-types"; import type { MigrationDeclaration } from "../helpers"; interface Pre500WorkspaceStoreModel { diff --git a/src/migrations/cluster-store/5.0.0-beta.13.ts b/src/migrations/cluster-store/5.0.0-beta.13.ts index e6f260db1b..6c8f37e366 100644 --- a/src/migrations/cluster-store/5.0.0-beta.13.ts +++ b/src/migrations/cluster-store/5.0.0-beta.13.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { ClusterModel, ClusterPreferences, ClusterPrometheusPreferences } from "../../common/cluster-store"; +import type { ClusterModel, ClusterPreferences, ClusterPrometheusPreferences } from "../../common/cluster-types"; import { MigrationDeclaration, migrationLog } from "../helpers"; import { generateNewIdFor } from "../utils"; import path from "path"; diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index c1c5eb2dc5..965d03ee5a 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -21,7 +21,7 @@ // Fix embedded kubeconfig paths under snap config -import type { ClusterModel } from "../../common/cluster-store"; +import type { ClusterModel } from "../../common/cluster-types"; import { getAppVersion } from "../../common/utils/app-version"; import fs from "fs"; import { MigrationDeclaration, migrationLog } from "../helpers"; diff --git a/src/migrations/user-store/5.0.3-beta.1.ts b/src/migrations/user-store/5.0.3-beta.1.ts index ef3448116d..728cf6a395 100644 --- a/src/migrations/user-store/5.0.3-beta.1.ts +++ b/src/migrations/user-store/5.0.3-beta.1.ts @@ -23,10 +23,10 @@ import { app } from "electron"; import { existsSync, readFileSync } from "fs"; import path from "path"; import os from "os"; -import { ClusterStore, ClusterStoreModel } from "../../common/cluster-store"; +import type { ClusterStoreModel } from "../../common/cluster-store"; import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../common/user-store"; import { MigrationDeclaration, migrationLog } from "../helpers"; -import { isLogicalChildPath } from "../../common/utils"; +import { isLogicalChildPath, storedKubeConfigFolder } from "../../common/utils"; export default { version: "5.0.3-beta.1", @@ -42,8 +42,8 @@ export default { for (const cluster of clusters) { const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath); - if (dirOfKubeconfig === ClusterStore.storedKubeConfigFolder) { - migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under ClusterStore.storedKubeConfigFolder`); + if (dirOfKubeconfig === storedKubeConfigFolder()) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under the stored KubeConfig folder`); continue; } diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 7ee8529492..5e59767081 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -30,12 +30,11 @@ import path from "path"; import React from "react"; import { catalogURL } from "../../../common/routes"; -import { ClusterStore } from "../../../common/cluster-store"; import { appEventBus } from "../../../common/event-bus"; import { loadConfigFromString, splitConfig } from "../../../common/kube-helpers"; import { docsUrl } from "../../../common/vars"; import { navigate } from "../../navigation"; -import { iter } from "../../utils"; +import { getCustomKubeConfigPath, iter } from "../../utils"; import { AceEditor } from "../ace-editor"; import { Button } from "../button"; import { Notifications } from "../notifications"; @@ -93,7 +92,7 @@ export class AddCluster extends React.Component { appEventBus.emit({ name: "cluster-add", action: "click" }); try { - const absPath = ClusterStore.getCustomKubeConfigPath(); + const absPath = getCustomKubeConfigPath(); await fse.ensureDir(path.dirname(absPath)); await fse.writeFile(absPath, this.customConfig.trim(), { encoding: "utf-8", mode: 0o600 }); diff --git a/src/renderer/components/+cluster/cluster-overview.tsx b/src/renderer/components/+cluster/cluster-overview.tsx index 8149f614ff..e68c2f752f 100644 --- a/src/renderer/components/+cluster/cluster-overview.tsx +++ b/src/renderer/components/+cluster/cluster-overview.tsx @@ -26,8 +26,7 @@ import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { nodesStore } from "../+nodes/nodes.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import { getHostedCluster } from "../../../common/cluster-store"; -import { interval } from "../../utils"; +import { getHostedClusterId, interval } from "../../utils"; import { TabLayout } from "../layout/tab-layout"; import { Spinner } from "../spinner"; import { ClusterIssues } from "./cluster-issues"; @@ -35,14 +34,19 @@ import { ClusterMetrics } from "./cluster-metrics"; import { clusterOverviewStore } from "./cluster-overview.store"; import { ClusterPieCharts } from "./cluster-pie-charts"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; +import { ClusterStore } from "../../../common/cluster-store"; @observer export class ClusterOverview extends React.Component { private metricPoller = interval(60, () => this.loadMetrics()); loadMetrics() { - getHostedCluster().available && clusterOverviewStore.loadMetrics(); + const cluster = ClusterStore.getInstance().getById(getHostedClusterId()); + + if (cluster.available) { + clusterOverviewStore.loadMetrics(); + } } componentDidMount() { diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index ee051977e5..ff997fe335 100644 --- a/src/renderer/components/+namespaces/namespace-details.tsx +++ b/src/renderer/components/+namespaces/namespace-details.tsx @@ -35,7 +35,7 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { limitRangeStore } from "../+config-limit-ranges/limit-ranges.store"; import { ResourceMetrics } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+network-ingresses/ingress-details.tsx b/src/renderer/components/+network-ingresses/ingress-details.tsx index 995e4d3b0f..97303ad679 100644 --- a/src/renderer/components/+network-ingresses/ingress-details.tsx +++ b/src/renderer/components/+network-ingresses/ingress-details.tsx @@ -33,7 +33,7 @@ import { IngressCharts } from "./ingress-charts"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { getBackendServiceNamePort, getMetricsForIngress, IIngressMetrics } from "../../api/endpoints/ingress.api"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index 56ce3e53e2..96e4eea4ca 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -36,7 +36,7 @@ import { makeObservable, observable, reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { NodeDetailsResources } from "./node-details-resources"; import { DrawerTitle } from "../drawer/drawer-title"; import { boundMethod } from "../../utils"; diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx index 372d6bfb6e..36d85b0488 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx @@ -33,7 +33,7 @@ import { VolumeClaimDiskChart } from "./volume-claim-disk-chart"; import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-object"; import { getMetricsForPvc, IPvcMetrics, PersistentVolumeClaim } from "../../api/endpoints"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx index 4479995506..e572ca5ab2 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx @@ -38,7 +38,7 @@ import { makeObservable, observable, reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { boundMethod } from "../../utils"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index 110c9a5679..6797df5ce1 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -40,7 +40,7 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; import { DeploymentReplicaSets } from "./deployment-replicasets"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { boundMethod } from "../../utils"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+workloads-jobs/job-details.tsx b/src/renderer/components/+workloads-jobs/job-details.tsx index b0ba055122..bdaa4650de 100644 --- a/src/renderer/components/+workloads-jobs/job-details.tsx +++ b/src/renderer/components/+workloads-jobs/job-details.tsx @@ -39,7 +39,7 @@ import { lookupApiLink } from "../../api/kube-api"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { makeObservable, observable } from "mobx"; import { podMetricTabs, PodCharts } from "../+workloads-pods/pod-charts"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { ResourceMetrics } from "../resource-metrics"; import { boundMethod } from "autobind-decorator"; diff --git a/src/renderer/components/+workloads-pods/pod-details-container.tsx b/src/renderer/components/+workloads-pods/pod-details-container.tsx index a6aeae0593..5ae7625fb0 100644 --- a/src/renderer/components/+workloads-pods/pod-details-container.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-container.tsx @@ -34,7 +34,7 @@ import type { IMetrics } from "../../api/endpoints/metrics.api"; import { ContainerCharts } from "./container-charts"; import { LocaleDate } from "../locale-date"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; interface Props { pod: Pod; diff --git a/src/renderer/components/+workloads-pods/pod-details.tsx b/src/renderer/components/+workloads-pods/pod-details.tsx index 6249288b77..3087cc8257 100644 --- a/src/renderer/components/+workloads-pods/pod-details.tsx +++ b/src/renderer/components/+workloads-pods/pod-details.tsx @@ -41,7 +41,7 @@ import { getItemMetrics } from "../../api/endpoints/metrics.api"; import { PodCharts, podMetricTabs } from "./pod-charts"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; interface Props extends KubeObjectDetailsProps { } diff --git a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx index 7c06b56840..2f84976db5 100644 --- a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx +++ b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx @@ -37,7 +37,7 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { boundMethod } from "../../utils"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx index f16578c703..0dac7c8a08 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx @@ -38,7 +38,7 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; -import { ClusterMetricsResourceType } from "../../../main/cluster"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; import { boundMethod } from "../../utils"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 52c9d5d0c3..b9c56f475e 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -32,7 +32,6 @@ import { DeploymentScaleDialog } from "./+workloads-deployments/deployment-scale import { CronJobTriggerDialog } from "./+workloads-cronjobs/cronjob-trigger-dialog"; import { CustomResources } from "./+custom-resources/custom-resources"; import { isAllowedResource } from "../../common/rbac"; -import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store"; import logger from "../../main/logger"; import { webFrame } from "electron"; import { ClusterPageRegistry, getExtensionPageUrl } from "../../extensions/registries/page-registry"; @@ -70,9 +69,14 @@ import { Workloads } from "./+workloads"; import { Config } from "./+config"; import { Storage } from "./+storage"; import { catalogEntityRegistry } from "../api/catalog-entity-registry"; +import { getHostedClusterId } from "../utils"; +import { ClusterStore } from "../../common/cluster-store"; +import type { ClusterId } from "../../common/cluster-types"; @observer export class App extends React.Component { + static clusterId: ClusterId; + constructor(props: {}) { super(props); makeObservable(this); @@ -81,15 +85,18 @@ export class App extends React.Component { static async init() { catalogEntityRegistry.init(); const frameId = webFrame.routingId; - const clusterId = getHostedClusterId(); - logger.info(`[APP]: Init dashboard, clusterId=${clusterId}, frameId=${frameId}`); + App.clusterId = getHostedClusterId(); + + logger.info(`[APP]: Init dashboard, clusterId=${App.clusterId}, frameId=${frameId}`); await Terminal.preloadFonts(); + await requestMain(clusterSetFrameIdHandler, App.clusterId); - await requestMain(clusterSetFrameIdHandler, clusterId); - await getHostedCluster().whenReady; // cluster.activate() is done at this point + const cluster = ClusterStore.getInstance().getById(App.clusterId); - const activeEntityDisposer = reaction(() => catalogEntityRegistry.getById(clusterId), (entity) => { + await cluster.whenReady; // cluster.activate() is done at this point + + const activeEntityDisposer = reaction(() => catalogEntityRegistry.getById(App.clusterId), (entity) => { if (!entity) { return; } @@ -103,7 +110,7 @@ export class App extends React.Component { name: "cluster", action: "open", params: { - clusterId + clusterId: App.clusterId } }); }); @@ -212,7 +219,7 @@ export class App extends React.Component { - + ); diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 366a809b59..acd6a8a51d 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -26,7 +26,7 @@ import { computed, observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import React from "react"; import { clusterActivateHandler } from "../../../common/cluster-ipc"; -import { ClusterId, ClusterStore } from "../../../common/cluster-store"; +import { ClusterStore } from "../../../common/cluster-store"; import { ipcRendererOn, requestMain } from "../../../common/ipc"; import type { Cluster } from "../../../main/cluster"; import { cssNames, IClassName } from "../../utils"; @@ -36,6 +36,7 @@ import { Spinner } from "../spinner"; import type { KubeAuthProxyLog } from "../../../main/kube-auth-proxy"; import { navigate } from "../../navigation"; import { entitySettingsURL } from "../../../common/routes"; +import type { ClusterId } from "../../../common/cluster-types"; interface Props { className?: IClassName; diff --git a/src/renderer/components/cluster-manager/lens-views.ts b/src/renderer/components/cluster-manager/lens-views.ts index ace85eed6e..3fcce1ed6f 100644 --- a/src/renderer/components/cluster-manager/lens-views.ts +++ b/src/renderer/components/cluster-manager/lens-views.ts @@ -20,10 +20,12 @@ */ import { observable, when } from "mobx"; -import { ClusterId, ClusterStore, getClusterFrameUrl } from "../../../common/cluster-store"; import logger from "../../../main/logger"; import { requestMain } from "../../../common/ipc"; import { clusterVisibilityHandler } from "../../../common/cluster-ipc"; +import { ClusterStore } from "../../../common/cluster-store"; +import type { ClusterId } from "../../../common/cluster-types"; +import { getClusterFrameUrl } from "../../utils"; export interface LensView { isLoaded?: boolean diff --git a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx index 8cce59bbe8..571886364a 100644 --- a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx @@ -25,8 +25,9 @@ import { Select, SelectOption } from "../../select/select"; import { Icon } from "../../icon/icon"; import { Button } from "../../button/button"; import { SubTitle } from "../../layout/sub-title"; -import { Cluster, ClusterMetricsResourceType } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { observable, reaction, makeObservable } from "mobx"; +import { ClusterMetricsResourceType } from "../../../../common/cluster-types"; interface Props { cluster: Cluster; diff --git a/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx index a5b4300fe3..1fb101a15c 100644 --- a/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx @@ -26,7 +26,7 @@ import React from "react"; import { Input } from "../../input/input"; import { disposeOnUnmount, observer } from "mobx-react"; import { Icon } from "../../icon/icon"; -import { initialNodeShellImage } from "../../../../common/cluster-store"; +import { initialNodeShellImage } from "../../../../common/cluster-types"; interface Props { cluster: Cluster; diff --git a/src/renderer/components/command-palette/command-container.tsx b/src/renderer/components/command-palette/command-container.tsx index b95d177891..f90586fd5a 100644 --- a/src/renderer/components/command-palette/command-container.tsx +++ b/src/renderer/components/command-palette/command-container.tsx @@ -28,7 +28,7 @@ import { Dialog } from "../dialog"; import { EventEmitter } from "../../../common/event-emitter"; import { ipcRendererOn } from "../../../common/ipc"; import { CommandDialog } from "./command-dialog"; -import type { ClusterId } from "../../../common/cluster-store"; +import type { ClusterId } from "../../../common/cluster-types"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { CommandRegistration, CommandRegistry } from "../../../extensions/registries/command-registry"; diff --git a/src/renderer/components/context.ts b/src/renderer/components/context.ts index f62b904f6e..758e3dd20d 100755 --- a/src/renderer/components/context.ts +++ b/src/renderer/components/context.ts @@ -19,8 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import { ClusterStore } from "../../common/cluster-store"; import type { Cluster } from "../../main/cluster"; -import { getHostedCluster } from "../../common/cluster-store"; +import { getHostedClusterId } from "../utils"; import { namespaceStore } from "./+namespaces/namespace.store"; export interface ClusterContext { @@ -31,7 +32,7 @@ export interface ClusterContext { export const clusterContext: ClusterContext = { get cluster(): Cluster | null { - return getHostedCluster(); + return ClusterStore.getInstance().getById(getHostedClusterId()); }, get allNamespaces(): string[] { diff --git a/src/renderer/utils/createStorage.ts b/src/renderer/utils/createStorage.ts index 0e1452ac80..3636180c35 100755 --- a/src/renderer/utils/createStorage.ts +++ b/src/renderer/utils/createStorage.ts @@ -26,8 +26,9 @@ import { app, remote } from "electron"; import { comparer, observable, reaction, toJS, when } from "mobx"; import fse from "fs-extra"; import { StorageHelper } from "./storageHelper"; -import { ClusterStore, getHostedClusterId } from "../../common/cluster-store"; +import { ClusterStore } from "../../common/cluster-store"; import logger from "../../main/logger"; +import { getHostedClusterId } from "../../common/utils"; const storage = observable({ initialized: false,