1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Convert status injectables to be for a Map instead of object

- Allows us to use the data during further computations instead
  of doing it all again
- Large speed wins

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-03-09 15:03:18 -05:00
parent e3cdcdc826
commit 3686fa24e0
10 changed files with 101 additions and 89 deletions

View File

@ -4,16 +4,16 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import computeStatusCountsForOwnersInjectable from "../../utils/compute-status-counts.injectable";
import computeStatusesOfObjectsBasedOnOwnedPodsInjectable from "../../utils/compute-status-counts.injectable";
import daemonSetStoreInjectable from "./store.injectable";
const totalStatusesForDaemonSetsInSelectedNamespacesInjectable = getInjectable({
id: "total-statuses-for-daemon-sets-in-selected-namespaces",
instantiate: (di) => {
const daemonSetStore = di.inject(daemonSetStoreInjectable);
const computeStatusCountsForOwners = di.inject(computeStatusCountsForOwnersInjectable);
const computeStatusesOfObjectsBasedOnOwnedPods = di.inject(computeStatusesOfObjectsBasedOnOwnedPodsInjectable);
return computed(() => computeStatusCountsForOwners(daemonSetStore.contextItems));
return computed(() => computeStatusesOfObjectsBasedOnOwnedPods(daemonSetStore.contextItems));
},
});

View File

@ -4,48 +4,19 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import podStoreInjectable from "../+workloads-pods/store.injectable";
import type { Deployment, PodStatusPhase } from "../../../common/k8s-api/endpoints";
import { byLabels } from "../../../common/k8s-api/kube-object.store";
import { getOrInsert } from "../../utils";
import { foldPodStatusPhase } from "../../utils/fold-pod-status-phase";
import statusesOfReplicaSetsByOwnerIdsInSelectedNamespacesInjectable from "../+workloads-replicasets/statuses-by-owner-id.injectable";
import deploymentStoreInjectable from "./store.injectable";
const statusCountsForAllDeploymentsInSelectedNamespacesInjectable = getInjectable({
id: "status-counts-for-all-deployments-in-selected-namespaces",
instantiate: (di) => {
const deploymentStore = di.inject(deploymentStoreInjectable);
const podStore = di.inject(podStoreInjectable);
const replicaSetStatuses = di.inject(statusesOfReplicaSetsByOwnerIdsInSelectedNamespacesInjectable);
return computed(() => {
const statuses = { running: 0, failed: 0, pending: 0 };
const podsByNamespace = new Map<string, { metadata: { labels: Partial<Record<string, string>> }; status: PodStatusPhase }[]>();
for (const pod of podStore.items) {
getOrInsert(podsByNamespace, pod.getNs(), []).push({
metadata: {
labels: JSON.parse(JSON.stringify(pod.metadata.labels ?? {})),
},
status: pod.getStatus(),
});
}
const getChildPods = (deployment: Deployment) => {
const pods = podsByNamespace.get(deployment.getNs()) ?? [];
return pods.filter(byLabels(deployment.spec.template.metadata.labels));
};
for (const deployment of deploymentStore.contextItems) {
const status = getChildPods(deployment)
.map(pod => pod.status)
.reduce(foldPodStatusPhase, "running");
statuses[status]++;
}
return statuses;
});
return computed(() => new Map(deploymentStore.contextItems.map(deployment => [
deployment.getId(),
replicaSetStatuses.get().get(deployment.getId()) ?? [],
])));
},
});

View File

@ -4,16 +4,16 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import computeStatusCountsForOwnersInjectable from "../../utils/compute-status-counts.injectable";
import computeStatusesOfObjectsBasedOnOwnedPodsInjectable from "../../utils/compute-status-counts.injectable";
import jobStoreInjectable from "./store.injectable";
const statusCountsForAllJobsInSelectedNamespacesInjectable = getInjectable({
id: "status-counts-for-all-jobs-in-selected-namespaces",
instantiate: (di) => {
const jobStore = di.inject(jobStoreInjectable);
const computeStatusCountsForOwners = di.inject(computeStatusCountsForOwnersInjectable);
const computeStatusesOfObjectsBasedOnOwnedPods = di.inject(computeStatusesOfObjectsBasedOnOwnedPodsInjectable);
return computed(() => computeStatusCountsForOwners(jobStore.contextItems));
return computed(() => computeStatusesOfObjectsBasedOnOwnedPods(jobStore.contextItems));
},
});

View File

