diff --git a/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/create-db-cluster.e2e.ts b/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/create-db-cluster.e2e.ts
index 1556fb09d..e7e4800ab 100644
--- a/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/create-db-cluster.e2e.ts
+++ b/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/create-db-cluster.e2e.ts
@@ -139,7 +139,16 @@ test.describe('DB Cluster creation', () => {
await resourcesStepCheck(page);
- // Same number of proxies as nodes, as user hasn't changed it
+ // Sharding off, no routers available
+ await expect(page.getByText('Routers (3)')).not.toBeVisible();
+
+ await moveBack(page);
+ await page
+ .getByTestId('switch-input-sharding-label')
+ .getByRole('checkbox')
+ .check();
+ await moveForward(page);
+
await expect(page.getByText('Routers (3)')).toBeVisible();
await page.getByTestId('proxies-accordion').getByRole('button').click();
await page.getByTestId('toggle-button-routers-1').click();
@@ -180,6 +189,10 @@ test.describe('DB Cluster creation', () => {
await page.getByTestId('button-edit-preview-basic-information').click();
// Because 2 nodes is not valid for MongoDB, the default will be picked
await page.getByTestId('mongodb-toggle-button').click();
+ await page
+ .getByTestId('switch-input-sharding-label')
+ .getByRole('checkbox')
+ .check();
await expect(page.getByText('NÂș nodes: 3')).toBeVisible();
await page.getByTestId('button-edit-preview-backups').click();
diff --git a/ui/apps/everest/src/components/cluster-form/resources/constants.ts b/ui/apps/everest/src/components/cluster-form/resources/constants.ts
index b91fec4e3..07e4e0912 100644
--- a/ui/apps/everest/src/components/cluster-form/resources/constants.ts
+++ b/ui/apps/everest/src/components/cluster-form/resources/constants.ts
@@ -162,6 +162,25 @@ export const getDefaultNumberOfconfigServersByNumberOfNodes = (
} else return '7';
};
+const numberOfResourcesValidator = (
+ numberOfResourcesStr: string,
+ customNrOfResoucesStr: string,
+ fieldPath: string,
+ ctx: z.RefinementCtx
+) => {
+ if (numberOfResourcesStr === CUSTOM_NR_UNITS_INPUT_VALUE) {
+ const intNr = parseInt(customNrOfResoucesStr, 10);
+
+ if (Number.isNaN(intNr) || intNr < 1) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: 'Please enter a valid number',
+ path: [fieldPath],
+ });
+ }
+ }
+};
+
export const resourcesFormSchema = (passthrough?: boolean) => {
const objectShape = {
[DbWizardFormFields.shardNr]: z.string().optional(),
@@ -199,26 +218,21 @@ export const resourcesFormSchema = (passthrough?: boolean) => {
},
ctx
) => {
- [
- [numberOfNodes, customNrOfNodes, DbWizardFormFields.customNrOfNodes],
- [
+ numberOfResourcesValidator(
+ numberOfNodes,
+ customNrOfNodes,
+ DbWizardFormFields.customNrOfNodes,
+ ctx
+ );
+
+ if (dbType !== DbType.Mongo || (dbType === DbType.Mongo && !!sharding)) {
+ numberOfResourcesValidator(
numberOfProxies,
- customNrOfProxies,
+ customNrOfNodes,
DbWizardFormFields.customNrOfProxies,
- ],
- ].forEach(([nr, customNr, path]) => {
- if (nr === CUSTOM_NR_UNITS_INPUT_VALUE) {
- const intNr = parseInt(customNr, 10);
-
- if (Number.isNaN(intNr) || intNr < 1) {
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: 'Please enter a valid number',
- path: [path],
- });
- }
- }
- });
+ ctx
+ );
+ }
if (
numberOfNodes === CUSTOM_NR_UNITS_INPUT_VALUE &&
diff --git a/ui/apps/everest/src/components/cluster-form/resources/resources.tsx b/ui/apps/everest/src/components/cluster-form/resources/resources.tsx
index 9f659ad38..39ed016a9 100644
--- a/ui/apps/everest/src/components/cluster-form/resources/resources.tsx
+++ b/ui/apps/everest/src/components/cluster-form/resources/resources.tsx
@@ -423,8 +423,10 @@ const ResourcesForm = ({
allowDiskInputUpdate,
pairProxiesWithNodes,
showSharding,
+ hideProxies = false,
}: {
dbType: DbType;
+ hideProxies?: boolean;
disableDiskInput?: boolean;
allowDiskInputUpdate?: boolean;
pairProxiesWithNodes?: boolean;
@@ -559,37 +561,41 @@ const ResourcesForm = ({
disableCustom={dbType === DbType.Mysql}
/>
-
-
-
-
- {proxyFieldError && (
-
- {proxyFieldError?.message}
-
- )}
-
+ {!hideProxies && (
+
+
+
+
+ {proxyFieldError && (
+
+ {proxyFieldError?.message}
+
+ )}
+
+ )}
{!!showSharding && !!sharding && (
diff --git a/ui/apps/everest/src/hooks/api/db-cluster/useCreateDbCluster.ts b/ui/apps/everest/src/hooks/api/db-cluster/useCreateDbCluster.ts
index 3942d3e5e..b43f4ab11 100644
--- a/ui/apps/everest/src/hooks/api/db-cluster/useCreateDbCluster.ts
+++ b/ui/apps/everest/src/hooks/api/db-cluster/useCreateDbCluster.ts
@@ -111,6 +111,7 @@ const formValuesToPayloadMapping = (
dbPayload.externalAccess,
dbPayload.proxyCpu,
dbPayload.proxyMemory,
+ dbPayload.sharding,
dbPayload.sourceRanges || []
),
...(dbPayload.dbType === DbType.Mongo && {
diff --git a/ui/apps/everest/src/hooks/api/db-cluster/useUpdateDbCluster.ts b/ui/apps/everest/src/hooks/api/db-cluster/useUpdateDbCluster.ts
index 2fbd80151..0e6f25627 100644
--- a/ui/apps/everest/src/hooks/api/db-cluster/useUpdateDbCluster.ts
+++ b/ui/apps/everest/src/hooks/api/db-cluster/useUpdateDbCluster.ts
@@ -15,12 +15,13 @@
import { UseMutationOptions, useMutation } from '@tanstack/react-query';
import { updateDbClusterFn } from 'api/dbClusterApi';
-import { DbCluster } from 'shared-types/dbCluster.types';
+import { DbCluster, Proxy } from 'shared-types/dbCluster.types';
import { DbWizardType } from 'pages/database-form/database-form-schema.ts';
import cronConverter from 'utils/cron-converter';
import { CUSTOM_NR_UNITS_INPUT_VALUE } from 'components/cluster-form';
import { getProxySpec } from './utils';
import { DbType } from '@percona/types';
+import { DbEngineType } from 'shared-types/dbEngines.types';
type UpdateDbClusterArgType = {
dbPayload: DbWizardType;
@@ -95,31 +96,35 @@ const formValuesToPayloadOverrides = (
monitoringConfigName: dbPayload?.monitoringInstance!,
}),
},
- proxy: {
- ...dbCluster.spec.proxy,
- ...getProxySpec(
- dbPayload.dbType,
- dbPayload.numberOfProxies,
- dbPayload.customNrOfProxies || '',
- dbPayload.externalAccess,
- dbPayload.proxyCpu,
- dbPayload.proxyMemory,
- dbPayload.sourceRanges || []
- ),
- // replicas: numberOfNodes,
- // expose: {
- // ...dbCluster.spec.proxy.expose,
- // type: dbPayload.externalAccess
- // ? ProxyExposeType.external
- // : ProxyExposeType.internal,
- // ...(!!dbPayload.externalAccess &&
- // dbPayload.sourceRanges && {
- // ipSourceRanges: dbPayload.sourceRanges.flatMap((source) =>
- // source.sourceRange ? [source.sourceRange] : []
- // ),
- // }),
- // },
- },
+ proxy:
+ dbPayload.dbType === DbType.Mongo && !dbPayload.sharding
+ ? {}
+ : {
+ ...dbCluster.spec.proxy,
+ ...getProxySpec(
+ dbPayload.dbType,
+ dbPayload.numberOfProxies,
+ dbPayload.customNrOfProxies || '',
+ dbPayload.externalAccess,
+ dbPayload.proxyCpu,
+ dbPayload.proxyMemory,
+ dbPayload.sharding,
+ dbPayload.sourceRanges || []
+ ),
+ // replicas: numberOfNodes,
+ // expose: {
+ // ...dbCluster.spec.proxy.expose,
+ // type: dbPayload.externalAccess
+ // ? ProxyExposeType.external
+ // : ProxyExposeType.internal,
+ // ...(!!dbPayload.externalAccess &&
+ // dbPayload.sourceRanges && {
+ // ipSourceRanges: dbPayload.sourceRanges.flatMap((source) =>
+ // source.sourceRange ? [source.sourceRange] : []
+ // ),
+ // }),
+ // },
+ },
...(dbPayload.dbType === DbType.Mongo && {
sharding: {
enabled: dbPayload.sharding,
@@ -235,6 +240,7 @@ export const useUpdateDbClusterResources = () =>
mutationFn: ({
dbCluster,
newResources,
+ sharding,
}: {
dbCluster: DbCluster;
newResources: {
@@ -247,6 +253,7 @@ export const useUpdateDbClusterResources = () =>
proxyMemory: number;
numberOfProxies: number;
};
+ sharding: boolean;
}) =>
updateDbClusterFn(dbCluster.metadata.name, dbCluster.metadata.namespace, {
...dbCluster,
@@ -264,14 +271,17 @@ export const useUpdateDbClusterResources = () =>
size: `${newResources.disk}${newResources.diskUnit}`,
},
},
- proxy: {
- ...dbCluster.spec.proxy,
- replicas: newResources.numberOfProxies,
- resources: {
- cpu: `${newResources.proxyCpu}`,
- memory: `${newResources.proxyMemory}G`,
- },
- },
+ proxy:
+ dbCluster.spec.engine.type === DbEngineType.PSMDB && !sharding
+ ? {}
+ : ({
+ ...dbCluster.spec.proxy,
+ replicas: newResources.numberOfProxies,
+ resources: {
+ cpu: `${newResources.proxyCpu}`,
+ memory: `${newResources.proxyMemory}G`,
+ },
+ } as Proxy),
},
}),
});
diff --git a/ui/apps/everest/src/hooks/api/db-cluster/utils.ts b/ui/apps/everest/src/hooks/api/db-cluster/utils.ts
index 7e92ff65a..3b8a26647 100644
--- a/ui/apps/everest/src/hooks/api/db-cluster/utils.ts
+++ b/ui/apps/everest/src/hooks/api/db-cluster/utils.ts
@@ -10,14 +10,24 @@ export const getProxySpec = (
externalAccess: boolean,
cpu: number,
memory: number,
+ sharding: boolean,
sourceRanges?: Array<{ sourceRange?: string }>
-): Proxy => {
+): Proxy | Record => {
+ console.log('dbType', dbType);
+ console.log('sharding', sharding);
+ if (dbType === DbType.Mongo && !sharding) {
+ console.log('returning empty object');
+ return {};
+ }
const proxyNr = parseInt(
numberOfProxies === CUSTOM_NR_UNITS_INPUT_VALUE
? customNrOfProxies
: numberOfProxies,
10
);
+ // const showResources =
+ // dbType !== DbType.Mongo || (dbType === DbType.Mongo && !sharding);
+
return {
type: dbTypeToProxyType(dbType),
replicas: proxyNr,
diff --git a/ui/apps/everest/src/pages/database-form/database-form-body/steps/resources/resources-step.tsx b/ui/apps/everest/src/pages/database-form/database-form-body/steps/resources/resources-step.tsx
index 3c70b50e1..b3f36d1ec 100644
--- a/ui/apps/everest/src/pages/database-form/database-form-body/steps/resources/resources-step.tsx
+++ b/ui/apps/everest/src/pages/database-form/database-form-body/steps/resources/resources-step.tsx
@@ -10,6 +10,7 @@ export const ResourcesStep = () => {
const { watch } = useFormContext();
const mode = useDatabasePageMode();
const dbType: DbType = watch(DbWizardFormFields.dbType);
+ const shardingEnabled = watch(DbWizardFormFields.sharding);
return (
<>
@@ -23,6 +24,7 @@ export const ResourcesStep = () => {
disableDiskInput={mode === 'edit'}
allowDiskInputUpdate={mode !== 'edit'}
showSharding={dbType === DbType.Mongo}
+ hideProxies={dbType === DbType.Mongo && !shardingEnabled}
/>
>
);
diff --git a/ui/apps/everest/src/pages/database-form/database-form.utils.ts b/ui/apps/everest/src/pages/database-form/database-form.utils.ts
index b570662af..0138cdc6d 100644
--- a/ui/apps/everest/src/pages/database-form/database-form.utils.ts
+++ b/ui/apps/everest/src/pages/database-form/database-form.utils.ts
@@ -49,7 +49,7 @@ export const DbClusterPayloadToFormValues = (
): DbWizardType => {
const backup = dbCluster?.spec?.backup;
const replicas = dbCluster?.spec?.engine?.replicas.toString();
- const proxies = dbCluster?.spec?.proxy?.replicas.toString();
+ const proxies = (dbCluster?.spec?.proxy?.replicas || 0).toString();
const diskValues = memoryParser(
dbCluster?.spec?.engine?.storage?.size.toString()
);
diff --git a/ui/apps/everest/src/pages/databases/DbClusterView.utils.ts b/ui/apps/everest/src/pages/databases/DbClusterView.utils.ts
index 291278551..dd25080c2 100644
--- a/ui/apps/everest/src/pages/databases/DbClusterView.utils.ts
+++ b/ui/apps/everest/src/pages/databases/DbClusterView.utils.ts
@@ -18,6 +18,7 @@ import { DbClusterForNamespaceResult } from '../../hooks/api/db-clusters/useDbCl
import { Messages } from './dbClusterView.messages';
import { DbClusterTableElement } from './dbClusterView.types';
import { Backup, BackupStatus } from 'shared-types/backups.types';
+import { isProxy } from 'utils/db';
const DB_CLUSTER_STATUS_HUMANIFIED: Record = {
[DbClusterStatus.ready]: Messages.statusProvider.up,
@@ -55,7 +56,9 @@ export const convertDbClusterPayloadToTableFormat = (
storage: cluster.spec.engine.storage.size,
nodes: cluster.spec.engine.replicas,
hostName: cluster.status ? cluster.status.hostname : '',
- exposetype: cluster.spec.proxy.expose.type,
+ exposetype: isProxy(cluster.spec.proxy)
+ ? cluster.spec.proxy.expose.type
+ : undefined,
port: cluster.status?.port,
monitoringConfigName:
cluster.spec.monitoring?.monitoringConfigName ?? '',
diff --git a/ui/apps/everest/src/pages/databases/dbClusterView.types.ts b/ui/apps/everest/src/pages/databases/dbClusterView.types.ts
index b5009d1d7..42efe92e3 100644
--- a/ui/apps/everest/src/pages/databases/dbClusterView.types.ts
+++ b/ui/apps/everest/src/pages/databases/dbClusterView.types.ts
@@ -38,7 +38,7 @@ export interface DbClusterTableElement {
nodes: number;
hostName: string;
port?: number;
- exposetype: ProxyExposeType;
+ exposetype?: ProxyExposeType;
monitoringConfigName?: string;
raw: DbCluster;
}
diff --git a/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cards/resources-details.tsx b/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cards/resources-details.tsx
index 54d0c2c86..f29109123 100644
--- a/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cards/resources-details.tsx
+++ b/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cards/resources-details.tsx
@@ -39,6 +39,7 @@ import {
import { dbEngineToDbType } from '@percona/utils';
import { DB_CLUSTER_QUERY, useUpdateDbClusterResources } from 'hooks';
import { DbType } from '@percona/types';
+import { isProxy } from 'utils/db';
export const ResourcesDetails = ({
dbCluster,
@@ -58,7 +59,9 @@ export const ResourcesDetails = ({
const parsedMemoryValues = memoryParser(memory.toString());
const dbType = dbEngineToDbType(dbCluster.spec.engine.type);
const replicas = dbCluster.spec.engine.replicas.toString();
- const proxies = dbCluster.spec.proxy.replicas.toString();
+ const proxies = isProxy(dbCluster.spec.proxy)
+ ? (dbCluster.spec.proxy.replicas || 0).toString()
+ : '';
const numberOfNodes = NODES_DB_TYPE_MAP[dbType].includes(replicas)
? replicas
: CUSTOM_NR_UNITS_INPUT_VALUE;
@@ -103,6 +106,7 @@ export const ResourcesDetails = ({
10
),
},
+ sharding: !!sharding?.enabled,
},
{
onSuccess: () => {
@@ -194,6 +198,7 @@ export const ResourcesDetails = ({
{openEditModal && (
setOpenEditModal(false)}
onSubmit={onSubmit}
defaultValues={{
@@ -213,7 +218,9 @@ export const ResourcesDetails = ({
),
resourceSizePerProxy: matchFieldsValueToResourceSize(
dbType,
- dbCluster.spec.proxy.resources
+ isProxy(dbCluster.spec.proxy)
+ ? dbCluster.spec.proxy.resources
+ : undefined
),
}}
/>
diff --git a/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cards/resources/resources-edit-modal.tsx b/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cards/resources/resources-edit-modal.tsx
index cca4e68f4..c66f48baf 100644
--- a/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cards/resources/resources-edit-modal.tsx
+++ b/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cards/resources/resources-edit-modal.tsx
@@ -6,6 +6,7 @@ import { FormDialog } from 'components/form-dialog';
type Props = {
handleCloseModal: () => void;
dbType: DbType;
+ shardingEnabled: boolean;
onSubmit: SubmitHandler>>;
defaultValues: z.infer>;
};
@@ -13,6 +14,7 @@ type Props = {
const ResourcesEditModal = ({
handleCloseModal,
dbType,
+ shardingEnabled,
onSubmit,
defaultValues,
}: Props) => {
@@ -33,6 +35,7 @@ const ResourcesEditModal = ({
showSharding={false}
disableDiskInput
allowDiskInputUpdate={false}
+ hideProxies={dbType === DbType.Mongo && !shardingEnabled}
/>
);
diff --git a/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cluster-overview.tsx b/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cluster-overview.tsx
index 41411240b..050cef706 100644
--- a/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cluster-overview.tsx
+++ b/ui/apps/everest/src/pages/db-cluster-details/cluster-overview/cluster-overview.tsx
@@ -25,6 +25,7 @@ import { useDbClusterCredentials } from 'hooks/api/db-cluster/useCreateDbCluster
import { useDbBackups } from 'hooks/api/backups/useBackups';
import { DbEngineType } from 'shared-types/dbEngines.types';
import { useRBACPermissions } from 'hooks/rbac';
+import { isProxy } from 'utils/db';
export const ClusterOverview = () => {
const { dbClusterName, namespace = '' } = useParams();
@@ -90,6 +91,7 @@ export const ClusterOverview = () => {
username={dbClusterDetails?.username!}
password={dbClusterDetails?.password!}
externalAccess={
+ isProxy(dbCluster.spec.proxy) &&
dbCluster.spec.proxy.expose.type === ProxyExposeType.external
}
monitoring={dbCluster?.spec.monitoring.monitoringConfigName}
diff --git a/ui/apps/everest/src/shared-types/dbCluster.types.ts b/ui/apps/everest/src/shared-types/dbCluster.types.ts
index 37814f659..288712dab 100644
--- a/ui/apps/everest/src/shared-types/dbCluster.types.ts
+++ b/ui/apps/everest/src/shared-types/dbCluster.types.ts
@@ -71,7 +71,7 @@ interface Engine {
}
export interface Proxy {
- replicas: number;
+ replicas?: number;
expose: {
type: ProxyExposeType;
ipSourceRanges?: string[];
@@ -106,7 +106,7 @@ export interface Spec {
allowUnsafeConfiguration?: boolean;
backup?: Backup;
engine: Engine;
- proxy: Proxy;
+ proxy: Proxy | Record;
paused?: boolean;
dataSource?: DataSource;
monitoring: Monitoring;
diff --git a/ui/apps/everest/src/utils/db.tsx b/ui/apps/everest/src/utils/db.tsx
index d0a29ccdf..2508bc6af 100644
--- a/ui/apps/everest/src/utils/db.tsx
+++ b/ui/apps/everest/src/utils/db.tsx
@@ -1,6 +1,7 @@
import { MongoIcon, MySqlIcon, PostgreSqlIcon } from '@percona/ui-lib';
import { DbType } from '@percona/types';
import { ProxyType } from 'shared-types/dbEngines.types';
+import { Proxy } from 'shared-types/dbCluster.types';
export const dbTypeToIcon = (dbType: DbType) => {
switch (dbType) {
@@ -39,3 +40,11 @@ export const dbTypeToProxyType = (dbType: DbType): ProxyType => {
return 'pgbouncer';
}
};
+
+export const isProxy = (
+ proxy: Proxy | Record
+): proxy is Proxy => {
+ return (
+ proxy && typeof proxy.expose === 'object' && typeof proxy.type === 'string'
+ );
+};