mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove multiple usages of shared global state
Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
8204dc5a9a
commit
4eb4edaed9
@ -15,8 +15,8 @@ import { loadConfigFromFile, loadConfigFromFileSync, validateKubeConfig } from "
|
||||
import type { KubeApiResource, KubeResource } from "../rbac";
|
||||
import { apiResourceRecord, apiResources } from "../rbac";
|
||||
import logger from "../../main/logger";
|
||||
import { VersionDetector } from "../../main/cluster-detectors/version-detector";
|
||||
import { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
|
||||
import type { VersionDetector } from "../../main/cluster-detectors/version-detector";
|
||||
import type { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
|
||||
import plimit from "p-limit";
|
||||
import type { ClusterState, ClusterRefreshOptions, ClusterMetricsResourceType, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, KubeAuthUpdate } from "../cluster-types";
|
||||
import { ClusterMetadataKey, initialNodeShellImage, ClusterStatus } from "../cluster-types";
|
||||
@ -33,6 +33,8 @@ export interface ClusterDependencies {
|
||||
createKubectl: (clusterVersion: string) => Kubectl;
|
||||
createAuthorizationReview: (config: KubeConfig) => CanI;
|
||||
createListNamespaces: (config: KubeConfig) => ListNamespaces;
|
||||
detectorRegistry: DetectorRegistry;
|
||||
createVersionDetector: (cluster: Cluster) => VersionDetector;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -425,7 +427,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
@action
|
||||
async refreshMetadata() {
|
||||
logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
|
||||
const metadata = await DetectorRegistry.getInstance().detectForCluster(this);
|
||||
const metadata = await this.dependencies.detectorRegistry.detectForCluster(this);
|
||||
const existingMetadata = this.metadata;
|
||||
|
||||
this.metadata = Object.assign(existingMetadata, metadata);
|
||||
@ -488,7 +490,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
|
||||
protected async getConnectionStatus(): Promise<ClusterStatus> {
|
||||
try {
|
||||
const versionDetector = new VersionDetector(this);
|
||||
const versionDetector = this.dependencies.createVersionDetector(this);
|
||||
const versionData = await versionDetector.detect();
|
||||
|
||||
this.metadata.version = versionData.value;
|
||||
|
||||
18
src/common/fs/ensure-dir.injectable.ts
Normal file
18
src/common/fs/ensure-dir.injectable.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
const ensureDirInjectable = getInjectable({
|
||||
id: "ensure-dir",
|
||||
|
||||
// TODO: Remove usages of ensureDir from business logic.
|
||||
// TODO: Read, Write, Watch etc. operations should do this internally.
|
||||
instantiate: (di) => di.inject(fsInjectable).ensureDir,
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default ensureDirInjectable;
|
||||
18
src/common/weblink-store.injectable.ts
Normal file
18
src/common/weblink-store.injectable.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { WeblinkStore } from "./weblink-store";
|
||||
|
||||
const weblinkStoreInjectable = getInjectable({
|
||||
id: "weblink-store",
|
||||
|
||||
instantiate: () => {
|
||||
WeblinkStore.resetInstance();
|
||||
|
||||
return WeblinkStore.createInstance();
|
||||
},
|
||||
});
|
||||
|
||||
export default weblinkStoreInjectable;
|
||||
@ -4,13 +4,17 @@
|
||||
*/
|
||||
|
||||
import { LensExtension } from "./lens-extension";
|
||||
import { WindowManager } from "../main/window-manager";
|
||||
import { catalogEntityRegistry } from "../main/catalog";
|
||||
import type { CatalogEntity } from "../common/catalog";
|
||||
import type { IObservableArray } from "mobx";
|
||||
import type { MenuRegistration } from "../main/menu/menu-registration";
|
||||
import type { TrayMenuRegistration } from "../main/tray/tray-menu-registration";
|
||||
import type { ShellEnvModifier } from "../main/shell-session/shell-env-modifier/shell-env-modifier-registration";
|
||||
import {
|
||||
Environments,
|
||||
getEnvironmentSpecificLegacyGlobalDiForExtensionApi,
|
||||
} from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import windowManagerInjectable from "../main/window-manager.injectable";
|
||||
|
||||
export class LensMainExtension extends LensExtension {
|
||||
appMenus: MenuRegistration[] = [];
|
||||
@ -18,21 +22,25 @@ export class LensMainExtension extends LensExtension {
|
||||
|
||||
/**
|
||||
* implement this to modify the shell environment that Lens terminals are opened with. The ShellEnvModifier type has the signature
|
||||
*
|
||||
*
|
||||
* (ctx: ShellEnvContext, env: Record<string, string | undefined>) => Record<string, string | undefined>
|
||||
*
|
||||
*
|
||||
* @param ctx the shell environment context, specifically the relevant catalog entity for the terminal. This can be used, for example, to get
|
||||
* cluster-specific information that can be made available in the shell environment by the implementation of terminalShellEnvModifier
|
||||
*
|
||||
*
|
||||
* @param env the current shell environment that the terminal will be opened with. The implementation should modify this as desired.
|
||||
*
|
||||
*
|
||||
* @returns the modified shell environment that the terminal will be opened with. The implementation must return env as passed in, if it
|
||||
* does not modify the shell environment
|
||||
*/
|
||||
terminalShellEnvModifier?: ShellEnvModifier;
|
||||
|
||||
async navigate(pageId?: string, params?: Record<string, any>, frameId?: number) {
|
||||
return WindowManager.getInstance().navigateExtension(this.id, pageId, params, frameId);
|
||||
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.main);
|
||||
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
|
||||
return windowManager.navigateExtension(this.id, pageId, params, frameId);
|
||||
}
|
||||
|
||||
addCatalogSource(id: string, source: IObservableArray<CatalogEntity>) {
|
||||
|
||||
@ -3,8 +3,17 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { WindowManager } from "../../main/window-manager";
|
||||
import {
|
||||
Environments,
|
||||
getEnvironmentSpecificLegacyGlobalDiForExtensionApi,
|
||||
} from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
|
||||
import windowManagerInjectable from "../../main/window-manager.injectable";
|
||||
|
||||
export function navigate(url: string) {
|
||||
return WindowManager.getInstance().navigate(url);
|
||||
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.main);
|
||||
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
|
||||
return windowManager.navigate(url);
|
||||
}
|
||||
|
||||
@ -12,6 +12,8 @@ import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
import prometheusProviderRegistryInjectable
|
||||
from "../prometheus/prometheus-provider-registry.injectable";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
app: {
|
||||
@ -74,6 +76,7 @@ const clusterStub = {
|
||||
|
||||
describe("ContextHandler", () => {
|
||||
let createContextHandler: (cluster: Cluster) => ContextHandler;
|
||||
let prometheusProviderRegistry: PrometheusProviderRegistry;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
@ -84,13 +87,12 @@ describe("ContextHandler", () => {
|
||||
|
||||
di.override(createKubeAuthProxyInjectable, () => ({} as any));
|
||||
|
||||
createContextHandler = di.inject(createContextHandlerInjectable);
|
||||
prometheusProviderRegistry = di.inject(prometheusProviderRegistryInjectable);
|
||||
|
||||
PrometheusProviderRegistry.createInstance();
|
||||
createContextHandler = di.inject(createContextHandlerInjectable);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
PrometheusProviderRegistry.resetInstance();
|
||||
UserStore.resetInstance();
|
||||
mockFs.restore();
|
||||
});
|
||||
@ -102,17 +104,16 @@ describe("ContextHandler", () => {
|
||||
[0, 2],
|
||||
[0, 3],
|
||||
])("should throw from %d success(es) after %d failure(s)", async (successes, failures) => {
|
||||
const reg = PrometheusProviderRegistry.getInstance();
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < failures; i += 1) {
|
||||
const serviceResult = i % 2 === 0 ? ServiceResult.Failure : ServiceResult.Undefined;
|
||||
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, serviceResult));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, serviceResult));
|
||||
}
|
||||
|
||||
for (let i = 0; i < successes; i += 1) {
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
}
|
||||
|
||||
expect(() => {
|
||||
@ -133,17 +134,16 @@ describe("ContextHandler", () => {
|
||||
[2, 2],
|
||||
[2, 3],
|
||||
])("should pick the first provider of %d success(es) after %d failure(s)", async (successes, failures) => {
|
||||
const reg = PrometheusProviderRegistry.getInstance();
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < failures; i += 1) {
|
||||
const serviceResult = i % 2 === 0 ? ServiceResult.Failure : ServiceResult.Undefined;
|
||||
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, serviceResult));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, serviceResult));
|
||||
}
|
||||
|
||||
for (let i = 0; i < successes; i += 1) {
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
}
|
||||
|
||||
// TODO: Unit test shouldn't access protected or private methods
|
||||
@ -164,17 +164,16 @@ describe("ContextHandler", () => {
|
||||
[2, 2],
|
||||
[2, 3],
|
||||
])("should pick the first provider of %d success(es) before %d failure(s)", async (successes, failures) => {
|
||||
const reg = PrometheusProviderRegistry.getInstance();
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < successes; i += 1) {
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
}
|
||||
|
||||
for (let i = 0; i < failures; i += 1) {
|
||||
const serviceResult = i % 2 === 0 ? ServiceResult.Failure : ServiceResult.Undefined;
|
||||
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, serviceResult));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, serviceResult));
|
||||
}
|
||||
|
||||
// TODO: Unit test shouldn't access protected or private methods
|
||||
@ -195,23 +194,22 @@ describe("ContextHandler", () => {
|
||||
[2, 2],
|
||||
[2, 3],
|
||||
])("should pick the first provider of %d success(es) between %d failure(s)", async (successes, failures) => {
|
||||
const reg = PrometheusProviderRegistry.getInstance();
|
||||
let count = 0;
|
||||
const beforeSuccesses = Math.floor(successes / 2);
|
||||
const afterSuccesses = successes - beforeSuccesses;
|
||||
|
||||
for (let i = 0; i < beforeSuccesses; i += 1) {
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
}
|
||||
|
||||
for (let i = 0; i < failures; i += 1) {
|
||||
const serviceResult = i % 2 === 0 ? ServiceResult.Failure : ServiceResult.Undefined;
|
||||
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, serviceResult));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, serviceResult));
|
||||
}
|
||||
|
||||
for (let i = 0; i < afterSuccesses; i += 1) {
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
}
|
||||
|
||||
// TODO: Unit test shouldn't access protected or private methods
|
||||
@ -223,12 +221,11 @@ describe("ContextHandler", () => {
|
||||
});
|
||||
|
||||
it("shouldn't pick the second provider of 2 success(es) after 1 failure(s)", async () => {
|
||||
const reg = PrometheusProviderRegistry.getInstance();
|
||||
let count = 0;
|
||||
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Failure));
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
reg.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Failure));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
prometheusProviderRegistry.registerProvider(new TestProvider(`id_${count++}`, ServiceResult.Success));
|
||||
|
||||
// TODO: Unit test shouldn't access protected or private methods
|
||||
const contextHandler = createContextHandler(clusterStub) as any;
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import electronAppInjectable from "./electron-app.injectable";
|
||||
|
||||
const exitAppInjectable = getInjectable({
|
||||
id: "exit-app",
|
||||
|
||||
instantiate: (di) => () => {
|
||||
const app = di.inject(electronAppInjectable);
|
||||
|
||||
app.exit(0);
|
||||
},
|
||||
});
|
||||
|
||||
export default exitAppInjectable;
|
||||
@ -10,7 +10,6 @@ import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { computeDiff as computeDiffFor, configToModels } from "../kubeconfig-sync-manager/kubeconfig-sync-manager";
|
||||
import mockFs from "mock-fs";
|
||||
import fs from "fs";
|
||||
import { ClusterManager } from "../../cluster-manager";
|
||||
import clusterStoreInjectable from "../../../common/cluster-store/cluster-store.injectable";
|
||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||
import { createClusterInjectionToken } from "../../../common/cluster/create-cluster-injection-token";
|
||||
@ -19,6 +18,7 @@ import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||
import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
|
||||
import appVersionInjectable from "../../../common/get-configuration-file-model/app-version/app-version.injectable";
|
||||
import { runSetups } from "../../../common/setupable-injection-token/run-setups";
|
||||
import clusterManagerInjectable from "../../cluster-manager.injectable";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
app: {
|
||||
@ -53,19 +53,17 @@ describe("kubeconfig-sync.source tests", () => {
|
||||
computeDiff = computeDiffFor({
|
||||
directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable),
|
||||
createCluster: di.inject(createClusterInjectionToken),
|
||||
clusterManager: di.inject(clusterManagerInjectable),
|
||||
});
|
||||
|
||||
di.permitSideEffects(getConfigurationFileModelInjectable);
|
||||
di.permitSideEffects(appVersionInjectable);
|
||||
|
||||
di.inject(clusterStoreInjectable);
|
||||
|
||||
ClusterManager.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
ClusterManager.resetInstance();
|
||||
ClusterStore.resetInstance();
|
||||
});
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||
import { KubeconfigSyncManager } from "./kubeconfig-sync-manager";
|
||||
import { createClusterInjectionToken } from "../../../common/cluster/create-cluster-injection-token";
|
||||
import clusterManagerInjectable from "../../cluster-manager.injectable";
|
||||
|
||||
const kubeconfigSyncManagerInjectable = getInjectable({
|
||||
id: "kubeconfig-sync-manager",
|
||||
@ -13,6 +14,7 @@ const kubeconfigSyncManagerInjectable = getInjectable({
|
||||
instantiate: (di) => new KubeconfigSyncManager({
|
||||
directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable),
|
||||
createCluster: di.inject(createClusterInjectionToken),
|
||||
clusterManager: di.inject(clusterManagerInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ const fileSyncMaxAllowedFileReadSize = 16 * folderSyncMaxAllowedFileReadSize; //
|
||||
interface Dependencies {
|
||||
directoryForKubeConfigs: string;
|
||||
createCluster: (model: ClusterModel) => Cluster;
|
||||
clusterManager: ClusterManager;
|
||||
}
|
||||
|
||||
const kubeConfigSyncName = "lens:kube-sync";
|
||||
@ -164,7 +165,7 @@ type RootSourceValue = [Cluster, CatalogEntity];
|
||||
type RootSource = ObservableMap<string, RootSourceValue>;
|
||||
|
||||
// exported for testing
|
||||
export const computeDiff = ({ directoryForKubeConfigs, createCluster }: Dependencies) => (contents: string, source: RootSource, filePath: string): void => {
|
||||
export const computeDiff = ({ directoryForKubeConfigs, createCluster, clusterManager }: Dependencies) => (contents: string, source: RootSource, filePath: string): void => {
|
||||
runInAction(() => {
|
||||
try {
|
||||
const { config, error } = loadConfigFromString(contents);
|
||||
@ -184,7 +185,7 @@ export const computeDiff = ({ directoryForKubeConfigs, createCluster }: Dependen
|
||||
// remove and disconnect clusters that were removed from the config
|
||||
if (!model) {
|
||||
// remove from the deleting set, so that if a new context of the same name is added, it isn't marked as deleting
|
||||
ClusterManager.getInstance().deleting.delete(value[0].id);
|
||||
clusterManager.deleting.delete(value[0].id);
|
||||
|
||||
value[0].disconnect();
|
||||
source.delete(contextName);
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { computed, observable, reaction } from "mobx";
|
||||
import { WeblinkStore } from "../../common/weblink-store";
|
||||
import type { WeblinkStore } from "../../common/weblink-store";
|
||||
import { WebLink } from "../../common/catalog-entities";
|
||||
import { catalogEntityRegistry } from "../catalog";
|
||||
import got from "got";
|
||||
@ -29,8 +29,7 @@ async function validateLink(link: WebLink) {
|
||||
}
|
||||
|
||||
|
||||
export function syncWeblinks() {
|
||||
const weblinkStore = WeblinkStore.getInstance();
|
||||
export function syncWeblinks(weblinkStore: WeblinkStore) {
|
||||
const webLinkEntities = observable.map<string, [WebLink, Disposer]>();
|
||||
|
||||
function periodicallyCheckLink(link: WebLink): Disposer {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
import type { RequestPromiseOptions } from "request-promise-native";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import { k8sRequest } from "../k8s-request";
|
||||
import type { K8sRequest } from "../k8s-request.injectable";
|
||||
|
||||
export interface ClusterDetectionResult {
|
||||
value: string | number | boolean;
|
||||
@ -15,7 +15,7 @@ export interface ClusterDetectionResult {
|
||||
export class BaseClusterDetector {
|
||||
key: string;
|
||||
|
||||
constructor(public cluster: Cluster) {
|
||||
constructor(public cluster: Cluster, private _k8sRequest: K8sRequest) {
|
||||
}
|
||||
|
||||
detect(): Promise<ClusterDetectionResult> {
|
||||
@ -23,6 +23,6 @@ export class BaseClusterDetector {
|
||||
}
|
||||
|
||||
protected async k8sRequest<T = any>(path: string, options: RequestPromiseOptions = {}): Promise<T> {
|
||||
return k8sRequest(this.cluster, path, options);
|
||||
return this._k8sRequest(this.cluster, path, options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { VersionDetector } from "./version-detector";
|
||||
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
|
||||
const createVersionDetectorInjectable = getInjectable({
|
||||
id: "create-version-detector",
|
||||
|
||||
instantiate: (di) => {
|
||||
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||
|
||||
return (cluster: Cluster) =>
|
||||
new VersionDetector(cluster, k8sRequest);
|
||||
},
|
||||
});
|
||||
|
||||
export default createVersionDetectorInjectable;
|
||||
16
src/main/cluster-detectors/detector-registry.injectable.ts
Normal file
16
src/main/cluster-detectors/detector-registry.injectable.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { DetectorRegistry } from "./detector-registry";
|
||||
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||
|
||||
const detectorRegistryInjectable = getInjectable({
|
||||
id: "detector-registry",
|
||||
|
||||
instantiate: (di) =>
|
||||
new DetectorRegistry({ k8sRequest: di.inject(k8sRequestInjectable) }),
|
||||
});
|
||||
|
||||
export default detectorRegistryInjectable;
|
||||
@ -5,11 +5,17 @@
|
||||
|
||||
import { observable } from "mobx";
|
||||
import type { ClusterMetadata } from "../../common/cluster-types";
|
||||
import { Singleton } from "../../common/utils";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector";
|
||||
import type { K8sRequest } from "../k8s-request.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
k8sRequest: K8sRequest;
|
||||
}
|
||||
|
||||
export class DetectorRegistry {
|
||||
constructor(private dependencies: Dependencies) {}
|
||||
|
||||
export class DetectorRegistry extends Singleton {
|
||||
registry = observable.array<typeof BaseClusterDetector>([], { deep: false });
|
||||
|
||||
add(detectorClass: typeof BaseClusterDetector): this {
|
||||
@ -22,7 +28,7 @@ export class DetectorRegistry extends Singleton {
|
||||
const results: { [key: string]: ClusterDetectionResult } = {};
|
||||
|
||||
for (const detectorClass of this.registry) {
|
||||
const detector = new detectorClass(cluster);
|
||||
const detector = new detectorClass(cluster, this.dependencies.k8sRequest);
|
||||
|
||||
try {
|
||||
const data = await detector.detect();
|
||||
|
||||
23
src/main/cluster-manager.injectable.ts
Normal file
23
src/main/cluster-manager.injectable.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ClusterManager } from "./cluster-manager";
|
||||
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
|
||||
|
||||
const clusterManagerInjectable = getInjectable({
|
||||
id: "cluster-manager",
|
||||
|
||||
instantiate: (di) => {
|
||||
const clusterManager = new ClusterManager({
|
||||
store: di.inject(clusterStoreInjectable),
|
||||
});
|
||||
|
||||
clusterManager.init();
|
||||
|
||||
return clusterManager;
|
||||
},
|
||||
});
|
||||
|
||||
export default clusterManagerInjectable;
|
||||
@ -9,42 +9,44 @@ import { action, makeObservable, observable, observe, reaction, toJS } from "mob
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
import logger from "./logger";
|
||||
import { apiKubePrefix } from "../common/vars";
|
||||
import { getClusterIdFromHost, Singleton } from "../common/utils";
|
||||
import { getClusterIdFromHost } from "../common/utils";
|
||||
import { catalogEntityRegistry } from "./catalog";
|
||||
import type { KubernetesClusterPrometheusMetrics } from "../common/catalog-entities/kubernetes-cluster";
|
||||
import { KubernetesCluster, LensKubernetesClusterStatus } from "../common/catalog-entities/kubernetes-cluster";
|
||||
import { ipcMainOn } from "../common/ipc";
|
||||
import { once } from "lodash";
|
||||
import { ClusterStore } from "../common/cluster-store/cluster-store";
|
||||
import type { ClusterStore } from "../common/cluster-store/cluster-store";
|
||||
import type { ClusterId } from "../common/cluster-types";
|
||||
|
||||
const logPrefix = "[CLUSTER-MANAGER]:";
|
||||
|
||||
const lensSpecificClusterStatuses: Set<string> = new Set(Object.values(LensKubernetesClusterStatus));
|
||||
|
||||
export class ClusterManager extends Singleton {
|
||||
private store = ClusterStore.getInstance();
|
||||
interface Dependencies {
|
||||
store: ClusterStore;
|
||||
}
|
||||
|
||||
export class ClusterManager {
|
||||
deleting = observable.set<ClusterId>();
|
||||
|
||||
@observable visibleCluster: ClusterId | undefined = undefined;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
constructor(private dependencies: Dependencies) {
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
init = once(() => {
|
||||
// reacting to every cluster's state change and total amount of items
|
||||
reaction(
|
||||
() => this.store.clustersList.map(c => c.getState()),
|
||||
() => this.updateCatalog(this.store.clustersList),
|
||||
() => this.dependencies.store.clustersList.map(c => c.getState()),
|
||||
() => this.updateCatalog(this.dependencies.store.clustersList),
|
||||
{ fireImmediately: false },
|
||||
);
|
||||
|
||||
// reacting to every cluster's preferences change and total amount of items
|
||||
reaction(
|
||||
() => this.store.clustersList.map(c => toJS(c.preferences)),
|
||||
() => this.updateCatalog(this.store.clustersList),
|
||||
() => this.dependencies.store.clustersList.map(c => toJS(c.preferences)),
|
||||
() => this.updateCatalog(this.dependencies.store.clustersList),
|
||||
{ fireImmediately: false },
|
||||
);
|
||||
|
||||
@ -180,7 +182,7 @@ export class ClusterManager extends Singleton {
|
||||
@action
|
||||
protected syncClustersFromCatalog(entities: KubernetesCluster[]) {
|
||||
for (const entity of entities) {
|
||||
const cluster = this.store.getById(entity.getId());
|
||||
const cluster = this.dependencies.store.getById(entity.getId());
|
||||
|
||||
if (!cluster) {
|
||||
const model = {
|
||||
@ -195,7 +197,7 @@ export class ClusterManager extends Singleton {
|
||||
* Add the bare minimum of data to ClusterStore. And especially no
|
||||
* preferences, as those might be configured by the entity's source
|
||||
*/
|
||||
this.store.addCluster(model);
|
||||
this.dependencies.store.addCluster(model);
|
||||
} catch (error) {
|
||||
if (error.code === "ENOENT" && error.path === entity.spec.kubeconfigPath) {
|
||||
logger.warn(`${logPrefix} kubeconfig file disappeared`, model);
|
||||
@ -234,7 +236,7 @@ export class ClusterManager extends Singleton {
|
||||
|
||||
protected onNetworkOffline = () => {
|
||||
logger.info(`${logPrefix} network is offline`);
|
||||
this.store.clustersList.forEach((cluster) => {
|
||||
this.dependencies.store.clustersList.forEach((cluster) => {
|
||||
if (!cluster.disconnected) {
|
||||
cluster.online = false;
|
||||
cluster.accessible = false;
|
||||
@ -245,7 +247,7 @@ export class ClusterManager extends Singleton {
|
||||
|
||||
protected onNetworkOnline = () => {
|
||||
logger.info(`${logPrefix} network is online`);
|
||||
this.store.clustersList.forEach((cluster) => {
|
||||
this.dependencies.store.clustersList.forEach((cluster) => {
|
||||
if (!cluster.disconnected) {
|
||||
cluster.refreshConnectionStatus().catch((e) => e);
|
||||
}
|
||||
@ -253,16 +255,16 @@ export class ClusterManager extends Singleton {
|
||||
};
|
||||
|
||||
stop() {
|
||||
this.store.clusters.forEach((cluster: Cluster) => {
|
||||
this.dependencies.store.clusters.forEach((cluster: Cluster) => {
|
||||
cluster.disconnect();
|
||||
});
|
||||
}
|
||||
|
||||
getClusterForRequest(req: http.IncomingMessage): Cluster {
|
||||
getClusterForRequest = (req: http.IncomingMessage): Cluster => {
|
||||
// lens-server is connecting to 127.0.0.1:<port>/<uid>
|
||||
if (req.headers.host.startsWith("127.0.0.1")) {
|
||||
const clusterId = req.url.split("/")[1];
|
||||
const cluster = this.store.getById(clusterId);
|
||||
const cluster = this.dependencies.store.getById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
// we need to swap path prefix so that request is proxied to kube api
|
||||
@ -272,8 +274,8 @@ export class ClusterManager extends Singleton {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
return this.store.getById(getClusterIdFromHost(req.headers.host));
|
||||
}
|
||||
return this.dependencies.store.getById(getClusterIdFromHost(req.headers.host));
|
||||
};
|
||||
}
|
||||
|
||||
export function catalogEntityFromCluster(cluster: Cluster) {
|
||||
|
||||
@ -3,8 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { PrometheusProvider, PrometheusService } from "../prometheus/provider-registry";
|
||||
import { PrometheusProviderRegistry } from "../prometheus/provider-registry";
|
||||
import type { PrometheusProvider, PrometheusService, PrometheusProviderRegistry } from "../prometheus/provider-registry";
|
||||
import type { ClusterPrometheusPreferences } from "../../common/cluster-types";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import type httpProxy from "http-proxy";
|
||||
@ -30,6 +29,7 @@ interface PrometheusServicePreferences {
|
||||
interface Dependencies {
|
||||
createKubeAuthProxy: CreateKubeAuthProxy;
|
||||
authProxyCa: string;
|
||||
prometheusProviderRegistry: PrometheusProviderRegistry;
|
||||
}
|
||||
|
||||
export class ContextHandler {
|
||||
@ -67,11 +67,11 @@ export class ContextHandler {
|
||||
this.prometheusProvider = service.id;
|
||||
}
|
||||
|
||||
return PrometheusProviderRegistry.getInstance().getByKind(this.prometheusProvider);
|
||||
return this.dependencies.prometheusProviderRegistry.getByKind(this.prometheusProvider);
|
||||
}
|
||||
|
||||
protected listPotentialProviders(): PrometheusProvider[] {
|
||||
const registry = PrometheusProviderRegistry.getInstance();
|
||||
const registry = this.dependencies.prometheusProviderRegistry;
|
||||
const provider = this.prometheusProvider && registry.getByKind(this.prometheusProvider);
|
||||
|
||||
if (provider) {
|
||||
|
||||
@ -9,6 +9,7 @@ import { ContextHandler } from "./context-handler";
|
||||
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
import { getKubeAuthProxyCertificate } from "../kube-auth-proxy/get-kube-auth-proxy-certificate";
|
||||
import URLParse from "url-parse";
|
||||
import prometheusProviderRegistryInjectable from "../prometheus/prometheus-provider-registry.injectable";
|
||||
|
||||
const createContextHandlerInjectable = getInjectable({
|
||||
id: "create-context-handler",
|
||||
@ -20,6 +21,7 @@ const createContextHandlerInjectable = getInjectable({
|
||||
const dependencies = {
|
||||
createKubeAuthProxy: di.inject(createKubeAuthProxyInjectable),
|
||||
authProxyCa: getKubeAuthProxyCertificate(clusterUrl.hostname, selfsigned.generate).cert,
|
||||
prometheusProviderRegistry: di.inject(prometheusProviderRegistryInjectable),
|
||||
};
|
||||
|
||||
return new ContextHandler(dependencies, cluster);
|
||||
|
||||
@ -12,6 +12,8 @@ import createContextHandlerInjectable from "../context-handler/create-context-ha
|
||||
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
||||
import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
|
||||
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
||||
import detectorRegistryInjectable from "../cluster-detectors/detector-registry.injectable";
|
||||
import createVersionDetectorInjectable from "../cluster-detectors/create-version-detector.injectable";
|
||||
|
||||
const createClusterInjectable = getInjectable({
|
||||
id: "create-cluster",
|
||||
@ -24,6 +26,8 @@ const createClusterInjectable = getInjectable({
|
||||
createContextHandler: di.inject(createContextHandlerInjectable),
|
||||
createAuthorizationReview: di.inject(authorizationReviewInjectable),
|
||||
createListNamespaces: di.inject(listNamespacesInjectable),
|
||||
detectorRegistry: di.inject(detectorRegistryInjectable),
|
||||
createVersionDetector: di.inject(createVersionDetectorInjectable),
|
||||
};
|
||||
|
||||
return (model) => new Cluster(dependencies, model);
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import logger from "./logger";
|
||||
|
||||
/**
|
||||
* Installs Electron developer tools in the development build.
|
||||
* The dependency is not bundled to the production build.
|
||||
*/
|
||||
export const installDeveloperTools = () => {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
logger.info("🤓 Installing developer tools");
|
||||
import("electron-devtools-installer")
|
||||
.then(({ default: devToolsInstaller, REACT_DEVELOPER_TOOLS }) => devToolsInstaller([REACT_DEVELOPER_TOOLS]))
|
||||
.then((name) => logger.info(`[DEVTOOLS-INSTALLER]: installed ${name}`))
|
||||
.catch(error => logger.error(`[DEVTOOLS-INSTALLER]: failed`, { error }));
|
||||
}
|
||||
};
|
||||
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { app } from "electron";
|
||||
import { WindowManager } from "./window-manager";
|
||||
import { appEventBus } from "../common/app-event-bus/event-bus";
|
||||
import { ClusterManager } from "./cluster-manager";
|
||||
import logger from "./logger";
|
||||
|
||||
export function exitApp() {
|
||||
const windowManager = WindowManager.getInstance(false);
|
||||
const clusterManager = ClusterManager.getInstance(false);
|
||||
|
||||
appEventBus.emit({ name: "service", action: "close" });
|
||||
windowManager?.hide();
|
||||
clusterManager?.stop();
|
||||
logger.info("SERVICE:QUIT");
|
||||
setTimeout(() => {
|
||||
app.exit();
|
||||
}, 1000);
|
||||
}
|
||||
37
src/main/get-metrics.injectable.ts
Normal file
37
src/main/get-metrics.injectable.ts
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
import type { IMetricsReqParams } from "../common/k8s-api/endpoints/metrics.api";
|
||||
import k8sRequestInjectable from "./k8s-request.injectable";
|
||||
|
||||
export type GetMetrics = (cluster: Cluster, prometheusPath: string, queryParams: IMetricsReqParams & { query: string }) => Promise<any>;
|
||||
|
||||
const getMetricsInjectable = getInjectable({
|
||||
id: "get-metrics",
|
||||
|
||||
instantiate: (di): GetMetrics => {
|
||||
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||
|
||||
return async (
|
||||
cluster,
|
||||
prometheusPath,
|
||||
queryParams,
|
||||
) => {
|
||||
const prometheusPrefix = cluster.preferences.prometheus?.prefix || "";
|
||||
const metricsPath = `/api/v1/namespaces/${prometheusPath}/proxy${prometheusPrefix}/api/v1/query_range`;
|
||||
|
||||
return k8sRequest(cluster, metricsPath, {
|
||||
timeout: 0,
|
||||
resolveWithFullResponse: false,
|
||||
json: true,
|
||||
method: "POST",
|
||||
form: queryParams,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default getMetricsInjectable;
|
||||
18
src/main/helm/helm-repo-manager.injectable.ts
Normal file
18
src/main/helm/helm-repo-manager.injectable.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { HelmRepoManager } from "./helm-repo-manager";
|
||||
|
||||
const helmRepoManagerInjectable = getInjectable({
|
||||
id: "helm-repo-manager",
|
||||
|
||||
instantiate: () => {
|
||||
HelmRepoManager.resetInstance();
|
||||
|
||||
return HelmRepoManager.createInstance();
|
||||
},
|
||||
});
|
||||
|
||||
export default helmRepoManagerInjectable;
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { ClusterIdDetector } from "../cluster-detectors/cluster-id-detector";
|
||||
import { DetectorRegistry } from "../cluster-detectors/detector-registry";
|
||||
import { DistributionDetector } from "../cluster-detectors/distribution-detector";
|
||||
import { LastSeenDetector } from "../cluster-detectors/last-seen-detector";
|
||||
import { NodesCountDetector } from "../cluster-detectors/nodes-count-detector";
|
||||
import { VersionDetector } from "../cluster-detectors/version-detector";
|
||||
|
||||
export function initClusterMetadataDetectors() {
|
||||
DetectorRegistry.createInstance()
|
||||
.add(ClusterIdDetector)
|
||||
.add(LastSeenDetector)
|
||||
.add(VersionDetector)
|
||||
.add(DistributionDetector)
|
||||
.add(NodesCountDetector);
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
export * from "./metrics-providers";
|
||||
export * from "./cluster-metadata-detectors";
|
||||
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { PrometheusProviderRegistry } from "../prometheus";
|
||||
import { PrometheusHelm } from "../prometheus/helm";
|
||||
import { PrometheusLens } from "../prometheus/lens";
|
||||
import { PrometheusOperator } from "../prometheus/operator";
|
||||
import { PrometheusStacklight } from "../prometheus/stacklight";
|
||||
|
||||
export function initPrometheusProviderRegistry() {
|
||||
PrometheusProviderRegistry
|
||||
.getInstance()
|
||||
.registerProvider(new PrometheusLens())
|
||||
.registerProvider(new PrometheusHelm())
|
||||
.registerProvider(new PrometheusOperator())
|
||||
.registerProvider(new PrometheusStacklight());
|
||||
}
|
||||
36
src/main/k8s-request.injectable.ts
Normal file
36
src/main/k8s-request.injectable.ts
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import request, { RequestPromiseOptions } from "request-promise-native";
|
||||
import { apiKubePrefix } from "../common/vars";
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import lensProxyPortNumberStateInjectable from "./lens-proxy-port-number-state.injectable";
|
||||
|
||||
export type K8sRequest = (cluster: Cluster, path: string, options?: RequestPromiseOptions) => Promise<any>;
|
||||
|
||||
const k8SRequestInjectable = getInjectable({
|
||||
id: "k8s-request",
|
||||
|
||||
instantiate: (di) => {
|
||||
const lensProxyPortNumberState = di.inject(lensProxyPortNumberStateInjectable);
|
||||
|
||||
return async (
|
||||
cluster: Cluster,
|
||||
path: string,
|
||||
options: RequestPromiseOptions = {},
|
||||
) => {
|
||||
const kubeProxyUrl = `http://localhost:${lensProxyPortNumberState.get()}${apiKubePrefix}`;
|
||||
|
||||
options.headers ??= {};
|
||||
options.json ??= true;
|
||||
options.timeout ??= 30000;
|
||||
options.headers.Host = `${cluster.id}.${new URL(kubeProxyUrl).host}`; // required in ClusterManager.getClusterForRequest()
|
||||
|
||||
return request(kubeProxyUrl + path, options);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default k8SRequestInjectable;
|
||||
@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { RequestPromiseOptions } from "request-promise-native";
|
||||
import request from "request-promise-native";
|
||||
import { apiKubePrefix } from "../common/vars";
|
||||
import type { IMetricsReqParams } from "../common/k8s-api/endpoints/metrics.api";
|
||||
import { LensProxy } from "./lens-proxy";
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
|
||||
export async function k8sRequest<T = any>(cluster: Cluster, path: string, options: RequestPromiseOptions = {}): Promise<T> {
|
||||
const kubeProxyUrl = `http://localhost:${LensProxy.getInstance().port}${apiKubePrefix}`;
|
||||
|
||||
options.headers ??= {};
|
||||
options.json ??= true;
|
||||
options.timeout ??= 30000;
|
||||
options.headers.Host = `${cluster.id}.${new URL(kubeProxyUrl).host}`; // required in ClusterManager.getClusterForRequest()
|
||||
|
||||
return request(kubeProxyUrl + path, options);
|
||||
}
|
||||
|
||||
export async function getMetrics(cluster: Cluster, prometheusPath: string, queryParams: IMetricsReqParams & { query: string }): Promise<any> {
|
||||
const prometheusPrefix = cluster.preferences.prometheus?.prefix || "";
|
||||
const metricsPath = `/api/v1/namespaces/${prometheusPath}/proxy${prometheusPrefix}/api/v1/query_range`;
|
||||
|
||||
return k8sRequest(cluster, metricsPath, {
|
||||
timeout: 0,
|
||||
resolveWithFullResponse: false,
|
||||
json: true,
|
||||
method: "POST",
|
||||
form: queryParams,
|
||||
});
|
||||
}
|
||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import directoryForTempInjectable from "../../common/app-paths/directory-for-temp/directory-for-temp.injectable";
|
||||
import { KubeconfigManager } from "./kubeconfig-manager";
|
||||
import lensProxyPortNumberStateInjectable from "../lens-proxy-port-number-state.injectable";
|
||||
|
||||
export interface KubeConfigManagerInstantiationParameter {
|
||||
cluster: Cluster;
|
||||
@ -17,6 +18,7 @@ const createKubeconfigManagerInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const dependencies = {
|
||||
directoryForTemp: di.inject(directoryForTempInjectable),
|
||||
lensProxyPortNumberState: di.inject(lensProxyPortNumberStateInjectable),
|
||||
};
|
||||
|
||||
return (cluster: Cluster) => new KubeconfigManager(dependencies, cluster);
|
||||
|
||||
@ -10,10 +10,10 @@ import path from "path";
|
||||
import fs from "fs-extra";
|
||||
import { dumpConfigYaml } from "../../common/kube-helpers";
|
||||
import logger from "../logger";
|
||||
import { LensProxy } from "../lens-proxy";
|
||||
|
||||
interface Dependencies {
|
||||
directoryForTemp: string;
|
||||
lensProxyPortNumberState: { get: () => number };
|
||||
}
|
||||
|
||||
export class KubeconfigManager {
|
||||
@ -79,7 +79,7 @@ export class KubeconfigManager {
|
||||
}
|
||||
|
||||
get resolveProxyUrl() {
|
||||
return `http://127.0.0.1:${LensProxy.getInstance().port}/${this.cluster.id}`;
|
||||
return `http://127.0.0.1:${this.dependencies.lensProxyPortNumberState.get()}/${this.cluster.id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
36
src/main/lens-proxy-port-number-state.injectable.ts
Normal file
36
src/main/lens-proxy-port-number-state.injectable.ts
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
const lensProxyPortNumberStateInjectable = getInjectable({
|
||||
id: "lens-proxy-port-number-state",
|
||||
|
||||
instantiate: () => {
|
||||
let _portNumber: number;
|
||||
|
||||
return {
|
||||
get: () => {
|
||||
if (!_portNumber) {
|
||||
throw new Error(
|
||||
"Tried to access port number of LensProxy while it has not been set yet.",
|
||||
);
|
||||
}
|
||||
|
||||
return _portNumber;
|
||||
},
|
||||
set: (portNumber: number) => {
|
||||
if (_portNumber) {
|
||||
throw new Error(
|
||||
"Tried to set port number for LensProxy when it has already been set.",
|
||||
);
|
||||
}
|
||||
|
||||
_portNumber = portNumber;
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default lensProxyPortNumberStateInjectable;
|
||||
14
src/main/lens-proxy-port-number.injectable.ts
Normal file
14
src/main/lens-proxy-port-number.injectable.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import lensProxyPortNumberStateInjectable from "./lens-proxy-port-number-state.injectable";
|
||||
|
||||
const lensProxyPortNumberInjectable = getInjectable({
|
||||
id: "lens-proxy-port-number",
|
||||
|
||||
instantiate: (di) => di.inject(lensProxyPortNumberStateInjectable).get(),
|
||||
});
|
||||
|
||||
export default lensProxyPortNumberInjectable;
|
||||
35
src/main/lens-proxy.injectable.ts
Normal file
35
src/main/lens-proxy.injectable.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { LensProxy } from "./lens-proxy";
|
||||
import { kubeApiUpgradeRequest } from "./proxy-functions";
|
||||
import routerInjectable from "./router/router.injectable";
|
||||
import httpProxy from "http-proxy";
|
||||
import clusterManagerInjectable from "./cluster-manager.injectable";
|
||||
import shellApiRequestInjectable from "./proxy-functions/shell-api-request/shell-api-request.injectable";
|
||||
import lensProxyPortNumberStateInjectable from "./lens-proxy-port-number-state.injectable";
|
||||
|
||||
const lensProxyInjectable = getInjectable({
|
||||
id: "lens-proxy",
|
||||
|
||||
instantiate: (di) => {
|
||||
const clusterManager = di.inject(clusterManagerInjectable);
|
||||
const router = di.inject(routerInjectable);
|
||||
const shellApiRequest = di.inject(shellApiRequestInjectable);
|
||||
const proxy = httpProxy.createProxy();
|
||||
const lensProxyPortNumberState = di.inject(lensProxyPortNumberStateInjectable);
|
||||
|
||||
return new LensProxy({
|
||||
router,
|
||||
proxy,
|
||||
kubeApiUpgradeRequest,
|
||||
shellApiRequest,
|
||||
getClusterForRequest: clusterManager.getClusterForRequest,
|
||||
lensProxyPortNumberState,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default lensProxyInjectable;
|
||||
@ -11,7 +11,6 @@ import { apiPrefix, apiKubePrefix } from "../common/vars";
|
||||
import type { Router } from "./router/router";
|
||||
import type { ContextHandler } from "./context-handler/context-handler";
|
||||
import logger from "./logger";
|
||||
import { Singleton } from "../common/utils";
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
import type { ProxyApiRequestArgs } from "./proxy-functions";
|
||||
import { appEventBus } from "../common/app-event-bus/event-bus";
|
||||
@ -19,10 +18,13 @@ import { getBoolean } from "./utils/parse-query";
|
||||
|
||||
type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | null;
|
||||
|
||||
export interface LensProxyFunctions {
|
||||
interface Dependencies {
|
||||
getClusterForRequest: GetClusterForRequest;
|
||||
shellApiRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||
kubeApiUpgradeRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||
router: Router;
|
||||
proxy: httpProxy;
|
||||
lensProxyPortNumberState: { set: (portNumber: number) => void };
|
||||
}
|
||||
|
||||
const watchParam = "watch";
|
||||
@ -52,21 +54,14 @@ const disallowedPorts = new Set([
|
||||
10080,
|
||||
]);
|
||||
|
||||
export class LensProxy extends Singleton {
|
||||
export class LensProxy {
|
||||
protected origin: string;
|
||||
protected proxyServer: http.Server;
|
||||
protected closed = false;
|
||||
protected retryCounters = new Map<string, number>();
|
||||
protected getClusterForRequest: GetClusterForRequest;
|
||||
|
||||
public port: number;
|
||||
|
||||
constructor(protected router: Router, protected proxy: httpProxy, { shellApiRequest, kubeApiUpgradeRequest, getClusterForRequest }: LensProxyFunctions) {
|
||||
super();
|
||||
|
||||
this.configureProxy(proxy);
|
||||
|
||||
this.getClusterForRequest = getClusterForRequest;
|
||||
constructor(private dependencies: Dependencies) {
|
||||
this.configureProxy(dependencies.proxy);
|
||||
|
||||
this.proxyServer = spdy.createServer({
|
||||
spdy: {
|
||||
@ -79,14 +74,14 @@ export class LensProxy extends Singleton {
|
||||
|
||||
this.proxyServer
|
||||
.on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
|
||||
const cluster = getClusterForRequest(req);
|
||||
const cluster = dependencies.getClusterForRequest(req);
|
||||
|
||||
if (!cluster) {
|
||||
logger.error(`[LENS-PROXY]: Could not find cluster for upgrade request from url=${req.url}`);
|
||||
socket.destroy();
|
||||
} else {
|
||||
const isInternal = req.url.startsWith(`${apiPrefix}?`);
|
||||
const reqHandler = isInternal ? shellApiRequest : kubeApiUpgradeRequest;
|
||||
const reqHandler = isInternal ? dependencies.shellApiRequest : dependencies.kubeApiUpgradeRequest;
|
||||
|
||||
(async () => reqHandler({ req, socket, head, cluster }))()
|
||||
.catch(error => logger.error("[LENS-PROXY]: failed to handle proxy upgrade", error));
|
||||
@ -110,13 +105,14 @@ export class LensProxy extends Singleton {
|
||||
|
||||
const { address, port } = this.proxyServer.address() as net.AddressInfo;
|
||||
|
||||
this.dependencies.lensProxyPortNumberState.set(port);
|
||||
|
||||
logger.info(`[LENS-PROXY]: Proxy server has started at ${address}:${port}`);
|
||||
|
||||
this.proxyServer.on("error", (error) => {
|
||||
logger.info(`[LENS-PROXY]: Subsequent error: ${error}`);
|
||||
});
|
||||
|
||||
this.port = port;
|
||||
appEventBus.emit({ name: "lens-proxy", action: "listen", params: { port }});
|
||||
resolve(port);
|
||||
})
|
||||
@ -228,15 +224,15 @@ export class LensProxy extends Singleton {
|
||||
}
|
||||
|
||||
protected async handleRequest(req: http.IncomingMessage, res: http.ServerResponse) {
|
||||
const cluster = this.getClusterForRequest(req);
|
||||
const cluster = this.dependencies.getClusterForRequest(req);
|
||||
|
||||
if (cluster) {
|
||||
const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler);
|
||||
|
||||
if (proxyTarget) {
|
||||
return this.proxy.web(req, res, proxyTarget);
|
||||
return this.dependencies.proxy.web(req, res, proxyTarget);
|
||||
}
|
||||
}
|
||||
this.router.route(cluster, req, res);
|
||||
this.dependencies.router.route(cluster, req, res);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { PrometheusProviderRegistry } from "./provider-registry";
|
||||
|
||||
const prometheusProviderRegistryInjectable = getInjectable({
|
||||
id: "prometheus-provider-registry",
|
||||
instantiate: () => new PrometheusProviderRegistry(),
|
||||
});
|
||||
|
||||
export default prometheusProviderRegistryInjectable;
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
import type { CoreV1Api } from "@kubernetes/client-node";
|
||||
import { inspect } from "util";
|
||||
import { Singleton } from "../../common/utils";
|
||||
|
||||
export interface PrometheusService {
|
||||
id: string;
|
||||
@ -65,7 +64,7 @@ export abstract class PrometheusProvider {
|
||||
}
|
||||
}
|
||||
|
||||
export class PrometheusProviderRegistry extends Singleton {
|
||||
export class PrometheusProviderRegistry {
|
||||
public providers = new Map<string, PrometheusProvider>();
|
||||
|
||||
getByKind(kind: string): PrometheusProvider {
|
||||
|
||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import extensionLoaderInjectable from "../../../extensions/extension-loader/extension-loader.injectable";
|
||||
import { LensProtocolRouterMain } from "./lens-protocol-router-main";
|
||||
import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable";
|
||||
import windowManagerInjectable from "../../window-manager.injectable";
|
||||
|
||||
const lensProtocolRouterMainInjectable = getInjectable({
|
||||
id: "lens-protocol-router-main",
|
||||
@ -14,6 +15,7 @@ const lensProtocolRouterMainInjectable = getInjectable({
|
||||
new LensProtocolRouterMain({
|
||||
extensionLoader: di.inject(extensionLoaderInjectable),
|
||||
extensionsStore: di.inject(extensionsStoreInjectable),
|
||||
windowManager: di.inject(windowManagerInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ import { observable, when, makeObservable } from "mobx";
|
||||
import type { RouteAttempt } from "../../../common/protocol-handler";
|
||||
import { ProtocolHandlerInvalid } from "../../../common/protocol-handler";
|
||||
import { disposer, noop } from "../../../common/utils";
|
||||
import { WindowManager } from "../../window-manager";
|
||||
import type { WindowManager } from "../../window-manager";
|
||||
import type { ExtensionLoader } from "../../../extensions/extension-loader";
|
||||
import type { ExtensionsStore } from "../../../extensions/extensions-store/extensions-store";
|
||||
|
||||
@ -40,6 +40,7 @@ function checkHost<Query>(url: URLParse<Query>): boolean {
|
||||
interface Dependencies {
|
||||
extensionLoader: ExtensionLoader;
|
||||
extensionsStore: ExtensionsStore;
|
||||
windowManager: WindowManager;
|
||||
}
|
||||
|
||||
export class LensProtocolRouterMain extends proto.LensProtocolRouter {
|
||||
@ -73,7 +74,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter {
|
||||
throw new proto.RoutingError(proto.RoutingErrorType.INVALID_PROTOCOL, url);
|
||||
}
|
||||
|
||||
WindowManager.getInstance(false)?.ensureMainWindow().catch(noop);
|
||||
this.dependencies.windowManager.ensureMainWindow().catch(noop);
|
||||
const routeInternally = checkHost(url);
|
||||
|
||||
logger.info(`${proto.LensProtocolRouter.LoggingPrefix}: routing ${url.toString()}`);
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
|
||||
import { app } from "electron";
|
||||
|
||||
const switchValue = app.commandLine.getSwitchValue("proxy-server");
|
||||
|
||||
export function mangleProxyEnv() {
|
||||
const switchValue = app.commandLine.getSwitchValue("proxy-server");
|
||||
|
||||
let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || "";
|
||||
|
||||
delete process.env.HTTPS_PROXY;
|
||||
@ -20,4 +20,8 @@ export function mangleProxyEnv() {
|
||||
if (httpsProxy !== "") {
|
||||
process.env.APP_HTTPS_PROXY = httpsProxy;
|
||||
}
|
||||
|
||||
if (app.commandLine.getSwitchValue("proxy-server") !== "") {
|
||||
process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server");
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { shellApiRequest } from "./shell-api-request";
|
||||
import createShellSessionInjectable from "../../shell-session/create-shell-session.injectable";
|
||||
import shellRequestAuthenticatorInjectable
|
||||
from "./shell-request-authenticator/shell-request-authenticator.injectable";
|
||||
import shellRequestAuthenticatorInjectable from "./shell-request-authenticator/shell-request-authenticator.injectable";
|
||||
import clusterManagerInjectable from "../../cluster-manager.injectable";
|
||||
|
||||
const shellApiRequestInjectable = getInjectable({
|
||||
id: "shell-api-request",
|
||||
@ -14,6 +14,7 @@ const shellApiRequestInjectable = getInjectable({
|
||||
instantiate: (di) => shellApiRequest({
|
||||
createShellSession: di.inject(createShellSessionInjectable),
|
||||
authenticateRequest: di.inject(shellRequestAuthenticatorInjectable).authenticate,
|
||||
clusterManager: di.inject(clusterManagerInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import logger from "../../logger";
|
||||
import type WebSocket from "ws";
|
||||
import { Server as WebSocketServer } from "ws";
|
||||
import type { ProxyApiRequestArgs } from "../types";
|
||||
import { ClusterManager } from "../../cluster-manager";
|
||||
import type { ClusterManager } from "../../cluster-manager";
|
||||
import URLParse from "url-parse";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import type { ClusterId } from "../../../common/cluster-types";
|
||||
@ -21,10 +21,12 @@ interface Dependencies {
|
||||
tabId: string;
|
||||
nodeName?: string;
|
||||
}) => { open: () => Promise<void> };
|
||||
|
||||
clusterManager: ClusterManager;
|
||||
}
|
||||
|
||||
export const shellApiRequest = ({ createShellSession, authenticateRequest }: Dependencies) => ({ req, socket, head }: ProxyApiRequestArgs): void => {
|
||||
const cluster = ClusterManager.getInstance().getClusterForRequest(req);
|
||||
export const shellApiRequest = ({ createShellSession, authenticateRequest, clusterManager }: Dependencies) => ({ req, socket, head }: ProxyApiRequestArgs): void => {
|
||||
const cluster = clusterManager.getClusterForRequest(req);
|
||||
const { query: { node: nodeName, shellToken, id: tabId }} = new URLParse(req.url, true);
|
||||
|
||||
if (!cluster || !authenticateRequest(cluster.id, tabId, shellToken)) {
|
||||
|
||||
@ -11,13 +11,14 @@ import type { ClusterPrometheusMetadata } from "../../../common/cluster-types";
|
||||
import { ClusterMetadataKey } from "../../../common/cluster-types";
|
||||
import logger from "../../logger";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { getMetrics } from "../../k8s-request";
|
||||
import type { IMetricsQuery } from "./metrics-query";
|
||||
import type { GetMetrics } from "../../get-metrics.injectable";
|
||||
import getMetricsInjectable from "../../get-metrics.injectable";
|
||||
|
||||
// This is used for backoff retry tracking.
|
||||
const ATTEMPTS = [false, false, false, false, true];
|
||||
|
||||
async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPath: string, queryParams: Record<string, string>): Promise<any[]> {
|
||||
const loadMetricsFor = (getMetrics: GetMetrics) => async (promQueries: string[], cluster: Cluster, prometheusPath: string, queryParams: Record<string, string>): Promise<any[]> => {
|
||||
const queries = promQueries.map(p => p.trim());
|
||||
const loaders = new Map<string, Promise<any>>();
|
||||
|
||||
@ -41,9 +42,11 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa
|
||||
}
|
||||
|
||||
return Promise.all(queries.map(loadMetric));
|
||||
}
|
||||
};
|
||||
|
||||
const addMetricsRoute = (getMetrics: GetMetrics) => async ({ cluster, payload, query }: LensApiRequest) => {
|
||||
const loadMetrics = loadMetricsFor(getMetrics);
|
||||
|
||||
const addMetricsRoute = async ({ cluster, payload, query }: LensApiRequest) => {
|
||||
const queryParams: IMetricsQuery = Object.fromEntries(query.entries());
|
||||
const prometheusMetadata: ClusterPrometheusMetadata = {};
|
||||
|
||||
@ -97,11 +100,15 @@ const addMetricsRoute = async ({ cluster, payload, query }: LensApiRequest) => {
|
||||
const addMetricsRouteInjectable = getInjectable({
|
||||
id: "add-metrics-route",
|
||||
|
||||
instantiate: (): Route<any> => ({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/metrics`,
|
||||
handler: addMetricsRoute,
|
||||
}),
|
||||
instantiate: (di): Route<any> => {
|
||||
const getMetrics = di.inject(getMetricsInjectable);
|
||||
|
||||
return {
|
||||
method: "post",
|
||||
path: `${apiPrefix}/metrics`,
|
||||
handler: addMetricsRoute(getMetrics),
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
});
|
||||
|
||||
@ -7,26 +7,34 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import type { Route } from "../../router/router";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import { PrometheusProviderRegistry } from "../../prometheus";
|
||||
import type { MetricProviderInfo } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
import prometheusProviderRegistryInjectable from "../../prometheus/prometheus-provider-registry.injectable";
|
||||
|
||||
const getMetricProvidersRouteInjectable = getInjectable({
|
||||
id: "get-metric-providers-route",
|
||||
|
||||
instantiate: (): Route<MetricProviderInfo[]> => ({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/metrics/providers`,
|
||||
instantiate: (di): Route<MetricProviderInfo[]> => {
|
||||
const prometheusProviderRegistry = di.inject(prometheusProviderRegistryInjectable);
|
||||
|
||||
handler: () => {
|
||||
const providers: MetricProviderInfo[] = [];
|
||||
return {
|
||||
method: "get",
|
||||
path: `${apiPrefix}/metrics/providers`,
|
||||
|
||||
for (const { name, id, isConfigurable } of PrometheusProviderRegistry.getInstance().providers.values()) {
|
||||
providers.push({ name, id, isConfigurable });
|
||||
}
|
||||
handler: () => {
|
||||
const providers: MetricProviderInfo[] = [];
|
||||
|
||||
return { response: providers };
|
||||
},
|
||||
}),
|
||||
for (const {
|
||||
name,
|
||||
id,
|
||||
isConfigurable,
|
||||
} of prometheusProviderRegistry.providers.values()) {
|
||||
providers.push({ name, id, isConfigurable });
|
||||
}
|
||||
|
||||
return { response: providers };
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
});
|
||||
|
||||
32
src/main/stop-services-and-exit-app.injectable.ts
Normal file
32
src/main/stop-services-and-exit-app.injectable.ts
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import exitAppInjectable from "./app-paths/get-electron-app-path/electron-app/exit-app.injectable";
|
||||
import clusterManagerInjectable from "./cluster-manager.injectable";
|
||||
import windowManagerInjectable from "./window-manager.injectable";
|
||||
import appEventBusInjectable from "../common/app-event-bus/app-event-bus.injectable";
|
||||
import loggerInjectable from "../common/logger.injectable";
|
||||
|
||||
const stopServicesAndExitAppInjectable = getInjectable({
|
||||
id: "stop-services-and-exit-app",
|
||||
|
||||
instantiate: (di) => {
|
||||
const exitApp = di.inject(exitAppInjectable);
|
||||
const windowManager = di.inject(windowManagerInjectable);
|
||||
const clusterManager = di.inject(clusterManagerInjectable);
|
||||
const appEventBus = di.inject(appEventBusInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return () => {
|
||||
appEventBus.emit({ name: "service", action: "close" });
|
||||
windowManager.hide();
|
||||
clusterManager.stop();
|
||||
logger.info("SERVICE:QUIT");
|
||||
setTimeout(exitApp, 1000);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default stopServicesAndExitAppInjectable;
|
||||
@ -4,15 +4,15 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { WindowManager } from "./window-manager";
|
||||
import lensProxyPortNumberStateInjectable from "./lens-proxy-port-number-state.injectable";
|
||||
|
||||
const windowManagerInjectable = getInjectable({
|
||||
id: "window-manager",
|
||||
|
||||
instantiate: () => {
|
||||
WindowManager.resetInstance();
|
||||
|
||||
return WindowManager.createInstance();
|
||||
},
|
||||
instantiate: (di) =>
|
||||
new WindowManager({
|
||||
lensProxyPortNumberState: di.inject(lensProxyPortNumberStateInjectable),
|
||||
}),
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
@ -9,13 +9,12 @@ import { app, BrowserWindow, dialog, ipcMain, webContents } from "electron";
|
||||
import windowStateKeeper from "electron-window-state";
|
||||
import { appEventBus } from "../common/app-event-bus/event-bus";
|
||||
import { ipcMainOn } from "../common/ipc";
|
||||
import { delay, iter, Singleton, openBrowser } from "../common/utils";
|
||||
import { delay, iter, openBrowser } from "../common/utils";
|
||||
import type { ClusterFrameInfo } from "../common/cluster-frames";
|
||||
import { clusterFrameMap } from "../common/cluster-frames";
|
||||
import { ClusterFrameInfo, clusterFrameMap } from "../common/cluster-frames";
|
||||
import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
|
||||
import logger from "./logger";
|
||||
import { isMac, productName } from "../common/vars";
|
||||
import { LensProxy } from "./lens-proxy";
|
||||
import { bundledExtensionsLoaded } from "../common/ipc/extension-handling";
|
||||
|
||||
function isHideable(window: BrowserWindow | null): boolean {
|
||||
@ -28,9 +27,11 @@ export interface SendToViewArgs {
|
||||
data?: any[];
|
||||
}
|
||||
|
||||
export class WindowManager extends Singleton {
|
||||
public mainContentUrl = `http://localhost:${LensProxy.getInstance().port}`;
|
||||
interface Dependencies {
|
||||
lensProxyPortNumberState: { get: () => number };
|
||||
}
|
||||
|
||||
export class WindowManager {
|
||||
protected mainWindow: BrowserWindow;
|
||||
protected splashWindow: BrowserWindow;
|
||||
protected windowState: windowStateKeeper.State;
|
||||
@ -38,12 +39,15 @@ export class WindowManager extends Singleton {
|
||||
|
||||
@observable activeClusterId: ClusterId;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
constructor(private dependencies: Dependencies) {
|
||||
makeObservable(this);
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
get mainContentUrl() {
|
||||
return `http://localhost:${this.dependencies.lensProxyPortNumberState.get()}`;
|
||||
}
|
||||
|
||||
private async initMainWindow(showSplash: boolean) {
|
||||
// Manage main window size and position with state persistence
|
||||
if (!this.windowState) {
|
||||
|
||||
@ -14,11 +14,15 @@ const createClusterInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const dependencies: ClusterDependencies = {
|
||||
directoryForKubeConfigs: di.inject(directoryForKubeConfigsInjectable),
|
||||
|
||||
// TODO: Dismantle wrong abstraction
|
||||
createKubeconfigManager: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
createKubectl: () => { throw new Error("Tried to access back-end feature in front-end.");},
|
||||
createContextHandler: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
createAuthorizationReview: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
createListNamespaces: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
detectorRegistry: null,
|
||||
createVersionDetector: () => { throw new Error("Tried to access back-end feature in front-end."); },
|
||||
};
|
||||
|
||||
return (model) => new Cluster(dependencies, model);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user