Files
supabase/apps/studio/components/interfaces/DiskManagement/DiskManagement.schema.ts
Jonathan Summers-MuirandJoshen Lim 9f420962e1 Feat/compute and disk (#30068)
* inited. added disk config to a new page

* add instances

* move moar

* moved things around. billing badges updated. compute added

* tidy

* new components

* form now dynamically updating itself

* updated compute form. moved warning panels. added collapsible for advanced options

* review dialog now only showing what is relevant

* Update DiskManagementForm.tsx

* compute sizes now a reccomendation

* fix old form

* started adding flags

* removed unused code. fixed issue with IOPS price showing on smaller compute

* moar clearning

* IOPS logic wrong way round

* type fixes

* start adding better error handling

* TIDY

* moved everything to own file

* tidy

* fix hydration issue

* moved some components around

* clean up

* inline errors

* update form message

* Update DiskManagementForm.tsx

* error fields fixed. some formatting issues. nano added as an option

* fix constants

* add some plan restrictions

* moar

* units updated. labels updated

* Update DiskManagement.schema.ts

* fix a ton of type issues

* text udpates

* add panel to suggest switching to io2

* more notice board stuff

* number formatting. moved a file

* Update DiskManagementForm.tsx

* remove console logs

* upgrade comms. more type fixes

* add empty states for the old areas

* more links

* updated some label issues

* hide labels when chart is active

* Update DiskManagement.utils.ts

* Delete next-env.d.ts

* Update DiskManagementForm.tsx

* Update DiskManagement.schema.ts

* text updates

* Update DiskManagement.constants.tsx

* Update next-env.d.ts

* Update next-env.d.ts

* Small clean uop

* Clean up empty files

* Clean up spelling

* Clean up more

* Fix typo in file name

* Clean up import statements

* Update DiskManagementForm.tsx

* fix issues

* Update ProjectLayout.tsx

* Remove unused import

* Fix

* Address nit

* Update database.tsx

* remove supress toast

* Update DiskManagement.schema.ts

* Update database.tsx

* change upgrade comms

* Update DiskManagementPanelForm.tsx

* fixes

* fix button size on old form

* Update DiskManagementForm.tsx

* Update StorageTypeField.tsx

* update labels on compute

* dont show banner when infra is FLY

* update comms. hide disk config for FLY

* Fix TS

* Last round of clean upo

* fix message state

* fix message

* Fix TS

* Update DiskManagement.utils.ts

* fix errors

* Update BillingChangeBadge.tsx

* fixed some label issues

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2024-11-04 09:05:37 +00:00

170 lines
6.3 KiB
TypeScript

import { z } from 'zod'
import {
calculateDiskSizeRequiredForIopsWithGp3,
calculateDiskSizeRequiredForIopsWithIo2,
calculateIopsRequiredForThroughput,
calculateMaxIopsAllowedForDiskSizeWithGp3,
calculateMaxIopsAllowedForDiskSizeWithio2,
formatNumber,
} from './DiskManagement.utils'
import { ComputeInstanceAddonVariantId } from './DiskManagement.types'
import { DISK_LIMITS, DiskType, IOPS_RANGE, THROUGHPUT_RANGE } from './ui/DiskManagement.constants'
const baseSchema = z.object({
storageType: z.enum(['io2', 'gp3']).describe('Type of storage: io2 or gp3'),
totalSize: z
.number()
.min(8, { message: 'Allocated disk size must be at least 8 GB.' })
.describe('Allocated disk size in GB'),
provisionedIOPS: z.number().describe('Provisioned IOPS for storage type'),
throughput: z.number().optional().describe('Throughput in MB/s for gp3'),
computeSize: z
.custom<ComputeInstanceAddonVariantId>((val): val is ComputeInstanceAddonVariantId => true)
.describe('Compute size'),
})
export const CreateDiskStorageSchema = (defaultTotalSize: number) => {
const schema = baseSchema.superRefine((data, ctx) => {
const { storageType, totalSize, provisionedIOPS, throughput, computeSize } = data
if (totalSize < defaultTotalSize) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Disk size cannot be reduced in size. Must be at least ${formatNumber(defaultTotalSize)} GB.`,
path: ['totalSize'],
})
}
if (storageType === 'io2') {
// Validation rules for io2
if (provisionedIOPS > IOPS_RANGE[DiskType.IO2].max) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `IOPS can not exceed ${formatNumber(IOPS_RANGE[DiskType.IO2].max)} for io2 Disk type. Please reach out to support if you need higher IOPS than this.`,
path: ['provisionedIOPS'],
})
}
const maxIOPSforDiskSizeWithio2 = calculateMaxIopsAllowedForDiskSizeWithio2(totalSize)
if (provisionedIOPS < IOPS_RANGE[DiskType.IO2].min) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Provisioned IOPS must be at least ${formatNumber(IOPS_RANGE[DiskType.IO2].min)}`,
path: ['provisionedIOPS'],
})
} else if (provisionedIOPS > maxIOPSforDiskSizeWithio2) {
if (totalSize >= 8) {
const diskSizeRequiredForIopsWithIo2 =
calculateDiskSizeRequiredForIopsWithIo2(provisionedIOPS)
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Larger Disk size of at least ${formatNumber(diskSizeRequiredForIopsWithIo2)} GB required. Current max is ${formatNumber(maxIOPSforDiskSizeWithio2)} IOPS.`,
path: ['provisionedIOPS'],
})
} else {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Invalid IOPS value due to small disk size`,
path: ['provisionedIOPS'],
})
}
}
if (throughput !== undefined) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Throughput is not configurable for io2.',
path: ['throughput'],
})
}
if (totalSize > DISK_LIMITS[DiskType.IO2].maxStorage) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Allocated disksize must not exceed ${formatNumber(DISK_LIMITS[DiskType.IO2].maxStorage)} GB `,
path: ['totalSize'],
})
}
}
if (storageType === 'gp3') {
const maxIopsAllowedForDiskSizeWithGp3 = calculateMaxIopsAllowedForDiskSizeWithGp3(totalSize)
if (provisionedIOPS > IOPS_RANGE[DiskType.GP3].max) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `IOPS can not exceed ${formatNumber(IOPS_RANGE[DiskType.GP3].max)} for GP3 Disk. Change the Disk type to io2 for higher IOPS support.`,
path: ['provisionedIOPS'],
})
}
if (provisionedIOPS < IOPS_RANGE[DiskType.GP3].min) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `IOPS must be at least ${formatNumber(IOPS_RANGE[DiskType.GP3].min)}`,
path: ['provisionedIOPS'],
})
} else if (provisionedIOPS > maxIopsAllowedForDiskSizeWithGp3) {
if (totalSize >= 8) {
const diskSizeRequiredForIopsWithGp3 =
calculateDiskSizeRequiredForIopsWithGp3(provisionedIOPS)
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Larger Disk size of at least ${formatNumber(diskSizeRequiredForIopsWithGp3)} GB required. Current max is ${formatNumber(maxIopsAllowedForDiskSizeWithGp3)} IOPS.`,
path: ['provisionedIOPS'],
})
} else {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Invalid IOPS value due to invalid disk size`,
path: ['provisionedIOPS'],
})
}
}
if (throughput !== undefined) {
const maxThroughput = Math.min(0.25 * provisionedIOPS, 1000)
if (throughput > THROUGHPUT_RANGE['gp3'].max) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Throughput can not exceed ${formatNumber(maxThroughput)} MiB/s`,
path: ['throughput'],
})
}
if (throughput > maxThroughput) {
const iopsRequiredForThroughput = calculateIopsRequiredForThroughput(throughput)
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Need at least ${formatNumber(iopsRequiredForThroughput)} IOPS to support ${formatNumber(throughput)} MiB/s.`,
path: ['throughput'],
})
}
if (throughput < THROUGHPUT_RANGE[DiskType.GP3].min) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Throughput must be at least ${formatNumber(THROUGHPUT_RANGE[DiskType.GP3].min)} MiB/s`,
path: ['throughput'],
})
}
}
if (totalSize > DISK_LIMITS[DiskType.GP3].maxStorage) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Allocated disksize must not exceed ${formatNumber(DISK_LIMITS[DiskType.GP3].maxStorage)} GB`,
path: ['totalSize'],
})
}
}
})
return schema
}
export type DiskStorageSchemaType = z.infer<ReturnType<typeof CreateDiskStorageSchema>>