Skip to content

Commit

Permalink
EVEREST-1405-sharding-wizard-update: new validation and view for shar…
Browse files Browse the repository at this point in the history
…ding in dbWizard (#637)

* EVEREST-1405-sharding-wizard-update: new validation and view for sharding in dbWizard

* EVEREST-1405-sharding-wizard-update: tests fix

* EVEREST-1405-sharding-wizard-update: review fix
  • Loading branch information
solovevayaroslavna authored Sep 5, 2024
1 parent 412e760 commit 63899e2
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ export const Messages = {
dbVersion: 'Database version',
storageClass: 'Storage class',
shardedCluster: 'Sharded Cluster',
numberOfShards: 'Number of shards',
numberOfConfigServers: 'Number of configuration servers',
},
placeholders: {
dbName: 'E.g. postgresql-123',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export const FirstStep = ({ loadingDefaultsForEdition }: StepProps) => {
const dbType: DbType = watch(DbWizardFormFields.dbType);
const dbVersion: DbType = watch(DbWizardFormFields.dbVersion);
const dbNamespace = watch(DbWizardFormFields.k8sNamespace);
const sharding = watch(DbWizardFormFields.sharding);
const dbClusterStatus = dbClusterData?.status?.status;
const disableShardingChange =
loadingDefaultsForEdition ||
Expand Down Expand Up @@ -179,6 +178,9 @@ export const FirstStep = ({ loadingDefaultsForEdition }: StepProps) => {
resetField(DbWizardFormFields.shardConfigServers, {
keepError: false,
});
resetField(DbWizardFormFields.sharding, {
keepError: false,
});
updateDbVersions();
},
[
Expand Down Expand Up @@ -381,35 +383,6 @@ export const FirstStep = ({ loadingDefaultsForEdition }: StepProps) => {
{/* </Tooltip>*/}
{/*)}*/}
</Stack>
{sharding && (
<>
<TextInput
name={DbWizardFormFields.shardNr}
textFieldProps={{
disabled: mode !== 'new',
label: Messages.labels.numberOfShards,
type: 'number',
inputProps: {
min: DB_WIZARD_DEFAULTS[DbWizardFormFields.shardNr],
},
}}
/>
<TextInput
name={DbWizardFormFields.shardConfigServers}
textFieldProps={{
disabled: mode !== 'new',
label: Messages.labels.numberOfConfigServers,
type: 'number',
inputProps: {
step: '2',
min: DB_WIZARD_DEFAULTS[
DbWizardFormFields.shardConfigServers
],
},
}}
/>
</>
)}
</>
)}
</FormGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ export const Messages = {
pageDescription:
'Configure the resources your new database will have access to.',
labels: {
numberOfNodes: 'nodes',
numberOfNodes: 'Number of nodes per shard',
resourceSizePerNode: 'Resource size per node',
cpu: 'cpu',
memory: 'memory',
disk: 'disk',
estimated: (value: string | number | undefined, units: string) =>
value ? `Estimated available: ${value} ${units}` : '',
shardsConfig: 'Shards configuration',
numberOfShards: 'Number of shards',
numberOfConfigServers: 'Number of configuration servers',
},
alerts: {
resourcesCapacityExceeding: (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Box, FormGroup } from '@mui/material';
import { Box, FormGroup, Typography } from '@mui/material';
import { DbType } from '@percona/types';
import { ToggleButtonGroupInput, ToggleCard } from '@percona/ui-lib';
import { TextInput, ToggleButtonGroupInput, ToggleCard } from '@percona/ui-lib';
import { useKubernetesClusterResourcesInfo } from 'hooks/api/kubernetesClusters/useKubernetesClusterResourcesInfo';
import { useActiveBreakpoint } from 'hooks/utils/useActiveBreakpoint';
import { useEffect } from 'react';
import { useFormContext } from 'react-hook-form';
import { NODES_DB_TYPE_MAP } from '../../../database-form.constants.ts';
import {
NODES_DB_TYPE_MAP,
SHARDING_DEFAULTS,
} from '../../../database-form.constants.ts';
import { DbWizardFormFields } from '../../../database-form.types.ts';
import { useDatabasePageMode } from '../../../useDatabasePageMode.ts';
import { StepHeader } from '../step-header/step-header.tsx';
Expand All @@ -15,6 +18,8 @@ import { Messages } from './resources-step.messages.ts';
import { ResourceSize } from './resources-step.types.ts';
import {
checkResourceText,
getDefaultConfigServers,
getDefaultShardsNumberByNode,
humanizeResourceSizeMap,
} from './resources-step.utils.ts';

Expand All @@ -35,6 +40,18 @@ export const ResourcesStep = () => {
const diskUnit: string = watch(DbWizardFormFields.diskUnit);
const dbType: DbType = watch(DbWizardFormFields.dbType);
const numberOfNodes = watch(DbWizardFormFields.numberOfNodes);
const sharding = watch(DbWizardFormFields.sharding);

useEffect(() => {
setValue(
DbWizardFormFields.shardNr,
getDefaultShardsNumberByNode(numberOfNodes)
);
setValue(
DbWizardFormFields.shardConfigServers,
getDefaultConfigServers(numberOfNodes)
);
}, [numberOfNodes]);

const cpuCapacityExceeded = resourcesInfo
? cpu * 1000 > resourcesInfo?.available.cpuMillis
Expand Down Expand Up @@ -102,6 +119,53 @@ export const ResourcesStep = () => {
pageDescription={Messages.pageDescription}
/>
<FormGroup sx={{ mt: 3 }}>
{sharding && (
<>
<Typography variant="sectionHeading">
{Messages.labels.shardsConfig}
</Typography>
<Box
sx={{
flexDirection: 'row',
gap: 2,
display: 'flex',
'.MuiTextField-root': {
width: '50%',
},
mb: 3,
}}
>
<TextInput
name={DbWizardFormFields.shardNr}
textFieldProps={{
disabled: mode !== 'new',
label: Messages.labels.numberOfShards,
type: 'number',
inputProps: {
min: SHARDING_DEFAULTS[DbWizardFormFields.shardNr].min,
},
}}
/>
<TextInput
name={DbWizardFormFields.shardConfigServers}
textFieldProps={{
disabled: mode !== 'new',
label: Messages.labels.numberOfConfigServers,
type: 'number',
inputProps: {
step: '2',
min: SHARDING_DEFAULTS[
DbWizardFormFields.shardConfigServers
].min,
max: SHARDING_DEFAULTS[
DbWizardFormFields.shardConfigServers
].max,
},
}}
/>
</Box>
</>
)}
<ToggleButtonGroupInput
name={DbWizardFormFields.numberOfNodes}
label={Messages.labels.numberOfNodes}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { DEFAULT_SIZES } from './resources-step.const.ts';
import { DbCluster } from 'shared-types/dbCluster.types';
import { memoryParser } from 'utils/k8ResourceParser';
import { Messages } from './resources-step.messages.ts';
import { SHARDING_DEFAULTS } from '../../../database-form.constants';
import { DbWizardFormFields } from '../../../database-form.types';

const humanizedResourceSizeMap: Record<ResourceSize, string> = {
[ResourceSize.small]: 'Small',
Expand Down Expand Up @@ -93,3 +95,12 @@ export const checkResourceText = (
}
return '';
};

export const getDefaultShardsNumberByNode = (nodeValue: number) => {
if (nodeValue == 1) return SHARDING_DEFAULTS[DbWizardFormFields.shardNr].min;
else return '2';
};

export const getDefaultConfigServers = (nodeValue: number) => {
return nodeValue.toString();
};
51 changes: 28 additions & 23 deletions ui/apps/everest/src/pages/database-form/database-form-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ResourceSize } from './database-form-body/steps/resources/resources-ste
import { DbWizardFormFields } from './database-form.types.ts';
import { rfc_123_schema } from 'utils/common-validation.ts';
import { Messages as ScheduleFormMessages } from 'components/schedule-form-dialog/schedule-form/schedule-form.messages.ts';
import { DB_WIZARD_DEFAULTS } from './database-form.constants';
import { SHARDING_DEFAULTS } from './database-form.constants';

const resourceToNumber = (minimum = 0) =>
z.union([z.string().nonempty(), z.number()]).pipe(
Expand Down Expand Up @@ -37,20 +37,35 @@ const basicInfoSchema = z
}
}),
[DbWizardFormFields.sharding]: z.boolean(),
})
.passthrough();

// .passthrough tells Zod to not drop unrecognized keys
// this is needed because we parse step by step
// so, by default, Zod would leave behind the keys from previous steps

const stepTwoSchema = z
.object({
[DbWizardFormFields.shardNr]: z.string().optional(),
[DbWizardFormFields.shardConfigServers]: z.string().optional(),
[DbWizardFormFields.cpu]: resourceToNumber(0.6),
[DbWizardFormFields.memory]: resourceToNumber(0.512),
[DbWizardFormFields.disk]: resourceToNumber(1),
// we will never input this, but we need it and zod will let it pass
[DbWizardFormFields.diskUnit]: z.string(),
[DbWizardFormFields.resourceSizePerNode]: z.nativeEnum(ResourceSize),
[DbWizardFormFields.numberOfNodes]: z.string(),
})
.passthrough()
.superRefine(({ sharding, shardNr = '', shardConfigServers = '' }, ctx) => {
if (sharding) {
const intShardNr = parseInt(shardNr, 10);
const intShardNrMin = +(DB_WIZARD_DEFAULTS[
DbWizardFormFields.shardNr
] as string);
const intShardNrMin = +SHARDING_DEFAULTS[DbWizardFormFields.shardNr].min;
const intShardConfigServers = parseInt(shardConfigServers, 10);
const intShardConfigServersMin = +(DB_WIZARD_DEFAULTS[
DbWizardFormFields.shardConfigServers
] as string);
const intShardConfigServersMin =
+SHARDING_DEFAULTS[DbWizardFormFields.shardNr].min;
const intShardConfigServersMax =
+SHARDING_DEFAULTS[DbWizardFormFields.shardConfigServers].max;

if (Number.isNaN(intShardNr) || intShardNr < 0) {
ctx.addIssue({
Expand Down Expand Up @@ -87,27 +102,17 @@ const basicInfoSchema = z
message: Messages.errors.sharding.odd,
path: [DbWizardFormFields.shardConfigServers],
});
} else if (intShardConfigServers > intShardConfigServersMax) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: Messages.errors.sharding.max(intShardConfigServersMax),
path: [DbWizardFormFields.shardConfigServers],
});
}
}
}
});

