fix(app): remove duplicate validation messages [EE-5933] (#10967)

pull/10979/head
Ali 2024-01-17 16:30:30 +13:00 committed by GitHub
parent 93593e1379
commit a58b4f479b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 80 additions and 6 deletions

View File

@ -24,7 +24,7 @@ func (kcl *KubeClient) GetNodesLimits() (portainer.K8sNodesLimits, error) {
for _, item := range nodes.Items { for _, item := range nodes.Items {
cpu := item.Status.Allocatable.Cpu().MilliValue() cpu := item.Status.Allocatable.Cpu().MilliValue()
memory := item.Status.Allocatable.Memory().Value() memory := item.Status.Allocatable.Memory().Value() // bytes
nodesLimits[item.ObjectMeta.Name] = &portainer.K8sNodeLimits{ nodesLimits[item.ObjectMeta.Name] = &portainer.K8sNodeLimits{
CPU: cpu, CPU: cpu,
@ -57,7 +57,7 @@ func (client *KubeClient) GetMaxResourceLimits(skipNamespace string, overCommitE
memory := int64(0) memory := int64(0)
for _, node := range nodes.Items { for _, node := range nodes.Items {
limits.CPU += node.Status.Allocatable.Cpu().MilliValue() limits.CPU += node.Status.Allocatable.Cpu().MilliValue()
memory += node.Status.Allocatable.Memory().Value() memory += node.Status.Allocatable.Memory().Value() // bytes
} }
limits.Memory = memory / 1000000 // B to MB limits.Memory = memory / 1000000 // B to MB

View File

@ -285,7 +285,7 @@
namespace-has-quota="ctrl.state.resourcePoolHasQuota" namespace-has-quota="ctrl.state.resourcePoolHasQuota"
max-memory-limit="ctrl.state.sliders.memory.max" max-memory-limit="ctrl.state.sliders.memory.max"
max-cpu-limit="ctrl.state.sliders.cpu.max" max-cpu-limit="ctrl.state.sliders.cpu.max"
validation-data="{maxMemoryLimit: ctrl.state.sliders.memory.max, maxCpuLimit: ctrl.state.sliders.cpu.max, isEnvironmentAdmin: ctrl.isAdmin}" validation-data="{maxMemoryLimit: ctrl.state.sliders.memory.max, maxCpuLimit: ctrl.state.sliders.cpu.max, isEnvironmentAdmin: ctrl.isAdmin, nodeLimits: ctrl.nodesLimits.nodesLimits}"
resource-quota-capacity-exceeded="ctrl.resourceQuotaCapacityExceeded()" resource-quota-capacity-exceeded="ctrl.resourceQuotaCapacityExceeded()"
></resource-reservation-form-section> ></resource-reservation-form-section>

View File

@ -14,6 +14,12 @@ export function deploymentTypeValidation(
.test( .test(
'exhaused', 'exhaused',
`This application would exceed available resources. Please review resource reservations or the instance count.`, `This application would exceed available resources. Please review resource reservations or the instance count.`,
() => !validationData?.isQuotaExceeded (value) => {
// ignore this validation if the user has selected Replicated, in this case, the isQuotaExceeded will below the instance count input
if (value === 'Replicated') {
return true;
}
return !validationData?.isQuotaExceeded;
}
); );
} }

View File

@ -24,7 +24,13 @@ export function replicationValidation(
.test( .test(
'overflow', 'overflow',
'This application would exceed available resources. Please review resource reservations or the instance count.', 'This application would exceed available resources. Please review resource reservations or the instance count.',
() => !resourceReservationsOverflow // must not have resource reservations overflow (value) => {
// the user can't fix the error here with 1 replica. There are validation errors in the resource reservations section that are helpful in a case of resourceReservationsOverflow.
if (value === 1) {
return true;
}
return !resourceReservationsOverflow;
}
) )
.test( .test(
'quota', 'quota',

View File

@ -1,11 +1,21 @@
import { SchemaOf, number, object } from 'yup'; import { SchemaOf, TestContext, number, object } from 'yup';
import KubernetesResourceReservationHelper from '@/kubernetes/helpers/resourceReservationHelper';
import { ResourceQuotaFormValues } from './types'; import { ResourceQuotaFormValues } from './types';
type NodeLimit = {
CPU: number;
Memory: number;
};
type NodesLimits = Record<string, NodeLimit>;
type ValidationData = { type ValidationData = {
maxMemoryLimit: number; maxMemoryLimit: number;
maxCpuLimit: number; maxCpuLimit: number;
isEnvironmentAdmin: boolean; isEnvironmentAdmin: boolean;
nodeLimits: NodesLimits;
}; };
export function resourceReservationValidation( export function resourceReservationValidation(
@ -28,6 +38,23 @@ export function resourceReservationValidation(
({ value }) => ({ value }) =>
`Value must be between 0 and ${validationData?.maxMemoryLimit}MB now - the previous value of ${value} exceeds this` `Value must be between 0 and ${validationData?.maxMemoryLimit}MB now - the previous value of ${value} exceeds this`
) )
.test(
'hasSuitableNode',
`These reservations would exceed the resources currently available in the cluster.`,
// eslint-disable-next-line prefer-arrow-callback, func-names
function (value: number | undefined, context: TestContext) {
if (!validationData || value === undefined) {
// explicitely check for undefined, since 0 is a valid value
return true;
}
const { memoryLimit, cpuLimit } = context.parent;
return hasSuitableNode(
memoryLimit,
cpuLimit,
validationData.nodeLimits
);
}
)
.required(), .required(),
cpuLimit: number() cpuLimit: number()
.min(0) .min(0)
@ -45,6 +72,41 @@ export function resourceReservationValidation(
({ value }) => ({ value }) =>
`Value must be between 0 and ${validationData?.maxCpuLimit} now - the previous value of ${value} exceeds this` `Value must be between 0 and ${validationData?.maxCpuLimit} now - the previous value of ${value} exceeds this`
) )
.test(
'hasSuitableNode',
`These reservations would exceed the resources currently available in the cluster.`,
// eslint-disable-next-line prefer-arrow-callback, func-names
function (value: number | undefined, context: TestContext) {
if (!validationData || value === undefined) {
// explicitely check for undefined, since 0 is a valid value
return true;
}
const { memoryLimit, cpuLimit } = context.parent;
return hasSuitableNode(
memoryLimit,
cpuLimit,
validationData.nodeLimits
);
}
)
.required(), .required(),
}); });
} }
function hasSuitableNode(
memoryLimit: number,
cpuLimit: number,
nodeLimits: NodesLimits
) {
// transform the nodelimits from bytes to MB
const limits = Object.values(nodeLimits).map((nodeLimit) => ({
...nodeLimit,
Memory: KubernetesResourceReservationHelper.megaBytesValue(
nodeLimit.Memory
),
}));
// make sure there's a node available with enough memory and cpu
return limits.some(
(nodeLimit) => nodeLimit.Memory >= memoryLimit && nodeLimit.CPU >= cpuLimit
);
}