Skip to content

Commit

Permalink
feat: redis and dyminic dbversion (#3449)
Browse files Browse the repository at this point in the history
* get version by cr

* feat: redis
  • Loading branch information
c121914yu committed Jul 3, 2023
1 parent 2f24bbe commit 15add6d
Show file tree
Hide file tree
Showing 18 changed files with 392 additions and 60 deletions.
3 changes: 2 additions & 1 deletion frontend/providers/dbprovider/public/locales/en/common.json
Expand Up @@ -91,5 +91,6 @@
"Confirm delete the backup": "Confirm delete the backup",
"Basic Info": "Basic",
"Restore Backup Tip": "Restoring the backup will create a new database, and you will need to provide the name of the new data, which cannot be the same as the current database.",
"Total Price": "Total"
"Total Price": "Total",
"Redis HA": "HA"
}
4 changes: 3 additions & 1 deletion frontend/providers/dbprovider/public/locales/zh/common.json
Expand Up @@ -121,5 +121,7 @@
"Backup Database": "备份数据库",
"Manual Backup": "手动备份",
"Auto Backup": "自动备份",
"Containers": "容器"
"Containers": "容器",
"Redis does not support backup at this time": "Redis 暂时不支持备份",
"The multi-replica Redis includes High Availability (HA) nodes. Please note, the anticipated price already encompasses the cost for the HA nodes.": "Redis 多副本包含 HA 节点,请悉知,预估价格已包含 HA 节点费用"
}
2 changes: 2 additions & 0 deletions frontend/providers/dbprovider/src/api/platform.ts
@@ -1,4 +1,6 @@
import { GET, POST, DELETE } from '@/services/request';
import type { Response as resourcePriceResponse } from '@/pages/api/platform/resourcePrice';
import type { Response as DBVersionMapType } from '@/pages/api/platform/getVersion';

