mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
More improvements to requestApiResources
- Also move files to better places Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
9ebec670e8
commit
1841907eb8
@ -26,7 +26,7 @@ import type { Logger } from "../logger";
|
|||||||
import type { BroadcastMessage } from "../ipc/broadcast-message.injectable";
|
import type { BroadcastMessage } from "../ipc/broadcast-message.injectable";
|
||||||
import type { LoadConfigfromFile } from "../kube-helpers/load-config-from-file.injectable";
|
import type { LoadConfigfromFile } from "../kube-helpers/load-config-from-file.injectable";
|
||||||
import type { CanListResource, RequestNamespaceListPermissions, RequestNamespaceListPermissionsFor } from "./request-namespace-list-permissions.injectable";
|
import type { CanListResource, RequestNamespaceListPermissions, RequestNamespaceListPermissionsFor } from "./request-namespace-list-permissions.injectable";
|
||||||
import type { RequestApiResources } from "./request-api-resources.injectable";
|
import type { RequestApiResources } from "../../main/cluster/request-api-resources.injectable";
|
||||||
|
|
||||||
export interface ClusterDependencies {
|
export interface ClusterDependencies {
|
||||||
readonly directoryForKubeConfigs: string;
|
readonly directoryForKubeConfigs: string;
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { V1APIGroupList, V1APIResourceList, V1APIVersions } from "@kubernetes/client-node";
|
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
|
||||||
import k8SRequestInjectable from "../../main/k8s-request.injectable";
|
|
||||||
import loggerInjectable from "../logger.injectable";
|
|
||||||
import type { KubeApiResource } from "../rbac";
|
|
||||||
import type { Cluster } from "./cluster";
|
|
||||||
import plimit from "p-limit";
|
|
||||||
import { pipeline } from "../utils/iter";
|
|
||||||
|
|
||||||
export type RequestApiResources = (cluster: Cluster) => Promise<KubeApiResource[]>;
|
|
||||||
|
|
||||||
interface KubeResourceListGroup {
|
|
||||||
group: string;
|
|
||||||
path: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestApiResourcesInjectable = getInjectable({
|
|
||||||
id: "request-api-resources",
|
|
||||||
instantiate: (di): RequestApiResources => {
|
|
||||||
const k8sRequest = di.inject(k8SRequestInjectable);
|
|
||||||
const logger = di.inject(loggerInjectable);
|
|
||||||
|
|
||||||
const requestApiVersions = async (cluster: Cluster) => (await k8sRequest(cluster, "/api") as V1APIVersions).versions;
|
|
||||||
const requestApisVersions = async (cluster: Cluster) => (await k8sRequest(cluster, "/apis") as V1APIGroupList).groups;
|
|
||||||
const limitingFor = (limit: plimit.Limit) => <Args extends any[], Res>(fn: (...args: Args) => Res) => (...args: Args) => limit(() => fn(...args));
|
|
||||||
const requestKubeApiResourcesFor = (cluster: Cluster) => async ({ group, path }: KubeResourceListGroup): Promise<KubeApiResource[]> => {
|
|
||||||
const { resources } = await k8sRequest(cluster, path) as V1APIResourceList;
|
|
||||||
|
|
||||||
return resources.map(resource => ({
|
|
||||||
apiName: resource.name,
|
|
||||||
kind: resource.kind,
|
|
||||||
group,
|
|
||||||
namespaced: resource.namespaced,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
return async (cluster) => {
|
|
||||||
const requestKubeApiResources = requestKubeApiResourcesFor(cluster);
|
|
||||||
const withApiLimit = limitingFor(plimit(5));
|
|
||||||
|
|
||||||
try {
|
|
||||||
const resourceListGroups: KubeResourceListGroup[] = [
|
|
||||||
...(await requestApiVersions(cluster))
|
|
||||||
.map(version => ({
|
|
||||||
group: version,
|
|
||||||
path: `/api/${version}`,
|
|
||||||
})),
|
|
||||||
...pipeline((await requestApisVersions(cluster)).values())
|
|
||||||
.filterMap(group => group.preferredVersion?.groupVersion && ({
|
|
||||||
group: group.name,
|
|
||||||
path: `/apis/${group.preferredVersion.groupVersion}`,
|
|
||||||
})),
|
|
||||||
];
|
|
||||||
|
|
||||||
const resources = await Promise.all(
|
|
||||||
resourceListGroups
|
|
||||||
.map(withApiLimit(requestKubeApiResources)),
|
|
||||||
);
|
|
||||||
|
|
||||||
return resources.flat();
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(`[LIST-API-RESOURCES]: failed to list api resources: ${error}`);
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default requestApiResourcesInjectable;
|
|
||||||
13
src/common/utils/with-concurrency-limit.ts
Normal file
13
src/common/utils/with-concurrency-limit.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import plimit from "p-limit";
|
||||||
|
|
||||||
|
export type ConcurrencyLimiter = <Args extends any[], Res>(fn: (...args: Args) => Res) => (...args: Args) => Promise<Res>;
|
||||||
|
|
||||||
|
export function withConcurrencyLimit(limit: number): ConcurrencyLimiter {
|
||||||
|
const limiter = plimit(limit);
|
||||||
|
|
||||||
|
return fn => (...args) => limiter(() => fn(...args));
|
||||||
|
}
|
||||||
49
src/main/cluster/request-api-resources.injectable.ts
Normal file
49
src/main/cluster/request-api-resources.injectable.ts
Normal file
@ -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 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 { withConcurrencyLimit } from "../../common/utils/with-concurrency-limit";
|
||||||
|
import requestKubeApiResourcesForInjectable from "./request-kube-api-resources-for.injectable";
|
||||||
|
|
||||||
|
export type RequestApiResources = (cluster: Cluster) => Promise<KubeApiResource[]>;
|
||||||
|
|
||||||
|
export interface KubeResourceListGroup {
|
||||||
|
group: string;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestApiResourcesInjectable = getInjectable({
|
||||||
|
id: "request-api-resources",
|
||||||
|
instantiate: (di): RequestApiResources => {
|
||||||
|
const logger = di.inject(loggerInjectable);
|
||||||
|
const apiVersionRequesters = di.injectMany(requestApiVersionsInjectionToken);
|
||||||
|
const requestKubeApiResourcesFor = di.inject(requestKubeApiResourcesForInjectable);
|
||||||
|
|
||||||
|
return async (cluster) => {
|
||||||
|
const requestKubeApiResources = withConcurrencyLimit(5)(requestKubeApiResourcesFor(cluster));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const requests = await Promise.all(apiVersionRequesters.map(fn => fn(cluster)));
|
||||||
|
const resources = await Promise.all((
|
||||||
|
requests
|
||||||
|
.flat()
|
||||||
|
.map(requestKubeApiResources)
|
||||||
|
));
|
||||||
|
|
||||||
|
return resources.flat();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`[LIST-API-RESOURCES]: failed to list api resources: ${error}`);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default requestApiResourcesInjectable;
|
||||||
18
src/main/cluster/request-api-versions.ts
Normal file
18
src/main/cluster/request-api-versions.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
import type { Cluster } from "../../common/cluster/cluster";
|
||||||
|
|
||||||
|
export interface KubeResourceListGroup {
|
||||||
|
group: string;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RequestApiVersions = (cluster: Cluster) => Promise<KubeResourceListGroup[]>;
|
||||||
|
|
||||||
|
export const requestApiVersionsInjectionToken = getInjectionToken<RequestApiVersions>({
|
||||||
|
id: "request-api-versions-token",
|
||||||
|
});
|
||||||
27
src/main/cluster/request-core-api-versions.injectable.ts
Normal file
27
src/main/cluster/request-core-api-versions.injectable.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
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";
|
||||||
|
|
||||||
|
const requestCoreApiVersionsInjectable = getInjectable({
|
||||||
|
id: "request-core-api-versions",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||||
|
|
||||||
|
return async (cluster) => {
|
||||||
|
const { versions } = await k8sRequest(cluster, "/api") as V1APIVersions;
|
||||||
|
|
||||||
|
return versions.map(version => ({
|
||||||
|
group: version,
|
||||||
|
path: `/api/${version}`,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
},
|
||||||
|
injectionToken: requestApiVersionsInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default requestCoreApiVersionsInjectable;
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { V1APIResourceList } from "@kubernetes/client-node";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import type { Cluster } from "../../common/cluster/cluster";
|
||||||
|
import type { KubeApiResource } from "../../common/rbac";
|
||||||
|
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||||
|
import type { KubeResourceListGroup } from "./request-api-versions";
|
||||||
|
|
||||||
|
export type RequestKubeApiResources = (grouping: KubeResourceListGroup) => Promise<KubeApiResource[]>;
|
||||||
|
|
||||||
|
export type RequestKubeApiResourcesFor = (cluster: Cluster) => RequestKubeApiResources;
|
||||||
|
|
||||||
|
const requestKubeApiResourcesForInjectable = getInjectable({
|
||||||
|
id: "request-kube-api-resources-for",
|
||||||
|
instantiate: (di): RequestKubeApiResourcesFor => {
|
||||||
|
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||||
|
|
||||||
|
return (cluster) => async ({ group, path }) => {
|
||||||
|
const { resources } = await k8sRequest(cluster, path) as V1APIResourceList;
|
||||||
|
|
||||||
|
return resources.map(resource => ({
|
||||||
|
apiName: resource.name,
|
||||||
|
kind: resource.kind,
|
||||||
|
group,
|
||||||
|
namespaced: resource.namespaced,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default requestKubeApiResourcesForInjectable;
|
||||||
30
src/main/cluster/request-non-core-api-versions.injectable.ts
Normal file
30
src/main/cluster/request-non-core-api-versions.injectable.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { V1APIGroupList } from "@kubernetes/client-node";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { pipeline } from "../../common/utils/iter";
|
||||||
|
import k8sRequestInjectable from "../k8s-request.injectable";
|
||||||
|
import { requestApiVersionsInjectionToken } from "./request-api-versions";
|
||||||
|
|
||||||
|
const requestNonCoreApiVersionsInjectable = getInjectable({
|
||||||
|
id: "request-non-core-api-versions",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const k8sRequest = di.inject(k8sRequestInjectable);
|
||||||
|
|
||||||
|
return async (cluster) => {
|
||||||
|
const { groups } = await k8sRequest(cluster, "/apis") as V1APIGroupList;
|
||||||
|
|
||||||
|
return pipeline(groups.values())
|
||||||
|
.filterMap(group => group.preferredVersion?.groupVersion && ({
|
||||||
|
group: group.name,
|
||||||
|
path: `/apis/${group.preferredVersion.groupVersion}`,
|
||||||
|
}))
|
||||||
|
.collect(v => [...v]);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
injectionToken: requestApiVersionsInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default requestNonCoreApiVersionsInjectable;
|
||||||
@ -12,7 +12,7 @@ import createContextHandlerInjectable from "../context-handler/create-context-ha
|
|||||||
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
||||||
import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
|
import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
|
||||||
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
|
||||||
import createListApiResourcesInjectable from "../../common/cluster/request-api-resources.injectable";
|
import createListApiResourcesInjectable from "../cluster/request-api-resources.injectable";
|
||||||
import loggerInjectable from "../../common/logger.injectable";
|
import loggerInjectable from "../../common/logger.injectable";
|
||||||
import detectorRegistryInjectable from "../cluster-detectors/detector-registry.injectable";
|
import detectorRegistryInjectable from "../cluster-detectors/detector-registry.injectable";
|
||||||
import createVersionDetectorInjectable from "../cluster-detectors/create-version-detector.injectable";
|
import createVersionDetectorInjectable from "../cluster-detectors/create-version-detector.injectable";
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import lensProxyPortInjectable from "./lens-proxy/lens-proxy-port.injectable";
|
|||||||
|
|
||||||
export type K8sRequest = (cluster: Cluster, path: string, options?: RequestPromiseOptions) => Promise<any>;
|
export type K8sRequest = (cluster: Cluster, path: string, options?: RequestPromiseOptions) => Promise<any>;
|
||||||
|
|
||||||
const k8SRequestInjectable = getInjectable({
|
const k8sRequestInjectable = getInjectable({
|
||||||
id: "k8s-request",
|
id: "k8s-request",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
@ -34,4 +34,4 @@ const k8SRequestInjectable = getInjectable({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default k8SRequestInjectable;
|
export default k8sRequestInjectable;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user