fix(striker-ui): make filter logic work with multiple VDs

main
Tsu-ba-me 3 years ago
parent 1094ad7d20
commit 653f7e6609
  1. 131
      striker-ui/components/ProvisionServerDialog.tsx

@ -115,6 +115,45 @@ type OrganizedAnvilDetailMetadataForProvisionServer = Omit<
fileUUIDs: string[]; fileUUIDs: string[];
}; };
type FilterAnvilsFunction = (
organizedAnvils: OrganizedAnvilDetailMetadataForProvisionServer[],
storageGroupUUIDMapToFree: StorageGroupUUIDMapToFree,
cpuCores: number,
memory: bigint,
vdSizes: bigint[],
storageGroupUUIDs: string[],
fileUUIDs: string[],
options?: {
includeAnvilUUIDs?: string[];
includeStorageGroupUUIDs?: string[];
},
) => {
anvils: OrganizedAnvilDetailMetadataForProvisionServer[];
anvilUUIDs: string[];
fileUUIDs: string[];
maxCPUCores: number;
maxMemory: bigint;
maxVirtualDiskSizes: bigint[];
storageGroupUUIDs: string[];
};
type FilterAnvilsParameters = Parameters<FilterAnvilsFunction>;
type VirtualDiskStates = {
maxes: bigint[];
inputMaxes: string[];
inputSizes: string[];
inputStorageGroupUUIDs: string[];
inputUnits: DataSizeUnit[];
sizes: bigint[];
};
type UpdateLimitsFunction = (
filterArgs: FilterAnvilsParameters,
localInputMemoryUnit: DataSizeUnit,
localVirtualDisks: VirtualDiskStates,
) => void;
const MOCK_DATA = { const MOCK_DATA = {
anvils: [ anvils: [
{ {
@ -576,7 +615,7 @@ const dSizeToBytes = (
}); });
}; };
const filterAnvils = ( const filterAnvils: FilterAnvilsFunction = (
organizedAnvils: OrganizedAnvilDetailMetadataForProvisionServer[], organizedAnvils: OrganizedAnvilDetailMetadataForProvisionServer[],
storageGroupUUIDMapToFree: StorageGroupUUIDMapToFree, storageGroupUUIDMapToFree: StorageGroupUUIDMapToFree,
cpuCores: number, cpuCores: number,
@ -628,17 +667,16 @@ const filterAnvils = (
{ all: BIGINT_ZERO }, { all: BIGINT_ZERO },
); );
return organizedAnvils.reduce<{ const result = organizedAnvils.reduce<{
anvils: OrganizedAnvilDetailMetadataForProvisionServer[]; anvils: OrganizedAnvilDetailMetadataForProvisionServer[];
anvilUUIDs: string[]; anvilUUIDs: string[];
fileUUIDs: string[]; fileUUIDs: string[];
maxCPUCores: number; maxCPUCores: number;
maxMemory: bigint; maxMemory: bigint;
// Both of the following should be nested in an array; index maps to each virtual disk. maxVirtualDiskSizes: bigint[];
maxVirtualDiskSize: bigint;
storageGroupUUIDs: string[]; storageGroupUUIDs: string[];
}>( }>(
(result, organizedAnvil) => { (reduceContainer, organizedAnvil) => {
const { anvilUUID } = organizedAnvil; const { anvilUUID } = organizedAnvil;
if (testIncludeAnvil(anvilUUID)) { if (testIncludeAnvil(anvilUUID)) {
@ -651,7 +689,7 @@ const filterAnvils = (
} = organizedAnvil; } = organizedAnvil;
const anvilStorageGroupUUIDs: string[] = []; const anvilStorageGroupUUIDs: string[] = [];
let anvilMaxVDSize: bigint = result.maxVirtualDiskSize; let anvilStorageGroupFreeMax: bigint = BIGINT_ZERO;
let anvilStorageGroupFreeTotal: bigint = BIGINT_ZERO; let anvilStorageGroupFreeTotal: bigint = BIGINT_ZERO;
storageGroups.forEach(({ storageGroupUUID, storageGroupFree }) => { storageGroups.forEach(({ storageGroupUUID, storageGroupFree }) => {
@ -659,21 +697,29 @@ const filterAnvils = (
anvilStorageGroupUUIDs.push(storageGroupUUID); anvilStorageGroupUUIDs.push(storageGroupUUID);
anvilStorageGroupFreeTotal += storageGroupFree; anvilStorageGroupFreeTotal += storageGroupFree;
if (storageGroupFree > anvilMaxVDSize) { if (storageGroupFree > anvilStorageGroupFreeMax) {
anvilMaxVDSize = storageGroupFree; anvilStorageGroupFreeMax = storageGroupFree;
} }
} }
}); });
const usableTests: (() => boolean)[] = [ const usableTests: (() => boolean)[] = [
// Does this anvil node pair have at least one storage group?
() => storageGroups.length > 0, () => storageGroups.length > 0,
// Does this anvil node pair have enough CPU cores?
() => cpuCores <= anvilTotalCPUCores, () => cpuCores <= anvilTotalCPUCores,
// Does this anvil node pair have enough memory?
() => memory <= anvilTotalAvailableMemory, () => memory <= anvilTotalAvailableMemory,
// For every virtual disk:
// 1. Does this anvil node pair have the selected storage group which
// will contain the VD?
// 2. Does the selected storage group OR any storage group on this
// anvil node pair have enough free space?
() => () =>
storageGroupUUIDs.every((uuid, index) => { storageGroupUUIDs.every((uuid, index) => {
const vdSize = vdSizes[index] ?? BIGINT_ZERO; const vdSize = vdSizes[index] ?? BIGINT_ZERO;
let hasStorageGroup = true; let hasStorageGroup = true;
let hasEnoughStorage = vdSize <= anvilMaxVDSize; let hasEnoughStorage = vdSize <= anvilStorageGroupFreeMax;
if (uuid !== '') { if (uuid !== '') {
hasStorageGroup = anvilStorageGroupUUIDs.includes(uuid); hasStorageGroup = anvilStorageGroupUUIDs.includes(uuid);
@ -682,12 +728,15 @@ const filterAnvils = (
return hasStorageGroup && hasEnoughStorage; return hasStorageGroup && hasEnoughStorage;
}), }),
// Do storage groups on this anvil node pair have enough free space
// to contain multiple VDs?
() => () =>
Object.entries(storageGroupTotals).every(([uuid, total]) => Object.entries(storageGroupTotals).every(([uuid, total]) =>
uuid === 'all' uuid === 'all'
? total <= anvilStorageGroupFreeTotal ? total <= anvilStorageGroupFreeTotal
: total <= storageGroupUUIDMapToFree[uuid], : total <= storageGroupUUIDMapToFree[uuid],
), ),
// Does this anvil node pair have access to selected files?
() => () =>
fileUUIDs.every( fileUUIDs.every(
(fileUUID) => (fileUUID) =>
@ -695,28 +744,32 @@ const filterAnvils = (
), ),
]; ];
// If an anvil doesn't pass all tests, then it and its parts shouldn't be used.
if (usableTests.every((test) => test())) { if (usableTests.every((test) => test())) {
result.anvils.push(organizedAnvil); reduceContainer.anvils.push(organizedAnvil);
result.anvilUUIDs.push(anvilUUID); reduceContainer.anvilUUIDs.push(anvilUUID);
result.maxCPUCores = Math.max(anvilTotalCPUCores, result.maxCPUCores); reduceContainer.maxCPUCores = Math.max(
anvilTotalCPUCores,
reduceContainer.maxCPUCores,
);
if (anvilTotalAvailableMemory > result.maxMemory) { if (anvilTotalAvailableMemory > reduceContainer.maxMemory) {
result.maxMemory = anvilTotalAvailableMemory; reduceContainer.maxMemory = anvilTotalAvailableMemory;
} }
files.forEach(({ fileUUID }) => { files.forEach(({ fileUUID }) => {
if (!result.fileUUIDs.includes(fileUUID)) { if (!reduceContainer.fileUUIDs.includes(fileUUID)) {
result.fileUUIDs.push(fileUUID); reduceContainer.fileUUIDs.push(fileUUID);
} }
}); });
result.storageGroupUUIDs.push(...anvilStorageGroupUUIDs); reduceContainer.storageGroupUUIDs.push(...anvilStorageGroupUUIDs);
result.maxVirtualDiskSize = anvilMaxVDSize; reduceContainer.maxVirtualDiskSizes.fill(anvilStorageGroupFreeMax);
} }
} }
return result; return reduceContainer;
}, },
{ {
anvils: [], anvils: [],
@ -724,29 +777,20 @@ const filterAnvils = (
fileUUIDs: [], fileUUIDs: [],
maxCPUCores: 0, maxCPUCores: 0,
maxMemory: BIGINT_ZERO, maxMemory: BIGINT_ZERO,
maxVirtualDiskSize: BIGINT_ZERO, maxVirtualDiskSizes: storageGroupUUIDs.map(() => BIGINT_ZERO),
storageGroupUUIDs: [], storageGroupUUIDs: [],
}, },
); );
};
type FilterAnvilsParameters = Parameters<typeof filterAnvils>; storageGroupUUIDs.forEach((uuid: string, uuidIndex: number) => {
if (uuid !== '') {
result.maxVirtualDiskSizes[uuidIndex] = storageGroupUUIDMapToFree[uuid];
}
});
type VirtualDiskStates = { return result;
maxes: bigint[];
inputMaxes: string[];
inputSizes: string[];
inputStorageGroupUUIDs: string[];
inputUnits: DataSizeUnit[];
sizes: bigint[];
}; };
type UpdateLimitsFunction = (
filterArgs: FilterAnvilsParameters,
localInputMemoryUnit: DataSizeUnit,
localVirtualDisks: VirtualDiskStates,
) => void;
const convertSelectValueToArray = (value: unknown) => const convertSelectValueToArray = (value: unknown) =>
typeof value === 'string' ? value.split(',') : (value as string[]); typeof value === 'string' ? value.split(',') : (value as string[]);
@ -858,6 +902,12 @@ const createVirtualDiskForm = (
updateLimits(filterArgs, inputMemoryUnit, virtualDisks); updateLimits(filterArgs, inputMemoryUnit, virtualDisks);
}, },
value: get('inputStorageGroupUUIDs'), value: get('inputStorageGroupUUIDs'),
onClearIndicatorClick: () => {
set('inputStorageGroupUUIDs', '');
filterArgs[5] = virtualDisks.inputStorageGroupUUIDs;
updateLimits(filterArgs, inputMemoryUnit, virtualDisks);
},
}, },
}, },
)} )}
@ -964,14 +1014,14 @@ const ProvisionServerDialog = ({
fileUUIDs, fileUUIDs,
maxCPUCores, maxCPUCores,
maxMemory, maxMemory,
maxVirtualDiskSize, maxVirtualDiskSizes,
storageGroupUUIDs, storageGroupUUIDs,
} = filterAnvils(...filterArgs); } = filterAnvils(...filterArgs);
setInputCPUCoresMax(maxCPUCores); setInputCPUCoresMax(maxCPUCores);
setMemoryValueMax(maxMemory); setMemoryValueMax(maxMemory);
localVirtualDisks.maxes.fill(maxVirtualDiskSize); localVirtualDisks.maxes = maxVirtualDiskSizes;
setVirtualDisks({ ...localVirtualDisks }); setVirtualDisks({ ...localVirtualDisks });
setIncludeAnvilUUIDs(anvilUUIDs); setIncludeAnvilUUIDs(anvilUUIDs);
@ -1032,18 +1082,19 @@ const ProvisionServerDialog = ({
setFileSelectItems(localFileSelectItems); setFileSelectItems(localFileSelectItems);
setStorageGroupSelectItems(localStorageGroupSelectItems); setStorageGroupSelectItems(localStorageGroupSelectItems);
const placeholderVirtualDisks = addVirtualDisk();
memorizedUpdateLimit( memorizedUpdateLimit(
[ [
localAllAnvils, localAllAnvils,
localStorageGroupUUIDMapToFree, localStorageGroupUUIDMapToFree,
0, 0,
BIGINT_ZERO, BIGINT_ZERO,
[], placeholderVirtualDisks.sizes,
[], placeholderVirtualDisks.inputStorageGroupUUIDs,
[], [],
], ],
'B', 'B',
addVirtualDisk(), placeholderVirtualDisks,
); );
setOSAutocompleteOptions( setOSAutocompleteOptions(

Loading…
Cancel
Save