// .passthrough tells Zod to not drop unrecognized keys
// this is needed because we parse step by step
// so, by default, Zod would leave behind the keys from previous steps

const stepTwoSchema = z
.object({
[DbWizardFormFields.cpu]: resourceToNumber(0.6),
[DbWizardFormFields.memory]: resourceToNumber(0.512),
[DbWizardFormFields.disk]: resourceToNumber(1),
// we will never input this, but we need it and zod will let it pass
[DbWizardFormFields.diskUnit]: z.string(),
[DbWizardFormFields.resourceSizePerNode]: z.nativeEnum(ResourceSize),
[DbWizardFormFields.numberOfNodes]: z.string(),
})
.passthrough();

const backupsStepSchema = z
.object({
[DbWizardFormFields.schedules]: z.array(
Expand Down
12 changes: 10 additions & 2 deletions ui/apps/everest/src/pages/database-form/database-form.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ import { DEFAULT_SIZES } from './database-form-body/steps/resources/resources-st
import { ResourceSize } from './database-form-body/steps/resources/resources-step.types.ts';
import { DbWizardType } from './database-form-schema.ts';

export const SHARDING_DEFAULTS = {
[DbWizardFormFields.shardConfigServers]: {
min: '1',
max: '7',
},
[DbWizardFormFields.shardNr]: {
min: '1',
},
};

export const DB_WIZARD_DEFAULTS: DbWizardType = {
// TODO should be changed to true after https://jira.percona.com/browse/EVEREST-509
[DbWizardFormFields.schedules]: [],
Expand All @@ -45,8 +55,6 @@ export const DB_WIZARD_DEFAULTS: DbWizardType = {
[DbWizardFormFields.diskUnit]: 'Gi',
[DbWizardFormFields.memory]: DEFAULT_SIZES.small.memory,
[DbWizardFormFields.sharding]: false,
[DbWizardFormFields.shardNr]: '1',
[DbWizardFormFields.shardConfigServers]: '3',
};

export const NODES_DB_TYPE_MAP: Record<DbType, string[]> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const Messages = {
sharding: {
invalid: 'Please fill in valid values for sharding',
min: (val: number) => `The value cannot be less than ${val}`,
max: (val: number) => `The value cannot be more than ${val}`,
odd: 'The value cannot be even',
},
},
Expand Down
10 changes: 6 additions & 4 deletions ui/apps/everest/src/pages/database-form/database-form.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import { cpuParser, memoryParser } from 'utils/k8ResourceParser';
import { generateShortUID } from './database-form-body/steps/first/utils.ts';
import { MAX_DB_CLUSTER_NAME_LENGTH } from 'consts';
import { DbWizardType } from './database-form-schema.ts';
import { DB_WIZARD_DEFAULTS } from './database-form.constants.ts';
import {
DB_WIZARD_DEFAULTS,
SHARDING_DEFAULTS,
} from './database-form.constants.ts';

export const DbClusterPayloadToFormValues = (
dbCluster: DbCluster,
Expand Down Expand Up @@ -53,11 +56,10 @@ export const DbClusterPayloadToFormValues = (
[DbWizardFormFields.sharding]: dbCluster?.spec?.sharding?.enabled || false,
[DbWizardFormFields.shardConfigServers]: (
sharding?.configServer?.replicas ||
(DB_WIZARD_DEFAULTS[DbWizardFormFields.shardConfigServers] as string)
SHARDING_DEFAULTS[DbWizardFormFields.shardConfigServers].min
).toString(),
[DbWizardFormFields.shardNr]: (
sharding?.shards ||
(DB_WIZARD_DEFAULTS[DbWizardFormFields.shardNr] as string)
sharding?.shards || SHARDING_DEFAULTS[DbWizardFormFields.shardNr].min
).toString(),

//resources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@ export const ResourcesPreviewSection = ({
disk,
diskUnit,
memory,
sharding,
shardNr,
shardConfigServers,
}: SectionProps) => {
const parsedCPU = Number(cpu) * Number(numberOfNodes);
const parsedDisk = Number(disk) * Number(numberOfNodes);
const parsedMemory = Number(memory) * Number(numberOfNodes);

return (
<>
{sharding && (
<>
<PreviewContentText text={`Shards: ${shardNr}`} />
<PreviewContentText
text={`Configuration servers: ${shardConfigServers}`}
/>
</>
)}
<PreviewContentText text={`Nº nodes: ${numberOfNodes}`} />
<PreviewContentText
text={`CPU: ${Number.isNaN(parsedCPU) ? '' : `${parsedCPU.toFixed(2)} CPU`}`}
Expand Down
Loading

0 comments on commit 63899e2

Please sign in to comment.