From c4d6d2840f4a3691c400531d2350323e3db34cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Silva?= Date: Wed, 6 Nov 2024 11:04:27 +0000 Subject: [PATCH] EVEREST-1399 | bad resources toggle selection (#804) * fix: bad custom resources * chore: test number of nodes on edition * fix: bad import * fix: UI test * test: UI custom resources * test: custom disk resources * fix: wrong resources comparison * e2e: test resouces on edit modal --- .../pr/db-cluster/db-cluster-overview.e2e.ts | 24 +++++-- .../edit-db-cluster/resources-step.e2e.ts | 64 +++++++++++++++++++ ui/apps/everest/.e2e/utils/db-cluster.ts | 20 +++++- .../cluster-form/resources/constants.ts | 22 ++++--- .../cluster-form/resources/resources.tsx | 16 ++++- .../everest/src/hooks/api/db-cluster/utils.ts | 5 +- .../database-form/database-form.utils.ts | 6 +- .../cards/resources-details.tsx | 7 +- .../src/shared-types/dbCluster.types.ts | 3 +- .../src/shared-types/dbEngines.types.ts | 2 - ui/apps/everest/src/utils/db.tsx | 12 ---- ui/packages/types/src/db-type/index.ts | 14 ++-- ui/packages/utils/src/db/db.ts | 13 +++- 13 files changed, 159 insertions(+), 49 deletions(-) diff --git a/ui/apps/everest/.e2e/pr/db-cluster/db-cluster-overview.e2e.ts b/ui/apps/everest/.e2e/pr/db-cluster/db-cluster-overview.e2e.ts index 44072e558..bc5b90e55 100644 --- a/ui/apps/everest/.e2e/pr/db-cluster/db-cluster-overview.e2e.ts +++ b/ui/apps/everest/.e2e/pr/db-cluster/db-cluster-overview.e2e.ts @@ -1,6 +1,7 @@ import { test, expect } from '@playwright/test'; import { createDbClusterFn, deleteDbClusterFn } from '@e2e/utils/db-cluster'; import { EVEREST_CI_NAMESPACES } from '@e2e/constants'; +import { findDbAndClickRow } from '@e2e/utils/db-clusters-list'; test.describe('DB Cluster Overview', async () => { const dbClusterName = 'cluster-overview-test'; @@ -10,9 +11,10 @@ test.describe('DB Cluster Overview', async () => { dbName: dbClusterName, dbType: 'mysql', numberOfNodes: '1', - cpu: 0.6, - disk: 1, - memory: 1, + cpu: 1, + memory: 2, + proxyCpu: 0.5, + proxyMemory: 0.8, externalAccess: true, sourceRanges: [ { @@ -31,9 +33,7 @@ test.describe('DB Cluster Overview', async () => { }); test('Overview information', async ({ page }) => { - const row = await page.getByText(dbClusterName); - - await row.click(); + await findDbAndClickRow(page, dbClusterName); await expect( page.getByRole('heading', { @@ -79,6 +79,18 @@ test.describe('DB Cluster Overview', async () => { ).toBeVisible(); }); + test('Show the correct resources during editing', async ({ page }) => { + await findDbAndClickRow(page, dbClusterName); + await page.getByTestId('edit-resources-button').click(); + await expect( + page.getByTestId('node-resources-toggle-button-small') + ).toHaveAttribute('aria-pressed', 'true'); + await page.getByTestId('proxies-accordion').click(); + await expect( + page.getByTestId('proxy-resources-toggle-button-medium') + ).toHaveAttribute('aria-pressed', 'true'); + }); + test('Delete Action', async ({ page, request }) => { const dbName = 'delete-test'; diff --git a/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/edit-db-cluster/resources-step.e2e.ts b/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/edit-db-cluster/resources-step.e2e.ts index c5097b121..c287e93c3 100644 --- a/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/edit-db-cluster/resources-step.e2e.ts +++ b/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/edit-db-cluster/resources-step.e2e.ts @@ -27,6 +27,11 @@ test.describe('DB Cluster Editing Resources Step (Mongo)', () => { dbName: mongoDBName, dbType: DbType.Mongo, numberOfNodes: '5', + sharding: true, + cpu: 1, + memory: 4, + proxyCpu: 2, + proxyMemory: 4, }); }); @@ -48,6 +53,13 @@ test.describe('DB Cluster Editing Resources Step (Mongo)', () => { await moveForward(page); await expect(page.getByTestId('toggle-button-nodes-5')).toBeVisible(); + await expect( + page.getByTestId('node-resources-toggle-button-small') + ).toHaveAttribute('aria-pressed', 'true'); + await page.getByTestId('proxies-accordion').click(); + await expect( + page.getByTestId('router-resources-toggle-button-medium') + ).toHaveAttribute('aria-pressed', 'true'); const a = page .getByRole('button', { pressed: true }) .filter({ hasText: '5 nodes' }); @@ -59,4 +71,56 @@ test.describe('DB Cluster Editing Resources Step (Mongo)', () => { await page.getByTestId('button-edit-preview-resources').click(); await expect(page.getByTestId('text-input-disk')).toBeDisabled(); }); + + test('Show custom resources during editing', async ({ page, request }) => { + const dbName = 'mongo-custom-resources'; + await createDbClusterFn(request, { + dbName, + dbType: DbType.Mongo, + numberOfNodes: '5', + sharding: true, + cpu: 1, + memory: 4, + proxyCpu: 3, + proxyMemory: 4, + }); + await findDbAndClickActions(page, dbName, 'Edit'); + await page.getByTestId('button-edit-preview-resources').click(); + await expect( + page.getByTestId('node-resources-toggle-button-small') + ).toHaveAttribute('aria-pressed', 'true'); + await page.getByTestId('proxies-accordion').click(); + await expect( + page.getByTestId('router-resources-toggle-button-custom') + ).toHaveAttribute('aria-pressed', 'true'); + await deleteDbClusterFn(request, dbName); + }); + + test('Show predefined resources regardless of disk', async ({ + page, + request, + }) => { + const dbName = 'mongo-disk-resources'; + await createDbClusterFn(request, { + dbName, + dbType: DbType.Mongo, + numberOfNodes: '5', + sharding: true, + cpu: 1, + memory: 4, + disk: 1, + proxyCpu: 2, + proxyMemory: 4, + }); + await findDbAndClickActions(page, dbName, 'Edit'); + await page.getByTestId('button-edit-preview-resources').click(); + await expect( + page.getByTestId('node-resources-toggle-button-small') + ).toHaveAttribute('aria-pressed', 'true'); + await page.getByTestId('proxies-accordion').click(); + await expect( + page.getByTestId('router-resources-toggle-button-medium') + ).toHaveAttribute('aria-pressed', 'true'); + await deleteDbClusterFn(request, dbName); + }); }); diff --git a/ui/apps/everest/.e2e/utils/db-cluster.ts b/ui/apps/everest/.e2e/utils/db-cluster.ts index 5353dac89..d756c00ac 100644 --- a/ui/apps/everest/.e2e/utils/db-cluster.ts +++ b/ui/apps/everest/.e2e/utils/db-cluster.ts @@ -14,11 +14,12 @@ // limitations under the License. import { APIRequestContext, expect } from '@playwright/test'; -import { dbTypeToDbEngine } from '@percona/utils'; +import { dbTypeToDbEngine, dbTypeToProxyType } from '@percona/utils'; import { getEnginesVersions } from './database-engines'; import { getClusterDetailedInfo } from './storage-class'; import { getTokenFromLocalStorage } from './localStorage'; import { getNamespacesFn } from './namespaces'; +import { DbType } from '@percona/types'; export const createDbClusterFn = async ( request: APIRequestContext, @@ -93,7 +94,12 @@ export const createDbClusterFn = async ( // }), }, proxy: { - replicas: +(customOptions?.numberOfNodes || 1), + type: dbTypeToProxyType(dbType), + replicas: +(customOptions?.numberOfProxies || 1), + resources: { + cpu: `${customOptions?.proxyCpu || 1}`, + memory: `${customOptions?.proxyMemory || 1}G`, + }, expose: { type: customOptions?.externalAccess ? 'external' : 'internal', ...(!!customOptions?.externalAccess && @@ -104,6 +110,16 @@ export const createDbClusterFn = async ( }), }, }, + ...(customOptions.sharding && + dbType === DbType.Mongo && { + sharding: { + enabled: true, + shards: customOptions.shards || 1, + configServer: { + replicas: customOptions.configServerReplicas || 3, + }, + }, + }), // TODO return for backups tests // ...(backupDataSource?.dbClusterBackupName && { // dataSource: { 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 db88666f1..6b47a2f92 100644 --- a/ui/apps/everest/src/components/cluster-form/resources/constants.ts +++ b/ui/apps/everest/src/components/cluster-form/resources/constants.ts @@ -2,7 +2,7 @@ import { DbType } from '@percona/types'; import { z } from 'zod'; import { Resources } from 'shared-types/dbCluster.types'; import { DbWizardFormFields } from 'consts'; -import { memoryParser } from 'utils/k8ResourceParser'; +import { cpuParser, memoryParser } from 'utils/k8ResourceParser'; import { Messages } from './messages'; const resourceToNumber = (minimum = 0) => @@ -15,19 +15,25 @@ const resourceToNumber = (minimum = 0) => ); export const matchFieldsValueToResourceSize = ( - dbType: DbType, + sizes: Record< + Exclude, + Record<'cpu' | 'memory', number> + >, resources?: Resources ): ResourceSize => { if (!resources) { return ResourceSize.custom; } - const memory = memoryParser(resources.memory.toString()); - - const res = Object.values(NODES_DEFAULT_SIZES[dbType]).findIndex( - (item) => item.cpu === Number(resources.cpu) && item.memory === memory.value - ); + const memory = memoryParser(resources.memory.toString(), 'G'); + const res = Object.values(sizes).findIndex((item) => { + const sizeParsedMemory = memoryParser(item.memory.toString(), 'G'); + return ( + cpuParser(item.cpu.toString()) === cpuParser(resources.cpu.toString()) && + sizeParsedMemory.value === memory.value + ); + }); return res !== -1 - ? (Object.keys(NODES_DEFAULT_SIZES[dbType])[res] as ResourceSize) + ? (Object.keys(sizes)[res] as ResourceSize) : ResourceSize.custom; }; 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 b29310705..cafe0ebcd 100644 --- a/ui/apps/everest/src/components/cluster-form/resources/resources.tsx +++ b/ui/apps/everest/src/components/cluster-form/resources/resources.tsx @@ -194,7 +194,9 @@ const ResourcesToggles = ({ useEffect(() => { if (diskCapacityExceeded) { setError(diskInputName, { type: 'custom' }); - } else clearErrors(diskInputName); + } else { + clearErrors(diskInputName); + } }, [diskCapacityExceeded, clearErrors, setError]); useEffect(() => { @@ -208,12 +210,13 @@ const ResourcesToggles = ({ useEffect(() => { if ( + allowDiskInputUpdate && resourceSizePerUnit !== ResourceSize.custom && disk !== sizeOptions[resourceSizePerUnit].disk ) { setValue(resourceSizePerUnitInputName, ResourceSize.custom); } - }, [disk, setValue]); + }, [disk, allowDiskInputUpdate, setValue]); useEffect(() => { if ( @@ -487,7 +490,14 @@ const ResourcesForm = ({ setValue(DbWizardFormFields.numberOfProxies, CUSTOM_NR_UNITS_INPUT_VALUE); setValue(DbWizardFormFields.customNrOfProxies, customNrOfNodes); } - }, [setValue, getFieldState, customNrOfNodes, dbType, numberOfNodes]); + }, [ + setValue, + getFieldState, + customNrOfNodes, + dbType, + numberOfNodes, + pairProxiesWithNodes, + ]); useEffect(() => { const { isTouched: isConfigServersTouched } = getFieldState( 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 3b8a26647..a33a3a4a5 100644 --- a/ui/apps/everest/src/hooks/api/db-cluster/utils.ts +++ b/ui/apps/everest/src/hooks/api/db-cluster/utils.ts @@ -1,7 +1,7 @@ import { DbType } from '@percona/types'; +import { dbTypeToProxyType } from '@percona/utils'; import { CUSTOM_NR_UNITS_INPUT_VALUE } from 'components/cluster-form'; import { Proxy, ProxyExposeType } from 'shared-types/dbCluster.types'; -import { dbTypeToProxyType } from 'utils/db'; export const getProxySpec = ( dbType: DbType, @@ -13,10 +13,7 @@ export const getProxySpec = ( sharding: boolean, sourceRanges?: Array<{ sourceRange?: string }> ): Proxy | Record => { - console.log('dbType', dbType); - console.log('sharding', sharding); if (dbType === DbType.Mongo && !sharding) { - console.log('returning empty object'); return {}; } const proxyNr = parseInt( 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 0138cdc6d..756b5940f 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 @@ -29,6 +29,8 @@ import { getDefaultNumberOfconfigServersByNumberOfNodes, matchFieldsValueToResourceSize, NODES_DB_TYPE_MAP, + NODES_DEFAULT_SIZES, + PROXIES_DEFAULT_SIZES, } from 'components/cluster-form'; const replicasToNodes = (replicas: string, dbType: DbType): string => { @@ -99,11 +101,11 @@ export const DbClusterPayloadToFormValues = ( [DbWizardFormFields.customNrOfNodes]: replicas, [DbWizardFormFields.customNrOfProxies]: proxies, [DbWizardFormFields.resourceSizePerNode]: matchFieldsValueToResourceSize( - dbEngineToDbType(dbCluster?.spec?.engine?.type), + NODES_DEFAULT_SIZES[dbEngineToDbType(dbCluster?.spec?.engine?.type)], dbCluster?.spec?.engine?.resources ), [DbWizardFormFields.resourceSizePerProxy]: matchFieldsValueToResourceSize( - dbEngineToDbType(dbCluster?.spec?.engine?.type), + PROXIES_DEFAULT_SIZES[dbEngineToDbType(dbCluster?.spec?.engine?.type)], dbCluster?.spec?.proxy.resources ), [DbWizardFormFields.sharding]: dbCluster?.spec?.sharding?.enabled || false, 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 3fcfa2261..d952fc2db 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 @@ -24,6 +24,8 @@ import { CUSTOM_NR_UNITS_INPUT_VALUE, matchFieldsValueToResourceSize, NODES_DB_TYPE_MAP, + NODES_DEFAULT_SIZES, + PROXIES_DEFAULT_SIZES, resourcesFormSchema, } from 'components/cluster-form'; import OverviewSection from '../overview-section'; @@ -138,6 +140,7 @@ export const ResourcesDetails = ({ size="small" startIcon={} onClick={() => setOpenEditModal(true)} + data-testid="edit-resources-button" > Edit @@ -245,11 +248,11 @@ export const ResourcesDetails = ({ customNrOfNodes: replicas, customNrOfProxies: proxies, resourceSizePerNode: matchFieldsValueToResourceSize( - dbType, + NODES_DEFAULT_SIZES[dbType], dbCluster.spec.engine.resources ), resourceSizePerProxy: matchFieldsValueToResourceSize( - dbType, + PROXIES_DEFAULT_SIZES[dbType], isProxy(dbCluster.spec.proxy) ? dbCluster.spec.proxy.resources : undefined diff --git a/ui/apps/everest/src/shared-types/dbCluster.types.ts b/ui/apps/everest/src/shared-types/dbCluster.types.ts index 3c5939f22..24057d53a 100644 --- a/ui/apps/everest/src/shared-types/dbCluster.types.ts +++ b/ui/apps/everest/src/shared-types/dbCluster.types.ts @@ -12,7 +12,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -import { DbEngineType, ProxyType } from './dbEngines.types'; +import { ProxyType } from '@percona/types'; +import { DbEngineType } from './dbEngines.types'; export enum ProxyExposeType { internal = 'internal', diff --git a/ui/apps/everest/src/shared-types/dbEngines.types.ts b/ui/apps/everest/src/shared-types/dbEngines.types.ts index e54622537..4274174d5 100644 --- a/ui/apps/everest/src/shared-types/dbEngines.types.ts +++ b/ui/apps/everest/src/shared-types/dbEngines.types.ts @@ -107,5 +107,3 @@ export type OperatorsUpgradePlan = { upgrades: OperatorUpgradeTask[]; pendingActions: OperatorUpgradePendingAction[]; }; - -export type ProxyType = 'mongos' | 'haproxy' | 'proxysql' | 'pgbouncer'; diff --git a/ui/apps/everest/src/utils/db.tsx b/ui/apps/everest/src/utils/db.tsx index 2508bc6af..dd463333f 100644 --- a/ui/apps/everest/src/utils/db.tsx +++ b/ui/apps/everest/src/utils/db.tsx @@ -1,6 +1,5 @@ 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) => { @@ -30,17 +29,6 @@ export const shortenOperatorName = (name: string) => { return name; }; -export const dbTypeToProxyType = (dbType: DbType): ProxyType => { - switch (dbType) { - case DbType.Mongo: - return 'mongos'; - case DbType.Mysql: - return 'haproxy'; - default: - return 'pgbouncer'; - } -}; - export const isProxy = ( proxy: Proxy | Record ): proxy is Proxy => { diff --git a/ui/packages/types/src/db-type/index.ts b/ui/packages/types/src/db-type/index.ts index d3ceeeb30..59765c2ae 100644 --- a/ui/packages/types/src/db-type/index.ts +++ b/ui/packages/types/src/db-type/index.ts @@ -1,13 +1,15 @@ enum DbType { - Postresql = 'postgresql', - Mongo = 'mongodb', - Mysql = 'mysql', + Postresql = "postgresql", + Mongo = "mongodb", + Mysql = "mysql", } enum DbEngineType { - PSMDB = 'psmdb', - PXC = 'pxc', - POSTGRESQL = 'postgresql', + PSMDB = "psmdb", + PXC = "pxc", + POSTGRESQL = "postgresql", } +export type ProxyType = "mongos" | "haproxy" | "proxysql" | "pgbouncer"; + export { DbType, DbEngineType }; diff --git a/ui/packages/utils/src/db/db.ts b/ui/packages/utils/src/db/db.ts index 4b1fc40a2..6a1557d58 100644 --- a/ui/packages/utils/src/db/db.ts +++ b/ui/packages/utils/src/db/db.ts @@ -1,4 +1,4 @@ -import { DbType, DbEngineType } from '@percona/types'; +import { DbType, DbEngineType, ProxyType } from '@percona/types'; export const dbEngineToDbType = (dbEngine: DbEngineType): DbType => { switch (dbEngine) { @@ -32,3 +32,14 @@ export const beautifyDbTypeName = (dbType: DbType): string => { return 'PostgreSQL'; } }; + +export const dbTypeToProxyType = (dbType: DbType): ProxyType => { + switch (dbType) { + case DbType.Mongo: + return 'mongos'; + case DbType.Mysql: + return 'haproxy'; + default: + return 'pgbouncer'; + } +};