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