@ -10,17 +10,20 @@ import capitalize from "lodash/capitalize";
import { observer } from "mobx-react";
import type { PieChartData } from "../chart";
import { PieChart } from "../chart";
import { object } from "../../utils";
import { iter, object } from "../../utils";
import type { LensTheme } from "../../themes/lens-theme";
import { withInjectables } from "@ogre-tools/injectable-react";
import type { PascalCase } from "type-fest";
import type { IComputedValue } from "mobx";
import activeThemeInjectable from "../../themes/active.injectable";
import type { Workload } from "./workloads/workload-injection-token";
import { foldWorkloadStatusPhase } from "../../utils/fold-workload-status-phase";
export type LowercaseOrPascalCase<T extends string> = Lowercase<T> | PascalCase<T>;
export type WorkloadStatus = Partial<Record<LowercaseOrPascalCase<keyof typeof statusBackgroundColorMapping>, number>>;
export type WorkloadStatusCounts = Partial<Record<LowercaseOrPascalCase<WorkloadStatus>, number>>;
export type WorkloadStatus = keyof typeof backgroundColourMapping;
function toLowercase<T extends string>(src: T): Lowercase<T> {
return src.toLowerCase() as Lowercase<T>;
@ -34,18 +37,24 @@ interface Dependencies {
activeTheme: IComputedValue<LensTheme>;
}
const statusBackgroundColorMapping = {
"running": "colorOk",
"scheduled": "colorOk",
"pending": "colorWarning",
const cronJobStatusBackgroundColourMapping = {
"suspended": "colorWarning",
"evicted": "colorError",
"succeeded": "colorSuccess",
"scheduled": "colorOk",
} as const;
const podStatusBackgroundColourMapping = {
"failed": "colorError",
"evicted": "colorError",
"pending": "colorWarning",
"running": "colorOk",
"succeeded": "colorSuccess",
"terminated": "colorTerminated",
"terminating": "colorTerminated",
"unknown": "colorVague",
"complete": "colorSuccess",
} as const;
const backgroundColourMapping = {
...podStatusBackgroundColourMapping,
...cronJobStatusBackgroundColourMapping,
} as const;
const NonInjectedOverviewWorkloadStatus = observer((props: OverviewWorkloadStatusProps & Dependencies) => {
@ -54,7 +63,12 @@ const NonInjectedOverviewWorkloadStatus = observer((props: OverviewWorkloadStatu
activeTheme,
} = props;
const statusesToBeShown = object.entries(workload.status.get()).filter(([, val]) => val > 0);
const statuses = workload.status.get();
const statusCounts = iter.chain(statuses.values())
.map(phases => phases.reduce(foldWorkloadStatusPhase, "unknown"))
.count();
const statusesToBeShown = object.entries(statusCounts).filter(([, val]) => val > 0);
const theme = activeTheme.get();
const emptyDataSet = {
@ -66,7 +80,7 @@ const NonInjectedOverviewWorkloadStatus = observer((props: OverviewWorkloadStatu
label: "Status",
data: statusesToBeShown.map(([, value]) => value),
backgroundColor: statusesToBeShown.map(([status]) => (
theme.colors[statusBackgroundColorMapping[toLowercase(status)]]
theme.colors[backgroundColourMapping[toLowercase(status)]]
)),
tooltipLabels: statusesToBeShown.map(([status]) => (
(percent: string) => `${capitalize(status)}: ${percent}`

View File

@ -5,13 +5,22 @@
import { getInjectionToken } from "@ogre-tools/injectable";
import type { IComputedValue } from "mobx";
import type { KubeApiResourceDescriptor } from "../../../../common/rbac";
import type { WorkloadStatus } from "../overview-workload-status";
export type WorkloadStatusPhase =
"Terminated"
| "Failed"
| "Pending"
| "Running"
| "Succeeded"
| "Evicted"
| "Suspended"
| "Scheduled";
export interface Workload {
resource: KubeApiResourceDescriptor;
open: () => void;
amountOfItems: IComputedValue<number>;
status: IComputedValue<WorkloadStatus>;
status: IComputedValue<Map<string, WorkloadStatusPhase[]>>;
title: string;
orderNumber: number;
}

View File

@ -11,7 +11,10 @@ const totalStatusesForPodsInSelectedNamespacesInjectable = getInjectable({
instantiate: (di) => {
const podStore = di.inject(podStoreInjectable);
return computed(() => podStore.getStatuses(podStore.contextItems));
return computed(() => new Map(podStore.contextItems.map(pod => [
pod.getId(),
[pod.getStatus()],
])));
},
});

View File

@ -0,0 +1,32 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import type { PodStatusPhase } from "../../../common/k8s-api/endpoints";
import { getOrInsert } from "../../utils";
import statusCountsForAllReplicaSetsInSelectedNamespacesInjectable from "./statuses.injectable";
import replicaSetStoreInjectable from "./store.injectable";
const statusesOfReplicaSetsByOwnerIdsInSelectedNamespacesInjectable = getInjectable({
id: "statuses-of-replica-sets-by-owner-ids-in-selected-namespaces",
instantiate: (di) => {
const replicaSetStore = di.inject(replicaSetStoreInjectable);
const statuses = di.inject(statusCountsForAllReplicaSetsInSelectedNamespacesInjectable);
return computed(() => {
const result = new Map<string, PodStatusPhase[]>();
for (const replicaSet of replicaSetStore.contextItems) {
for (const ownerRef of replicaSet.getOwnerRefs()) {
getOrInsert(result, ownerRef.uid, []).push(...statuses.get().get(replicaSet.getId()) ?? []);
}
}
return result;
});
},
});
export default statusesOfReplicaSetsByOwnerIdsInSelectedNamespacesInjectable;

View File

@ -5,16 +5,16 @@
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import computeStatusCountsForOwnersInjectable from "../../utils/compute-status-counts.injectable";
import computeStatusesOfObjectsBasedOnOwnedPodsInjectable from "../../utils/compute-status-counts.injectable";
import replicaSetStoreInjectable from "./store.injectable";
const statusCountsForAllReplicaSetsInSelectedNamespacesInjectable = getInjectable({
id: "status-counts-for-all-replica-sets-in-selected-namespaces",
instantiate: (di) => {
const replicaSetStore = di.inject(replicaSetStoreInjectable);
const computeStatusCountsForOwners = di.inject(computeStatusCountsForOwnersInjectable);
const computeStatusesOfObjectsBasedOnOwnedPods = di.inject(computeStatusesOfObjectsBasedOnOwnedPodsInjectable);
return computed(() => computeStatusCountsForOwners(replicaSetStore.contextItems));
return computed(() => computeStatusesOfObjectsBasedOnOwnedPods(replicaSetStore.contextItems));
},
});

View File

@ -4,16 +4,16 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import computeStatusCountsForOwnersInjectable from "../../utils/compute-status-counts.injectable";
import computeStatusesOfObjectsBasedOnOwnedPodsInjectable from "../../utils/compute-status-counts.injectable";
import statefulSetStoreInjectable from "./store.injectable";
const totalStatusesForStatefulSetsInSelectedNamespacesInjectable = getInjectable({
id: "total-statuses-for-stateful-sets-in-selected-namespaces",
instantiate: (di) => {
const statefulSetStore = di.inject(statefulSetStoreInjectable);
const computeStatusCountsForOwners = di.inject(computeStatusCountsForOwnersInjectable);
const computeStatusesOfObjectsBasedOnOwnedPods = di.inject(computeStatusesOfObjectsBasedOnOwnedPodsInjectable);
return computed(() => computeStatusCountsForOwners(statefulSetStore.contextItems));
return computed(() => computeStatusesOfObjectsBasedOnOwnedPods(statefulSetStore.contextItems));
},
});

View File

@ -5,52 +5,35 @@
import type { PodStatusPhase } from "../../common/k8s-api/endpoints";
import { getOrInsert } from "../../common/utils";
import { foldPodStatusPhase } from "./fold-pod-status-phase";
import { getInjectable } from "@ogre-tools/injectable";
import podStoreInjectable from "../components/+workloads-pods/store.injectable";
import { computed } from "mobx";
import type { KubeObject } from "../../common/k8s-api/kube-object";
export interface StatusCounts {
running: number;
failed: number;
pending: number;
}
const computeStatusCountsForOwnersInjectable = getInjectable({
id: "compute-status-counts-for-owners",
const computeStatusesOfObjectsBasedOnOwnedPodsInjectable = getInjectable({
id: "compute-statuses-of-objects-based-on-owned-pods",
instantiate: (di) => {
const podStore = di.inject(podStoreInjectable);
const podsByOwnerId = computed(() => {
const podsByOwnerId = new Map<string, ({ status: PodStatusPhase })[]>();
const podStatusesByOwnerId = computed(() => {
const podsByOwnerId = new Map<string, PodStatusPhase[]>();
for (const pod of podStore.contextItems) {
for (const ownerRef of pod.getOwnerRefs()) {
getOrInsert(podsByOwnerId, ownerRef.uid, []).push({
status: pod.getStatus(),
});
getOrInsert(podsByOwnerId, ownerRef.uid, []).push(pod.getStatus());
}
}
return podsByOwnerId;
});
return (possibleOwners: KubeObject[]): StatusCounts => {
const statuses = { running: 0, failed: 0, pending: 0 };
return (owners: KubeObject[]) => new Map(owners.map(owner => {
const statuses = podStatusesByOwnerId.get().get(owner.getId()) ?? [];
for (const possibleOwner of possibleOwners) {
const status = (podsByOwnerId.get().get(possibleOwner.getId()) ?? [])
.map(pod => pod.status)
.reduce(foldPodStatusPhase, "running");
statuses[status]++;
}
return statuses;
};
return [owner.getId(), statuses];
}));
},
});
export default computeStatusCountsForOwnersInjectable;
export default computeStatusesOfObjectsBasedOnOwnedPodsInjectable;