Skip to content

Commit a849ab8

Browse files
committed
HPA require CPU resource limit even though HPAs use requests for scaling
1 parent 64c1b3c commit a849ab8

File tree

6 files changed

+11
-117
lines changed

6 files changed

+11
-117
lines changed

frontend/packages/dev-console/locales/en/devconsole.json

+1-6
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,9 @@
328328
"Path": "Path",
329329
"argument": "argument",
330330
"The command to run inside the Container.": "The command to run inside the Container.",
331-
"CPU and memory resource limits must be set if you want to use CPU and memory utilization. The HorizontalPodAutoscaler will not have CPU or memory metrics until resource limits are set.": "CPU and memory resource limits must be set if you want to use CPU and memory utilization. The HorizontalPodAutoscaler will not have CPU or memory metrics until resource limits are set.",
331+
"CPU and memory resource requests must be set if you want to use CPU and memory utilization. The HorizontalPodAutoscaler will not have CPU or memory metrics until resource requests are set.": "CPU and memory resource requests must be set if you want to use CPU and memory utilization. The HorizontalPodAutoscaler will not have CPU or memory metrics until resource requests are set.",
332332
"CPU resource limits must be set if you want to use CPU utilization. The HorizontalPodAutoscaler will not have CPU metrics until resource limits are set.": "CPU resource limits must be set if you want to use CPU utilization. The HorizontalPodAutoscaler will not have CPU metrics until resource limits are set.",
333333
"Memory resource limits must be set if you want to use memory utilization. The HorizontalPodAutoscaler will not have memory metrics until resource limits are set.": "Memory resource limits must be set if you want to use memory utilization. The HorizontalPodAutoscaler will not have memory metrics until resource limits are set.",
334-
"Cannot create a HorizontalPodAutoscaler with no valid metrics.": "Cannot create a HorizontalPodAutoscaler with no valid metrics.",
335-
"CPU and memory utilization cannot be used currently.": "CPU and memory utilization cannot be used currently.",
336-
"CPU utilization cannot be used currently.": "CPU utilization cannot be used currently.",
337-
"Memory utilization cannot be used currently.": "Memory utilization cannot be used currently.",
338334
"Note: Some fields may not be represented in this form view. Please select \"YAML view\" for full control.": "Note: Some fields may not be represented in this form view. Please select \"YAML view\" for full control.",
339335
"Minimum Pods": "Minimum Pods",
340336
"Maximum Pods": "Maximum Pods",
@@ -354,7 +350,6 @@
354350
"Maximum Pods must be an integer.": "Maximum Pods must be an integer.",
355351
"Maximum Pods should be greater than or equal to Minimum Pods.": "Maximum Pods should be greater than or equal to Minimum Pods.",
356352
"Max Pods must be defined.": "Max Pods must be defined.",
357-
"Average utilization must be a positive number.": "Average utilization must be a positive number.",
358353
"Health checks": "Health checks",
359354
"Resource limits": "Resource limits",
360355
"Labels": "Labels",

