diff --git a/frontend/providers/dbprovider/src/pages/api-docs.tsx b/frontend/providers/dbprovider/src/pages/api-docs.tsx
index 8438a51c7..96610af45 100644
--- a/frontend/providers/dbprovider/src/pages/api-docs.tsx
+++ b/frontend/providers/dbprovider/src/pages/api-docs.tsx
@@ -7,6 +7,5 @@ export default function ApiDocs() {
const config = {
content: document
};
-
return ;
}
diff --git a/frontend/providers/dbprovider/src/pages/api/v1/database.ts b/frontend/providers/dbprovider/src/pages/api/v1/database.ts
index 2aa0647b5..3acde0c5a 100644
--- a/frontend/providers/dbprovider/src/pages/api/v1/database.ts
+++ b/frontend/providers/dbprovider/src/pages/api/v1/database.ts
@@ -39,12 +39,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
});
}
- await createDatabase(k8s, {
+ const result = await createDatabase(k8s, {
body: bodyParseResult.data
});
- jsonRes(res, {
- data: 'success create db'
+ return jsonRes(res, {
+ message: 'success create db',
+ data: result
});
} catch (err: any) {
console.log('error create db', err);
diff --git a/frontend/providers/dbprovider/src/pages/api/v1/database/[databaseName].ts b/frontend/providers/dbprovider/src/pages/api/v1/database/[databaseName].ts
index 1c3805511..2ab11ee16 100644
--- a/frontend/providers/dbprovider/src/pages/api/v1/database/[databaseName].ts
+++ b/frontend/providers/dbprovider/src/pages/api/v1/database/[databaseName].ts
@@ -3,8 +3,11 @@ import { getK8s } from '@/services/backend/kubernetes';
import { handleK8sError, jsonRes } from '@/services/backend/response';
import { NextApiRequest, NextApiResponse } from 'next';
import { ResponseCode, ResponseMessages } from '@/types/response';
-import { updateDatabaseSchemas } from '@/types/apis';
+import { createDatabaseSchemas, getDatabaseSchemas, updateDatabaseSchemas } from '@/types/apis';
import { updateDatabase } from '@/services/backend/apis/update-database';
+import { getDatabase } from '@/services/backend/apis/get-database';
+import path from 'node:path/win32';
+import { deleteDatabase } from '@/services/backend/apis/delete-database';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const kubeconfig = await authSession(req).catch(() => null);
@@ -22,18 +25,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
message: ResponseMessages[ResponseCode.UNAUTHORIZED]
});
}
-
+ const pathParamsParseResult = getDatabaseSchemas.pathParams.safeParse(req.query);
+ if (!pathParamsParseResult.success) {
+ return jsonRes(res, {
+ code: ResponseCode.BAD_REQUEST,
+ message: ResponseMessages[ResponseCode.BAD_REQUEST],
+ error: pathParamsParseResult.error.issues
+ });
+ }
if (req.method === 'PATCH') {
try {
- const pathParamsParseResult = updateDatabaseSchemas.pathParams.safeParse(req.query);
- if (!pathParamsParseResult.success) {
- return jsonRes(res, {
- code: 400,
- message: 'Invalid request params.',
- error: pathParamsParseResult.error.issues
- });
- }
-
const bodyParseResult = updateDatabaseSchemas.body.safeParse(req.body);
if (!bodyParseResult.success) {
return jsonRes(res, {
@@ -48,17 +49,47 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
body: bodyParseResult.data
});
- return jsonRes(res, {
- data: `Successfully submitted ${result.opsRequests.length} change requests`
- });
+ return jsonRes(res, result);
} catch (err) {
- console.log('error create db', err);
+ console.log('error update db', err);
jsonRes(res, handleK8sError(err));
}
+ } else if (req.method === 'GET') {
+ try {
+ const pathParamsParseResult = getDatabaseSchemas.pathParams.safeParse(req.query);
+ if (!pathParamsParseResult.success) {
+ return jsonRes(res, {
+ code: ResponseCode.BAD_REQUEST,
+ message: ResponseMessages[ResponseCode.BAD_REQUEST],
+ error: pathParamsParseResult.error.issues
+ });
+ }
+ const result = await getDatabase(k8s, {
+ params: pathParamsParseResult.data
+ });
+ jsonRes(res, {
+ data: result
+ });
+ } catch (err) {
+ console.log('error get db by name', err);
+ jsonRes(res, handleK8sError(err));
+ }
+ } else if (req.method === 'DELETE') {
+ try {
+ await deleteDatabase(k8s, {
+ params: pathParamsParseResult.data
+ });
+ jsonRes(res, {
+ data: `Successfully deleted`
+ });
+ } catch (err) {
+ console.log('error delete db', err);
+ jsonRes(res, handleK8sError(err));
+ }
+ } else {
+ return jsonRes(res, {
+ code: 405,
+ message: 'Method not allowed'
+ });
}
-
- return jsonRes(res, {
- code: 405,
- message: 'Method not allowed'
- });
}
diff --git a/frontend/providers/dbprovider/src/pages/api/v1/database/list.ts b/frontend/providers/dbprovider/src/pages/api/v1/database/list.ts
new file mode 100644
index 000000000..5c6405c9e
--- /dev/null
+++ b/frontend/providers/dbprovider/src/pages/api/v1/database/list.ts
@@ -0,0 +1,36 @@
+import { authSession } from '@/services/backend/auth';
+import { getK8s } from '@/services/backend/kubernetes';
+import { handleK8sError, jsonRes } from '@/services/backend/response';
+import { NextApiRequest, NextApiResponse } from 'next';
+import { ResponseCode, ResponseMessages } from '@/types/response';
+import { updateDatabaseSchemas } from '@/types/apis';
+import { updateDatabase } from '@/services/backend/apis/update-database';
+import { KbPgClusterType } from '@/types/cluster';
+import { adaptDBListItem } from '@/utils/adapt';
+import { getDatabaseList } from '@/services/backend/apis/list-database';
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ try {
+ const kubeconfig = await authSession(req).catch(() => null);
+ if (!kubeconfig) {
+ return jsonRes(res, {
+ code: ResponseCode.UNAUTHORIZED,
+ message: ResponseMessages[ResponseCode.UNAUTHORIZED]
+ });
+ }
+
+ const k8s = await getK8s({ kubeconfig }).catch(() => null);
+ if (!k8s) {
+ return jsonRes(res, {
+ code: ResponseCode.UNAUTHORIZED,
+ message: ResponseMessages[ResponseCode.UNAUTHORIZED]
+ });
+ }
+ const data = await getDatabaseList(k8s);
+
+ return jsonRes(res, { data });
+ } catch (err) {
+ console.log('error list db', err);
+ jsonRes(res, handleK8sError(err));
+ }
+}
diff --git a/frontend/providers/dbprovider/src/pages/api/v1/database/version/list.ts b/frontend/providers/dbprovider/src/pages/api/v1/database/version/list.ts
new file mode 100644
index 000000000..e17cfab8d
--- /dev/null
+++ b/frontend/providers/dbprovider/src/pages/api/v1/database/version/list.ts
@@ -0,0 +1,76 @@
+import { authSession } from '@/services/backend/auth';
+import { getK8s, K8sApi } from '@/services/backend/kubernetes';
+import { handleK8sError, jsonRes } from '@/services/backend/response';
+import { NextApiRequest, NextApiResponse } from 'next';
+import { ResponseCode, ResponseMessages } from '@/types/response';
+import { createDatabaseSchemas, getDatabaseSchemas, updateDatabaseSchemas } from '@/types/apis';
+import { updateDatabase } from '@/services/backend/apis/update-database';
+import { getDatabase } from '@/services/backend/apis/get-database';
+import { adaptDBDetail } from '@/utils/adapt';
+import { createDatabase } from '@/services/backend/apis/create-database';
+import { dbDetailSchema, dbTypeSchema, versionListSchema } from '@/types/schemas/db';
+import path from 'node:path/win32';
+import { deleteDatabase } from '@/services/backend/apis/delete-database';
+import { DBTypeEnum } from '@/constants/db';
+import { result } from 'lodash';
+import z from 'zod';
+import { DBVersionMap } from '@/store/static';
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ const kc = K8sApi();
+
+ const k8s = (await getK8s({ kubeconfig: kc.exportConfig() }))!;
+
+ if (req.method === 'GET') {
+ try {
+ const DBVersion: z.Infer = {
+ [DBTypeEnum.postgresql]: [],
+ [DBTypeEnum.mongodb]: [],
+ [DBTypeEnum.mysql]: [],
+ [DBTypeEnum.redis]: [],
+ [DBTypeEnum.kafka]: [],
+ [DBTypeEnum.qdrant]: [],
+ [DBTypeEnum.nebula]: [],
+ [DBTypeEnum.weaviate]: [],
+ [DBTypeEnum.milvus]: [],
+ [DBTypeEnum.pulsar]: [],
+ [DBTypeEnum.clickhouse]: []
+ };
+
+ // source price
+ const { k8sCustomObjects } = k8s;
+
+ 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].unshift(item.metadata.name);
+ }
+ });
+
+ jsonRes(res, {
+ data: DBVersionMap
+ });
+ jsonRes(res, {
+ data: result
+ });
+ } catch (err) {
+ console.log('error get db by name', err);
+ jsonRes(res, handleK8sError(err));
+ }
+ } else {
+ return jsonRes(res, {
+ code: 405,
+ message: 'Method not allowed'
+ });
+ }
+}
diff --git a/frontend/providers/dbprovider/src/pages/api/v1/logs/files.ts b/frontend/providers/dbprovider/src/pages/api/v1/logs/files.ts
new file mode 100644
index 000000000..2649f1692
--- /dev/null
+++ b/frontend/providers/dbprovider/src/pages/api/v1/logs/files.ts
@@ -0,0 +1,92 @@
+import { ServiceLogConfigs } from '@/constants/log';
+import { authSession } from '@/services/backend/auth';
+import { getK8s } from '@/services/backend/kubernetes';
+import { jsonRes } from '@/services/backend/response';
+import { ApiResp } from '@/services/kubernet';
+import { SupportReconfigureDBType } from '@/types/db';
+import { LogTypeEnum } from '@/constants/log';
+import { KubeFileSystem } from '@/utils/kubeFileSystem';
+import type { NextApiRequest, NextApiResponse } from 'next';
+import { ResponseCode, ResponseMessages } from '@/types/response';
+import { logsFileSchemas } from '@/types/apis';
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ try {
+ const kubeconfig = await authSession(req).catch(() => null);
+ if (!kubeconfig) {
+ return jsonRes(res, {
+ code: ResponseCode.UNAUTHORIZED,
+ message: ResponseMessages[ResponseCode.UNAUTHORIZED]
+ });
+ }
+
+ const k8s = await getK8s({ kubeconfig }).catch(() => null);
+ if (!k8s) {
+ return jsonRes(res, {
+ code: ResponseCode.UNAUTHORIZED,
+ message: ResponseMessages[ResponseCode.UNAUTHORIZED]
+ });
+ }
+ const { namespace, k8sExec, k8sCore } = k8s;
+ const parseResult = logsFileSchemas.query.safeParse({
+ podName: req.query.podName as string,
+ dbType: req.query.dbType as SupportReconfigureDBType,
+ logType: req.query.logType as LogTypeEnum
+ });
+ if (!parseResult.success) {
+ return jsonRes(res, {
+ code: ResponseCode.BAD_REQUEST,
+ message: ResponseMessages[ResponseCode.BAD_REQUEST]
+ });
+ }
+ const { podName, dbType, logType } = parseResult.data;
+
+ const kubefs = new KubeFileSystem(k8sExec);
+
+ const logConfig = ServiceLogConfigs[dbType][logType];
+
+ console.log('/api/logs/getFiles', { podName, dbType, logType, logConfig });
+
+ if (!logConfig) {
+ throw new Error('Invalid log type');
+ }
+
+ let files, directories;
+ let lastError: any;
+ for (const container of logConfig.containerNames) {
+ try {
+ const result = await kubefs.ls({
+ namespace,
+ podName,
+ containerName: container,
+ path: logConfig.path,
+ showHidden: false
+ });
+ files = result.files;
+ directories = result.directories;
+ break;
+ } catch (error) {
+ lastError = error;
+ console.error('/api/logs/getFiles error', error);
+ continue;
+ }
+ }
+
+ if (!files) {
+ throw new Error(lastError?.message || 'No valid log files found in any container');
+ }
+
+ const validFiles = logConfig.filter(files);
+
+ if (!validFiles || validFiles.length === 0) {
+ throw new Error('No valid log files found');
+ }
+
+ jsonRes(res, { data: validFiles });
+ } catch (err: any) {
+ jsonRes(res, {
+ code: 500,
+ error: err
+ });
+ }
+}
diff --git a/frontend/providers/dbprovider/src/pages/api/v1/logs/index.ts b/frontend/providers/dbprovider/src/pages/api/v1/logs/index.ts
new file mode 100644
index 000000000..f23fcf076
--- /dev/null
+++ b/frontend/providers/dbprovider/src/pages/api/v1/logs/index.ts
@@ -0,0 +1,74 @@
+import { DBTypeEnum } from '@/constants/db';
+import { ServiceLogConfigs } from '@/constants/log';
+import { authSession } from '@/services/backend/auth';
+import { getK8s } from '@/services/backend/kubernetes';
+import { jsonRes } from '@/services/backend/response';
+import { ApiResp } from '@/services/kubernet';
+import { SupportReconfigureDBType } from '@/types/db';
+import { LogTypeEnum } from '@/constants/log';
+import { DatabaseLogService } from '@/utils/logParsers/LogParser';
+import type { NextApiRequest, NextApiResponse } from 'next';
+import { ResponseCode, ResponseMessages } from '@/types/response';
+import { logsDataSchemas } from '@/types/apis';
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ try {
+ const kubeconfig = await authSession(req).catch(() => null);
+ if (!kubeconfig) {
+ return jsonRes(res, {
+ code: ResponseCode.UNAUTHORIZED,
+ message: ResponseMessages[ResponseCode.UNAUTHORIZED]
+ });
+ }
+
+ const k8s = await getK8s({ kubeconfig }).catch(() => null);
+ if (!k8s) {
+ return jsonRes(res, {
+ code: ResponseCode.UNAUTHORIZED,
+ message: ResponseMessages[ResponseCode.UNAUTHORIZED]
+ });
+ }
+ const { namespace, k8sExec, k8sCore } = k8s;
+
+ const parseResult = logsDataSchemas.query.safeParse({
+ podName: req.query.podName as string,
+ dbType: req.query.dbType as SupportReconfigureDBType,
+ logType: req.query.logType as LogTypeEnum,
+ logPath: req.query.logPath as string,
+ page: parseInt((req.query.page as string) || '0'),
+ pageSize: parseInt((req.query.pageSize as string) || '10')
+ });
+ if (!parseResult.success) {
+ return jsonRes(res, {
+ code: ResponseCode.BAD_REQUEST,
+ message: ResponseMessages[ResponseCode.BAD_REQUEST]
+ });
+ }
+ const { podName, dbType, logType, logPath, page = 0, pageSize = 10 } = parseResult.data;
+
+ const logConfig = ServiceLogConfigs[dbType][logType];
+
+ if (!logConfig) {
+ throw new Error('Invalid log type');
+ }
+
+ const logService = new DatabaseLogService(k8sExec, k8sCore, namespace);
+
+ const result = await logService.readLogs({
+ podName,
+ containerNames: logConfig.containerNames,
+ logPath,
+ page,
+ pageSize,
+ dbType: dbType as DBTypeEnum,
+ logType
+ });
+
+ return jsonRes(res, { data: result });
+ } catch (err: any) {
+ jsonRes(res, {
+ code: 500,
+ error: err
+ });
+ }
+}
diff --git a/frontend/providers/dbprovider/src/pages/api/v1/monitor/data.ts b/frontend/providers/dbprovider/src/pages/api/v1/monitor/data.ts
new file mode 100644
index 000000000..2d283c90b
--- /dev/null
+++ b/frontend/providers/dbprovider/src/pages/api/v1/monitor/data.ts
@@ -0,0 +1,116 @@
+import { authSession } from '@/services/backend/auth';
+import { getK8s } from '@/services/backend/kubernetes';
+import { jsonRes } from '@/services/backend/response';
+import { handleAxiosStream } from '@/services/handleStream';
+import { ApiResp } from '@/services/kubernet';
+import { AdapterChartDataType, MonitorChartDataResult, MonitorDBResult } from '@/types/monitor';
+import { ResponseCode, ResponseMessages } from '@/types/response';
+import type { NextApiRequest, NextApiResponse } from 'next';
+
+const AdapterChartData: AdapterChartDataType = {
+ disk: (data: MonitorDBResult) => {
+ const temp = data?.data?.result;
+ let XTimePoint: number[] = [];
+ const desiredResult = temp.map((dataObject, index) => {
+ const name = dataObject.metric?.persistentvolumeclaim;
+ if (index === 0) {
+ XTimePoint = dataObject.values.map((timePoint) => timePoint[0]);
+ }
+ const data = dataObject.values.map((item) => parseFloat(item[1]));
+ return { name, data };
+ });
+ return {
+ xData: XTimePoint,
+ yData: desiredResult
+ };
+ },
+ cpu: (data: MonitorDBResult) => {
+ const temp = data?.data?.result;
+ let XTimePoint: number[] = [];
+ const desiredResult = temp.map((dataObject, index) => {
+ const name = dataObject.metric?.pod;
+ if (index === 0) {
+ XTimePoint = dataObject.values.map((timePoint) => timePoint[0]);
+ }
+ const data = dataObject.values.map((item) => parseFloat(item[1]));
+ return { name, data };
+ });
+ return {
+ xData: XTimePoint,
+ yData: desiredResult
+ };
+ },
+ memory: (data: MonitorDBResult) => {
+ const temp = data?.data?.result;
+ let XTimePoint: number[] = [];
+ const desiredResult = temp.map((dataObject, index) => {
+ const name = dataObject.metric?.pod;
+ if (index === 0) {
+ XTimePoint = dataObject.values.map((timePoint) => timePoint[0]);
+ }
+ const data = dataObject.values.map((item) => parseFloat(item[1]));
+ return { name, data };
+ });
+ return {
+ xData: XTimePoint,
+ yData: desiredResult
+ };
+ }
+};
+
+export default async function handler(req: NextApiRequest, res: NextApiResponse) {
+ try {
+ const kubeconfig = await authSession(req).catch(() => null);
+ if (!kubeconfig) {
+ return jsonRes(res, {
+ code: ResponseCode.UNAUTHORIZED,
+ message: ResponseMessages[ResponseCode.UNAUTHORIZED]
+ });
+ }
+
+ const k8s = await getK8s({ kubeconfig }).catch(() => null);
+ if (!k8s) {
+ return jsonRes(res, {
+ code: ResponseCode.UNAUTHORIZED,
+ message: ResponseMessages[ResponseCode.UNAUTHORIZED]
+ });
+ }
+ const { namespace } = k8s;
+ const { dbName, dbType, queryKey, start, end, step } = req.query;
+ const endTime = Date.now(); // 当前时间的时间戳
+ const startTime = endTime - 60 * 60 * 1000; // 前向推进1个小时的时间戳
+
+ const params = {
+ query: queryKey,
+ app: dbName,
+ type: dbType,
+ namespace: namespace,
+ start: start ? Number(start) : startTime / 1000,
+ end: end ? Number(end) : endTime / 1000,
+ step: '1m'
+ };
+
+ const result: MonitorChartDataResult = await handleAxiosStream(
+ {
+ url: '/q',
+ params: params
+ },
+ kubeconfig
+ ).then((res) => {
+ // @ts-ignore
+ return AdapterChartData[queryKey] ? AdapterChartData[queryKey](res as MonitorDBResult) : res;
+ });
+
+ jsonRes(res, {
+ code: 200,
+ data: {
+ result
+ }
+ });
+ } catch (error) {
+ jsonRes(res, {
+ code: 500,
+ error: error
+ });
+ }
+}
diff --git a/frontend/providers/dbprovider/src/services/backend/apis/create-database.ts b/frontend/providers/dbprovider/src/services/backend/apis/create-database.ts
index b3c877eea..1dccbe3dc 100644
--- a/frontend/providers/dbprovider/src/services/backend/apis/create-database.ts
+++ b/frontend/providers/dbprovider/src/services/backend/apis/create-database.ts
@@ -4,17 +4,33 @@ import { z } from 'zod';
import { BackupSupportedDBTypeList } from '@/constants/db';
import { updateBackupPolicyApi } from '@/pages/api/backup/updatePolicy';
import { KbPgClusterType } from '@/types/cluster';
-import { convertBackupFormToSpec } from '@/utils/adapt';
+import { adaptDBDetail, convertBackupFormToSpec } from '@/utils/adapt';
import { json2Account, json2CreateCluster } from '@/utils/json2Yaml';
-
+import { DBEditType, EditType } from '@/types/db';
+import { raw2schema } from './get-database';
+const schema2Raw = (dbForm: z.Infer): DBEditType => {
+ return {
+ dbType: dbForm.type,
+ dbVersion: dbForm.version,
+ dbName: dbForm.name,
+ replicas: dbForm.resource.replicas,
+ cpu: parseFloat(dbForm.resource.cpu),
+ memory: parseFloat(dbForm.resource.memory),
+ storage: parseFloat(dbForm.resource.storage),
+ labels: {},
+ terminationPolicy: dbForm.terminationPolicy,
+ autoBackup: dbForm.autoBackup
+ };
+};
export async function createDatabase(
k8s: Awaited>,
request: {
body: z.infer;
}
) {
- const account = json2Account(request.body.dbForm);
- const cluster = json2CreateCluster(request.body.dbForm, request.body.backupInfo, {
+ const rawDbForm = schema2Raw(request.body);
+ const account = json2Account(rawDbForm);
+ const cluster = json2CreateCluster(rawDbForm, undefined, {
storageClassName: process.env.STORAGE_CLASSNAME
});
@@ -24,34 +40,32 @@ export async function createDatabase(
'v1alpha1',
k8s.namespace,
'clusters',
- request.body.dbForm.dbName
+ rawDbForm.dbName
)) as {
body: KbPgClusterType;
};
const dbUid = body.metadata.uid;
- const updateAccountYaml = json2Account(request.body.dbForm, dbUid);
+ const updateAccountYaml = json2Account(rawDbForm, dbUid);
await k8s.applyYamlList([updateAccountYaml], 'replace');
try {
- if (
- BackupSupportedDBTypeList.includes(request.body.dbForm.dbType) &&
- request.body.dbForm?.autoBackup
- ) {
+ if (BackupSupportedDBTypeList.includes(rawDbForm.dbType) && rawDbForm?.autoBackup) {
const autoBackup = convertBackupFormToSpec({
- autoBackup: request.body.dbForm?.autoBackup,
- dbType: request.body.dbForm.dbType
+ autoBackup: rawDbForm?.autoBackup,
+ dbType: rawDbForm.dbType
});
await updateBackupPolicyApi({
- dbName: request.body.dbForm.dbName,
- dbType: request.body.dbForm.dbType,
+ dbName: rawDbForm.dbName,
+ dbType: rawDbForm.dbType,
autoBackup,
k8sCustomObjects: k8s.k8sCustomObjects,
namespace: k8s.namespace
});
}
+ return raw2schema(adaptDBDetail(body));
} catch (err: any) {
// local env will fail to update backup policy
if (process.env.NODE_ENV === 'production') {
diff --git a/frontend/providers/dbprovider/src/services/backend/apis/delete-database.ts b/frontend/providers/dbprovider/src/services/backend/apis/delete-database.ts
new file mode 100644
index 000000000..c10292b34
--- /dev/null
+++ b/frontend/providers/dbprovider/src/services/backend/apis/delete-database.ts
@@ -0,0 +1,100 @@
+import { getDatabaseSchemas, updateDatabaseSchemas } from '@/types/apis';
+import { getK8s } from '../kubernetes';
+import { z } from 'zod';
+import { delMigrateByName } from '@/pages/api/migrate/delete';
+import { GetJobByName, DeleteJobByName } from '@/pages/api/migrate/delJobByName';
+import { CloudMigraionLabel } from '@/constants/db';
+import { getMigrateList } from '@/pages/api/migrate/list';
+export async function deleteDatabase(
+ k8s: Awaited>,
+ request: {
+ params: z.infer;
+ }
+) {
+ const name = request.params.databaseName;
+ // get job and delete
+ const { k8sBatch, namespace, k8sCustomObjects, k8sCore, k8sAuth } = k8s;
+ const jobsToDelete = (
+ await k8sBatch.listNamespacedJob(
+ namespace,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ `${CloudMigraionLabel}=${name}`
+ )
+ ).body.items;
+
+ for (const job of jobsToDelete) {
+ if (job?.metadata?.name) {
+ await k8sBatch
+ .deleteNamespacedJob(
+ job.metadata.name,
+ namespace,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ 'Background'
+ )
+ .catch((error) => {
+ console.error(`Error deleting job`, error);
+ });
+ }
+ }
+
+ // get migrates and delete
+ /* Retrieve migrations */
+ const { body } = (await k8sCustomObjects.listNamespacedCustomObject(
+ 'datamigration.apecloud.io',
+ 'v1alpha1',
+ namespace,
+ 'migrationtasks',
+ undefined, //pretty
+ undefined, //allowWatchBookmarks
+ undefined, //_continue
+ undefined, //fieldSelector
+ `${CloudMigraionLabel}=${name}` //labelSelector
+ )) as { body: { items: any[] } };
+ const migrates = body?.items || [];
+
+ /* Delete each migrationTask custom object */
+ for (const migrate of migrates) {
+ if (migrate?.metadata?.name) {
+ await k8sCustomObjects
+ .deleteNamespacedCustomObject(
+ 'datamigration.apecloud.io',
+ 'v1alpha1',
+ namespace,
+ 'migrationtasks',
+ migrate.metadata.name
+ )
+ .catch((error) => {
+ console.error('Failed to delete migrationTask', error);
+ });
+ }
+ }
+
+ // del service
+ await k8sCore.deleteNamespacedService(`${name}-export`, namespace).catch((err) => {
+ if (err?.body?.code !== 404) {
+ throw new Error(err?.message || 'Delete DB Service Export Error');
+ }
+ });
+
+ // del role
+ await Promise.all([
+ k8sAuth.deleteNamespacedRole(name, namespace),
+ k8sAuth.deleteNamespacedRoleBinding(name, namespace),
+ k8sCore.deleteNamespacedServiceAccount(name, namespace)
+ ]).catch((err) => console.log(err, 'delete role err'));
+
+ // delete cluster
+ const result = await k8sCustomObjects.deleteNamespacedCustomObject(
+ 'apps.kubeblocks.io',
+ 'v1alpha1',
+ namespace,
+ 'clusters',
+ name
+ );
+}
diff --git a/frontend/providers/dbprovider/src/services/backend/apis/get-database.ts b/frontend/providers/dbprovider/src/services/backend/apis/get-database.ts
new file mode 100644
index 000000000..f2c7275a2
--- /dev/null
+++ b/frontend/providers/dbprovider/src/services/backend/apis/get-database.ts
@@ -0,0 +1,56 @@
+import { updateDatabaseSchemas } from '@/types/apis';
+import { getK8s } from '../kubernetes';
+import { z } from 'zod';
+import { KbPgClusterType } from '@/types/cluster';
+import { adaptDBDetail } from '@/utils/adapt';
+import { dbDetailSchema } from '@/types/schemas/db';
+import { DBDetailType } from '@/types/db';
+export const raw2schema = (raw: DBDetailType): z.Infer => {
+ const dbEditSchemaFromRaw: z.Infer = {
+ terminationPolicy: raw.terminationPolicy,
+ name: raw.dbName,
+ type: raw.dbType,
+ version: raw.dbVersion,
+ resource: {
+ cpu: raw.cpu.toString(),
+ memory: raw.memory.toString(),
+ storage: raw.storage.toString(),
+ replicas: raw.replicas
+ },
+ id: raw.id,
+ status: raw.status.value, // 假设 status 是一个对象,其中的 value 是状态字符串
+ createTime: raw.createTime,
+ totalResource: {
+ cpu: raw.totalCpu.toString(),
+ memory: raw.totalMemory.toString(),
+ storage: raw.totalStorage.toString()
+ },
+ isDiskSpaceOverflow: raw.isDiskSpaceOverflow,
+ source: {
+ hasSource: raw.source.hasSource,
+ sourceName: raw.source.sourceName,
+ sourceType: raw.source.sourceType
+ },
+ autoBackup: raw.autoBackup
+ };
+
+ return dbEditSchemaFromRaw;
+};
+export async function getDatabase(
+ k8s: Awaited>,
+ request: {
+ params: z.infer;
+ }
+) {
+ const { k8sBatch, namespace, k8sCustomObjects, k8sCore, k8sAuth } = k8s;
+ const { body } = (await k8sCustomObjects.getNamespacedCustomObject(
+ 'apps.kubeblocks.io',
+ 'v1alpha1',
+ namespace,
+ 'clusters',
+ request.params.databaseName
+ )) as {
+ body: KbPgClusterType;
+ };
+ return raw2schema(adaptDBDetail(body));
+}
diff --git a/frontend/providers/dbprovider/src/services/backend/apis/list-database.ts b/frontend/providers/dbprovider/src/services/backend/apis/list-database.ts
new file mode 100644
index 000000000..94e10cc36
--- /dev/null
+++ b/frontend/providers/dbprovider/src/services/backend/apis/list-database.ts
@@ -0,0 +1,59 @@
+import { updateDatabaseSchemas } from '@/types/apis';
+import { getK8s } from '../kubernetes';
+import { z } from 'zod';
+import { KbPgClusterType } from '@/types/cluster';
+import { adaptDBDetail, adaptDBListItem } from '@/utils/adapt';
+import { dbDetailSchema, dblistItemSchema } from '@/types/schemas/db';
+import { DBDetailType, DBListItemType } from '@/types/db';
+const raw2schema = (raw: DBDetailType): z.Infer => {
+ const autoBackup = raw.autoBackup;
+ const dbEditSchemaFromRaw: z.Infer = {
+ terminationPolicy: raw.terminationPolicy,
+ name: raw.dbName,
+ type: raw.dbType,
+ version: raw.dbVersion,
+ resource: {
+ cpu: raw.cpu.toString(),
+ memory: raw.memory.toString(),
+ storage: raw.storage.toString(),
+ replicas: raw.replicas
+ },
+ id: raw.id,
+ status: raw.status.value, // 假设 status 是一个对象,其中的 value 是状态字符串
+ createTime: raw.createTime,
+ totalResource: {
+ cpu: raw.totalCpu.toString(),
+ memory: raw.totalMemory.toString(),
+ storage: raw.totalStorage.toString()
+ },
+ isDiskSpaceOverflow: raw.isDiskSpaceOverflow,
+ source: {
+ hasSource: raw.source.hasSource,
+ sourceName: raw.source.sourceName,
+ sourceType: raw.source.sourceType
+ },
+ autoBackup
+ };
+
+ return dbEditSchemaFromRaw;
+};
+export async function getDatabaseList(k8s: Awaited>) {
+ const { k8sBatch, namespace, k8sCustomObjects, k8sCore, k8sAuth } = k8s;
+ const response = (await k8sCustomObjects.listNamespacedCustomObject(
+ 'apps.kubeblocks.io',
+ 'v1alpha1',
+ namespace,
+ 'clusters',
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ `clusterdefinition.kubeblocks.io/name`
+ )) as {
+ body: {
+ items: KbPgClusterType[];
+ };
+ };
+ const data = (response?.body?.items || []).map(adaptDBDetail).map(raw2schema);
+ return data;
+}
diff --git a/frontend/providers/dbprovider/src/services/backend/apis/pause-database.ts b/frontend/providers/dbprovider/src/services/backend/apis/pause-database.ts
index 9a7520279..279a1ccf3 100644
--- a/frontend/providers/dbprovider/src/services/backend/apis/pause-database.ts
+++ b/frontend/providers/dbprovider/src/services/backend/apis/pause-database.ts
@@ -5,6 +5,8 @@ import { getCluster } from '@/pages/api/getDBByName';
import { json2BasicOps } from '@/utils/json2Yaml';
import { PatchUtils } from '@kubernetes/client-node';
import { NextApiRequest } from 'next';
+import { raw2schema } from './get-database';
+import { adaptDBDetail } from '@/utils/adapt';
export async function pauseDatabase(
k8s: Awaited>,
@@ -62,5 +64,5 @@ export async function pauseDatabase(
});
await k8s.applyYamlList([yaml], 'update');
- return { data: 'pause success' };
+ return { data: raw2schema(adaptDBDetail(body)) };
}
diff --git a/frontend/providers/dbprovider/src/services/backend/apis/start-database.ts b/frontend/providers/dbprovider/src/services/backend/apis/start-database.ts
index 73dc28b60..0db5d4faf 100644
--- a/frontend/providers/dbprovider/src/services/backend/apis/start-database.ts
+++ b/frontend/providers/dbprovider/src/services/backend/apis/start-database.ts
@@ -5,6 +5,8 @@ import { getCluster } from '@/pages/api/getDBByName';
import { json2BasicOps } from '@/utils/json2Yaml';
import { PatchUtils } from '@kubernetes/client-node';
import { NextApiRequest } from 'next';
+import { adaptDBDetail } from '@/utils/adapt';
+import { raw2schema } from './get-database';
export async function startDatabase(
k8s: Awaited>,
@@ -47,5 +49,5 @@ export async function startDatabase(
});
await k8s.applyYamlList([yaml], 'update');
- return { data: 'start success' };
+ return { data: raw2schema(adaptDBDetail(body)) };
}
diff --git a/frontend/providers/dbprovider/src/services/backend/apis/update-database.ts b/frontend/providers/dbprovider/src/services/backend/apis/update-database.ts
index c614e2102..b7e87c270 100644
--- a/frontend/providers/dbprovider/src/services/backend/apis/update-database.ts
+++ b/frontend/providers/dbprovider/src/services/backend/apis/update-database.ts
@@ -7,6 +7,7 @@ import { json2ResourceOps } from '@/utils/json2Yaml';
import { BackupSupportedDBTypeList } from '@/constants/db';
import { updateBackupPolicyApi } from '@/pages/api/backup/updatePolicy';
import { updateTerminationPolicyApi } from '@/pages/api/createDB';
+import { raw2schema } from './get-database';
export async function updateDatabase(
k8s: Awaited>,
@@ -79,8 +80,16 @@ export async function updateDatabase(
});
}
}
-
+ const { body: body2 } = (await k8s.k8sCustomObjects.getNamespacedCustomObject(
+ 'apps.kubeblocks.io',
+ 'v1alpha1',
+ k8s.namespace,
+ 'clusters',
+ request.params.databaseName
+ )) as {
+ body: KbPgClusterType;
+ };
return {
- opsRequests
+ data: raw2schema(adaptDBDetail(body2))
};
}
diff --git a/frontend/providers/dbprovider/src/types/apis/create-database.ts b/frontend/providers/dbprovider/src/types/apis/create-database.ts
deleted file mode 100644
index bc5b76a23..000000000
--- a/frontend/providers/dbprovider/src/types/apis/create-database.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import * as z from 'zod';
-import { backupItemSchema, dbEditSchema } from '../schemas/db';
-
-export const body = z.object({
- dbForm: dbEditSchema,
- backupInfo: z.optional(backupItemSchema)
-});
-
-export const response = z.object({
- code: z.number(),
- message: z.string()
-});
diff --git a/frontend/providers/dbprovider/src/types/apis/database/create-database.ts b/frontend/providers/dbprovider/src/types/apis/database/create-database.ts
new file mode 100644
index 000000000..d7ac0b766
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/apis/database/create-database.ts
@@ -0,0 +1,10 @@
+import * as z from 'zod';
+import { dbDetailSchema, dbEditSchema } from '../../schemas/db';
+
+export const body = dbEditSchema;
+
+export const response = z.object({
+ code: z.number(),
+ message: z.string(),
+ data: dbDetailSchema
+});
diff --git a/frontend/providers/dbprovider/src/types/apis/pause-database.ts b/frontend/providers/dbprovider/src/types/apis/database/delete-database.ts
similarity index 100%
rename from frontend/providers/dbprovider/src/types/apis/pause-database.ts
rename to frontend/providers/dbprovider/src/types/apis/database/delete-database.ts
diff --git a/frontend/providers/dbprovider/src/types/apis/database/get-database.ts b/frontend/providers/dbprovider/src/types/apis/database/get-database.ts
new file mode 100644
index 000000000..9dd51da07
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/apis/database/get-database.ts
@@ -0,0 +1,12 @@
+import * as z from 'zod';
+import { dbDetailSchema, dbEditSchema } from '../../schemas/db';
+
+export const pathParams = z.object({
+ databaseName: z.string()
+});
+
+export const response = z.object({
+ code: z.number(),
+ message: z.string(),
+ data: dbDetailSchema
+});
diff --git a/frontend/providers/dbprovider/src/types/apis/database/list-database.ts b/frontend/providers/dbprovider/src/types/apis/database/list-database.ts
new file mode 100644
index 000000000..f34ecf43f
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/apis/database/list-database.ts
@@ -0,0 +1,10 @@
+import * as z from 'zod';
+import { dbDetailSchema, dbEditSchema } from '../../schemas/db';
+
+export const pathParams = z.object({});
+
+export const response = z.object({
+ code: z.number(),
+ message: z.string(),
+ data: z.array(dbDetailSchema)
+});
diff --git a/frontend/providers/dbprovider/src/types/apis/start-database.ts b/frontend/providers/dbprovider/src/types/apis/database/pause-database.ts
similarity index 100%
rename from frontend/providers/dbprovider/src/types/apis/start-database.ts
rename to frontend/providers/dbprovider/src/types/apis/database/pause-database.ts
diff --git a/frontend/providers/dbprovider/src/types/apis/database/start-database.ts b/frontend/providers/dbprovider/src/types/apis/database/start-database.ts
new file mode 100644
index 000000000..72a3637ca
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/apis/database/start-database.ts
@@ -0,0 +1,10 @@
+import * as z from 'zod';
+
+export const pathParams = z.object({
+ databaseName: z.string()
+});
+
+export const response = z.object({
+ code: z.number(),
+ message: z.string()
+});
diff --git a/frontend/providers/dbprovider/src/types/apis/update-database.ts b/frontend/providers/dbprovider/src/types/apis/database/update-database.ts
similarity index 63%
rename from frontend/providers/dbprovider/src/types/apis/update-database.ts
rename to frontend/providers/dbprovider/src/types/apis/database/update-database.ts
index 84f4a607f..eee8d1679 100644
--- a/frontend/providers/dbprovider/src/types/apis/update-database.ts
+++ b/frontend/providers/dbprovider/src/types/apis/database/update-database.ts
@@ -1,5 +1,5 @@
import * as z from 'zod';
-import { dbEditSchema } from '../schemas/db';
+import { dbEditSchema } from '../../schemas/db';
export const pathParams = z.object({
databaseName: z.string()
@@ -8,11 +8,7 @@ export const pathParams = z.object({
export const body = z.object({
dbForm: dbEditSchema
.pick({
- cpu: true,
- memory: true,
- replicas: true,
- storage: true,
- terminationPolicy: true
+ resource: true
})
.partial()
});
diff --git a/frontend/providers/dbprovider/src/types/apis/database/version/list.ts b/frontend/providers/dbprovider/src/types/apis/database/version/list.ts
new file mode 100644
index 000000000..a398ea71c
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/apis/database/version/list.ts
@@ -0,0 +1,8 @@
+import { versionListSchema } from '@/types/schemas/db';
+import * as z from 'zod';
+
+export const response = z.object({
+ code: z.number(),
+ message: z.string(),
+ data: versionListSchema
+});
diff --git a/frontend/providers/dbprovider/src/types/apis/index.ts b/frontend/providers/dbprovider/src/types/apis/index.ts
index e0bb88c52..10f656891 100644
--- a/frontend/providers/dbprovider/src/types/apis/index.ts
+++ b/frontend/providers/dbprovider/src/types/apis/index.ts
@@ -1,16 +1,30 @@
import { createDocument } from 'zod-openapi';
-import * as createDatabaseSchemas from './create-database';
-export * as createDatabaseSchemas from './create-database';
+import * as createDatabaseSchemas from './database/create-database';
+export * as createDatabaseSchemas from './database/create-database';
-import * as updateDatabaseSchemas from './update-database';
-export * as updateDatabaseSchemas from './update-database';
+import * as updateDatabaseSchemas from './database/update-database';
+export * as updateDatabaseSchemas from './database/update-database';
-import * as startDatabaseSchemas from './start-database';
-export * as startDatabaseSchemas from './start-database';
+import * as startDatabaseSchemas from './database/start-database';
+export * as startDatabaseSchemas from './database/start-database';
-import * as pauseDatabaseSchemas from './pause-database';
-export * as pauseDatabaseSchemas from './pause-database';
+import * as pauseDatabaseSchemas from './database/pause-database';
+export * as pauseDatabaseSchemas from './database/pause-database';
+
+import * as getDatabaseSchemas from './database/get-database';
+export * as getDatabaseSchemas from './database/get-database';
+
+import * as deleteDatabaseSchemas from './database/delete-database';
+export * as deleteDatabaseSchemas from './database/delete-database';
+
+import * as logsDataSchemas from './logs/data';
+export * as logsDataSchemas from './logs/data';
+
+import * as logsFileSchemas from './logs/file';
+export * as logsFileSchemas from './logs/file';
+
+import * as databaseVersionListSchemas from './database/version/list';
export const document = createDocument({
openapi: '3.1.0',
@@ -37,8 +51,12 @@ export const document = createDocument({
'/database': {
post: {
summary: 'Create Database',
- description: 'Create a database.',
- security: [{ KubeconfigAuth: [] }],
+ description: 'Create a new database.',
+ security: [
+ {
+ KubeconfigAuth: []
+ }
+ ],
requestBody: {
content: {
'application/json': {
@@ -48,12 +66,15 @@ export const document = createDocument({
},
responses: {
'200': {
- description: 'OK',
+ description: 'Created',
content: {
'application/json': {
schema: createDatabaseSchemas.response
}
}
+ },
+ '400': {
+ description: 'Bad Request'
}
}
}
@@ -81,6 +102,55 @@ export const document = createDocument({
schema: updateDatabaseSchemas.response
}
}
+ },
+ '400': {
+ description: 'Bad Request'
+ },
+ '404': {
+ description: 'Database not found'
+ }
+ }
+ },
+ get: {
+ summary: 'Get Database',
+ description: 'Get a database by name.',
+ security: [
+ {
+ KubeconfigAuth: []
+ }
+ ],
+ requestParams: {
+ path: getDatabaseSchemas.pathParams
+ },
+ responses: {
+ '200': {
+ description: 'OK',
+ content: {
+ 'application/json': {
+ schema: getDatabaseSchemas.response
+ }
+ }
+ },
+ '404': {
+ description: 'Database not found'
+ }
+ }
+ },
+ delete: {
+ summary: 'Delete a Database',
+ description: 'Delete a database by name.',
+ security: [{ KubeconfigAuth: [] }],
+ responses: {
+ '200': {
+ description: 'OK',
+ content: {
+ 'application/json': {
+ schema: deleteDatabaseSchemas.response
+ }
+ }
+ },
+ '404': {
+ description: 'Database not found'
}
}
}
@@ -124,6 +194,63 @@ export const document = createDocument({
}
}
}
+ },
+ '/database/version/list': {
+ get: {
+ summary: 'Get Database Versions',
+ description: 'Get database versions.',
+ security: [{ KubeconfigAuth: [] }],
+ responses: {
+ '200': {
+ description: 'OK',
+ content: {
+ 'application/json': {
+ schema: databaseVersionListSchemas.response
+ }
+ }
+ }
+ }
+ }
+ },
+ '/logs/data': {
+ get: {
+ summary: 'Get Logs Files',
+ description: 'Get logs files.',
+ security: [{ KubeconfigAuth: [] }],
+ requestParams: {
+ query: logsDataSchemas.query
+ },
+ responses: {
+ '200': {
+ description: 'OK',
+ content: {
+ 'application/json': {
+ schema: logsDataSchemas.response
+ }
+ }
+ }
+ }
+ }
+ },
+ '/logs/files': {
+ get: {
+ summary: 'Get Logs File',
+ description: 'Get logs file.',
+ security: [{ KubeconfigAuth: [] }],
+ requestParams: {
+ query: logsFileSchemas.query
+ },
+ responses: {
+ '200': {
+ description: 'OK',
+ content: {
+ 'application/json': {
+ schema: logsFileSchemas.response
+ }
+ }
+ }
+ }
+ }
}
}
});
diff --git a/frontend/providers/dbprovider/src/types/apis/logs/data.ts b/frontend/providers/dbprovider/src/types/apis/logs/data.ts
new file mode 100644
index 000000000..ebe2c1acc
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/apis/logs/data.ts
@@ -0,0 +1,21 @@
+import { z } from 'zod';
+import { LogTypeEnum } from '@/constants/log';
+import { DBTypeEnum } from '@/constants/db';
+import { logResultSchema } from '@/types/schemas/logs';
+
+export const query = z.object({
+ podName: z.string().nonempty('podName is required'),
+ dbType: z
+ .enum(DBTypeEnum)
+ .extract(['mysql', DBTypeEnum.mongodb, DBTypeEnum.redis, DBTypeEnum.postgresql]),
+ logType: z.enum(LogTypeEnum),
+ logPath: z.string().nonempty('logPath is required'),
+ page: z.number().int().min(1).optional(),
+ pageSize: z.number().int().min(1).optional()
+});
+
+export const response = z.object({
+ code: z.number(),
+ message: z.string(),
+ data: logResultSchema
+});
diff --git a/frontend/providers/dbprovider/src/types/apis/logs/file.ts b/frontend/providers/dbprovider/src/types/apis/logs/file.ts
new file mode 100644
index 000000000..a51a234c0
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/apis/logs/file.ts
@@ -0,0 +1,18 @@
+import { z } from 'zod';
+import { LogTypeEnum } from '@/constants/log';
+import { DBTypeEnum } from '@/constants/db';
+import { logFileItemSchema, logResultSchema } from '@/types/schemas/logs';
+
+export const query = z.object({
+ podName: z.string().nonempty('podName is required'),
+ dbType: z
+ .enum(DBTypeEnum)
+ .extract(['mysql', DBTypeEnum.mongodb, DBTypeEnum.redis, DBTypeEnum.postgresql]),
+ logType: z.enum(LogTypeEnum)
+});
+
+export const response = z.object({
+ code: z.number(),
+ message: z.string(),
+ data: z.array(logFileItemSchema)
+});
diff --git a/frontend/providers/dbprovider/src/types/schemas/backup.ts b/frontend/providers/dbprovider/src/types/schemas/backup.ts
index 47c544ef2..c8c56bcfd 100644
--- a/frontend/providers/dbprovider/src/types/schemas/backup.ts
+++ b/frontend/providers/dbprovider/src/types/schemas/backup.ts
@@ -1,3 +1,4 @@
+import { BackupTypeEnum, BackupStatusEnum } from '@/constants/backup';
import * as z from 'zod';
export const autoBackupTypeSchema = z.union([
@@ -15,3 +16,39 @@ export const autoBackupFormSchema = z.object({
saveTime: z.number(),
saveType: z.string()
});
+
+export const backupTypeEnumSchema = z.enum([
+ BackupTypeEnum.manual,
+ BackupTypeEnum.auto,
+ BackupTypeEnum.UnKnow
+]);
+
+export const backupStatusEnumSchema = z.enum([
+ BackupStatusEnum.Completed,
+ BackupStatusEnum.InProgress,
+ BackupStatusEnum.Failed,
+ BackupStatusEnum.UnKnow,
+ BackupStatusEnum.Running,
+ BackupStatusEnum.Deleting
+]);
+
+// export const backupStatusMapSchema = z.object({
+// label: z.string(),
+// value: backupStatusEnumSchema
+// });
+export const backupBaseSchema = z.object({
+ name: z.string(),
+ namespace: z.string(),
+ connectionPassword: z.string()
+});
+
+export const backupInfoSchema = z
+ .object({
+ id: z.string(),
+ // remark: z.string(),
+ status: backupStatusEnumSchema,
+ startTime: z.date(),
+ // failureReason: z.string().optional(),
+ type: backupTypeEnumSchema
+ })
+ .and(backupBaseSchema);
diff --git a/frontend/providers/dbprovider/src/types/schemas/db.ts b/frontend/providers/dbprovider/src/types/schemas/db.ts
index bae803989..815b33048 100644
--- a/frontend/providers/dbprovider/src/types/schemas/db.ts
+++ b/frontend/providers/dbprovider/src/types/schemas/db.ts
@@ -1,71 +1,89 @@
import { BackupStatusEnum, BackupTypeEnum } from '@/constants/backup';
import { DBTypeEnum } from '@/constants/db';
import * as z from 'zod';
-import { autoBackupFormSchema } from './backup';
+import { autoBackupFormSchema, backupInfoSchema } from './backup';
export const dbTypeSchema = z.enum([
- DBTypeEnum.postgresql,
- DBTypeEnum.mongodb,
- DBTypeEnum.mysql,
- DBTypeEnum.redis,
- DBTypeEnum.kafka,
- DBTypeEnum.qdrant,
- DBTypeEnum.nebula,
- DBTypeEnum.weaviate,
- DBTypeEnum.milvus,
- DBTypeEnum.pulsar,
- DBTypeEnum.clickhouse
+ 'postgresql',
+ 'mongodb',
+ 'apecloud-mysql',
+ 'redis',
+ 'kafka',
+ 'qdrant',
+ 'nebula',
+ 'weaviate',
+ 'milvus',
+ 'pulsar',
+ 'clickhouse'
]);
-
-export const kubeBlockClusterTerminationPolicySchema = z.union([
- z.literal('Delete'),
- z.literal('WipeOut')
-]);
-
-export const backupTypeEnumSchema = z.enum([
- BackupTypeEnum.manual,
- BackupTypeEnum.auto,
- BackupTypeEnum.UnKnow
-]);
-
-export const backupStatusEnumSchema = z.enum([
- BackupStatusEnum.Completed,
- BackupStatusEnum.InProgress,
- BackupStatusEnum.Failed,
- BackupStatusEnum.UnKnow,
- BackupStatusEnum.Running,
- BackupStatusEnum.Deleting
-]);
-
-export const backupStatusMapSchema = z.object({
- label: z.string(),
- value: backupStatusEnumSchema,
- color: z.string()
+export const kubeBlockClusterTerminationPolicySchema = z.enum(['Delete', 'WipeOut']);
+export const baseResourceSchema = z.object({
+ cpu: z.string(),
+ memory: z.string(),
+ storage: z.string()
});
-
-export const backupItemSchema = z.object({
- id: z.string(),
- name: z.string(),
- remark: z.string(),
- status: backupStatusMapSchema,
- startTime: z.date(),
- failureReason: z.string().optional(),
- type: backupTypeEnumSchema,
- namespace: z.string(),
- connectionPassword: z.string(),
- dbName: z.string(),
- dbType: z.string()
-});
-
+export const allResourceSchema = baseResourceSchema.and(
+ z.object({
+ replicas: z.number().min(1).max(3)
+ })
+);
export const dbEditSchema = z.object({
- dbType: dbTypeSchema,
- dbVersion: z.string(),
- dbName: z.string(),
- replicas: z.number(),
- cpu: z.number(),
- memory: z.number(),
- storage: z.number(),
- labels: z.record(z.string(), z.string()),
terminationPolicy: kubeBlockClusterTerminationPolicySchema,
- autoBackup: z.optional(autoBackupFormSchema)
+ name: z.string(),
+ type: dbTypeSchema,
+ version: z.string(),
+ resource: allResourceSchema,
+ autoBackup: autoBackupFormSchema.optional()
});
+// export const dbConditionItemSchema = z.object({
+// lastTransitionTime: z.string(),
+// message: z.string(),
+// observedGeneration: z.number(),
+// reason: z.string(),
+// status: z.enum(['True', 'False']),
+// type: z.string()
+// });
+export const dbSourceSchema = z.object({
+ hasSource: z.boolean(),
+ sourceName: z.string(),
+ sourceType: z.enum(['app_store', 'sealaf'])
+});
+export const dbStatusSchema = z.enum([
+ 'Creating',
+ 'Starting',
+ 'Stopping',
+ 'Stopped',
+ 'Running',
+ 'Updating',
+ 'SpecUpdating',
+ 'Rebooting',
+ 'Upgrade',
+ 'VerticalScaling',
+ 'VolumeExpanding',
+ 'Failed',
+ 'UnKnow',
+ 'Deleting'
+]);
+export const dbDetailSchema = dbEditSchema.and(
+ z.object({
+ id: z.string(),
+ status: dbStatusSchema,
+ createTime: z.string(),
+ totalResource: baseResourceSchema,
+ isDiskSpaceOverflow: z.boolean(),
+ source: dbSourceSchema
+ })
+);
+export const dblistItemSchema = dbEditSchema.and(
+ z.object({
+ id: z.string(),
+ status: dbStatusSchema,
+ createTime: z.string(),
+ totalResource: baseResourceSchema,
+ isDiskSpaceOverflow: z.boolean(),
+ source: dbSourceSchema
+ // autoBackup: autoBackupFormSchema.optional()
+ })
+);
+
+export const versionListSchema = z.record(dbTypeSchema, z.array(z.string()));
diff --git a/frontend/providers/dbprovider/src/types/schemas/logs.ts b/frontend/providers/dbprovider/src/types/schemas/logs.ts
new file mode 100644
index 000000000..f6a8efee0
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/schemas/logs.ts
@@ -0,0 +1,33 @@
+import { z } from 'zod';
+
+const baseLogEntrySchema = z.object({
+ timestamp: z.string(),
+ level: z.string(),
+ content: z.string()
+});
+
+export const logResultSchema = z.object({
+ logs: z.array(baseLogEntrySchema),
+ metadata: z.object({
+ total: z.number(),
+ page: z.number(),
+ pageSize: z.number(),
+ processingTime: z.string(),
+ hasMore: z.boolean()
+ })
+});
+
+export const logFileItemSchema = z.object({
+ name: z.string(),
+ path: z.string(),
+ dir: z.string(),
+ kind: z.string(),
+ attr: z.string(),
+ hardLinks: z.number(),
+ owner: z.string(),
+ group: z.string(),
+ size: z.number(),
+ updateTime: z.date(),
+ linkTo: z.string().optional(),
+ processed: z.boolean().optional()
+});
diff --git a/frontend/providers/dbprovider/src/types/schemas/monitor.ts b/frontend/providers/dbprovider/src/types/schemas/monitor.ts
new file mode 100644
index 000000000..c075be42b
--- /dev/null
+++ b/frontend/providers/dbprovider/src/types/schemas/monitor.ts
@@ -0,0 +1,11 @@
+import { z } from 'zod';
+
+export const MonitorChartDataResultSchema = z.object({
+ xData: z.array(z.number()),
+ yData: z.array(
+ z.object({
+ name: z.string().optional(),
+ data: z.array(z.number())
+ })
+ )
+});
diff --git a/frontend/providers/dbprovider/src/utils/adapt.ts b/frontend/providers/dbprovider/src/utils/adapt.ts
index ad81cf913..c8196cdf9 100644
--- a/frontend/providers/dbprovider/src/utils/adapt.ts
+++ b/frontend/providers/dbprovider/src/utils/adapt.ts
@@ -44,6 +44,8 @@ import { has } from 'lodash';
dayjs.extend(utc);
dayjs.extend(timezone);
import type { BackupItemType } from '../types/db';
+import z from 'zod';
+import { dbDetailSchema, dbEditSchema, dbTypeSchema } from '@/types/schemas/db';
export const getDBSource = (
db: KbPgClusterType
diff --git a/frontend/providers/dbprovider/src/utils/json2Yaml.ts b/frontend/providers/dbprovider/src/utils/json2Yaml.ts
index d311ae2e1..f958684db 100644
--- a/frontend/providers/dbprovider/src/utils/json2Yaml.ts
+++ b/frontend/providers/dbprovider/src/utils/json2Yaml.ts
@@ -27,6 +27,8 @@ import { V1StatefulSet } from '@kubernetes/client-node';
import { customAlphabet } from 'nanoid';
import { SwitchMsData } from '@/pages/api/pod/switchPodMs';
import { distributeResources } from './database';
+import z from 'zod';
+import { backupBaseSchema } from '@/types/schemas/backup';
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 5);
@@ -40,7 +42,7 @@ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 5);
*/
export const json2CreateCluster = (
rawData: Partial = {},
- backupInfo?: BackupItemType,
+ backupInfo?: z.Infer,
options?: {
storageClassName?: string;
}