Skip to content

Commit

Permalink
feat: redis
Browse files Browse the repository at this point in the history
  • Loading branch information
c121914yu committed Jun 30, 2023
1 parent 8811241 commit cf8bd5d
Show file tree
Hide file tree
Showing 17 changed files with 335 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 节点费用"
}
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
29 changes: 25 additions & 4 deletions frontend/providers/dbprovider/src/constants/db.ts
Expand Up @@ -6,7 +6,8 @@ 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,17 +150,20 @@ 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 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 = {
Expand Down Expand Up @@ -190,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
};
};
1 change: 1 addition & 0 deletions frontend/providers/dbprovider/src/pages/_app.tsx
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 @@ -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
44 changes: 39 additions & 5 deletions frontend/providers/dbprovider/src/pages/api/platform/getVersion.ts
@@ -1,8 +1,8 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import * as yaml from 'js-yaml';
import { getK8s } from '@/services/backend/kubernetes';
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}`,
Expand All @@ -12,19 +12,53 @@ export type Response = Record<
}[]
>;

const DBVersionMap = {
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.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, { code: 500, message: 'get price 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,14 +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 } 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 @@ -197,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 @@ -293,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 @@ -311,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
Expand Up @@ -11,36 +11,52 @@ export const colorMap = {
};

const PriceBox = ({
cpu,
memory,
storage,
pods = [1, 1]
}: resourcePriceResponse & { pods: [number, number] }) => {
components = []
}: {
components: {
cpu: number;
memory: number;
storage: number;
replicas: number[];
}[];
}) => {
const { t } = useTranslation();

const priceList = useMemo(() => {
const cpuP = +((SOURCE_PRICE.cpu * cpu * 24) / 1000).toFixed(2);
const memoryP = +((SOURCE_PRICE.memory * memory * 24) / 1024).toFixed(2);
const storageP = +(SOURCE_PRICE.storage * storage * 24).toFixed(2);
const totalP = +(cpuP + memoryP + storageP).toFixed(2);
let cp = [0, 0];
let mp = [0, 0];
let sp = [0, 0];
let tp = [0, 0];
components.forEach(({ cpu, memory, storage, replicas }) => {
const cpuP = (SOURCE_PRICE.cpu * cpu * 24) / 1000;
const memoryP = (SOURCE_PRICE.memory * memory * 24) / 1024;
const storageP = SOURCE_PRICE.storage * storage * 24;
const totalP = cpuP + memoryP + storageP;

replicas.forEach((item, i) => {
cp[i] += cpuP * item;
mp[i] += memoryP * item;
sp[i] += storageP * item;
tp[i] += totalP * item;
});
});

const podScale = (val: number) => {
const min = (val * pods[0]).toFixed(2);
const max = (val * pods[1]).toFixed(2);
return pods[0] === pods[1] ? `¥${min}` : `¥${min} ~ ${max}`;
const podScale = (val: number[]) => {
return val[0] === val[1]
? `¥${val[0].toFixed(2)}`
: `¥${val[0].toFixed(2)} ~ ${val[1].toFixed(2)}`;
};

return [
{
label: 'CPU',
color: '#33BABB',
value: podScale(cpuP)
value: podScale(cp)
},
{ label: 'Memory', color: '#36ADEF', value: podScale(memoryP) },
{ label: 'Storage', color: '#8172D8', value: podScale(storageP) },
{ label: 'Total Price', color: '#485058', value: podScale(totalP) }
{ label: 'Memory', color: '#36ADEF', value: podScale(mp) },
{ label: 'Storage', color: '#8172D8', value: podScale(sp) },
{ label: 'Total Price', color: '#485058', value: podScale(tp) }
];
}, [cpu, memory, pods, storage]);
}, [components]);

return (
<Box>
Expand Down

0 comments on commit cf8bd5d

Please sign in to comment.