Files
object-browser/portal-ui/src/common/utils.ts
Alex a2180e123d Removed warnings on console (#345)
For Operator modules this will be removed after upgrading component to use redux/formik

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
2020-10-24 00:05:26 -07:00

338 lines
8.8 KiB
TypeScript

// This file is part of MinIO Console Server
// Copyright (c) 2020 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 storage from "local-storage-fallback";
import { ICapacity, IZoneModel } from "./types";
const minStReq = 1073741824; // Minimal Space required for MinIO
const minMemReq = 2147483648; // Minimal Memory required for MinIO in bytes
export const units = [
"B",
"KiB",
"MiB",
"GiB",
"TiB",
"PiB",
"EiB",
"ZiB",
"YiB",
];
export const k8sUnits = ["Ki", "Mi", "Gi", "Ti", "Pi", "Ei"];
export const k8sCalcUnits = ["B", ...k8sUnits];
export const niceBytes = (x: string) => {
let l = 0,
n = parseInt(x, 10) || 0;
while (n >= 1024 && ++l) {
n = n / 1024;
}
//include a decimal point and a tenths-place digit if presenting
//less than ten of KB or greater units
return n.toFixed(n < 10 && l > 0 ? 1 : 0) + " " + units[l];
};
export const setCookie = (name: string, val: string) => {
const date = new Date();
const value = val;
// Set it expire in 45 minutes
date.setTime(date.getTime() + 45 * 60 * 1000);
// Set it
document.cookie =
name + "=" + value + "; expires=" + date.toUTCString() + "; path=/";
};
export const deleteCookie = (name: string) => {
document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT;";
};
export const setSession = (token: string) => {
setCookie("token", token);
storage.setItem("token", token);
};
export const clearSession = () => {
storage.removeItem("token");
deleteCookie("token");
};
// timeFromdate gets time string from date input
export const timeFromDate = (d: Date) => {
let h = d.getHours() < 10 ? `0${d.getHours()}` : `${d.getHours()}`;
let m = d.getMinutes() < 10 ? `0${d.getMinutes()}` : `${d.getMinutes()}`;
let s = d.getSeconds() < 10 ? `0${d.getSeconds()}` : `${d.getSeconds()}`;
return `${h}:${m}:${s}:${d.getMilliseconds()}`;
};
// units to be used in a dropdown
export const factorForDropdown = () => {
return units.map((unit) => {
return { label: unit, value: unit };
});
};
// units to be used in a dropdown
export const k8sfactorForDropdown = () => {
return k8sUnits.map((unit) => {
return { label: unit, value: unit };
});
};
//getBytes, converts from a value and a unit from units array to bytes
export const getBytes = (
value: string,
unit: string,
fork8s: boolean = false
) => {
const vl: number = parseFloat(value);
const unitsTake = fork8s ? k8sCalcUnits : units;
const powFactor = unitsTake.findIndex((element) => element === unit);
if (powFactor === -1) {
return "0";
}
const factor = Math.pow(1024, powFactor);
const total = vl * factor;
return total.toString(10);
};
//getTotalSize gets the total size of a value & unit
export const getTotalSize = (value: string, unit: string) => {
const bytes = getBytes(value, unit, true).toString();
return niceBytes(bytes);
};
export const setMemoryResource = (
memorySize: number,
capacitySize: string,
maxMemorySize: number
) => {
// value always comes as Gi
const requestedSizeBytes = getBytes(memorySize.toString(10), "Gi", true);
const memReqSize = parseInt(requestedSizeBytes, 10);
if (maxMemorySize === 0) {
return {
error: "There is no memory available for the selected number of nodes",
request: 0,
limit: 0,
};
}
if (maxMemorySize < minMemReq) {
return {
error: "There are not enough memory resources available",
request: 0,
limit: 0,
};
}
if (memReqSize < minMemReq) {
return {
error: "The requested memory size must be greater than 2Gi",
request: 0,
limit: 0,
};
}
if (memReqSize > maxMemorySize) {
return {
error:
"The requested memory is greater than the max available memory for the selected number of nodes",
request: 0,
limit: 0,
};
}
const capSize = parseInt(capacitySize, 10);
let memLimitSize = memReqSize;
// set memory limit based on the capacitySize
// if capacity size is lower than 1TiB we use the limit equal to request
if (capSize >= parseInt(getBytes("1", "Pi", true), 10)) {
memLimitSize = Math.max(
memReqSize,
parseInt(getBytes("64", "Gi", true), 10)
);
} else if (capSize >= parseInt(getBytes("100", "Ti"), 10)) {
memLimitSize = Math.max(
memReqSize,
parseInt(getBytes("32", "Gi", true), 10)
);
} else if (capSize >= parseInt(getBytes("10", "Ti"), 10)) {
memLimitSize = Math.max(
memReqSize,
parseInt(getBytes("16", "Gi", true), 10)
);
} else if (capSize >= parseInt(getBytes("1", "Ti"), 10)) {
memLimitSize = Math.max(
memReqSize,
parseInt(getBytes("8", "Gi", true), 10)
);
}
return {
error: "",
request: memReqSize,
limit: memLimitSize,
};
};
export const calculateDistribution = (
capacityToUse: ICapacity,
forcedNodes: number = 0,
limitSize: number = 0
) => {
let numberOfNodes = {};
const requestedSizeBytes = getBytes(
capacityToUse.value,
capacityToUse.unit,
true
);
if (parseInt(requestedSizeBytes, 10) < minStReq) {
return {
error: "The zone size must be greater than 1Gi",
nodes: 0,
persistentVolumes: 0,
disks: 0,
pvSize: 0,
};
}
if (forcedNodes < 4) {
return {
error: "Number of nodes cannot be less than 4",
nodes: 0,
persistentVolumes: 0,
disks: 0,
pvSize: 0,
};
}
numberOfNodes = calculateStorage(requestedSizeBytes, forcedNodes, limitSize);
return numberOfNodes;
};
const calculateStorage = (
requestedBytes: string,
forcedNodes: number,
limitSize: number
) => {
// Size validation
const intReqBytes = parseInt(requestedBytes, 10);
const maxDiskSize = minStReq * 256; // 256 GiB
// We get the distribution
return structureCalc(forcedNodes, intReqBytes, maxDiskSize, limitSize);
};
const structureCalc = (
nodes: number,
desiredCapacity: number,
maxDiskSize: number,
maxClusterSize: number,
disksPerNode: number = 0
) => {
if (
isNaN(nodes) ||
isNaN(desiredCapacity) ||
isNaN(maxDiskSize) ||
isNaN(maxClusterSize)
) {
return {
error: "Some provided data is invalid, please try again.",
nodes: 0,
persistentVolumes: 0,
disks: 0,
volumePerDisk: 0,
}; // Invalid Data
}
let persistentVolumeSize = 0;
let numberPersistentVolumes = 0;
let volumesPerServer = 0;
if (disksPerNode === 0) {
persistentVolumeSize = Math.floor(
Math.min(desiredCapacity / Math.max(4, nodes), maxDiskSize)
); // pVS = min((desiredCapacity / max(4 | nodes)) | maxDiskSize)
numberPersistentVolumes = desiredCapacity / persistentVolumeSize; // nPV = dC / pVS
volumesPerServer = numberPersistentVolumes / nodes; // vPS = nPV / n
}
if (disksPerNode) {
volumesPerServer = disksPerNode;
numberPersistentVolumes = volumesPerServer * nodes;
persistentVolumeSize = Math.floor(
desiredCapacity / numberPersistentVolumes
);
}
// Volumes are not exact, we force the volumes number & minimize the volume size
if (volumesPerServer % 1 > 0) {
volumesPerServer = Math.ceil(volumesPerServer); // Increment of volumes per server
numberPersistentVolumes = volumesPerServer * nodes; // nPV = vPS * n
persistentVolumeSize = Math.floor(
desiredCapacity / numberPersistentVolumes
); // pVS = dC / nPV
const limitSize = persistentVolumeSize * volumesPerServer * nodes; // lS = pVS * vPS * n
if (limitSize > maxClusterSize) {
return {
error: "We were not able to allocate this server.",
nodes: 0,
persistentVolumes: 0,
disks: 0,
volumePerDisk: 0,
}; // Cannot allocate this server
}
}
if (persistentVolumeSize < minStReq) {
return {
error:
"Disk Size with this combination would be less than 1Gi, please try another combination",
nodes: 0,
persistentVolumes: 0,
disks: 0,
volumePerDisk: 0,
}; // Cannot allocate this volume size
}
return {
error: "",
nodes,
persistentVolumes: numberPersistentVolumes,
disks: volumesPerServer,
pvSize: persistentVolumeSize,
};
};
// Zone Name Generator
export const generateZoneName = (zones: IZoneModel[]) => {
const zoneCounter = zones.length;
return `zone-${zoneCounter}`;
};