Added initial AWS Marketplace support to operator console (#1347)
* Added initial AWS Marketplace support to operator console Signed-off-by: Benjamin Perez <benjamin@bexsoft.net> * Renamed interface * Removed resources request in tenant request. * Destructured map state in Tenant Size * Resource Validations Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> * Removed ecparity set default option Co-authored-by: Benjamin Perez <benjamin@bexsoft.net> Co-authored-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
This commit is contained in:
@@ -37,6 +37,9 @@ import (
|
||||
// swagger:model operatorSessionResponse
|
||||
type OperatorSessionResponse struct {
|
||||
|
||||
// features
|
||||
Features []string `json:"features"`
|
||||
|
||||
// operator
|
||||
Operator bool `json:"operator,omitempty"`
|
||||
|
||||
|
||||
@@ -65,3 +65,8 @@ func getK8sSAToken() string {
|
||||
}
|
||||
return string(dat)
|
||||
}
|
||||
|
||||
// Marketplace Mode Token
|
||||
func getMPMode() string {
|
||||
return env.Get(ConsoleMPMode, "")
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ const (
|
||||
ConsoleSubnetLicense = "CONSOLE_SUBNET_LICENSE"
|
||||
ConsoleOperatorSAToken = "CONSOLE_OPERATOR_SA_TOKEN"
|
||||
MinIOSubnetLicense = "MINIO_SUBNET_LICENSE"
|
||||
ConsoleMPMode = "CONSOLE_OPERATOR_MARKETPLACE"
|
||||
|
||||
// Constants for prometheus annotations
|
||||
prometheusPath = "prometheus.io/path"
|
||||
|
||||
@@ -2361,6 +2361,12 @@ func init() {
|
||||
"operatorSessionResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"features": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"operator": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -6230,6 +6236,12 @@ func init() {
|
||||
"operatorSessionResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"features": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"operator": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package operatorapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/operatorapi/operations"
|
||||
@@ -44,6 +46,19 @@ func getSessionResponse(session *models.Principal) (*models.OperatorSessionRespo
|
||||
Status: models.OperatorSessionResponseStatusOk,
|
||||
Operator: true,
|
||||
Permissions: map[string][]string{},
|
||||
Features: getListOfOperatorFeatures(),
|
||||
}
|
||||
return sessionResp, nil
|
||||
}
|
||||
|
||||
// getListOfEnabledFeatures returns a list of features
|
||||
func getListOfOperatorFeatures() []string {
|
||||
features := []string{}
|
||||
mpEnabled := getMPMode()
|
||||
|
||||
if mpEnabled != "" {
|
||||
features = append(features, fmt.Sprintf("mp-mode-%s", mpEnabled))
|
||||
}
|
||||
|
||||
return features
|
||||
}
|
||||
|
||||
@@ -1257,9 +1257,6 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
if tenantReq.LogSearchConfiguration.StorageClass != "" {
|
||||
logSearchStorageClass = tenantReq.LogSearchConfiguration.StorageClass
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.StorageClass == "" && len(tenantReq.Pools) > 0 {
|
||||
logSearchStorageClass = tenantReq.Pools[0].VolumeConfiguration.StorageClassName
|
||||
}
|
||||
if tenantReq.LogSearchConfiguration.Image != "" {
|
||||
logSearchImage = tenantReq.LogSearchConfiguration.Image
|
||||
}
|
||||
@@ -1346,12 +1343,6 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
if tenantReq.PrometheusConfiguration.StorageClass != "" {
|
||||
prometheusStorageClass = tenantReq.PrometheusConfiguration.StorageClass
|
||||
}
|
||||
|
||||
// Default class name for prometheus
|
||||
if tenantReq.PrometheusConfiguration.StorageClass == "" && len(tenantReq.Pools) > 0 {
|
||||
prometheusStorageClass = tenantReq.Pools[0].VolumeConfiguration.StorageClassName
|
||||
}
|
||||
|
||||
if tenantReq.PrometheusConfiguration.Image != "" {
|
||||
prometheusImage = tenantReq.PrometheusConfiguration.Image
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ test("From value and unit to a number of bytes for kubernetes", () => {
|
||||
expect(getBytes("1", "Ki", true)).toBe("1024");
|
||||
expect(getBytes("1", "Mi", true)).toBe("1048576");
|
||||
expect(getBytes("1", "Gi", true)).toBe("1073741824");
|
||||
expect(getBytes("7500", "Gi", true)).toBe("8053063680000");
|
||||
});
|
||||
|
||||
test("Determine the amount of memory to use", () => {
|
||||
|
||||
@@ -147,18 +147,18 @@ export interface ITolerationSeconds {
|
||||
}
|
||||
|
||||
export interface IResourceModel {
|
||||
requests: IResourceRequests;
|
||||
requests?: IResourceRequests;
|
||||
limits?: IResourceLimits;
|
||||
}
|
||||
|
||||
export interface IResourceRequests {
|
||||
memory: number;
|
||||
cpu: number;
|
||||
memory?: number;
|
||||
cpu?: number;
|
||||
}
|
||||
|
||||
export interface IResourceLimits {
|
||||
memory: number;
|
||||
cpu: number;
|
||||
memory?: number;
|
||||
cpu?: number;
|
||||
}
|
||||
|
||||
export interface ITLSTenantConfiguration {
|
||||
@@ -272,7 +272,7 @@ export interface IActiveDirectoryConfiguration {
|
||||
}
|
||||
|
||||
export interface IStorageDistribution {
|
||||
error: number;
|
||||
error: number | string;
|
||||
nodes: number;
|
||||
persistentVolumes: number;
|
||||
disks: number;
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import storage from "local-storage-fallback";
|
||||
import get from "lodash/get";
|
||||
import { ICapacity, IErasureCodeCalc, IStorageFactors } from "./types";
|
||||
import {
|
||||
ICapacity,
|
||||
IErasureCodeCalc,
|
||||
IStorageDistribution,
|
||||
IStorageFactors,
|
||||
} from "./types";
|
||||
import { IPool } from "../screens/Console/Tenants/ListTenants/types";
|
||||
import { AllocableResourcesResponse } from "../screens/Console/Tenants/types";
|
||||
|
||||
const minStReq = 1073741824; // Minimal Space required for MinIO
|
||||
const minMemReq = 2147483648; // Minimal Memory required for MinIO in bytes
|
||||
@@ -199,8 +202,7 @@ export const calculateDistribution = (
|
||||
forcedNodes: number = 0,
|
||||
limitSize: number = 0,
|
||||
drivesPerServer: number = 0
|
||||
) => {
|
||||
let numberOfNodes = {};
|
||||
): IStorageDistribution => {
|
||||
const requestedSizeBytes = getBytes(
|
||||
capacityToUse.value,
|
||||
capacityToUse.unit,
|
||||
@@ -227,7 +229,7 @@ export const calculateDistribution = (
|
||||
};
|
||||
}
|
||||
|
||||
numberOfNodes = calculateStorage(
|
||||
let numberOfNodes = calculateStorage(
|
||||
requestedSizeBytes,
|
||||
forcedNodes,
|
||||
limitSize,
|
||||
@@ -242,7 +244,7 @@ const calculateStorage = (
|
||||
forcedNodes: number,
|
||||
limitSize: number,
|
||||
drivesPerServer: number
|
||||
) => {
|
||||
): IStorageDistribution => {
|
||||
// Size validation
|
||||
const intReqBytes = parseInt(requestedBytes, 10);
|
||||
const maxDiskSize = minStReq * 256; // 256 GiB
|
||||
@@ -263,7 +265,7 @@ const structureCalc = (
|
||||
maxDiskSize: number,
|
||||
maxClusterSize: number,
|
||||
disksPerNode: number = 0
|
||||
) => {
|
||||
): IStorageDistribution => {
|
||||
if (
|
||||
isNaN(nodes) ||
|
||||
isNaN(desiredCapacity) ||
|
||||
@@ -275,7 +277,7 @@ const structureCalc = (
|
||||
nodes: 0,
|
||||
persistentVolumes: 0,
|
||||
disks: 0,
|
||||
volumePerDisk: 0,
|
||||
pvSize: 0,
|
||||
}; // Invalid Data
|
||||
}
|
||||
|
||||
@@ -316,7 +318,7 @@ const structureCalc = (
|
||||
nodes: 0,
|
||||
persistentVolumes: 0,
|
||||
disks: 0,
|
||||
volumePerDisk: 0,
|
||||
pvSize: 0,
|
||||
}; // Cannot allocate this server
|
||||
}
|
||||
}
|
||||
@@ -328,7 +330,7 @@ const structureCalc = (
|
||||
nodes: 0,
|
||||
persistentVolumes: 0,
|
||||
disks: 0,
|
||||
volumePerDisk: 0,
|
||||
pvSize: 0,
|
||||
}; // Cannot allocate this volume size
|
||||
}
|
||||
|
||||
@@ -501,7 +503,8 @@ export const getTimeFromTimestamp = (
|
||||
export const calculateBytes = (
|
||||
x: string,
|
||||
showDecimals = false,
|
||||
roundFloor = true
|
||||
roundFloor = true,
|
||||
k8sUnit = false
|
||||
) => {
|
||||
const bytes = parseInt(x, 10);
|
||||
|
||||
@@ -523,7 +526,7 @@ export const calculateBytes = (
|
||||
|
||||
// Get Unit parsed
|
||||
const unitParsed = parseFloat(roundedUnit.toFixed(fractionDigits));
|
||||
const finalUnit = units[i];
|
||||
const finalUnit = k8sUnit ? k8sCalcUnits[i] : units[i];
|
||||
|
||||
return { total: unitParsed, unit: finalUnit };
|
||||
};
|
||||
@@ -596,113 +599,3 @@ export const decodeFileName = (text: string) => {
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
export const setResourcesValidation = (
|
||||
memorySize: number,
|
||||
cpusSelected: number,
|
||||
maxAllocatableResources: AllocableResourcesResponse
|
||||
) => {
|
||||
const requestedSizeBytes = getBytes(memorySize.toString(10), "GB");
|
||||
const memReqSize = parseInt(requestedSizeBytes, 10);
|
||||
|
||||
const minimalRequiredMemory = 2147483648; // Minimal required memory, 2Gi
|
||||
|
||||
const memoryExists = get(
|
||||
maxAllocatableResources,
|
||||
"min_allocatable_mem",
|
||||
false
|
||||
);
|
||||
|
||||
const cpuExists = get(maxAllocatableResources, "min_allocatable_cpu", false);
|
||||
|
||||
if (memoryExists === false) {
|
||||
return {
|
||||
error:
|
||||
"No available memory for the selected number of nodes. Please try another combination.",
|
||||
memoryRequest: 0,
|
||||
memoryLimit: 0,
|
||||
cpuRequest: 0,
|
||||
cpuLimit: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (cpuExists === false) {
|
||||
return {
|
||||
error:
|
||||
"No available CPUs for the selected number of nodes. Please try another combination",
|
||||
memoryRequest: 0,
|
||||
memoryLimit: 0,
|
||||
cpuRequest: 0,
|
||||
cpuLimit: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (memReqSize < minimalRequiredMemory) {
|
||||
return {
|
||||
error: "Memory size is set bellow minimum required",
|
||||
memoryRequest: 0,
|
||||
memoryLimit: 0,
|
||||
cpuRequest: 0,
|
||||
cpuLimit: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (cpusSelected < 1) {
|
||||
return {
|
||||
error: "CPU amount is set bellow minimum available",
|
||||
memoryRequest: 0,
|
||||
memoryLimit: 0,
|
||||
cpuRequest: 0,
|
||||
cpuLimit: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
memReqSize <= maxAllocatableResources.mem_priority.max_allocatable_mem &&
|
||||
cpusSelected > maxAllocatableResources.mem_priority.max_allocatable_cpu
|
||||
) {
|
||||
return {
|
||||
error:
|
||||
"It is not possible to allocate this amount of memory in all the CPUs",
|
||||
memoryRequest: 0,
|
||||
memoryLimit: 0,
|
||||
cpuRequest: 0,
|
||||
cpuLimit: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
cpusSelected <= maxAllocatableResources.cpu_priority.max_allocatable_cpu &&
|
||||
memReqSize > maxAllocatableResources.cpu_priority.max_allocatable_mem
|
||||
) {
|
||||
return {
|
||||
error:
|
||||
"It is not possible to allocate this amount of CPUs with the available memory",
|
||||
memoryRequest: 0,
|
||||
memoryLimit: 0,
|
||||
cpuRequest: 0,
|
||||
cpuLimit: 0,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
cpusSelected > maxAllocatableResources.cpu_priority.max_allocatable_cpu ||
|
||||
memReqSize > maxAllocatableResources.mem_priority.max_allocatable_mem
|
||||
) {
|
||||
return {
|
||||
error: "CPUs or Memory selected is beyond bounds",
|
||||
memoryRequest: 0,
|
||||
memoryLimit: 0,
|
||||
cpuRequest: 0,
|
||||
cpuLimit: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
error: "",
|
||||
memoryRequest: memReqSize,
|
||||
memoryLimit: maxAllocatableResources.mem_priority.max_allocatable_mem,
|
||||
cpuRequest: cpusSelected,
|
||||
cpuLimit: maxAllocatableResources.cpu_priority.max_allocatable_cpu,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -39,7 +39,6 @@ import { KeyPair } from "../ListTenants/utils";
|
||||
import { setErrorSnackMessage } from "../../../../actions";
|
||||
import { getDefaultAffinity, getNodeSelector } from "../TenantDetails/utils";
|
||||
import CredentialsPrompt from "../../Common/CredentialsPrompt/CredentialsPrompt";
|
||||
import NameTenant from "./Steps/NameTenant";
|
||||
import { AppState } from "../../../../store";
|
||||
import { ICertificatesItems, IFieldStore } from "../types";
|
||||
import { resetAddTenantForm, updateAddField } from "../actions";
|
||||
@@ -53,6 +52,7 @@ import history from "../../../../history";
|
||||
import Images from "./Steps/Images";
|
||||
import PageLayout from "../../Common/Layout/PageLayout";
|
||||
import BackLink from "../../../../common/BackLink";
|
||||
import TenantResources from "./Steps/TenantResources/TenantResources";
|
||||
|
||||
interface IAddTenantProps {
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
@@ -174,7 +174,6 @@ const AddTenant = ({
|
||||
const enableTLS = fields.security.enableTLS;
|
||||
const ecParity = fields.tenantSize.ecParity;
|
||||
const distribution = fields.tenantSize.distribution;
|
||||
const resourcesSize = fields.tenantSize.resourcesSize;
|
||||
const tenantCustom = fields.configure.tenantCustom;
|
||||
const logSearchCustom = fields.configure.logSearchCustom;
|
||||
const prometheusCustom = fields.configure.prometheusCustom;
|
||||
@@ -253,16 +252,6 @@ const AddTenant = ({
|
||||
size: distribution.pvSize,
|
||||
storage_class_name: selectedStorageClass,
|
||||
},
|
||||
resources: {
|
||||
requests: {
|
||||
memory: resourcesSize.memoryRequest,
|
||||
cpu: resourcesSize.cpuRequest,
|
||||
},
|
||||
limits: {
|
||||
memory: resourcesSize.memoryRequest,
|
||||
cpu: resourcesSize.cpuRequest,
|
||||
},
|
||||
},
|
||||
securityContext: tenantCustom ? tenantSecurityContext : null,
|
||||
...affinityObject,
|
||||
},
|
||||
@@ -270,6 +259,49 @@ const AddTenant = ({
|
||||
erasureCodingParity: parseInt(erasureCode, 10),
|
||||
};
|
||||
|
||||
// Set Resources
|
||||
if (
|
||||
fields.tenantSize.resourcesCPURequest !== "" ||
|
||||
fields.tenantSize.resourcesCPULimit !== "" ||
|
||||
fields.tenantSize.resourcesMemoryRequest !== "" ||
|
||||
fields.tenantSize.resourcesMemoryLimit !== ""
|
||||
) {
|
||||
dataSend.pools[0].resources = {};
|
||||
// requests
|
||||
if (
|
||||
fields.tenantSize.resourcesCPURequest !== "" ||
|
||||
fields.tenantSize.resourcesMemoryRequest !== ""
|
||||
) {
|
||||
dataSend.pools[0].resources.requests = {};
|
||||
if (fields.tenantSize.resourcesCPURequest !== "") {
|
||||
dataSend.pools[0].resources.requests.cpu = parseInt(
|
||||
fields.tenantSize.resourcesCPURequest
|
||||
);
|
||||
}
|
||||
if (fields.tenantSize.resourcesMemoryRequest !== "") {
|
||||
dataSend.pools[0].resources.requests.memory = parseInt(
|
||||
fields.tenantSize.resourcesMemoryRequest
|
||||
);
|
||||
}
|
||||
}
|
||||
// limits
|
||||
if (
|
||||
fields.tenantSize.resourcesCPULimit !== "" ||
|
||||
fields.tenantSize.resourcesMemoryLimit !== ""
|
||||
) {
|
||||
dataSend.pools[0].resources.limits = {};
|
||||
if (fields.tenantSize.resourcesCPULimit !== "") {
|
||||
dataSend.pools[0].resources.limits.cpu = parseInt(
|
||||
fields.tenantSize.resourcesCPULimit
|
||||
);
|
||||
}
|
||||
if (fields.tenantSize.resourcesMemoryLimit !== "") {
|
||||
dataSend.pools[0].resources.limits.memory = parseInt(
|
||||
fields.tenantSize.resourcesMemoryLimit
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (customDockerhub) {
|
||||
dataSend = {
|
||||
...dataSend,
|
||||
@@ -285,7 +317,10 @@ const AddTenant = ({
|
||||
dataSend = {
|
||||
...dataSend,
|
||||
logSearchConfiguration: {
|
||||
storageClass: logSearchSelectedStorageClass,
|
||||
storageClass:
|
||||
logSearchSelectedStorageClass === "default"
|
||||
? ""
|
||||
: logSearchSelectedStorageClass,
|
||||
storageSize: parseInt(logSearchVolumeSize),
|
||||
image: logSearchImage,
|
||||
postgres_image: logSearchPostgresImage,
|
||||
@@ -309,7 +344,10 @@ const AddTenant = ({
|
||||
dataSend = {
|
||||
...dataSend,
|
||||
prometheusConfiguration: {
|
||||
storageClass: prometheusSelectedStorageClass,
|
||||
storageClass:
|
||||
prometheusSelectedStorageClass === "default"
|
||||
? ""
|
||||
: prometheusSelectedStorageClass,
|
||||
storageSize: parseInt(prometheusVolumeSize),
|
||||
image: prometheusImage,
|
||||
sidecar_image: prometheusSidecarImage,
|
||||
@@ -671,7 +709,7 @@ const AddTenant = ({
|
||||
const wizardSteps: IWizardElement[] = [
|
||||
{
|
||||
label: "Setup",
|
||||
componentRender: <NameTenant />,
|
||||
componentRender: <TenantResources />,
|
||||
buttons: [cancelButton, createButton],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -163,6 +163,11 @@ const Configure = ({
|
||||
}: IConfigureProps) => {
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
|
||||
const configureSTClasses = [
|
||||
{ label: "Default", value: "default" },
|
||||
...storageClasses,
|
||||
];
|
||||
|
||||
// Common
|
||||
const updateField = useCallback(
|
||||
(field: string, value: any) => {
|
||||
@@ -450,20 +455,20 @@ const Configure = ({
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
// New default values is current selection is invalid
|
||||
// New default values in current selection is invalid
|
||||
if (storageClasses.length > 0) {
|
||||
const filterPrometheus = storageClasses.filter(
|
||||
(item: any) => item.value === prometheusSelectedStorageClass
|
||||
);
|
||||
if (filterPrometheus.length === 0) {
|
||||
updateField("prometheusSelectedStorageClass", selectedStorageClass);
|
||||
updateField("prometheusSelectedStorageClass", "default");
|
||||
}
|
||||
|
||||
const filterLogSearch = storageClasses.filter(
|
||||
(item: any) => item.value === logSearchSelectedStorageClass
|
||||
);
|
||||
if (filterLogSearch.length === 0) {
|
||||
updateField("logSearchSelectedStorageClass", selectedStorageClass);
|
||||
updateField("logSearchSelectedStorageClass", "default");
|
||||
}
|
||||
}
|
||||
}, [
|
||||
@@ -673,8 +678,8 @@ const Configure = ({
|
||||
}}
|
||||
label="Log Search Storage Class"
|
||||
value={logSearchSelectedStorageClass}
|
||||
options={storageClasses}
|
||||
disabled={storageClasses.length < 1}
|
||||
options={configureSTClasses}
|
||||
disabled={configureSTClasses.length < 1}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
@@ -925,8 +930,8 @@ const Configure = ({
|
||||
}}
|
||||
label="Prometheus Storage Class"
|
||||
value={prometheusSelectedStorageClass}
|
||||
options={storageClasses}
|
||||
disabled={storageClasses.length < 1}
|
||||
options={configureSTClasses}
|
||||
disabled={configureSTClasses.length < 1}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
|
||||
@@ -277,31 +277,6 @@ const Images = ({
|
||||
logSearchVolumeSize,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
// New default values is current selection is invalid
|
||||
if (storageClasses.length > 0) {
|
||||
const filterPrometheus = storageClasses.filter(
|
||||
(item: any) => item.value === prometheusSelectedStorageClass
|
||||
);
|
||||
if (filterPrometheus.length === 0) {
|
||||
updateField("prometheusSelectedStorageClass", selectedStorageClass);
|
||||
}
|
||||
|
||||
const filterLogSearch = storageClasses.filter(
|
||||
(item: any) => item.value === logSearchSelectedStorageClass
|
||||
);
|
||||
if (filterLogSearch.length === 0) {
|
||||
updateField("logSearchSelectedStorageClass", selectedStorageClass);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
logSearchSelectedStorageClass,
|
||||
prometheusSelectedStorageClass,
|
||||
selectedStorageClass,
|
||||
storageClasses,
|
||||
updateField,
|
||||
]);
|
||||
|
||||
const cleanValidation = (fieldName: string) => {
|
||||
setValidationErrors(clearValidationError(validationErrors, fieldName));
|
||||
};
|
||||
|
||||
@@ -35,12 +35,12 @@ import { IResourcesSize } from "../../ListTenants/types";
|
||||
import { IErasureCodeCalc } from "../../../../../common/types";
|
||||
|
||||
import { Divider } from "@mui/material";
|
||||
import { IntegrationConfiguration } from "./TenantResources/utils";
|
||||
|
||||
interface ISizePreviewProps {
|
||||
classes: any;
|
||||
updateAddField: typeof updateAddField;
|
||||
isPageValid: typeof isPageValid;
|
||||
advancedMode: boolean;
|
||||
volumeSize: string;
|
||||
sizeFactor: string;
|
||||
drivesPerServer: string;
|
||||
@@ -49,13 +49,13 @@ interface ISizePreviewProps {
|
||||
ecParity: string;
|
||||
ecParityChoices: Opts[];
|
||||
cleanECChoices: string[];
|
||||
maxAllocableMemo: number;
|
||||
resourcesSize: IResourcesSize;
|
||||
distribution: any;
|
||||
ecParityCalc: IErasureCodeCalc;
|
||||
limitSize: any;
|
||||
selectedStorageClass: string;
|
||||
cpuToUse: string;
|
||||
integrationSelection: IntegrationConfiguration;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -76,7 +76,6 @@ const SizePreview = ({
|
||||
classes,
|
||||
updateAddField,
|
||||
isPageValid,
|
||||
advancedMode,
|
||||
volumeSize,
|
||||
sizeFactor,
|
||||
drivesPerServer,
|
||||
@@ -85,13 +84,13 @@ const SizePreview = ({
|
||||
ecParity,
|
||||
ecParityChoices,
|
||||
cleanECChoices,
|
||||
maxAllocableMemo,
|
||||
resourcesSize,
|
||||
distribution,
|
||||
ecParityCalc,
|
||||
limitSize,
|
||||
selectedStorageClass,
|
||||
cpuToUse,
|
||||
integrationSelection,
|
||||
}: ISizePreviewProps) => {
|
||||
const usableInformation = ecParityCalc.storageFactors.find(
|
||||
(element) => element.erasureCode === ecParity
|
||||
@@ -109,34 +108,47 @@ const SizePreview = ({
|
||||
{parseInt(nodes) > 0 ? nodes : "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell scope="row">Drives per Server</TableCell>
|
||||
<TableCell align="right">
|
||||
{distribution ? distribution.disks : "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell scope="row">Drive Capacity</TableCell>
|
||||
<TableCell align="right">
|
||||
{distribution ? niceBytes(distribution.pvSize) : "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{integrationSelection.typeSelection === "" &&
|
||||
integrationSelection.storageClass === "" && (
|
||||
<Fragment>
|
||||
<TableRow>
|
||||
<TableCell scope="row">Drives per Server</TableCell>
|
||||
<TableCell align="right">
|
||||
{distribution ? distribution.disks : "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell scope="row">Drive Capacity</TableCell>
|
||||
<TableCell align="right">
|
||||
{distribution ? niceBytes(distribution.pvSize) : "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
<TableRow>
|
||||
<TableCell scope="row">Total Volumes</TableCell>
|
||||
<TableCell align="right">
|
||||
{distribution ? distribution.persistentVolumes : "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{!advancedMode && (
|
||||
<TableRow>
|
||||
<TableCell scope="row">Memory per Node</TableCell>
|
||||
<TableCell align="right">{memoryNode} Gi</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
<TableRow>
|
||||
<TableCell scope="row">CPU Selection</TableCell>
|
||||
<TableCell align="right">{cpuToUse}</TableCell>
|
||||
</TableRow>
|
||||
{integrationSelection.typeSelection === "" &&
|
||||
integrationSelection.storageClass === "" && (
|
||||
<Fragment>
|
||||
<TableRow>
|
||||
<TableCell scope="row">Memory per Node</TableCell>
|
||||
<TableCell align="right">{memoryNode} Gi</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ borderBottom: 0 }} scope="row">
|
||||
CPU Selection
|
||||
</TableCell>
|
||||
<TableCell style={{ borderBottom: 0 }} align="right">
|
||||
{cpuToUse}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</Fragment>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{ecParityCalc.error === 0 && usableInformation && (
|
||||
@@ -184,12 +196,59 @@ const SizePreview = ({
|
||||
</Table>
|
||||
</Fragment>
|
||||
)}
|
||||
{integrationSelection.typeSelection !== "" &&
|
||||
integrationSelection.storageClass !== "" && (
|
||||
<Fragment>
|
||||
<h4>Single Instance Configuration</h4>
|
||||
<Divider />
|
||||
<Table
|
||||
className={classes.table}
|
||||
aria-label="simple table"
|
||||
size={"small"}
|
||||
>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell scope="row">CPU</TableCell>
|
||||
<TableCell align="right">
|
||||
{integrationSelection.CPU !== 0
|
||||
? integrationSelection.CPU
|
||||
: "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell scope="row">Memory</TableCell>
|
||||
<TableCell align="right">
|
||||
{integrationSelection.memory !== 0
|
||||
? `${integrationSelection.memory} Gi`
|
||||
: "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell scope="row">Drives per Server</TableCell>
|
||||
<TableCell align="right">
|
||||
{integrationSelection.drivesPerServer !== 0
|
||||
? `${integrationSelection.drivesPerServer}`
|
||||
: "-"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ borderBottom: 0 }} scope="row">
|
||||
Drive Size
|
||||
</TableCell>
|
||||
<TableCell style={{ borderBottom: 0 }} align="right">
|
||||
{integrationSelection.driveSize.driveSize}
|
||||
{integrationSelection.driveSize.sizeUnit}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
advancedMode: state.tenants.createTenant.advancedModeOn,
|
||||
volumeSize: state.tenants.createTenant.fields.tenantSize.volumeSize,
|
||||
sizeFactor: state.tenants.createTenant.fields.tenantSize.sizeFactor,
|
||||
drivesPerServer: state.tenants.createTenant.fields.tenantSize.drivesPerServer,
|
||||
@@ -198,8 +257,6 @@ const mapState = (state: AppState) => ({
|
||||
ecParity: state.tenants.createTenant.fields.tenantSize.ecParity,
|
||||
ecParityChoices: state.tenants.createTenant.fields.tenantSize.ecParityChoices,
|
||||
cleanECChoices: state.tenants.createTenant.fields.tenantSize.cleanECChoices,
|
||||
maxAllocableMemo:
|
||||
state.tenants.createTenant.fields.tenantSize.maxAllocableMemo,
|
||||
resourcesSize: state.tenants.createTenant.fields.tenantSize.resourcesSize,
|
||||
distribution: state.tenants.createTenant.fields.tenantSize.distribution,
|
||||
ecParityCalc: state.tenants.createTenant.fields.tenantSize.ecParityCalc,
|
||||
@@ -207,6 +264,8 @@ const mapState = (state: AppState) => ({
|
||||
selectedStorageClass:
|
||||
state.tenants.createTenant.fields.nameTenant.selectedStorageClass,
|
||||
cpuToUse: state.tenants.createTenant.fields.tenantSize.cpuToUse,
|
||||
integrationSelection:
|
||||
state.tenants.createTenant.fields.tenantSize.integrationSelection,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, {
|
||||
|
||||
@@ -32,32 +32,33 @@ import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
wizardCommon,
|
||||
} from "../../../Common/FormComponents/common/styleLibrary";
|
||||
import { setModalErrorSnackMessage } from "../../../../../actions";
|
||||
} from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import { setModalErrorSnackMessage } from "../../../../../../actions";
|
||||
import {
|
||||
isPageValid,
|
||||
setLimitSize,
|
||||
setStorageClassesList,
|
||||
updateAddField,
|
||||
} from "../../actions";
|
||||
} from "../../../actions";
|
||||
import {
|
||||
getLimitSizes,
|
||||
IQuotaElement,
|
||||
IQuotas,
|
||||
Opts,
|
||||
} from "../../ListTenants/utils";
|
||||
import { AppState } from "../../../../../store";
|
||||
import { commonFormValidation } from "../../../../../utils/validationFunctions";
|
||||
import { clearValidationError } from "../../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../common/types";
|
||||
import api from "../../../../../common/api";
|
||||
import InputBoxWrapper from "../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import SelectWrapper from "../../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import AddIcon from "../../../../../icons/AddIcon";
|
||||
import AddNamespaceModal from "./helpers/AddNamespaceModal";
|
||||
import SizePreview from "./SizePreview";
|
||||
} from "../../../ListTenants/utils";
|
||||
import { AppState } from "../../../../../../store";
|
||||
import { commonFormValidation } from "../../../../../../utils/validationFunctions";
|
||||
import { clearValidationError } from "../../../utils";
|
||||
import { ErrorResponseHandler } from "../../../../../../common/types";
|
||||
import api from "../../../../../../common/api";
|
||||
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import SelectWrapper from "../../../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import AddIcon from "../../../../../../icons/AddIcon";
|
||||
import AddNamespaceModal from "../helpers/AddNamespaceModal";
|
||||
import SizePreview from "../SizePreview";
|
||||
import TenantSize from "./TenantSize";
|
||||
import { Paper, SelectChangeEvent } from "@mui/material";
|
||||
import { IMkEnvs, mkPanelConfigurations } from "./utils";
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -73,7 +74,7 @@ const styles = (theme: Theme) =>
|
||||
...wizardCommon,
|
||||
});
|
||||
|
||||
interface INameTenantScreen {
|
||||
interface INameTenantMainScreen {
|
||||
classes: any;
|
||||
storageClasses: Opts[];
|
||||
setModalErrorSnackMessage: typeof setModalErrorSnackMessage;
|
||||
@@ -84,20 +85,24 @@ interface INameTenantScreen {
|
||||
tenantName: string;
|
||||
namespace: string;
|
||||
selectedStorageClass: string;
|
||||
selectedStorageType: string;
|
||||
formToRender?: IMkEnvs;
|
||||
}
|
||||
|
||||
const NameTenant = ({
|
||||
const NameTenantMain = ({
|
||||
classes,
|
||||
storageClasses,
|
||||
tenantName,
|
||||
namespace,
|
||||
selectedStorageClass,
|
||||
selectedStorageType,
|
||||
formToRender = IMkEnvs.default,
|
||||
updateAddField,
|
||||
setStorageClassesList,
|
||||
setLimitSize,
|
||||
isPageValid,
|
||||
setModalErrorSnackMessage,
|
||||
}: INameTenantScreen) => {
|
||||
}: INameTenantMainScreen) => {
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
const [emptyNamespace, setEmptyNamespace] = useState<boolean>(true);
|
||||
const [loadingNamespaceInfo, setLoadingNamespaceInfo] =
|
||||
@@ -230,7 +235,8 @@ const NameTenant = ({
|
||||
const isValid =
|
||||
!("tenant-name" in commonValidation) &&
|
||||
!("namespace" in commonValidation) &&
|
||||
storageClasses.length > 0;
|
||||
((formToRender === IMkEnvs.default && storageClasses.length > 0) ||
|
||||
(formToRender !== IMkEnvs.default && selectedStorageType !== ""));
|
||||
|
||||
isPageValid("nameTenant", isValid);
|
||||
|
||||
@@ -242,6 +248,8 @@ const NameTenant = ({
|
||||
isPageValid,
|
||||
emptyNamespace,
|
||||
loadingNamespaceInfo,
|
||||
selectedStorageType,
|
||||
formToRender,
|
||||
]);
|
||||
|
||||
const frmValidationCleanup = (fieldName: string) => {
|
||||
@@ -271,11 +279,11 @@ const NameTenant = ({
|
||||
)}
|
||||
<Grid container>
|
||||
<Grid item xs={8} md={9}>
|
||||
<Paper className={classes.paperWrapper}>
|
||||
<Paper className={classes.paperWrapper} sx={{ minHeight: 550 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.headerElement}>
|
||||
<h3 className={classes.h3Section}>Name Tenant</h3>
|
||||
<h3 className={classes.h3Section}>Name</h3>
|
||||
<span className={classes.descriptionText}>
|
||||
How would you like to name this new tenant?
|
||||
</span>
|
||||
@@ -311,23 +319,57 @@ const NameTenant = ({
|
||||
required
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<SelectWrapper
|
||||
id="storage_class"
|
||||
name="storage_class"
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
updateField(
|
||||
"selectedStorageClass",
|
||||
e.target.value as string
|
||||
);
|
||||
}}
|
||||
label="Storage Class"
|
||||
value={selectedStorageClass}
|
||||
options={storageClasses}
|
||||
disabled={storageClasses.length < 1}
|
||||
/>
|
||||
</Grid>
|
||||
<TenantSize />
|
||||
{formToRender === IMkEnvs.default ? (
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<SelectWrapper
|
||||
id="storage_class"
|
||||
name="storage_class"
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
updateField(
|
||||
"selectedStorageClass",
|
||||
e.target.value as string
|
||||
);
|
||||
}}
|
||||
label="Storage Class"
|
||||
value={selectedStorageClass}
|
||||
options={storageClasses}
|
||||
disabled={storageClasses.length < 1}
|
||||
/>
|
||||
</Grid>
|
||||
) : (
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<SelectWrapper
|
||||
id="storage_type"
|
||||
name="storage_type"
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
updateField(
|
||||
"selectedStorageType",
|
||||
e.target.value as string
|
||||
);
|
||||
}}
|
||||
label={get(
|
||||
mkPanelConfigurations,
|
||||
`${formToRender}.variantSelectorLabel`,
|
||||
"Storage Type"
|
||||
)}
|
||||
value={selectedStorageType}
|
||||
options={get(
|
||||
mkPanelConfigurations,
|
||||
`${formToRender}.variantSelectorValues`,
|
||||
[]
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{formToRender === IMkEnvs.default ? (
|
||||
<TenantSize />
|
||||
) : (
|
||||
get(
|
||||
mkPanelConfigurations,
|
||||
`${formToRender}.sizingComponent`,
|
||||
null
|
||||
)
|
||||
)}
|
||||
</Grid>
|
||||
</Paper>
|
||||
</Grid>
|
||||
@@ -346,6 +388,8 @@ const mapState = (state: AppState) => ({
|
||||
namespace: state.tenants.createTenant.fields.nameTenant.namespace,
|
||||
selectedStorageClass:
|
||||
state.tenants.createTenant.fields.nameTenant.selectedStorageClass,
|
||||
selectedStorageType:
|
||||
state.tenants.createTenant.fields.nameTenant.selectedStorageType,
|
||||
storageClasses: state.tenants.createTenant.storageClasses,
|
||||
});
|
||||
|
||||
@@ -357,4 +401,4 @@ const connector = connect(mapState, {
|
||||
isPageValid,
|
||||
});
|
||||
|
||||
export default withStyles(styles)(connector(NameTenant));
|
||||
export default withStyles(styles)(connector(NameTenantMain));
|
||||
@@ -0,0 +1,64 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// 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, { useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import get from "lodash/get";
|
||||
import NameTenantMain from "./NameTenantMain";
|
||||
import { IMkEnvs, resourcesConfigurations } from "./utils";
|
||||
import { AppState } from "../../../../../../store";
|
||||
|
||||
interface ITenantResources {
|
||||
features?: string[];
|
||||
}
|
||||
|
||||
const TenantResources = ({ features }: ITenantResources) => {
|
||||
const [formRender, setFormRender] = useState<IMkEnvs | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let setConfiguration = IMkEnvs.default;
|
||||
|
||||
if (features && features.length !== 0) {
|
||||
const possibleVariables = Object.keys(resourcesConfigurations);
|
||||
|
||||
possibleVariables.forEach((element) => {
|
||||
if (features.includes(element)) {
|
||||
setConfiguration = get(
|
||||
resourcesConfigurations,
|
||||
element,
|
||||
IMkEnvs.default
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setFormRender(setConfiguration);
|
||||
}, [features]);
|
||||
|
||||
if (formRender === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <NameTenantMain formToRender={formRender} />;
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
features: state.console.session.features,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, null);
|
||||
|
||||
export default connector(TenantResources);
|
||||
@@ -20,14 +20,13 @@ import { Theme } from "@mui/material/styles";
|
||||
import { SelectChangeEvent } from "@mui/material";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import get from "lodash/get";
|
||||
import { AppState } from "../../../../../store";
|
||||
import { isPageValid, updateAddField } from "../../actions";
|
||||
import { AppState } from "../../../../../../store";
|
||||
import { isPageValid, updateAddField } from "../../../actions";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
wizardCommon,
|
||||
} from "../../../Common/FormComponents/common/styleLibrary";
|
||||
} from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import {
|
||||
calculateDistribution,
|
||||
@@ -35,23 +34,21 @@ import {
|
||||
getBytes,
|
||||
k8sfactorForDropdown,
|
||||
niceBytes,
|
||||
setResourcesValidation,
|
||||
} from "../../../../../common/utils";
|
||||
import { clearValidationError } from "../../utils";
|
||||
import { ecListTransform, Opts } from "../../ListTenants/utils";
|
||||
import { IResourcesSize } from "../../ListTenants/types";
|
||||
import { AllocableResourcesResponse } from "../../types";
|
||||
import { ICapacity, IErasureCodeCalc } from "../../../../../common/types";
|
||||
import { commonFormValidation } from "../../../../../utils/validationFunctions";
|
||||
import api from "../../../../../common/api";
|
||||
import InputBoxWrapper from "../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import SelectWrapper from "../../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
} from "../../../../../../common/utils";
|
||||
import { clearValidationError } from "../../../utils";
|
||||
import { ecListTransform, Opts } from "../../../ListTenants/utils";
|
||||
import { IResourcesSize } from "../../../ListTenants/types";
|
||||
import { ICapacity, IErasureCodeCalc } from "../../../../../../common/types";
|
||||
import { commonFormValidation } from "../../../../../../utils/validationFunctions";
|
||||
import api from "../../../../../../common/api";
|
||||
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import SelectWrapper from "../../../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import TenantSizeResources from "./TenantSizeResources";
|
||||
|
||||
interface ITenantSizeProps {
|
||||
classes: any;
|
||||
updateAddField: typeof updateAddField;
|
||||
isPageValid: typeof isPageValid;
|
||||
advancedMode: boolean;
|
||||
volumeSize: string;
|
||||
sizeFactor: string;
|
||||
drivesPerServer: string;
|
||||
@@ -60,16 +57,11 @@ interface ITenantSizeProps {
|
||||
ecParity: string;
|
||||
ecParityChoices: Opts[];
|
||||
cleanECChoices: string[];
|
||||
maxAllocableMemo: number;
|
||||
resourcesSize: IResourcesSize;
|
||||
distribution: any;
|
||||
ecParityCalc: IErasureCodeCalc;
|
||||
limitSize: any;
|
||||
selectedStorageClass: string;
|
||||
cpuToUse: string;
|
||||
maxAllocatableResources: AllocableResourcesResponse;
|
||||
maxCPUsUse: string;
|
||||
maxMemorySize: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
@@ -98,7 +90,6 @@ const TenantSize = ({
|
||||
classes,
|
||||
updateAddField,
|
||||
isPageValid,
|
||||
advancedMode,
|
||||
volumeSize,
|
||||
sizeFactor,
|
||||
drivesPerServer,
|
||||
@@ -107,16 +98,11 @@ const TenantSize = ({
|
||||
ecParity,
|
||||
ecParityChoices,
|
||||
cleanECChoices,
|
||||
maxAllocableMemo,
|
||||
resourcesSize,
|
||||
distribution,
|
||||
ecParityCalc,
|
||||
limitSize,
|
||||
cpuToUse,
|
||||
selectedStorageClass,
|
||||
maxAllocatableResources,
|
||||
maxCPUsUse,
|
||||
maxMemorySize,
|
||||
}: ITenantSizeProps) => {
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
const [errorFlag, setErrorFlag] = useState<boolean>(false);
|
||||
@@ -138,23 +124,6 @@ const TenantSize = ({
|
||||
|
||||
// Storage Quotas
|
||||
|
||||
const validateResourcesSize = useCallback(() => {
|
||||
const memSize = memoryNode || "0";
|
||||
const cpusSelected = cpuToUse;
|
||||
|
||||
const resourcesSize = setResourcesValidation(
|
||||
parseInt(memSize),
|
||||
parseInt(cpusSelected),
|
||||
maxAllocatableResources
|
||||
);
|
||||
|
||||
updateField("resourcesSize", resourcesSize);
|
||||
}, [memoryNode, cpuToUse, maxAllocatableResources, updateField]);
|
||||
|
||||
useEffect(() => {
|
||||
validateResourcesSize();
|
||||
}, [memoryNode, cpuToUse, validateResourcesSize]);
|
||||
|
||||
useEffect(() => {
|
||||
if (ecParityChoices.length > 0 && distribution.error === "") {
|
||||
const ecCodeValidated = erasureCodeCalc(
|
||||
@@ -165,9 +134,11 @@ const TenantSize = ({
|
||||
);
|
||||
|
||||
updateField("ecParityCalc", ecCodeValidated);
|
||||
updateField("ecParity", ecCodeValidated.defaultEC);
|
||||
if (!cleanECChoices.includes(ecParity) || ecParity === "") {
|
||||
updateField("ecParity", ecCodeValidated.defaultEC);
|
||||
}
|
||||
}
|
||||
}, [ecParityChoices.length, distribution, cleanECChoices, updateField]);
|
||||
}, [ecParity, ecParityChoices.length, distribution, cleanECChoices, updateField]);
|
||||
/*End debounce functions*/
|
||||
|
||||
/*Calculate Allocation*/
|
||||
@@ -192,74 +163,7 @@ const TenantSize = ({
|
||||
updateField("distribution", distrCalculate);
|
||||
setErrorFlag(false);
|
||||
setNodeError("");
|
||||
|
||||
// Get allocatable Resources
|
||||
api
|
||||
.invoke("GET", `api/v1/cluster/allocatable-resources?num_nodes=${nodes}`)
|
||||
.then((res: AllocableResourcesResponse) => {
|
||||
updateField("maxAllocatableResources", res);
|
||||
|
||||
const maxAllocatableResources = res;
|
||||
|
||||
const memoryExists = get(
|
||||
maxAllocatableResources,
|
||||
"min_allocatable_mem",
|
||||
false
|
||||
);
|
||||
|
||||
const cpuExists = get(
|
||||
maxAllocatableResources,
|
||||
"min_allocatable_cpu",
|
||||
false
|
||||
);
|
||||
|
||||
if (memoryExists === false || cpuExists === false) {
|
||||
updateField("cpuToUse", 0);
|
||||
|
||||
updateField("maxMemorySize", "0");
|
||||
updateField("maxCPUsUse", "0");
|
||||
|
||||
validateResourcesSize();
|
||||
return;
|
||||
}
|
||||
|
||||
// We default to Best CPU Configuration
|
||||
updateField(
|
||||
"maxMemorySize",
|
||||
res.mem_priority.max_allocatable_mem.toString()
|
||||
);
|
||||
updateField(
|
||||
"maxCPUsUse",
|
||||
res.cpu_priority.max_allocatable_cpu.toString()
|
||||
);
|
||||
|
||||
updateField("maxAllocableMemo", res.mem_priority.max_allocatable_mem);
|
||||
|
||||
const cpuInt = parseInt(cpuToUse);
|
||||
const maxAlocatableCPU = get(
|
||||
maxAllocatableResources,
|
||||
"cpu_priority.max_allocatable_cpu",
|
||||
0
|
||||
);
|
||||
|
||||
if (cpuInt === 0 && cpuInt !== maxAlocatableCPU) {
|
||||
updateField("cpuToUse", maxAlocatableCPU);
|
||||
} else if (cpuInt > maxAlocatableCPU) {
|
||||
updateField("cpuToUse", maxAlocatableCPU);
|
||||
}
|
||||
|
||||
// We reset error states
|
||||
validateResourcesSize();
|
||||
})
|
||||
.catch((err: any) => {
|
||||
updateField("maxAllocableMemo", 0);
|
||||
updateField("cpuToUse", "0");
|
||||
setErrorFlag(true);
|
||||
setNodeError(err.errorMessage);
|
||||
console.error(err);
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [nodes, volumeSize, sizeFactor, updateField]);
|
||||
}, [nodes, volumeSize, sizeFactor, updateField, drivesPerServer]);
|
||||
|
||||
/*Calculate Allocation End*/
|
||||
|
||||
@@ -288,13 +192,6 @@ const TenantSize = ({
|
||||
true
|
||||
)}`,
|
||||
},
|
||||
{
|
||||
fieldKey: "memory_per_node",
|
||||
required: true,
|
||||
value: memoryNode,
|
||||
customValidation: parseInt(memoryNode) < 2,
|
||||
customValidationMessage: "Memory size must be greater than 2Gi",
|
||||
},
|
||||
{
|
||||
fieldKey: "drivesps",
|
||||
required: true,
|
||||
@@ -308,13 +205,9 @@ const TenantSize = ({
|
||||
"tenantSize",
|
||||
!("nodes" in commonValidation) &&
|
||||
!("volume_size" in commonValidation) &&
|
||||
!("memory_per_node" in commonValidation) &&
|
||||
!("drivesps" in commonValidation) &&
|
||||
distribution.error === "" &&
|
||||
ecParityCalc.error === 0 &&
|
||||
resourcesSize.error === "" &&
|
||||
parseInt(cpuToUse) <= parseInt(maxCPUsUse) &&
|
||||
parseInt(cpuToUse) > 0 &&
|
||||
ecParity !== ""
|
||||
);
|
||||
|
||||
@@ -329,8 +222,6 @@ const TenantSize = ({
|
||||
resourcesSize,
|
||||
limitSize,
|
||||
selectedStorageClass,
|
||||
cpuToUse,
|
||||
maxCPUsUse,
|
||||
isPageValid,
|
||||
errorFlag,
|
||||
nodeError,
|
||||
@@ -365,7 +256,7 @@ const TenantSize = ({
|
||||
<Fragment>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.headerElement}>
|
||||
<h3 className={classes.h3Section}>Tenant Size</h3>
|
||||
<h3 className={classes.h3Section}>Capacity</h3>
|
||||
<span className={classes.descriptionText}>
|
||||
Please select the desired capacity
|
||||
</span>
|
||||
@@ -376,11 +267,6 @@ const TenantSize = ({
|
||||
<div className={classes.error}>{distribution.error}</div>
|
||||
</Grid>
|
||||
)}
|
||||
{resourcesSize.error !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.error}>{resourcesSize.error}</div>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id="nodes"
|
||||
@@ -410,7 +296,7 @@ const TenantSize = ({
|
||||
cleanValidation("drivesps");
|
||||
}
|
||||
}}
|
||||
label="Number of Drives per Server"
|
||||
label="Drives per Server"
|
||||
value={drivesPerServer}
|
||||
disabled={selectedStorageClass === ""}
|
||||
min="1"
|
||||
@@ -456,49 +342,6 @@ const TenantSize = ({
|
||||
</div>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
label={"CPU Selection"}
|
||||
id={"cpuToUse"}
|
||||
name={"cpuToUse"}
|
||||
onChange={(e) => {
|
||||
if (e.target.validity.valid) {
|
||||
updateField("cpuToUse", e.target.value);
|
||||
}
|
||||
}}
|
||||
value={cpuToUse}
|
||||
disabled={selectedStorageClass === ""}
|
||||
min="1"
|
||||
max={maxCPUsUse}
|
||||
error={
|
||||
parseInt(cpuToUse) > parseInt(maxCPUsUse) ||
|
||||
parseInt(cpuToUse) <= 0 ||
|
||||
isNaN(parseInt(cpuToUse))
|
||||
? "Invalid CPU Configuration"
|
||||
: ""
|
||||
}
|
||||
pattern={"[0-9]*"}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
type="number"
|
||||
id="memory_per_node"
|
||||
name="memory_per_node"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updateField("memoryNode", e.target.value);
|
||||
cleanValidation("memory_per_node");
|
||||
}}
|
||||
label="Memory per Node [Gi]"
|
||||
value={memoryNode}
|
||||
disabled={selectedStorageClass === ""}
|
||||
required
|
||||
error={validationErrors["memory_per_node"] || ""}
|
||||
min="2"
|
||||
max={maxMemorySize}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<SelectWrapper
|
||||
id="ec_parity"
|
||||
@@ -516,12 +359,13 @@ const TenantSize = ({
|
||||
usable capacity in the cluster
|
||||
</span>
|
||||
</Grid>
|
||||
|
||||
<TenantSizeResources />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
advancedMode: state.tenants.createTenant.advancedModeOn,
|
||||
volumeSize: state.tenants.createTenant.fields.tenantSize.volumeSize,
|
||||
sizeFactor: state.tenants.createTenant.fields.tenantSize.sizeFactor,
|
||||
drivesPerServer: state.tenants.createTenant.fields.tenantSize.drivesPerServer,
|
||||
@@ -530,19 +374,13 @@ const mapState = (state: AppState) => ({
|
||||
ecParity: state.tenants.createTenant.fields.tenantSize.ecParity,
|
||||
ecParityChoices: state.tenants.createTenant.fields.tenantSize.ecParityChoices,
|
||||
cleanECChoices: state.tenants.createTenant.fields.tenantSize.cleanECChoices,
|
||||
maxAllocableMemo:
|
||||
state.tenants.createTenant.fields.tenantSize.maxAllocableMemo,
|
||||
|
||||
resourcesSize: state.tenants.createTenant.fields.tenantSize.resourcesSize,
|
||||
distribution: state.tenants.createTenant.fields.tenantSize.distribution,
|
||||
ecParityCalc: state.tenants.createTenant.fields.tenantSize.ecParityCalc,
|
||||
limitSize: state.tenants.createTenant.limitSize,
|
||||
selectedStorageClass:
|
||||
state.tenants.createTenant.fields.nameTenant.selectedStorageClass,
|
||||
cpuToUse: state.tenants.createTenant.fields.tenantSize.cpuToUse,
|
||||
maxAllocatableResources:
|
||||
state.tenants.createTenant.fields.tenantSize.maxAllocatableResources,
|
||||
maxCPUsUse: state.tenants.createTenant.fields.tenantSize.maxCPUsUse,
|
||||
maxMemorySize: state.tenants.createTenant.fields.tenantSize.maxMemorySize,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, {
|
||||
@@ -0,0 +1,385 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// 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, useCallback, useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { SelectChangeEvent } from "@mui/material";
|
||||
import get from "lodash/get";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { AppState } from "../../../../../../store";
|
||||
import { isPageValid, updateAddField } from "../../../actions";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
wizardCommon,
|
||||
} from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { erasureCodeCalc, getBytes } from "../../../../../../common/utils";
|
||||
import { clearValidationError } from "../../../utils";
|
||||
import { ecListTransform, Opts } from "../../../ListTenants/utils";
|
||||
import { IResourcesSize } from "../../../ListTenants/types";
|
||||
import {
|
||||
IErasureCodeCalc,
|
||||
IStorageDistribution,
|
||||
} from "../../../../../../common/types";
|
||||
import { commonFormValidation } from "../../../../../../utils/validationFunctions";
|
||||
import api from "../../../../../../common/api";
|
||||
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import SelectWrapper from "../../../../Common/FormComponents/SelectWrapper/SelectWrapper";
|
||||
import {
|
||||
IMkEnvs,
|
||||
IntegrationConfiguration,
|
||||
mkPanelConfigurations,
|
||||
} from "./utils";
|
||||
|
||||
interface ITenantSizeAWSProps {
|
||||
classes: any;
|
||||
updateAddField: typeof updateAddField;
|
||||
isPageValid: typeof isPageValid;
|
||||
volumeSize: string;
|
||||
sizeFactor: string;
|
||||
drivesPerServer: string;
|
||||
nodes: string;
|
||||
memoryNode: string;
|
||||
ecParity: string;
|
||||
ecParityChoices: Opts[];
|
||||
cleanECChoices: string[];
|
||||
resourcesSize: IResourcesSize;
|
||||
distribution: any;
|
||||
ecParityCalc: IErasureCodeCalc;
|
||||
limitSize: any;
|
||||
selectedStorageType: string;
|
||||
cpuToUse: string;
|
||||
maxCPUsUse: string;
|
||||
formToRender?: IMkEnvs;
|
||||
integrationSelection: IntegrationConfiguration;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
compositeFieldContainer: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
compositeAddOn: {
|
||||
marginLeft: 10,
|
||||
"& div": {
|
||||
marginBottom: 0,
|
||||
},
|
||||
"@media (max-width: 900px)": {
|
||||
"& div": {
|
||||
marginTop: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
...formFieldStyles,
|
||||
...modalBasic,
|
||||
...wizardCommon,
|
||||
});
|
||||
|
||||
const TenantSizeMK = ({
|
||||
classes,
|
||||
updateAddField,
|
||||
isPageValid,
|
||||
volumeSize,
|
||||
sizeFactor,
|
||||
drivesPerServer,
|
||||
nodes,
|
||||
memoryNode,
|
||||
ecParity,
|
||||
ecParityChoices,
|
||||
cleanECChoices,
|
||||
resourcesSize,
|
||||
distribution,
|
||||
ecParityCalc,
|
||||
limitSize,
|
||||
cpuToUse,
|
||||
selectedStorageType,
|
||||
maxCPUsUse,
|
||||
formToRender,
|
||||
integrationSelection,
|
||||
}: ITenantSizeAWSProps) => {
|
||||
const [validationErrors, setValidationErrors] = useState<any>({});
|
||||
|
||||
// Common
|
||||
const updateField = useCallback(
|
||||
(field: string, value: any) => {
|
||||
updateAddField("tenantSize", field, value);
|
||||
},
|
||||
[updateAddField]
|
||||
);
|
||||
|
||||
const updateMainField = useCallback(
|
||||
(field: string, value: string) => {
|
||||
updateAddField("nameTenant", field, value);
|
||||
},
|
||||
[updateAddField]
|
||||
);
|
||||
|
||||
const cleanValidation = (fieldName: string) => {
|
||||
setValidationErrors(clearValidationError(validationErrors, fieldName));
|
||||
};
|
||||
|
||||
/*Debounce functions*/
|
||||
|
||||
// Storage Quotas
|
||||
useEffect(() => {
|
||||
if (ecParityChoices.length > 0 && distribution.error === "") {
|
||||
const ecCodeValidated = erasureCodeCalc(
|
||||
cleanECChoices,
|
||||
distribution.persistentVolumes,
|
||||
distribution.pvSize,
|
||||
distribution.nodes
|
||||
);
|
||||
|
||||
updateField("ecParityCalc", ecCodeValidated);
|
||||
|
||||
if (!cleanECChoices.includes(ecParity) || ecParity === "") {
|
||||
updateField("ecParity", ecCodeValidated.defaultEC);
|
||||
}
|
||||
}
|
||||
}, [ecParity, ecParityChoices, distribution, cleanECChoices, updateField]);
|
||||
/*End debounce functions*/
|
||||
|
||||
/*Set location Storage Types*/
|
||||
useEffect(() => {
|
||||
if (formToRender !== undefined && parseInt(nodes) >= 4) {
|
||||
const setConfigs = mkPanelConfigurations[formToRender];
|
||||
const keyCount = Object.keys(setConfigs).length;
|
||||
|
||||
//Configuration is filled
|
||||
if (keyCount > 0) {
|
||||
const configs: IntegrationConfiguration[] = get(
|
||||
setConfigs,
|
||||
"configurations",
|
||||
[]
|
||||
);
|
||||
|
||||
const mainSelection = configs.find(
|
||||
(item) => item.typeSelection === selectedStorageType
|
||||
);
|
||||
|
||||
if (mainSelection) {
|
||||
updateField("integrationSelection", mainSelection);
|
||||
updateMainField("selectedStorageClass", mainSelection.storageClass);
|
||||
|
||||
let pvSize = parseInt(
|
||||
getBytes(
|
||||
mainSelection.driveSize.driveSize,
|
||||
mainSelection.driveSize.sizeUnit,
|
||||
true
|
||||
),
|
||||
10
|
||||
);
|
||||
|
||||
const distrCalculate: IStorageDistribution = {
|
||||
pvSize,
|
||||
nodes: parseInt(nodes),
|
||||
disks: mainSelection.drivesPerServer,
|
||||
persistentVolumes: mainSelection.drivesPerServer * parseInt(nodes),
|
||||
error: "",
|
||||
};
|
||||
|
||||
updateField("distribution", distrCalculate);
|
||||
// apply requests, half of the available resources
|
||||
updateField(
|
||||
"resourcesCPURequest",
|
||||
Math.max(1, mainSelection.CPU / 2)
|
||||
);
|
||||
updateField(
|
||||
"resourcesMemoryRequest",
|
||||
Math.max(2, mainSelection.memory / 2)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [nodes, selectedStorageType, formToRender, updateField, updateMainField]);
|
||||
|
||||
/*Calculate Allocation End*/
|
||||
|
||||
/* Validations of pages */
|
||||
|
||||
useEffect(() => {
|
||||
const commonValidation = commonFormValidation([
|
||||
{
|
||||
fieldKey: "nodes",
|
||||
required: true,
|
||||
value: nodes,
|
||||
customValidation: parseInt(nodes) < 4,
|
||||
customValidationMessage: "Al least 4 servers must be selected",
|
||||
},
|
||||
]);
|
||||
|
||||
isPageValid(
|
||||
"tenantSize",
|
||||
!("nodes" in commonValidation) &&
|
||||
distribution.error === "" &&
|
||||
ecParityCalc.error === 0 &&
|
||||
resourcesSize.error === "" &&
|
||||
ecParity !== "" &&
|
||||
parseInt(nodes) >= 4
|
||||
);
|
||||
|
||||
setValidationErrors(commonValidation);
|
||||
}, [
|
||||
nodes,
|
||||
volumeSize,
|
||||
sizeFactor,
|
||||
memoryNode,
|
||||
distribution,
|
||||
ecParityCalc,
|
||||
resourcesSize,
|
||||
limitSize,
|
||||
selectedStorageType,
|
||||
cpuToUse,
|
||||
maxCPUsUse,
|
||||
isPageValid,
|
||||
drivesPerServer,
|
||||
ecParity,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationSelection.drivesPerServer !== 0) {
|
||||
// Get EC Value
|
||||
if (nodes.trim() !== "") {
|
||||
api
|
||||
.invoke(
|
||||
"GET",
|
||||
`api/v1/get-parity/${nodes}/${integrationSelection.drivesPerServer}`
|
||||
)
|
||||
.then((ecList: string[]) => {
|
||||
updateField("ecParityChoices", ecListTransform(ecList));
|
||||
updateField("cleanECChoices", ecList);
|
||||
})
|
||||
.catch((err: any) => {
|
||||
updateField("ecparityChoices", []);
|
||||
isPageValid("tenantSize", false);
|
||||
updateField("ecParity", "");
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [integrationSelection, nodes, isPageValid, updateField]);
|
||||
|
||||
/* End Validation of pages */
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.headerElement}>
|
||||
<h3 className={classes.h3Section}>Tenant Size</h3>
|
||||
<span className={classes.descriptionText}>
|
||||
Please select the desired capacity
|
||||
</span>
|
||||
</div>
|
||||
</Grid>
|
||||
{distribution.error !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.error}>{distribution.error}</div>
|
||||
</Grid>
|
||||
)}
|
||||
{resourcesSize.error !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.error}>{resourcesSize.error}</div>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id="nodes"
|
||||
name="nodes"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.validity.valid) {
|
||||
updateField("nodes", e.target.value);
|
||||
cleanValidation("nodes");
|
||||
}
|
||||
}}
|
||||
label="Number of Servers"
|
||||
disabled={selectedStorageType === ""}
|
||||
value={nodes}
|
||||
min="4"
|
||||
required
|
||||
error={validationErrors["nodes"] || ""}
|
||||
pattern={"[0-9]*"}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<SelectWrapper
|
||||
id="ec_parity"
|
||||
name="ec_parity"
|
||||
onChange={(e: SelectChangeEvent<string>) => {
|
||||
updateField("ecParity", e.target.value as string);
|
||||
}}
|
||||
label="Erasure Code Parity"
|
||||
disabled={selectedStorageType === ""}
|
||||
value={ecParity}
|
||||
options={ecParityChoices}
|
||||
/>
|
||||
<span className={classes.descriptionText}>
|
||||
Please select the desired parity. This setting will change the max
|
||||
usable capacity in the cluster
|
||||
</span>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => () => {
|
||||
const createTenant = state.tenants.createTenant;
|
||||
|
||||
const {
|
||||
memoryNode,
|
||||
ecParityChoices,
|
||||
distribution,
|
||||
cleanECChoices,
|
||||
sizeFactor,
|
||||
ecParity,
|
||||
cpuToUse,
|
||||
integrationSelection,
|
||||
resourcesSize,
|
||||
drivesPerServer,
|
||||
maxCPUsUse,
|
||||
ecParityCalc,
|
||||
volumeSize,
|
||||
nodes,
|
||||
} = createTenant.fields.tenantSize;
|
||||
|
||||
return {
|
||||
volumeSize,
|
||||
sizeFactor,
|
||||
drivesPerServer,
|
||||
nodes,
|
||||
memoryNode,
|
||||
ecParity,
|
||||
ecParityChoices,
|
||||
cleanECChoices,
|
||||
resourcesSize,
|
||||
distribution,
|
||||
ecParityCalc,
|
||||
cpuToUse,
|
||||
maxCPUsUse,
|
||||
integrationSelection,
|
||||
limitSize: createTenant.limitSize,
|
||||
selectedStorageType: createTenant.fields.nameTenant.selectedStorageType,
|
||||
};
|
||||
};
|
||||
|
||||
const connector = connect(mapState, {
|
||||
updateAddField,
|
||||
isPageValid,
|
||||
});
|
||||
|
||||
export default withStyles(styles)(connector(TenantSizeMK));
|
||||
@@ -0,0 +1,400 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// 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, useCallback, useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import get from "lodash/get";
|
||||
import { AppState } from "../../../../../../store";
|
||||
import { isPageValid, updateAddField } from "../../../actions";
|
||||
import {
|
||||
formFieldStyles,
|
||||
modalBasic,
|
||||
wizardCommon,
|
||||
} from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { IResourcesSize } from "../../../ListTenants/types";
|
||||
import { AllocableResourcesResponse } from "../../../types";
|
||||
import api from "../../../../../../common/api";
|
||||
import InputBoxWrapper from "../../../../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
|
||||
import FormSwitchWrapper from "../../../../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
|
||||
import { floor } from "lodash";
|
||||
|
||||
interface ITenantSizeResourcesProps {
|
||||
classes: any;
|
||||
updateAddField: typeof updateAddField;
|
||||
isPageValid: typeof isPageValid;
|
||||
nodes: string;
|
||||
resourcesSize: IResourcesSize;
|
||||
selectedStorageClass: string;
|
||||
maxAllocatableResources: AllocableResourcesResponse;
|
||||
maxCPUsUse: string;
|
||||
maxMemorySize: string;
|
||||
|
||||
resourcesSpecifyLimit: boolean;
|
||||
resourcesCPURequestError: string;
|
||||
resourcesCPURequest: string;
|
||||
resourcesCPULimitError: string;
|
||||
resourcesCPULimit: string;
|
||||
resourcesMemoryRequestError: string;
|
||||
resourcesMemoryRequest: string;
|
||||
resourcesMemoryLimitError: string;
|
||||
resourcesMemoryLimit: string;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
compositeFieldContainer: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
compositeAddOn: {
|
||||
marginLeft: 10,
|
||||
"& div": {
|
||||
marginBottom: 0,
|
||||
},
|
||||
"@media (max-width: 900px)": {
|
||||
"& div": {
|
||||
marginTop: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
...formFieldStyles,
|
||||
...modalBasic,
|
||||
...wizardCommon,
|
||||
});
|
||||
|
||||
const TenantSizeResources = ({
|
||||
classes,
|
||||
updateAddField,
|
||||
isPageValid,
|
||||
nodes,
|
||||
|
||||
resourcesSize,
|
||||
selectedStorageClass,
|
||||
maxAllocatableResources,
|
||||
maxCPUsUse,
|
||||
maxMemorySize,
|
||||
resourcesSpecifyLimit,
|
||||
resourcesCPURequestError,
|
||||
resourcesCPURequest,
|
||||
resourcesCPULimitError,
|
||||
resourcesCPULimit,
|
||||
resourcesMemoryRequestError,
|
||||
resourcesMemoryRequest,
|
||||
resourcesMemoryLimitError,
|
||||
resourcesMemoryLimit,
|
||||
}: ITenantSizeResourcesProps) => {
|
||||
// Common
|
||||
const updateField = useCallback(
|
||||
(field: string, value: any) => {
|
||||
updateAddField("tenantSize", field, value);
|
||||
},
|
||||
[updateAddField]
|
||||
);
|
||||
|
||||
/*Debounce functions*/
|
||||
|
||||
useEffect(() => {
|
||||
isPageValid(
|
||||
"tenantSize",
|
||||
resourcesMemoryRequestError === "" &&
|
||||
resourcesMemoryLimitError === "" &&
|
||||
resourcesCPURequestError === "" &&
|
||||
resourcesCPULimitError === ""
|
||||
);
|
||||
}, [
|
||||
isPageValid,
|
||||
resourcesMemoryRequestError,
|
||||
resourcesMemoryLimitError,
|
||||
resourcesCPURequestError,
|
||||
resourcesCPULimitError,
|
||||
]);
|
||||
|
||||
/*End debounce functions*/
|
||||
|
||||
/*Calculate Allocation*/
|
||||
useEffect(() => {
|
||||
// Get allocatable Resources
|
||||
api
|
||||
.invoke("GET", `api/v1/cluster/allocatable-resources?num_nodes=${nodes}`)
|
||||
.then((res: AllocableResourcesResponse) => {
|
||||
updateField("maxAllocatableResources", res);
|
||||
|
||||
const maxAllocatableResources = res;
|
||||
|
||||
const memoryExists = get(
|
||||
maxAllocatableResources,
|
||||
"min_allocatable_mem",
|
||||
false
|
||||
);
|
||||
|
||||
const cpuExists = get(
|
||||
maxAllocatableResources,
|
||||
"min_allocatable_cpu",
|
||||
false
|
||||
);
|
||||
|
||||
if (memoryExists === false || cpuExists === false) {
|
||||
updateField("cpuToUse", 0);
|
||||
|
||||
updateField("maxMemorySize", "");
|
||||
updateField("maxCPUsUse", "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const maxMemory = floor(
|
||||
res.mem_priority.max_allocatable_mem / 1024 / 1024 / 1024
|
||||
);
|
||||
// We default to Best CPU Configuration
|
||||
updateField("maxMemorySize", maxMemory.toString());
|
||||
updateField(
|
||||
"maxCPUsUse",
|
||||
res.cpu_priority.max_allocatable_cpu.toString()
|
||||
);
|
||||
|
||||
const maxAllocatableCPU = get(
|
||||
maxAllocatableResources,
|
||||
"cpu_priority.max_allocatable_cpu",
|
||||
0
|
||||
);
|
||||
|
||||
const baseCpuUse = Math.max(1, floor(maxAllocatableCPU / 2));
|
||||
updateField("resourcesCPURequest", baseCpuUse);
|
||||
|
||||
const baseMemoryUse = Math.max(2, floor(maxMemory / 2));
|
||||
updateField("resourcesMemoryRequest", baseMemoryUse);
|
||||
})
|
||||
.catch((err: any) => {
|
||||
updateField("maxMemorySize", 0);
|
||||
updateField("resourcesCPURequest", "");
|
||||
|
||||
console.error(err);
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [nodes, updateField]);
|
||||
|
||||
/*Calculate Allocation End*/
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.headerElement}>
|
||||
<h3 className={classes.h3Section}>Resources</h3>
|
||||
<span className={classes.descriptionText}>
|
||||
You may specify the amount of CPU and Memory that MinIO servers
|
||||
should reserve on each node.
|
||||
</span>
|
||||
</div>
|
||||
</Grid>
|
||||
{resourcesSize.error !== "" && (
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.error}>{resourcesSize.error}</div>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
label={"CPU Request"}
|
||||
id={"resourcesCPURequest"}
|
||||
name={"resourcesCPURequest"}
|
||||
onChange={(e) => {
|
||||
let value = parseInt(e.target.value);
|
||||
if (e.target.value === "") {
|
||||
updateField("resourcesCPURequestError", "");
|
||||
} else if (isNaN(value)) {
|
||||
updateField("resourcesCPURequestError", "Invalid number");
|
||||
} else if (value > parseInt(maxCPUsUse)) {
|
||||
updateField(
|
||||
"resourcesCPURequestError",
|
||||
`Request exceeds available cores (${maxCPUsUse})`
|
||||
);
|
||||
} else if (e.target.validity.valid) {
|
||||
updateField("resourcesCPURequestError", "");
|
||||
} else {
|
||||
updateField("resourcesCPURequestError", "Invalid configuration");
|
||||
}
|
||||
updateField("resourcesCPURequest", e.target.value);
|
||||
}}
|
||||
value={resourcesCPURequest}
|
||||
disabled={selectedStorageClass === ""}
|
||||
max={maxCPUsUse}
|
||||
error={resourcesCPURequestError}
|
||||
pattern={"[0-9]*"}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id="resourcesMemoryRequest"
|
||||
name="resourcesMemoryRequest"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let value = parseInt(e.target.value);
|
||||
if (e.target.value === "") {
|
||||
updateField("resourcesMemoryRequestError", "");
|
||||
} else if (isNaN(value)) {
|
||||
updateField("resourcesMemoryRequestError", "Invalid number");
|
||||
} else if (value > parseInt(maxMemorySize)) {
|
||||
updateField(
|
||||
"resourcesMemoryRequestError",
|
||||
`Request exceeds available memory across ${nodes} nodes (${maxMemorySize}Gi)`
|
||||
);
|
||||
} else if (value < 2) {
|
||||
updateField(
|
||||
"resourcesMemoryRequestError",
|
||||
"At least 2Gi must be requested"
|
||||
);
|
||||
} else if (e.target.validity.valid) {
|
||||
updateField("resourcesMemoryRequestError", "");
|
||||
} else {
|
||||
updateField(
|
||||
"resourcesMemoryRequestError",
|
||||
"Invalid configuration"
|
||||
);
|
||||
}
|
||||
updateField("resourcesMemoryRequest", e.target.value);
|
||||
}}
|
||||
label="Memory Request [Gi]"
|
||||
value={resourcesMemoryRequest}
|
||||
disabled={selectedStorageClass === ""}
|
||||
error={resourcesMemoryRequestError}
|
||||
pattern={"[0-9]*"}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<FormSwitchWrapper
|
||||
value="resourcesSpecifyLimit"
|
||||
id="resourcesSpecifyLimit"
|
||||
name="resourcesSpecifyLimit"
|
||||
checked={resourcesSpecifyLimit}
|
||||
onChange={(e) => {
|
||||
const targetD = e.target;
|
||||
const checked = targetD.checked;
|
||||
|
||||
updateField("resourcesSpecifyLimit", checked);
|
||||
}}
|
||||
label={"Specify Limit"}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{resourcesSpecifyLimit && (
|
||||
<Fragment>
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
label={"CPU Limit"}
|
||||
id={"resourcesCPULimit"}
|
||||
name={"resourcesCPULimit"}
|
||||
onChange={(e) => {
|
||||
let value = parseInt(e.target.value);
|
||||
if (e.target.value === "") {
|
||||
updateField("resourcesCPULimitError", "");
|
||||
} else if (isNaN(value)) {
|
||||
updateField("resourcesCPULimitError", "Invalid number");
|
||||
} else if (e.target.validity.valid) {
|
||||
updateField("resourcesCPULimitError", "");
|
||||
} else {
|
||||
updateField(
|
||||
"resourcesCPULimitError",
|
||||
"Invalid configuration"
|
||||
);
|
||||
}
|
||||
updateField("resourcesCPULimit", e.target.value);
|
||||
}}
|
||||
value={resourcesCPULimit}
|
||||
disabled={selectedStorageClass === ""}
|
||||
max={maxCPUsUse}
|
||||
error={resourcesCPULimitError}
|
||||
pattern={"[0-9]*"}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.formFieldRow}>
|
||||
<InputBoxWrapper
|
||||
id="resourcesMemoryLimit"
|
||||
name="resourcesMemoryLimit"
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let value = parseInt(e.target.value);
|
||||
console.log("value", value);
|
||||
if (e.target.value === "") {
|
||||
updateField("resourcesMemoryLimitError", "");
|
||||
} else if (isNaN(value)) {
|
||||
updateField("resourcesMemoryLimitError", "Invalid number");
|
||||
} else if (e.target.validity.valid) {
|
||||
updateField("resourcesMemoryLimitError", "");
|
||||
} else {
|
||||
updateField(
|
||||
"resourcesMemoryLimitError",
|
||||
"Invalid configuration"
|
||||
);
|
||||
}
|
||||
updateField("resourcesMemoryLimit", e.target.value);
|
||||
}}
|
||||
label="Memory Limit [Gi]"
|
||||
value={resourcesMemoryLimit}
|
||||
disabled={selectedStorageClass === ""}
|
||||
error={resourcesMemoryLimitError}
|
||||
pattern={"[0-9]*"}
|
||||
/>
|
||||
</Grid>
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const mapState = (state: AppState) => ({
|
||||
nodes: state.tenants.createTenant.fields.tenantSize.nodes,
|
||||
|
||||
resourcesSize: state.tenants.createTenant.fields.tenantSize.resourcesSize,
|
||||
selectedStorageClass:
|
||||
state.tenants.createTenant.fields.nameTenant.selectedStorageClass,
|
||||
maxAllocatableResources:
|
||||
state.tenants.createTenant.fields.tenantSize.maxAllocatableResources,
|
||||
maxCPUsUse: state.tenants.createTenant.fields.tenantSize.maxCPUsUse,
|
||||
maxMemorySize: state.tenants.createTenant.fields.tenantSize.maxMemorySize,
|
||||
|
||||
resourcesSpecifyLimit:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesSpecifyLimit,
|
||||
|
||||
resourcesCPURequestError:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesCPURequestError,
|
||||
resourcesCPURequest:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesCPURequest,
|
||||
resourcesCPULimitError:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesCPULimitError,
|
||||
resourcesCPULimit:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesCPULimit,
|
||||
|
||||
resourcesMemoryRequestError:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesMemoryRequestError,
|
||||
resourcesMemoryRequest:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesMemoryRequest,
|
||||
resourcesMemoryLimitError:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesMemoryLimitError,
|
||||
resourcesMemoryLimit:
|
||||
state.tenants.createTenant.fields.tenantSize.resourcesMemoryLimit,
|
||||
});
|
||||
|
||||
const connector = connect(mapState, {
|
||||
updateAddField,
|
||||
isPageValid,
|
||||
});
|
||||
|
||||
export default withStyles(styles)(connector(TenantSizeResources));
|
||||
@@ -0,0 +1,84 @@
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2021 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// 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 from "react";
|
||||
import { Opts } from "../../../ListTenants/utils";
|
||||
import TenantSizeMK from "./TenantSizeMK";
|
||||
|
||||
export enum IMkEnvs {
|
||||
"aws",
|
||||
"azure",
|
||||
"gcs",
|
||||
"default",
|
||||
undefined,
|
||||
}
|
||||
|
||||
export interface IDriveSizing {
|
||||
driveSize: string;
|
||||
sizeUnit: string;
|
||||
}
|
||||
|
||||
export interface IntegrationConfiguration {
|
||||
typeSelection: string;
|
||||
storageClass: string;
|
||||
CPU: number;
|
||||
memory: number;
|
||||
drivesPerServer: number;
|
||||
driveSize: IDriveSizing;
|
||||
}
|
||||
|
||||
export const AWSStorageTypes: Opts[] = [
|
||||
{ label: "NVME", value: "nvme" },
|
||||
{ label: "HDD", value: "hdd" },
|
||||
];
|
||||
|
||||
export const resourcesConfigurations = {
|
||||
"mp-mode-aws": IMkEnvs.aws,
|
||||
"mp-mode-azure": IMkEnvs.azure,
|
||||
"mp-mode-gcs": IMkEnvs.gcs,
|
||||
};
|
||||
|
||||
export const AWSConfigurations: IntegrationConfiguration[] = [
|
||||
{
|
||||
typeSelection: "nvme",
|
||||
storageClass: "nvme-i3en-12xlarge",
|
||||
CPU: 48,
|
||||
memory: 384,
|
||||
driveSize: { driveSize: "7500", sizeUnit: "Gi" },
|
||||
drivesPerServer: 4,
|
||||
},
|
||||
{
|
||||
typeSelection: "hdd",
|
||||
storageClass: "hdd-d3en-12xlarge",
|
||||
CPU: 8,
|
||||
memory: 32,
|
||||
driveSize: { driveSize: "12.7", sizeUnit: "Ti" },
|
||||
drivesPerServer: 4,
|
||||
},
|
||||
];
|
||||
|
||||
export const mkPanelConfigurations = {
|
||||
[IMkEnvs.aws]: {
|
||||
variantSelectorLabel: "Storage Type",
|
||||
variantSelectorValues: AWSStorageTypes,
|
||||
configurations: AWSConfigurations,
|
||||
sizingComponent: <TenantSizeMK formToRender={IMkEnvs.aws} />,
|
||||
},
|
||||
[IMkEnvs.azure]: {},
|
||||
[IMkEnvs.gcs]: {},
|
||||
[IMkEnvs.default]: {},
|
||||
[IMkEnvs.undefined]: {},
|
||||
};
|
||||
@@ -17,32 +17,31 @@
|
||||
import { ITenant } from "./ListTenants/types";
|
||||
import { Opts } from "./ListTenants/utils";
|
||||
import {
|
||||
ADD_TENANT_SET_ADVANCED_MODE,
|
||||
ADD_TENANT_ADD_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_CONSOLE_CERT,
|
||||
ADD_TENANT_ADD_FILE_TO_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_MINIO_KEYPAIR,
|
||||
ADD_TENANT_ADD_MINIO_KEYPAIR,
|
||||
ADD_TENANT_DELETE_CA_KEYPAIR,
|
||||
ADD_TENANT_DELETE_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_DELETE_MINIO_KEYPAIR,
|
||||
ADD_TENANT_ENCRYPTION_CLIENT_CERT,
|
||||
ADD_TENANT_ENCRYPTION_GEMALTO_CA,
|
||||
ADD_TENANT_ENCRYPTION_SERVER_CERT,
|
||||
ADD_TENANT_ENCRYPTION_VAULT_CA,
|
||||
ADD_TENANT_ENCRYPTION_VAULT_CERT,
|
||||
ADD_TENANT_RESET_FORM,
|
||||
ADD_TENANT_SET_CURRENT_PAGE,
|
||||
ADD_TENANT_UPDATE_FIELD,
|
||||
ADD_TENANT_SET_LIMIT_SIZE,
|
||||
ADD_TENANT_SET_PAGE_VALID,
|
||||
ADD_TENANT_SET_STORAGE_CLASSES_LIST,
|
||||
ADD_TENANT_SET_LIMIT_SIZE,
|
||||
ADD_TENANT_ADD_CA_KEYPAIR,
|
||||
ADD_TENANT_DELETE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_MINIO_KEYPAIR,
|
||||
ADD_TENANT_DELETE_MINIO_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_MINIO_KEYPAIR,
|
||||
ADD_TENANT_ADD_CONSOLE_CERT,
|
||||
ADD_TENANT_ADD_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_DELETE_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_ENCRYPTION_SERVER_CERT,
|
||||
ADD_TENANT_ENCRYPTION_CLIENT_CERT,
|
||||
ADD_TENANT_ENCRYPTION_VAULT_CERT,
|
||||
ADD_TENANT_ENCRYPTION_VAULT_CA,
|
||||
ADD_TENANT_ENCRYPTION_GEMALTO_CA,
|
||||
ADD_TENANT_RESET_FORM,
|
||||
TENANT_DETAILS_SET_LOADING,
|
||||
TENANT_DETAILS_SET_TENANT,
|
||||
ADD_TENANT_UPDATE_FIELD,
|
||||
TENANT_DETAILS_SET_CURRENT_TENANT,
|
||||
TENANT_DETAILS_SET_LOADING,
|
||||
TENANT_DETAILS_SET_TAB,
|
||||
TENANT_DETAILS_SET_TENANT,
|
||||
} from "./types";
|
||||
|
||||
// Basic actions
|
||||
@@ -53,13 +52,6 @@ export const setWizardPage = (page: number) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const setAdvancedMode = (state: boolean) => {
|
||||
return {
|
||||
type: ADD_TENANT_SET_ADVANCED_MODE,
|
||||
state,
|
||||
};
|
||||
};
|
||||
|
||||
export const updateAddField = (
|
||||
pageName: string,
|
||||
fieldName: string,
|
||||
|
||||
@@ -16,34 +16,33 @@
|
||||
import has from "lodash/has";
|
||||
import get from "lodash/get";
|
||||
import {
|
||||
TenantsManagementTypes,
|
||||
ITenantState,
|
||||
ADD_TENANT_ADD_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_CONSOLE_CERT,
|
||||
ADD_TENANT_ADD_FILE_TO_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_MINIO_KEYPAIR,
|
||||
ADD_TENANT_ADD_MINIO_KEYPAIR,
|
||||
ADD_TENANT_DELETE_CA_KEYPAIR,
|
||||
ADD_TENANT_DELETE_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_DELETE_MINIO_KEYPAIR,
|
||||
ADD_TENANT_ENCRYPTION_CLIENT_CERT,
|
||||
ADD_TENANT_ENCRYPTION_GEMALTO_CA,
|
||||
ADD_TENANT_ENCRYPTION_SERVER_CERT,
|
||||
ADD_TENANT_ENCRYPTION_VAULT_CA,
|
||||
ADD_TENANT_ENCRYPTION_VAULT_CERT,
|
||||
ADD_TENANT_RESET_FORM,
|
||||
ADD_TENANT_SET_CURRENT_PAGE,
|
||||
ADD_TENANT_SET_ADVANCED_MODE,
|
||||
ADD_TENANT_UPDATE_FIELD,
|
||||
ADD_TENANT_SET_LIMIT_SIZE,
|
||||
ADD_TENANT_SET_PAGE_VALID,
|
||||
ADD_TENANT_SET_STORAGE_CLASSES_LIST,
|
||||
ADD_TENANT_ADD_MINIO_KEYPAIR,
|
||||
ADD_TENANT_DELETE_MINIO_KEYPAIR,
|
||||
ADD_TENANT_ADD_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_CA_KEYPAIR,
|
||||
ADD_TENANT_DELETE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_CONSOLE_CERT,
|
||||
ADD_TENANT_ADD_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_DELETE_CONSOLE_CA_KEYPAIR,
|
||||
ADD_TENANT_ADD_FILE_TO_MINIO_KEYPAIR,
|
||||
ADD_TENANT_ENCRYPTION_SERVER_CERT,
|
||||
ADD_TENANT_ENCRYPTION_CLIENT_CERT,
|
||||
ADD_TENANT_ENCRYPTION_VAULT_CERT,
|
||||
ADD_TENANT_ENCRYPTION_VAULT_CA,
|
||||
ADD_TENANT_ENCRYPTION_GEMALTO_CA,
|
||||
ADD_TENANT_RESET_FORM,
|
||||
ADD_TENANT_SET_LIMIT_SIZE,
|
||||
TENANT_DETAILS_SET_LOADING,
|
||||
ADD_TENANT_UPDATE_FIELD,
|
||||
ITenantState,
|
||||
TENANT_DETAILS_SET_CURRENT_TENANT,
|
||||
TENANT_DETAILS_SET_TENANT,
|
||||
TENANT_DETAILS_SET_LOADING,
|
||||
TENANT_DETAILS_SET_TAB,
|
||||
TENANT_DETAILS_SET_TENANT,
|
||||
TenantsManagementTypes,
|
||||
} from "./types";
|
||||
import { KeyPair } from "./ListTenants/utils";
|
||||
import { getRandomString } from "./utils";
|
||||
@@ -61,7 +60,6 @@ const initialState: ITenantState = {
|
||||
"security",
|
||||
"encryption",
|
||||
],
|
||||
advancedModeOn: false,
|
||||
storageClasses: [],
|
||||
limitSize: {},
|
||||
fields: {
|
||||
@@ -69,6 +67,7 @@ const initialState: ITenantState = {
|
||||
tenantName: "",
|
||||
namespace: "",
|
||||
selectedStorageClass: "",
|
||||
selectedStorageType: "",
|
||||
},
|
||||
configure: {
|
||||
customImage: true,
|
||||
@@ -90,8 +89,8 @@ const initialState: ITenantState = {
|
||||
logSearchPostgresInitImage: "",
|
||||
prometheusVolumeSize: "5",
|
||||
prometheusSizeFactor: "Gi",
|
||||
logSearchSelectedStorageClass: "",
|
||||
prometheusSelectedStorageClass: "",
|
||||
logSearchSelectedStorageClass: "default",
|
||||
prometheusSelectedStorageClass: "default",
|
||||
prometheusImage: "",
|
||||
prometheusSidecarImage: "",
|
||||
prometheusInitImage: "",
|
||||
@@ -200,8 +199,17 @@ const initialState: ITenantState = {
|
||||
ecParity: "",
|
||||
ecParityChoices: [],
|
||||
cleanECChoices: [],
|
||||
maxAllocableMemo: 0,
|
||||
cpuToUse: "0",
|
||||
// resource request
|
||||
resourcesSpecifyLimit: false,
|
||||
resourcesCPURequestError: "",
|
||||
resourcesCPURequest: "",
|
||||
resourcesCPULimitError: "",
|
||||
resourcesCPULimit: "",
|
||||
resourcesMemoryRequestError: "",
|
||||
resourcesMemoryRequest: "",
|
||||
resourcesMemoryLimitError: "",
|
||||
resourcesMemoryLimit: "",
|
||||
resourcesSize: {
|
||||
error: "",
|
||||
memoryRequest: 0,
|
||||
@@ -214,7 +222,6 @@ const initialState: ITenantState = {
|
||||
nodes: 0,
|
||||
persistentVolumes: 0,
|
||||
disks: 0,
|
||||
volumePerDisk: 0,
|
||||
},
|
||||
ecParityCalc: {
|
||||
error: 0,
|
||||
@@ -239,6 +246,14 @@ const initialState: ITenantState = {
|
||||
},
|
||||
maxCPUsUse: "0",
|
||||
maxMemorySize: "0",
|
||||
integrationSelection: {
|
||||
driveSize: { driveSize: "0", sizeUnit: "B" },
|
||||
CPU: 0,
|
||||
typeSelection: "",
|
||||
memory: 0,
|
||||
drivesPerServer: 0,
|
||||
storageClass: "",
|
||||
},
|
||||
},
|
||||
affinity: {
|
||||
nodeSelectorLabels: "",
|
||||
@@ -338,10 +353,7 @@ export function tenantsReducer(
|
||||
newState.createTenant.page = action.page;
|
||||
|
||||
return { ...newState };
|
||||
case ADD_TENANT_SET_ADVANCED_MODE:
|
||||
newState.createTenant.advancedModeOn = action.state;
|
||||
|
||||
return { ...newState };
|
||||
case ADD_TENANT_UPDATE_FIELD:
|
||||
if (
|
||||
has(newState.createTenant.fields, `${action.pageName}.${action.field}`)
|
||||
@@ -599,7 +611,6 @@ export function tenantsReducer(
|
||||
"security",
|
||||
"encryption",
|
||||
],
|
||||
advancedModeOn: false,
|
||||
storageClasses: [],
|
||||
limitSize: {},
|
||||
fields: {
|
||||
@@ -607,6 +618,7 @@ export function tenantsReducer(
|
||||
tenantName: "",
|
||||
namespace: "",
|
||||
selectedStorageClass: "",
|
||||
selectedStorageType: "",
|
||||
},
|
||||
configure: {
|
||||
customImage: false,
|
||||
@@ -622,14 +634,14 @@ export function tenantsReducer(
|
||||
prometheusCustom: false,
|
||||
logSearchVolumeSize: "5",
|
||||
logSearchSizeFactor: "Gi",
|
||||
logSearchSelectedStorageClass: "",
|
||||
logSearchSelectedStorageClass: "default",
|
||||
logSearchImage: "",
|
||||
kesImage: "",
|
||||
logSearchPostgresImage: "",
|
||||
logSearchPostgresInitImage: "",
|
||||
prometheusVolumeSize: "5",
|
||||
prometheusSizeFactor: "Gi",
|
||||
prometheusSelectedStorageClass: "",
|
||||
prometheusSelectedStorageClass: "default",
|
||||
prometheusImage: "",
|
||||
prometheusSidecarImage: "",
|
||||
prometheusInitImage: "",
|
||||
@@ -738,13 +750,11 @@ export function tenantsReducer(
|
||||
ecParity: "",
|
||||
ecParityChoices: [],
|
||||
cleanECChoices: [],
|
||||
maxAllocableMemo: 0,
|
||||
distribution: {
|
||||
error: "",
|
||||
nodes: 0,
|
||||
persistentVolumes: 0,
|
||||
disks: 0,
|
||||
volumePerDisk: 0,
|
||||
},
|
||||
ecParityCalc: {
|
||||
error: 0,
|
||||
@@ -756,6 +766,16 @@ export function tenantsReducer(
|
||||
},
|
||||
limitSize: {},
|
||||
cpuToUse: "0",
|
||||
// resource request
|
||||
resourcesSpecifyLimit: false,
|
||||
resourcesCPURequestError: "",
|
||||
resourcesCPURequest: "",
|
||||
resourcesCPULimitError: "",
|
||||
resourcesCPULimit: "",
|
||||
resourcesMemoryRequestError: "",
|
||||
resourcesMemoryRequest: "",
|
||||
resourcesMemoryLimitError: "",
|
||||
resourcesMemoryLimit: "",
|
||||
resourcesSize: {
|
||||
error: "",
|
||||
memoryRequest: 0,
|
||||
@@ -777,6 +797,14 @@ export function tenantsReducer(
|
||||
},
|
||||
maxCPUsUse: "0",
|
||||
maxMemorySize: "0",
|
||||
integrationSelection: {
|
||||
driveSize: { driveSize: "0", sizeUnit: "B" },
|
||||
CPU: 0,
|
||||
typeSelection: "",
|
||||
memory: 0,
|
||||
drivesPerServer: 0,
|
||||
storageClass: "",
|
||||
},
|
||||
},
|
||||
affinity: {
|
||||
nodeSelectorLabels: "",
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { IErasureCodeCalc } from "../../../common/types";
|
||||
import { ITenant, IResourcesSize } from "./ListTenants/types";
|
||||
import { IResourcesSize, ITenant } from "./ListTenants/types";
|
||||
import { KeyPair, Opts } from "./ListTenants/utils";
|
||||
import { IntegrationConfiguration } from "./AddTenant/Steps/TenantResources/utils";
|
||||
|
||||
export const ADD_TENANT_SET_CURRENT_PAGE = "ADD_TENANT/SET_CURRENT_PAGE";
|
||||
export const ADD_TENANT_SET_ADVANCED_MODE = "ADD_TENANT/SET_ADVANCED_MODE";
|
||||
@@ -64,6 +65,7 @@ export const TENANT_DETAILS_SET_CURRENT_TENANT =
|
||||
"TENANT_DETAILS/SET_CURRENT_TENANT";
|
||||
export const TENANT_DETAILS_SET_TENANT = "TENANT_DETAILS/SET_TENANT";
|
||||
export const TENANT_DETAILS_SET_TAB = "TENANT_DETAILS/SET_TAB";
|
||||
|
||||
export interface ICertificateInfo {
|
||||
name: string;
|
||||
serialNumber: string;
|
||||
@@ -86,7 +88,6 @@ export interface ITenantSecurityResponse {
|
||||
export interface ICreateTenant {
|
||||
page: number;
|
||||
validPages: string[];
|
||||
advancedModeOn: boolean;
|
||||
storageClasses: Opts[];
|
||||
limitSize: any;
|
||||
fields: IFieldStore;
|
||||
@@ -119,6 +120,7 @@ export interface INameTenantFields {
|
||||
tenantName: string;
|
||||
namespace: string;
|
||||
selectedStorageClass: string;
|
||||
selectedStorageType: string;
|
||||
}
|
||||
|
||||
export interface ISecurityContext {
|
||||
@@ -237,7 +239,6 @@ export interface ITenantSizeFields {
|
||||
ecParity: string;
|
||||
ecParityChoices: Opts[];
|
||||
cleanECChoices: string[];
|
||||
maxAllocableMemo: number;
|
||||
resourcesSize: IResourcesSize;
|
||||
distribution: any;
|
||||
ecParityCalc: IErasureCodeCalc;
|
||||
@@ -246,6 +247,19 @@ export interface ITenantSizeFields {
|
||||
maxAllocatableResources: AllocableResourcesResponse;
|
||||
maxCPUsUse: string;
|
||||
maxMemorySize: string;
|
||||
integrationSelection: IntegrationConfiguration;
|
||||
|
||||
resourcesSpecifyLimit: boolean;
|
||||
|
||||
resourcesCPURequestError: string;
|
||||
resourcesCPURequest: string;
|
||||
resourcesCPULimitError: string;
|
||||
resourcesCPULimit: string;
|
||||
|
||||
resourcesMemoryRequestError: string;
|
||||
resourcesMemoryRequest: string;
|
||||
resourcesMemoryLimitError: string;
|
||||
resourcesMemoryLimit: string;
|
||||
}
|
||||
|
||||
export interface ITenantAffinity {
|
||||
@@ -289,11 +303,6 @@ interface SetTenantWizardPage {
|
||||
page: number;
|
||||
}
|
||||
|
||||
interface SetAdvancedMode {
|
||||
type: typeof ADD_TENANT_SET_ADVANCED_MODE;
|
||||
state: boolean;
|
||||
}
|
||||
|
||||
interface UpdateATField {
|
||||
type: typeof ADD_TENANT_UPDATE_FIELD;
|
||||
pageName: keyof IFieldStore;
|
||||
@@ -333,6 +342,7 @@ interface DeleteMinioKeyPair {
|
||||
type: typeof ADD_TENANT_DELETE_MINIO_KEYPAIR;
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface AddCAKeyPair {
|
||||
type: typeof ADD_TENANT_ADD_CA_KEYPAIR;
|
||||
}
|
||||
@@ -349,6 +359,7 @@ interface DeleteCAKeyPair {
|
||||
type: typeof ADD_TENANT_DELETE_CA_KEYPAIR;
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface AddConsoleCAKeyPair {
|
||||
type: typeof ADD_TENANT_ADD_CONSOLE_CA_KEYPAIR;
|
||||
}
|
||||
@@ -436,7 +447,6 @@ export type FieldsToHandle = INameTenantFields;
|
||||
|
||||
export type TenantsManagementTypes =
|
||||
| SetTenantWizardPage
|
||||
| SetAdvancedMode
|
||||
| UpdateATField
|
||||
| SetPageValid
|
||||
| SetStorageClassesList
|
||||
|
||||
@@ -998,6 +998,10 @@ definitions:
|
||||
operatorSessionResponse:
|
||||
type: object
|
||||
properties:
|
||||
features:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
enum: [ok]
|
||||
|
||||
Reference in New Issue
Block a user