frontend/packages/dev-console/src/components/hpa/HPADetailsForm.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const HPADetailsForm: React.FC = () => {
1515
const {
1616
setFieldValue,
1717
values: {
18-
disabledFields: { name: nameDisabled, cpuUtilization, memoryUtilization },
18+
disabledFields: { name: nameDisabled },
1919
showCanUseYAMLMessage,
2020
},
2121
} = useFormikContext<HPAFormValues>();
@@ -84,14 +84,12 @@ const HPADetailsForm: React.FC = () => {
8484
setOutputAsIntegerFlag
8585
/>
8686
<HPAUtilizationField
87-
disabled={cpuUtilization}
8887
hpa={field.value}
8988
label={t('devconsole~CPU')}
9089
onUpdate={updateField('cpu')}
9190
type="cpu"
9291
/>
9392
<HPAUtilizationField
94-
disabled={memoryUtilization}
9593
hpa={field.value}
9694
label={t('devconsole~Memory')}
9795
onUpdate={updateField('memory')}

frontend/packages/dev-console/src/components/hpa/HPAFormikForm.tsx

-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { EditorType } from '@console/shared/src/components/synced-editor/editor-
1414
import { safeYAMLToJS } from '@console/shared/src/utils/yaml';
1515
import {
1616
getFormData,
17-
getInvalidUsageError,
1817
getYAMLData,
1918
hasCustomMetrics,
2019
isCpuUtilizationPossible,
@@ -50,12 +49,6 @@ const HPAFormikForm: React.FC<HPAFormikFormProps> = ({ existingHPA, targetResour
5049
values.editorType === EditorType.YAML ? safeYAMLToJS(values.yamlData) : values.formData,
5150
);
5251

53-
const invalidUsageError = getInvalidUsageError(hpa, values);
54-
if (invalidUsageError) {
55-
helpers.setStatus({ submitError: invalidUsageError });
56-
return Promise.resolve();
57-
}
58-
5952
const method: (
6053
kind: K8sKind,
6154
data: HorizontalPodAutoscalerKind,

frontend/packages/dev-console/src/components/hpa/__tests__/hpa-utils.spec.ts

+6-44
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { cloneDeep } from 'lodash';
22
import { DeploymentKind, HorizontalPodAutoscalerKind } from '@console/internal/module/k8s';
33
import {
44
getFormData,
5-
getInvalidUsageError,
65
getLimitWarning,
76
getMetricByType,
87
getYAMLData,
@@ -12,7 +11,6 @@ import {
1211
sanitizeHPAToForm,
1312
sanityForSubmit,
1413
} from '../hpa-utils';
15-
import { HPAFormValues } from '../types';
1614
import { deploymentConfigExamples, deploymentExamples, hpaExamples } from './hpa-utils-data';
1715

1816
describe('isCpuUtilizationPossible provides accurate checks', () => {
@@ -144,30 +142,28 @@ describe('getYAMLData gets back an hpa structured editor string', () => {
144142

145143
describe('getMetricByType returns an appropriate metric and the index it is at', () => {
146144
it('expect no metrics to return a default metric as a new metric on the end', () => {
147-
const { metric, index } = getMetricByType(hpaExamples.noMetrics, 'memory');
145+
const { metric } = getMetricByType(hpaExamples.noMetrics, 'memory');
148146
expect(metric).toBeTruthy();
149147
expect(metric.resource.name).toBe('memory');
150-
expect(metric.resource.target.averageUtilization).toBe(0);
151-
expect(index).toBe(0);
148+
expect(metric.resource.target.averageUtilization).toBe(50);
152149
});
153150

154151
it('expect to get back a default memory metric when only cpu metric is available', () => {
155152
const { metric, index } = getMetricByType(hpaExamples.cpuScaled, 'memory');
156153
expect(metric).toBeTruthy();
157154
expect(metric.resource.name).toBe('memory');
158-
expect(metric.resource.target.averageUtilization).toBe(0);
155+
expect(metric.resource.target.averageUtilization).toBe(50);
159156
expect(index).toBe(1);
160157
});
161158

162159
it('expect to get back the cpu metric when it is available', () => {
163160
const hpaResource: HorizontalPodAutoscalerKind = hpaExamples.cpuScaled;
164-
const { metric, index } = getMetricByType(hpaResource, 'cpu');
161+
const { metric } = getMetricByType(hpaResource, 'cpu');
165162
expect(metric).toBeTruthy();
166163
expect(metric.resource.name).toBe('cpu');
167164
expect(metric.resource.target.averageUtilization).toBe(
168165
hpaResource.spec.metrics[0].resource.target.averageUtilization,
169166
);
170-
expect(index).toBe(0);
171167
});
172168
});
173169

@@ -234,8 +230,8 @@ describe('sanityForSubmit covers some basic field locking and trimming', () => {
234230

235231
it('expect not to have empty cpu or memory metrics', () => {
236232
const overriddenResource: HorizontalPodAutoscalerKind = cloneDeep(hpaResource);
237-
overriddenResource.spec.metrics[0].resource.target.averageUtilization = 0;
238-
expect(sanityForSubmit(deploymentResource, overriddenResource).spec.metrics.length).toBe(0);
233+
overriddenResource.spec.metrics[0].resource.target.averageUtilization = 50;
234+
expect(sanityForSubmit(deploymentResource, overriddenResource).spec.metrics.length).toBe(1);
239235
});
240236

241237
it('expect not to trim custom resource metrics', () => {
@@ -246,40 +242,6 @@ describe('sanityForSubmit covers some basic field locking and trimming', () => {
246242
});
247243
});
248244

249-
describe('getInvalidUsageError returns an error string when limits are not set', () => {
250-
const formValues: HPAFormValues = {
251-
showCanUseYAMLMessage: false,
252-
disabledFields: {
253-
name: false,
254-
cpuUtilization: true,
255-
memoryUtilization: true,
256-
},
257-
editorType: null,
258-
formData: null,
259-
yamlData: null,
260-
};
261-
const hpaResource: HorizontalPodAutoscalerKind = hpaExamples.cpuScaled;
262-
263-
it('expect no metrics to be an error', () => {
264-
const noMetricsHPA: HorizontalPodAutoscalerKind = hpaExamples.noMetrics;
265-
expect(typeof getInvalidUsageError(noMetricsHPA, formValues)).toBe('string');
266-
267-
const emptyMetricsHPA: HorizontalPodAutoscalerKind = cloneDeep(noMetricsHPA);
268-
emptyMetricsHPA.spec.metrics = [];
269-
expect(typeof getInvalidUsageError(emptyMetricsHPA, formValues)).toBe('string');
270-
});
271-
272-
it('expect cpu metric not to be allowed while disabled', () => {
273-
expect(typeof getInvalidUsageError(hpaResource, formValues)).toBe('string');
274-
});
275-
276-
it('expect memory metric to not be allowed while disabled', () => {
277-
const memoryHPA = cloneDeep(hpaResource);
278-
memoryHPA.spec.metrics[0].resource.name = 'memory';
279-
expect(typeof getInvalidUsageError(memoryHPA, formValues)).toBe('string');
280-
});
281-
});
282-
283245
describe('hasCustomMetrics accurately determines if an hpa contains non-default metrics', () => {
284246
it('expect no metrics to mean no custom metrics', () => {
285247
expect(hasCustomMetrics(null)).toBe(false);

frontend/packages/dev-console/src/components/hpa/hpa-utils.ts

+3-39
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from '@console/internal/module/k8s';
1111
import { LimitsData } from '@console/shared/src';
1212
import { safeJSToYAML, safeYAMLToJS } from '@console/shared/src/utils/yaml';
13-
import { HPAFormValues, SupportedMetricTypes } from './types';
13+
import { SupportedMetricTypes } from './types';
1414

1515
export const VALID_HPA_TARGET_KINDS = ['Deployment', 'DeploymentConfig'];
1616

@@ -31,7 +31,7 @@ export const getLimitWarning = (resource: K8sResourceKind): string => {
3131

3232
if (!limits) {
3333
return i18next.t(
34-
'devconsole~CPU and memory resource limits must be set if you want to use CPU and memory utilization. The HorizontalPodAutoscaler will not have CPU or memory metrics until resource limits are set.',
34+
'devconsole~CPU and memory resource requests must be set if you want to use CPU and memory utilization. The HorizontalPodAutoscaler will not have CPU or memory metrics until resource requests are set.',
3535
);
3636
}
3737

@@ -58,7 +58,7 @@ const getDefaultMetric = (type: SupportedMetricTypes): HPAMetric => ({
5858
resource: {
5959
name: type,
6060
target: {
61-
averageUtilization: 0,
61+
averageUtilization: 50,
6262
type: 'Utilization',
6363
},
6464
},
@@ -128,45 +128,9 @@ export const sanityForSubmit = (
128128
{ spec: { scaleTargetRef: createScaleTargetRef(targetResource) } },
129129
);
130130

131-
// Remove empty metrics
132-
validHPA.spec.metrics = validHPA.spec.metrics?.filter(
133-
(metric: HPAMetric) =>
134-
!['cpu', 'memory'].includes(metric?.resource?.name?.toLowerCase()) ||
135-
(metric.resource.target.type === 'Utilization' &&
136-
metric.resource.target.averageUtilization > 0),
137-
);
138-
139131
return validHPA;
140132
};
141133

142-
export const getInvalidUsageError = (
143-
hpa: HorizontalPodAutoscalerKind,
144-
formValues: HPAFormValues,
145-
): string => {
146-
const lackCPULimits = formValues.disabledFields.cpuUtilization;
147-
const lackMemoryLimits = formValues.disabledFields.memoryUtilization;
148-
const metricNames = (hpa.spec.metrics || []).map((metric) =>
149-
metric.resource?.name?.toLowerCase(),
150-
);
151-
const invalidCPU = lackCPULimits && metricNames.includes('cpu');
152-
const invalidMemory = lackMemoryLimits && metricNames.includes('memory');
153-
154-
if (metricNames.length === 0) {
155-
return i18next.t('devconsole~Cannot create a HorizontalPodAutoscaler with no valid metrics.');
156-
}
157-
if (invalidCPU && invalidMemory) {
158-
return i18next.t('devconsole~CPU and memory utilization cannot be used currently.');
159-
}
160-
if (invalidCPU) {
161-
return i18next.t('devconsole~CPU utilization cannot be used currently.');
162-
}
163-
if (invalidMemory) {
164-
return i18next.t('devconsole~Memory utilization cannot be used currently.');
165-
}
166-
167-
return null;
168-
};
169-
170134
export const hasCustomMetrics = (hpa?: HorizontalPodAutoscalerKind): boolean => {
171135
const metrics = hpa?.spec?.metrics;
172136
if (!metrics) {

frontend/packages/dev-console/src/components/hpa/validation-utils.ts

-18
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,6 @@ export const hpaValidationSchema = (t: TFunction) =>
5151
},
5252
)
5353
.required(t('devconsole~Max Pods must be defined.')),
54-
metrics: yup.array(
55-
yup.object({
56-
resource: yup.object({
57-
target: yup.object({
58-
averageUtilization: yup
59-
.mixed()
60-
.test(
61-
'test-for-valid-utilization',
62-
t('devconsole~Average utilization must be a positive number.'),
63-
function (avgUtilization) {
64-
if (!avgUtilization) return true;
65-
return /^\d+$/.test(String(avgUtilization));
66-
},
67-
),
68-
}),
69-
}),
70-
}),
71-
),
7254
}),
7355
}),
7456
}),

0 commit comments

Comments
 (0)