diff --git a/operatorapi/error.go b/operatorapi/error.go index 50ef7b4f8..db10ec24e 100644 --- a/operatorapi/error.go +++ b/operatorapi/error.go @@ -38,6 +38,9 @@ var ( errLicenseNotFound = errors.New("license not found") errAvoidSelfAccountDelete = errors.New("logged in user cannot be deleted by itself") errAccessDenied = errors.New("access denied") + errTooFewNodes = errors.New("at least 4 nodes are required in cluster") + errTooFewSchedulableNodes = errors.New("at least 4 schedulable nodes are required in cluster") + errFewerThanFourNodes = errors.New("at least 4 nodes are required in request") ) // prepareError receives an error object and parse it against k8sErrors, returns the right error code paired with a generic error message @@ -156,6 +159,18 @@ func prepareError(err ...error) *models.Error { if errors.Is(err[0], errRemoteTierExists) { errorMessage = err[0].Error() } + if errors.Is(err[0], errTooFewNodes) { + errorCode = 507 + errorMessage = errTooFewNodes.Error() + } + if errors.Is(err[0], errTooFewSchedulableNodes) { + errorCode = 507 + errorMessage = errTooFewSchedulableNodes.Error() + } + if errors.Is(err[0], errFewerThanFourNodes) { + errorCode = 507 + errorMessage = errFewerThanFourNodes.Error() + } } return &models.Error{Code: errorCode, Message: swag.String(errorMessage), DetailedMessage: swag.String(err[0].Error())} } diff --git a/operatorapi/operator_nodes.go b/operatorapi/operator_nodes.go index 3c0239520..5d02e1f1f 100644 --- a/operatorapi/operator_nodes.go +++ b/operatorapi/operator_nodes.go @@ -56,8 +56,8 @@ func registerNodesHandlers(api *operations.OperatorAPI) { // getMaxAllocatableMemory get max allocatable memory given a desired number of nodes func getMaxAllocatableMemory(ctx context.Context, clientset v1.CoreV1Interface, numNodes int32) (*models.MaxAllocatableMemResponse, error) { - if numNodes == 0 { - return nil, errors.New("error NumNodes must be greated than 0") + if numNodes < 4 { + return nil, errors.New("error NumNodes must be at least 4") } // get all nodes from cluster @@ -65,6 +65,18 @@ func getMaxAllocatableMemory(ctx context.Context, clientset v1.CoreV1Interface, if err != nil { return nil, err } + if len(nodes.Items) < int(numNodes) { + return nil, errTooFewNodes + } + activeNodes := 0 + for i := 0; i < len(nodes.Items); i++ { + if !nodes.Items[i].Spec.Unschedulable { + activeNodes++ + } + } + if activeNodes < int(numNodes) { + return nil, errTooFewSchedulableNodes + } availableMemSizes := []int64{} OUTER: diff --git a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/TenantSize.tsx b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/TenantSize.tsx index 11bbbc19a..5aadcc5fe 100644 --- a/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/TenantSize.tsx +++ b/portal-ui/src/screens/Console/Tenants/AddTenant/Steps/TenantSize.tsx @@ -100,6 +100,8 @@ const TenantSize = ({ selectedStorageClass, }: ITenantSizeProps) => { const [validationErrors, setValidationErrors] = useState({}); + const [errorFlag, setErrorFlag] = useState(false); + const [nodeError, setNodeError] = useState(""); const usableInformation = ecParityCalc.storageFactors.find( (element) => element.erasureCode === ecParity ); @@ -131,7 +133,6 @@ const TenantSize = ({ clusterSizeFactor ); const memoSize = setMemoryResource(memSize, clusterSizeBytes, maxMemSize); - updateField("memorySize", memoSize); }, [maxAllocableMemo, memoryNode, sizeFactor, updateField, volumeSize]); @@ -146,8 +147,9 @@ const TenantSize = ({ const maxMemory = res.max_memory ? res.max_memory : 0; updateField("maxAllocableMemo", maxMemory); }) - .catch((err: ErrorResponseHandler) => { - updateField("maxAllocableMemo", 0); + .catch((err: any) => { + setErrorFlag(true); + setNodeError(err.errorMessage); console.error(err); }); } @@ -227,7 +229,6 @@ const TenantSize = ({ useEffect(() => { const parsedSize = getBytes(volumeSize, sizeFactor, true); - const commonValidation = commonFormValidation([ { fieldKey: "nodes", @@ -236,6 +237,13 @@ const TenantSize = ({ customValidation: parseInt(nodes) < 4, customValidationMessage: "Number of nodes cannot be less than 4", }, + { + fieldKey: "nodes", + required: true, + value: nodes, + customValidation: errorFlag, + customValidationMessage: nodeError, + }, { fieldKey: "volume_size", required: true, @@ -288,6 +296,8 @@ const TenantSize = ({ limitSize, selectedStorageClass, isPageValid, + errorFlag, + nodeError ]); /* End Validation of pages */