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

Move cluster related types and function into seperate files (#3530)

This commit is contained in:
Sebastian Malton 2021-08-03 10:36:14 -04:00 committed by GitHub
parent 2893ad956d
commit a6e91fc34a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 435 additions and 258 deletions

View File

@ -25,9 +25,11 @@ import yaml from "js-yaml";
import path from "path"; import path from "path";
import fse from "fs-extra"; import fse from "fs-extra";
import { Cluster } from "../../main/cluster"; import { Cluster } from "../../main/cluster";
import { ClusterId, ClusterStore, getClusterIdFromHost } from "../cluster-store"; import { ClusterStore } from "../cluster-store";
import { Console } from "console"; import { Console } from "console";
import { stdout, stderr } from "process"; import { stdout, stderr } from "process";
import type { ClusterId } from "../cluster-types";
import { getCustomKubeConfigPath } from "../utils";
console = new Console(stdout, stderr); console = new Console(stdout, stderr);
@ -57,7 +59,7 @@ users:
`; `;
function embed(clusterId: ClusterId, contents: any): string { function embed(clusterId: ClusterId, contents: any): string {
const absPath = ClusterStore.getCustomKubeConfigPath(clusterId); const absPath = getCustomKubeConfigPath(clusterId);
fse.ensureDirSync(path.dirname(absPath)); fse.ensureDirSync(path.dirname(absPath));
fse.writeFileSync(absPath, contents, { encoding: "utf-8", mode: 0o600 }); 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); 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);
});
});

View File

