mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
introducing vpa resources (#7004)
* introducing vpa resources (as hpa resources to start) vpa spec (WIP) adding real vpa fields scss files, and updates after rebase on master scss update tweaks to vpa api definition putting more fields into the vpa list adding vpa details, fixing vpa spec implementation (WIP) vpa details page done merge conflicts Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com> * moved files after monorepo merge Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com> * address review comments, added vpa endpoint to endpoints export list Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com> * deprecate HPAStore in favour of HorizontalPodAuotoscalerStore Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com> --------- Signed-off-by: Jim Ehrismann <jehrismann@mirantis.com>
This commit is contained in:
parent
e196ca56eb
commit
a8a59ff191
@ -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 verticalPodAutoscalersRouteInjectable from "./vertical-pod-autoscalers-route.injectable";
|
||||||
|
import { navigateToRouteInjectionToken } from "../../../../navigate-to-route-injection-token";
|
||||||
|
|
||||||
|
const navigateToVerticalPodAutoscalersInjectable = getInjectable({
|
||||||
|
id: "navigate-to-vertical-pod-autoscalers",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
||||||
|
const route = di.inject(verticalPodAutoscalersRouteInjectable);
|
||||||
|
|
||||||
|
return () => navigateToRoute(route);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default navigateToVerticalPodAutoscalersInjectable;
|
||||||
@ -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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
|
||||||
|
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
|
||||||
|
|
||||||
|
const verticalPodAutoscalersRouteInjectable = getInjectable({
|
||||||
|
id: "vertical-pod-autoscalers-route",
|
||||||
|
|
||||||
|
instantiate: (di) => ({
|
||||||
|
path: "/vpa",
|
||||||
|
clusterFrame: true,
|
||||||
|
isEnabled: di.inject(shouldShowResourceInjectionToken, {
|
||||||
|
apiName: "verticalpodautoscalers",
|
||||||
|
group: "autoscaling.k8s.io",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
|
||||||
|
injectionToken: frontEndRouteInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default verticalPodAutoscalersRouteInjectable;
|
||||||
@ -8,6 +8,7 @@ import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
|||||||
import { KubeApi } from "../kube-api";
|
import { KubeApi } from "../kube-api";
|
||||||
import type { BaseKubeObjectCondition, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
import type { BaseKubeObjectCondition, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
|
import type { CrossVersionObjectReference } from "./types/cross-version-object-reference";
|
||||||
|
|
||||||
export enum HpaMetricType {
|
export enum HpaMetricType {
|
||||||
Resource = "Resource",
|
Resource = "Resource",
|
||||||
@ -299,12 +300,6 @@ export type HorizontalPodAutoscalerMetricStatus =
|
|||||||
| OptionVarient<HpaMetricType.Pods, BaseHorizontalPodAutoscalerMetricStatus, "pods">
|
| OptionVarient<HpaMetricType.Pods, BaseHorizontalPodAutoscalerMetricStatus, "pods">
|
||||||
| OptionVarient<HpaMetricType.ContainerResource, BaseHorizontalPodAutoscalerMetricStatus, "containerResource">;
|
| OptionVarient<HpaMetricType.ContainerResource, BaseHorizontalPodAutoscalerMetricStatus, "containerResource">;
|
||||||
|
|
||||||
export interface CrossVersionObjectReference {
|
|
||||||
kind: string;
|
|
||||||
name: string;
|
|
||||||
apiVersion: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HorizontalPodAutoscalerSpec {
|
export interface HorizontalPodAutoscalerSpec {
|
||||||
scaleTargetRef: CrossVersionObjectReference;
|
scaleTargetRef: CrossVersionObjectReference;
|
||||||
minReplicas?: number;
|
minReplicas?: number;
|
||||||
|
|||||||
@ -44,3 +44,4 @@ export * from "./service-account.api";
|
|||||||
export * from "./stateful-set.api";
|
export * from "./stateful-set.api";
|
||||||
export * from "./storage-class.api";
|
export * from "./storage-class.api";
|
||||||
export * from "./types";
|
export * from "./types";
|
||||||
|
export * from "./vertical-pod-autoscaler.api";
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface CrossVersionObjectReference {
|
||||||
|
kind: string;
|
||||||
|
name: string;
|
||||||
|
apiVersion: string;
|
||||||
|
}
|
||||||
|
|
||||||
@ -7,6 +7,7 @@ export * from "./aggregation-rule";
|
|||||||
export * from "./capabilities";
|
export * from "./capabilities";
|
||||||
export * from "./container";
|
export * from "./container";
|
||||||
export * from "./container-port";
|
export * from "./container-port";
|
||||||
|
export * from "./cross-version-object-reference";
|
||||||
export * from "./env-from-source";
|
export * from "./env-from-source";
|
||||||
export * from "./env-source";
|
export * from "./env-source";
|
||||||
export * from "./env-var-key-selector";
|
export * from "./env-var-key-selector";
|
||||||
|
|||||||
@ -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 assert from "assert";
|
||||||
|
import { storesAndApisCanBeCreatedInjectionToken } from "../stores-apis-can-be-created.token";
|
||||||
|
import { VerticalPodAutoscalerApi } from "./vertical-pod-autoscaler.api";
|
||||||
|
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
|
||||||
|
import loggerInjectable from "../../logger.injectable";
|
||||||
|
import maybeKubeApiInjectable from "../maybe-kube-api.injectable";
|
||||||
|
|
||||||
|
const verticalPodAutoscalerApiInjectable = getInjectable({
|
||||||
|
id: "vertical-pod-autoscaler-api",
|
||||||
|
instantiate: (di) => {
|
||||||
|
assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "verticalPodAutoscalerApi is only available in certain environments");
|
||||||
|
|
||||||
|
return new VerticalPodAutoscalerApi({
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
|
maybeKubeApi: di.inject(maybeKubeApiInjectable),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeApiInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default verticalPodAutoscalerApiInjectable;
|
||||||
@ -0,0 +1,149 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { BaseKubeObjectCondition, NamespaceScopedMetadata } from "../kube-object";
|
||||||
|
import { KubeObject } from "../kube-object";
|
||||||
|
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||||
|
import { KubeApi } from "../kube-api";
|
||||||
|
import type { CrossVersionObjectReference } from "./types/cross-version-object-reference";
|
||||||
|
|
||||||
|
export enum ResourceName {
|
||||||
|
ResourceCPU = "cpu",
|
||||||
|
ResourceMemory = "memory",
|
||||||
|
ResourceStorage = "storage",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ResourceList = Partial<Record<string, string>>;
|
||||||
|
|
||||||
|
export interface RecommendedContainerResources {
|
||||||
|
containerName?: string;
|
||||||
|
target: ResourceList;
|
||||||
|
lowerBound?: ResourceList;
|
||||||
|
upperBound?: ResourceList;
|
||||||
|
uncappedTarget?: ResourceList;
|
||||||
|
}
|
||||||
|
export interface RecommendedPodResources {
|
||||||
|
containerRecommendations?: RecommendedContainerResources[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VerticalPodAutoscalerStatus {
|
||||||
|
conditions?: BaseKubeObjectCondition[];
|
||||||
|
recommendation?: RecommendedPodResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VerticalPodAutoscalerRecommenderSelector {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ContainerScalingMode {
|
||||||
|
ContainerScalingModeAuto = "Auto",
|
||||||
|
ContainerScalingModeOff = "Off",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ControlledValues {
|
||||||
|
ControlledValueRequestsAndLimits = "RequestsAndLimits",
|
||||||
|
ControlledValueRequestsOnly = "RequestsOnly",
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ContainerResourcePolicy controls how autoscaler computes the recommended resources for
|
||||||
|
* a specific container.
|
||||||
|
*/
|
||||||
|
export interface ContainerResourcePolicy {
|
||||||
|
containerName?: string;
|
||||||
|
mode?: ContainerScalingMode;
|
||||||
|
minAllowed?: ResourceList;
|
||||||
|
maxAllowed?: ResourceList;
|
||||||
|
controlledResources?: ResourceName[];
|
||||||
|
controlledValues?: ControlledValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls how the autoscaler computes recommended resources.
|
||||||
|
* The resource policy may be used to set constraints on the recommendations for individual
|
||||||
|
* containers.
|
||||||
|
* If not specified, the autoscaler computes recommended resources for all containers in the
|
||||||
|
* pod, without additional constraints.
|
||||||
|
*/
|
||||||
|
export interface PodResourcePolicy {
|
||||||
|
containerPolicies?: ContainerResourcePolicy[]; // Per-container resource policies.
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum UpdateMode {
|
||||||
|
/**
|
||||||
|
* UpdateModeOff means that autoscaler never changes Pod resources.
|
||||||
|
* The recommender still sets the recommended resources in the
|
||||||
|
* VerticalPodAutoscaler object. This can be used for a "dry run".
|
||||||
|
*/
|
||||||
|
UpdateModeOff = "Off",
|
||||||
|
/**
|
||||||
|
* UpdateModeInitial means that autoscaler only assigns resources on pod
|
||||||
|
* creation and does not change them during the lifetime of the pod.
|
||||||
|
*/
|
||||||
|
UpdateModeInitial = "Initial",
|
||||||
|
/**
|
||||||
|
* UpdateModeRecreate means that autoscaler assigns resources on pod
|
||||||
|
* creation and additionally can update them during the lifetime of the
|
||||||
|
* pod by deleting and recreating the pod.
|
||||||
|
*/
|
||||||
|
UpdateModeRecreate = "Recreate",
|
||||||
|
/**
|
||||||
|
* UpdateModeAuto means that autoscaler assigns resources on pod creation
|
||||||
|
* and additionally can update them during the lifetime of the pod,
|
||||||
|
* using any available update method. Currently this is equivalent to
|
||||||
|
* Recreate, which is the only available update method.
|
||||||
|
*/
|
||||||
|
UpdateModeAuto = "Auto",
|
||||||
|
}
|
||||||
|
export interface PodUpdatePolicy {
|
||||||
|
minReplicas?: number;
|
||||||
|
updateMode?: UpdateMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VerticalPodAutoscalerSpec {
|
||||||
|
targetRef: CrossVersionObjectReference;
|
||||||
|
updatePolicy?: PodUpdatePolicy;
|
||||||
|
resourcePolicy?: PodResourcePolicy;
|
||||||
|
recommenders?: VerticalPodAutoscalerRecommenderSelector[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VerticalPodAutoscaler extends KubeObject<
|
||||||
|
NamespaceScopedMetadata,
|
||||||
|
VerticalPodAutoscalerStatus,
|
||||||
|
VerticalPodAutoscalerSpec
|
||||||
|
> {
|
||||||
|
static readonly kind = "VerticalPodAutoscaler";
|
||||||
|
static readonly namespaced = true;
|
||||||
|
static readonly apiBase = "/apis/autoscaling.k8s.io/v1/verticalpodautoscalers";
|
||||||
|
|
||||||
|
getReadyConditions() {
|
||||||
|
return this.getConditions().filter(({ isReady }) => isReady);
|
||||||
|
}
|
||||||
|
|
||||||
|
getConditions() {
|
||||||
|
return this.status?.conditions?.map(condition => {
|
||||||
|
const { message, reason, lastTransitionTime, status } = condition;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...condition,
|
||||||
|
isReady: status === "True",
|
||||||
|
tooltip: `${message || reason || ""} (${lastTransitionTime})`,
|
||||||
|
};
|
||||||
|
}) ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getMode() {
|
||||||
|
return this.spec.updatePolicy?.updateMode ?? UpdateMode.UpdateModeAuto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VerticalPodAutoscalerApi extends KubeApi<VerticalPodAutoscaler> {
|
||||||
|
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||||
|
super(deps, {
|
||||||
|
...opts ?? {},
|
||||||
|
objectConstructor: VerticalPodAutoscaler,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@ export type KubeResource =
|
|||||||
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "leases" |
|
"namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "leases" |
|
||||||
"secrets" | "configmaps" | "ingresses" | "ingressclasses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" |
|
"secrets" | "configmaps" | "ingresses" | "ingressclasses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" |
|
||||||
"pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" |
|
"pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" |
|
||||||
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" |
|
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "verticalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" |
|
||||||
"priorityclasses" | "runtimeclasses" |
|
"priorityclasses" | "runtimeclasses" |
|
||||||
"roles" | "clusterroles" | "rolebindings" | "clusterrolebindings" | "serviceaccounts";
|
"roles" | "clusterroles" | "rolebindings" | "clusterrolebindings" | "serviceaccounts";
|
||||||
|
|
||||||
@ -206,4 +206,9 @@ export const apiResourceRecord: Record<KubeResource, KubeApiResourceData> = {
|
|||||||
group: "storage.k8s.io",
|
group: "storage.k8s.io",
|
||||||
namespaced: false,
|
namespaced: false,
|
||||||
},
|
},
|
||||||
|
verticalpodautoscalers: {
|
||||||
|
kind: "VerticalPodAutoscaler",
|
||||||
|
group: "autoscaling.k8s.io",
|
||||||
|
namespaced: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import secretApiInjectable from "../../common/k8s-api/endpoints/secret.api.injec
|
|||||||
import resourceQuotaApiInjectable from "../../common/k8s-api/endpoints/resource-quota.api.injectable";
|
import resourceQuotaApiInjectable from "../../common/k8s-api/endpoints/resource-quota.api.injectable";
|
||||||
import limitRangeApiInjectable from "../../common/k8s-api/endpoints/limit-range.api.injectable";
|
import limitRangeApiInjectable from "../../common/k8s-api/endpoints/limit-range.api.injectable";
|
||||||
import horizontalPodAutoscalerApiInjectable from "../../common/k8s-api/endpoints/horizontal-pod-autoscaler.api.injectable";
|
import horizontalPodAutoscalerApiInjectable from "../../common/k8s-api/endpoints/horizontal-pod-autoscaler.api.injectable";
|
||||||
|
import verticalPodAutoscalerApiInjectable from "../../common/k8s-api/endpoints/vertical-pod-autoscaler.api.injectable";
|
||||||
import podDisruptionBudgetApiInjectable from "../../common/k8s-api/endpoints/pod-disruption-budget.api.injectable";
|
import podDisruptionBudgetApiInjectable from "../../common/k8s-api/endpoints/pod-disruption-budget.api.injectable";
|
||||||
import priorityClassStoreApiInjectable from "../../common/k8s-api/endpoints/priority-class.api.injectable";
|
import priorityClassStoreApiInjectable from "../../common/k8s-api/endpoints/priority-class.api.injectable";
|
||||||
import serviceApiInjectable from "../../common/k8s-api/endpoints/service.api.injectable";
|
import serviceApiInjectable from "../../common/k8s-api/endpoints/service.api.injectable";
|
||||||
@ -76,6 +77,7 @@ export const resourceQuotaApi = asLegacyGlobalForExtensionApi(resourceQuotaApiIn
|
|||||||
export const limitRangeApi = asLegacyGlobalForExtensionApi(limitRangeApiInjectable);
|
export const limitRangeApi = asLegacyGlobalForExtensionApi(limitRangeApiInjectable);
|
||||||
export const serviceApi = asLegacyGlobalForExtensionApi(serviceApiInjectable);
|
export const serviceApi = asLegacyGlobalForExtensionApi(serviceApiInjectable);
|
||||||
export const hpaApi = asLegacyGlobalForExtensionApi(horizontalPodAutoscalerApiInjectable);
|
export const hpaApi = asLegacyGlobalForExtensionApi(horizontalPodAutoscalerApiInjectable);
|
||||||
|
export const vpaApi = asLegacyGlobalForExtensionApi(verticalPodAutoscalerApiInjectable);
|
||||||
export const pdbApi = asLegacyGlobalForExtensionApi(podDisruptionBudgetApiInjectable);
|
export const pdbApi = asLegacyGlobalForExtensionApi(podDisruptionBudgetApiInjectable);
|
||||||
export const pcApi = asLegacyGlobalForExtensionApi(priorityClassStoreApiInjectable);
|
export const pcApi = asLegacyGlobalForExtensionApi(priorityClassStoreApiInjectable);
|
||||||
export const endpointApi = asLegacyGlobalForExtensionApi(endpointsApiInjectable);
|
export const endpointApi = asLegacyGlobalForExtensionApi(endpointsApiInjectable);
|
||||||
@ -110,7 +112,14 @@ export type { SecretStore as SecretsStore } from "../../renderer/components/+con
|
|||||||
export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/store";
|
export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/store";
|
||||||
export type { ResourceQuotaStore as ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/store";
|
export type { ResourceQuotaStore as ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/store";
|
||||||
export type { LimitRangeStore as LimitRangesStore } from "../../renderer/components/+config-limit-ranges/store";
|
export type { LimitRangeStore as LimitRangesStore } from "../../renderer/components/+config-limit-ranges/store";
|
||||||
export type { HorizontalPodAutoscalerStore as HPAStore } from "../../renderer/components/+config-autoscalers/store";
|
export type {
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
HorizontalPodAutoscalerStore as HPAStore,
|
||||||
|
HorizontalPodAutoscalerStore,
|
||||||
|
} from "../../renderer/components/+config-horizontal-pod-autoscalers/store";
|
||||||
|
export type { VerticalPodAutoscalerStore } from "../../renderer/components/+config-vertical-pod-autoscalers/store";
|
||||||
export type { PodDisruptionBudgetStore as PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/store";
|
export type { PodDisruptionBudgetStore as PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/store";
|
||||||
export type { PriorityClassStore as PriorityClassStoreStore } from "../../renderer/components/+config-priority-classes/store";
|
export type { PriorityClassStore as PriorityClassStoreStore } from "../../renderer/components/+config-priority-classes/store";
|
||||||
export type { ServiceStore } from "../../renderer/components/+network-services/store";
|
export type { ServiceStore } from "../../renderer/components/+network-services/store";
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$vpa-status-colors: (
|
||||||
|
recommendationprovided: var(--colorOk),
|
||||||
|
lowconfidence: var(--colorInfo),
|
||||||
|
fetchinghistory: var(--colorInfo),
|
||||||
|
nopodsmatched: var(--colorInfo),
|
||||||
|
configdeprecated: var(--colorSoftError),
|
||||||
|
configunsupported: var(--colorError),
|
||||||
|
);
|
||||||
|
|
||||||
|
@mixin vpa-status-bgc {
|
||||||
|
|
||||||
|
@each $status,
|
||||||
|
$color in $vpa-status-colors {
|
||||||
|
&.#{$status} {
|
||||||
|
background: $color;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from "./vpa";
|
||||||
|
export * from "./vpa-details";
|
||||||
@ -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 assert from "assert";
|
||||||
|
import loggerInjectable from "../../../common/logger.injectable";
|
||||||
|
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/kube-object-store-token";
|
||||||
|
import verticalPodAutoscalerApiInjectable from "../../../common/k8s-api/endpoints/vertical-pod-autoscaler.api.injectable";
|
||||||
|
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
|
||||||
|
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
|
||||||
|
import { VerticalPodAutoscalerStore } from "./store";
|
||||||
|
|
||||||
|
const verticalPodAutoscalerStoreInjectable = getInjectable({
|
||||||
|
id: "vertical-pod-autoscaler-store",
|
||||||
|
instantiate: (di) => {
|
||||||
|
assert(di.inject(storesAndApisCanBeCreatedInjectable), "verticalPodAutoscalerStore is only available in certain environments");
|
||||||
|
|
||||||
|
const api = di.inject(verticalPodAutoscalerApiInjectable);
|
||||||
|
|
||||||
|
return new VerticalPodAutoscalerStore({
|
||||||
|
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
|
}, api);
|
||||||
|
},
|
||||||
|
injectionToken: kubeObjectStoreInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default verticalPodAutoscalerStoreInjectable;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
||||||
|
import type { VerticalPodAutoscaler, VerticalPodAutoscalerApi } from "../../../common/k8s-api/endpoints/vertical-pod-autoscaler.api";
|
||||||
|
|
||||||
|
export class VerticalPodAutoscalerStore extends KubeObjectStore<VerticalPodAutoscaler, VerticalPodAutoscalerApi> {
|
||||||
|
}
|
||||||
@ -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 { computed } from "mobx";
|
||||||
|
import verticalPodAutoscalersRouteInjectable from "../../../common/front-end-routing/routes/cluster/config/vertical-pod-autoscalers/vertical-pod-autoscalers-route.injectable";
|
||||||
|
import { configSidebarItemId } from "../+config/config-sidebar-items.injectable";
|
||||||
|
import type { SidebarItemRegistration } from "../layout/sidebar-items.injectable";
|
||||||
|
import { sidebarItemsInjectionToken } from "../layout/sidebar-items.injectable";
|
||||||
|
import routeIsActiveInjectable from "../../routes/route-is-active.injectable";
|
||||||
|
import navigateToVerticalPodAutoscalersInjectable from "../../../common/front-end-routing/routes/cluster/config/vertical-pod-autoscalers/navigate-to-vertical-pod-autoscalers.injectable";
|
||||||
|
|
||||||
|
const verticalPodAutoScalersSidebarItemsInjectable = getInjectable({
|
||||||
|
id: "vertical-pod-auto-scalers-sidebar-items",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const route = di.inject(verticalPodAutoscalersRouteInjectable);
|
||||||
|
const navigateToVerticalPodAutoscalers = di.inject(navigateToVerticalPodAutoscalersInjectable);
|
||||||
|
const routeIsActive = di.inject(routeIsActiveInjectable, route);
|
||||||
|
|
||||||
|
return computed((): SidebarItemRegistration[] => [
|
||||||
|
{
|
||||||
|
id: "vertical-pod-auto-scalers",
|
||||||
|
parentId: configSidebarItemId,
|
||||||
|
title: "VPA",
|
||||||
|
onClick: navigateToVerticalPodAutoscalers,
|
||||||
|
isActive: routeIsActive,
|
||||||
|
isVisible: route.isEnabled,
|
||||||
|
orderNumber: 50,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: sidebarItemsInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default verticalPodAutoScalersSidebarItemsInjectable;
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* 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 { routeSpecificComponentInjectionToken } from "../../routes/route-specific-component-injection-token";
|
||||||
|
import verticalPodAutoscalersRouteInjectable from "../../../common/front-end-routing/routes/cluster/config/vertical-pod-autoscalers/vertical-pod-autoscalers-route.injectable";
|
||||||
|
import { VerticalPodAutoscalers } from "./vpa";
|
||||||
|
|
||||||
|
const verticalPodAutoscalersRouteComponentInjectable = getInjectable({
|
||||||
|
id: "vertical-pod-autoscalers-route-component",
|
||||||
|
|
||||||
|
instantiate: (di) => ({
|
||||||
|
route: di.inject(verticalPodAutoscalersRouteInjectable),
|
||||||
|
Component: VerticalPodAutoscalers,
|
||||||
|
}),
|
||||||
|
|
||||||
|
injectionToken: routeSpecificComponentInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default verticalPodAutoscalersRouteComponentInjectable;
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import "autoscaler.mixins";
|
||||||
|
|
||||||
|
.VpaDetails {
|
||||||
|
.status {
|
||||||
|
@include vpa-status-bgc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metrics .Table {
|
||||||
|
.TableCell {
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
|
&.name {
|
||||||
|
flex-grow: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,220 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./vpa-details.scss";
|
||||||
|
|
||||||
|
import startCase from "lodash/startCase";
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { DrawerItem, DrawerTitle } from "../drawer";
|
||||||
|
import { Badge } from "../badge";
|
||||||
|
import type { KubeObjectDetailsProps } from "../kube-object-details";
|
||||||
|
import { cssNames } from "../../utils";
|
||||||
|
import { ContainerScalingMode, ControlledValues, ResourceName, UpdateMode, VerticalPodAutoscaler } from "../../../common/k8s-api/endpoints/vertical-pod-autoscaler.api";
|
||||||
|
import type { PodUpdatePolicy, PodResourcePolicy, VerticalPodAutoscalerStatus } from "../../../common/k8s-api/endpoints/vertical-pod-autoscaler.api";
|
||||||
|
import type { ApiManager } from "../../../common/k8s-api/api-manager";
|
||||||
|
import loggerInjectable from "../../../common/logger.injectable";
|
||||||
|
import type { Logger } from "../../../common/logger";
|
||||||
|
import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
|
||||||
|
import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable";
|
||||||
|
|
||||||
|
export interface VpaDetailsProps extends KubeObjectDetailsProps<VerticalPodAutoscaler> {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
apiManager: ApiManager;
|
||||||
|
getDetailsUrl: GetDetailsUrl;
|
||||||
|
logger: Logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class NonInjectedVpaDetails extends React.Component<VpaDetailsProps & Dependencies> {
|
||||||
|
renderStatus(status: VerticalPodAutoscalerStatus) {
|
||||||
|
const { recommendation } = status;
|
||||||
|
const { object: vpa } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<DrawerTitle>Status</DrawerTitle>
|
||||||
|
<DrawerItem
|
||||||
|
name="Status"
|
||||||
|
className="status"
|
||||||
|
labelsOnly
|
||||||
|
>
|
||||||
|
{vpa.getReadyConditions()
|
||||||
|
.map(({ type, tooltip, isReady }) => (
|
||||||
|
<Badge
|
||||||
|
key={type}
|
||||||
|
label={type}
|
||||||
|
tooltip={tooltip}
|
||||||
|
className={cssNames({ [type.toLowerCase()]: isReady })}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</DrawerItem>
|
||||||
|
|
||||||
|
{recommendation?.containerRecommendations && (
|
||||||
|
recommendation.containerRecommendations
|
||||||
|
.map( ({ containerName, target, lowerBound, upperBound, uncappedTarget }) => {
|
||||||
|
return (
|
||||||
|
<div key={containerName}>
|
||||||
|
<DrawerTitle>{`Container Recommendation for ${containerName}`}</DrawerTitle>
|
||||||
|
<DrawerItem name="target" >
|
||||||
|
{Object.entries(target).map(([name, value]) => (
|
||||||
|
<DrawerItem key={name} name={startCase(name)}>
|
||||||
|
{value}
|
||||||
|
</DrawerItem>
|
||||||
|
))}
|
||||||
|
</DrawerItem>
|
||||||
|
{lowerBound && (
|
||||||
|
<DrawerItem name="lowerBound" >
|
||||||
|
{Object.entries(lowerBound).map(([name, value]) => (
|
||||||
|
<DrawerItem key={name} name={startCase(name)}>
|
||||||
|
{value}
|
||||||
|
</DrawerItem>
|
||||||
|
))}
|
||||||
|
</DrawerItem>
|
||||||
|
)}
|
||||||
|
{upperBound && (
|
||||||
|
<DrawerItem name="upperBound" >
|
||||||
|
{Object.entries(upperBound).map(([name, value]) => (
|
||||||
|
<DrawerItem key={name} name={startCase(name)}>
|
||||||
|
{value}
|
||||||
|
</DrawerItem>
|
||||||
|
))}
|
||||||
|
</DrawerItem>
|
||||||
|
)}
|
||||||
|
{uncappedTarget && (
|
||||||
|
<DrawerItem name="uncappedTarget" >
|
||||||
|
{Object.entries(uncappedTarget).map(([name, value]) => (
|
||||||
|
<DrawerItem key={name} name={startCase(name)}>
|
||||||
|
{value}
|
||||||
|
</DrawerItem>
|
||||||
|
))}
|
||||||
|
</DrawerItem>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderUpdatePolicy(updatePolicy: PodUpdatePolicy) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<DrawerTitle>Update Policy</DrawerTitle>
|
||||||
|
<DrawerItem name="updateMode" >
|
||||||
|
{updatePolicy?.updateMode ?? UpdateMode.UpdateModeAuto}
|
||||||
|
</DrawerItem>
|
||||||
|
<DrawerItem name="minReplicas" >
|
||||||
|
{updatePolicy?.minReplicas}
|
||||||
|
</DrawerItem>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderResourcePolicy(resourcePolicy: PodResourcePolicy) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{resourcePolicy.containerPolicies && (
|
||||||
|
<div>
|
||||||
|
{resourcePolicy.containerPolicies
|
||||||
|
.map( ({ containerName, mode, minAllowed, maxAllowed, controlledResources, controlledValues }) => {
|
||||||
|
return (
|
||||||
|
<div key={containerName}>
|
||||||
|
<DrawerTitle>{`Container Policy for ${containerName}`}</DrawerTitle>
|
||||||
|
<DrawerItem name="mode" >
|
||||||
|
{mode ?? ContainerScalingMode.ContainerScalingModeAuto}
|
||||||
|
</DrawerItem>
|
||||||
|
{minAllowed && (
|
||||||
|
<DrawerItem name="minAllowed" >
|
||||||
|
{Object.entries(minAllowed).map(([name, value]) => (
|
||||||
|
<DrawerItem key={name} name={startCase(name)}>
|
||||||
|
{value}
|
||||||
|
</DrawerItem>
|
||||||
|
))}
|
||||||
|
</DrawerItem>
|
||||||
|
)}
|
||||||
|
{maxAllowed && (
|
||||||
|
<DrawerItem name="maxAllowed" >
|
||||||
|
{Object.entries(maxAllowed).map(([name, value]) => (
|
||||||
|
<DrawerItem key={name} name={startCase(name)}>
|
||||||
|
{value}
|
||||||
|
</DrawerItem>
|
||||||
|
))}
|
||||||
|
</DrawerItem>
|
||||||
|
)}
|
||||||
|
<DrawerItem name="controlledResources" >
|
||||||
|
{controlledResources?.length ? controlledResources.join(", ") : `${ResourceName.ResourceCPU}, ${ResourceName.ResourceMemory}`}
|
||||||
|
</DrawerItem>
|
||||||
|
<DrawerItem name="controlledValues" >
|
||||||
|
{controlledValues ?? ControlledValues.ControlledValueRequestsAndLimits}
|
||||||
|
</DrawerItem>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { object: vpa, apiManager, getDetailsUrl, logger } = this.props;
|
||||||
|
|
||||||
|
if (!vpa) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(vpa instanceof VerticalPodAutoscaler)) {
|
||||||
|
logger.error("[VpaDetails]: passed object that is not an instanceof VerticalPodAutoscaler", vpa);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { targetRef, recommenders, resourcePolicy, updatePolicy } = vpa.spec;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="VpaDetails">
|
||||||
|
<DrawerItem name="Reference">
|
||||||
|
{targetRef && (
|
||||||
|
<Link to={getDetailsUrl(apiManager.lookupApiLink(targetRef, vpa))}>
|
||||||
|
{targetRef.kind}
|
||||||
|
/
|
||||||
|
{targetRef.name}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</DrawerItem>
|
||||||
|
|
||||||
|
<DrawerItem name="Recommender">
|
||||||
|
{
|
||||||
|
/* according to the spec there can be 0 or 1 recommenders, only */
|
||||||
|
recommenders?.length ? recommenders[0].name : "default"
|
||||||
|
}
|
||||||
|
</DrawerItem>
|
||||||
|
|
||||||
|
{vpa.status && this.renderStatus(vpa.status)}
|
||||||
|
{updatePolicy && this.renderUpdatePolicy(updatePolicy)}
|
||||||
|
{resourcePolicy && this.renderResourcePolicy(resourcePolicy)}
|
||||||
|
|
||||||
|
<DrawerTitle>CRD details</DrawerTitle>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VpaDetails = withInjectables<Dependencies, VpaDetailsProps>(NonInjectedVpaDetails, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
|
apiManager: di.inject(apiManagerInjectable),
|
||||||
|
getDetailsUrl: di.inject(getDetailsUrlInjectable),
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import "autoscaler.mixins";
|
||||||
|
|
||||||
|
.VerticalPodAutoscalers {
|
||||||
|
.TableCell {
|
||||||
|
&.name {
|
||||||
|
flex: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
@include table-cell-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.metrics {
|
||||||
|
flex: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.status {
|
||||||
|
flex: 1.5;
|
||||||
|
@include table-cell-labels-offsets;
|
||||||
|
@include vpa-status-bgc;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.age {
|
||||||
|
flex: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./vpa.scss";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||||
|
import { Badge } from "../badge";
|
||||||
|
import { cssNames, prevDefault } from "../../utils";
|
||||||
|
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||||
|
import { SiblingsInTabLayout } from "../layout/siblings-in-tab-layout";
|
||||||
|
import { KubeObjectAge } from "../kube-object/age";
|
||||||
|
import type { VerticalPodAutoscalerStore } from "./store";
|
||||||
|
import type { FilterByNamespace } from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import filterByNamespaceInjectable from "../+namespaces/namespace-select-filter-model/filter-by-namespace.injectable";
|
||||||
|
import verticalPodAutoscalerStoreInjectable from "./store.injectable";
|
||||||
|
|
||||||
|
enum columnId {
|
||||||
|
name = "name",
|
||||||
|
namespace = "namespace",
|
||||||
|
mode = "mode",
|
||||||
|
age = "age",
|
||||||
|
status = "status",
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
verticalPodAutoscalerStore: VerticalPodAutoscalerStore;
|
||||||
|
filterByNamespace: FilterByNamespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class NonInjectedVerticalPodAutoscalers extends React.Component<Dependencies> {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<SiblingsInTabLayout>
|
||||||
|
<KubeObjectListLayout
|
||||||
|
isConfigurable
|
||||||
|
tableId="configuration_vpa"
|
||||||
|
className="VerticalPodAutoscalers"
|
||||||
|
store={this.props.verticalPodAutoscalerStore}
|
||||||
|
sortingCallbacks={{
|
||||||
|
[columnId.name]: vpa => vpa.getName(),
|
||||||
|
[columnId.namespace]: vpa => vpa.getNs(),
|
||||||
|
[columnId.age]: vpa => -vpa.getCreationTimestamp(),
|
||||||
|
}}
|
||||||
|
searchFilters={[
|
||||||
|
vpa => vpa.getSearchFields(),
|
||||||
|
]}
|
||||||
|
renderHeaderTitle="Vertical Pod Autoscalers"
|
||||||
|
renderTableHeader={[
|
||||||
|
{ title: "Name", className: "name", sortBy: columnId.name },
|
||||||
|
{ className: "warning", showWithColumn: columnId.name },
|
||||||
|
{ title: "Namespace", className: "namespace", sortBy: columnId.namespace, id: columnId.namespace },
|
||||||
|
{ title: "Mode", className: "mode", sortBy: columnId.mode, id: columnId.mode },
|
||||||
|
{ title: "Age", className: "age", sortBy: columnId.age, id: columnId.age },
|
||||||
|
{ title: "Status", className: "status scrollable", id: columnId.status },
|
||||||
|
]}
|
||||||
|
renderTableContents={vpa => [
|
||||||
|
vpa.getName(),
|
||||||
|
<KubeObjectStatusIcon key="icon" object={vpa} />,
|
||||||
|
<a
|
||||||
|
key="namespace"
|
||||||
|
className="filterNamespace"
|
||||||
|
onClick={prevDefault(() => this.props.filterByNamespace(vpa.getNs()))}
|
||||||
|
>
|
||||||
|
{vpa.getNs()}
|
||||||
|
</a>,
|
||||||
|
vpa.getMode(),
|
||||||
|
<KubeObjectAge key="age" object={vpa} />,
|
||||||
|
vpa.getConditions()
|
||||||
|
.filter(({ isReady }) => isReady)
|
||||||
|
.map(({ type, tooltip }) => (
|
||||||
|
<Badge
|
||||||
|
key={type}
|
||||||
|
label={type}
|
||||||
|
tooltip={tooltip}
|
||||||
|
className={cssNames(type.toLowerCase())}
|
||||||
|
expandable={false}
|
||||||
|
scrollable={true}
|
||||||
|
/>
|
||||||
|
)),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</SiblingsInTabLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VerticalPodAutoscalers = withInjectables<Dependencies>(NonInjectedVerticalPodAutoscalers, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
...props,
|
||||||
|
filterByNamespace: di.inject(filterByNamespaceInjectable),
|
||||||
|
verticalPodAutoscalerStore: di.inject(verticalPodAutoscalerStoreInjectable),
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { kubeObjectDetailItemInjectionToken } from "../kube-object-detail-item-injection-token";
|
import { kubeObjectDetailItemInjectionToken } from "../kube-object-detail-item-injection-token";
|
||||||
import { HpaDetails } from "../../../+config-autoscalers";
|
import { HpaDetails } from "../../../+config-horizontal-pod-autoscalers";
|
||||||
import { computed } from "mobx";
|
import { computed } from "mobx";
|
||||||
import { kubeObjectMatchesToKindAndApiVersion } from "../kube-object-matches-to-kind-and-api-version";
|
import { kubeObjectMatchesToKindAndApiVersion } from "../kube-object-matches-to-kind-and-api-version";
|
||||||
import currentKubeObjectInDetailsInjectable from "../../current-kube-object-in-details.injectable";
|
import currentKubeObjectInDetailsInjectable from "../../current-kube-object-in-details.injectable";
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 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 { kubeObjectDetailItemInjectionToken } from "../kube-object-detail-item-injection-token";
|
||||||
|
import { VpaDetails } from "../../../+config-vertical-pod-autoscalers";
|
||||||
|
import { computed } from "mobx";
|
||||||
|
import { kubeObjectMatchesToKindAndApiVersion } from "../kube-object-matches-to-kind-and-api-version";
|
||||||
|
import currentKubeObjectInDetailsInjectable from "../../current-kube-object-in-details.injectable";
|
||||||
|
|
||||||
|
const verticalPodAutoscalerDetailItemInjectable = getInjectable({
|
||||||
|
id: "vertical-pod-autoscaler-detail-item",
|
||||||
|
|
||||||
|
instantiate: (di) => {
|
||||||
|
const kubeObject = di.inject(currentKubeObjectInDetailsInjectable);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Component: VpaDetails,
|
||||||
|
enabled: computed(() => isVerticalPodAutoscaler(kubeObject.value.get()?.object)),
|
||||||
|
orderNumber: 10,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
injectionToken: kubeObjectDetailItemInjectionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const isVerticalPodAutoscaler = kubeObjectMatchesToKindAndApiVersion(
|
||||||
|
"VerticalPodAutoscaler",
|
||||||
|
["autoscaling.k8s.io/v1"],
|
||||||
|
);
|
||||||
|
|
||||||
|
export default verticalPodAutoscalerDetailItemInjectable;
|
||||||
@ -42,6 +42,7 @@ export const ResourceNames: Record<KubeResource, string> = {
|
|||||||
"clusterrolebindings": "Cluster Role Bindings",
|
"clusterrolebindings": "Cluster Role Bindings",
|
||||||
"clusterroles": "Cluster Roles",
|
"clusterroles": "Cluster Roles",
|
||||||
"serviceaccounts": "Service Accounts",
|
"serviceaccounts": "Service Accounts",
|
||||||
|
"verticalpodautoscalers": "Vertical Pod Autoscalers",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ResourceKindMap = object.fromEntries(
|
export const ResourceKindMap = object.fromEntries(
|
||||||
|
|||||||
@ -87,6 +87,15 @@ rules:
|
|||||||
- get
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- autoscaling.k8s.io
|
||||||
|
resources:
|
||||||
|
- verticalpodautoscalers
|
||||||
|
- verticalpodautoscalers/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- storage.k8s.io
|
- storage.k8s.io
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user