Fix Node Number validation (#918)

Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
Daniel Valdivia
2021-08-03 09:18:51 -07:00
committed by GitHub
parent 7e4d34958e
commit fcb74aee77
4 changed files with 44 additions and 41 deletions

View File

@@ -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

View File

@@ -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
}

View File

@@ -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",

View File

@@ -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"