mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into app-modal-registry
This commit is contained in:
commit
3bdbf2bc46
445 files changed
+19436
-6675
No files matched your search
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import https from "https";
|
||||
import os from "os";
|
||||
import { getMacRootCA, getWinRootCA, injectCAs, DSTRootCAX3 } from "../system-ca";
|
||||
import { dependencies, devDependencies } from "../../../package.json";
|
||||
import assert from "assert";
|
||||
|
||||
const deps = { ...dependencies, ...devDependencies };
|
||||
|
||||
// Skip the test if mac-ca is not installed, or os is not darwin
|
||||
(deps["mac-ca"] && os.platform().includes("darwin") ? describe: describe.skip)("inject CA for Mac", () => {
|
||||
// for reset https.globalAgent.options.ca after testing
|
||||
let _ca: string | Buffer | (string | Buffer)[] | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
_ca = https.globalAgent.options.ca;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
https.globalAgent.options.ca = _ca;
|
||||
});
|
||||
|
||||
/**
|
||||
* The test to ensure using getMacRootCA + injectCAs injects CAs in the same way as using
|
||||
* the auto injection (require('mac-ca'))
|
||||
*/
|
||||
it("should inject the same ca as mac-ca", async () => {
|
||||
const osxCAs = await getMacRootCA();
|
||||
|
||||
injectCAs(osxCAs);
|
||||
const injected = https.globalAgent.options.ca as (string | Buffer)[];
|
||||
|
||||
await import("mac-ca");
|
||||
const injectedByMacCA = https.globalAgent.options.ca as (string | Buffer)[];
|
||||
|
||||
expect(new Set(injected)).toEqual(new Set(injectedByMacCA));
|
||||
});
|
||||
|
||||
it("shouldn't included the expired DST Root CA X3 on Mac", async () => {
|
||||
const osxCAs = await getMacRootCA();
|
||||
|
||||
injectCAs(osxCAs);
|
||||
const injected = https.globalAgent.options.ca;
|
||||
|
||||
assert(injected);
|
||||
expect(injected.includes(DSTRootCAX3)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
// Skip the test if win-ca is not installed, or os is not win32
|
||||
(deps["win-ca"] && os.platform().includes("win32") ? describe: describe.skip)("inject CA for Windows", () => {
|
||||
// for reset https.globalAgent.options.ca after testing
|
||||
let _ca: string | Buffer | (string | Buffer)[] | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
_ca = https.globalAgent.options.ca;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
https.globalAgent.options.ca = _ca;
|
||||
});
|
||||
|
||||
/**
|
||||
* The test to ensure using win-ca/api injects CAs in the same way as using
|
||||
* the auto injection (require('win-ca').inject('+'))
|
||||
*/
|
||||
it("should inject the same ca as winca.inject('+')", async () => {
|
||||
const winCAs = await getWinRootCA();
|
||||
|
||||
const wincaAPI = await import("win-ca/api");
|
||||
|
||||
wincaAPI.inject("+", winCAs);
|
||||
const injected = https.globalAgent.options.ca as (string | Buffer)[];
|
||||
|
||||
const winca = await import("win-ca");
|
||||
|
||||
winca.inject("+"); // see: https://github.com/ukoloff/win-ca#caveats
|
||||
const injectedByWinCA = https.globalAgent.options.ca as (string | Buffer)[];
|
||||
|
||||
expect(new Set(injected)).toEqual(new Set(injectedByWinCA));
|
||||
});
|
||||
|
||||
it("shouldn't included the expired DST Root CA X3 on Windows", async () => {
|
||||
const winCAs = await getWinRootCA();
|
||||
|
||||
const wincaAPI = await import("win-ca/api");
|
||||
|
||||
wincaAPI.inject("true", winCAs);
|
||||
const injected = https.globalAgent.options.ca as (string | Buffer)[];
|
||||
|
||||
expect(injected.includes(DSTRootCAX3)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import directoryForUserDataInjectable from "../directory-for-user-data/directory-for-user-data.injectable";
|
||||
import getAbsolutePathInjectable from "../../path/get-absolute-path.injectable";
|
||||
import joinPathsInjectable from "../../path/join-paths.injectable";
|
||||
|
||||
const directoryForBinariesInjectable = getInjectable({
|
||||
id: "directory-for-binaries",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getAbsolutePath = di.inject(getAbsolutePathInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const directoryForUserData = di.inject(directoryForUserDataInjectable);
|
||||
|
||||
return getAbsolutePath(directoryForUserData, "binaries");
|
||||
return joinPaths(directoryForUserData, "binaries");
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
+3
-6
@@ -4,19 +4,16 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import directoryForUserDataInjectable from "../directory-for-user-data/directory-for-user-data.injectable";
|
||||
import getAbsolutePathInjectable from "../../path/get-absolute-path.injectable";
|
||||
import joinPathsInjectable from "../../path/join-paths.injectable";
|
||||
|
||||
const directoryForKubeConfigsInjectable = getInjectable({
|
||||
id: "directory-for-kube-configs",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getAbsolutePath = di.inject(getAbsolutePathInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const directoryForUserData = di.inject(directoryForUserDataInjectable);
|
||||
|
||||
return getAbsolutePath(
|
||||
directoryForUserData,
|
||||
"kubeconfigs",
|
||||
);
|
||||
return joinPaths(directoryForUserData, "kubeconfigs");
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
+3
-4
@@ -4,17 +4,16 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import directoryForBinariesInjectable from "../directory-for-binaries/directory-for-binaries.injectable";
|
||||
import getAbsolutePathInjectable from "../../path/get-absolute-path.injectable";
|
||||
import joinPathsInjectable from "../../path/join-paths.injectable";
|
||||
|
||||
const directoryForKubectlBinariesInjectable = getInjectable({
|
||||
id: "directory-for-kubectl-binaries",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getAbsolutePath = di.inject(getAbsolutePathInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const directoryForBinaries = di.inject(directoryForBinariesInjectable);
|
||||
|
||||
|
||||
return getAbsolutePath(directoryForBinaries, "kubectl");
|
||||
return joinPaths(directoryForBinaries, "kubectl");
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
+3
-4
@@ -4,17 +4,16 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import directoryForKubeConfigsInjectable from "../directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||
import getAbsolutePathInjectable from "../../path/get-absolute-path.injectable";
|
||||
import joinPathsInjectable from "../../path/join-paths.injectable";
|
||||
|
||||
const getCustomKubeConfigDirectoryInjectable = getInjectable({
|
||||
id: "get-custom-kube-config-directory",
|
||||
|
||||
instantiate: (di) => {
|
||||
const directoryForKubeConfigs = di.inject(directoryForKubeConfigsInjectable);
|
||||
const getAbsolutePath = di.inject(getAbsolutePathInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
|
||||
return (directoryName: string) =>
|
||||
getAbsolutePath(directoryForKubeConfigs, directoryName);
|
||||
return (directoryName: string) => joinPaths(directoryForKubeConfigs, directoryName);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import catalogCategoryRegistryInjectable from "./category-registry.injectable";
|
||||
|
||||
const filteredCategoriesInjectable = getInjectable({
|
||||
id: "filtered-categories",
|
||||
instantiate: (di) => {
|
||||
const registry = di.inject(catalogCategoryRegistryInjectable);
|
||||
|
||||
return computed(() => [...registry.filteredItems]);
|
||||
},
|
||||
});
|
||||
|
||||
export default filteredCategoriesInjectable;
|
||||
@@ -1,39 +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 { globalAgent } from "https";
|
||||
import { requestSystemCAsInjectionToken } from "./request-system-cas-token";
|
||||
|
||||
// DST Root CA X3, which was expired on 9.30.2021
|
||||
const DSTRootCAX3 = "-----BEGIN CERTIFICATE-----\nMIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\nPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\nEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\nrz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\nOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\nxiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\naeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\nHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\nSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\nikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\nAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\nR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\nJDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\nOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n-----END CERTIFICATE-----\n";
|
||||
|
||||
function isCertActive(cert: string) {
|
||||
const isExpired = typeof cert !== "string" || cert.includes(DSTRootCAX3);
|
||||
|
||||
return !isExpired;
|
||||
}
|
||||
|
||||
const injectSystemCAsInjectable = getInjectable({
|
||||
id: "inject-system-cas",
|
||||
instantiate: (di) => {
|
||||
const requestSystemCAs = di.inject(requestSystemCAsInjectionToken);
|
||||
|
||||
return async () => {
|
||||
for (const cert of await requestSystemCAs()) {
|
||||
if (isCertActive(cert)) {
|
||||
if (Array.isArray(globalAgent.options.ca) && !globalAgent.options.ca.includes(cert)) {
|
||||
globalAgent.options.ca.push(cert);
|
||||
} else {
|
||||
globalAgent.options.ca = [cert];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default injectSystemCAsInjectable;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
|
||||
export const requestSystemCAsInjectionToken = getInjectionToken<() => Promise<string[]>>({
|
||||
id: "request-system-cas-token",
|
||||
});
|
||||
@@ -1,44 +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 execFileInjectable from "../fs/exec-file.injectable";
|
||||
import loggerInjectable from "../logger.injectable";
|
||||
import { requestSystemCAsInjectionToken } from "./request-system-cas-token";
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet#other_assertions
|
||||
const certSplitPattern = /(?=-----BEGIN\sCERTIFICATE-----)/g;
|
||||
|
||||
const requestSystemCAsInjectable = getInjectable({
|
||||
id: "request-system-cas",
|
||||
instantiate: (di) => {
|
||||
const execFile = di.inject(execFileInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
const execSecurity = async (...args: string[]) => {
|
||||
const output = await execFile("/usr/bin/security", args);
|
||||
|
||||
return output.split(certSplitPattern);
|
||||
};
|
||||
|
||||
return async () => {
|
||||
try {
|
||||
const [trusted, rootCA] = await Promise.all([
|
||||
execSecurity("find-certificate", "-a", "-p"),
|
||||
execSecurity("find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain"),
|
||||
]);
|
||||
|
||||
return [...new Set([...trusted, ...rootCA])];
|
||||
} catch (error) {
|
||||
logger.warn(`[INJECT-CAS]: Error injecting root CAs from MacOSX: ${error}`);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
},
|
||||
causesSideEffects: true,
|
||||
injectionToken: requestSystemCAsInjectionToken,
|
||||
});
|
||||
|
||||
export default requestSystemCAsInjectable;
|
||||
@@ -1,14 +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 { requestSystemCAsInjectionToken } from "./request-system-cas-token";
|
||||
|
||||
const requestSystemCAsInjectable = getInjectable({
|
||||
id: "request-system-cas",
|
||||
instantiate: () => async () => [],
|
||||
injectionToken: requestSystemCAsInjectionToken,
|
||||
});
|
||||
|
||||
export default requestSystemCAsInjectable;
|
||||
@@ -1,14 +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 { requestSystemCAsInjectionToken } from "./request-system-cas-token";
|
||||
|
||||
const requestSystemCAsInjectable = getInjectable({
|
||||
id: "request-system-cas",
|
||||
instantiate: () => async () => [],
|
||||
injectionToken: requestSystemCAsInjectionToken,
|
||||
});
|
||||
|
||||
export default requestSystemCAsInjectable;
|
||||
@@ -1,45 +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 execFileInjectable from "../fs/exec-file.injectable";
|
||||
import { requestSystemCAsInjectionToken } from "./request-system-cas-token";
|
||||
|
||||
const pemEncoding = (hexEncodedCert: String) => {
|
||||
const certData = Buffer.from(hexEncodedCert, "hex").toString("base64");
|
||||
const lines = ["-----BEGIN CERTIFICATE-----"];
|
||||
|
||||
for (let i = 0; i < certData.length; i += 64) {
|
||||
lines.push(certData.substring(i, i + 64));
|
||||
}
|
||||
|
||||
lines.push("-----END CERTIFICATE-----", "");
|
||||
|
||||
return lines.join("\r\n");
|
||||
};
|
||||
|
||||
const requestSystemCAsInjectable = getInjectable({
|
||||
id: "request-system-cas",
|
||||
instantiate: (di) => {
|
||||
const wincaRootsExePath: string = __non_webpack_require__.resolve("win-ca/lib/roots.exe");
|
||||
const execFile = di.inject(execFileInjectable);
|
||||
|
||||
return async () => {
|
||||
/**
|
||||
* This needs to be done manually because for some reason calling the api from "win-ca"
|
||||
* directly fails to load "child_process" correctly on renderer
|
||||
*/
|
||||
const output = await execFile(wincaRootsExePath);
|
||||
|
||||
return output
|
||||
.split("\r\n")
|
||||
.filter(Boolean)
|
||||
.map(pemEncoding);
|
||||
};
|
||||
},
|
||||
causesSideEffects: true,
|
||||
injectionToken: requestSystemCAsInjectionToken,
|
||||
});
|
||||
|
||||
export default requestSystemCAsInjectable;
|
||||
@@ -9,7 +9,6 @@ import type { KubeConfig } from "@kubernetes/client-node";
|
||||
import { HttpError } from "@kubernetes/client-node";
|
||||
import type { Kubectl } from "../../main/kubectl/kubectl";
|
||||
import type { KubeconfigManager } from "../../main/kubeconfig-manager/kubeconfig-manager";
|
||||
import { loadConfigFromFile } from "../kube-helpers";
|
||||
import type { KubeApiResource, KubeResource } from "../rbac";
|
||||
import { apiResourceRecord, apiResources } from "../rbac";
|
||||
import type { VersionDetector } from "../../main/cluster-detectors/version-detector";
|
||||
@@ -25,6 +24,7 @@ import type { ListNamespaces } from "./list-namespaces.injectable";
|
||||
import assert from "assert";
|
||||
import type { Logger } from "../logger";
|
||||
import type { BroadcastMessage } from "../ipc/broadcast-message.injectable";
|
||||
import type { LoadConfigfromFile } from "../kube-helpers/load-config-from-file.injectable";
|
||||
|
||||
export interface ClusterDependencies {
|
||||
readonly directoryForKubeConfigs: string;
|
||||
@@ -37,6 +37,7 @@ export interface ClusterDependencies {
|
||||
createListNamespaces: (config: KubeConfig) => ListNamespaces;
|
||||
createVersionDetector: (cluster: Cluster) => VersionDetector;
|
||||
broadcastMessage: BroadcastMessage;
|
||||
loadConfigfromFile: LoadConfigfromFile;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,7 +501,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
}
|
||||
|
||||
async getKubeconfig(): Promise<KubeConfig> {
|
||||
const { config } = await loadConfigFromFile(this.kubeConfigPath);
|
||||
const { config } = await this.dependencies.loadConfigfromFile(this.kubeConfigPath);
|
||||
|
||||
return config;
|
||||
}
|
||||
@@ -510,7 +511,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
*/
|
||||
async getProxyKubeconfig(): Promise<KubeConfig> {
|
||||
const proxyKCPath = await this.getProxyKubeconfigPath();
|
||||
const { config } = await loadConfigFromFile(proxyKCPath);
|
||||
const { config } = await this.dependencies.loadConfigfromFile(proxyKCPath);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
+3
-3
@@ -4,16 +4,16 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import getAbsolutePathInjectable from "../path/get-absolute-path.injectable";
|
||||
import joinPathsInjectable from "../path/join-paths.injectable";
|
||||
|
||||
const directoryForLensLocalStorageInjectable = getInjectable({
|
||||
id: "directory-for-lens-local-storage",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getAbsolutePath = di.inject(getAbsolutePathInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const directoryForUserData = di.inject(directoryForUserDataInjectable);
|
||||
|
||||
return getAbsolutePath(
|
||||
return joinPaths(
|
||||
directoryForUserData,
|
||||
"lens-local-storage",
|
||||
);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import fetchInjectable from "./fetch.injectable";
|
||||
|
||||
export default getGlobalOverride(fetchInjectable, () => () => {
|
||||
throw new Error("tried to fetch a resource without override in test");
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 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 { RequestInfo, RequestInit, Response } from "node-fetch";
|
||||
import fetch from "node-fetch";
|
||||
|
||||
export type Fetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
|
||||
|
||||
const fetchInjectable = getInjectable({
|
||||
id: "fetch",
|
||||
instantiate: (): Fetch => fetch,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default fetchInjectable;
|
||||
+20
@@ -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 runtimeClassesRouteInjectable from "./runtime-classes-route.injectable";
|
||||
import { navigateToRouteInjectionToken } from "../../../../navigate-to-route-injection-token";
|
||||
|
||||
const navigateToRuntimeClassesInjectable = getInjectable({
|
||||
id: "navigate-to-runtime-classes",
|
||||
|
||||
instantiate: (di) => {
|
||||
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
||||
const route = di.inject(runtimeClassesRouteInjectable);
|
||||
|
||||
return () => navigateToRoute(route);
|
||||
},
|
||||
});
|
||||
|
||||
export default navigateToRuntimeClassesInjectable;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable";
|
||||
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
|
||||
|
||||
const runtimeClassesRouteInjectable = getInjectable({
|
||||
id: "runtime-classes-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const isAllowedResource = di.inject(isAllowedResourceInjectable, "runtimeclasses");
|
||||
|
||||
return {
|
||||
path: "/runtimeclasses",
|
||||
clusterFrame: true,
|
||||
isEnabled: isAllowedResource,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
export default runtimeClassesRouteInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import accessPathInjectable from "./access-path.injectable";
|
||||
|
||||
export default getGlobalOverride(accessPathInjectable, () => async () => {
|
||||
throw new Error("tried to verify path access without override");
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type AccessPath = (path: string, mode?: number) => Promise<boolean>;
|
||||
|
||||
const accessPathInjectable = getInjectable({
|
||||
id: "access-path",
|
||||
instantiate: (di): AccessPath => {
|
||||
const { access } = di.inject(fsInjectable);
|
||||
|
||||
return async (path, mode) => {
|
||||
try {
|
||||
await access(path, mode);
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default accessPathInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import copyInjectable from "./copy.injectable";
|
||||
|
||||
export default getGlobalOverride(copyInjectable, () => async () => {
|
||||
throw new Error("tried to copy filepaths without override");
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { CopyOptions } from "fs-extra";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type Copy = (src: string, dest: string, options?: CopyOptions | undefined) => Promise<void>;
|
||||
|
||||
const copyInjectable = getInjectable({
|
||||
id: "copy",
|
||||
instantiate: (di): Copy => di.inject(fsInjectable).copy,
|
||||
});
|
||||
|
||||
export default copyInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import deleteFileInjectable from "./delete-file.injectable";
|
||||
|
||||
export default getGlobalOverride(deleteFileInjectable, () => async () => {
|
||||
throw new Error("tried to delete file without override");
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type DeleteFile = (filePath: string) => Promise<void>;
|
||||
|
||||
const deleteFileInjectable = getInjectable({
|
||||
id: "delete-file",
|
||||
instantiate: (di): DeleteFile => di.inject(fsInjectable).unlink,
|
||||
});
|
||||
|
||||
export default deleteFileInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import ensureDirInjectable from "./ensure-dir.injectable";
|
||||
|
||||
export default getGlobalOverride(ensureDirInjectable, () => async () => {
|
||||
throw new Error("tried to ensure directory without override");
|
||||
});
|
||||
@@ -5,14 +5,14 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type EnsureDirectory = (dirPath: string) => Promise<void>;
|
||||
|
||||
const ensureDirInjectable = getInjectable({
|
||||
id: "ensure-dir",
|
||||
|
||||
// TODO: Remove usages of ensureDir from business logic.
|
||||
// TODO: Read, Write, Watch etc. operations should do this internally.
|
||||
instantiate: (di) => di.inject(fsInjectable).ensureDir,
|
||||
|
||||
causesSideEffects: true,
|
||||
instantiate: (di): EnsureDirectory => di.inject(fsInjectable).ensureDir,
|
||||
});
|
||||
|
||||
export default ensureDirInjectable;
|
||||
@@ -7,11 +7,7 @@ import type { ExecFileOptions } from "child_process";
|
||||
import { execFile } from "child_process";
|
||||
import { promisify } from "util";
|
||||
|
||||
export interface ExecFile {
|
||||
(filePath: string): Promise<string>;
|
||||
(filePath: string, argsOrOptions: string[] | ExecFileOptions): Promise<string>;
|
||||
(filePath: string, args: string[], options: ExecFileOptions): Promise<string>;
|
||||
}
|
||||
export type ExecFile = (filePath: string, args: string[], options: ExecFileOptions) => Promise<string>;
|
||||
|
||||
const execFileInjectable = getInjectable({
|
||||
id: "exec-file",
|
||||
@@ -19,22 +15,8 @@ const execFileInjectable = getInjectable({
|
||||
instantiate: (): ExecFile => {
|
||||
const asyncExecFile = promisify(execFile);
|
||||
|
||||
return async (filePath: string, argsOrOptions?: string[] | ExecFileOptions, maybeOptions?: ExecFileOptions) => {
|
||||
let args: string[];
|
||||
let options: ExecFileOptions;
|
||||
|
||||
if (Array.isArray(argsOrOptions)) {
|
||||
args = argsOrOptions;
|
||||
options = maybeOptions ?? {};
|
||||
} else {
|
||||
args = [];
|
||||
options = maybeOptions ?? argsOrOptions ?? {};
|
||||
}
|
||||
|
||||
const result = await asyncExecFile(filePath, args, {
|
||||
encoding: "utf-8",
|
||||
...options,
|
||||
});
|
||||
return async (filePath, args, options) => {
|
||||
const result = await asyncExecFile(filePath, args, options);
|
||||
|
||||
return result.stdout;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import extractTarInjectable from "./extract-tar.injectable";
|
||||
|
||||
export default getGlobalOverride(extractTarInjectable, () => async () => {
|
||||
throw new Error("tried to extract a tar file without override");
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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 { ExtractOptions } from "tar";
|
||||
import { extract } from "tar";
|
||||
import getDirnameOfPathInjectable from "../path/get-dirname.injectable";
|
||||
|
||||
export type ExtractTar = (filePath: string, opts?: ExtractOptions) => Promise<void>;
|
||||
|
||||
const extractTarInjectable = getInjectable({
|
||||
id: "extract-tar",
|
||||
instantiate: (di): ExtractTar => {
|
||||
const getDirnameOfPath = di.inject(getDirnameOfPathInjectable);
|
||||
|
||||
return (filePath, opts = {}) => extract({
|
||||
file: filePath,
|
||||
cwd: getDirnameOfPath(filePath),
|
||||
...opts,
|
||||
});
|
||||
},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default extractTarInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import lstatInjectable from "./lstat.injectable";
|
||||
|
||||
export default getGlobalOverride(lstatInjectable, () => async () => {
|
||||
throw new Error("tried to lstat a filepath without override");
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Stats } from "fs";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type LStat = (path: string) => Promise<Stats>;
|
||||
|
||||
const lstatInjectable = getInjectable({
|
||||
id: "lstat",
|
||||
instantiate: (di): LStat => di.inject(fsInjectable).lstat,
|
||||
});
|
||||
|
||||
export default lstatInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import moveInjectable from "./move.injectable";
|
||||
|
||||
export default getGlobalOverride(moveInjectable, () => async () => {
|
||||
throw new Error("tried to move without override");
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MoveOptions } from "fs-extra";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type Move = (src: string, dest: string, options?: MoveOptions) => Promise<void>;
|
||||
|
||||
const moveInjectable = getInjectable({
|
||||
id: "move",
|
||||
instantiate: (di): Move => di.inject(fsInjectable).move,
|
||||
});
|
||||
|
||||
export default moveInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import pathExistsInjectable from "./path-exists.injectable";
|
||||
|
||||
export default getGlobalOverride(pathExistsInjectable, () => async () => {
|
||||
throw new Error("Tried to check if a path exists without override");
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import readDirectoryInjectable from "./read-directory.injectable";
|
||||
|
||||
export default getGlobalOverride(readDirectoryInjectable, () => async () => {
|
||||
throw new Error("tried to read a directory's content without 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 type { Dirent } from "fs";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export interface ReadDirectory {
|
||||
(
|
||||
path: string,
|
||||
options: "buffer" | { encoding: "buffer"; withFileTypes?: false | undefined }
|
||||
): Promise<Buffer[]>;
|
||||
(
|
||||
path: string,
|
||||
options?:
|
||||
| { encoding: BufferEncoding | string | null; withFileTypes?: false | undefined }
|
||||
| BufferEncoding
|
||||
| string
|
||||
| null,
|
||||
): Promise<string[]>;
|
||||
(
|
||||
path: string,
|
||||
options?: { encoding?: BufferEncoding | string | null | undefined; withFileTypes?: false | undefined },
|
||||
): Promise<string[] | Buffer[]>;
|
||||
(
|
||||
path: string,
|
||||
options: { encoding?: BufferEncoding | string | null | undefined; withFileTypes: true },
|
||||
): Promise<Dirent[]>;
|
||||
}
|
||||
|
||||
const readDirectoryInjectable = getInjectable({
|
||||
id: "read-directory",
|
||||
instantiate: (di): ReadDirectory => di.inject(fsInjectable).readdir,
|
||||
});
|
||||
|
||||
export default readDirectoryInjectable;
|
||||
@@ -5,11 +5,16 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type ReadFile = (filePath: string) => Promise<string>;
|
||||
|
||||
const readFileInjectable = getInjectable({
|
||||
id: "read-file",
|
||||
|
||||
instantiate: (di) => (filePath: string) =>
|
||||
di.inject(fsInjectable).readFile(filePath, "utf-8"),
|
||||
instantiate: (di): ReadFile => {
|
||||
const { readFile } = di.inject(fsInjectable);
|
||||
|
||||
return (filePath) => readFile(filePath, "utf-8");
|
||||
},
|
||||
});
|
||||
|
||||
export default readFileInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import removePathInjectable from "./remove-path.injectable";
|
||||
|
||||
export default getGlobalOverride(removePathInjectable, () => async () => {
|
||||
throw new Error("tried to remove a path without override");
|
||||
});
|
||||
@@ -5,9 +5,11 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
const readDirInjectable = getInjectable({
|
||||
id: "read-dir",
|
||||
instantiate: (di) => di.inject(fsInjectable).readdir,
|
||||
export type RemovePath = (path: string) => Promise<void>;
|
||||
|
||||
const removePathInjectable = getInjectable({
|
||||
id: "remove-path",
|
||||
instantiate: (di): RemovePath => di.inject(fsInjectable).remove,
|
||||
});
|
||||
|
||||
export default readDirInjectable;
|
||||
export default removePathInjectable;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||
import writeFileInjectable from "./write-file.injectable";
|
||||
|
||||
export default getGlobalOverride(writeFileInjectable, () => async () => {
|
||||
throw new Error("tried to write file without override");
|
||||
});
|
||||
@@ -3,20 +3,28 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import path from "path";
|
||||
import type { WriteFileOptions } from "fs-extra";
|
||||
import getDirnameOfPathInjectable from "../path/get-dirname.injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type WriteFile = (filePath: string, content: string | Buffer, opts?: WriteFileOptions) => Promise<void>;
|
||||
|
||||
const writeFileInjectable = getInjectable({
|
||||
id: "write-file",
|
||||
|
||||
instantiate: (di) => {
|
||||
instantiate: (di): WriteFile => {
|
||||
const { writeFile, ensureDir } = di.inject(fsInjectable);
|
||||
const getDirnameOfPath = di.inject(getDirnameOfPathInjectable);
|
||||
|
||||
return async (filePath: string, content: string | Buffer) => {
|
||||
await ensureDir(path.dirname(filePath), { mode: 0o755 });
|
||||
return async (filePath, content, opts) => {
|
||||
await ensureDir(getDirnameOfPath(filePath), {
|
||||
mode: 0o755,
|
||||
...(opts ?? {}),
|
||||
});
|
||||
|
||||
await writeFile(filePath, content, {
|
||||
encoding: "utf-8",
|
||||
...(opts ?? {}),
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
@@ -3,37 +3,27 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { EnsureOptions, WriteOptions } from "fs-extra";
|
||||
import path from "path";
|
||||
import type { JsonValue } from "type-fest";
|
||||
import getDirnameOfPathInjectable from "../path/get-dirname.injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type WriteJson = (filePath: string, contents: JsonValue) => Promise<void>;
|
||||
|
||||
interface Dependencies {
|
||||
writeJson: (file: string, object: any, options?: WriteOptions | BufferEncoding | string) => Promise<void>;
|
||||
ensureDir: (dir: string, options?: EnsureOptions | number) => Promise<void>;
|
||||
}
|
||||
|
||||
const writeJsonFile = ({ writeJson, ensureDir }: Dependencies): WriteJson => async (filePath, content) => {
|
||||
await ensureDir(path.dirname(filePath), { mode: 0o755 });
|
||||
|
||||
await writeJson(filePath, content, {
|
||||
encoding: "utf-8",
|
||||
spaces: 2,
|
||||
});
|
||||
};
|
||||
|
||||
const writeJsonFileInjectable = getInjectable({
|
||||
id: "write-json-file",
|
||||
|
||||
instantiate: (di) => {
|
||||
instantiate: (di): WriteJson => {
|
||||
const { writeJson, ensureDir } = di.inject(fsInjectable);
|
||||
const getDirnameOfPath = di.inject(getDirnameOfPathInjectable);
|
||||
|
||||
return writeJsonFile({
|
||||
writeJson,
|
||||
ensureDir,
|
||||
});
|
||||
return async (filePath, content) => {
|
||||
await ensureDir(getDirnameOfPath(filePath), { mode: 0o755 });
|
||||
|
||||
await writeJson(filePath, content, {
|
||||
encoding: "utf-8",
|
||||
spaces: 2,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@ export const clusterSetFrameIdHandler = "cluster:set-frame-id";
|
||||
export const clusterVisibilityHandler = "cluster:visibility";
|
||||
export const clusterRefreshHandler = "cluster:refresh";
|
||||
export const clusterDisconnectHandler = "cluster:disconnect";
|
||||
export const clusterDeleteHandler = "cluster:delete";
|
||||
export const clusterSetDeletingHandler = "cluster:deleting:set";
|
||||
export const clusterClearDeletingHandler = "cluster:deleting:clear";
|
||||
export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all";
|
||||
export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all";
|
||||
export const clusterStates = "cluster:states";
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -3,38 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { JsonApi } from "./json-api";
|
||||
import { apiPrefix, isDebugging, isDevelopment } from "../vars";
|
||||
import { appEventBus } from "../app-event-bus/event-bus";
|
||||
import type { JsonApi } from "./json-api";
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
|
||||
export let apiBase: JsonApi;
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
appEventBus.addListener((event) => {
|
||||
if (event.name !== "lens-proxy" && event.action !== "listen") return;
|
||||
|
||||
const params = event.params as { port?: number };
|
||||
|
||||
if (!params.port) return;
|
||||
|
||||
apiBase = new JsonApi({
|
||||
serverAddress: `http://127.0.0.1:${params.port}`,
|
||||
apiBase: apiPrefix,
|
||||
debug: isDevelopment || isDebugging,
|
||||
}, {
|
||||
headers: {
|
||||
"Host": `localhost:${params.port}`,
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
apiBase = new JsonApi({
|
||||
serverAddress: `http://127.0.0.1:${window.location.port}`,
|
||||
apiBase: apiPrefix,
|
||||
debug: isDevelopment || isDebugging,
|
||||
}, {
|
||||
headers: {
|
||||
"Host": window.location.host,
|
||||
},
|
||||
});
|
||||
}
|
||||
export const apiBaseInjectionToken = getInjectionToken<JsonApi>({
|
||||
id: "api-base-token",
|
||||
});
|
||||
@@ -4,11 +4,8 @@
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import { asLegacyGlobalForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
|
||||
import type { KubeJsonApi } from "./kube-json-api";
|
||||
|
||||
export const apiKubeInjectionToken = getInjectionToken<KubeJsonApi>({
|
||||
id: "api-kube-injection-token",
|
||||
});
|
||||
|
||||
export const apiKube = asLegacyGlobalForExtensionApi(apiKubeInjectionToken);
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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 { RequestInit } from "node-fetch";
|
||||
import fetchInjectable from "../fetch/fetch.injectable";
|
||||
import loggerInjectable from "../logger.injectable";
|
||||
import type { JsonApiConfig, JsonApiData, JsonApiDependencies, JsonApiParams } from "./json-api";
|
||||
import { JsonApi } from "./json-api";
|
||||
|
||||
export type CreateJsonApi = <Data = JsonApiData, Params extends JsonApiParams<Data> = JsonApiParams<Data>>(config: JsonApiConfig, reqInit?: RequestInit) => JsonApi<Data, Params>;
|
||||
|
||||
const createJsonApiInjectable = getInjectable({
|
||||
id: "create-json-api",
|
||||
instantiate: (di): CreateJsonApi => {
|
||||
const deps: JsonApiDependencies = {
|
||||
fetch: di.inject(fetchInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
};
|
||||
|
||||
return (config, reqInit) => new JsonApi(deps, config, reqInit);
|
||||
},
|
||||
});
|
||||
|
||||
export default createJsonApiInjectable;
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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 { apiKubePrefix } from "../vars";
|
||||
import isDevelopmentInjectable from "../vars/is-development.injectable";
|
||||
import { apiBaseInjectionToken } from "./api-base";
|
||||
import createKubeJsonApiInjectable from "./create-kube-json-api.injectable";
|
||||
import type { KubeApiOptions } from "./kube-api";
|
||||
import { KubeApi } from "./kube-api";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "./kube-object";
|
||||
|
||||
export interface CreateKubeApiForLocalClusterConfig {
|
||||
metadata: {
|
||||
uid: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateKubeApiForCluster {
|
||||
<Object extends KubeObject, Api extends KubeApi<Object>, Data extends KubeJsonApiDataFor<Object>>(
|
||||
cluster: CreateKubeApiForLocalClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<Object, Data>,
|
||||
apiClass: new (apiOpts: KubeApiOptions<Object>) => Api
|
||||
): Api;
|
||||
<Object extends KubeObject, Data extends KubeJsonApiDataFor<Object>>(
|
||||
cluster: CreateKubeApiForLocalClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<Object, Data>,
|
||||
apiClass?: new (apiOpts: KubeApiOptions<Object>) => KubeApi<Object>
|
||||
): KubeApi<Object>;
|
||||
}
|
||||
|
||||
const createKubeApiForClusterInjectable = getInjectable({
|
||||
id: "create-kube-api-for-cluster",
|
||||
instantiate: (di): CreateKubeApiForCluster => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
const isDevelopment = di.inject(isDevelopmentInjectable);
|
||||
const createKubeJsonApi = di.inject(createKubeJsonApiInjectable);
|
||||
|
||||
return (
|
||||
cluster: CreateKubeApiForLocalClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<KubeObject, KubeJsonApiDataFor<KubeObject>>,
|
||||
apiClass = KubeApi,
|
||||
) => (
|
||||
new apiClass({
|
||||
objectConstructor: kubeClass,
|
||||
request: createKubeJsonApi(
|
||||
{
|
||||
serverAddress: apiBase.config.serverAddress,
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDevelopment,
|
||||
}, {
|
||||
headers: {
|
||||
"Host": `${cluster.metadata.uid}.localhost:${new URL(apiBase.config.serverAddress).port}`,
|
||||
},
|
||||
},
|
||||
),
|
||||
})
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default createKubeApiForClusterInjectable;
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* 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 { AgentOptions } from "https";
|
||||
import { Agent } from "https";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
import isDevelopmentInjectable from "../vars/is-development.injectable";
|
||||
import createKubeJsonApiInjectable from "./create-kube-json-api.injectable";
|
||||
import type { KubeApiOptions } from "./kube-api";
|
||||
import { KubeApi } from "./kube-api";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "./kube-object";
|
||||
|
||||
export interface CreateKubeApiForRemoteClusterConfig {
|
||||
cluster: {
|
||||
server: string;
|
||||
caData?: string;
|
||||
skipTLSVerify?: boolean;
|
||||
};
|
||||
user: {
|
||||
token?: string | (() => Promise<string>);
|
||||
clientCertificateData?: string;
|
||||
clientKeyData?: string;
|
||||
};
|
||||
/**
|
||||
* Custom instance of https.agent to use for the requests
|
||||
*
|
||||
* @remarks the custom agent replaced default agent, options skipTLSVerify,
|
||||
* clientCertificateData, clientKeyData and caData are ignored.
|
||||
*/
|
||||
agent?: Agent;
|
||||
}
|
||||
|
||||
export interface CreateKubeApiForRemoteCluster {
|
||||
<Object extends KubeObject, Api extends KubeApi<Object>, Data extends KubeJsonApiDataFor<Object>>(
|
||||
config: CreateKubeApiForRemoteClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<Object, Data>,
|
||||
apiClass: new (apiOpts: KubeApiOptions<Object>) => Api,
|
||||
): Api;
|
||||
<Object extends KubeObject, Data extends KubeJsonApiDataFor<Object>>(
|
||||
config: CreateKubeApiForRemoteClusterConfig,
|
||||
kubeClass: KubeObjectConstructor<Object, Data>,
|
||||
apiClass?: new (apiOpts: KubeApiOptions<Object>) => KubeApi<Object>,
|
||||
): KubeApi<Object>;
|
||||
}
|
||||
|
||||
const createKubeApiForRemoteClusterInjectable = getInjectable({
|
||||
id: "create-kube-api-for-remote-cluster",
|
||||
instantiate: (di): CreateKubeApiForRemoteCluster => {
|
||||
const isDevelopment = di.inject(isDevelopmentInjectable);
|
||||
const createKubeJsonApi = di.inject(createKubeJsonApiInjectable);
|
||||
|
||||
return (config: CreateKubeApiForRemoteClusterConfig, kubeClass: KubeObjectConstructor<KubeObject, KubeJsonApiDataFor<KubeObject>>, apiClass = KubeApi) => {
|
||||
const reqInit: RequestInit = {};
|
||||
const agentOptions: AgentOptions = {};
|
||||
|
||||
if (config.cluster.skipTLSVerify === true) {
|
||||
agentOptions.rejectUnauthorized = false;
|
||||
}
|
||||
|
||||
if (config.user.clientCertificateData) {
|
||||
agentOptions.cert = config.user.clientCertificateData;
|
||||
}
|
||||
|
||||
if (config.user.clientKeyData) {
|
||||
agentOptions.key = config.user.clientKeyData;
|
||||
}
|
||||
|
||||
if (config.cluster.caData) {
|
||||
agentOptions.ca = config.cluster.caData;
|
||||
}
|
||||
|
||||
if (Object.keys(agentOptions).length > 0) {
|
||||
reqInit.agent = new Agent(agentOptions);
|
||||
}
|
||||
|
||||
if (config.agent) {
|
||||
reqInit.agent = config.agent;
|
||||
}
|
||||
|
||||
const token = config.user.token;
|
||||
const request = createKubeJsonApi({
|
||||
serverAddress: config.cluster.server,
|
||||
apiBase: "",
|
||||
debug: isDevelopment,
|
||||
...(token ? {
|
||||
getRequestOptions: async () => ({
|
||||
headers: {
|
||||
"Authorization": `Bearer ${typeof token === "function" ? await token() : token}`,
|
||||
},
|
||||
}),
|
||||
} : {}),
|
||||
}, reqInit);
|
||||
|
||||
return new apiClass({
|
||||
objectConstructor: kubeClass,
|
||||
request,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default createKubeApiForRemoteClusterInjectable;
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { apiKubePrefix } from "../vars";
|
||||
import isDebuggingInjectable from "../vars/is-debugging.injectable";
|
||||
import { apiBaseInjectionToken } from "./api-base";
|
||||
import createKubeJsonApiInjectable from "./create-kube-json-api.injectable";
|
||||
import type { KubeJsonApi } from "./kube-json-api";
|
||||
|
||||
export type CreateKubeJsonApiForCluster = (clusterId: string) => KubeJsonApi;
|
||||
|
||||
const createKubeJsonApiForClusterInjectable = getInjectable({
|
||||
id: "create-kube-json-api-for-cluster",
|
||||
instantiate: (di): CreateKubeJsonApiForCluster => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
const createKubeJsonApi = di.inject(createKubeJsonApiInjectable);
|
||||
const isDebugging = di.inject(isDebuggingInjectable);
|
||||
|
||||
return (clusterId) => createKubeJsonApi(
|
||||
{
|
||||
serverAddress: apiBase.config.serverAddress,
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDebugging,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Host": `${clusterId}.localhost:${new URL(apiBase.config.serverAddress).port}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default createKubeJsonApiForClusterInjectable;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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 { RequestInit } from "node-fetch";
|
||||
import fetchInjectable from "../fetch/fetch.injectable";
|
||||
import loggerInjectable from "../logger.injectable";
|
||||
import type { JsonApiConfig, JsonApiDependencies } from "./json-api";
|
||||
import { KubeJsonApi } from "./kube-json-api";
|
||||
|
||||
export type CreateKubeJsonApi = (config: JsonApiConfig, reqInit?: RequestInit) => KubeJsonApi;
|
||||
|
||||
const createKubeJsonApiInjectable = getInjectable({
|
||||
id: "create-kube-json-api",
|
||||
instantiate: (di): CreateKubeJsonApi => {
|
||||
const dependencies: JsonApiDependencies = {
|
||||
fetch: di.inject(fetchInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
};
|
||||
|
||||
return (config, reqInit) => new KubeJsonApi(dependencies, config, reqInit);
|
||||
},
|
||||
});
|
||||
|
||||
export default createKubeJsonApiInjectable;
|
||||
@@ -3,8 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { MetricData, IMetricsReqParams } from "./metrics.api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
@@ -28,30 +26,6 @@ export class ClusterApi extends KubeApi<Cluster> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsByNodeNames(nodeNames: string[], params?: IMetricsReqParams): Promise<ClusterMetricData> {
|
||||
const nodes = nodeNames.join("|");
|
||||
const opts = { category: "cluster", nodes };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
memoryUsage: opts,
|
||||
workloadMemoryUsage: opts,
|
||||
memoryRequests: opts,
|
||||
memoryLimits: opts,
|
||||
memoryCapacity: opts,
|
||||
memoryAllocatableCapacity: opts,
|
||||
cpuUsage: opts,
|
||||
cpuRequests: opts,
|
||||
cpuLimits: opts,
|
||||
cpuCapacity: opts,
|
||||
cpuAllocatableCapacity: opts,
|
||||
podUsage: opts,
|
||||
podCapacity: opts,
|
||||
podAllocatableCapacity: opts,
|
||||
fsSize: opts,
|
||||
fsUsage: opts,
|
||||
}, params);
|
||||
}
|
||||
|
||||
export enum ClusterStatus {
|
||||
ACTIVE = "Active",
|
||||
CREATING = "Creating",
|
||||
@@ -59,21 +33,6 @@ export enum ClusterStatus {
|
||||
ERROR = "Error",
|
||||
}
|
||||
|
||||
export interface ClusterMetricData extends Partial<Record<string, MetricData>> {
|
||||
memoryUsage: MetricData;
|
||||
memoryRequests: MetricData;
|
||||
memoryLimits: MetricData;
|
||||
memoryCapacity: MetricData;
|
||||
cpuUsage: MetricData;
|
||||
cpuRequests: MetricData;
|
||||
cpuLimits: MetricData;
|
||||
cpuCapacity: MetricData;
|
||||
podUsage: MetricData;
|
||||
podCapacity: MetricData;
|
||||
fsSize: MetricData;
|
||||
fsUsage: MetricData;
|
||||
}
|
||||
|
||||
export interface Cluster {
|
||||
spec: {
|
||||
clusterNetwork?: {
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { PodMetricData } from "./pod.api";
|
||||
import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodTemplateSpec } from "./types/pod-template-spec";
|
||||
@@ -90,20 +88,3 @@ export class DaemonSetApi extends KubeApi<DaemonSet> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForDaemonSets(daemonsets: DaemonSet[], namespace: string, selector = ""): Promise<PodMetricData> {
|
||||
const podSelector = daemonsets.map(daemonset => `${daemonset.getName()}-[[:alnum:]]{5}`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
}
|
||||
@@ -7,8 +7,7 @@ import moment from "moment";
|
||||
|
||||
import type { DerivedKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { PodMetricData, PodSpec } from "./pod.api";
|
||||
import type { PodSpec } from "./pod.api";
|
||||
import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { hasTypedProperty, isNumber, isObject } from "../../utils";
|
||||
@@ -70,23 +69,6 @@ export class DeploymentApi extends KubeApi<Deployment> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForDeployments(deployments: Deployment[], namespace: string, selector = ""): Promise<PodMetricData> {
|
||||
const podSelector = deployments.map(deployment => `${deployment.getName()}-[[:alnum:]]{9,}-[[:alnum:]]{5}`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
}
|
||||
|
||||
export interface DeploymentSpec {
|
||||
replicas: number;
|
||||
selector: LabelSelector;
|
||||
|
||||
@@ -3,72 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { compile } from "path-to-regexp";
|
||||
import { apiBase } from "../index";
|
||||
import { stringify } from "querystring";
|
||||
import type { RequestInit } from "node-fetch";
|
||||
import { autoBind, bifurcateArray, isDefined } from "../../utils";
|
||||
import { autoBind, bifurcateArray } from "../../utils";
|
||||
import Joi from "joi";
|
||||
|
||||
export type RepoHelmChartList = Record<string, RawHelmChart[]>;
|
||||
|
||||
export interface IHelmChartDetails {
|
||||
readme: string;
|
||||
versions: HelmChart[];
|
||||
}
|
||||
|
||||
const endpoint = compile(`/v2/charts/:repo?/:name?`) as (params?: {
|
||||
repo?: string;
|
||||
name?: string;
|
||||
}) => string;
|
||||
|
||||
/**
|
||||
* Get a list of all helm charts from all saved helm repos
|
||||
*/
|
||||
export async function listCharts(): Promise<HelmChart[]> {
|
||||
const data = await apiBase.get<Record<string, RepoHelmChartList>>(endpoint());
|
||||
|
||||
return Object
|
||||
.values(data)
|
||||
.reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), new Array<RawHelmChart[]>())
|
||||
.map(([chart]) => HelmChart.create(chart, { onError: "log" }))
|
||||
.filter(isDefined);
|
||||
}
|
||||
|
||||
export interface GetChartDetailsOptions {
|
||||
version?: string;
|
||||
reqInit?: RequestInit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the readme and all versions of a chart
|
||||
* @param repo The repo to get from
|
||||
* @param name The name of the chart to request the data of
|
||||
* @param options.version The version of the chart's readme to get, default latest
|
||||
* @param options.reqInit A way for passing in an abort controller or other browser request options
|
||||
*/
|
||||
export async function getChartDetails(repo: string, name: string, { version, reqInit }: GetChartDetailsOptions = {}): Promise<IHelmChartDetails> {
|
||||
const path = endpoint({ repo, name });
|
||||
|
||||
const { readme, ...data } = await apiBase.get<IHelmChartDetails>(`${path}?${stringify({ version })}`, undefined, reqInit);
|
||||
const versions = data.versions.map(version => HelmChart.create(version, { onError: "log" })).filter(isDefined);
|
||||
|
||||
return {
|
||||
readme,
|
||||
versions,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chart values related to a specific repos' version of a chart
|
||||
* @param repo The repo to get from
|
||||
* @param name The name of the chart to request the data of
|
||||
* @param version The version to get the values from
|
||||
*/
|
||||
export async function getChartValues(repo: string, name: string, version: string): Promise<string> {
|
||||
return apiBase.get<string>(`/v2/charts/${repo}/${name}/values?${stringify({ version })}`);
|
||||
}
|
||||
|
||||
export interface RawHelmChart {
|
||||
apiVersion: string;
|
||||
name: string;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 { apiBaseInjectionToken } from "../../api-base";
|
||||
import type { RawHelmChart } from "../helm-charts.api";
|
||||
import { HelmChart } from "../helm-charts.api";
|
||||
import { isDefined } from "../../../utils";
|
||||
|
||||
export type RequestHelmCharts = () => Promise<HelmChart[]>;
|
||||
export type RepoHelmChartList = Record<string, RawHelmChart[]>;
|
||||
|
||||
/**
|
||||
* Get a list of all helm charts from all saved helm repos
|
||||
*/
|
||||
const requestHelmChartsInjectable = getInjectable({
|
||||
id: "request-helm-charts",
|
||||
instantiate: (di) => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return async () => {
|
||||
const data = await apiBase.get<Record<string, RepoHelmChartList>>("/v2/charts");
|
||||
|
||||
return Object
|
||||
.values(data)
|
||||
.reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), new Array<RawHelmChart[]>())
|
||||
.map(([chart]) => HelmChart.create(chart, { onError: "log" }))
|
||||
.filter(isDefined);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmChartsInjectable;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
|
||||
const requestReadmeEndpoint = urlBuilderFor("/v2/charts/:repo/:name/readme");
|
||||
|
||||
export type RequestHelmChartReadme = (repo: string, name: string, version?: string) => Promise<string>;
|
||||
|
||||
const requestHelmChartReadmeInjectable = getInjectable({
|
||||
id: "request-helm-chart-readme",
|
||||
instantiate: (di): RequestHelmChartReadme => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (repo, name, version) => (
|
||||
apiBase.get(requestReadmeEndpoint.compile({ name, repo }, { version }))
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmChartReadmeInjectable;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
|
||||
const requestValuesEndpoint = urlBuilderFor("/v2/charts/:repo/:name/values");
|
||||
|
||||
export type RequestHelmChartValues = (repo: string, name: string, version: string) => Promise<string>;
|
||||
|
||||
const requestHelmChartValuesInjectable = getInjectable({
|
||||
id: "request-helm-chart-values",
|
||||
instantiate: (di): RequestHelmChartValues => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (repo, name, version) => (
|
||||
apiBase.get(requestValuesEndpoint.compile({ repo, name }, { version }))
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmChartValuesInjectable;
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
import { HelmChart } from "../helm-charts.api";
|
||||
import type { RawHelmChart } from "../helm-charts.api";
|
||||
import { isDefined } from "../../../utils";
|
||||
|
||||
const requestVersionsEndpoint = urlBuilderFor("/v2/charts/:repo/:name/versions");
|
||||
|
||||
export type RequestHelmChartVersions = (repo: string, chartName: string) => Promise<HelmChart[]>;
|
||||
|
||||
const requestHelmChartVersionsInjectable = getInjectable({
|
||||
id: "request-helm-chart-versions",
|
||||
instantiate: (di): RequestHelmChartVersions => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return async (repo, name) => {
|
||||
const rawVersions = await apiBase.get(requestVersionsEndpoint.compile({ name, repo })) as RawHelmChart[];
|
||||
|
||||
return rawVersions
|
||||
.map(version => HelmChart.create(version, { onError: "log" }))
|
||||
.filter(isDefined);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmChartVersionsInjectable;
|
||||
@@ -3,65 +3,14 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { apiBase } from "../index";
|
||||
import type { ItemObject } from "../../item.store";
|
||||
import type { JsonApiData } from "../json-api";
|
||||
import { buildURLPositional } from "../../utils/buildUrl";
|
||||
import type { HelmReleaseDetails } from "../../../renderer/components/+helm-releases/release-details/release-details-model/call-for-helm-release/call-for-helm-release-details/call-for-helm-release-details.injectable";
|
||||
import type { HelmReleaseDetails } from "./helm-releases.api/request-details.injectable";
|
||||
|
||||
export interface HelmReleaseUpdateDetails {
|
||||
log: string;
|
||||
release: HelmReleaseDetails;
|
||||
}
|
||||
|
||||
export interface HelmReleaseRevision {
|
||||
revision: number;
|
||||
updated: string;
|
||||
status: string;
|
||||
chart: string;
|
||||
app_version: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
type EndpointParams = {}
|
||||
| { namespace: string }
|
||||
| { namespace: string; name: string }
|
||||
| { namespace: string; name: string; route: string };
|
||||
|
||||
interface EndpointQuery {
|
||||
all?: boolean;
|
||||
}
|
||||
|
||||
export const endpoint = buildURLPositional<EndpointParams, EndpointQuery>("/v2/releases/:namespace?/:name?/:route?");
|
||||
|
||||
export async function deleteRelease(name: string, namespace: string): Promise<JsonApiData> {
|
||||
const path = endpoint({ name, namespace });
|
||||
|
||||
return apiBase.del(path);
|
||||
}
|
||||
|
||||
export async function getReleaseValues(name: string, namespace: string, all?: boolean): Promise<string> {
|
||||
const route = "values";
|
||||
const path = endpoint({ name, namespace, route }, { all });
|
||||
|
||||
return apiBase.get<string>(path);
|
||||
}
|
||||
|
||||
export async function getReleaseHistory(name: string, namespace: string): Promise<HelmReleaseRevision[]> {
|
||||
const route = "history";
|
||||
const path = endpoint({ name, namespace, route });
|
||||
|
||||
return apiBase.get(path);
|
||||
}
|
||||
|
||||
export async function rollbackRelease(name: string, namespace: string, revision: number): Promise<JsonApiData> {
|
||||
const route = "rollback";
|
||||
const path = endpoint({ name, namespace, route });
|
||||
const data = { revision };
|
||||
|
||||
return apiBase.put(path, { data });
|
||||
}
|
||||
|
||||
export interface HelmReleaseDto {
|
||||
appVersion: string;
|
||||
name: string;
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../../test-utils/get-global-override";
|
||||
import requestHelmReleaseConfigurationInjectable from "./request-configuration.injectable";
|
||||
|
||||
export default getGlobalOverride(requestHelmReleaseConfigurationInjectable, () => () => {
|
||||
throw new Error("Tried to call requestHelmReleaseConfiguration with no override");
|
||||
});
|
||||
@@ -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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
|
||||
export type RequestHelmReleaseConfiguration = (
|
||||
name: string,
|
||||
namespace: string,
|
||||
all: boolean
|
||||
) => Promise<string>;
|
||||
|
||||
const requestConfigurationEnpoint = urlBuilderFor("/v2/releases/:namespace/:name/values");
|
||||
|
||||
const requestHelmReleaseConfigurationInjectable = getInjectable({
|
||||
id: "request-helm-release-configuration",
|
||||
|
||||
instantiate: (di): RequestHelmReleaseConfiguration => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (name, namespace, all: boolean) => (
|
||||
apiBase.get(requestConfigurationEnpoint.compile({ name, namespace }, { all }))
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmReleaseConfigurationInjectable;
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import yaml from "js-yaml";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { HelmReleaseUpdateDetails } from "../helm-releases.api";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
import { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
|
||||
interface HelmReleaseCreatePayload {
|
||||
name?: string;
|
||||
repo: string;
|
||||
chart: string;
|
||||
namespace: string;
|
||||
version: string;
|
||||
values: string;
|
||||
}
|
||||
|
||||
export type RequestCreateHelmRelease = (payload: HelmReleaseCreatePayload) => Promise<HelmReleaseUpdateDetails>;
|
||||
|
||||
const requestCreateEndpoint = urlBuilderFor("/v2/releases");
|
||||
|
||||
const requestCreateHelmReleaseInjectable = getInjectable({
|
||||
id: "request-create-helm-release",
|
||||
|
||||
instantiate: (di): RequestCreateHelmRelease => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return ({ repo, chart, values, ...data }) => {
|
||||
return apiBase.post(requestCreateEndpoint.compile({}), {
|
||||
data: {
|
||||
chart: `${repo}/${chart}`,
|
||||
values: yaml.load(values),
|
||||
...data,
|
||||
},
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestCreateHelmReleaseInjectable;
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
|
||||
export type RequestDeleteHelmRelease = (name: string, namespace: string) => Promise<void>;
|
||||
|
||||
const requestDeleteEndpoint = urlBuilderFor("/v2/releases/:namespace/:name");
|
||||
|
||||
const requestDeleteHelmReleaseInjectable = getInjectable({
|
||||
id: "request-delete-helm-release",
|
||||
instantiate: (di): RequestDeleteHelmRelease => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (name, namespace) => apiBase.del(requestDeleteEndpoint.compile({ name, namespace }));
|
||||
},
|
||||
});
|
||||
|
||||
export default requestDeleteHelmReleaseInjectable;
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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 { KubeJsonApiData } from "../../kube-json-api";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
import { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
|
||||
export interface HelmReleaseDetails {
|
||||
resources: KubeJsonApiData[];
|
||||
name: string;
|
||||
namespace: string;
|
||||
version: string;
|
||||
config: string; // release values
|
||||
manifest: string;
|
||||
info: {
|
||||
deleted: string;
|
||||
description: string;
|
||||
first_deployed: string;
|
||||
last_deployed: string;
|
||||
notes: string;
|
||||
status: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type CallForHelmReleaseDetails = (name: string, namespace: string) => Promise<HelmReleaseDetails>;
|
||||
|
||||
const requestDetailsEnpoint = urlBuilderFor("/v2/releases/:namespace/:name");
|
||||
|
||||
const requestHelmReleaseDetailsInjectable = getInjectable({
|
||||
id: "call-for-helm-release-details",
|
||||
|
||||
instantiate: (di): CallForHelmReleaseDetails => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (name, namespace) => apiBase.get(requestDetailsEnpoint.compile({ name, namespace }));
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmReleaseDetailsInjectable;
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
|
||||
export interface HelmReleaseRevision {
|
||||
revision: number;
|
||||
updated: string;
|
||||
status: string;
|
||||
chart: string;
|
||||
app_version: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export type RequestHelmReleaseHistory = (name: string, namespace: string) => Promise<HelmReleaseRevision[]>;
|
||||
|
||||
const requestHistoryEnpoint = urlBuilderFor("/v2/releases/:namespace/:name/history");
|
||||
|
||||
const requestHelmReleaseHistoryInjectable = getInjectable({
|
||||
id: "request-helm-release-history",
|
||||
instantiate: (di): RequestHelmReleaseHistory => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (name, namespace) => apiBase.get(requestHistoryEnpoint.compile({ name, namespace }));
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmReleaseHistoryInjectable;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
import type { HelmReleaseDto } from "../helm-releases.api";
|
||||
|
||||
export type RequestHelmReleases = (namespace?: string) => Promise<HelmReleaseDto[]>;
|
||||
|
||||
const requestHelmReleasesEndpoint = urlBuilderFor("/v2/releases/:namespace?");
|
||||
|
||||
const requestHelmReleasesInjectable = getInjectable({
|
||||
id: "request-helm-releases",
|
||||
|
||||
instantiate: (di): RequestHelmReleases => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (namespace) => apiBase.get(requestHelmReleasesEndpoint.compile({ namespace }));
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmReleasesInjectable;
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
|
||||
export type RequestHelmReleaseRollback = (name: string, namespace: string, revision: number) => Promise<void>;
|
||||
|
||||
const requestRollbackEndpoint = urlBuilderFor("/v2/releases/:namespace/:name");
|
||||
|
||||
const requestHelmReleaseRollbackInjectable = getInjectable({
|
||||
id: "request-helm-release-rollback",
|
||||
instantiate: (di): RequestHelmReleaseRollback => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return async (name, namespace, revision) => {
|
||||
await apiBase.put(
|
||||
requestRollbackEndpoint.compile({ name, namespace }),
|
||||
{ data: { revision }},
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmReleaseRollbackInjectable;
|
||||
@@ -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 yaml from "js-yaml";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
import { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
|
||||
interface HelmReleaseUpdatePayload {
|
||||
repo: string;
|
||||
chart: string;
|
||||
version: string;
|
||||
values: string;
|
||||
}
|
||||
|
||||
export type RequestHelmReleaseUpdate = (
|
||||
name: string,
|
||||
namespace: string,
|
||||
payload: HelmReleaseUpdatePayload
|
||||
) => Promise<{ updateWasSuccessful: true } | { updateWasSuccessful: false; error: unknown }>;
|
||||
|
||||
const requestUpdateEndpoint = urlBuilderFor("/v2/releases/:namespace/:name");
|
||||
|
||||
const requestHelmReleaseUpdateInjectable = getInjectable({
|
||||
id: "request-helm-release-update",
|
||||
|
||||
instantiate: (di): RequestHelmReleaseUpdate => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return async (name, namespace, { repo, chart, values, ...data }) => {
|
||||
try {
|
||||
await apiBase.put(requestUpdateEndpoint.compile({ name, namespace }), {
|
||||
data: {
|
||||
chart: `${repo}/${chart}`,
|
||||
values: yaml.load(values),
|
||||
...data,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return { updateWasSuccessful: false, error: e };
|
||||
}
|
||||
|
||||
return { updateWasSuccessful: true };
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmReleaseUpdateInjectable;
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 { urlBuilderFor } from "../../../utils/buildUrl";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
|
||||
export type RequestHelmReleaseValues = (name: string, namespace: string, all?: boolean) => Promise<string>;
|
||||
|
||||
const requestValuesEndpoint = urlBuilderFor("/v2/release/:namespace/:name/values");
|
||||
|
||||
const requestHelmReleaseValuesInjectable = getInjectable({
|
||||
id: "request-helm-release-values",
|
||||
instantiate: (di): RequestHelmReleaseValues => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (name, namespace, all) => apiBase.get(requestValuesEndpoint.compile({ name, namespace }, { all }));
|
||||
},
|
||||
});
|
||||
|
||||
export default requestHelmReleaseValuesInjectable;
|
||||
@@ -34,6 +34,7 @@ export * from "./replica-set.api";
|
||||
export * from "./resource-quota.api";
|
||||
export * from "./role.api";
|
||||
export * from "./role-binding.api";
|
||||
export * from "./runtime-class.api";
|
||||
export * from "./secret.api";
|
||||
export * from "./self-subject-rules-reviews.api";
|
||||
export * from "./service.api";
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
import type { NamespaceScopedMetadata, TypedLocalObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { hasTypedProperty, isString, iter } from "../../utils";
|
||||
import type { MetricData } from "./metrics.api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { RequireExactlyOne } from "type-fest";
|
||||
@@ -24,26 +22,6 @@ export class IngressApi extends KubeApi<Ingress> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForIngress(ingress: string, namespace: string): Promise<IngressMetricData> {
|
||||
const opts = { category: "ingress", ingress, namespace };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
bytesSentSuccess: opts,
|
||||
bytesSentFailure: opts,
|
||||
requestDurationSeconds: opts,
|
||||
responseDurationSeconds: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
}
|
||||
|
||||
export interface IngressMetricData extends Partial<Record<string, MetricData>> {
|
||||
bytesSentSuccess: MetricData;
|
||||
bytesSentFailure: MetricData;
|
||||
requestDurationSeconds: MetricData;
|
||||
responseDurationSeconds: MetricData;
|
||||
}
|
||||
|
||||
export interface ILoadBalancerIngress {
|
||||
hostname?: string;
|
||||
ip?: string;
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { PodMetricData, PodSpec } from "./pod.api";
|
||||
import type { PodSpec } from "./pod.api";
|
||||
import type { Container } from "./types/container";
|
||||
import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
@@ -103,20 +102,3 @@ export class JobApi extends KubeApi<Job> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForJobs(jobs: Job[], namespace: string, selector = ""): Promise<PodMetricData> {
|
||||
const podSelector = jobs.map(job => `${job.getName()}-[[:alnum:]]{5}`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
// Metrics api
|
||||
|
||||
import moment from "moment";
|
||||
import { apiBase } from "../index";
|
||||
import { isDefined, object } from "../../utils";
|
||||
|
||||
export interface MetricData {
|
||||
status: string;
|
||||
@@ -29,63 +29,6 @@ export interface MetricResult {
|
||||
values: [number, string][];
|
||||
}
|
||||
|
||||
export interface MetricProviderInfo {
|
||||
name: string;
|
||||
id: string;
|
||||
isConfigurable: boolean;
|
||||
}
|
||||
|
||||
export interface IMetricsReqParams {
|
||||
start?: number | string; // timestamp in seconds or valid date-string
|
||||
end?: number | string;
|
||||
step?: number; // step in seconds (default: 60s = each point 1m)
|
||||
range?: number; // time-range in seconds for data aggregation (default: 3600s = last 1h)
|
||||
namespace?: string; // rbac-proxy validation param
|
||||
}
|
||||
|
||||
export interface IResourceMetrics<T extends MetricData> {
|
||||
[metric: string]: T;
|
||||
cpuUsage: T;
|
||||
memoryUsage: T;
|
||||
fsUsage: T;
|
||||
fsWrites: T;
|
||||
fsReads: T;
|
||||
networkReceive: T;
|
||||
networkTransmit: T;
|
||||
}
|
||||
|
||||
async function getMetrics(query: string, reqParams?: IMetricsReqParams): Promise<MetricData>;
|
||||
async function getMetrics(query: string[], reqParams?: IMetricsReqParams): Promise<MetricData[]>;
|
||||
async function getMetrics<MetricNames extends string>(query: Record<MetricNames, Partial<Record<string, string>>>, reqParams?: IMetricsReqParams): Promise<Record<MetricNames, MetricData>>;
|
||||
|
||||
async function getMetrics(query: string | string[] | Partial<Record<string, Partial<Record<string, string>>>>, reqParams: IMetricsReqParams = {}): Promise<MetricData | MetricData[] | Partial<Record<string, MetricData>>> {
|
||||
const { range = 3600, step = 60, namespace } = reqParams;
|
||||
let { start, end } = reqParams;
|
||||
|
||||
if (!start && !end) {
|
||||
const timeNow = Date.now() / 1000;
|
||||
const now = moment.unix(timeNow).startOf("minute").unix(); // round date to minutes
|
||||
|
||||
start = now - range;
|
||||
end = now;
|
||||
}
|
||||
|
||||
return apiBase.post("/metrics", {
|
||||
data: query,
|
||||
query: {
|
||||
start, end, step,
|
||||
"kubernetes_namespace": namespace,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const metricsApi = {
|
||||
getMetrics,
|
||||
async getMetricProviders(): Promise<MetricProviderInfo[]> {
|
||||
return apiBase.get("/metrics/providers");
|
||||
},
|
||||
};
|
||||
|
||||
export function normalizeMetrics(metrics: MetricData | undefined | null, frames = 60): MetricData {
|
||||
if (!metrics?.data?.result) {
|
||||
return {
|
||||
@@ -145,7 +88,7 @@ export function isMetricsEmpty(metrics: Partial<Record<string, MetricData>>) {
|
||||
return Object.values(metrics).every(metric => !metric?.data?.result?.length);
|
||||
}
|
||||
|
||||
export function getItemMetrics(metrics: Partial<Record<string, MetricData>> | null | undefined, itemName: string): Partial<Record<string, MetricData>> | undefined {
|
||||
export function getItemMetrics<Keys extends string>(metrics: Partial<Record<Keys, MetricData>> | null | undefined, itemName: string): Partial<Record<Keys, MetricData>> | undefined {
|
||||
if (!metrics) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -166,22 +109,16 @@ export function getItemMetrics(metrics: Partial<Record<string, MetricData>> | nu
|
||||
return itemMetrics;
|
||||
}
|
||||
|
||||
export function getMetricLastPoints<T extends Partial<Record<string, MetricData>>>(metrics: T): Record<keyof T, number> {
|
||||
const result: Partial<{ [metric: string]: number }> = {};
|
||||
|
||||
Object.keys(metrics).forEach(metricName => {
|
||||
try {
|
||||
const metric = metrics[metricName];
|
||||
|
||||
if (metric?.data.result.length) {
|
||||
result[metricName] = +metric.data.result[0].values.slice(-1)[0][1];
|
||||
}
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
|
||||
return result;
|
||||
}, {});
|
||||
|
||||
return result as Record<keyof T, number>;
|
||||
export function getMetricLastPoints<Keys extends string>(metrics: Partial<Record<Keys, MetricData>>): Partial<Record<Keys, number>> {
|
||||
return object.fromEntries(
|
||||
object.entries(metrics)
|
||||
.map(([metricName, metric]) => {
|
||||
try {
|
||||
return [metricName, +metric.data.result[0].values.slice(-1)[0][1]] as const;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
})
|
||||
.filter(isDefined),
|
||||
);
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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 { MetricData } from "../metrics.api";
|
||||
import type { RequestMetricsParams } from "./request-metrics.injectable";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface ClusterMetricData {
|
||||
memoryUsage: MetricData;
|
||||
memoryRequests: MetricData;
|
||||
memoryLimits: MetricData;
|
||||
memoryCapacity: MetricData;
|
||||
memoryAllocatableCapacity: MetricData;
|
||||
cpuUsage: MetricData;
|
||||
cpuRequests: MetricData;
|
||||
cpuLimits: MetricData;
|
||||
cpuCapacity: MetricData;
|
||||
cpuAllocatableCapacity: MetricData;
|
||||
podUsage: MetricData;
|
||||
podCapacity: MetricData;
|
||||
podAllocatableCapacity: MetricData;
|
||||
fsSize: MetricData;
|
||||
fsUsage: MetricData;
|
||||
}
|
||||
|
||||
export type RequestClusterMetricsByNodeNames = (nodeNames: string[], params?: RequestMetricsParams) => Promise<ClusterMetricData>;
|
||||
|
||||
const requestClusterMetricsByNodeNamesInjectable = getInjectable({
|
||||
id: "get-cluster-metrics-by-node-names",
|
||||
instantiate: (di): RequestClusterMetricsByNodeNames => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (nodeNames, params) => {
|
||||
const opts = {
|
||||
category: "cluster",
|
||||
nodes: nodeNames.join("|"),
|
||||
};
|
||||
|
||||
return requestMetrics({
|
||||
memoryUsage: opts,
|
||||
workloadMemoryUsage: opts,
|
||||
memoryRequests: opts,
|
||||
memoryLimits: opts,
|
||||
memoryCapacity: opts,
|
||||
memoryAllocatableCapacity: opts,
|
||||
cpuUsage: opts,
|
||||
cpuRequests: opts,
|
||||
cpuLimits: opts,
|
||||
cpuCapacity: opts,
|
||||
cpuAllocatableCapacity: opts,
|
||||
podUsage: opts,
|
||||
podCapacity: opts,
|
||||
podAllocatableCapacity: opts,
|
||||
fsSize: opts,
|
||||
fsUsage: opts,
|
||||
}, params);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestClusterMetricsByNodeNamesInjectable;
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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 { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface IngressMetricData {
|
||||
bytesSentSuccess: MetricData;
|
||||
bytesSentFailure: MetricData;
|
||||
requestDurationSeconds: MetricData;
|
||||
responseDurationSeconds: MetricData;
|
||||
}
|
||||
|
||||
export type RequestIngressMetrics = (ingress: string, namespace: string) => Promise<IngressMetricData>;
|
||||
|
||||
const requestIngressMetricsInjectable = getInjectable({
|
||||
id: "request-ingress-metrics",
|
||||
instantiate: (di): RequestIngressMetrics => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (ingress, namespace) => {
|
||||
const opts = { category: "ingress", ingress, namespace };
|
||||
|
||||
return requestMetrics({
|
||||
bytesSentSuccess: opts,
|
||||
bytesSentFailure: opts,
|
||||
requestDurationSeconds: opts,
|
||||
responseDurationSeconds: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestIngressMetricsInjectable;
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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 { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface NodeMetricData {
|
||||
memoryUsage: MetricData;
|
||||
workloadMemoryUsage: MetricData;
|
||||
memoryCapacity: MetricData;
|
||||
memoryAllocatableCapacity: MetricData;
|
||||
cpuUsage: MetricData;
|
||||
cpuCapacity: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsSize: MetricData;
|
||||
}
|
||||
|
||||
export type RequestAllNodeMetrics = () => Promise<NodeMetricData>;
|
||||
|
||||
const requestAllNodeMetricsInjectable = getInjectable({
|
||||
id: "request-all-node-metrics",
|
||||
instantiate: (di): RequestAllNodeMetrics => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return () => {
|
||||
const opts = { category: "nodes" };
|
||||
|
||||
return requestMetrics({
|
||||
memoryUsage: opts,
|
||||
workloadMemoryUsage: opts,
|
||||
memoryCapacity: opts,
|
||||
memoryAllocatableCapacity: opts,
|
||||
cpuUsage: opts,
|
||||
cpuCapacity: opts,
|
||||
fsSize: opts,
|
||||
fsUsage: opts,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestAllNodeMetricsInjectable;
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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 { getSecondsFromUnixEpoch } from "../../../utils/date/get-current-date-time";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
|
||||
|
||||
export interface RequestMetricsParams {
|
||||
/**
|
||||
* timestamp in seconds or valid date-string
|
||||
*/
|
||||
start?: number | string;
|
||||
|
||||
/**
|
||||
* timestamp in seconds or valid date-string
|
||||
*/
|
||||
end?: number | string;
|
||||
|
||||
/**
|
||||
* step in seconds
|
||||
* @default 60 (1 minute)
|
||||
*/
|
||||
step?: number;
|
||||
|
||||
/**
|
||||
* time-range in seconds for data aggregation
|
||||
* @default 3600 (1 hour)
|
||||
*/
|
||||
range?: number;
|
||||
|
||||
/**
|
||||
* rbac-proxy validation param
|
||||
*/
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
export interface RequestMetrics {
|
||||
(query: string, params?: RequestMetricsParams): Promise<MetricData>;
|
||||
(query: string[], params?: RequestMetricsParams): Promise<MetricData[]>;
|
||||
<Keys extends string>(query: Record<Keys, Partial<Record<string, string>>>, params?: RequestMetricsParams): Promise<Record<Keys, MetricData>>;
|
||||
}
|
||||
|
||||
const requestMetricsInjectable = getInjectable({
|
||||
id: "request-metrics",
|
||||
instantiate: (di) => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (async (query: object, params: RequestMetricsParams = {}) => {
|
||||
const { range = 3600, step = 60, namespace } = params;
|
||||
let { start, end } = params;
|
||||
|
||||
if (!start && !end) {
|
||||
const now = getSecondsFromUnixEpoch();
|
||||
|
||||
start = now - range;
|
||||
end = now;
|
||||
}
|
||||
|
||||
return apiBase.post("/metrics", {
|
||||
data: query,
|
||||
query: {
|
||||
start, end, step,
|
||||
"kubernetes_namespace": namespace,
|
||||
},
|
||||
});
|
||||
}) as RequestMetrics;
|
||||
},
|
||||
});
|
||||
|
||||
export default requestMetricsInjectable;
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import type { PersistentVolumeClaim } from "../persistent-volume-claim.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface PersistentVolumeClaimMetricData {
|
||||
diskUsage: MetricData;
|
||||
diskCapacity: MetricData;
|
||||
}
|
||||
|
||||
export type RequestPersistentVolumeClaimMetrics = (claim: PersistentVolumeClaim) => Promise<PersistentVolumeClaimMetricData>;
|
||||
|
||||
const requestPersistentVolumeClaimMetricsInjectable = getInjectable({
|
||||
id: "request-persistent-volume-claim-metrics",
|
||||
instantiate: (di): RequestPersistentVolumeClaimMetrics => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (claim) => {
|
||||
const opts = { category: "pvc", pvc: claim.getName(), namespace: claim.getNs() };
|
||||
|
||||
return requestMetrics({
|
||||
diskUsage: opts,
|
||||
diskCapacity: opts,
|
||||
}, {
|
||||
namespace: opts.namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestPersistentVolumeClaimMetricsInjectable;
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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 { DaemonSet } from "../daemon-set.api";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface DaemonSetPodMetricData {
|
||||
cpuUsage: MetricData;
|
||||
memoryUsage: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsWrites: MetricData;
|
||||
fsReads: MetricData;
|
||||
networkReceive: MetricData;
|
||||
networkTransmit: MetricData;
|
||||
}
|
||||
|
||||
export type RequestPodMetricsForDaemonSets = (daemonsets: DaemonSet[], namespace: string, selector?: string) => Promise<DaemonSetPodMetricData>;
|
||||
|
||||
const requestPodMetricsForDaemonSetsInjectable = getInjectable({
|
||||
id: "request-pod-metrics-for-daemon-sets",
|
||||
instantiate: (di): RequestPodMetricsForDaemonSets => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (daemonSets, namespace, selector = "") => {
|
||||
const podSelector = daemonSets.map(daemonSet => `${daemonSet.getName()}-[[:alnum:]]{5}`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return requestMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestPodMetricsForDaemonSetsInjectable;
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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 { Deployment } from "../deployment.api";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface DeploymentPodMetricData {
|
||||
cpuUsage: MetricData;
|
||||
memoryUsage: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsWrites: MetricData;
|
||||
fsReads: MetricData;
|
||||
networkReceive: MetricData;
|
||||
networkTransmit: MetricData;
|
||||
}
|
||||
|
||||
export type RequestPodMetricsForDeployments = (deployments: Deployment[], namespace: string, selector?: string) => Promise<DeploymentPodMetricData>;
|
||||
|
||||
const requestPodMetricsForDeploymentsInjectable = getInjectable({
|
||||
id: "request-pod-metrics-for-deployments",
|
||||
instantiate: (di): RequestPodMetricsForDeployments => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (deployments, namespace, selector = "") => {
|
||||
const podSelector = deployments.map(deployment => `${deployment.getName()}-[[:alnum:]]{9,}-[[:alnum:]]{5}`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return requestMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestPodMetricsForDeploymentsInjectable;
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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 { Job } from "../job.api";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface JobPodMetricData {
|
||||
cpuUsage: MetricData;
|
||||
memoryUsage: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsWrites: MetricData;
|
||||
fsReads: MetricData;
|
||||
networkReceive: MetricData;
|
||||
networkTransmit: MetricData;
|
||||
}
|
||||
|
||||
export type RequestPodMetricsForJobs = (jobs: Job[], namespace: string, selector?: string) => Promise<JobPodMetricData>;
|
||||
|
||||
const requestPodMetricsForJobsInjectable = getInjectable({
|
||||
id: "request-pod-metrics-for-jobs",
|
||||
instantiate: (di): RequestPodMetricsForJobs => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (jobs, namespace, selector) => {
|
||||
const podSelector = jobs.map(job => `${job.getName()}-[[:alnum:]]{5}`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return requestMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestPodMetricsForJobsInjectable;
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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 { MetricData } from "../metrics.api";
|
||||
import type { ReplicaSet } from "../replica-set.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface ReplicaSetPodMetricData {
|
||||
cpuUsage: MetricData;
|
||||
memoryUsage: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsWrites: MetricData;
|
||||
fsReads: MetricData;
|
||||
networkReceive: MetricData;
|
||||
networkTransmit: MetricData;
|
||||
}
|
||||
|
||||
export type RequestPodMetricsForReplicaSets = (replicaSets: ReplicaSet[], namespace: string, selector?: string) => Promise<ReplicaSetPodMetricData>;
|
||||
|
||||
const requestPodMetricsForReplicaSetsInjectable = getInjectable({
|
||||
id: "request-pod-metrics-for-replica-sets",
|
||||
instantiate: (di): RequestPodMetricsForReplicaSets => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (replicaSets, namespace, selector = "") => {
|
||||
const podSelector = replicaSets.map(replicaSet => `${replicaSet.getName()}-[[:alnum:]]{5}`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return requestMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestPodMetricsForReplicaSetsInjectable;
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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 { MetricData } from "../metrics.api";
|
||||
import type { StatefulSet } from "../stateful-set.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface StatefulSetPodMetricData {
|
||||
cpuUsage: MetricData;
|
||||
memoryUsage: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsWrites: MetricData;
|
||||
fsReads: MetricData;
|
||||
networkReceive: MetricData;
|
||||
networkTransmit: MetricData;
|
||||
}
|
||||
|
||||
export type RequestPodMetricsForStatefulSets = (statefulSets: StatefulSet[], namespace: string, selector?: string) => Promise<StatefulSetPodMetricData>;
|
||||
|
||||
const requestPodMetricsForStatefulSetsInjectable = getInjectable({
|
||||
id: "request-pod-metrics-for-stateful-sets",
|
||||
instantiate: (di): RequestPodMetricsForStatefulSets => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (statefulSets, namespace, selector = "") => {
|
||||
const podSelector = statefulSets.map(statefulset => `${statefulset.getName()}-[[:digit:]]+`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return requestMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestPodMetricsForStatefulSetsInjectable;
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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 { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface PodMetricInNamespaceData {
|
||||
cpuUsage: MetricData;
|
||||
memoryUsage: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsWrites: MetricData;
|
||||
fsReads: MetricData;
|
||||
networkReceive: MetricData;
|
||||
networkTransmit: MetricData;
|
||||
}
|
||||
|
||||
export type RequestPodMetricsInNamespace = (namespace: string, selector?: string) => Promise<PodMetricInNamespaceData>;
|
||||
|
||||
const requestPodMetricsInNamespaceInjectable = getInjectable({
|
||||
id: "request-pod-metrics-in-namespace",
|
||||
instantiate: (di): RequestPodMetricsInNamespace => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (namespace, selector) => {
|
||||
const opts = { category: "pods", pods: ".*", namespace, selector };
|
||||
|
||||
return requestMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestPodMetricsInNamespaceInjectable;
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 { MetricData } from "../metrics.api";
|
||||
import type { Pod } from "../pod.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface PodMetricData {
|
||||
cpuUsage: MetricData;
|
||||
memoryUsage: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsWrites: MetricData;
|
||||
fsReads: MetricData;
|
||||
networkReceive: MetricData;
|
||||
networkTransmit: MetricData;
|
||||
cpuRequests: MetricData;
|
||||
cpuLimits: MetricData;
|
||||
memoryRequests: MetricData;
|
||||
memoryLimits: MetricData;
|
||||
}
|
||||
|
||||
export type RequestPodMetrics = (pods: Pod[], namespace: string, selector?: string) => Promise<PodMetricData>;
|
||||
|
||||
const requestPodMetricsInjectable = getInjectable({
|
||||
id: "request-pod-metrics",
|
||||
instantiate: (di): RequestPodMetrics => {
|
||||
const requestMetrics = di.inject(requestMetricsInjectable);
|
||||
|
||||
return (pods, namespace, selector = "pod, namespace") => {
|
||||
const podSelector = pods.map(pod => pod.getName()).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return requestMetrics({
|
||||
cpuUsage: opts,
|
||||
cpuRequests: opts,
|
||||
cpuLimits: opts,
|
||||
memoryUsage: opts,
|
||||
memoryRequests: opts,
|
||||
memoryLimits: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default requestPodMetricsInjectable;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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 { apiBaseInjectionToken } from "../../api-base";
|
||||
|
||||
export interface MetricProviderInfo {
|
||||
name: string;
|
||||
id: string;
|
||||
isConfigurable: boolean;
|
||||
}
|
||||
|
||||
export type RequestMetricsProviders = () => Promise<MetricProviderInfo[]>;
|
||||
|
||||
const requestMetricsProvidersInjectable = getInjectable({
|
||||
id: "request-metrics-providers",
|
||||
instantiate: (di): RequestMetricsProviders => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return () => apiBase.get("/metrics/providers");
|
||||
},
|
||||
});
|
||||
|
||||
export default requestMetricsProvidersInjectable;
|
||||
@@ -7,8 +7,6 @@ import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { ClusterScopedMetadata, KubeObjectStatus } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { PodMetricData } from "./pod.api";
|
||||
|
||||
export enum NamespaceStatusKind {
|
||||
ACTIVE = "Active",
|
||||
@@ -45,19 +43,3 @@ export class NamespaceApi extends KubeApi<Namespace> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForNamespace(namespace: string, selector = ""): Promise<PodMetricData> {
|
||||
const opts = { category: "pods", pods: ".*", namespace, selector };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
}
|
||||
@@ -6,8 +6,6 @@
|
||||
import type { BaseKubeObjectCondition, ClusterScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { cpuUnitsToNumber, unitsToBytes, isObject } from "../../../renderer/utils";
|
||||
import type { MetricData } from "./metrics.api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { TypedRegEx } from "typed-regex";
|
||||
@@ -21,32 +19,6 @@ export class NodeApi extends KubeApi<Node> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForAllNodes(): Promise<NodeMetricData> {
|
||||
const opts = { category: "nodes" };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
memoryUsage: opts,
|
||||
workloadMemoryUsage: opts,
|
||||
memoryCapacity: opts,
|
||||
memoryAllocatableCapacity: opts,
|
||||
cpuUsage: opts,
|
||||
cpuCapacity: opts,
|
||||
fsSize: opts,
|
||||
fsUsage: opts,
|
||||
});
|
||||
}
|
||||
|
||||
export interface NodeMetricData extends Partial<Record<string, MetricData>> {
|
||||
memoryUsage: MetricData;
|
||||
workloadMemoryUsage: MetricData;
|
||||
memoryCapacity: MetricData;
|
||||
memoryAllocatableCapacity: MetricData;
|
||||
cpuUsage: MetricData;
|
||||
cpuCapacity: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsSize: MetricData;
|
||||
}
|
||||
|
||||
export interface NodeTaint {
|
||||
key: string;
|
||||
value?: string;
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
import type { LabelSelector, NamespaceScopedMetadata, TypedLocalObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { MetricData } from "./metrics.api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { Pod } from "./pod.api";
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
@@ -22,22 +20,6 @@ export class PersistentVolumeClaimApi extends KubeApi<PersistentVolumeClaim> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForPvc(pvc: PersistentVolumeClaim): Promise<PersistentVolumeClaimMetricData> {
|
||||
const opts = { category: "pvc", pvc: pvc.getName(), namespace: pvc.getNs() };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
diskUsage: opts,
|
||||
diskCapacity: opts,
|
||||
}, {
|
||||
namespace: opts.namespace,
|
||||
});
|
||||
}
|
||||
|
||||
export interface PersistentVolumeClaimMetricData extends Partial<Record<string, MetricData>> {
|
||||
diskUsage: MetricData;
|
||||
diskCapacity: MetricData;
|
||||
}
|
||||
|
||||
export interface PersistentVolumeClaimSpec {
|
||||
accessModes?: string[];
|
||||
dataSource?: TypedLocalObjectReference;
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { MetricData } from "./metrics.api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions, ResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { RequireExactlyOne } from "type-fest";
|
||||
@@ -33,41 +31,6 @@ export class PodApi extends KubeApi<Pod> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForPods(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise<PodMetricData> {
|
||||
const podSelector = pods.map(pod => pod.getName()).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
cpuUsage: opts,
|
||||
cpuRequests: opts,
|
||||
cpuLimits: opts,
|
||||
memoryUsage: opts,
|
||||
memoryRequests: opts,
|
||||
memoryLimits: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
}
|
||||
|
||||
export interface PodMetricData extends Partial<Record<string, MetricData>> {
|
||||
cpuUsage: MetricData;
|
||||
memoryUsage: MetricData;
|
||||
fsUsage: MetricData;
|
||||
fsWrites: MetricData;
|
||||
fsReads: MetricData;
|
||||
networkReceive: MetricData;
|
||||
networkTransmit: MetricData;
|
||||
cpuRequests?: MetricData;
|
||||
cpuLimits?: MetricData;
|
||||
memoryRequests?: MetricData;
|
||||
memoryLimits?: MetricData;
|
||||
}
|
||||
|
||||
// Reference: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#read-log-pod-v1-core
|
||||
export interface PodLogsQuery {
|
||||
container?: string;
|
||||
@@ -714,6 +677,10 @@ export class Pod extends KubeObject<
|
||||
return this.spec?.priorityClassName || "";
|
||||
}
|
||||
|
||||
getRuntimeClassName() {
|
||||
return this.spec?.runtimeClassName || "";
|
||||
}
|
||||
|
||||
getServiceAccountName() {
|
||||
return this.spec?.serviceAccountName || "";
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { PodMetricData } from "./pod.api";
|
||||
import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodTemplateSpec } from "./types/pod-template-spec";
|
||||
@@ -41,23 +39,6 @@ export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForReplicaSets(replicasets: ReplicaSet[], namespace: string, selector = ""): Promise<PodMetricData> {
|
||||
const podSelector = replicasets.map(replicaset => `${replicaset.getName()}-[[:alnum:]]{5}`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
}
|
||||
|
||||
export interface ReplicaSetSpec {
|
||||
replicas?: number;
|
||||
selector: LabelSelector;
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import yaml from "js-yaml";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { apiBase } from "../index";
|
||||
import type { Patch } from "rfc6902";
|
||||
|
||||
export const annotations = [
|
||||
"kubectl.kubernetes.io/last-applied-configuration",
|
||||
];
|
||||
|
||||
export async function update(resource: object | string): Promise<KubeJsonApiData> {
|
||||
if (typeof resource === "string") {
|
||||
const parsed = yaml.load(resource);
|
||||
|
||||
if (!parsed || typeof parsed !== "object") {
|
||||
throw new Error("Cannot update resource to string or number");
|
||||
}
|
||||
|
||||
resource = parsed;
|
||||
}
|
||||
|
||||
return apiBase.post<KubeJsonApiData>("/stack", { data: resource });
|
||||
}
|
||||
|
||||
export async function patch(name: string, kind: string, ns: string | undefined, patch: Patch): Promise<KubeJsonApiData> {
|
||||
return apiBase.patch<KubeJsonApiData>("/stack", {
|
||||
data: {
|
||||
name,
|
||||
kind,
|
||||
ns,
|
||||
patch,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 { Patch } from "rfc6902";
|
||||
import { apiBaseInjectionToken } from "../../api-base";
|
||||
import type { KubeJsonApiData } from "../../kube-json-api";
|
||||
|
||||
export type RequestKubeObjectPatch = (name: string, kind: string, ns: string | undefined, patch: Patch) => Promise<KubeJsonApiData>;
|
||||
|
||||
const requestKubeObjectPatchInjectable = getInjectable({
|
||||
id: "request-kube-object-patch",
|
||||
instantiate: (di): RequestKubeObjectPatch => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (name, kind, ns, patch) => (
|
||||
apiBase.patch("/stack", {
|
||||
data: {
|
||||
name,
|
||||
kind,
|
||||
ns,
|
||||
patch,
|
||||
},
|
||||
})
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default requestKubeObjectPatchInjectable;
|
||||
@@ -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 { apiBaseInjectionToken } from "../../api-base";
|
||||
import type { KubeJsonApiData } from "../../kube-json-api";
|
||||
|
||||
export type RequestKubeObjectCreation = (resourceDescriptor: string) => Promise<KubeJsonApiData>;
|
||||
|
||||
const requestKubeObjectCreationInjectable = getInjectable({
|
||||
id: "request-kube-object-creation",
|
||||
instantiate: (di): RequestKubeObjectCreation => {
|
||||
const apiBase = di.inject(apiBaseInjectionToken);
|
||||
|
||||
return (data) => apiBase.post("/stack", { data });
|
||||
},
|
||||
});
|
||||
|
||||
export default requestKubeObjectCreationInjectable;
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 assert from "assert";
|
||||
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||
import { RuntimeClassApi } from "./runtime-class.api";
|
||||
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||
|
||||
const runtimeClassApiInjectable = getInjectable({
|
||||
id: "runtime-class-api",
|
||||
instantiate: (di) => {
|
||||
assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "RuntimeClassApi is only available in certain environments");
|
||||
|
||||
return new RuntimeClassApi();
|
||||
},
|
||||
|
||||
injectionToken: kubeApiInjectionToken,
|
||||
});
|
||||
|
||||
export default runtimeClassApiInjectable;
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { DerivedKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { ClusterScopedMetadata, KubeObjectMetadata, KubeObjectScope, Toleration } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
export interface RuntimeClassData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Cluster>, void, void> {
|
||||
handler: string;
|
||||
overhead?: RuntimeClassOverhead;
|
||||
scheduling?: RuntimeClassScheduling;
|
||||
}
|
||||
|
||||
export interface RuntimeClassOverhead {
|
||||
podFixed?: string;
|
||||
}
|
||||
|
||||
export interface RuntimeClassScheduling {
|
||||
nodeSelector?: Partial<Record<string, string>>;
|
||||
tolerations?: Toleration[];
|
||||
}
|
||||
|
||||
export class RuntimeClass extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "RuntimeClass";
|
||||
static readonly namespaced = false;
|
||||
static readonly apiBase = "/apis/node.k8s.io/v1/runtimeclasses";
|
||||
|
||||
handler: string;
|
||||
overhead?: RuntimeClassOverhead;
|
||||
scheduling?: RuntimeClassScheduling;
|
||||
|
||||
constructor({ handler, overhead, scheduling, ...rest }: RuntimeClassData) {
|
||||
super(rest);
|
||||
this.handler = handler;
|
||||
this.overhead = overhead;
|
||||
this.scheduling = scheduling;
|
||||
}
|
||||
|
||||
getHandler() {
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
getPodFixed() {
|
||||
return this.overhead?.podFixed ?? "";
|
||||
}
|
||||
|
||||
getNodeSelectors(): string[] {
|
||||
return Object.entries(this.scheduling?.nodeSelector ?? {})
|
||||
.map(values => values.join(": "));
|
||||
}
|
||||
|
||||
getTolerations() {
|
||||
return this.scheduling?.tolerations ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
export class RuntimeClassApi extends KubeApi<RuntimeClass, RuntimeClassData> {
|
||||
constructor(opts: DerivedKubeApiOptions = {}) {
|
||||
super({
|
||||
objectConstructor: RuntimeClass,
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, IgnoredKubeApiOptions } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { metricsApi } from "./metrics.api";
|
||||
import type { PodMetricData } from "./pod.api";
|
||||
import type { LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodTemplateSpec } from "./types/pod-template-spec";
|
||||
@@ -46,23 +44,6 @@ export class StatefulSetApi extends KubeApi<StatefulSet> {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetricsForStatefulSets(statefulSets: StatefulSet[], namespace: string, selector = ""): Promise<PodMetricData> {
|
||||
const podSelector = statefulSets.map(statefulset => `${statefulset.getName()}-[[:digit:]]+`).join("|");
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector };
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
cpuUsage: opts,
|
||||
memoryUsage: opts,
|
||||
fsUsage: opts,
|
||||
fsWrites: opts,
|
||||
fsReads: opts,
|
||||
networkReceive: opts,
|
||||
networkTransmit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
}
|
||||
|
||||
export interface StatefulSetSpec {
|
||||
serviceName: string;
|
||||
replicas: number;
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export { apiBase } from "./api-base";
|
||||
export { apiKube } from "./api-kube";
|
||||
@@ -9,12 +9,12 @@ import { Agent as HttpAgent } from "http";
|
||||
import { Agent as HttpsAgent } from "https";
|
||||
import { merge } from "lodash";
|
||||
import type { Response, RequestInit } from "node-fetch";
|
||||
import fetch from "node-fetch";
|
||||
import { stringify } from "querystring";
|
||||
import type { Patch } from "rfc6902";
|
||||
import type { PartialDeep, ValueOf } from "type-fest";
|
||||
import { EventEmitter } from "../../common/event-emitter";
|
||||
import logger from "../../common/logger";
|
||||
import type { Logger } from "../../common/logger";
|
||||
import type { Fetch } from "../fetch/fetch.injectable";
|
||||
import type { Defaulted } from "../utils";
|
||||
import { json } from "../utils";
|
||||
|
||||
@@ -59,6 +59,11 @@ export type ParamsAndQuery<Params, Query> = (
|
||||
: Params & { query?: undefined }
|
||||
);
|
||||
|
||||
export interface JsonApiDependencies {
|
||||
fetch: Fetch;
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = JsonApiParams<Data>> {
|
||||
static readonly reqInitDefault = {
|
||||
headers: {
|
||||
@@ -71,7 +76,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
debug: false,
|
||||
};
|
||||
|
||||
constructor(public readonly config: JsonApiConfig, reqInit?: RequestInit) {
|
||||
constructor(protected readonly dependencies: JsonApiDependencies, public readonly config: JsonApiConfig, reqInit?: RequestInit) {
|
||||
this.config = Object.assign({}, JsonApi.configDefault, config);
|
||||
this.reqInit = merge({}, JsonApi.reqInitDefault, reqInit);
|
||||
this.parseResponse = this.parseResponse.bind(this);
|
||||
@@ -105,7 +110,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString;
|
||||
}
|
||||
|
||||
return fetch(reqUrl, reqInit);
|
||||
return this.dependencies.fetch(reqUrl, reqInit);
|
||||
}
|
||||
|
||||
get<OutData = Data, Query = QueryParams>(
|
||||
@@ -177,7 +182,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
reqInit,
|
||||
};
|
||||
|
||||
const res = await fetch(reqUrl, reqInit);
|
||||
const res = await this.dependencies.fetch(reqUrl, reqInit);
|
||||
|
||||
return this.parseResponse<OutData>(res, infoLog);
|
||||
}
|
||||
@@ -233,7 +238,7 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
|
||||
protected writeLog(log: JsonApiLog) {
|
||||
const { method, reqUrl, ...params } = log;
|
||||
|
||||
logger.debug(`[JSON-API] request ${method} ${reqUrl}`, params);
|
||||
this.dependencies.logger.debug(`[JSON-API] request ${method} ${reqUrl}`, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 445 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user