mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove a lot of usages of legacy globals (#6825)
* Remove all usages of legacy global logger Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global storageClassApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global serviceApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global secretApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global resourceQuotaApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global persistentVolumeClaimApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global nodeApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global networkPolicyApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix formatting Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global configMapApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global jobApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global cronJobApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global podApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global roleApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove exports of NonInjected components - To improve auto-complete Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global catalogEntityRegistry Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add lint against using legacy global works Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix lint in KubeObject file Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global catalogCategoryRegistry Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global navigation Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global navigate Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove unneeded index file Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global customResourceDefinitionStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global eventStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global podSecurityPolicyStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global storageClassStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global persistentVolumeStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global clusterRoleBindingStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global clusterRoleStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global roleBindingStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move files around Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global roleStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global serviceAccountStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usages of legacy global podStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove final uses of asLegacyGlobalForExtensionApi in application code Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix lint rule and start fixing lint errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make listHelmReleases injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make installHelmChart injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make deleteHelmRelease injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make getHelmReleaseValues injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make getHelmReleaseHistory injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make rollbackHelmRelease injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove unnecessary overrides from getDiForUnitTesting Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add global override for logger Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add global override for history Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cleanup typing around getting injectables within jest Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move some more overrides to global if needed Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add global override for forcusWindow Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix lint in KubeApi Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix lint in catalog/index.ts Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove last usages of legacy global getDetailsUrl Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove last usages of legacy global showDetails Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add functions back to extension API Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove all uses of legacy global Notification functions Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove no longer existing export Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove unnecessary overrides Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix injecting side effects by using more injectables Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix cluster role binding dialog Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix cluster role dialog Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix create service account dialog Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix history override Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make KubeApi consume its dependencies while not breaking the extension API Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix CephFs tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix user store tests by using override of config Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of mockFs in hotbar store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add direct devDep of memfs Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of mockFs in cluster store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of mockFs in router tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of mockFs in kube auth proxy tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of mockFs in log resource selector tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of mockFs in hotbar remove command tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of mockFs in the select component tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove mock-fs as a dependency Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove no longer necessary mocks Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix namespace select filter tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of mockFs in the extension loader tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fixing edit-namespace-from-new-tab test Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix app paths tests by making the tests run in "production" mode Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove last vestiges of isTestEnv and the is* globals Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix delete-cluster-dialog tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix install-helm-chart-from-previously-opened-tab tests - Split out storage initialization to a runnable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove unnecessary override of non side effect injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix disable-kube-object-detail-items-when-cluster-is-not-relevant tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix reactively-hide-kube-object-detail-item tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix lint Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix sidebar-and-tab-navigation-for-core tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove need to override lensLocalStoragePath in tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Replace more overrides with global ones Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix typings Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove no longer needed technical test Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
900a8bbda3
commit
2b33d5eed6
530 files changed
+11320
-5399
No files matched your search
@@ -3,7 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable";
|
||||
import { Console } from "console";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import { Kubectl } from "../kubectl/kubectl";
|
||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
@@ -25,8 +24,6 @@ import pathExistsInjectable from "../../common/fs/path-exists.injectable";
|
||||
import readJsonSyncInjectable from "../../common/fs/read-json-sync.injectable";
|
||||
import writeJsonSyncInjectable from "../../common/fs/write-json-sync.injectable";
|
||||
|
||||
console = new Console(process.stdout, process.stderr); // fix mockFS
|
||||
|
||||
describe("create clusters", () => {
|
||||
let cluster: Cluster;
|
||||
let createCluster: CreateCluster;
|
||||
|
||||
@@ -12,28 +12,21 @@ import type { DeepMockProxy } from "jest-mock-extended";
|
||||
import { mockDeep, mock } from "jest-mock-extended";
|
||||
import type { Readable } from "stream";
|
||||
import { EventEmitter } from "stream";
|
||||
import { Console } from "console";
|
||||
import { stdout, stderr } from "process";
|
||||
import mockFs from "mock-fs";
|
||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
import type { CreateCluster } from "../../common/cluster/create-cluster-injection-token";
|
||||
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
||||
import path from "path";
|
||||
import spawnInjectable from "../child-process/spawn.injectable";
|
||||
import getConfigurationFileModelInjectable from "../../common/get-configuration-file-model/get-configuration-file-model.injectable";
|
||||
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import directoryForTempInjectable from "../../common/app-paths/directory-for-temp/directory-for-temp.injectable";
|
||||
import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable";
|
||||
import kubectlBinaryNameInjectable from "../kubectl/binary-name.injectable";
|
||||
import kubectlDownloadingNormalizedArchInjectable from "../kubectl/normalized-arch.injectable";
|
||||
import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable";
|
||||
import pathExistsInjectable from "../../common/fs/path-exists.injectable";
|
||||
import readJsonSyncInjectable from "../../common/fs/read-json-sync.injectable";
|
||||
import writeJsonSyncInjectable from "../../common/fs/write-json-sync.injectable";
|
||||
import pathExistsSyncInjectable from "../../common/fs/path-exists-sync.injectable";
|
||||
|
||||
console = new Console(stdout, stderr);
|
||||
import ensureDirInjectable from "../../common/fs/ensure-dir.injectable";
|
||||
import type { GetBasenameOfPath } from "../../common/path/get-basename.injectable";
|
||||
import getBasenameOfPathInjectable from "../../common/path/get-basename.injectable";
|
||||
|
||||
const clusterServerUrl = "https://192.168.64.3:8443";
|
||||
|
||||
@@ -43,44 +36,42 @@ describe("kube auth proxy tests", () => {
|
||||
let spawnMock: jest.Mock;
|
||||
let waitUntilPortIsUsedMock: jest.Mock;
|
||||
let broadcastMessageMock: jest.Mock;
|
||||
let getBasenameOfPath: GetBasenameOfPath;
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
const mockMinikubeConfig = {
|
||||
"minikube-config.yml": JSON.stringify({
|
||||
apiVersion: "v1",
|
||||
clusters: [{
|
||||
name: "minikube",
|
||||
cluster: {
|
||||
server: clusterServerUrl,
|
||||
},
|
||||
}],
|
||||
"current-context": "minikube",
|
||||
contexts: [{
|
||||
context: {
|
||||
cluster: "minikube",
|
||||
user: "minikube",
|
||||
},
|
||||
name: "minikube",
|
||||
}],
|
||||
users: [{
|
||||
name: "minikube",
|
||||
}],
|
||||
kind: "Config",
|
||||
preferences: {},
|
||||
}),
|
||||
"tmp": {},
|
||||
};
|
||||
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
di.override(directoryForTempInjectable, () => "some-directory-for-temp");
|
||||
di.override(pathExistsInjectable, () => () => { throw new Error("tried call pathExists without override"); });
|
||||
di.override(pathExistsSyncInjectable, () => () => { throw new Error("tried call pathExistsSync without override"); });
|
||||
di.override(readJsonSyncInjectable, () => () => { throw new Error("tried call readJsonSync without override"); });
|
||||
di.override(writeJsonSyncInjectable, () => () => { throw new Error("tried call writeJsonSync without override"); });
|
||||
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
|
||||
di.override(directoryForTempInjectable, () => "/some-directory-for-temp");
|
||||
|
||||
const writeJsonSync = di.inject(writeJsonSyncInjectable);
|
||||
const ensureDir = di.inject(ensureDirInjectable);
|
||||
|
||||
getBasenameOfPath = di.inject(getBasenameOfPathInjectable);
|
||||
|
||||
writeJsonSync("/minikube-config.yml", {
|
||||
apiVersion: "v1",
|
||||
clusters: [{
|
||||
name: "minikube",
|
||||
cluster: {
|
||||
server: clusterServerUrl,
|
||||
},
|
||||
}],
|
||||
"current-context": "minikube",
|
||||
contexts: [{
|
||||
context: {
|
||||
cluster: "minikube",
|
||||
user: "minikube",
|
||||
},
|
||||
name: "minikube",
|
||||
}],
|
||||
users: [{
|
||||
name: "minikube",
|
||||
}],
|
||||
kind: "Config",
|
||||
preferences: {},
|
||||
});
|
||||
await ensureDir("/tmp");
|
||||
|
||||
spawnMock = jest.fn();
|
||||
di.override(spawnInjectable, () => spawnMock);
|
||||
@@ -95,19 +86,10 @@ describe("kube auth proxy tests", () => {
|
||||
di.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
|
||||
di.override(normalizedPlatformInjectable, () => "darwin");
|
||||
|
||||
di.permitSideEffects(getConfigurationFileModelInjectable);
|
||||
|
||||
mockFs(mockMinikubeConfig);
|
||||
|
||||
createCluster = di.inject(createClusterInjectionToken);
|
||||
|
||||
createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it("calling exit multiple times shouldn't throw", async () => {
|
||||
const cluster = createCluster({
|
||||
id: "foobar",
|
||||
@@ -197,7 +179,7 @@ describe("kube auth proxy tests", () => {
|
||||
return stdout;
|
||||
});
|
||||
spawnMock.mockImplementationOnce((command: string): ChildProcess => {
|
||||
expect(path.basename(command).split(".")[0]).toBe("lens-k8s-proxy");
|
||||
expect(getBasenameOfPath(command).split(".")[0]).toBe("lens-k8s-proxy");
|
||||
|
||||
return mockedCP;
|
||||
});
|
||||
|
||||
@@ -7,22 +7,6 @@ import type { LensApiRequest, Route } from "../router/route";
|
||||
import staticFileRouteInjectable from "../routes/files/static-file-route.injectable";
|
||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
app: {
|
||||
getVersion: () => "99.99.99",
|
||||
getName: () => "lens",
|
||||
setName: jest.fn(),
|
||||
setPath: jest.fn(),
|
||||
getPath: () => "tmp",
|
||||
getLocale: () => "en",
|
||||
setLoginItemSettings: jest.fn(),
|
||||
},
|
||||
ipcMain: {
|
||||
on: jest.fn(),
|
||||
handle: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe("static-file-route", () => {
|
||||
let handleStaticFileRoute: Route<Buffer, "/{path*}">;
|
||||
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../../common/test-utils/get-global-override";
|
||||
import directoryForIntegrationTestingInjectable from "./directory-for-integration-testing.injectable";
|
||||
|
||||
export default getGlobalOverride(directoryForIntegrationTestingInjectable, () => undefined);
|
||||
+2
-7
@@ -3,16 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import environmentVariablesInjectable from "../../../common/utils/environment-variables.injectable";
|
||||
|
||||
const directoryForIntegrationTestingInjectable = getInjectable({
|
||||
id: "directory-for-integration-testing",
|
||||
|
||||
instantiate: (di) => {
|
||||
const environmentVariables = di.inject(environmentVariablesInjectable);
|
||||
|
||||
return environmentVariables.CICD;
|
||||
},
|
||||
instantiate: () => process.env.CICD,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default directoryForIntegrationTestingInjectable;
|
||||
@@ -3,15 +3,29 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { PathName } from "../../../common/app-paths/app-path-names";
|
||||
import electronAppInjectable from "../../electron-app/electron-app.injectable";
|
||||
import { getElectronAppPath } from "./get-electron-app-path";
|
||||
|
||||
export type GetElectronAppPath = (name: PathName | "currentApp") => string;
|
||||
|
||||
const getElectronAppPathInjectable = getInjectable({
|
||||
id: "get-electron-app-path",
|
||||
|
||||
instantiate: (di) => getElectronAppPath({
|
||||
app: di.inject(electronAppInjectable),
|
||||
}),
|
||||
instantiate: (di): GetElectronAppPath => {
|
||||
const electronApp = di.inject(electronAppInjectable);
|
||||
|
||||
return (name) => {
|
||||
try {
|
||||
if (name === "currentApp") {
|
||||
return electronApp.getAppPath();
|
||||
}
|
||||
|
||||
return electronApp.getPath(name);
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default getElectronAppPathInjectable;
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { App } from "electron";
|
||||
import type { PathName } from "../../../common/app-paths/app-path-names";
|
||||
|
||||
interface Dependencies {
|
||||
app: App;
|
||||
}
|
||||
|
||||
export type GetElectronAppPath = (name: PathName | "currentApp") => string;
|
||||
|
||||
export const getElectronAppPath = ({
|
||||
app,
|
||||
}: Dependencies): GetElectronAppPath => (
|
||||
(name) => {
|
||||
try {
|
||||
if (name === "currentApp") {
|
||||
return app.getAppPath();
|
||||
}
|
||||
|
||||
return app.getPath(name);
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -6,11 +6,16 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { PathName } from "../../../common/app-paths/app-path-names";
|
||||
import electronAppInjectable from "../../electron-app/electron-app.injectable";
|
||||
|
||||
export type SetElectronAppPath = (name: PathName, path: string) => void;
|
||||
|
||||
const setElectronAppPathInjectable = getInjectable({
|
||||
id: "set-electron-app-path",
|
||||
|
||||
instantiate: (di) => (name: PathName, path: string) : void =>
|
||||
di.inject(electronAppInjectable).setPath(name, path),
|
||||
instantiate: (di): SetElectronAppPath => {
|
||||
const electronApp = di.inject(electronAppInjectable);
|
||||
|
||||
return (name, path) => electronApp.setPath(name, path);
|
||||
},
|
||||
});
|
||||
|
||||
export default setElectronAppPathInjectable;
|
||||
@@ -21,7 +21,7 @@ const setupAppPathsInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const setElectronAppPath = di.inject(setElectronAppPathInjectable);
|
||||
const appName = di.inject(appNameInjectable);
|
||||
const getAppPath = di.inject(getElectronAppPathInjectable);
|
||||
const getElectronAppPath = di.inject(getElectronAppPathInjectable);
|
||||
const appPathsState = di.inject(appPathsStateInjectable);
|
||||
const directoryForIntegrationTesting = di.inject(directoryForIntegrationTestingInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
@@ -33,13 +33,13 @@ const setupAppPathsInjectable = getInjectable({
|
||||
setElectronAppPath("appData", directoryForIntegrationTesting);
|
||||
}
|
||||
|
||||
const appDataPath = getAppPath("appData");
|
||||
const appDataPath = getElectronAppPath("appData");
|
||||
|
||||
setElectronAppPath("userData", joinPaths(appDataPath, appName));
|
||||
|
||||
const appPaths = pipeline(
|
||||
pathNames,
|
||||
map(name => [name, getAppPath(name)]),
|
||||
map(name => [name, getElectronAppPath(name)]),
|
||||
fromPairs,
|
||||
) as AppPaths;
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { reaction } from "mobx";
|
||||
import { broadcastMessage, ipcMainOn } from "../common/ipc";
|
||||
import type { CatalogEntityRegistry } from "./catalog";
|
||||
import "../common/catalog-entities/kubernetes-cluster";
|
||||
import { disposer, toJS } from "../common/utils";
|
||||
import { debounce } from "lodash";
|
||||
import type { CatalogEntity } from "../common/catalog";
|
||||
import { catalogInitChannel, catalogItemsChannel } from "../common/ipc/catalog";
|
||||
|
||||
const broadcaster = debounce((items: CatalogEntity[]) => {
|
||||
broadcastMessage(catalogItemsChannel, items);
|
||||
}, 100, { leading: true, trailing: true });
|
||||
|
||||
export function pushCatalogToRenderer(catalog: CatalogEntityRegistry) {
|
||||
broadcaster(toJS(catalog.items));
|
||||
}
|
||||
|
||||
export function startCatalogSyncToRenderer(catalog: CatalogEntityRegistry) {
|
||||
return disposer(
|
||||
ipcMainOn(catalogInitChannel, () => broadcaster(toJS(catalog.items))),
|
||||
reaction(() => toJS(catalog.items), (items) => {
|
||||
broadcaster(items);
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { debounce } from "lodash";
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import catalogSyncBroadcasterInjectable from "./broadcaster.injectable";
|
||||
|
||||
export default getGlobalOverride(catalogSyncBroadcasterInjectable, () => debounce(() => {}));
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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 { debounce } from "lodash";
|
||||
import type { CatalogEntity } from "../../common/catalog";
|
||||
import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable";
|
||||
import { catalogItemsChannel } from "../../common/ipc/catalog";
|
||||
|
||||
const catalogSyncBroadcasterInjectable = getInjectable({
|
||||
id: "catalog-sync-broadcaster",
|
||||
instantiate: (di) => {
|
||||
const broadcastMessage = di.inject(broadcastMessageInjectable);
|
||||
|
||||
return debounce(
|
||||
(items: CatalogEntity[]) => {
|
||||
broadcastMessage(catalogItemsChannel, items);
|
||||
},
|
||||
100,
|
||||
{
|
||||
leading: true,
|
||||
trailing: true,
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default catalogSyncBroadcasterInjectable;
|
||||
@@ -3,23 +3,40 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { startCatalogSyncToRenderer } from "../catalog-pusher";
|
||||
import { reaction } from "mobx";
|
||||
import { catalogInitChannel } from "../../common/ipc/catalog";
|
||||
import { disposer, toJS } from "../../common/utils";
|
||||
import { getStartableStoppable } from "../../common/utils/get-startable-stoppable";
|
||||
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
||||
import ipcMainInjectable from "../utils/channel/ipc-main/ipc-main.injectable";
|
||||
import catalogSyncBroadcasterInjectable from "./broadcaster.injectable";
|
||||
|
||||
const catalogSyncToRendererInjectable = getInjectable({
|
||||
id: "catalog-sync-to-renderer",
|
||||
|
||||
instantiate: (di) => {
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
const ipcMain = di.inject(ipcMainInjectable);
|
||||
const catalogSyncBroadcaster = di.inject(catalogSyncBroadcasterInjectable);
|
||||
|
||||
return getStartableStoppable(
|
||||
"catalog-sync",
|
||||
() => startCatalogSyncToRenderer(catalogEntityRegistry),
|
||||
() => {
|
||||
const initChannelHandler = () => catalogSyncBroadcaster(toJS(catalogEntityRegistry.items));
|
||||
|
||||
ipcMain.on(catalogInitChannel, initChannelHandler);
|
||||
|
||||
return disposer(
|
||||
() => ipcMain.off(catalogInitChannel, initChannelHandler),
|
||||
reaction(() => toJS(catalogEntityRegistry.items), (items) => {
|
||||
catalogSyncBroadcaster(items);
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default catalogSyncToRendererInjectable;
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 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 { toJS } from "../../common/utils";
|
||||
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
||||
import catalogSyncBroadcasterInjectable from "./broadcaster.injectable";
|
||||
|
||||
const pushCatalogToRendererInjectable = getInjectable({
|
||||
id: "push-catalog-to-renderer",
|
||||
instantiate: (di) => {
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
const catalogSyncBroadcaster = di.inject(catalogSyncBroadcasterInjectable);
|
||||
|
||||
return () => catalogSyncBroadcaster(toJS(catalogEntityRegistry.items));
|
||||
},
|
||||
});
|
||||
|
||||
export default pushCatalogToRendererInjectable;
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { asLegacyGlobalForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||
import catalogEntityRegistryInjectable from "./entity-registry.injectable";
|
||||
|
||||
/**
|
||||
* @deprecated use `di.inject(catalogEntityRegistryInjectable)` instead
|
||||
*/
|
||||
export const catalogEntityRegistry = asLegacyGlobalForExtensionApi(catalogEntityRegistryInjectable);
|
||||
@@ -3,5 +3,4 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export * from "./catalog-entity-registry";
|
||||
export * from "./entity-registry";
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import clusterStoreInjectable from "../../common/cluster-store/cluster-store.injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
||||
import clustersThatAreBeingDeletedInjectable from "./are-being-deleted.injectable";
|
||||
import { ClusterManager } from "./manager";
|
||||
@@ -17,6 +18,7 @@ const clusterManagerInjectable = getInjectable({
|
||||
catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||
clustersThatAreBeingDeleted: di.inject(clustersThatAreBeingDeletedInjectable),
|
||||
visibleCluster: di.inject(visibleClusterInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
+13
-35
@@ -4,13 +4,10 @@
|
||||
*/
|
||||
|
||||
import "../../common/ipc/cluster";
|
||||
import type http from "http";
|
||||
import type { IObservableValue, ObservableSet } from "mobx";
|
||||
import { action, makeObservable, observe, reaction, toJS } from "mobx";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import logger from "../logger";
|
||||
import { apiKubePrefix } from "../../common/vars";
|
||||
import { getClusterIdFromHost, isErrnoException } from "../../common/utils";
|
||||
import { isErrnoException } from "../../common/utils";
|
||||
import type { KubernetesClusterPrometheusMetrics } from "../../common/catalog-entities/kubernetes-cluster";
|
||||
import { isKubernetesCluster, KubernetesCluster, LensKubernetesClusterStatus } from "../../common/catalog-entities/kubernetes-cluster";
|
||||
import { ipcMainOn } from "../../common/ipc";
|
||||
@@ -18,6 +15,7 @@ import { once } from "lodash";
|
||||
import type { ClusterStore } from "../../common/cluster-store/cluster-store";
|
||||
import type { ClusterId } from "../../common/cluster-types";
|
||||
import type { CatalogEntityRegistry } from "../catalog";
|
||||
import type { Logger } from "../../common/logger";
|
||||
|
||||
const logPrefix = "[CLUSTER-MANAGER]:";
|
||||
|
||||
@@ -28,6 +26,7 @@ interface Dependencies {
|
||||
readonly catalogEntityRegistry: CatalogEntityRegistry;
|
||||
readonly clustersThatAreBeingDeleted: ObservableSet<ClusterId>;
|
||||
readonly visibleCluster: IObservableValue<ClusterId | null>;
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
export class ClusterManager {
|
||||
@@ -80,7 +79,7 @@ export class ClusterManager {
|
||||
|
||||
@action
|
||||
protected updateCatalog(clusters: Cluster[]) {
|
||||
logger.debug("[CLUSTER-MANAGER]: updating catalog from cluster store");
|
||||
this.dependencies.logger.debug("[CLUSTER-MANAGER]: updating catalog from cluster store");
|
||||
|
||||
for (const cluster of clusters) {
|
||||
this.updateEntityFromCluster(cluster);
|
||||
@@ -146,31 +145,31 @@ export class ClusterManager {
|
||||
} else {
|
||||
entity.status.phase = (() => {
|
||||
if (!cluster) {
|
||||
logger.debug(`${logPrefix} setting entity ${entity.getName()} to DISCONNECTED, reason="no cluster"`);
|
||||
this.dependencies.logger.debug(`${logPrefix} setting entity ${entity.getName()} to DISCONNECTED, reason="no cluster"`);
|
||||
|
||||
return LensKubernetesClusterStatus.DISCONNECTED;
|
||||
}
|
||||
|
||||
if (cluster.accessible) {
|
||||
logger.debug(`${logPrefix} setting entity ${entity.getName()} to CONNECTED, reason="cluster is accessible"`);
|
||||
this.dependencies.logger.debug(`${logPrefix} setting entity ${entity.getName()} to CONNECTED, reason="cluster is accessible"`);
|
||||
|
||||
return LensKubernetesClusterStatus.CONNECTED;
|
||||
}
|
||||
|
||||
if (!cluster.disconnected) {
|
||||
logger.debug(`${logPrefix} setting entity ${entity.getName()} to CONNECTING, reason="cluster is not disconnected"`);
|
||||
this.dependencies.logger.debug(`${logPrefix} setting entity ${entity.getName()} to CONNECTING, reason="cluster is not disconnected"`);
|
||||
|
||||
return LensKubernetesClusterStatus.CONNECTING;
|
||||
}
|
||||
|
||||
// Extensions are not allowed to use the Lens specific status phases
|
||||
if (!lensSpecificClusterStatuses.has(entity?.status?.phase)) {
|
||||
logger.debug(`${logPrefix} not clearing entity ${entity.getName()} status, reason="custom string"`);
|
||||
this.dependencies.logger.debug(`${logPrefix} not clearing entity ${entity.getName()} status, reason="custom string"`);
|
||||
|
||||
return entity.status.phase;
|
||||
}
|
||||
|
||||
logger.debug(`${logPrefix} setting entity ${entity.getName()} to DISCONNECTED, reason="fallthrough"`);
|
||||
this.dependencies.logger.debug(`${logPrefix} setting entity ${entity.getName()} to DISCONNECTED, reason="fallthrough"`);
|
||||
|
||||
return LensKubernetesClusterStatus.DISCONNECTED;
|
||||
})();
|
||||
@@ -200,9 +199,9 @@ export class ClusterManager {
|
||||
this.dependencies.store.addCluster(model);
|
||||
} catch (error) {
|
||||
if (isErrnoException(error) && error.code === "ENOENT" && error.path === entity.spec.kubeconfigPath) {
|
||||
logger.warn(`${logPrefix} kubeconfig file disappeared`, model);
|
||||
this.dependencies.logger.warn(`${logPrefix} kubeconfig file disappeared`, model);
|
||||
} else {
|
||||
logger.error(`${logPrefix} failed to add cluster: ${error}`, model);
|
||||
this.dependencies.logger.error(`${logPrefix} failed to add cluster: ${error}`, model);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -235,7 +234,7 @@ export class ClusterManager {
|
||||
}
|
||||
|
||||
protected onNetworkOffline = () => {
|
||||
logger.info(`${logPrefix} network is offline`);
|
||||
this.dependencies.logger.info(`${logPrefix} network is offline`);
|
||||
this.dependencies.store.clustersList.forEach((cluster) => {
|
||||
if (!cluster.disconnected) {
|
||||
cluster.online = false;
|
||||
@@ -246,7 +245,7 @@ export class ClusterManager {
|
||||
};
|
||||
|
||||
protected onNetworkOnline = () => {
|
||||
logger.info(`${logPrefix} network is online`);
|
||||
this.dependencies.logger.info(`${logPrefix} network is online`);
|
||||
this.dependencies.store.clustersList.forEach((cluster) => {
|
||||
if (!cluster.disconnected) {
|
||||
cluster.refreshConnectionStatus().catch((e) => e);
|
||||
@@ -259,27 +258,6 @@ export class ClusterManager {
|
||||
cluster.disconnect();
|
||||
});
|
||||
}
|
||||
|
||||
getClusterForRequest = (req: http.IncomingMessage): Cluster | undefined => {
|
||||
if (!req.headers.host) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// lens-server is connecting to 127.0.0.1:<port>/<uid>
|
||||
if (req.url && req.headers.host.startsWith("127.0.0.1")) {
|
||||
const clusterId = req.url.split("/")[1];
|
||||
const cluster = this.dependencies.store.getById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
// we need to swap path prefix so that request is proxied to kube api
|
||||
req.url = req.url.replace(`/${clusterId}`, apiKubePrefix);
|
||||
}
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
return this.dependencies.store.getById(getClusterIdFromHost(req.headers.host));
|
||||
};
|
||||
}
|
||||
|
||||
export function catalogEntityFromCluster(cluster: Cluster) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// convert file path cluster icons to their base64 encoded versions
|
||||
|
||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import getCustomKubeConfigDirectoryInjectable from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
|
||||
import getCustomKubeConfigFilePathInjectable from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
|
||||
import type { ClusterModel } from "../../../common/cluster-types";
|
||||
import readFileSyncInjectable from "../../../common/fs/read-file-sync.injectable";
|
||||
import { loadConfigFromString } from "../../../common/kube-helpers";
|
||||
@@ -27,7 +27,7 @@ const v360Beta1ClusterStoreMigrationInjectable = getInjectable({
|
||||
id: "v3.6.0-beta.1-cluster-store-migration",
|
||||
instantiate: (di) => {
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const getCustomKubeConfigDirectory = di.inject(getCustomKubeConfigDirectoryInjectable);
|
||||
const getCustomKubeConfigDirectory = di.inject(getCustomKubeConfigFilePathInjectable);
|
||||
const readFileSync = di.inject(readFileSyncInjectable);
|
||||
const readFileBufferSync = di.inject(readFileBufferSyncInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
@@ -44,8 +44,8 @@ const v360Beta1ClusterStoreMigrationInjectable = getInjectable({
|
||||
|
||||
for (const clusterModel of storedClusters) {
|
||||
/**
|
||||
* migrate kubeconfig
|
||||
*/
|
||||
* migrate kubeconfig
|
||||
*/
|
||||
try {
|
||||
const absPath = getCustomKubeConfigDirectory(clusterModel.id);
|
||||
|
||||
@@ -80,6 +80,7 @@ const v360Beta1ClusterStoreMigrationInjectable = getInjectable({
|
||||
delete clusterModel.preferences?.icon;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.info(`Failed to migrate cluster icon for cluster "${clusterModel.id}"`, error);
|
||||
delete clusterModel.preferences?.icon;
|
||||
}
|
||||
|
||||
@@ -49,10 +49,17 @@ const v500Beta10ClusterStoreMigrationInjectable = getInjectable({
|
||||
|
||||
store.set("clusters", clusters);
|
||||
} catch (error) {
|
||||
if (isErrnoException(error) && !(error.code === "ENOENT" && error.path?.endsWith("lens-workspace-store.json"))) {
|
||||
// ignore lens-workspace-store.json being missing
|
||||
throw error;
|
||||
// KLUDGE: remove after https://github.com/streamich/memfs/pull/893 is released
|
||||
if (process.env.JEST_WORKER_ID && (error as any).code === "ENOENT") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isErrnoException(error) && error.code === "ENOENT" && error.path?.endsWith("lens-workspace-store.json")) {
|
||||
// ignore lens-workspace-store.json being missing
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -3,17 +3,44 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { kebabCase } from "lodash";
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import electronAppInjectable from "./electron-app.injectable";
|
||||
|
||||
export default getGlobalOverride(electronAppInjectable, () => ({
|
||||
getVersion: () => "6.0.0",
|
||||
setLoginItemSettings: () => {},
|
||||
commandLine: {
|
||||
appendArgument: () => {},
|
||||
appendSwitch: () => {},
|
||||
getSwitchValue: () => "",
|
||||
hasSwitch: () => false,
|
||||
removeSwitch: () => {},
|
||||
},
|
||||
} as Partial<Electron.App> as Electron.App));
|
||||
export default getGlobalOverride(electronAppInjectable, () => {
|
||||
const commandLineArgs: string[] = [];
|
||||
const chromiumArgs = new Map<string, string | undefined>();
|
||||
const appPaths = new Map<string, string>();
|
||||
|
||||
const app = ({
|
||||
getVersion: () => "6.0.0",
|
||||
setLoginItemSettings: () => { },
|
||||
on: () => app,
|
||||
whenReady: async () => {},
|
||||
getPath: (name) => appPaths.get(name) ?? `/some-directory-for-${kebabCase(name)}`,
|
||||
setPath: (name, value) => appPaths.set(name, value),
|
||||
getAppPath: () => "/some-path-to-the-applcation-binary",
|
||||
focus: () => {},
|
||||
commandLine: {
|
||||
appendArgument: (value) => commandLineArgs.push(value),
|
||||
appendSwitch: (key, value) => chromiumArgs.set(key, value),
|
||||
getSwitchValue: (key) => chromiumArgs.get(key),
|
||||
hasSwitch: (key) => chromiumArgs.has(key),
|
||||
removeSwitch: (key) => chromiumArgs.delete(key),
|
||||
},
|
||||
disableHardwareAcceleration: () => {},
|
||||
requestSingleInstanceLock: () => true,
|
||||
getLoginItemSettings: () => ({
|
||||
executableWillLaunchAtLogin: false,
|
||||
openAtLogin: false,
|
||||
openAsHidden: false,
|
||||
wasOpenedAtLogin: false,
|
||||
wasOpenedAsHidden: false,
|
||||
restoreState: false,
|
||||
launchItems: [],
|
||||
}),
|
||||
exit: () => {},
|
||||
} as Partial<Electron.App> as Electron.App);
|
||||
|
||||
return app;
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../../common/test-utils/get-global-override";
|
||||
import electronDialogInjectable from "./electron-dialog.injectable";
|
||||
|
||||
export default getGlobalOverride(electronDialogInjectable, () => ({
|
||||
showCertificateTrustDialog: async () => {},
|
||||
showErrorBox: () => {},
|
||||
showMessageBox: async () => ({
|
||||
checkboxChecked: false,
|
||||
response: 0,
|
||||
}),
|
||||
showMessageBoxSync: () => 0,
|
||||
showOpenDialog: async () => ({
|
||||
canceled: true,
|
||||
filePaths: [],
|
||||
}),
|
||||
showOpenDialogSync: () => [],
|
||||
showSaveDialog: async () => ({
|
||||
canceled: true,
|
||||
}),
|
||||
showSaveDialogSync: () => "",
|
||||
}));
|
||||
@@ -15,8 +15,6 @@ const focusApplicationInjectable = getInjectable({
|
||||
electronApp.focus({ steal: true });
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default focusApplicationInjectable;
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import EventEmitter from "events";
|
||||
import { getGlobalOverride } from "../../../common/test-utils/get-global-override";
|
||||
import nativeThemeInjectable from "./native-theme.injectable";
|
||||
|
||||
export default getGlobalOverride(nativeThemeInjectable, () => Object.assign(new EventEmitter(), {
|
||||
shouldUseDarkColors: true,
|
||||
inForcedColorsMode: true,
|
||||
shouldUseHighContrastColors: false,
|
||||
shouldUseInvertedColorScheme: false,
|
||||
themeSource: "dark" as const,
|
||||
}));
|
||||
+3
-3
@@ -7,10 +7,10 @@ import { setupIpcMainHandlers } from "./setup-ipc-main-handlers";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
|
||||
import { onLoadOfApplicationInjectionToken } from "../../../start-main-application/runnable-tokens/on-load-of-application-injection-token";
|
||||
import catalogEntityRegistryInjectable from "../../../catalog/entity-registry.injectable";
|
||||
import applicationMenuItemCompositeInjectable from "../../../../features/application-menu/main/application-menu-item-composite.injectable";
|
||||
import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable";
|
||||
import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable";
|
||||
import pushCatalogToRendererInjectable from "../../../catalog-sync-to-renderer/push-catalog-to-renderer.injectable";
|
||||
|
||||
const setupIpcMainHandlersInjectable = getInjectable({
|
||||
id: "setup-ipc-main-handlers",
|
||||
@@ -18,7 +18,7 @@ const setupIpcMainHandlersInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const applicationMenuItemComposite = di.inject(applicationMenuItemCompositeInjectable);
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
const pushCatalogToRenderer = di.inject(pushCatalogToRendererInjectable);
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
const emitAppEvent = di.inject(emitAppEventInjectable);
|
||||
const getClusterById = di.inject(getClusterByIdInjectable);
|
||||
@@ -30,7 +30,7 @@ const setupIpcMainHandlersInjectable = getInjectable({
|
||||
|
||||
setupIpcMainHandlers({
|
||||
applicationMenuItemComposite,
|
||||
catalogEntityRegistry,
|
||||
pushCatalogToRenderer,
|
||||
clusterStore,
|
||||
emitAppEvent,
|
||||
getClusterById,
|
||||
|
||||
@@ -9,8 +9,6 @@ import { clusterActivateHandler, clusterSetFrameIdHandler, clusterDisconnectHand
|
||||
import type { ClusterId } from "../../../../common/cluster-types";
|
||||
import type { ClusterStore } from "../../../../common/cluster-store/cluster-store";
|
||||
import { broadcastMainChannel, broadcastMessage, ipcMainHandle, ipcMainOn } from "../../../../common/ipc";
|
||||
import type { CatalogEntityRegistry } from "../../../catalog";
|
||||
import { pushCatalogToRenderer } from "../../../catalog-pusher";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../../common/ipc/window";
|
||||
import { handleWindowAction, onLocationChange } from "../../../ipc/window";
|
||||
@@ -22,18 +20,18 @@ import type { EmitAppEvent } from "../../../../common/app-event-bus/emit-event.i
|
||||
import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable";
|
||||
interface Dependencies {
|
||||
applicationMenuItemComposite: IComputedValue<Composite<ApplicationMenuItemTypes | MenuItemRoot>>;
|
||||
catalogEntityRegistry: CatalogEntityRegistry;
|
||||
clusterStore: ClusterStore;
|
||||
emitAppEvent: EmitAppEvent;
|
||||
getClusterById: GetClusterById;
|
||||
pushCatalogToRenderer: () => void;
|
||||
}
|
||||
|
||||
export const setupIpcMainHandlers = ({
|
||||
applicationMenuItemComposite,
|
||||
catalogEntityRegistry,
|
||||
clusterStore,
|
||||
emitAppEvent,
|
||||
getClusterById,
|
||||
pushCatalogToRenderer,
|
||||
}: Dependencies) => {
|
||||
ipcMainHandle(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => {
|
||||
return getClusterById(clusterId)
|
||||
@@ -45,8 +43,7 @@ export const setupIpcMainHandlers = ({
|
||||
|
||||
if (cluster) {
|
||||
clusterFrameMap.set(cluster.id, { frameId: event.frameId, processId: event.processId });
|
||||
|
||||
pushCatalogToRenderer(catalogEntityRegistry);
|
||||
pushCatalogToRenderer();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+13
-127
@@ -3,76 +3,35 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { kebabCase, noop, chunk } from "lodash/fp";
|
||||
import { chunk } from "lodash/fp";
|
||||
import type { DiContainer, Injectable } from "@ogre-tools/injectable";
|
||||
import { createContainer, isInjectable, getInjectable } from "@ogre-tools/injectable";
|
||||
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import writeJsonFileInjectable from "../common/fs/write-json-file.injectable";
|
||||
import readJsonFileInjectable from "../common/fs/read-json-file.injectable";
|
||||
import readFileInjectable from "../common/fs/read-file.injectable";
|
||||
import loggerInjectable from "../common/logger.injectable";
|
||||
import spawnInjectable from "./child-process/spawn.injectable";
|
||||
import commandLineArgumentsInjectable from "./utils/command-line-arguments.injectable";
|
||||
import initializeExtensionsInjectable from "./start-main-application/runnables/initialize-extensions.injectable";
|
||||
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
|
||||
import environmentVariablesInjectable from "../common/utils/environment-variables.injectable";
|
||||
import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable";
|
||||
import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable";
|
||||
import setupShellInjectable from "../features/shell-sync/main/setup-shell.injectable";
|
||||
import setupSyncingOfWeblinksInjectable from "./start-main-application/runnables/setup-syncing-of-weblinks.injectable";
|
||||
import stopServicesAndExitAppInjectable from "./stop-services-and-exit-app.injectable";
|
||||
import isDevelopmentInjectable from "../common/vars/is-development.injectable";
|
||||
import setupSystemCaInjectable from "./start-main-application/runnables/setup-system-ca.injectable";
|
||||
import setupDeepLinkingInjectable from "./electron-app/runnables/setup-deep-linking.injectable";
|
||||
import exitAppInjectable from "./electron-app/features/exit-app.injectable";
|
||||
import getCommandLineSwitchInjectable from "./electron-app/features/get-command-line-switch.injectable";
|
||||
import requestSingleInstanceLockInjectable from "./electron-app/features/request-single-instance-lock.injectable";
|
||||
import disableHardwareAccelerationInjectable from "./electron-app/features/disable-hardware-acceleration.injectable";
|
||||
import shouldStartHiddenInjectable from "./electron-app/features/should-start-hidden.injectable";
|
||||
import getElectronAppPathInjectable from "./app-paths/get-electron-app-path/get-electron-app-path.injectable";
|
||||
import setElectronAppPathInjectable from "./app-paths/set-electron-app-path/set-electron-app-path.injectable";
|
||||
import setupMainWindowVisibilityAfterActivationInjectable from "./electron-app/runnables/setup-main-window-visibility-after-activation.injectable";
|
||||
import setupDeviceShutdownInjectable from "./electron-app/runnables/setup-device-shutdown.injectable";
|
||||
import setupApplicationNameInjectable from "./electron-app/runnables/setup-application-name.injectable";
|
||||
import setupRunnablesBeforeClosingOfApplicationInjectable from "./electron-app/runnables/setup-runnables-before-closing-of-application.injectable";
|
||||
import showMessagePopupInjectable from "./electron-app/features/show-message-popup.injectable";
|
||||
import clusterFramesInjectable from "../common/cluster-frames.injectable";
|
||||
import type { ClusterFrameInfo } from "../common/cluster-frames";
|
||||
import { observable, runInAction } from "mobx";
|
||||
import waitForElectronToBeReadyInjectable from "./electron-app/features/wait-for-electron-to-be-ready.injectable";
|
||||
import setupRunnablesAfterWindowIsOpenedInjectable from "./electron-app/runnables/setup-runnables-after-window-is-opened.injectable";
|
||||
import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectable";
|
||||
import getElectronThemeInjectable from "./electron-app/features/get-electron-theme.injectable";
|
||||
import syncThemeFromOperatingSystemInjectable from "./electron-app/features/sync-theme-from-operating-system.injectable";
|
||||
import platformInjectable from "../common/vars/platform.injectable";
|
||||
import electronQuitAndInstallUpdateInjectable from "./electron-app/features/electron-quit-and-install-update.injectable";
|
||||
import electronUpdaterIsActiveInjectable from "./electron-app/features/electron-updater-is-active.injectable";
|
||||
import baseBundledBinariesDirectoryInjectable from "../common/vars/base-bundled-binaries-dir.injectable";
|
||||
import setUpdateOnQuitInjectable from "./electron-app/features/set-update-on-quit.injectable";
|
||||
import startCatalogSyncInjectable from "./catalog-sync-to-renderer/start-catalog-sync.injectable";
|
||||
import startKubeConfigSyncInjectable from "./start-main-application/runnables/kube-config-sync/start-kube-config-sync.injectable";
|
||||
import getRandomIdInjectable from "../common/utils/get-random-id.injectable";
|
||||
import execFileInjectable from "../common/fs/exec-file.injectable";
|
||||
import normalizedPlatformArchitectureInjectable from "../common/vars/normalized-platform-architecture.injectable";
|
||||
import getHelmChartVersionsInjectable from "./helm/helm-service/get-helm-chart-versions.injectable";
|
||||
import getHelmChartValuesInjectable from "./helm/helm-service/get-helm-chart-values.injectable";
|
||||
import listHelmChartsInjectable from "./helm/helm-service/list-helm-charts.injectable";
|
||||
import deleteHelmReleaseInjectable from "./helm/helm-service/delete-helm-release.injectable";
|
||||
import getHelmReleaseHistoryInjectable from "./helm/helm-service/get-helm-release-history.injectable";
|
||||
import getHelmReleaseValuesInjectable from "./helm/helm-service/get-helm-release-values.injectable";
|
||||
import installHelmChartInjectable from "./helm/helm-service/install-helm-chart.injectable";
|
||||
import listHelmReleasesInjectable from "./helm/helm-service/list-helm-releases.injectable";
|
||||
import rollbackHelmReleaseInjectable from "./helm/helm-service/rollback-helm-release.injectable";
|
||||
import waitUntilBundledExtensionsAreLoadedInjectable from "./start-main-application/lens-window/application-window/wait-until-bundled-extensions-are-loaded.injectable";
|
||||
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
|
||||
import electronInjectable from "./utils/resolve-system-proxy/electron.injectable";
|
||||
import focusApplicationInjectable from "./electron-app/features/focus-application.injectable";
|
||||
import kubectlDownloadingNormalizedArchInjectable from "./kubectl/normalized-arch.injectable";
|
||||
import initializeClusterManagerInjectable from "./cluster/initialize-manager.injectable";
|
||||
import addKubeconfigSyncAsEntitySourceInjectable from "./start-main-application/runnables/kube-config-sync/add-source.injectable";
|
||||
import type { GlobalOverride } from "../common/test-utils/get-global-override";
|
||||
import applicationInformationInjectable from "../common/vars/application-information-injectable";
|
||||
import nodeEnvInjectionToken from "../common/vars/node-env-injection-token";
|
||||
import { getOverrideFsWithFakes } from "../test-utils/override-fs-with-fakes";
|
||||
|
||||
export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) {
|
||||
const {
|
||||
@@ -83,7 +42,7 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
|
||||
|
||||
di.register(getInjectable({
|
||||
id: "node-env",
|
||||
instantiate: () => "test",
|
||||
instantiate: () => "production",
|
||||
injectionToken: nodeEnvInjectionToken,
|
||||
}));
|
||||
|
||||
@@ -91,13 +50,12 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
|
||||
|
||||
di.preventSideEffects();
|
||||
|
||||
const injectables: Injectable<any, any, any>[] = (
|
||||
global as any
|
||||
).mainInjectablePaths.flatMap((filePath: string) =>
|
||||
Object.values(require(filePath)).filter(
|
||||
(maybeInjectable: any) => isInjectable(maybeInjectable),
|
||||
),
|
||||
);
|
||||
const injectables = (
|
||||
global.injectablePaths.main.paths
|
||||
.map(path => require(path))
|
||||
.flatMap(Object.values)
|
||||
.filter(isInjectable)
|
||||
) as Injectable<any, any, any>[];
|
||||
|
||||
runInAction(() => {
|
||||
registerMobX(di);
|
||||
@@ -109,52 +67,24 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
|
||||
});
|
||||
|
||||
if (doGeneralOverrides) {
|
||||
const globalOverrides: GlobalOverride[] = (global as any).mainGlobalOverridePaths.map(
|
||||
(filePath: string) => require(filePath).default,
|
||||
);
|
||||
for (const globalOverridePath of global.injectablePaths.main.globalOverridePaths) {
|
||||
const globalOverride = require(globalOverridePath).default as GlobalOverride;
|
||||
|
||||
globalOverrides.forEach(globalOverride => {
|
||||
di.override(globalOverride.injectable, globalOverride.overridingInstantiate);
|
||||
});
|
||||
}
|
||||
|
||||
di.override(electronInjectable, () => ({}));
|
||||
di.override(waitUntilBundledExtensionsAreLoadedInjectable, () => async () => {});
|
||||
di.override(getRandomIdInjectable, () => () => "some-irrelevant-random-id");
|
||||
di.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
|
||||
|
||||
overrideOperatingSystem(di);
|
||||
overrideRunnablesHavingSideEffects(di);
|
||||
overrideElectronFeatures(di);
|
||||
|
||||
di.override(isDevelopmentInjectable, () => false);
|
||||
di.override(environmentVariablesInjectable, () => ({}));
|
||||
di.override(commandLineArgumentsInjectable, () => []);
|
||||
getOverrideFsWithFakes()(di);
|
||||
|
||||
di.override(clusterFramesInjectable, () => observable.map<string, ClusterFrameInfo>());
|
||||
|
||||
di.override(stopServicesAndExitAppInjectable, () => () => {});
|
||||
di.override(lensResourcesDirInjectable, () => "/irrelevant");
|
||||
|
||||
overrideFunctionalInjectables(di, [
|
||||
getHelmChartVersionsInjectable,
|
||||
getHelmChartValuesInjectable,
|
||||
listHelmChartsInjectable,
|
||||
deleteHelmReleaseInjectable,
|
||||
getHelmReleaseHistoryInjectable,
|
||||
getHelmReleaseValuesInjectable,
|
||||
installHelmChartInjectable,
|
||||
listHelmReleasesInjectable,
|
||||
rollbackHelmReleaseInjectable,
|
||||
writeJsonFileInjectable,
|
||||
readJsonFileInjectable,
|
||||
readFileInjectable,
|
||||
execFileInjectable,
|
||||
]);
|
||||
|
||||
di.override(broadcastMessageInjectable, () => (channel) => {
|
||||
throw new Error(`Tried to broadcast message to channel "${channel}" over IPC without explicit override.`);
|
||||
});
|
||||
di.override(baseBundledBinariesDirectoryInjectable, () => "some-bin-directory");
|
||||
di.override(spawnInjectable, () => () => {
|
||||
return {
|
||||
stderr: { on: jest.fn(), removeAllListeners: jest.fn() },
|
||||
@@ -162,14 +92,6 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
|
||||
on: jest.fn(),
|
||||
} as never;
|
||||
});
|
||||
|
||||
di.override(loggerInjectable, () => ({
|
||||
warn: noop,
|
||||
debug: noop,
|
||||
error: noop,
|
||||
info: noop,
|
||||
silly: noop,
|
||||
}));
|
||||
}
|
||||
|
||||
return di;
|
||||
@@ -180,15 +102,9 @@ const overrideRunnablesHavingSideEffects = (di: DiContainer) => {
|
||||
[
|
||||
initializeExtensionsInjectable,
|
||||
initializeClusterManagerInjectable,
|
||||
addKubeconfigSyncAsEntitySourceInjectable,
|
||||
setupIpcMainHandlersInjectable,
|
||||
setupLensProxyInjectable,
|
||||
setupShellInjectable,
|
||||
setupSyncingOfWeblinksInjectable,
|
||||
setupSystemCaInjectable,
|
||||
setupRunnablesAfterWindowIsOpenedInjectable,
|
||||
startCatalogSyncInjectable,
|
||||
startKubeConfigSyncInjectable,
|
||||
].forEach((injectable) => {
|
||||
di.override(injectable, () => ({
|
||||
id: injectable.id,
|
||||
@@ -197,11 +113,6 @@ const overrideRunnablesHavingSideEffects = (di: DiContainer) => {
|
||||
});
|
||||
};
|
||||
|
||||
const overrideOperatingSystem = (di: DiContainer) => {
|
||||
di.override(platformInjectable, () => "darwin");
|
||||
di.override(normalizedPlatformArchitectureInjectable, () => "arm64");
|
||||
};
|
||||
|
||||
const overrideElectronFeatures = (di: DiContainer) => {
|
||||
[
|
||||
setupMainWindowVisibilityAfterActivationInjectable,
|
||||
@@ -216,32 +127,7 @@ const overrideElectronFeatures = (di: DiContainer) => {
|
||||
}));
|
||||
});
|
||||
|
||||
di.override(exitAppInjectable, () => () => {});
|
||||
di.override(getCommandLineSwitchInjectable, () => () => "irrelevant");
|
||||
di.override(requestSingleInstanceLockInjectable, () => () => true);
|
||||
di.override(disableHardwareAccelerationInjectable, () => () => {});
|
||||
di.override(shouldStartHiddenInjectable, () => false);
|
||||
di.override(showMessagePopupInjectable, () => () => {});
|
||||
di.override(waitForElectronToBeReadyInjectable, () => () => Promise.resolve());
|
||||
di.override(getElectronThemeInjectable, () => () => "dark");
|
||||
di.override(syncThemeFromOperatingSystemInjectable, () => ({ start: () => {}, stop: () => {} }));
|
||||
di.override(electronQuitAndInstallUpdateInjectable, () => () => {});
|
||||
di.override(setUpdateOnQuitInjectable, () => () => {});
|
||||
di.override(focusApplicationInjectable, () => () => {});
|
||||
|
||||
di.override(
|
||||
getElectronAppPathInjectable,
|
||||
() => (name: string) => `/some-electron-app-path-for-${kebabCase(name)}`,
|
||||
);
|
||||
|
||||
di.override(setElectronAppPathInjectable, () => () => {});
|
||||
di.override(electronUpdaterIsActiveInjectable, () => false);
|
||||
};
|
||||
|
||||
const overrideFunctionalInjectables = (di: DiContainer, injectables: Injectable<any, any, any>[]) => {
|
||||
injectables.forEach(injectable => {
|
||||
di.override(injectable, () => () => {
|
||||
throw new Error(`Tried to run "${injectable.id}" without explicit override.`);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -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 execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||
|
||||
export interface DeleteHelmReleaseData {
|
||||
name: string;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
export type DeleteHelmRelease = (kubeconfigPath: string, data: DeleteHelmReleaseData) => Promise<string>;
|
||||
|
||||
const deleteHelmReleaseInjectable = getInjectable({
|
||||
id: "delete-helm-release",
|
||||
instantiate: (di): DeleteHelmRelease => {
|
||||
const execHelm = di.inject(execHelmInjectable);
|
||||
|
||||
return async (kubeconfigPath, { name, namespace }) => {
|
||||
const result = await execHelm([
|
||||
"delete",
|
||||
name,
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
]);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response;
|
||||
}
|
||||
|
||||
throw result.error;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default deleteHelmReleaseInjectable;
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 { HelmReleaseRevision } from "../../common/k8s-api/endpoints/helm-releases.api/request-history.injectable";
|
||||
import execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||
|
||||
export interface GetHelmReleaseHistoryData {
|
||||
name: string;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
export type GetHelmReleaseHistory = (kubeconfigPath: string, data: GetHelmReleaseHistoryData) => Promise<HelmReleaseRevision[]>;
|
||||
|
||||
const getHelmReleaseHistoryInjectable = getInjectable({
|
||||
id: "get-helm-release-history",
|
||||
instantiate: (di): GetHelmReleaseHistory => {
|
||||
const execHelm = di.inject(execHelmInjectable);
|
||||
|
||||
return async (kubeconfigPath, { name, namespace }) => {
|
||||
const result = await execHelm([
|
||||
"history",
|
||||
name,
|
||||
"--output", "json",
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
]);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return JSON.parse(result.response);
|
||||
}
|
||||
|
||||
throw result.error;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default getHelmReleaseHistoryInjectable;
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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 execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||
|
||||
export interface GetHelmReleaseValuesData {
|
||||
name: string;
|
||||
namespace: string;
|
||||
all?: boolean;
|
||||
}
|
||||
|
||||
export type GetHelmReleaseValues = (kubeconfigPath: string, data: GetHelmReleaseValuesData) => Promise<string>;
|
||||
|
||||
const getHelmReleaseValuesInjectable = getInjectable({
|
||||
id: "get-helm-release-values",
|
||||
instantiate: (di): GetHelmReleaseValues => {
|
||||
const execHelm = di.inject(execHelmInjectable);
|
||||
|
||||
return async (kubeconfigPath, { name, namespace, all = false }) => {
|
||||
const args = [
|
||||
"get",
|
||||
"values",
|
||||
name,
|
||||
];
|
||||
|
||||
if (all) {
|
||||
args.push("--all");
|
||||
}
|
||||
|
||||
args.push(
|
||||
"--output", "yaml",
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
);
|
||||
|
||||
const result = await execHelm(args);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response;
|
||||
}
|
||||
|
||||
throw result.error;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default getHelmReleaseValuesInjectable;
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import tempy from "tempy";
|
||||
import fse from "fs-extra";
|
||||
import * as yaml from "js-yaml";
|
||||
import { toCamelCase } from "../../common/utils/camelCase";
|
||||
import type { JsonValue } from "type-fest";
|
||||
import { isObject, json } from "../../common/utils";
|
||||
import { asLegacyGlobalFunctionForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
|
||||
import execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||
|
||||
const execHelm = asLegacyGlobalFunctionForExtensionApi(execHelmInjectable);
|
||||
|
||||
export async function listReleases(pathToKubeconfig: string, namespace?: string): Promise<Record<string, any>[]> {
|
||||
const args = [
|
||||
"ls",
|
||||
"--all",
|
||||
"--output", "json",
|
||||
];
|
||||
|
||||
if (namespace) {
|
||||
args.push("-n", namespace);
|
||||
} else {
|
||||
args.push("--all-namespaces");
|
||||
}
|
||||
|
||||
args.push("--kubeconfig", pathToKubeconfig);
|
||||
|
||||
const result = await execHelm(args);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
const output = json.parse(result.response);
|
||||
|
||||
if (!Array.isArray(output) || output.length == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return output.filter(isObject).map(toCamelCase);
|
||||
}
|
||||
|
||||
|
||||
export async function installChart(chart: string, values: JsonValue, name: string | undefined = "", namespace: string, version: string, kubeconfigPath: string) {
|
||||
const valuesFilePath = tempy.file({ name: "values.yaml" });
|
||||
|
||||
await fse.writeFile(valuesFilePath, yaml.dump(values));
|
||||
|
||||
const args = ["install"];
|
||||
|
||||
if (name) {
|
||||
args.push(name);
|
||||
}
|
||||
|
||||
args.push(
|
||||
chart,
|
||||
"--version", version,
|
||||
"--values", valuesFilePath,
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
);
|
||||
|
||||
if (!name) {
|
||||
args.push("--generate-name");
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await execHelm(args);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
const output = result.response;
|
||||
const releaseName = output.split("\n")[0].split(" ")[1].trim();
|
||||
|
||||
return {
|
||||
log: output,
|
||||
release: {
|
||||
name: releaseName,
|
||||
namespace,
|
||||
},
|
||||
};
|
||||
} finally {
|
||||
await fse.unlink(valuesFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteRelease(name: string, namespace: string, kubeconfigPath: string): Promise<string> {
|
||||
const result = await execHelm([
|
||||
"delete",
|
||||
name,
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
]);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response;
|
||||
}
|
||||
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
interface GetValuesOptions {
|
||||
namespace: string;
|
||||
all?: boolean;
|
||||
kubeconfigPath: string;
|
||||
}
|
||||
|
||||
export async function getValues(name: string, { namespace, all = false, kubeconfigPath }: GetValuesOptions): Promise<string> {
|
||||
const args = [
|
||||
"get",
|
||||
"values",
|
||||
name,
|
||||
];
|
||||
|
||||
if (all) {
|
||||
args.push("--all");
|
||||
}
|
||||
|
||||
args.push(
|
||||
"--output", "yaml",
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
);
|
||||
|
||||
const result = await execHelm(args);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response;
|
||||
}
|
||||
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
export async function getHistory(name: string, namespace: string, kubeconfigPath: string): Promise<JsonValue> {
|
||||
const result = await execHelm([
|
||||
"history",
|
||||
name,
|
||||
"--output", "json",
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
]);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return json.parse(result.response);
|
||||
}
|
||||
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
export async function rollback(name: string, namespace: string, revision: number, kubeconfigPath: string): Promise<void> {
|
||||
const result = await execHelm([
|
||||
"rollback",
|
||||
name,
|
||||
`${revision}`,
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
]);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
throw result.error;
|
||||
}
|
||||
}
|
||||
@@ -4,25 +4,25 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { deleteRelease } from "../helm-release-manager";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import type { DeleteHelmReleaseData } from "../delete-helm-release.injectable";
|
||||
import deleteHelmReleaseInjectable from "../delete-helm-release.injectable";
|
||||
|
||||
const deleteHelmReleaseInjectable = getInjectable({
|
||||
id: "delete-helm-release",
|
||||
const deleteClusterHelmReleaseInjectable = getInjectable({
|
||||
id: "delete-cluster-helm-release",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const deleteHelmRelease = di.inject(deleteHelmReleaseInjectable);
|
||||
|
||||
return async (cluster: Cluster, releaseName: string, namespace: string) => {
|
||||
return async (cluster: Cluster, data: DeleteHelmReleaseData) => {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("Delete release");
|
||||
logger.debug(`[CLUSTER]: Delete helm release`, data);
|
||||
|
||||
return deleteRelease(releaseName, namespace, proxyKubeconfig);
|
||||
return deleteHelmRelease(proxyKubeconfig, data);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default deleteHelmReleaseInjectable;
|
||||
export default deleteClusterHelmReleaseInjectable;
|
||||
@@ -24,8 +24,6 @@ const getHelmChartValuesInjectable = getInjectable({
|
||||
return getChartManager(repo).getValues(chartName, version);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default getHelmChartValuesInjectable;
|
||||
@@ -24,8 +24,6 @@ const getHelmChartVersionsInjectable = getInjectable({
|
||||
return getChartManager(repo).chartVersions(chartName);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default getHelmChartVersionsInjectable;
|
||||
@@ -4,25 +4,25 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { getHistory } from "../helm-release-manager";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import type { GetHelmReleaseHistoryData } from "../get-helm-release-history.injectable";
|
||||
import getHelmReleaseHistoryInjectable from "../get-helm-release-history.injectable";
|
||||
|
||||
const getHelmReleaseHistoryInjectable = getInjectable({
|
||||
id: "get-helm-release-history",
|
||||
const getClusterHelmReleaseHistoryInjectable = getInjectable({
|
||||
id: "get-cluster-helm-release-history",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const getHelmReleaseHistory = di.inject(getHelmReleaseHistoryInjectable);
|
||||
|
||||
return async (cluster: Cluster, releaseName: string, namespace: string) => {
|
||||
return async (cluster: Cluster, data: GetHelmReleaseHistoryData) => {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("Fetch release history");
|
||||
logger.debug(`[CLUSTER]: Fetch release history for clusterId=${cluster.id}`, data);
|
||||
|
||||
return getHistory(releaseName, namespace, proxyKubeconfig);
|
||||
return getHelmReleaseHistory(proxyKubeconfig, data);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default getHelmReleaseHistoryInjectable;
|
||||
export default getClusterHelmReleaseHistoryInjectable;
|
||||
@@ -3,39 +3,26 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { getValues } from "../helm-release-manager";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import type { GetHelmReleaseValuesData } from "../get-helm-release-values.injectable";
|
||||
import getHelmReleaseValuesInjectable from "../get-helm-release-values.injectable";
|
||||
|
||||
interface GetReleaseValuesArgs {
|
||||
cluster: Cluster;
|
||||
namespace: string;
|
||||
all: boolean;
|
||||
}
|
||||
|
||||
const getHelmReleaseValuesInjectable = getInjectable({
|
||||
id: "get-helm-release-values",
|
||||
const getClusterHelmReleaseValuesInjectable = getInjectable({
|
||||
id: "get-cluster-helm-release-values",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const getHelmReleaseValues = di.inject(getHelmReleaseValuesInjectable);
|
||||
|
||||
return async (
|
||||
releaseName: string,
|
||||
{ cluster, namespace, all }: GetReleaseValuesArgs,
|
||||
) => {
|
||||
return async (cluster: Cluster, data: GetHelmReleaseValuesData) => {
|
||||
const pathToKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("Fetch release values");
|
||||
logger.debug(`[CLUSTER]: getting helm release values`, data);
|
||||
|
||||
return getValues(releaseName, {
|
||||
namespace,
|
||||
all,
|
||||
kubeconfigPath: pathToKubeconfig,
|
||||
});
|
||||
return getHelmReleaseValues(pathToKubeconfig, data);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default getHelmReleaseValuesInjectable;
|
||||
export default getClusterHelmReleaseValuesInjectable;
|
||||
@@ -5,7 +5,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { JsonObject } from "type-fest";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { installChart } from "../helm-release-manager";
|
||||
import installHelmChartInjectable from "../install-helm-chart.injectable";
|
||||
|
||||
export interface InstallChartArgs {
|
||||
chart: string;
|
||||
@@ -15,16 +15,21 @@ export interface InstallChartArgs {
|
||||
version: string;
|
||||
}
|
||||
|
||||
const installHelmChartInjectable = getInjectable({
|
||||
id: "install-helm-chart",
|
||||
const installClusterHelmChartInjectable = getInjectable({
|
||||
id: "install-cluster-helm-chart",
|
||||
|
||||
instantiate: () => async (cluster: Cluster, data: InstallChartArgs) => {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
instantiate: (di) => {
|
||||
const installHelmChart = di.inject(installHelmChartInjectable);
|
||||
|
||||
return installChart(data.chart, data.values, data.name, data.namespace, data.version, proxyKubeconfig);
|
||||
return async (cluster: Cluster, data: InstallChartArgs) => {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
return installHelmChart({
|
||||
...data,
|
||||
kubeconfigPath: proxyKubeconfig,
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default installHelmChartInjectable;
|
||||
export default installClusterHelmChartInjectable;
|
||||
@@ -36,8 +36,6 @@ const listHelmChartsInjectable = getInjectable({
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default listHelmChartsInjectable;
|
||||
@@ -5,24 +5,23 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import { listReleases } from "../helm-release-manager";
|
||||
import listHelmReleasesInjectable from "../list-helm-releases.injectable";
|
||||
|
||||
const listHelmReleasesInjectable = getInjectable({
|
||||
id: "list-helm-releases",
|
||||
const listClusterHelmReleasesInjectable = getInjectable({
|
||||
id: "list-cluster-helm-releases",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const listHelmReleases = di.inject(listHelmReleasesInjectable);
|
||||
|
||||
return async (cluster: Cluster, namespace?: string) => {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("list releases");
|
||||
logger.debug(`[CLUSTER]: listing helm releases for clusterId=${cluster.id}`, { namespace });
|
||||
|
||||
return listReleases(proxyKubeconfig, namespace);
|
||||
return listHelmReleases(proxyKubeconfig, namespace);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default listHelmReleasesInjectable;
|
||||
export default listClusterHelmReleasesInjectable;
|
||||
@@ -5,28 +5,24 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import { rollback } from "../helm-release-manager";
|
||||
import type { RollbackHelmReleaseData } from "../rollback-helm-release.injectable";
|
||||
import rollbackHelmReleaseInjectable from "../rollback-helm-release.injectable";
|
||||
|
||||
const rollbackHelmReleaseInjectable = getInjectable({
|
||||
id: "rollback-helm-release",
|
||||
const rollbackClusterHelmReleaseInjectable = getInjectable({
|
||||
id: "rollback-cluster-helm-release",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const rollbackHelmRelease = di.inject(rollbackHelmReleaseInjectable);
|
||||
|
||||
return async (
|
||||
cluster: Cluster,
|
||||
releaseName: string,
|
||||
namespace: string,
|
||||
revision: number,
|
||||
) => {
|
||||
return async (cluster: Cluster, data: RollbackHelmReleaseData) => {
|
||||
const proxyKubeconfig = await cluster.getProxyKubeconfigPath();
|
||||
|
||||
logger.debug("Rollback release");
|
||||
await rollback(releaseName, namespace, revision, proxyKubeconfig);
|
||||
logger.debug(`[CLUSTER]: rolling back helm release for clusterId=${cluster.id}`, data);
|
||||
|
||||
await rollbackHelmRelease(proxyKubeconfig, data);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default rollbackHelmReleaseInjectable;
|
||||
export default rollbackClusterHelmReleaseInjectable;
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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 { dump } from "js-yaml";
|
||||
import tempy from "tempy";
|
||||
import type { JsonValue } from "type-fest";
|
||||
import removePathInjectable from "../../common/fs/remove.injectable";
|
||||
import writeFileInjectable from "../../common/fs/write-file.injectable";
|
||||
import execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||
|
||||
export interface InstallHelmChartData {
|
||||
chart: string;
|
||||
values: JsonValue;
|
||||
name: string;
|
||||
namespace: string;
|
||||
version: string;
|
||||
kubeconfigPath: string;
|
||||
}
|
||||
|
||||
export interface InstallHelmChartResult {
|
||||
log: string;
|
||||
release: {
|
||||
name: string;
|
||||
namespace: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type InstallHelmChart = (data: InstallHelmChartData) => Promise<InstallHelmChartResult>;
|
||||
|
||||
const installHelmChartInjectable = getInjectable({
|
||||
id: "install-helm-chart",
|
||||
instantiate: (di): InstallHelmChart => {
|
||||
const writeFile = di.inject(writeFileInjectable);
|
||||
const removePath = di.inject(removePathInjectable);
|
||||
const execHelm = di.inject(execHelmInjectable);
|
||||
|
||||
return async ({
|
||||
chart,
|
||||
kubeconfigPath,
|
||||
name,
|
||||
namespace,
|
||||
values,
|
||||
version,
|
||||
}) => {
|
||||
const valuesFilePath = tempy.file({ name: "values.yaml" });
|
||||
|
||||
await writeFile(valuesFilePath, dump(values));
|
||||
|
||||
const args = ["install"];
|
||||
|
||||
if (name) {
|
||||
args.push(name);
|
||||
}
|
||||
|
||||
args.push(
|
||||
chart,
|
||||
"--version", version,
|
||||
"--values", valuesFilePath,
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
);
|
||||
|
||||
if (!name) {
|
||||
args.push("--generate-name");
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await execHelm(args);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
const output = result.response;
|
||||
const releaseName = output.split("\n")[0].split(" ")[1].trim();
|
||||
|
||||
return {
|
||||
log: output,
|
||||
release: {
|
||||
name: releaseName,
|
||||
namespace,
|
||||
},
|
||||
};
|
||||
} finally {
|
||||
await removePath(valuesFilePath);
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default installHelmChartInjectable;
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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 execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||
import { isObject, json, toCamelCase } from "../../common/utils";
|
||||
|
||||
export type ListHelmReleases = (pathToKubeconfig: string, namespace?: string) => Promise<Record<string, any>[]>;
|
||||
|
||||
const listHelmReleasesInjectable = getInjectable({
|
||||
id: "list-helm-releases",
|
||||
instantiate: (di): ListHelmReleases => {
|
||||
const execHelm = di.inject(execHelmInjectable);
|
||||
|
||||
return async (pathToKubeconfig, namespace) => {
|
||||
const args = [
|
||||
"ls",
|
||||
"--all",
|
||||
"--output", "json",
|
||||
];
|
||||
|
||||
if (namespace) {
|
||||
args.push("-n", namespace);
|
||||
} else {
|
||||
args.push("--all-namespaces");
|
||||
}
|
||||
|
||||
args.push("--kubeconfig", pathToKubeconfig);
|
||||
|
||||
const result = await execHelm(args);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
const output = json.parse(result.response);
|
||||
|
||||
if (!Array.isArray(output) || output.length == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return output.filter(isObject).map(toCamelCase);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default listHelmReleasesInjectable;
|
||||
@@ -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 execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||
|
||||
export interface RollbackHelmReleaseData {
|
||||
name: string;
|
||||
namespace: string;
|
||||
revision: number;
|
||||
}
|
||||
|
||||
export type RollbackHelmRelease = (kubeconfigPath: string, data: RollbackHelmReleaseData) => Promise<void>;
|
||||
|
||||
const rollbackHelmReleaseInjectable = getInjectable({
|
||||
id: "rollback-helm-release",
|
||||
instantiate: (di): RollbackHelmRelease => {
|
||||
const execHelm = di.inject(execHelmInjectable);
|
||||
|
||||
return async (kubeconfigPath, { name, namespace, revision }) => {
|
||||
const result = await execHelm([
|
||||
"rollback",
|
||||
name,
|
||||
`${revision}`,
|
||||
"--namespace", namespace,
|
||||
"--kubeconfig", kubeconfigPath,
|
||||
]);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
throw result.error;
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default rollbackHelmReleaseInjectable;
|
||||
@@ -11,6 +11,7 @@ import kubeAuthProxyCertificateInjectable from "./kube-auth-proxy-certificate.in
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import waitUntilPortIsUsedInjectable from "./wait-until-port-is-used/wait-until-port-is-used.injectable";
|
||||
import lensK8sProxyPathInjectable from "./lens-k8s-proxy-path.injectable";
|
||||
import getPortFromStreamInjectable from "../utils/get-port-from-stream.injectable";
|
||||
|
||||
export type CreateKubeAuthProxy = (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => KubeAuthProxy;
|
||||
|
||||
@@ -23,6 +24,7 @@ const createKubeAuthProxyInjectable = getInjectable({
|
||||
spawn: di.inject(spawnInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
waitUntilPortIsUsed: di.inject(waitUntilPortIsUsedInjectable),
|
||||
getPortFromStream: di.inject(getPortFromStreamInjectable),
|
||||
};
|
||||
|
||||
return (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import type { ChildProcess } from "child_process";
|
||||
import { randomBytes } from "crypto";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import { getPortFrom } from "../utils/get-port";
|
||||
import type { GetPortFromStream } from "../utils/get-port-from-stream.injectable";
|
||||
import { makeObservable, observable, when } from "mobx";
|
||||
import type { SelfSignedCert } from "selfsigned";
|
||||
import assert from "assert";
|
||||
@@ -23,9 +23,10 @@ const startingServeRegex = Object.assign(TypedRegEx(startingServeMatcher, "i"),
|
||||
export interface KubeAuthProxyDependencies {
|
||||
readonly proxyBinPath: string;
|
||||
readonly proxyCert: SelfSignedCert;
|
||||
readonly spawn: Spawn;
|
||||
readonly logger: Logger;
|
||||
readonly waitUntilPortIsUsed: WaitUntilPortIsUsed;
|
||||
spawn: Spawn;
|
||||
waitUntilPortIsUsed: WaitUntilPortIsUsed;
|
||||
getPortFromStream: GetPortFromStream;
|
||||
}
|
||||
|
||||
export class KubeAuthProxy {
|
||||
@@ -101,7 +102,7 @@ export class KubeAuthProxy {
|
||||
}
|
||||
});
|
||||
|
||||
this._port = await getPortFrom(this.proxyProcess.stdout, {
|
||||
this._port = await this.dependencies.getPortFromStream(this.proxyProcess.stdout, {
|
||||
lineRegex: startingServeRegex,
|
||||
onFind: () => this.cluster.broadcastConnectUpdate("Authentication proxy started"),
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@ import kubectlVersionMapInjectable from "./version-map.injectable";
|
||||
import getDirnameOfPathInjectable from "../../common/path/get-dirname.injectable";
|
||||
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
||||
import getBasenameOfPathInjectable from "../../common/path/get-basename.injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
|
||||
const createKubectlInjectable = getInjectable({
|
||||
id: "create-kubectl",
|
||||
@@ -32,6 +33,7 @@ const createKubectlInjectable = getInjectable({
|
||||
baseBundeledBinariesDirectory: di.inject(baseBundledBinariesDirectoryInjectable),
|
||||
bundledKubectlVersion: di.inject(bundledKubectlVersionInjectable),
|
||||
kubectlVersionMap: di.inject(kubectlVersionMapInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
getDirnameOfPath: di.inject(getDirnameOfPathInjectable),
|
||||
joinPaths: di.inject(joinPathsInjectable),
|
||||
getBasenameOfPath: di.inject(getBasenameOfPathInjectable),
|
||||
|
||||
+20
-19
@@ -5,7 +5,6 @@
|
||||
|
||||
import fs from "fs";
|
||||
import { promiseExecFile } from "../../common/utils/promise-exec";
|
||||
import logger from "../logger";
|
||||
import { ensureDir, pathExists } from "fs-extra";
|
||||
import * as lockFile from "proper-lockfile";
|
||||
import { SemVer, coerce } from "semver";
|
||||
@@ -18,6 +17,7 @@ import type { JoinPaths } from "../../common/path/join-paths.injectable";
|
||||
import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable";
|
||||
import type { GetBasenameOfPath } from "../../common/path/get-basename.injectable";
|
||||
import type { NormalizedPlatform } from "../../common/vars/normalized-platform.injectable";
|
||||
import type { Logger } from "../../common/logger";
|
||||
|
||||
const initScriptVersionString = "# lens-initscript v3";
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface KubectlDependencies {
|
||||
};
|
||||
readonly bundledKubectlVersion: string;
|
||||
readonly kubectlVersionMap: Map<string, string>;
|
||||
readonly logger: Logger;
|
||||
joinPaths: JoinPaths;
|
||||
getDirnameOfPath: GetDirnameOfPath;
|
||||
getBasenameOfPath: GetBasenameOfPath;
|
||||
@@ -67,13 +68,13 @@ export class Kubectl {
|
||||
*/
|
||||
if (fromMajorMinor) {
|
||||
this.kubectlVersion = fromMajorMinor;
|
||||
logger.debug(`Set kubectl version ${this.kubectlVersion} for cluster version ${clusterVersion} using version map`);
|
||||
this.dependencies.logger.debug(`Set kubectl version ${this.kubectlVersion} for cluster version ${clusterVersion} using version map`);
|
||||
} else {
|
||||
/* this is the version (without possible prelease tag) to get from the download mirror */
|
||||
const ver = coerce(version.format()) ?? bundledVersion;
|
||||
|
||||
this.kubectlVersion = ver.format();
|
||||
logger.debug(`Set kubectl version ${this.kubectlVersion} for cluster version ${clusterVersion} using fallback`);
|
||||
this.dependencies.logger.debug(`Set kubectl version ${this.kubectlVersion} for cluster version ${clusterVersion} using fallback`);
|
||||
}
|
||||
|
||||
this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${this.dependencies.normalizedDownloadPlatform}/${this.dependencies.normalizedDownloadArch}/${this.dependencies.kubectlBinaryName}`;
|
||||
@@ -115,14 +116,14 @@ export class Kubectl {
|
||||
|
||||
try {
|
||||
if (!await this.ensureKubectl()) {
|
||||
logger.error("Failed to ensure kubectl, fallback to the bundled version");
|
||||
this.dependencies.logger.error("Failed to ensure kubectl, fallback to the bundled version");
|
||||
|
||||
return this.getBundledPath();
|
||||
}
|
||||
|
||||
return this.path;
|
||||
} catch (err) {
|
||||
logger.error("Failed to ensure kubectl, fallback to the bundled version", err);
|
||||
this.dependencies.logger.error("Failed to ensure kubectl, fallback to the bundled version", err);
|
||||
|
||||
return this.getBundledPath();
|
||||
}
|
||||
@@ -135,7 +136,7 @@ export class Kubectl {
|
||||
|
||||
return this.dirname;
|
||||
} catch (err) {
|
||||
logger.error("Failed to get biniary directory", err);
|
||||
this.dependencies.logger.error("Failed to get biniary directory", err);
|
||||
|
||||
return "";
|
||||
}
|
||||
@@ -164,13 +165,13 @@ export class Kubectl {
|
||||
}
|
||||
|
||||
if (version === this.kubectlVersion) {
|
||||
logger.debug(`Local kubectl is version ${this.kubectlVersion}`);
|
||||
this.dependencies.logger.debug(`Local kubectl is version ${this.kubectlVersion}`);
|
||||
|
||||
return true;
|
||||
}
|
||||
logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`);
|
||||
this.dependencies.logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`);
|
||||
} catch (error) {
|
||||
logger.error(`Local kubectl failed to run properly (${error}), unlinking`);
|
||||
this.dependencies.logger.error(`Local kubectl failed to run properly (${error}), unlinking`);
|
||||
}
|
||||
await fs.promises.unlink(this.path);
|
||||
}
|
||||
@@ -190,7 +191,7 @@ export class Kubectl {
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
logger.error(`Could not copy the bundled kubectl to app-data: ${err}`);
|
||||
this.dependencies.logger.error(`Could not copy the bundled kubectl to app-data: ${err}`);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -205,7 +206,7 @@ export class Kubectl {
|
||||
}
|
||||
|
||||
if (Kubectl.invalidBundle) {
|
||||
logger.error(`Detected invalid bundle binary, returning ...`);
|
||||
this.dependencies.logger.error(`Detected invalid bundle binary, returning ...`);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -215,7 +216,7 @@ export class Kubectl {
|
||||
try {
|
||||
const release = await lockFile.lock(this.dirname);
|
||||
|
||||
logger.debug(`Acquired a lock for ${this.kubectlVersion}`);
|
||||
this.dependencies.logger.debug(`Acquired a lock for ${this.kubectlVersion}`);
|
||||
const bundled = await this.checkBundled();
|
||||
let isValid = await this.checkBinary(this.path, !bundled);
|
||||
|
||||
@@ -223,8 +224,8 @@ export class Kubectl {
|
||||
try {
|
||||
await this.downloadKubectl();
|
||||
} catch (error) {
|
||||
logger.error(`[KUBECTL]: failed to download kubectl`, error);
|
||||
logger.debug(`[KUBECTL]: Releasing lock for ${this.kubectlVersion}`);
|
||||
this.dependencies.logger.error(`[KUBECTL]: failed to download kubectl`, error);
|
||||
this.dependencies.logger.debug(`[KUBECTL]: Releasing lock for ${this.kubectlVersion}`);
|
||||
await release();
|
||||
|
||||
return false;
|
||||
@@ -234,18 +235,18 @@ export class Kubectl {
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
logger.debug(`[KUBECTL]: Releasing lock for ${this.kubectlVersion}`);
|
||||
this.dependencies.logger.debug(`[KUBECTL]: Releasing lock for ${this.kubectlVersion}`);
|
||||
await release();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.debug(`[KUBECTL]: Releasing lock for ${this.kubectlVersion}`);
|
||||
this.dependencies.logger.debug(`[KUBECTL]: Releasing lock for ${this.kubectlVersion}`);
|
||||
await release();
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error(`[KUBECTL]: Failed to get a lock for ${this.kubectlVersion}`, error);
|
||||
this.dependencies.logger.error(`[KUBECTL]: Failed to get a lock for ${this.kubectlVersion}`, error);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -254,7 +255,7 @@ export class Kubectl {
|
||||
public async downloadKubectl() {
|
||||
await ensureDir(this.dependencies.getDirnameOfPath(this.path), 0o755);
|
||||
|
||||
logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`);
|
||||
this.dependencies.logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`);
|
||||
|
||||
const downloadStream = got.stream({ url: this.url, decompress: true });
|
||||
const fileWriteStream = fs.createWriteStream(this.path, { mode: 0o755 });
|
||||
@@ -263,7 +264,7 @@ export class Kubectl {
|
||||
try {
|
||||
await pipeline(downloadStream, fileWriteStream);
|
||||
await fs.promises.chmod(this.path, 0o755);
|
||||
logger.debug("kubectl binary download finished");
|
||||
this.dependencies.logger.debug("kubectl binary download finished");
|
||||
} catch (error) {
|
||||
await fs.promises.unlink(this.path).catch(noop);
|
||||
throw error;
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import processArchInjectable from "../../common/vars/process-arch.injectable";
|
||||
|
||||
const kubectlDownloadingNormalizedArchInjectable = getInjectable({
|
||||
id: "kubectl-downloading-normalized-arch",
|
||||
instantiate: () => {
|
||||
switch (process.arch) {
|
||||
instantiate: (di) => {
|
||||
const processArch = di.inject(processArchInjectable);
|
||||
|
||||
switch (processArch) {
|
||||
case "arm64":
|
||||
return "arm64";
|
||||
case "x64":
|
||||
@@ -18,10 +21,9 @@ const kubectlDownloadingNormalizedArchInjectable = getInjectable({
|
||||
case "ia32":
|
||||
return "386";
|
||||
default:
|
||||
throw new Error(`arch=${process.arch} is unsupported`);
|
||||
throw new Error(`arch=${processArch} is unsupported`);
|
||||
}
|
||||
},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default kubectlDownloadingNormalizedArchInjectable;
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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 getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable";
|
||||
import { getClusterIdFromHost } from "../../common/utils";
|
||||
import { apiKubePrefix } from "../../common/vars";
|
||||
import type { GetClusterForRequest } from "./lens-proxy";
|
||||
|
||||
const getClusterForRequestInjectable = getInjectable({
|
||||
id: "get-cluster-for-request",
|
||||
instantiate: (di): GetClusterForRequest => {
|
||||
const getClusterById = di.inject(getClusterByIdInjectable);
|
||||
|
||||
return (req) => {
|
||||
if (!req.headers.host) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// lens-server is connecting to 127.0.0.1:<port>/<uid>
|
||||
if (req.url && req.headers.host.startsWith("127.0.0.1")) {
|
||||
const clusterId = req.url.split("/")[1];
|
||||
const cluster = getClusterById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
// we need to swap path prefix so that request is proxied to kube api
|
||||
req.url = req.url.replace(`/${clusterId}`, apiKubePrefix);
|
||||
}
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
const clusterId = getClusterIdFromHost(req.headers.host);
|
||||
|
||||
if (!clusterId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getClusterById(clusterId);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default getClusterForRequestInjectable;
|
||||
@@ -7,13 +7,13 @@ 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 shellApiRequestInjectable from "./proxy-functions/shell-api-request.injectable";
|
||||
import lensProxyPortInjectable from "./lens-proxy-port.injectable";
|
||||
import contentSecurityPolicyInjectable from "../../common/vars/content-security-policy.injectable";
|
||||
import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import lensProxyCertificateInjectable from "../../common/certificate/lens-proxy-certificate.injectable";
|
||||
import getClusterForRequestInjectable from "./get-cluster-for-request.injectable";
|
||||
|
||||
const lensProxyInjectable = getInjectable({
|
||||
id: "lens-proxy",
|
||||
@@ -23,7 +23,7 @@ const lensProxyInjectable = getInjectable({
|
||||
proxy: httpProxy.createProxy(),
|
||||
kubeApiUpgradeRequest,
|
||||
shellApiRequest: di.inject(shellApiRequestInjectable),
|
||||
getClusterForRequest: di.inject(clusterManagerInjectable).getClusterForRequest,
|
||||
getClusterForRequest: di.inject(getClusterForRequestInjectable),
|
||||
lensProxyPort: di.inject(lensProxyPortInjectable),
|
||||
contentSecurityPolicy: di.inject(contentSecurityPolicyInjectable),
|
||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||
|
||||
@@ -19,14 +19,14 @@ import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injecta
|
||||
import type { Logger } from "../../common/logger";
|
||||
import type { SelfSignedCert } from "selfsigned";
|
||||
|
||||
type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | undefined;
|
||||
|
||||
export type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | undefined;
|
||||
export type ServerIncomingMessage = SetRequired<http.IncomingMessage, "url" | "method">;
|
||||
export type LensProxyApiRequest = (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||
|
||||
interface Dependencies {
|
||||
getClusterForRequest: GetClusterForRequest;
|
||||
shellApiRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||
kubeApiUpgradeRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||
shellApiRequest: LensProxyApiRequest;
|
||||
kubeApiUpgradeRequest: LensProxyApiRequest;
|
||||
emitAppEvent: EmitAppEvent;
|
||||
readonly router: Router;
|
||||
readonly proxy: httpProxy;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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 shellRequestAuthenticatorInjectable from "./shell-request-authenticator/shell-request-authenticator.injectable";
|
||||
import openShellSessionInjectable from "../../shell-session/create-shell-session.injectable";
|
||||
import type { LensProxyApiRequest } from "../lens-proxy";
|
||||
import URLParse from "url-parse";
|
||||
import { Server as WebSocketServer } from "ws";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import getClusterForRequestInjectable from "../get-cluster-for-request.injectable";
|
||||
|
||||
const shellApiRequestInjectable = getInjectable({
|
||||
id: "shell-api-request",
|
||||
|
||||
instantiate: (di): LensProxyApiRequest => {
|
||||
const openShellSession = di.inject(openShellSessionInjectable);
|
||||
const authenticateRequest = di.inject(shellRequestAuthenticatorInjectable).authenticate;
|
||||
const getClusterForRequest = di.inject(getClusterForRequestInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return ({ req, socket, head }) => {
|
||||
const cluster = getClusterForRequest(req);
|
||||
const { query: { node: nodeName, shellToken, id: tabId }} = new URLParse(req.url, true);
|
||||
|
||||
if (!tabId || !cluster || !authenticateRequest(cluster.id, tabId, shellToken)) {
|
||||
socket.write("Invalid shell request");
|
||||
socket.end();
|
||||
} else {
|
||||
const ws = new WebSocketServer({ noServer: true });
|
||||
|
||||
ws.handleUpgrade(req, socket, head, (websocket) => {
|
||||
openShellSession({ websocket, cluster, tabId, nodeName })
|
||||
.catch(error => logger.error(`[SHELL-SESSION]: failed to open a ${nodeName ? "node" : "local"} shell`, error));
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default shellApiRequestInjectable;
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* 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 { shellApiRequest } from "./shell-api-request";
|
||||
import shellRequestAuthenticatorInjectable from "./shell-request-authenticator/shell-request-authenticator.injectable";
|
||||
import clusterManagerInjectable from "../../../cluster/manager.injectable";
|
||||
import openShellSessionInjectable from "../../../shell-session/create-shell-session.injectable";
|
||||
|
||||
const shellApiRequestInjectable = getInjectable({
|
||||
id: "shell-api-request",
|
||||
|
||||
instantiate: (di) => shellApiRequest({
|
||||
openShellSession: di.inject(openShellSessionInjectable),
|
||||
authenticateRequest: di.inject(shellRequestAuthenticatorInjectable).authenticate,
|
||||
clusterManager: di.inject(clusterManagerInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default shellApiRequestInjectable;
|
||||
@@ -1,36 +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";
|
||||
import { Server as WebSocketServer } from "ws";
|
||||
import type { ProxyApiRequestArgs } from "../types";
|
||||
import type { ClusterManager } from "../../../cluster/manager";
|
||||
import URLParse from "url-parse";
|
||||
import type { ClusterId } from "../../../../common/cluster-types";
|
||||
import type { OpenShellSession } from "../../../shell-session/create-shell-session.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
authenticateRequest: (clusterId: ClusterId, tabId: string, shellToken: string | undefined) => boolean;
|
||||
openShellSession: OpenShellSession;
|
||||
clusterManager: ClusterManager;
|
||||
}
|
||||
|
||||
export const shellApiRequest = ({ openShellSession, 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 (!tabId || !cluster || !authenticateRequest(cluster.id, tabId, shellToken)) {
|
||||
socket.write("Invalid shell request");
|
||||
|
||||
return void socket.end();
|
||||
}
|
||||
|
||||
const ws = new WebSocketServer({ noServer: true });
|
||||
|
||||
ws.handleUpgrade(req, socket, head, (websocket) => {
|
||||
openShellSession({ websocket, cluster, tabId, nodeName })
|
||||
.catch(error => logger.error(`[SHELL-SESSION]: failed to open a ${nodeName ? "node" : "local"} shell`, error));
|
||||
});
|
||||
};
|
||||
File renamed without changes.
+3
-3
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getOrInsertMap } from "../../../../../common/utils";
|
||||
import type { ClusterId } from "../../../../../common/cluster-types";
|
||||
import { ipcMainHandle } from "../../../../../common/ipc";
|
||||
import { getOrInsertMap } from "../../../../common/utils";
|
||||
import type { ClusterId } from "../../../../common/cluster-types";
|
||||
import { ipcMainHandle } from "../../../../common/ipc";
|
||||
import crypto from "crypto";
|
||||
import { promisify } from "util";
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import logger from "../common/logger";
|
||||
|
||||
export default logger;
|
||||
@@ -13,14 +13,12 @@ import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import parseRequestInjectable from "./parse-request.injectable";
|
||||
import { contentTypes } from "./router-content-types";
|
||||
import mockFs from "mock-fs";
|
||||
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import type { Route } from "./route";
|
||||
import type { SetRequired } from "type-fest";
|
||||
import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable";
|
||||
import kubectlBinaryNameInjectable from "../kubectl/binary-name.injectable";
|
||||
import kubectlDownloadingNormalizedArchInjectable from "../kubectl/normalized-arch.injectable";
|
||||
import fsInjectable from "../../common/fs/fs.injectable";
|
||||
import { runInAction } from "mobx";
|
||||
|
||||
describe("router", () => {
|
||||
@@ -32,14 +30,11 @@ describe("router", () => {
|
||||
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
mockFs();
|
||||
di.permitSideEffects(fsInjectable);
|
||||
|
||||
di.override(parseRequestInjectable, () => () => Promise.resolve({
|
||||
payload: "some-payload",
|
||||
mime: "some-mime",
|
||||
}));
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
|
||||
di.override(kubectlBinaryNameInjectable, () => "kubectl");
|
||||
di.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
|
||||
di.override(normalizedPlatformInjectable, () => "darwin");
|
||||
@@ -63,10 +58,6 @@ describe("router", () => {
|
||||
router = di.inject(routerInjectable);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
describe("when navigating to the route", () => {
|
||||
let actualPromise: Promise<boolean>;
|
||||
let clusterStub: Cluster;
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import deleteHelmReleaseInjectable from "../../../helm/helm-service/delete-helm-release.injectable";
|
||||
import deleteClusterHelmReleaseInjectable from "../../../helm/helm-service/delete-helm-release.injectable";
|
||||
|
||||
const deleteReleaseRouteInjectable = getRouteInjectable({
|
||||
id: "delete-release-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const deleteHelmRelease = di.inject(deleteHelmReleaseInjectable);
|
||||
const deleteHelmRelease = di.inject(deleteClusterHelmReleaseInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "delete",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}`,
|
||||
})(async ({ cluster, params: { release, namespace }}) => ({
|
||||
response: await deleteHelmRelease(cluster, release, namespace),
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{name}`,
|
||||
})(async ({ cluster, params }) => ({
|
||||
response: await deleteHelmRelease(cluster, params),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -5,23 +5,19 @@
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import getHelmReleaseHistoryInjectable from "../../../helm/helm-service/get-helm-release-history.injectable";
|
||||
import getClusterHelmReleaseHistoryInjectable from "../../../helm/helm-service/get-helm-release-history.injectable";
|
||||
|
||||
const getReleaseRouteHistoryInjectable = getRouteInjectable({
|
||||
id: "get-release-history-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getHelmReleaseHistory = di.inject(getHelmReleaseHistoryInjectable);
|
||||
const getHelmReleaseHistory = di.inject(getClusterHelmReleaseHistoryInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}/history`,
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{name}/history`,
|
||||
})(async ({ cluster, params }) => ({
|
||||
response: await getHelmReleaseHistory(
|
||||
cluster,
|
||||
params.release,
|
||||
params.namespace,
|
||||
),
|
||||
response: await getHelmReleaseHistory(cluster, params),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -7,20 +7,20 @@ import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { getBoolean } from "../../../utils/parse-query";
|
||||
import { contentTypes } from "../../../router/router-content-types";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import getHelmReleaseValuesInjectable from "../../../helm/helm-service/get-helm-release-values.injectable";
|
||||
import getClusterHelmReleaseValuesInjectable from "../../../helm/helm-service/get-helm-release-values.injectable";
|
||||
|
||||
const getReleaseRouteValuesInjectable = getRouteInjectable({
|
||||
id: "get-release-values-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getHelmReleaseValues = di.inject(getHelmReleaseValuesInjectable);
|
||||
const getClusterHelmReleaseValues = di.inject(getClusterHelmReleaseValuesInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}/values`,
|
||||
})(async ({ cluster, params: { namespace, release }, query }) => ({
|
||||
response: await getHelmReleaseValues(release, {
|
||||
cluster,
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{name}/values`,
|
||||
})(async ({ cluster, params: { namespace, name }, query }) => ({
|
||||
response: await getClusterHelmReleaseValues(cluster, {
|
||||
name,
|
||||
namespace,
|
||||
all: getBoolean(query, "all"),
|
||||
}),
|
||||
|
||||
@@ -7,7 +7,7 @@ import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import Joi from "joi";
|
||||
import { payloadValidatedClusterRoute } from "../../../router/route";
|
||||
import type { InstallChartArgs } from "../../../helm/helm-service/install-helm-chart.injectable";
|
||||
import installHelmChartInjectable from "../../../helm/helm-service/install-helm-chart.injectable";
|
||||
import installClusterHelmChartInjectable from "../../../helm/helm-service/install-helm-chart.injectable";
|
||||
|
||||
const installChartArgsValidator = Joi.object<InstallChartArgs, true, InstallChartArgs>({
|
||||
chart: Joi
|
||||
@@ -31,7 +31,7 @@ const installChartRouteInjectable = getRouteInjectable({
|
||||
id: "install-chart-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const installHelmChart = di.inject(installHelmChartInjectable);
|
||||
const installHelmChart = di.inject(installClusterHelmChartInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "post",
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import listHelmReleasesInjectable from "../../../helm/helm-service/list-helm-releases.injectable";
|
||||
import listClusterHelmReleasesInjectable from "../../../helm/helm-service/list-helm-releases.injectable";
|
||||
|
||||
const listReleasesRouteInjectable = getRouteInjectable({
|
||||
id: "list-releases-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const listHelmReleases = di.inject(listHelmReleasesInjectable);
|
||||
const listHelmReleases = di.inject(listClusterHelmReleasesInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "get",
|
||||
|
||||
@@ -6,7 +6,7 @@ import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import Joi from "joi";
|
||||
import { payloadValidatedClusterRoute } from "../../../router/route";
|
||||
import rollbackHelmReleaseInjectable from "../../../helm/helm-service/rollback-helm-release.injectable";
|
||||
import rollbackClusterHelmReleaseInjectable from "../../../helm/helm-service/rollback-helm-release.injectable";
|
||||
|
||||
interface RollbackReleasePayload {
|
||||
revision: number;
|
||||
@@ -22,14 +22,14 @@ const rollbackReleaseRouteInjectable = getRouteInjectable({
|
||||
id: "rollback-release-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const rollbackRelease = di.inject(rollbackHelmReleaseInjectable);
|
||||
const rollbackRelease = di.inject(rollbackClusterHelmReleaseInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "put",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback`,
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{name}/rollback`,
|
||||
payloadValidator: rollbackReleasePayloadValidator,
|
||||
})(async ({ cluster, params: { release, namespace }, payload }) => {
|
||||
await rollbackRelease(cluster, release, namespace, payload.revision);
|
||||
})(async ({ cluster, params, payload }) => {
|
||||
await rollbackRelease(cluster, { ...params, ...payload });
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -3,22 +3,25 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { PortForwardArgs } from "./port-forward";
|
||||
import type { PortForwardArgs, PortForwardDependencies } from "./port-forward";
|
||||
import { PortForward } from "./port-forward";
|
||||
import bundledKubectlInjectable from "../../../kubectl/bundled-kubectl.injectable";
|
||||
import getPortFromStreamInjectable from "../../../utils/get-port-from-stream.injectable";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
|
||||
export type CreatePortForward = (pathToKubeConfig: string, args: PortForwardArgs) => PortForward;
|
||||
|
||||
const createPortForwardInjectable = getInjectable({
|
||||
id: "create-port-forward",
|
||||
|
||||
instantiate: (di) => {
|
||||
const bundledKubectl = di.inject(bundledKubectlInjectable);
|
||||
|
||||
const dependencies = {
|
||||
getKubectlBinPath: bundledKubectl.getPath,
|
||||
instantiate: (di): CreatePortForward => {
|
||||
const dependencies: PortForwardDependencies = {
|
||||
getKubectlBinPath: di.inject(bundledKubectlInjectable).getPath,
|
||||
getPortFromStream: di.inject(getPortFromStreamInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
};
|
||||
|
||||
return (pathToKubeConfig: string, args: PortForwardArgs) =>
|
||||
new PortForward(dependencies, pathToKubeConfig, args);
|
||||
return (pathToKubeConfig, args) => new PortForward(dependencies, pathToKubeConfig, args);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import logger from "../../../logger";
|
||||
import { getPortFrom } from "../../../utils/get-port";
|
||||
import type { GetPortFromStream } from "../../../utils/get-port-from-stream.injectable";
|
||||
import type { ChildProcessWithoutNullStreams } from "child_process";
|
||||
import { spawn } from "child_process";
|
||||
import * as tcpPortUsed from "tcp-port-used";
|
||||
import { TypedRegEx } from "typed-regex";
|
||||
import type { Logger } from "../../../../common/logger";
|
||||
|
||||
const internalPortMatcher = "^forwarding from (?<address>.+) ->";
|
||||
const internalPortRegex = Object.assign(TypedRegEx(internalPortMatcher, "i"), {
|
||||
@@ -23,8 +23,10 @@ export interface PortForwardArgs {
|
||||
forwardPort: number;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
export interface PortForwardDependencies {
|
||||
readonly logger: Logger;
|
||||
getKubectlBinPath: (bundled: boolean) => Promise<string>;
|
||||
getPortFromStream: GetPortFromStream;
|
||||
}
|
||||
|
||||
export class PortForward {
|
||||
@@ -48,7 +50,7 @@ export class PortForward {
|
||||
public port: number;
|
||||
public forwardPort: number;
|
||||
|
||||
constructor(private dependencies: Dependencies, public pathToKubeConfig: string, args: PortForwardArgs) {
|
||||
constructor(private dependencies: PortForwardDependencies, public pathToKubeConfig: string, args: PortForwardArgs) {
|
||||
this.clusterId = args.clusterId;
|
||||
this.kind = args.kind;
|
||||
this.namespace = args.namespace;
|
||||
@@ -80,10 +82,10 @@ export class PortForward {
|
||||
});
|
||||
|
||||
this.process.stderr.on("data", (data) => {
|
||||
logger.debug(`[PORT-FORWARD-ROUTE]: kubectl port-forward process stderr: ${data}`);
|
||||
this.dependencies.logger.debug(`[PORT-FORWARD-ROUTE]: kubectl port-forward process stderr: ${data}`);
|
||||
});
|
||||
|
||||
const internalPort = await getPortFrom(this.process.stdout, {
|
||||
const internalPort = await this.dependencies.getPortFromStream(this.process.stdout, {
|
||||
lineRegex: internalPortRegex,
|
||||
});
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ import type { KubeConfig } from "@kubernetes/client-node";
|
||||
import type { ShellSessionArgs, ShellSessionDependencies } from "../shell-session";
|
||||
import { ShellOpenError, ShellSession } from "../shell-session";
|
||||
import { get, once } from "lodash";
|
||||
import { Node, NodeApi } from "../../../common/k8s-api/endpoints";
|
||||
import { NodeApi } from "../../../common/k8s-api/endpoints";
|
||||
import { TerminalChannels } from "../../../common/terminal/channels";
|
||||
import type { CreateKubeJsonApiForCluster } from "../../../common/k8s-api/create-kube-json-api-for-cluster.injectable";
|
||||
import type { CreateKubeApi } from "../../../common/k8s-api/create-kube-api.injectable";
|
||||
|
||||
export interface NodeShellSessionArgs extends ShellSessionArgs {
|
||||
nodeName: string;
|
||||
@@ -19,6 +20,7 @@ export interface NodeShellSessionArgs extends ShellSessionArgs {
|
||||
|
||||
export interface NodeShellSessionDependencies extends ShellSessionDependencies {
|
||||
createKubeJsonApiForCluster: CreateKubeJsonApiForCluster;
|
||||
createKubeApi: CreateKubeApi;
|
||||
}
|
||||
|
||||
export class NodeShellSession extends ShellSession {
|
||||
@@ -67,8 +69,7 @@ export class NodeShellSession extends ShellSession {
|
||||
|
||||
const env = await this.getCachedShellEnv();
|
||||
const args = ["exec", "-i", "-t", "-n", "kube-system", this.podName, "--"];
|
||||
const nodeApi = new NodeApi({
|
||||
objectConstructor: Node,
|
||||
const nodeApi = this.dependencies.createKubeApi(NodeApi, {
|
||||
request: this.dependencies.createKubeJsonApiForCluster(this.cluster.id),
|
||||
});
|
||||
const node = await nodeApi.get({ name: this.nodeName });
|
||||
|
||||
@@ -19,6 +19,7 @@ import appNameInjectable from "../../../common/vars/app-name.injectable";
|
||||
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
|
||||
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||
import statInjectable from "../../../common/fs/stat.injectable";
|
||||
import createKubeApiInjectable from "../../../common/k8s-api/create-kube-api.injectable";
|
||||
|
||||
export interface NodeShellSessionArgs {
|
||||
websocket: WebSocket;
|
||||
@@ -45,6 +46,7 @@ const openNodeShellSessionInjectable = getInjectable({
|
||||
spawnPty: di.inject(spawnPtyInjectable),
|
||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||
stat: di.inject(statInjectable),
|
||||
createKubeApi: di.inject(createKubeApiInjectable),
|
||||
};
|
||||
|
||||
return async (args) => {
|
||||
|
||||
-2
@@ -28,8 +28,6 @@ const startKubeConfigSyncInjectable = getInjectable({
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
|
||||
injectionToken: afterApplicationIsLoadedInjectionToken,
|
||||
});
|
||||
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import environmentVariablesInjectable from "../../../common/utils/environment-variables.injectable";
|
||||
import disableHardwareAccelerationInjectable from "../../electron-app/features/disable-hardware-acceleration.injectable";
|
||||
import hardwareAccelerationShouldBeDisabledInjectable from "../../vars/hardware-acceleration-should-be-disabled.injectable";
|
||||
import { beforeElectronIsReadyInjectionToken } from "../runnable-tokens/before-electron-is-ready-injection-token";
|
||||
|
||||
const setupHardwareAccelerationInjectable = getInjectable({
|
||||
id: "setup-hardware-acceleration",
|
||||
|
||||
instantiate: (di) => {
|
||||
const { LENS_DISABLE_GPU: hardwareAccelerationShouldBeDisabled } = di.inject(environmentVariablesInjectable);
|
||||
const hardwareAccelerationShouldBeDisabled = di.inject(hardwareAccelerationShouldBeDisabledInjectable);
|
||||
const disableHardwareAcceleration = di.inject(disableHardwareAccelerationInjectable);
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import commandLineArgumentsInjectable from "./command-line-arguments.injectable";
|
||||
|
||||
export default getGlobalOverride(commandLineArgumentsInjectable, () => []);
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { Readable } from "stream";
|
||||
import URLParse from "url-parse";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
|
||||
export interface GetPortFromStreamArgs {
|
||||
/**
|
||||
* Should be case insensitive
|
||||
* Must have a named matching group called `address`
|
||||
*/
|
||||
lineRegex: {
|
||||
match: (line: string) => {
|
||||
matched: boolean;
|
||||
groups?: {
|
||||
address?: string;
|
||||
};
|
||||
raw?: RegExpExecArray;
|
||||
};
|
||||
rawMatcher: string;
|
||||
};
|
||||
/**
|
||||
* Called when the port is found
|
||||
*/
|
||||
onFind?: () => void;
|
||||
/**
|
||||
* Timeout for how long to wait for the port.
|
||||
* Default: 15s
|
||||
*/
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
export type GetPortFromStream = (stream: Readable, args: GetPortFromStreamArgs) => Promise<number>;
|
||||
|
||||
const getPortFromStreamInjectable = getInjectable({
|
||||
id: "get-port-from-stream",
|
||||
instantiate: (di): GetPortFromStream => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return (stream, args) => {
|
||||
const logLines: string[] = [];
|
||||
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
const handler = (data: unknown) => {
|
||||
const logItem = String(data);
|
||||
const match = args.lineRegex.match(logItem);
|
||||
|
||||
logLines.push(logItem);
|
||||
|
||||
if (match.matched) {
|
||||
// use unknown protocol so that there is no default port
|
||||
const addr = new URLParse(`s://${match.groups?.address?.trim()}`);
|
||||
|
||||
args.onFind?.();
|
||||
stream.off("data", handler);
|
||||
clearTimeout(timeoutID);
|
||||
resolve(+addr.port);
|
||||
}
|
||||
};
|
||||
const timeoutID = setTimeout(() => {
|
||||
stream.off("data", handler);
|
||||
logger.warn(`[getPortFrom]: failed to retrieve port via ${args.lineRegex.rawMatcher}`, logLines);
|
||||
reject(new Error("failed to retrieve port from stream"));
|
||||
}, args.timeout ?? 15000);
|
||||
|
||||
stream.on("data", handler);
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default getPortFromStreamInjectable;
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { Readable } from "stream";
|
||||
import URLParse from "url-parse";
|
||||
import logger from "../logger";
|
||||
|
||||
interface GetPortArgs {
|
||||
/**
|
||||
* Should be case insensitive
|
||||
* Must have a named matching group called `address`
|
||||
*/
|
||||
lineRegex: {
|
||||
match: (line: string) => {
|
||||
matched: boolean;
|
||||
groups?: {
|
||||
address?: string;
|
||||
};
|
||||
raw?: RegExpExecArray;
|
||||
};
|
||||
rawMatcher: string;
|
||||
};
|
||||
/**
|
||||
* Called when the port is found
|
||||
*/
|
||||
onFind?: () => void;
|
||||
/**
|
||||
* Timeout for how long to wait for the port.
|
||||
* Default: 15s
|
||||
*/
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse lines from `stream` (assumes data comes in lines) to find the port
|
||||
* which the source of the stream is watching on.
|
||||
* @param stream A readable stream to match lines against
|
||||
* @param args The args concerning the stream
|
||||
* @returns A Promise for port number
|
||||
*/
|
||||
export function getPortFrom(stream: Readable, args: GetPortArgs): Promise<number> {
|
||||
const logLines: string[] = [];
|
||||
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
const handler = (data: unknown) => {
|
||||
const logItem = String(data);
|
||||
const match = args.lineRegex.match(logItem);
|
||||
|
||||
logLines.push(logItem);
|
||||
|
||||
if (match.matched) {
|
||||
// use unknown protocol so that there is no default port
|
||||
const addr = new URLParse(`s://${match.groups?.address?.trim()}`);
|
||||
|
||||
args.onFind?.();
|
||||
stream.off("data", handler);
|
||||
clearTimeout(timeoutID);
|
||||
resolve(+addr.port);
|
||||
}
|
||||
};
|
||||
const timeoutID = setTimeout(() => {
|
||||
stream.off("data", handler);
|
||||
logger.warn(`[getPortFrom]: failed to retrieve port via ${args.lineRegex.rawMatcher}`, logLines);
|
||||
reject(new Error("failed to retrieve port from stream"));
|
||||
}, args.timeout ?? 15000);
|
||||
|
||||
stream.on("data", handler);
|
||||
});
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import applicationInformationInjectable from "../../common/vars/application-information-injectable";
|
||||
|
||||
export default getGlobalOverride(applicationInformationInjectable, () => ({
|
||||
name: "some-product-name",
|
||||
productName: "some-product-name",
|
||||
version: "6.0.0",
|
||||
build: {} as any,
|
||||
config: {
|
||||
k8sProxyVersion: "0.2.1",
|
||||
bundledKubectlVersion: "1.23.3",
|
||||
bundledHelmVersion: "3.7.2",
|
||||
sentryDsn: "",
|
||||
contentSecurityPolicy: "script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:",
|
||||
welcomeRoute: "/welcome",
|
||||
},
|
||||
copyright: "some-copyright-information",
|
||||
description: "some-descriptive-text",
|
||||
}));
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import hardwareAccelerationShouldBeDisabledInjectable from "./hardware-acceleration-should-be-disabled.injectable";
|
||||
|
||||
export default getGlobalOverride(hardwareAccelerationShouldBeDisabledInjectable, () => false);
|
||||
@@ -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";
|
||||
|
||||
const hardwareAccelerationShouldBeDisabledInjectable = getInjectable({
|
||||
id: "hardware-acceleration-should-be-disabled",
|
||||
instantiate: () => Boolean(process.env.LENS_DISABLE_GPU),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default hardwareAccelerationShouldBeDisabledInjectable;
|
||||
Reference in new issue
Block a user