@ -19,119 +19,26 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
import path from "path"; import { ipcMain, ipcRenderer, webFrame } from "electron";
import { app, ipcMain, ipcRenderer, remote, webFrame } from "electron";
import { action, comparer, computed, makeObservable, observable, reaction } from "mobx"; import { action, comparer, computed, makeObservable, observable, reaction } from "mobx";
import { BaseStore } from "./base-store"; import { BaseStore } from "./base-store";
import { Cluster, ClusterState } from "../main/cluster"; import { Cluster } from "../main/cluster";
import migrations from "../migrations/cluster-store"; import migrations from "../migrations/cluster-store";
import * as uuid from "uuid";
import logger from "../main/logger"; import logger from "../main/logger";
import { appEventBus } from "./event-bus"; import { appEventBus } from "./event-bus";
import { ipcMainHandle, ipcMainOn, ipcRendererOn, requestMain } from "./ipc"; import { ipcMainHandle, ipcMainOn, ipcRendererOn, requestMain } from "./ipc";
import { disposer, toJS } from "./utils"; import { disposer, toJS } from "./utils";
import type { ClusterModel, ClusterId, ClusterState } from "./cluster-types";
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;
};
export interface ClusterStoreModel { export interface ClusterStoreModel {
clusters?: ClusterModel[]; clusters?: ClusterModel[];
} }
export type ClusterId = string;
export interface UpdateClusterModel extends Omit<ClusterModel, "id"> {
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<string, string>;
/** 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"; const initialStates = "cluster:states";
export const initialNodeShellImage = "docker.io/alpine:3.13";
export class ClusterStore extends BaseStore<ClusterStoreModel> { export class ClusterStore extends BaseStore<ClusterStoreModel> {
private static StateChannel = "cluster:state"; 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<ClusterId, Cluster>(); clusters = observable.map<ClusterId, Cluster>();
removedClusters = observable.map<ClusterId, Cluster>(); removedClusters = observable.map<ClusterId, Cluster>();
@ -272,22 +179,3 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
}); });
} }
} }
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());
}

180
src/common/cluster-types.ts Normal file
View File

@ -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<string, string | number | boolean | object>;
/**
* 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<ClusterModel, "id">;
/**
* 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<string, string>;
}
/**
* 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;
}

View File

@ -19,7 +19,8 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 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 = export type KubeResource =
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" |
@ -78,7 +79,7 @@ export function isAllowedResource(resources: KubeResource | KubeResource[]) {
if (!Array.isArray(resources)) { if (!Array.isArray(resources)) {
resources = [resources]; resources = [resources];
} }
const { allowedResources = [] } = getHostedCluster() || {}; const { allowedResources = [] } = ClusterStore.getInstance().getById(getHostedClusterId()) || {};
for (const resource of resources) { for (const resource of resources) {
if (!allowedResources.includes(resource)) { if (!allowedResources.includes(resource)) {

View File

@ -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);
});
});

View File

@ -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);
}

View File

@ -31,6 +31,7 @@ export * from "./autobind";
export * from "./base64"; export * from "./base64";
export * from "./camelCase"; export * from "./camelCase";
export * from "./cloneJson"; export * from "./cloneJson";
export * from "./cluster-id-url-parsing";
export * from "./debouncePromise"; export * from "./debouncePromise";
export * from "./defineGlobal"; export * from "./defineGlobal";
export * from "./delay"; export * from "./delay";
@ -40,6 +41,7 @@ export * from "./escapeRegExp";
export * from "./extended-map"; export * from "./extended-map";
export * from "./getRandId"; export * from "./getRandId";
export * from "./hash-set"; export * from "./hash-set";
export * from "./local-kubeconfig";
export * from "./n-fircate"; export * from "./n-fircate";
export * from "./openExternal"; export * from "./openExternal";
export * from "./paths"; export * from "./paths";
@ -51,6 +53,7 @@ export * from "./tar";
export * from "./toggle-set"; export * from "./toggle-set";
export * from "./toJS"; export * from "./toJS";
export * from "./type-narrowing"; export * from "./type-narrowing";
export * from "./types";
import * as iter from "./iter"; import * as iter from "./iter";

View File

@ -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);
}

26
src/common/utils/types.ts Normal file
View File

@ -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<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
type _TupleOf<T, N extends number, R extends unknown[]> = R["length"] extends N ? R : _TupleOf<T, N, [T, ...R]>;

View File

@ -24,9 +24,9 @@ import { EventEmitter } from "events";
import { isEqual } from "lodash"; import { isEqual } from "lodash";
import { action, computed, makeObservable, observable, observe, reaction, when } from "mobx"; import { action, computed, makeObservable, observable, observe, reaction, when } from "mobx";
import path from "path"; 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 { 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 logger from "../main/logger";
import type { InstalledExtension } from "./extension-discovery"; import type { InstalledExtension } from "./extension-discovery";
import { ExtensionsStore } from "./extensions-store"; import { ExtensionsStore } from "./extensions-store";
@ -296,7 +296,7 @@ export class ExtensionLoader extends Singleton {
loadOnClusterRenderer() { loadOnClusterRenderer() {
logger.debug(`${logModule}: load on cluster renderer (dashboard)`); logger.debug(`${logModule}: load on cluster renderer (dashboard)`);
const cluster = getHostedCluster(); const cluster = ClusterStore.getInstance().getById(getHostedClusterId());
this.autoInitExtensions(async (extension: LensRendererExtension) => { this.autoInitExtensions(async (extension: LensRendererExtension) => {
if ((await extension.isEnabledForCluster(cluster)) === false) { if ((await extension.isEnabledForCluster(cluster)) === false) {

View File

@ -27,18 +27,19 @@ import fs from "fs";
import path from "path"; import path from "path";
import fse from "fs-extra"; import fse from "fs-extra";
import type stream from "stream"; 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 logger from "../logger";
import type { KubeConfig } from "@kubernetes/client-node"; import type { KubeConfig } from "@kubernetes/client-node";
import { loadConfigFromString, splitConfig } from "../../common/kube-helpers"; import { loadConfigFromString, splitConfig } from "../../common/kube-helpers";
import { Cluster } from "../cluster"; import { Cluster } from "../cluster";
import { catalogEntityFromCluster, ClusterManager } from "../cluster-manager"; import { catalogEntityFromCluster, ClusterManager } from "../cluster-manager";
import { UserStore } from "../../common/user-store"; import { UserStore } from "../../common/user-store";
import { ClusterStore, UpdateClusterModel } from "../../common/cluster-store"; import { ClusterStore } from "../../common/cluster-store";
import { createHash } from "crypto"; import { createHash } from "crypto";
import { homedir } from "os"; import { homedir } from "os";
import globToRegExp from "glob-to-regexp"; import globToRegExp from "glob-to-regexp";
import { inspect } from "util"; import { inspect } from "util";
import type { UpdateClusterModel } from "../../common/cluster-types";
const logPrefix = "[KUBECONFIG-SYNC]:"; 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 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()) { for (const filePath of UserStore.getInstance().syncKubeconfigEntries.keys()) {
this.startNewSync(filePath); this.startNewSync(filePath);
@ -216,7 +217,7 @@ export function computeDiff(contents: string, source: RootSource, filePath: stri
const entity = catalogEntityFromCluster(cluster); const entity = catalogEntityFromCluster(cluster);
if (!filePath.startsWith(ClusterStore.storedKubeConfigFolder)) { if (!filePath.startsWith(storedKubeConfigFolder())) {
entity.metadata.labels.file = filePath.replace(homedir(), "~"); entity.metadata.labels.file = filePath.replace(homedir(), "~");
} }
source.set(contextName, [cluster, entity]); source.set(contextName, [cluster, entity]);

View File

@ -21,7 +21,7 @@
import { BaseClusterDetector } from "./base-cluster-detector"; import { BaseClusterDetector } from "./base-cluster-detector";
import { createHash } from "crypto"; import { createHash } from "crypto";
import { ClusterMetadataKey } from "../cluster"; import { ClusterMetadataKey } from "../../common/cluster-types";
export class ClusterIdDetector extends BaseClusterDetector { export class ClusterIdDetector extends BaseClusterDetector {
key = ClusterMetadataKey.CLUSTER_ID; key = ClusterMetadataKey.CLUSTER_ID;

View File

@ -20,7 +20,7 @@
*/ */
import { observable } from "mobx"; 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 { Cluster } from "../cluster";
import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector"; import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector";
import { ClusterIdDetector } from "./cluster-id-detector"; import { ClusterIdDetector } from "./cluster-id-detector";

View File

@ -20,7 +20,7 @@
*/ */
import { BaseClusterDetector } from "./base-cluster-detector"; import { BaseClusterDetector } from "./base-cluster-detector";
import { ClusterMetadataKey } from "../cluster"; import { ClusterMetadataKey } from "../../common/cluster-types";
export class DistributionDetector extends BaseClusterDetector { export class DistributionDetector extends BaseClusterDetector {
key = ClusterMetadataKey.DISTRIBUTION; key = ClusterMetadataKey.DISTRIBUTION;

View File

@ -20,7 +20,7 @@
*/ */
import { BaseClusterDetector } from "./base-cluster-detector"; import { BaseClusterDetector } from "./base-cluster-detector";
import { ClusterMetadataKey } from "../cluster"; import { ClusterMetadataKey } from "../../common/cluster-types";
export class LastSeenDetector extends BaseClusterDetector { export class LastSeenDetector extends BaseClusterDetector {
key = ClusterMetadataKey.LAST_SEEN; key = ClusterMetadataKey.LAST_SEEN;

View File

@ -20,7 +20,7 @@
*/ */
import { BaseClusterDetector } from "./base-cluster-detector"; import { BaseClusterDetector } from "./base-cluster-detector";
import { ClusterMetadataKey } from "../cluster"; import { ClusterMetadataKey } from "../../common/cluster-types";
export class NodesCountDetector extends BaseClusterDetector { export class NodesCountDetector extends BaseClusterDetector {
key = ClusterMetadataKey.NODES_COUNT; key = ClusterMetadataKey.NODES_COUNT;

View File

@ -20,7 +20,7 @@
*/ */
import { BaseClusterDetector } from "./base-cluster-detector"; import { BaseClusterDetector } from "./base-cluster-detector";
import { ClusterMetadataKey } from "../cluster"; import { ClusterMetadataKey } from "../../common/cluster-types";
export class VersionDetector extends BaseClusterDetector { export class VersionDetector extends BaseClusterDetector {
key = ClusterMetadataKey.VERSION; key = ClusterMetadataKey.VERSION;

View File

@ -22,15 +22,16 @@
import "../common/cluster-ipc"; import "../common/cluster-ipc";
import type http from "http"; import type http from "http";
import { action, autorun, makeObservable, observable, observe, reaction, toJS } from "mobx"; import { action, autorun, makeObservable, observable, observe, reaction, toJS } from "mobx";
import { ClusterId, ClusterStore, getClusterIdFromHost } from "../common/cluster-store";
import { Cluster } from "./cluster"; import { Cluster } from "./cluster";
import logger from "./logger"; import logger from "./logger";
import { apiKubePrefix } from "../common/vars"; import { apiKubePrefix } from "../common/vars";
import { Singleton } from "../common/utils"; import { getClusterIdFromHost, Singleton } from "../common/utils";
import { catalogEntityRegistry } from "./catalog"; import { catalogEntityRegistry } from "./catalog";
import { KubernetesCluster, KubernetesClusterPrometheusMetrics, KubernetesClusterStatusPhase } from "../common/catalog-entities/kubernetes-cluster"; import { KubernetesCluster, KubernetesClusterPrometheusMetrics, KubernetesClusterStatusPhase } from "../common/catalog-entities/kubernetes-cluster";
import { ipcMainOn } from "../common/ipc"; import { ipcMainOn } from "../common/ipc";
import { once } from "lodash"; import { once } from "lodash";
import { ClusterStore } from "../common/cluster-store";
import type { ClusterId } from "../common/cluster-types";
const logPrefix = "[CLUSTER-MANAGER]:"; const logPrefix = "[CLUSTER-MANAGER]:";

View File

@ -20,7 +20,6 @@
*/ */
import { ipcMain } from "electron"; 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 { action, comparer, computed, makeObservable, observable, reaction, when } from "mobx";
import { broadcastMessage, ClusterListNamespaceForbiddenChannel } from "../common/ipc"; import { broadcastMessage, ClusterListNamespaceForbiddenChannel } from "../common/ipc";
import { ContextHandler } from "./context-handler"; import { ContextHandler } from "./context-handler";
@ -34,54 +33,7 @@ import { VersionDetector } from "./cluster-detectors/version-detector";
import { detectorRegistry } from "./cluster-detectors/detector-registry"; import { detectorRegistry } from "./cluster-detectors/detector-registry";
import plimit from "p-limit"; import plimit from "p-limit";
import { toJS } from "../common/utils"; import { toJS } from "../common/utils";
import { initialNodeShellImage } from "../common/cluster-store"; import { initialNodeShellImage, ClusterState, ClusterMetadataKey, ClusterRefreshOptions, ClusterStatus, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-types";
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;
}
/** /**
* Cluster * Cluster

View File

@ -21,7 +21,7 @@
import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"; import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry";
import { PrometheusProviderRegistry } 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 { Cluster } from "./cluster";
import type httpProxy from "http-proxy"; import type httpProxy from "http-proxy";
import url, { UrlWithStringQuery } from "url"; import url, { UrlWithStringQuery } from "url";

View File

@ -23,7 +23,8 @@ import type { IpcMainInvokeEvent } from "electron";
import { KubernetesCluster } from "../../common/catalog-entities"; import { KubernetesCluster } from "../../common/catalog-entities";
import { clusterFrameMap } from "../../common/cluster-frames"; import { clusterFrameMap } from "../../common/cluster-frames";
import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler, clusterDeleteHandler } from "../../common/cluster-ipc"; 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 { appEventBus } from "../../common/event-bus";
import { ipcMainHandle } from "../../common/ipc"; import { ipcMainHandle } from "../../common/ipc";
import { catalogEntityRegistry } from "../catalog"; import { catalogEntityRegistry } from "../catalog";

View File

@ -22,8 +22,8 @@
import _ from "lodash"; import _ from "lodash";
import type { LensApiRequest } from "../router"; import type { LensApiRequest } from "../router";
import { respondJson } from "../utils/http-responses"; import { respondJson } from "../utils/http-responses";
import { Cluster, ClusterMetadataKey } from "../cluster"; import type { Cluster } from "../cluster";
import type { ClusterPrometheusMetadata } from "../../common/cluster-store"; import { ClusterMetadataKey, ClusterPrometheusMetadata } from "../../common/cluster-types";
import logger from "../logger"; import logger from "../logger";
import { getMetrics } from "../k8s-request"; import { getMetrics } from "../k8s-request";
import { PrometheusProviderRegistry } from "../prometheus"; import { PrometheusProviderRegistry } from "../prometheus";

View File

@ -19,7 +19,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 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 { makeObservable, observable } from "mobx";
import { app, BrowserWindow, dialog, ipcMain, shell, webContents } from "electron"; import { app, BrowserWindow, dialog, ipcMain, shell, webContents } from "electron";
import windowStateKeeper from "electron-window-state"; import windowStateKeeper from "electron-window-state";

View File

@ -25,9 +25,10 @@
import path from "path"; import path from "path";
import { app } from "electron"; import { app } from "electron";
import fse from "fs-extra"; import fse from "fs-extra";
import { ClusterModel, ClusterStore } from "../../common/cluster-store";
import { loadConfigFromFileSync } from "../../common/kube-helpers"; import { loadConfigFromFileSync } from "../../common/kube-helpers";
import { MigrationDeclaration, migrationLog } from "../helpers"; import { MigrationDeclaration, migrationLog } from "../helpers";
import type { ClusterModel } from "../../common/cluster-types";
import { getCustomKubeConfigPath, storedKubeConfigFolder } from "../../common/utils";
interface Pre360ClusterModel extends ClusterModel { interface Pre360ClusterModel extends ClusterModel {
kubeConfig: string; kubeConfig: string;
@ -40,7 +41,7 @@ export default {
const storedClusters: Pre360ClusterModel[] = store.get("clusters") ?? []; const storedClusters: Pre360ClusterModel[] = store.get("clusters") ?? [];
const migratedClusters: ClusterModel[] = []; const migratedClusters: ClusterModel[] = [];
fse.ensureDirSync(ClusterStore.storedKubeConfigFolder); fse.ensureDirSync(storedKubeConfigFolder());
migrationLog("Number of clusters to migrate: ", storedClusters.length); migrationLog("Number of clusters to migrate: ", storedClusters.length);
@ -49,7 +50,7 @@ export default {
* migrate kubeconfig * migrate kubeconfig
*/ */
try { try {
const absPath = ClusterStore.getCustomKubeConfigPath(clusterModel.id); const absPath = getCustomKubeConfigPath(clusterModel.id);
// take the embedded kubeconfig and dump it into a file // take the embedded kubeconfig and dump it into a file
fse.writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 }); fse.writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 });

View File

@ -22,7 +22,7 @@
import path from "path"; import path from "path";
import { app } from "electron"; import { app } from "electron";
import fse from "fs-extra"; import fse from "fs-extra";
import type { ClusterModel } from "../../common/cluster-store"; import type { ClusterModel } from "../../common/cluster-types";
import type { MigrationDeclaration } from "../helpers"; import type { MigrationDeclaration } from "../helpers";
interface Pre500WorkspaceStoreModel { interface Pre500WorkspaceStoreModel {

View File

@ -19,7 +19,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 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 { MigrationDeclaration, migrationLog } from "../helpers";
import { generateNewIdFor } from "../utils"; import { generateNewIdFor } from "../utils";
import path from "path"; import path from "path";

View File

@ -21,7 +21,7 @@
// Fix embedded kubeconfig paths under snap config // 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 { getAppVersion } from "../../common/utils/app-version";
import fs from "fs"; import fs from "fs";
import { MigrationDeclaration, migrationLog } from "../helpers"; import { MigrationDeclaration, migrationLog } from "../helpers";

View File

@ -23,10 +23,10 @@ import { app } from "electron";
import { existsSync, readFileSync } from "fs"; import { existsSync, readFileSync } from "fs";
import path from "path"; import path from "path";
import os from "os"; 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 type { KubeconfigSyncEntry, UserPreferencesModel } from "../../common/user-store";
import { MigrationDeclaration, migrationLog } from "../helpers"; import { MigrationDeclaration, migrationLog } from "../helpers";
import { isLogicalChildPath } from "../../common/utils"; import { isLogicalChildPath, storedKubeConfigFolder } from "../../common/utils";
export default { export default {
version: "5.0.3-beta.1", version: "5.0.3-beta.1",
@ -42,8 +42,8 @@ export default {
for (const cluster of clusters) { for (const cluster of clusters) {
const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath); const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath);
if (dirOfKubeconfig === ClusterStore.storedKubeConfigFolder) { if (dirOfKubeconfig === storedKubeConfigFolder()) {
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under ClusterStore.storedKubeConfigFolder`); migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under the stored KubeConfig folder`);
continue; continue;
} }

View File

@ -30,12 +30,11 @@ import path from "path";
import React from "react"; import React from "react";
import { catalogURL } from "../../../common/routes"; import { catalogURL } from "../../../common/routes";
import { ClusterStore } from "../../../common/cluster-store";
import { appEventBus } from "../../../common/event-bus"; import { appEventBus } from "../../../common/event-bus";
import { loadConfigFromString, splitConfig } from "../../../common/kube-helpers"; import { loadConfigFromString, splitConfig } from "../../../common/kube-helpers";
import { docsUrl } from "../../../common/vars"; import { docsUrl } from "../../../common/vars";
import { navigate } from "../../navigation"; import { navigate } from "../../navigation";
import { iter } from "../../utils"; import { getCustomKubeConfigPath, iter } from "../../utils";
import { AceEditor } from "../ace-editor"; import { AceEditor } from "../ace-editor";
import { Button } from "../button"; import { Button } from "../button";
import { Notifications } from "../notifications"; import { Notifications } from "../notifications";
@ -93,7 +92,7 @@ export class AddCluster extends React.Component {
appEventBus.emit({ name: "cluster-add", action: "click" }); appEventBus.emit({ name: "cluster-add", action: "click" });
try { try {
const absPath = ClusterStore.getCustomKubeConfigPath(); const absPath = getCustomKubeConfigPath();
await fse.ensureDir(path.dirname(absPath)); await fse.ensureDir(path.dirname(absPath));
await fse.writeFile(absPath, this.customConfig.trim(), { encoding: "utf-8", mode: 0o600 }); await fse.writeFile(absPath, this.customConfig.trim(), { encoding: "utf-8", mode: 0o600 });

View File

@ -26,8 +26,7 @@ import { reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react"; import { disposeOnUnmount, observer } from "mobx-react";
import { nodesStore } from "../+nodes/nodes.store"; import { nodesStore } from "../+nodes/nodes.store";
import { podsStore } from "../+workloads-pods/pods.store"; import { podsStore } from "../+workloads-pods/pods.store";
import { getHostedCluster } from "../../../common/cluster-store"; import { getHostedClusterId, interval } from "../../utils";
import { interval } from "../../utils";
import { TabLayout } from "../layout/tab-layout"; import { TabLayout } from "../layout/tab-layout";
import { Spinner } from "../spinner"; import { Spinner } from "../spinner";
import { ClusterIssues } from "./cluster-issues"; import { ClusterIssues } from "./cluster-issues";
@ -35,14 +34,19 @@ import { ClusterMetrics } from "./cluster-metrics";
import { clusterOverviewStore } from "./cluster-overview.store"; import { clusterOverviewStore } from "./cluster-overview.store";
import { ClusterPieCharts } from "./cluster-pie-charts"; import { ClusterPieCharts } from "./cluster-pie-charts";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; 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 @observer
export class ClusterOverview extends React.Component { export class ClusterOverview extends React.Component {
private metricPoller = interval(60, () => this.loadMetrics()); private metricPoller = interval(60, () => this.loadMetrics());
loadMetrics() { loadMetrics() {
getHostedCluster().available && clusterOverviewStore.loadMetrics(); const cluster = ClusterStore.getInstance().getById(getHostedClusterId());
if (cluster.available) {
clusterOverviewStore.loadMetrics();
}
} }
componentDidMount() { componentDidMount() {

View File

@ -35,7 +35,7 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { limitRangeStore } from "../+config-limit-ranges/limit-ranges.store"; import { limitRangeStore } from "../+config-limit-ranges/limit-ranges.store";
import { ResourceMetrics } from "../resource-metrics"; import { ResourceMetrics } from "../resource-metrics";
import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; 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"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
interface Props extends KubeObjectDetailsProps<Namespace> { interface Props extends KubeObjectDetailsProps<Namespace> {

View File

@ -33,7 +33,7 @@ import { IngressCharts } from "./ingress-charts";
import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { getBackendServiceNamePort, getMetricsForIngress, IIngressMetrics } from "../../api/endpoints/ingress.api"; import { getBackendServiceNamePort, getMetricsForIngress, IIngressMetrics } from "../../api/endpoints/ingress.api";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ClusterMetricsResourceType } from "../../../main/cluster"; import { ClusterMetricsResourceType } from "../../../common/cluster-types";
interface Props extends KubeObjectDetailsProps<Ingress> { interface Props extends KubeObjectDetailsProps<Ingress> {
} }

View File

@ -36,7 +36,7 @@ import { makeObservable, observable, reaction } from "mobx";
import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; 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 { NodeDetailsResources } from "./node-details-resources";
import { DrawerTitle } from "../drawer/drawer-title"; import { DrawerTitle } from "../drawer/drawer-title";
import { boundMethod } from "../../utils"; import { boundMethod } from "../../utils";

View File

@ -33,7 +33,7 @@ import { VolumeClaimDiskChart } from "./volume-claim-disk-chart";
import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-object"; import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-object";
import { getMetricsForPvc, IPvcMetrics, PersistentVolumeClaim } from "../../api/endpoints"; import { getMetricsForPvc, IPvcMetrics, PersistentVolumeClaim } from "../../api/endpoints";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ClusterMetricsResourceType } from "../../../main/cluster"; import { ClusterMetricsResourceType } from "../../../common/cluster-types";
interface Props extends KubeObjectDetailsProps<PersistentVolumeClaim> { interface Props extends KubeObjectDetailsProps<PersistentVolumeClaim> {
} }

View File

@ -38,7 +38,7 @@ import { makeObservable, observable, reaction } from "mobx";
import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ClusterMetricsResourceType } from "../../../main/cluster"; import { ClusterMetricsResourceType } from "../../../common/cluster-types";
import { boundMethod } from "../../utils"; import { boundMethod } from "../../utils";
interface Props extends KubeObjectDetailsProps<DaemonSet> { interface Props extends KubeObjectDetailsProps<DaemonSet> {

View File

@ -40,7 +40,7 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store";
import { DeploymentReplicaSets } from "./deployment-replicasets"; import { DeploymentReplicaSets } from "./deployment-replicasets";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ClusterMetricsResourceType } from "../../../main/cluster"; import { ClusterMetricsResourceType } from "../../../common/cluster-types";
import { boundMethod } from "../../utils"; import { boundMethod } from "../../utils";
interface Props extends KubeObjectDetailsProps<Deployment> { interface Props extends KubeObjectDetailsProps<Deployment> {

View File

@ -39,7 +39,7 @@ import { lookupApiLink } from "../../api/kube-api";
import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { makeObservable, observable } from "mobx"; import { makeObservable, observable } from "mobx";
import { podMetricTabs, PodCharts } from "../+workloads-pods/pod-charts"; 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 { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ResourceMetrics } from "../resource-metrics"; import { ResourceMetrics } from "../resource-metrics";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";

View File

@ -34,7 +34,7 @@ import type { IMetrics } from "../../api/endpoints/metrics.api";
import { ContainerCharts } from "./container-charts"; import { ContainerCharts } from "./container-charts";
import { LocaleDate } from "../locale-date"; import { LocaleDate } from "../locale-date";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ClusterMetricsResourceType } from "../../../main/cluster"; import { ClusterMetricsResourceType } from "../../../common/cluster-types";
interface Props { interface Props {
pod: Pod; pod: Pod;

View File

@ -41,7 +41,7 @@ import { getItemMetrics } from "../../api/endpoints/metrics.api";
import { PodCharts, podMetricTabs } from "./pod-charts"; import { PodCharts, podMetricTabs } from "./pod-charts";
import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ClusterMetricsResourceType } from "../../../main/cluster"; import { ClusterMetricsResourceType } from "../../../common/cluster-types";
interface Props extends KubeObjectDetailsProps<Pod> { interface Props extends KubeObjectDetailsProps<Pod> {
} }

View File

@ -37,7 +37,7 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ClusterMetricsResourceType } from "../../../main/cluster"; import { ClusterMetricsResourceType } from "../../../common/cluster-types";
import { boundMethod } from "../../utils"; import { boundMethod } from "../../utils";
interface Props extends KubeObjectDetailsProps<ReplicaSet> { interface Props extends KubeObjectDetailsProps<ReplicaSet> {

View File

@ -38,7 +38,7 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts";
import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { getActiveClusterEntity } from "../../api/catalog-entity-registry"; import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
import { ClusterMetricsResourceType } from "../../../main/cluster"; import { ClusterMetricsResourceType } from "../../../common/cluster-types";
import { boundMethod } from "../../utils"; import { boundMethod } from "../../utils";
interface Props extends KubeObjectDetailsProps<StatefulSet> { interface Props extends KubeObjectDetailsProps<StatefulSet> {

View File

@ -32,7 +32,6 @@ import { DeploymentScaleDialog } from "./+workloads-deployments/deployment-scale
import { CronJobTriggerDialog } from "./+workloads-cronjobs/cronjob-trigger-dialog"; import { CronJobTriggerDialog } from "./+workloads-cronjobs/cronjob-trigger-dialog";
import { CustomResources } from "./+custom-resources/custom-resources"; import { CustomResources } from "./+custom-resources/custom-resources";
import { isAllowedResource } from "../../common/rbac"; import { isAllowedResource } from "../../common/rbac";
import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store";
import logger from "../../main/logger"; import logger from "../../main/logger";
import { webFrame } from "electron"; import { webFrame } from "electron";
import { ClusterPageRegistry, getExtensionPageUrl } from "../../extensions/registries/page-registry"; import { ClusterPageRegistry, getExtensionPageUrl } from "../../extensions/registries/page-registry";
@ -70,9 +69,14 @@ import { Workloads } from "./+workloads";
import { Config } from "./+config"; import { Config } from "./+config";
import { Storage } from "./+storage"; import { Storage } from "./+storage";
import { catalogEntityRegistry } from "../api/catalog-entity-registry"; 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 @observer
export class App extends React.Component { export class App extends React.Component {
static clusterId: ClusterId;
constructor(props: {}) { constructor(props: {}) {
super(props); super(props);
makeObservable(this); makeObservable(this);
@ -81,15 +85,18 @@ export class App extends React.Component {
static async init() { static async init() {
catalogEntityRegistry.init(); catalogEntityRegistry.init();
const frameId = webFrame.routingId; 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 Terminal.preloadFonts();
await requestMain(clusterSetFrameIdHandler, App.clusterId);
await requestMain(clusterSetFrameIdHandler, clusterId); const cluster = ClusterStore.getInstance().getById(App.clusterId);
await getHostedCluster().whenReady; // cluster.activate() is done at this point
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) { if (!entity) {
return; return;
} }
@ -103,7 +110,7 @@ export class App extends React.Component {
name: "cluster", name: "cluster",
action: "open", action: "open",
params: { params: {
clusterId clusterId: App.clusterId
} }
}); });
}); });
@ -212,7 +219,7 @@ export class App extends React.Component {
<StatefulSetScaleDialog/> <StatefulSetScaleDialog/>
<ReplicaSetScaleDialog/> <ReplicaSetScaleDialog/>
<CronJobTriggerDialog/> <CronJobTriggerDialog/>
<CommandContainer clusterId={getHostedCluster()?.id}/> <CommandContainer clusterId={App.clusterId}/>
</ErrorBoundary> </ErrorBoundary>
</Router> </Router>
); );

View File

@ -26,7 +26,7 @@ import { computed, observable, makeObservable } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import React from "react"; import React from "react";
import { clusterActivateHandler } from "../../../common/cluster-ipc"; 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 { ipcRendererOn, requestMain } from "../../../common/ipc";
import type { Cluster } from "../../../main/cluster"; import type { Cluster } from "../../../main/cluster";
import { cssNames, IClassName } from "../../utils"; import { cssNames, IClassName } from "../../utils";
@ -36,6 +36,7 @@ import { Spinner } from "../spinner";
import type { KubeAuthProxyLog } from "../../../main/kube-auth-proxy"; import type { KubeAuthProxyLog } from "../../../main/kube-auth-proxy";
import { navigate } from "../../navigation"; import { navigate } from "../../navigation";
import { entitySettingsURL } from "../../../common/routes"; import { entitySettingsURL } from "../../../common/routes";
import type { ClusterId } from "../../../common/cluster-types";
interface Props { interface Props {
className?: IClassName; className?: IClassName;

View File

@ -20,10 +20,12 @@
*/ */
import { observable, when } from "mobx"; import { observable, when } from "mobx";
import { ClusterId, ClusterStore, getClusterFrameUrl } from "../../../common/cluster-store";
import logger from "../../../main/logger"; import logger from "../../../main/logger";
import { requestMain } from "../../../common/ipc"; import { requestMain } from "../../../common/ipc";
import { clusterVisibilityHandler } from "../../../common/cluster-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 { export interface LensView {
isLoaded?: boolean isLoaded?: boolean

View File

@ -25,8 +25,9 @@ import { Select, SelectOption } from "../../select/select";
import { Icon } from "../../icon/icon"; import { Icon } from "../../icon/icon";
import { Button } from "../../button/button"; import { Button } from "../../button/button";
import { SubTitle } from "../../layout/sub-title"; 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 { observable, reaction, makeObservable } from "mobx";
import { ClusterMetricsResourceType } from "../../../../common/cluster-types";
interface Props { interface Props {
cluster: Cluster; cluster: Cluster;

View File

@ -26,7 +26,7 @@ import React from "react";
import { Input } from "../../input/input"; import { Input } from "../../input/input";
import { disposeOnUnmount, observer } from "mobx-react"; import { disposeOnUnmount, observer } from "mobx-react";
import { Icon } from "../../icon/icon"; import { Icon } from "../../icon/icon";
import { initialNodeShellImage } from "../../../../common/cluster-store"; import { initialNodeShellImage } from "../../../../common/cluster-types";
interface Props { interface Props {
cluster: Cluster; cluster: Cluster;

View File

@ -28,7 +28,7 @@ import { Dialog } from "../dialog";
import { EventEmitter } from "../../../common/event-emitter"; import { EventEmitter } from "../../../common/event-emitter";
import { ipcRendererOn } from "../../../common/ipc"; import { ipcRendererOn } from "../../../common/ipc";
import { CommandDialog } from "./command-dialog"; 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 { catalogEntityRegistry } from "../../api/catalog-entity-registry";
import { CommandRegistration, CommandRegistry } from "../../../extensions/registries/command-registry"; import { CommandRegistration, CommandRegistry } from "../../../extensions/registries/command-registry";

View File

@ -19,8 +19,9 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 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 type { Cluster } from "../../main/cluster";
import { getHostedCluster } from "../../common/cluster-store"; import { getHostedClusterId } from "../utils";
import { namespaceStore } from "./+namespaces/namespace.store"; import { namespaceStore } from "./+namespaces/namespace.store";
export interface ClusterContext { export interface ClusterContext {
@ -31,7 +32,7 @@ export interface ClusterContext {
export const clusterContext: ClusterContext = { export const clusterContext: ClusterContext = {
get cluster(): Cluster | null { get cluster(): Cluster | null {
return getHostedCluster(); return ClusterStore.getInstance().getById(getHostedClusterId());
}, },
get allNamespaces(): string[] { get allNamespaces(): string[] {

View File

@ -26,8 +26,9 @@ import { app, remote } from "electron";
import { comparer, observable, reaction, toJS, when } from "mobx"; import { comparer, observable, reaction, toJS, when } from "mobx";
import fse from "fs-extra"; import fse from "fs-extra";
import { StorageHelper } from "./storageHelper"; import { StorageHelper } from "./storageHelper";
import { ClusterStore, getHostedClusterId } from "../../common/cluster-store"; import { ClusterStore } from "../../common/cluster-store";
import logger from "../../main/logger"; import logger from "../../main/logger";
import { getHostedClusterId } from "../../common/utils";
const storage = observable({ const storage = observable({
initialized: false, initialized: false,