mirror of
https://github.com/labring/sealos.git
synced 2026-10-29 17:25:58 +08:00
feat: dbprovider api (#5820)
This commit is contained in:
@@ -7,6 +7,5 @@ export default function ApiDocs() {
|
||||
const config = {
|
||||
content: document
|
||||
};
|
||||
|
||||
return <ApiReferenceReact configuration={config} />;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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<typeof versionListSchema> = {
|
||||
[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'
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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<ApiResp>) {
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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<ApiResp>) {
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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<ApiResp>) {
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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<typeof createDatabaseSchemas.body>): 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<ReturnType<typeof getK8s>>,
|
||||
request: {
|
||||
body: z.infer<typeof createDatabaseSchemas.body>;
|
||||
}
|
||||
) {
|
||||
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') {
|
||||
|
||||
@@ -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<ReturnType<typeof getK8s>>,
|
||||
request: {
|
||||
params: z.infer<typeof getDatabaseSchemas.pathParams>;
|
||||
}
|
||||
) {
|
||||
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
|
||||
);
|
||||
}
|
||||
@@ -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<typeof dbDetailSchema> => {
|
||||
const dbEditSchemaFromRaw: z.Infer<typeof dbDetailSchema> = {
|
||||
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<ReturnType<typeof getK8s>>,
|
||||
request: {
|
||||
params: z.infer<typeof updateDatabaseSchemas.pathParams>;
|
||||
}
|
||||
) {
|
||||
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));
|
||||
}
|
||||
@@ -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<typeof dblistItemSchema> => {
|
||||
const autoBackup = raw.autoBackup;
|
||||
const dbEditSchemaFromRaw: z.Infer<typeof dblistItemSchema> = {
|
||||
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<ReturnType<typeof getK8s>>) {
|
||||
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;
|
||||
}
|
||||
@@ -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<ReturnType<typeof getK8s>>,
|
||||
@@ -62,5 +64,5 @@ export async function pauseDatabase(
|
||||
});
|
||||
await k8s.applyYamlList([yaml], 'update');
|
||||
|
||||
return { data: 'pause success' };
|
||||
return { data: raw2schema(adaptDBDetail(body)) };
|
||||
}
|
||||
|
||||
@@ -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<ReturnType<typeof getK8s>>,
|
||||
@@ -47,5 +49,5 @@ export async function startDatabase(
|
||||
});
|
||||
await k8s.applyYamlList([yaml], 'update');
|
||||
|
||||
return { data: 'start success' };
|
||||
return { data: raw2schema(adaptDBDetail(body)) };
|
||||
}
|
||||
|
||||
@@ -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<ReturnType<typeof getK8s>>,
|
||||
@@ -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))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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()
|
||||
});
|
||||
+2
-6
@@ -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()
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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
|
||||
});
|
||||
@@ -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)
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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()
|
||||
});
|
||||
@@ -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())
|
||||
})
|
||||
)
|
||||
});
|
||||
@@ -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
|
||||
|
||||
@@ -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<DBEditType> = {},
|
||||
backupInfo?: BackupItemType,
|
||||
backupInfo?: z.Infer<typeof backupBaseSchema>,
|
||||
options?: {
|
||||
storageClassName?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user