mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix getting metrics name for HPA v1 (#7011)
* Add ability for KubeApi to filter server versions Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update error message Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Show metric name is targetCPUUtilizationPercentage is used Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Testing metric names in HPA details Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Linter fixes Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> Co-authored-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
c62fcb742c
commit
9b001adb07
@ -0,0 +1,326 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<HpaDetails/> renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="HpaDetails"
|
||||
>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Reference
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
Deployment
|
||||
/
|
||||
hpav2deployment
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Min Pods
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Max Pods
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
10
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Replicas
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem status labelsOnly"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Status
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`<HpaDetails/> shows unknown metrics with lack of metric type 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="HpaDetails"
|
||||
>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Reference
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
Deployment
|
||||
/
|
||||
hpav2deployment
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Min Pods
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Max Pods
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
10
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Replicas
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem status labelsOnly"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Status
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerTitle title"
|
||||
>
|
||||
Metrics
|
||||
</div>
|
||||
<div
|
||||
class="metrics"
|
||||
>
|
||||
<div
|
||||
class="Table flex column scrollable autoSize"
|
||||
>
|
||||
<div
|
||||
class="TableHead sticky flat"
|
||||
>
|
||||
<div
|
||||
class="TableCell name"
|
||||
>
|
||||
Name
|
||||
</div>
|
||||
<div
|
||||
class="TableCell metrics"
|
||||
>
|
||||
Current / Target
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableRow"
|
||||
>
|
||||
<div
|
||||
class="TableCell name"
|
||||
>
|
||||
unknown
|
||||
</div>
|
||||
<div
|
||||
class="TableCell metrics"
|
||||
>
|
||||
unknown / unknown
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`<HpaDetails/> shows unknown metrics with with unusual type 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="HpaDetails"
|
||||
>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Reference
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
Deployment
|
||||
/
|
||||
hpav2deployment
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Min Pods
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Max Pods
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
10
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Replicas
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
>
|
||||
0
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerItem status labelsOnly"
|
||||
>
|
||||
<span
|
||||
class="name"
|
||||
>
|
||||
Status
|
||||
</span>
|
||||
<span
|
||||
class="value"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="DrawerTitle title"
|
||||
>
|
||||
Metrics
|
||||
</div>
|
||||
<div
|
||||
class="metrics"
|
||||
>
|
||||
<div
|
||||
class="Table flex column scrollable autoSize"
|
||||
>
|
||||
<div
|
||||
class="TableHead sticky flat"
|
||||
>
|
||||
<div
|
||||
class="TableCell name"
|
||||
>
|
||||
Name
|
||||
</div>
|
||||
<div
|
||||
class="TableCell metrics"
|
||||
>
|
||||
Current / Target
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="TableRow"
|
||||
>
|
||||
<div
|
||||
class="TableCell name"
|
||||
>
|
||||
unknown
|
||||
</div>
|
||||
<div
|
||||
class="TableCell metrics"
|
||||
>
|
||||
unknown / unknown
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -19,8 +19,8 @@ interface Metric extends MetricNames {
|
||||
type: HpaMetricType;
|
||||
}
|
||||
|
||||
export function getMetricName(metric: Metric): string | undefined {
|
||||
switch (metric.type) {
|
||||
export function getMetricName(metric: Metric | undefined): string | undefined {
|
||||
switch (metric?.type) {
|
||||
case HpaMetricType.Resource:
|
||||
return metric.resource?.name;
|
||||
case HpaMetricType.Pods:
|
||||
|
||||
@ -0,0 +1,392 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import React from "react";
|
||||
import { HorizontalPodAutoscaler, HpaMetricType } from "../../../common/k8s-api/endpoints";
|
||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||
import type { DiRender } from "../test-utils/renderFor";
|
||||
import { renderFor } from "../test-utils/renderFor";
|
||||
import { HpaDetails } from "./hpa-details";
|
||||
|
||||
jest.mock("react-router-dom", () => ({
|
||||
Link: ({ children }: { children: React.ReactNode }) => children,
|
||||
}));
|
||||
|
||||
const hpaV2 = {
|
||||
apiVersion: "autoscaling/v2",
|
||||
kind: "HorizontalPodAutoscaler",
|
||||
metadata: {
|
||||
name: "hpav2",
|
||||
resourceVersion: "1",
|
||||
uid: "hpav2",
|
||||
namespace: "default",
|
||||
selfLink: "/apis/autoscaling/v2/namespaces/default/horizontalpodautoscalers/hpav2",
|
||||
},
|
||||
spec: {
|
||||
maxReplicas: 10,
|
||||
scaleTargetRef: {
|
||||
kind: "Deployment",
|
||||
name: "hpav2deployment",
|
||||
apiVersion: "apps/v1",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("<HpaDetails/>", () => {
|
||||
let result: RenderResult;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
render = renderFor(di);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(hpaV2);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show metrics table if no metrics found", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(hpaV2);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.queryByTestId("hpa-metrics")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows proper metric name for autoscaling/v1", () => {
|
||||
const hpa = new HorizontalPodAutoscaler({
|
||||
apiVersion: "autoscaling/v1",
|
||||
kind: "HorizontalPodAutoscaler",
|
||||
metadata: {
|
||||
name: "hpav1",
|
||||
resourceVersion: "1",
|
||||
uid: "hpav1",
|
||||
namespace: "default",
|
||||
selfLink: "/apis/autoscaling/v1/namespaces/default/horizontalpodautoscalers/hpav1",
|
||||
},
|
||||
spec: {
|
||||
maxReplicas: 10,
|
||||
scaleTargetRef: {
|
||||
kind: "Deployment",
|
||||
name: "hpav1deployment",
|
||||
apiVersion: "apps/v1",
|
||||
},
|
||||
targetCPUUtilizationPercentage: 80,
|
||||
},
|
||||
});
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText("CPU Utilization percentage")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows proper metric name for container resource metrics", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
type: HpaMetricType.ContainerResource,
|
||||
containerResource: {
|
||||
name: "cpu",
|
||||
container: "nginx",
|
||||
target: {
|
||||
type: "Utilization",
|
||||
averageUtilization: 60,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText("Resource cpu on Pods")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows proper metric name for resource metrics", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
type: HpaMetricType.Resource,
|
||||
resource: {
|
||||
name: "cpu",
|
||||
target: {
|
||||
type: "Utilization",
|
||||
averageUtilization: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText("Resource cpu on Pods")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows proper metric name for pod metrics for hpa v2", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
type: HpaMetricType.Pods,
|
||||
pods: {
|
||||
metric: {
|
||||
name: "packets-per-second",
|
||||
},
|
||||
target: {
|
||||
type: "AverageValue",
|
||||
averageValue: "1k",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText("packets-per-second on Pods")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows proper metric name for pod metrics for hpa v2beta1", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
type: HpaMetricType.Pods,
|
||||
pods: {
|
||||
metricName: "packets-per-second",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText("packets-per-second on Pods")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows proper metric name for object metrics for hpa v2", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
type: HpaMetricType.Object,
|
||||
object: {
|
||||
metric: {
|
||||
name: "requests-per-second",
|
||||
},
|
||||
target: {
|
||||
type: "Value",
|
||||
value: "10k",
|
||||
},
|
||||
describedObject: {
|
||||
kind: "Service",
|
||||
name: "nginx",
|
||||
apiVersion: "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText(/requests-per-second/)).toHaveTextContent("requests-per-second onService/nginx");
|
||||
});
|
||||
|
||||
it("shows proper metric name for object metrics for hpa v2beta1", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
type: HpaMetricType.Object,
|
||||
object: {
|
||||
metricName: "requests-per-second",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText("requests-per-second")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows proper metric name for external metrics for hpa v2", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
type: HpaMetricType.External,
|
||||
external: {
|
||||
metric: {
|
||||
name: "queue_messages_ready",
|
||||
selector: {
|
||||
matchLabels: { queue: "worker_tasks" },
|
||||
},
|
||||
},
|
||||
target: {
|
||||
type: "AverageValue",
|
||||
averageValue: "30",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText("queue_messages_ready on {\"matchLabels\":{\"queue\":\"worker_tasks\"}}")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows proper metric name for external metrics for hpa v2beta1", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
type: HpaMetricType.External,
|
||||
external: {
|
||||
metricName: "queue_messages_ready",
|
||||
metricSelector: {
|
||||
matchLabels: { queue: "worker_tasks" },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.getByText("queue_messages_ready on {\"matchLabels\":{\"queue\":\"worker_tasks\"}}")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows unknown metrics with lack of metric type", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
// @ts-ignore
|
||||
{
|
||||
resource: {
|
||||
name: "cpu",
|
||||
target: {
|
||||
type: "Utilization",
|
||||
averageUtilization: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows unknown metrics with with unusual type", () => {
|
||||
const hpa = new HorizontalPodAutoscaler(
|
||||
{
|
||||
...hpaV2,
|
||||
spec: {
|
||||
...hpaV2.spec,
|
||||
metrics: [
|
||||
{
|
||||
// @ts-ignore
|
||||
type: "Unusual",
|
||||
resource: {
|
||||
name: "cpu",
|
||||
target: {
|
||||
type: "Utilization",
|
||||
averageUtilization: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
result = render(
|
||||
<HpaDetails object={hpa} />,
|
||||
);
|
||||
|
||||
expect(result.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@ -62,7 +62,7 @@ class NonInjectedHpaDetails extends React.Component<HpaDetailsProps & Dependenci
|
||||
const renderName = (metric: HorizontalPodAutoscalerMetricSpec) => {
|
||||
const metricName = getMetricName(metric);
|
||||
|
||||
switch (metric.type) {
|
||||
switch (metric?.type) {
|
||||
case HpaMetricType.ContainerResource:
|
||||
|
||||
// fallthrough
|
||||
@ -85,11 +85,13 @@ class NonInjectedHpaDetails extends React.Component<HpaDetailsProps & Dependenci
|
||||
}
|
||||
case HpaMetricType.External:
|
||||
return `${metricName} on ${JSON.stringify(metric.external.metricSelector ?? metric.external.metric?.selector)}`;
|
||||
default:
|
||||
return hpa.spec?.targetCPUUtilizationPercentage ? "CPU Utilization percentage" : "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<Table data-testid="hpa-metrics">
|
||||
<TableHead flat>
|
||||
<TableCell className="name">Name</TableCell>
|
||||
<TableCell className="metrics">Current / Target</TableCell>
|
||||
@ -162,10 +164,14 @@ class NonInjectedHpaDetails extends React.Component<HpaDetailsProps & Dependenci
|
||||
))}
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerTitle>Metrics</DrawerTitle>
|
||||
<div className="metrics">
|
||||
{this.renderMetrics()}
|
||||
</div>
|
||||
{(hpa.getMetrics().length !== 0 || hpa.spec?.targetCPUUtilizationPercentage) && (
|
||||
<>
|
||||
<DrawerTitle>Metrics</DrawerTitle>
|
||||
<div className="metrics">
|
||||
{this.renderMetrics()}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user