mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add behavioural tests for Cluster Menu K8s Resources in Sidebar menu not being shown (#7280)
* Add behavioural tests to cover bug fix Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove previous fix to fix last test Signed-off-by: Sebastian Malton <sebastian@malton.name> * More consistent impl of flushPromises Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fixup tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove ContextHandler test (dead code) Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix PrometheusHandler describe text Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add useful case test-utils helper Signed-off-by: Sebastian Malton <sebastian@malton.name> * Rename file to match token Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cleanup tests to fix type errors and use tables Signed-off-by: Sebastian Malton <sebastian@malton.name> --------- Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
5409324236
commit
8a80607d85
32 files changed
+1104
-774
No files matched your search
@@ -5,10 +5,6 @@
|
||||
import { Cluster } from "../../common/cluster/cluster";
|
||||
import { Kubectl } from "../kubectl/kubectl";
|
||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
import createAuthorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
|
||||
import requestNamespaceListPermissionsForInjectable from "../../common/cluster/request-namespace-list-permissions.injectable";
|
||||
import createListNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
||||
import prometheusHandlerInjectable from "../cluster/prometheus-handler/prometheus-handler.injectable";
|
||||
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import directoryForTempInjectable from "../../common/app-paths/directory-for-temp/directory-for-temp.injectable";
|
||||
import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable";
|
||||
@@ -19,6 +15,10 @@ import clusterConnectionInjectable from "../cluster/cluster-connection.injectabl
|
||||
import kubeconfigManagerInjectable from "../kubeconfig-manager/kubeconfig-manager.injectable";
|
||||
import type { KubeconfigManager } from "../kubeconfig-manager/kubeconfig-manager";
|
||||
import broadcastConnectionUpdateInjectable from "../cluster/broadcast-connection-update.injectable";
|
||||
import createCanIInjectable from "../../common/cluster/create-can-i.injectable";
|
||||
import createRequestNamespaceListPermissionsInjectable from "../../common/cluster/create-request-namespace-list-permissions.injectable";
|
||||
import createListNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
||||
import prometheusHandlerInjectable from "../cluster/prometheus-handler/prometheus-handler.injectable";
|
||||
|
||||
describe("create clusters", () => {
|
||||
let cluster: Cluster;
|
||||
@@ -34,8 +34,8 @@ describe("create clusters", () => {
|
||||
di.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
|
||||
di.override(normalizedPlatformInjectable, () => "darwin");
|
||||
di.override(broadcastConnectionUpdateInjectable, () => async () => {});
|
||||
di.override(createAuthorizationReviewInjectable, () => () => () => Promise.resolve(true));
|
||||
di.override(requestNamespaceListPermissionsForInjectable, () => () => async () => () => true);
|
||||
di.override(createCanIInjectable, () => () => () => Promise.resolve(true));
|
||||
di.override(createRequestNamespaceListPermissionsInjectable, () => () => async () => () => true);
|
||||
di.override(createListNamespacesInjectable, () => () => () => Promise.resolve([ "default" ]));
|
||||
di.override(prometheusHandlerInjectable, () => ({
|
||||
getPrometheusDetails: jest.fn(),
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
import { Cluster } from "../../common/cluster/cluster";
|
||||
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { PrometheusProvider } from "../prometheus/provider";
|
||||
import { prometheusProviderInjectionToken } from "../prometheus/provider";
|
||||
import { runInAction } from "mobx";
|
||||
import prometheusHandlerInjectable from "../cluster/prometheus-handler/prometheus-handler.injectable";
|
||||
import directoryForTempInjectable from "../../common/app-paths/directory-for-temp/directory-for-temp.injectable";
|
||||
import lensProxyPortInjectable from "../lens-proxy/lens-proxy-port.injectable";
|
||||
import type { KubeAuthProxy } from "../kube-auth-proxy/kube-auth-proxy";
|
||||
import loadProxyKubeconfigInjectable from "../cluster/load-proxy-kubeconfig.injectable";
|
||||
import type { KubeConfig } from "@kubernetes/client-node";
|
||||
|
||||
enum ServiceResult {
|
||||
Success,
|
||||
Failure,
|
||||
}
|
||||
|
||||
const createTestPrometheusProvider = (kind: string, alwaysFail: ServiceResult): PrometheusProvider => ({
|
||||
kind,
|
||||
name: "TestProvider1",
|
||||
isConfigurable: false,
|
||||
getQuery: () => {
|
||||
throw new Error("getQuery is not implemented.");
|
||||
},
|
||||
getPrometheusService: async () => {
|
||||
switch (alwaysFail) {
|
||||
case ServiceResult.Success:
|
||||
return {
|
||||
kind,
|
||||
namespace: "default",
|
||||
port: 7000,
|
||||
service: "",
|
||||
};
|
||||
case ServiceResult.Failure:
|
||||
throw new Error("does fail");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
describe("ContextHandler", () => {
|
||||
let di: DiContainer;
|
||||
let cluster: Cluster;
|
||||
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting();
|
||||
|
||||
di.override(loadProxyKubeconfigInjectable, () => async () => ({
|
||||
makeApiClient: () => ({} as any),
|
||||
} as Partial<KubeConfig>));
|
||||
|
||||
di.override(createKubeAuthProxyInjectable, () => () => ({
|
||||
run: async () => {},
|
||||
} as KubeAuthProxy));
|
||||
di.override(directoryForTempInjectable, () => "/some-directory-for-tmp");
|
||||
di.inject(lensProxyPortInjectable).set(9968);
|
||||
|
||||
cluster = new Cluster({
|
||||
contextName: "some-context-name",
|
||||
id: "some-cluster-id",
|
||||
kubeConfigPath: "/some-kubeconfig-path",
|
||||
}, {
|
||||
clusterServerUrl: "https://some-website.com",
|
||||
});
|
||||
});
|
||||
|
||||
describe("getPrometheusService", () => {
|
||||
it.each([
|
||||
[0],
|
||||
[1],
|
||||
[2],
|
||||
[3],
|
||||
])("should throw after %d failure(s)", async (failures) => {
|
||||
runInAction(() => {
|
||||
for (let i = 0; i < failures; i += 1) {
|
||||
di.register(getInjectable({
|
||||
id: `test-prometheus-provider-failure-${i}`,
|
||||
injectionToken: prometheusProviderInjectionToken,
|
||||
instantiate: () => createTestPrometheusProvider(`id_failure_${i}`, ServiceResult.Failure),
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
expect(() => di.inject(prometheusHandlerInjectable, cluster).getPrometheusDetails()).rejects.toThrowError();
|
||||
});
|
||||
|
||||
it.each([
|
||||
[1, 0],
|
||||
[1, 1],
|
||||
[1, 2],
|
||||
[1, 3],
|
||||
[2, 0],
|
||||
[2, 1],
|
||||
[2, 2],
|
||||
[2, 3],
|
||||
])("should pick the first provider of %d success(es) after %d failure(s)", async (successes, failures) => {
|
||||
runInAction(() => {
|
||||
for (let i = 0; i < failures; i += 1) {
|
||||
di.register(getInjectable({
|
||||
id: `test-prometheus-provider-failure-${i}`,
|
||||
injectionToken: prometheusProviderInjectionToken,
|
||||
instantiate: () => createTestPrometheusProvider(`id_failure_${i}`, ServiceResult.Failure),
|
||||
}));
|
||||
}
|
||||
|
||||
for (let i = 0; i < successes; i += 1) {
|
||||
di.register(getInjectable({
|
||||
id: `test-prometheus-provider-success-${i}`,
|
||||
injectionToken: prometheusProviderInjectionToken,
|
||||
instantiate: () => createTestPrometheusProvider(`id_success_${i}`, ServiceResult.Success),
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const details = await di.inject(prometheusHandlerInjectable, cluster).getPrometheusDetails();
|
||||
|
||||
expect(details.provider.kind === `id_failure_${failures}`);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[1, 0],
|
||||
[1, 1],
|
||||
[1, 2],
|
||||
[1, 3],
|
||||
[2, 0],
|
||||
[2, 1],
|
||||
[2, 2],
|
||||
[2, 3],
|
||||
])("should pick the first provider of %d success(es) before %d failure(s)", async (successes, failures) => {
|
||||
runInAction(() => {
|
||||
for (let i = 0; i < failures; i += 1) {
|
||||
di.register(getInjectable({
|
||||
id: `test-prometheus-provider-failure-${i}`,
|
||||
injectionToken: prometheusProviderInjectionToken,
|
||||
instantiate: () => createTestPrometheusProvider(`id_failure_${i}`, ServiceResult.Failure),
|
||||
}));
|
||||
}
|
||||
|
||||
for (let i = 0; i < successes; i += 1) {
|
||||
di.register(getInjectable({
|
||||
id: `test-prometheus-provider-success-${i}`,
|
||||
injectionToken: prometheusProviderInjectionToken,
|
||||
instantiate: () => createTestPrometheusProvider(`id_success_${i}`, ServiceResult.Success),
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const details = await di.inject(prometheusHandlerInjectable, cluster).getPrometheusDetails();
|
||||
|
||||
expect(details.provider.kind === "id_failure_0");
|
||||
});
|
||||
|
||||
it.each([
|
||||
[1, 0],
|
||||
[1, 1],
|
||||
[1, 2],
|
||||
[1, 3],
|
||||
[2, 0],
|
||||
[2, 1],
|
||||
[2, 2],
|
||||
[2, 3],
|
||||
])("should pick the first provider of %d success(es) between %d failure(s)", async (successes, failures) => {
|
||||
const beforeSuccesses = Math.floor(successes / 2);
|
||||
|
||||
runInAction(() => {
|
||||
for (let i = 0; i < beforeSuccesses; i += 1) {
|
||||
di.register(getInjectable({
|
||||
id: `test-prometheus-provider-success-${i}`,
|
||||
injectionToken: prometheusProviderInjectionToken,
|
||||
instantiate: () => createTestPrometheusProvider(`id_success_${i}`, ServiceResult.Success),
|
||||
}));
|
||||
}
|
||||
|
||||
for (let i = 0; i < failures; i += 1) {
|
||||
di.register(getInjectable({
|
||||
id: `test-prometheus-provider-failure-${i}`,
|
||||
injectionToken: prometheusProviderInjectionToken,
|
||||
instantiate: () => createTestPrometheusProvider(`id_failure_${i}`, ServiceResult.Failure),
|
||||
}));
|
||||
}
|
||||
|
||||
for (let i = beforeSuccesses; i < successes; i += 1) {
|
||||
di.register(getInjectable({
|
||||
id: `test-prometheus-provider-success-${i}`,
|
||||
injectionToken: prometheusProviderInjectionToken,
|
||||
instantiate: () => createTestPrometheusProvider(`id_success_${i}`, ServiceResult.Success),
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const details = await di.inject(prometheusHandlerInjectable, cluster).getPrometheusDetails();
|
||||
|
||||
expect(details.provider.kind === "id_success_0");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import waitUntilPortIsUsedInjectable from "../kube-auth-proxy/wait-until-port-is-used/wait-until-port-is-used.injectable";
|
||||
import { Cluster } from "../../common/cluster/cluster";
|
||||
import type { KubeAuthProxy } from "../kube-auth-proxy/kube-auth-proxy";
|
||||
import type { ChildProcess } from "child_process";
|
||||
import { Kubectl } from "../kubectl/kubectl";
|
||||
import type { DeepMockProxy } from "jest-mock-extended";
|
||||
@@ -13,6 +12,7 @@ import { mockDeep, mock } from "jest-mock-extended";
|
||||
import type { Readable } from "stream";
|
||||
import { EventEmitter } from "stream";
|
||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
import type { CreateKubeAuthProxy, KubeAuthProxy } from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
import spawnInjectable from "../child-process/spawn.injectable";
|
||||
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
@@ -29,7 +29,7 @@ import getBasenameOfPathInjectable from "../../common/path/get-basename.injectab
|
||||
const clusterServerUrl = "https://192.168.64.3:8443";
|
||||
|
||||
describe("kube auth proxy tests", () => {
|
||||
let createKubeAuthProxy: (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => KubeAuthProxy;
|
||||
let createKubeAuthProxy: CreateKubeAuthProxy;
|
||||
let spawnMock: jest.Mock;
|
||||
let waitUntilPortIsUsedMock: jest.Mock;
|
||||
let broadcastMessageMock: jest.Mock;
|
||||
|
||||
@@ -43,7 +43,7 @@ const createTestPrometheusProvider = (kind: string, alwaysFail: ServiceResult):
|
||||
},
|
||||
});
|
||||
|
||||
describe("ContextHandler", () => {
|
||||
describe("PrometheusHandler", () => {
|
||||
let di: DiContainer;
|
||||
let cluster: Cluster;
|
||||
|
||||
|
||||
+5
-2
@@ -15,8 +15,11 @@ export interface ClusterData {
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
export type RequestApiVersions = (cluster: ClusterData) => AsyncResult<KubeResourceListGroup[], Error>;
|
||||
export interface ApiVersionsRequester {
|
||||
request(cluster: ClusterData): AsyncResult<KubeResourceListGroup[], Error>;
|
||||
readonly orderNumber: number;
|
||||
}
|
||||
|
||||
export const requestApiVersionsInjectionToken = getInjectionToken<RequestApiVersions>({
|
||||
export const apiVersionsRequesterInjectionToken = getInjectionToken<ApiVersionsRequester>({
|
||||
id: "request-api-versions-token",
|
||||
});
|
||||
@@ -6,10 +6,7 @@
|
||||
import { type KubeConfig, HttpError } from "@kubernetes/client-node";
|
||||
import { reaction, comparer, runInAction } from "mobx";
|
||||
import { ClusterStatus } from "../../common/cluster-types";
|
||||
import type { CreateAuthorizationReview } from "../../common/cluster/authorization-review.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import type { CreateListNamespaces } from "../../common/cluster/list-namespaces.injectable";
|
||||
import type { RequestNamespaceListPermissionsFor, RequestNamespaceListPermissions } from "../../common/cluster/request-namespace-list-permissions.injectable";
|
||||
import type { BroadcastMessage } from "../../common/ipc/broadcast-message.injectable";
|
||||
import { clusterListNamespaceForbiddenChannel } from "../../common/ipc/cluster";
|
||||
import type { Logger } from "../../common/logger";
|
||||
@@ -25,7 +22,6 @@ import type { RequestApiResources } from "./request-api-resources.injectable";
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import broadcastConnectionUpdateInjectable from "./broadcast-connection-update.injectable";
|
||||
import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable";
|
||||
import createAuthorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
|
||||
import createListNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
||||
import kubeAuthProxyServerInjectable from "./kube-auth-proxy-server.injectable";
|
||||
import loadProxyKubeconfigInjectable from "./load-proxy-kubeconfig.injectable";
|
||||
@@ -33,21 +29,31 @@ import loggerInjectable from "../../common/logger.injectable";
|
||||
import prometheusHandlerInjectable from "./prometheus-handler/prometheus-handler.injectable";
|
||||
import removeProxyKubeconfigInjectable from "./remove-proxy-kubeconfig.injectable";
|
||||
import requestApiResourcesInjectable from "./request-api-resources.injectable";
|
||||
import requestNamespaceListPermissionsForInjectable from "../../common/cluster/request-namespace-list-permissions.injectable";
|
||||
import type { DetectClusterMetadata } from "../cluster-detectors/detect-cluster-metadata.injectable";
|
||||
import type { FallibleOnlyClusterMetadataDetector } from "../cluster-detectors/token";
|
||||
import clusterVersionDetectorInjectable from "../cluster-detectors/cluster-version-detector.injectable";
|
||||
import detectClusterMetadataInjectable from "../cluster-detectors/detect-cluster-metadata.injectable";
|
||||
import { replaceObservableObject } from "../../common/utils/replace-observable-object";
|
||||
import type { CreateAuthorizationApi } from "../../common/cluster/create-authorization-api.injectable";
|
||||
import type { CreateCanI } from "../../common/cluster/create-can-i.injectable";
|
||||
import type { CreateRequestNamespaceListPermissions, RequestNamespaceListPermissions } from "../../common/cluster/create-request-namespace-list-permissions.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import createAuthorizationApiInjectable from "../../common/cluster/create-authorization-api.injectable";
|
||||
import createCanIInjectable from "../../common/cluster/create-can-i.injectable";
|
||||
import createRequestNamespaceListPermissionsInjectable from "../../common/cluster/create-request-namespace-list-permissions.injectable";
|
||||
import type { CreateCoreApi } from "../../common/cluster/create-core-api.injectable";
|
||||
import createCoreApiInjectable from "../../common/cluster/create-core-api.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
readonly logger: Logger;
|
||||
readonly prometheusHandler: ClusterPrometheusHandler;
|
||||
readonly kubeAuthProxyServer: KubeAuthProxyServer;
|
||||
readonly clusterVersionDetector: FallibleOnlyClusterMetadataDetector;
|
||||
createAuthorizationReview: CreateAuthorizationReview;
|
||||
createCanI: CreateCanI;
|
||||
requestApiResources: RequestApiResources;
|
||||
requestNamespaceListPermissionsFor: RequestNamespaceListPermissionsFor;
|
||||
createRequestNamespaceListPermissions: CreateRequestNamespaceListPermissions;
|
||||
createAuthorizationApi: CreateAuthorizationApi;
|
||||
createCoreApi: CreateCoreApi;
|
||||
createListNamespaces: CreateListNamespaces;
|
||||
detectClusterMetadata: DetectClusterMetadata;
|
||||
broadcastMessage: BroadcastMessage;
|
||||
@@ -224,8 +230,9 @@ class ClusterConnection {
|
||||
private async refreshAccessibility(): Promise<void> {
|
||||
this.dependencies.logger.info(`[CLUSTER]: refreshAccessibility`, this.cluster.getMeta());
|
||||
const proxyConfig = await this.dependencies.loadProxyKubeconfig();
|
||||
const canI = this.dependencies.createAuthorizationReview(proxyConfig);
|
||||
const requestNamespaceListPermissions = this.dependencies.requestNamespaceListPermissionsFor(proxyConfig);
|
||||
const api = this.dependencies.createAuthorizationApi(proxyConfig);
|
||||
const canI = this.dependencies.createCanI(api);
|
||||
const requestNamespaceListPermissions = this.dependencies.createRequestNamespaceListPermissions(api);
|
||||
|
||||
const isAdmin = await canI({
|
||||
namespace: "kube-system",
|
||||
@@ -360,7 +367,8 @@ class ClusterConnection {
|
||||
}
|
||||
|
||||
try {
|
||||
const listNamespaces = this.dependencies.createListNamespaces(proxyConfig);
|
||||
const api = this.dependencies.createCoreApi(proxyConfig);
|
||||
const listNamespaces = this.dependencies.createListNamespaces(api);
|
||||
|
||||
return await listNamespaces();
|
||||
} catch (error) {
|
||||
@@ -403,13 +411,15 @@ const clusterConnectionInjectable = getInjectable({
|
||||
prometheusHandler: di.inject(prometheusHandlerInjectable, cluster),
|
||||
broadcastConnectionUpdate: di.inject(broadcastConnectionUpdateInjectable, cluster),
|
||||
broadcastMessage: di.inject(broadcastMessageInjectable),
|
||||
createAuthorizationReview: di.inject(createAuthorizationReviewInjectable),
|
||||
createListNamespaces: di.inject(createListNamespacesInjectable),
|
||||
detectClusterMetadata: di.inject(detectClusterMetadataInjectable),
|
||||
loadProxyKubeconfig: di.inject(loadProxyKubeconfigInjectable, cluster),
|
||||
removeProxyKubeconfig: di.inject(removeProxyKubeconfigInjectable, cluster),
|
||||
requestApiResources: di.inject(requestApiResourcesInjectable),
|
||||
requestNamespaceListPermissionsFor: di.inject(requestNamespaceListPermissionsForInjectable),
|
||||
createAuthorizationApi: di.inject(createAuthorizationApiInjectable),
|
||||
createCoreApi: di.inject(createCoreApiInjectable),
|
||||
createCanI: di.inject(createCanIInjectable),
|
||||
createRequestNamespaceListPermissions: di.inject(createRequestNamespaceListPermissionsInjectable),
|
||||
},
|
||||
cluster,
|
||||
),
|
||||
|
||||
@@ -8,7 +8,7 @@ import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
import kubeAuthProxyCertificateInjectable from "../kube-auth-proxy/kube-auth-proxy-certificate.injectable";
|
||||
import type { KubeAuthProxy } from "../kube-auth-proxy/kube-auth-proxy";
|
||||
import type { KubeAuthProxy } from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||
|
||||
export interface KubeAuthProxyServer {
|
||||
getApiTarget(isLongRunningRequest?: boolean): Promise<ServerOptions>;
|
||||
|
||||
@@ -7,11 +7,12 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import type { KubeApiResource } from "../../common/rbac";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import { requestApiVersionsInjectionToken } from "./request-api-versions";
|
||||
import { apiVersionsRequesterInjectionToken } from "./api-versions-requester";
|
||||
import { backoffCaller, withConcurrencyLimit } from "@k8slens/utilities";
|
||||
import requestKubeApiResourcesForInjectable from "./request-kube-api-resources-for.injectable";
|
||||
import type { AsyncResult } from "@k8slens/utilities";
|
||||
import broadcastConnectionUpdateInjectable from "./broadcast-connection-update.injectable";
|
||||
import { byOrderNumber } from "../../common/utils/composable-responsibilities/orderable/orderable";
|
||||
|
||||
export type RequestApiResources = (cluster: Cluster) => AsyncResult<KubeApiResource[], Error>;
|
||||
|
||||
@@ -24,7 +25,8 @@ const requestApiResourcesInjectable = getInjectable({
|
||||
id: "request-api-resources",
|
||||
instantiate: (di): RequestApiResources => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const apiVersionRequesters = di.injectMany(requestApiVersionsInjectionToken);
|
||||
const apiVersionRequesters = di.injectMany(apiVersionsRequesterInjectionToken)
|
||||
.sort(byOrderNumber);
|
||||
const requestKubeApiResourcesFor = di.inject(requestKubeApiResourcesForInjectable);
|
||||
|
||||
return async (...args) => {
|
||||
@@ -35,7 +37,7 @@ const requestApiResourcesInjectable = getInjectable({
|
||||
const groupLists: KubeResourceListGroup[] = [];
|
||||
|
||||
for (const apiVersionRequester of apiVersionRequesters) {
|
||||
const result = await backoffCaller(() => apiVersionRequester(cluster), {
|
||||
const result = await backoffCaller(() => apiVersionRequester.request(cluster), {
|
||||
onIntermediateError: (error, attempt) => {
|
||||
broadcastConnectionUpdate({
|
||||
message: `Failed to list kube API resource kinds, attempt ${attempt}: ${error}`,
|
||||
|
||||
@@ -5,33 +5,36 @@
|
||||
import type { V1APIVersions } from "@kubernetes/client-node";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||
import { requestApiVersionsInjectionToken } from "./request-api-versions";
|
||||
import { apiVersionsRequesterInjectionToken } from "./api-versions-requester";
|
||||
|
||||
const requestCoreApiVersionsInjectable = getInjectable({
|
||||
id: "request-core-api-versions",
|
||||
instantiate: (di) => {
|
||||
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||
|
||||
return async (cluster) => {
|
||||
try {
|
||||
const { versions } = await k8sRequest(cluster, "/api") as V1APIVersions;
|
||||
return {
|
||||
request: async (cluster) => {
|
||||
try {
|
||||
const { versions } = await k8sRequest(cluster, "/api") as V1APIVersions;
|
||||
|
||||
return {
|
||||
callWasSuccessful: true,
|
||||
response: versions.map(version => ({
|
||||
group: "",
|
||||
path: `/api/${version}`,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: error as Error,
|
||||
};
|
||||
}
|
||||
return {
|
||||
callWasSuccessful: true,
|
||||
response: versions.map(version => ({
|
||||
group: "",
|
||||
path: `/api/${version}`,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: error as Error,
|
||||
};
|
||||
}
|
||||
},
|
||||
orderNumber: 10,
|
||||
};
|
||||
},
|
||||
injectionToken: requestApiVersionsInjectionToken,
|
||||
injectionToken: apiVersionsRequesterInjectionToken,
|
||||
});
|
||||
|
||||
export default requestCoreApiVersionsInjectable;
|
||||
@@ -8,7 +8,7 @@ import type { Cluster } from "../../common/cluster/cluster";
|
||||
import type { KubeApiResource } from "../../common/rbac";
|
||||
import type { AsyncResult } from "@k8slens/utilities";
|
||||
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||
import type { KubeResourceListGroup } from "./request-api-versions";
|
||||
import type { KubeResourceListGroup } from "./api-versions-requester";
|
||||
|
||||
export type RequestKubeApiResources = (grouping: KubeResourceListGroup) => AsyncResult<KubeApiResource[], Error>;
|
||||
|
||||
|
||||
@@ -6,35 +6,40 @@ import type { V1APIGroupList } from "@kubernetes/client-node";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { iter } from "@k8slens/utilities";
|
||||
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||
import { requestApiVersionsInjectionToken } from "./request-api-versions";
|
||||
import { apiVersionsRequesterInjectionToken } from "./api-versions-requester";
|
||||
|
||||
const requestNonCoreApiVersionsInjectable = getInjectable({
|
||||
id: "request-non-core-api-versions",
|
||||
instantiate: (di) => {
|
||||
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||
|
||||
return async (cluster) => {
|
||||
try {
|
||||
const { groups } = await k8sRequest(cluster, "/apis") as V1APIGroupList;
|
||||
return {
|
||||
request: async (cluster) => {
|
||||
try {
|
||||
const { groups } = (await k8sRequest(cluster, "/apis")) as V1APIGroupList;
|
||||
|
||||
return {
|
||||
callWasSuccessful: true,
|
||||
response: iter.chain(groups.values())
|
||||
.flatMap(group => group.versions.map(version => ({
|
||||
group: group.name,
|
||||
path: `/apis/${version.groupVersion}`,
|
||||
})))
|
||||
.collect(v => [...v]),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: error as Error,
|
||||
};
|
||||
}
|
||||
return {
|
||||
callWasSuccessful: true,
|
||||
response: iter.chain(groups.values())
|
||||
.flatMap((group) =>
|
||||
group.versions.map((version) => ({
|
||||
group: group.name,
|
||||
path: `/apis/${version.groupVersion}`,
|
||||
})),
|
||||
)
|
||||
.collect((v) => [...v]),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: error as Error,
|
||||
};
|
||||
}
|
||||
},
|
||||
orderNumber: 20,
|
||||
};
|
||||
},
|
||||
injectionToken: requestApiVersionsInjectionToken,
|
||||
injectionToken: apiVersionsRequesterInjectionToken,
|
||||
});
|
||||
|
||||
export default requestNonCoreApiVersionsInjectable;
|
||||
@@ -10,13 +10,13 @@ import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
import type { K8sRequest } from "../k8s-request.injectable";
|
||||
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||
import type { RequestApiVersions } from "./request-api-versions";
|
||||
import type { ApiVersionsRequester } from "./api-versions-requester";
|
||||
import requestNonCoreApiVersionsInjectable from "./request-non-core-api-versions.injectable";
|
||||
|
||||
describe("requestNonCoreApiVersions", () => {
|
||||
let di: DiContainer;
|
||||
let k8sRequestMock: AsyncFnMock<K8sRequest>;
|
||||
let requestNonCoreApiVersions: RequestApiVersions;
|
||||
let requestNonCoreApiVersions: ApiVersionsRequester;
|
||||
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting();
|
||||
@@ -28,10 +28,10 @@ describe("requestNonCoreApiVersions", () => {
|
||||
});
|
||||
|
||||
describe("when called", () => {
|
||||
let versionsRequest: ReturnType<RequestApiVersions>;
|
||||
let versionsRequest: ReturnType<ApiVersionsRequester["request"]>;
|
||||
|
||||
beforeEach(() => {
|
||||
versionsRequest = requestNonCoreApiVersions({ id: "some-cluster-id" });
|
||||
versionsRequest = requestNonCoreApiVersions.request({ id: "some-cluster-id" });
|
||||
});
|
||||
|
||||
it("should request all api groups", () => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { KubeAuthProxyDependencies } from "./kube-auth-proxy";
|
||||
import { KubeAuthProxy } from "./kube-auth-proxy";
|
||||
import { KubeAuthProxyImpl } from "./kube-auth-proxy";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import spawnInjectable from "../child-process/spawn.injectable";
|
||||
import kubeAuthProxyCertificateInjectable from "./kube-auth-proxy-certificate.injectable";
|
||||
@@ -15,6 +15,13 @@ import getPortFromStreamInjectable from "../utils/get-port-from-stream.injectabl
|
||||
import getDirnameOfPathInjectable from "../../common/path/get-dirname.injectable";
|
||||
import broadcastConnectionUpdateInjectable from "../cluster/broadcast-connection-update.injectable";
|
||||
|
||||
export interface KubeAuthProxy {
|
||||
readonly apiPrefix: string;
|
||||
readonly port: number;
|
||||
run: () => Promise<void>;
|
||||
exit: () => void;
|
||||
}
|
||||
|
||||
export type CreateKubeAuthProxy = (cluster: Cluster, env: NodeJS.ProcessEnv) => KubeAuthProxy;
|
||||
|
||||
const createKubeAuthProxyInjectable = getInjectable({
|
||||
@@ -33,7 +40,7 @@ const createKubeAuthProxyInjectable = getInjectable({
|
||||
return (cluster, env) => {
|
||||
const clusterUrl = new URL(cluster.apiUrl.get());
|
||||
|
||||
return new KubeAuthProxy({
|
||||
return new KubeAuthProxyImpl({
|
||||
...dependencies,
|
||||
proxyCert: di.inject(kubeAuthProxyCertificateInjectable, clusterUrl.hostname),
|
||||
broadcastConnectionUpdate: di.inject(broadcastConnectionUpdateInjectable, cluster),
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { Logger } from "../../common/logger";
|
||||
import type { WaitUntilPortIsUsed } from "./wait-until-port-is-used/wait-until-port-is-used.injectable";
|
||||
import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable";
|
||||
import type { BroadcastConnectionUpdate } from "../cluster/broadcast-connection-update.injectable";
|
||||
import type { KubeAuthProxy } from "./create-kube-auth-proxy.injectable";
|
||||
|
||||
const startingServeMatcher = "starting to serve on (?<address>.+)";
|
||||
const startingServeRegex = Object.assign(TypedRegEx(startingServeMatcher, "i"), {
|
||||
@@ -33,7 +34,7 @@ export interface KubeAuthProxyDependencies {
|
||||
broadcastConnectionUpdate: BroadcastConnectionUpdate;
|
||||
}
|
||||
|
||||
export class KubeAuthProxy {
|
||||
export class KubeAuthProxyImpl implements KubeAuthProxy {
|
||||
public readonly apiPrefix = `/${randomBytes(8).toString("hex")}`;
|
||||
|
||||
public get port(): number {
|
||||
|
||||
@@ -85,7 +85,7 @@ export class KubeconfigManager {
|
||||
|
||||
return this.tempFilePath = await this.createProxyKubeconfig();
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to creat temp config for auth-proxy: ${error}`);
|
||||
throw new Error(`Failed to create temp config for auth-proxy: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user