Fix Node Number validation (#918)
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
@@ -38,9 +38,10 @@ 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")
|
||||
errTooManyNodes = errors.New("cannot request more nodes than what is available in the cluster")
|
||||
errTooFewNodes = errors.New("there are not enough nodes in the cluster to support this tenant")
|
||||
errTooFewSchedulableNodes = errors.New("there is not enough schedulable nodes to satisfy this requirement")
|
||||
errFewerThanFourNodes = errors.New("at least 4 nodes are required for a tenant")
|
||||
)
|
||||
|
||||
// prepareError receives an error object and parse it against k8sErrors, returns the right error code paired with a generic error message
|
||||
|
||||
@@ -26,8 +26,6 @@ import (
|
||||
|
||||
"github.com/minio/console/cluster"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/operatorapi/operations"
|
||||
@@ -56,8 +54,9 @@ 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) {
|
||||
// can't request less than 4 nodes
|
||||
if numNodes < 4 {
|
||||
return nil, errors.New("error NumNodes must be at least 4")
|
||||
return nil, errFewerThanFourNodes
|
||||
}
|
||||
|
||||
// get all nodes from cluster
|
||||
@@ -65,16 +64,32 @@ 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++
|
||||
|
||||
// requesting more nodes than are schedulable in the cluster
|
||||
schedulableNodes := len(nodes.Items)
|
||||
nonMasterNodes := len(nodes.Items)
|
||||
for _, node := range nodes.Items {
|
||||
// check taints to check if node is schedulable
|
||||
for _, taint := range node.Spec.Taints {
|
||||
if taint.Effect == corev1.TaintEffectNoSchedule {
|
||||
schedulableNodes--
|
||||
}
|
||||
// check if the node is a master
|
||||
if taint.Key == "node-role.kubernetes.io/master" {
|
||||
nonMasterNodes--
|
||||
}
|
||||
}
|
||||
}
|
||||
if activeNodes < int(numNodes) {
|
||||
// requesting more nodes than schedulable and less than total number of workers
|
||||
if int(numNodes) > schedulableNodes && int(numNodes) < nonMasterNodes {
|
||||
return nil, errTooManyNodes
|
||||
}
|
||||
if nonMasterNodes < int(numNodes) {
|
||||
return nil, errTooFewNodes
|
||||
}
|
||||
|
||||
// not enough schedulable nodes
|
||||
if schedulableNodes < int(numNodes) {
|
||||
return nil, errTooFewSchedulableNodes
|
||||
}
|
||||
|
||||
|
||||
@@ -224,16 +224,6 @@ export const calculateDistribution = (
|
||||
};
|
||||
}
|
||||
|
||||
if (forcedNodes < 4) {
|
||||
return {
|
||||
error: "Number of nodes cannot be less than 4",
|
||||
nodes: 0,
|
||||
persistentVolumes: 0,
|
||||
disks: 0,
|
||||
pvSize: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (drivesPerServer <= 0) {
|
||||
return {
|
||||
error: "Number of drives must be at least 1",
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Fragment, useState, useEffect, useCallback } from "react";
|
||||
import React, { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import { AppState } from "../../../../../store";
|
||||
import { updateAddField, isPageValid } from "../../actions";
|
||||
import { isPageValid, updateAddField } from "../../actions";
|
||||
import {
|
||||
wizardCommon,
|
||||
modalBasic,
|
||||
wizardCommon,
|
||||
} from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Table from "@material-ui/core/Table";
|
||||
@@ -29,11 +29,11 @@ import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import {
|
||||
calculateDistribution,
|
||||
erasureCodeCalc,
|
||||
getBytes,
|
||||
k8sfactorForDropdown,
|
||||
niceBytes,
|
||||
calculateDistribution,
|
||||
erasureCodeCalc,
|
||||
setMemoryResource,
|
||||
} from "../../../../../common/utils";
|
||||
import { clearValidationError } from "../../utils";
|
||||
@@ -138,6 +138,7 @@ const TenantSize = ({
|
||||
|
||||
const getMaxAllocableMemory = (nodes: string) => {
|
||||
if (nodes !== "" && !isNaN(parseInt(nodes))) {
|
||||
setNodeError("");
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
@@ -147,10 +148,9 @@ const TenantSize = ({
|
||||
const maxMemory = res.max_memory ? res.max_memory : 0;
|
||||
updateField("maxAllocableMemo", maxMemory);
|
||||
})
|
||||
.catch((err: any) => {
|
||||
.catch((err: ErrorResponseHandler) => {
|
||||
setErrorFlag(true);
|
||||
setNodeError(err.errorMessage);
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -230,13 +230,6 @@ const TenantSize = ({
|
||||
useEffect(() => {
|
||||
const parsedSize = getBytes(volumeSize, sizeFactor, true);
|
||||
const commonValidation = commonFormValidation([
|
||||
{
|
||||
fieldKey: "nodes",
|
||||
required: true,
|
||||
value: nodes,
|
||||
customValidation: parseInt(nodes) < 4,
|
||||
customValidationMessage: "Number of nodes cannot be less than 4",
|
||||
},
|
||||
{
|
||||
fieldKey: "nodes",
|
||||
required: true,
|
||||
@@ -297,7 +290,7 @@ const TenantSize = ({
|
||||
selectedStorageClass,
|
||||
isPageValid,
|
||||
errorFlag,
|
||||
nodeError
|
||||
nodeError,
|
||||
]);
|
||||
|
||||
/* End Validation of pages */
|
||||
@@ -310,8 +303,12 @@ const TenantSize = ({
|
||||
Please select the desired capacity
|
||||
</span>
|
||||
</div>
|
||||
<span className={classes.error}>{distribution.error}</span>
|
||||
<span className={classes.error}>{memorySize.error}</span>
|
||||
{distribution.error !== "" && (
|
||||
<div className={classes.error}>{distribution.error}</div>
|
||||
)}
|
||||
{memorySize.error !== "" && (
|
||||
<div className={classes.error}>{memorySize.error}</div>
|
||||
)}
|
||||
<Grid item xs={12}>
|
||||
<InputBoxWrapper
|
||||
id="nodes"
|
||||
|
||||
Reference in New Issue
Block a user