export const getResourcePrice = () => GET<resourcePriceResponse>('/api/platform/resourcePrice');
export const getDBVersionMap = () => GET<DBVersionMapType>('/api/platform/getVersion');
Expand Up @@ -46,6 +46,7 @@ const RangeInput = ({
return (
<Tooltip label={hoverText} closeOnClick={false}>
<HStack
flex={`0 0 ${w}px`}
w={`${w}px`}
position={'relative'}
borderBottom={`2px solid`}
Expand Down
5 changes: 4 additions & 1 deletion frontend/providers/dbprovider/src/components/Tip/index.tsx
@@ -1,5 +1,6 @@
import React, { useMemo } from 'react';
import { BoxProps, Flex, Box } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';

interface Props extends BoxProps {
text: string;
Expand All @@ -9,6 +10,8 @@ interface Props extends BoxProps {
}

const Tip = ({ size = 'md', text, icon, theme, ...props }: Props) => {
const { t } = useTranslation();

const sizeMap = useMemo(() => {
switch (size) {
case 'sm':
Expand Down Expand Up @@ -55,7 +58,7 @@ const Tip = ({ size = 'md', text, icon, theme, ...props }: Props) => {
{icon}
</Flex>
) : null}
<Box>{text}</Box>
<Box>{t(text)}</Box>
</Flex>
);
};
Expand Down
38 changes: 27 additions & 11 deletions frontend/providers/dbprovider/src/constants/db.ts
@@ -1,12 +1,13 @@
import { DBEditType, DBDetailType, PodDetailType, BackupStatusMapType } from '@/types/db';
import { DBEditType, DBDetailType, PodDetailType } from '@/types/db';
import { CpuSlideMarkList, MemorySlideMarkList } from './editApp';

export const crLabelKey = 'sealos-db-provider-cr';

export enum DBTypeEnum {
'postgresql' = 'postgresql',
'mongodb' = 'mongodb',
'mysql' = 'apecloud-mysql'
'mysql' = 'apecloud-mysql',
'redis' = 'redis'
}

export enum DBStatusEnum {
Expand Down Expand Up @@ -149,27 +150,25 @@ export const minReplicasKey = 'deploy.cloud.sealos.io/minReplicas';
export const DBTypeList = [
{ id: DBTypeEnum.postgresql, label: 'postgres' },
{ id: DBTypeEnum.mongodb, label: 'mongo' },
{ id: DBTypeEnum.mysql, label: 'mysql' }
{ id: DBTypeEnum.mysql, label: 'mysql' },
{ id: DBTypeEnum.redis, label: 'redis' }
];
export const DBVersionMap = {
[DBTypeEnum.postgresql]: [{ id: 'postgresql-14.8.0', label: 'postgresql-14.8.0' }],
[DBTypeEnum.mongodb]: [{ id: 'mongodb-5.0.14', label: 'mongodb-5.0.14' }],
[DBTypeEnum.mysql]: [{ id: 'ac-mysql-8.0.30', label: 'ac-mysql-8.0.30' }]
};
export const DBComponentNameMap = {
[DBTypeEnum.postgresql]: 'postgresql',
[DBTypeEnum.mongodb]: 'mongo',
[DBTypeEnum.mysql]: 'mysql'
[DBTypeEnum.mysql]: 'mysql',
[DBTypeEnum.redis]: 'redis'
};
export const DBBackupPolicyNameMap = {
[DBTypeEnum.postgresql]: 'postgresql',
[DBTypeEnum.mongodb]: 'mongodb',
[DBTypeEnum.mysql]: 'mysql'
[DBTypeEnum.mysql]: 'mysql',
[DBTypeEnum.redis]: 'redis'
};

export const defaultDBEditValue: DBEditType = {
dbType: DBTypeEnum.postgresql,
dbVersion: DBVersionMap[DBTypeEnum.postgresql][0].id,
dbVersion: '',
dbName: 'dbname',
replicas: 1,
cpu: CpuSlideMarkList[1].value,
Expand All @@ -195,3 +194,20 @@ export const defaultPod: PodDetailType = {
cpu: 1,
memory: 1
};

export const RedisHAConfig = (ha = true) => {
if (ha) {
return {
cpu: 200,
memory: 200,
storage: 1,
replicas: 3
};
}
return {
cpu: 100,
memory: 100,
storage: 0,
replicas: 1
};
};
5 changes: 4 additions & 1 deletion frontend/providers/dbprovider/src/pages/_app.tsx
Expand Up @@ -15,7 +15,7 @@ import { useLoading } from '@/hooks/useLoading';
import { useRouter } from 'next/router';
import { appWithTranslation, useTranslation } from 'next-i18next';
import { getLangStore, setLangStore } from '@/utils/cookieUtils';
import { getUserPrice } from '@/store/static';
import { getUserPrice, getDBVersion } from '@/store/static';

import 'nprogress/nprogress.css';
import 'react-day-picker/dist/style.css';
Expand Down Expand Up @@ -60,6 +60,7 @@ function App({ Component, pageProps, domain }: AppProps & { domain: string }) {
} catch (err) {
console.log('App is not running in desktop');
if (!process.env.NEXT_PUBLIC_MOCK_USER) {
localStorage.removeItem('session');
openConfirm(() => {
window.open(`https://${domain}`, '_self');
})();
Expand Down Expand Up @@ -99,6 +100,8 @@ function App({ Component, pageProps, domain }: AppProps & { domain: string }) {
};

getUserPrice();
getDBVersion();

(async () => {
try {
const lang = await sealosApp.getLanguage();
Expand Down
Expand Up @@ -38,6 +38,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
[DBTypeEnum.mysql]: {
passwordKey: 'password',
connectKey: 'mysql'
},
[DBTypeEnum.redis]: {
passwordKey: 'password',
connectKey: 'redis'
}
};
// get secret
Expand Down
64 changes: 64 additions & 0 deletions frontend/providers/dbprovider/src/pages/api/platform/getVersion.ts
@@ -0,0 +1,64 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { K8sApi } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { DBTypeEnum } from '@/constants/db';
import * as k8s from '@kubernetes/client-node';

export type Response = Record<
`${DBTypeEnum}`,
{
id: string;
label: string;
}[]
>;

const MOCK = {
[DBTypeEnum.postgresql]: [{ id: 'postgresql-14.8.0', label: 'postgresql-14.8.0' }],
[DBTypeEnum.mongodb]: [{ id: 'mongodb-5.0.14', label: 'mongodb-5.0.14' }],
[DBTypeEnum.mysql]: [{ id: 'ac-mysql-8.0.30', label: 'ac-mysql-8.0.30' }],
[DBTypeEnum.redis]: [{ id: 'redis-7.0.6', label: 'redis-7.0.6' }]
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const DBVersionMap: Response = {
[DBTypeEnum.postgresql]: [],
[DBTypeEnum.mongodb]: [],
[DBTypeEnum.mysql]: [],
[DBTypeEnum.redis]: []
};

// source price
const kc = K8sApi();
const k8sCustomObjects = kc.makeApiClient(k8s.CustomObjectsApi);

const { body } = (await k8sCustomObjects.listClusterCustomObject(
'apps.kubeblocks.io',
'v1alpha1',
'clusterversions'
)) as any;

body.items.forEach((item: any) => {
const db = item?.spec?.clusterDefinitionRef as `${DBTypeEnum}`;
if (
DBVersionMap[db] &&
item?.metadata?.name &&
!DBVersionMap[db].find((db) => db.id === item.metadata.name)
) {
DBVersionMap[db].push({
id: item.metadata.name,
label: item.metadata.name
});
}
});

jsonRes(res, {
data: DBVersionMap
});
} catch (error) {
console.log(error);
jsonRes(res, {
data: MOCK
});
}
}
Expand Up @@ -60,7 +60,8 @@ const AppBaseInfo = ({ db = defaultDBDetail }: { db: DBDetailType }) => {
const commandMap = {
[DBTypeEnum.postgresql]: `psql '${secret.connection}'`,
[DBTypeEnum.mongodb]: `mongosh '${secret.connection}'`,
[DBTypeEnum.mysql]: `mysql -h ${secret.host} -P ${secret.port} -u ${secret.username} -p${secret.password}`
[DBTypeEnum.mysql]: `mysql -h ${secret.host} -P ${secret.port} -u ${secret.username} -p${secret.password}`,
[DBTypeEnum.redis]: `redis-cli -h ${secret.host} -p ${secret.port}`
};

const defaultCommand = commandMap[db.dbType];
Expand Down
15 changes: 14 additions & 1 deletion frontend/providers/dbprovider/src/pages/db/detail/index.tsx
Expand Up @@ -12,6 +12,7 @@ import AppBaseInfo from './components/AppBaseInfo';
import Pods from './components/Pods';
import BackupTable, { type ComponentRef } from './components/BackupTable';
import { useTranslation } from 'next-i18next';
import { DBTypeEnum } from '@/constants/db';

enum TabEnum {
pod = 'pod',
Expand Down Expand Up @@ -110,7 +111,19 @@ const AppDetail = ({ dbName, listType }: { dbName: string; listType: `${TabEnum}
{listType === 'pod' && <Box color={'myGray.500'}>{dbPods.length} Items</Box>}
{listType === 'backup' && !BackupTableRef.current?.backupProcessing && (
<Flex alignItems={'center'}>
<Button ml={3} variant={'primary'} onClick={BackupTableRef.current?.openBackup}>
<Button
ml={3}
variant={'primary'}
onClick={() => {
if (dbDetail.dbType === DBTypeEnum.redis) {
return toast({
status: 'warning',
title: t('Redis does not support backup at this time')
});
}
BackupTableRef.current?.openBackup();
}}
>
{t('Backup')}
</Button>
</Flex>
Expand Down
Expand Up @@ -11,7 +11,8 @@ import {
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
Tooltip
Tooltip,
Switch
} from '@chakra-ui/react';
import { UseFormReturn } from 'react-hook-form';
import { useRouter } from 'next/router';
Expand All @@ -23,13 +24,16 @@ import type { DBEditType } from '@/types/db';
import { CpuSlideMarkList, MemorySlideMarkList } from '@/constants/editApp';
import Tabs from '@/components/Tabs';
import MySelect from '@/components/Select';
import { DBTypeList, DBVersionMap } from '@/constants/db';
import { DBTypeEnum, DBTypeList, RedisHAConfig } from '@/constants/db';
import { DBVersionMap } from '@/store/static';
import { useTranslation } from 'next-i18next';
import PriceBox from './PriceBox';
import { INSTALL_ACCOUNT } from '@/store/static';
import Tip from '@/components/Tip';

import { obj2Query } from '@/api/tools';
import { throttle } from 'lodash';
import { InfoOutlineIcon } from '@chakra-ui/icons';

const Form = ({
formHook,
Expand Down Expand Up @@ -196,10 +200,25 @@ const Form = ({
{INSTALL_ACCOUNT && (
<Box mt={3} borderRadius={'sm'} overflow={'hidden'} backgroundColor={'white'} p={3}>
<PriceBox
pods={[getValues('replicas') || 1, getValues('replicas') || 1]}
cpu={getValues('cpu')}
memory={getValues('memory')}
storage={getValues('storage')}
components={[
{
cpu: getValues('cpu'),
memory: getValues('memory'),
storage: getValues('storage'),
replicas: [getValues('replicas') || 1, getValues('replicas') || 1]
},
...(getValues('dbType') === DBTypeEnum.redis
? (() => {
const config = RedisHAConfig(getValues('replicas') > 1);
return [
{
...config,
replicas: [config.replicas, config.replicas]
}
];
})()
: [])
]}
/>
</Box>
)}
Expand Down Expand Up @@ -292,6 +311,7 @@ const Form = ({
<Flex mb={8} alignItems={'center'}>
<Label w={80}>{t('Replicas')}</Label>
<RangeInput
w={180}
value={getValues('replicas')}
min={1}
max={20}
Expand All @@ -310,12 +330,22 @@ const Form = ({
setValue('replicas', val || 1);
}}
/>
{getValues('dbType') === DBTypeEnum.redis && getValues('replicas') > 1 && (
<Tip
ml={4}
icon={<InfoOutlineIcon />}
text="The multi-replica Redis includes High Availability (HA) nodes. Please note, the anticipated price already encompasses the cost for the HA nodes."
size="sm"
/>
)}
</Flex>

<FormControl isInvalid={!!errors.storage} w={'500px'}>
<Flex alignItems={'center'}>
<Label w={80}>{t('Storage')}</Label>
<Tooltip label={`${t('Storage Range')}${minStorage}~200 Gi`}>
<NumberInput
w={'180px'}
max={200}
min={minStorage}
step={1}
Expand Down

0 comments on commit 15add6d

Please sign in to comment.