Skip to content

Commit

Permalink
feat: optimize database pause and backup handling (#5242)
Browse files Browse the repository at this point in the history
* update

* fix launchpad

* feat: support disable auto backup when pause database

* fix connection

* fix launchpad

* refactor database modification logic

* update pod age time
  • Loading branch information
zjy365 authored Nov 27, 2024
1 parent d4fe959 commit 98fdc1a
Show file tree
Hide file tree
Showing 16 changed files with 380 additions and 78 deletions.
4 changes: 2 additions & 2 deletions frontend/providers/applaunchpad/src/api/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
adaptMetrics,
adaptEvents
} from '@/utils/adapt';
import type { AppPatchPropsType } from '@/types/app';
import type { AppPatchPropsType, PodDetailType } from '@/types/app';
import { MonitorDataResult, MonitorQueryKey } from '@/types/monitor';

export const postDeployApp = (yamlList: string[]) => POST('/api/applyApp', { yamlList });
Expand All @@ -27,7 +27,7 @@ export const getAppByName = (name: string) =>
GET(`/api/getAppByAppName?appName=${name}`).then(adaptAppDetail);

export const getAppPodsByAppName = (name: string) =>
GET<V1Pod[]>('/api/getAppPodsByAppName', { name }).then((item) => item.map(adaptPod));
GET<PodDetailType[]>('/api/getAppPodsByAppName', { name });

export const getPodsMetrics = (podsName: string[]) =>
POST<SinglePodMetrics[]>('/api/getPodsMetrics', { podsName }).then((item) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ApiResp } from '@/services/kubernet';
import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { adaptPod } from '@/utils/adapt';

// get App Metrics By DeployName. compute average value
export default async function handler(req: NextApiRequest, res: NextApiResponse<ApiResp>) {
Expand Down Expand Up @@ -30,7 +31,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
);

jsonRes(res, {
data: pods
data: pods.map((item) => adaptPod(item))
});
} catch (err: any) {
// console.log(err, 'get metrics error')
Expand Down
5 changes: 2 additions & 3 deletions frontend/providers/applaunchpad/src/pages/app/edit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,7 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) =>
t,
applySuccess,
userSourcePrice?.gpu,
refetchPrice,
isGuided
refetchPrice
]
);

Expand Down Expand Up @@ -322,7 +321,7 @@ const EditApp = ({ appName, tabType }: { appName?: string; tabType: string }) =>
formHook.setValue('networks', completeNetworks);
}
} catch (error) {}
}, []);
}, [router.query]);

return (
<>
Expand Down
5 changes: 3 additions & 2 deletions frontend/providers/dbprovider/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"backup_database": "Backup Database",
"backup_deleting": "Purging Backup",
"backup_failed": "Backup Failed",
"backup_list": "Backup History",
"backup_list": "Data Backups",
"backup_name": "Backup Name",
"backup_name_cannot_empty": "Must provide backup name",
"backup_processing": "Saving Backup",
Expand Down Expand Up @@ -316,5 +316,6 @@
"within_1_hour": "Within 1 hour",
"within_5_minutes": "Within 5 minutes",
"yaml_file": "YAML",
"you_have_successfully_deployed_database": "You have successfully deployed and created a database!"
"you_have_successfully_deployed_database": "You have successfully deployed and created a database!",
"database_name_max_length": "Database name length cannot exceed {{length}} characters"
}
7 changes: 4 additions & 3 deletions frontend/providers/dbprovider/public/locales/zh/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"backup_database": "备份数据库",
"backup_deleting": "删除中",
"backup_failed": "备份失败",
"backup_list": "备份历史",
"backup_list": "数据备份",
"backup_name": "备份名",
"backup_name_cannot_empty": "备份名称不能为空",
"backup_processing": "备份中",
Expand Down Expand Up @@ -316,5 +316,6 @@
"within_1_hour": "一小时内",
"within_5_minutes": "五分钟内",
"yaml_file": "YAML 文件",
"you_have_successfully_deployed_database": "您已成功部署创建一个数据库!"
}
"you_have_successfully_deployed_database": "您已成功部署创建一个数据库!",
"database_name_max_length": "数据库名长度不能超过 {{length}} 个字符"
}
2 changes: 1 addition & 1 deletion frontend/providers/dbprovider/src/api/backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { Props as UpdatePolicyProps } from '@/pages/api/backup/updatePolicy
* for the specific database in the cluster.
*
* To update the auto-backup policy, use the PATCH operation on the 'cluster spec backup' resource.
*
* @deprecated
* @param data - Object containing information about the database, including dbName and dbType.
* @returns {Promise<AutoBackupFormType>} - A promise resolving to the auto-backup configuration form.
*/
Expand Down
20 changes: 5 additions & 15 deletions frontend/providers/dbprovider/src/api/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const applyYamlList = (yamlList: string[], type: 'create' | 'replace' | '
POST('/api/applyYamlList', { yamlList, type });

export const getPodsByDBName = (name: string): Promise<PodDetailType[]> =>
GET('/api/pod/getPodsByDBName', { name }).then((res) => res.map(adaptPod));
GET('/api/pod/getPodsByDBName', { name });

export const getPodLogs = (data: {
dbName: string;
Expand All @@ -66,21 +66,11 @@ export const restartDB = (data: { dbName: string; dbType: DBType }) => {
return applyYamlList([yaml], 'update');
};

export const pauseDBByName = (data: { dbName: string; dbType: DBType }) => {
const yaml = json2StartOrStop({
...data,
type: 'Stop'
});
return applyYamlList([yaml], 'update');
};
export const pauseDBByName = (data: { dbName: string; dbType: DBType }) =>
POST('/api/pauseDBByName', data);

export const startDBByName = (data: { dbName: string; dbType: DBType }) => {
const yaml = json2StartOrStop({
...data,
type: 'Start'
});
return applyYamlList([yaml], 'update');
};
export const startDBByName = (data: { dbName: string; dbType: DBType }) =>
POST('/api/startDBByName', data);

export const getDBServiceByName = (name: string) =>
GET<V1Service>(`/api/getServiceByName?name=${name}`);
Expand Down
61 changes: 58 additions & 3 deletions frontend/providers/dbprovider/src/pages/api/createDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { jsonRes } from '@/services/backend/response';
import { ApiResp } from '@/services/kubernet';
import { KbPgClusterType } from '@/types/cluster';
import { BackupItemType, DBEditType } from '@/types/db';
import { json2Account, json2CreateCluster } from '@/utils/json2Yaml';
import { json2Account, json2ClusterOps, json2CreateCluster } from '@/utils/json2Yaml';
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse<ApiResp>) {
Expand All @@ -20,8 +20,63 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
});

if (isEdit) {
const cluster = json2CreateCluster(dbForm);
await applyYamlList([cluster], 'replace');
const { body } = (await k8sCustomObjects.getNamespacedCustomObject(
'apps.kubeblocks.io',
'v1alpha1',
namespace,
'clusters',
dbForm.dbName
)) as {
body: KbPgClusterType;
};

const currentConfig = {
cpu: parseInt(body.spec.componentSpecs[0].resources.limits.cpu.replace('m', '')),
memory: parseInt(body.spec.componentSpecs[0].resources.limits.memory.replace('Mi', '')),
replicas: body.spec.componentSpecs[0].replicas,
storage: parseInt(
body.spec.componentSpecs[0].volumeClaimTemplates[0].spec.resources.requests.storage.replace(
'Gi',
''
)
)
};

const opsRequests = [];

if (currentConfig.cpu !== dbForm.cpu || currentConfig.memory !== dbForm.memory) {
const verticalScalingYaml = json2ClusterOps(dbForm, 'VerticalScaling');
opsRequests.push(verticalScalingYaml);
}

if (currentConfig.replicas !== dbForm.replicas) {
const horizontalScalingYaml = json2ClusterOps(dbForm, 'HorizontalScaling');
opsRequests.push(horizontalScalingYaml);
}

if (dbForm.storage > currentConfig.storage) {
const volumeExpansionYaml = json2ClusterOps(dbForm, 'VolumeExpansion');
opsRequests.push(volumeExpansionYaml);
}

console.log('DB Edit Operation:', {
dbName: dbForm.dbName,
changes: {
cpu: currentConfig.cpu !== dbForm.cpu,
memory: currentConfig.memory !== dbForm.memory,
replicas: currentConfig.replicas !== dbForm.replicas,
storage: dbForm.storage > currentConfig.storage
},
opsCount: opsRequests.length
});

if (opsRequests.length > 0) {
await applyYamlList(opsRequests, 'create');
return jsonRes(res, {
data: `Successfully submitted ${opsRequests.length} change requests`
});
}

return jsonRes(res, {
data: 'success update db'
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
key: 'redis'
},
[DBTypeEnum.kafka]: {
key: 'kafka'
key: 'kafka-broker'
},
[DBTypeEnum.qdrant]: {
key: 'qdrant'
Expand Down
73 changes: 73 additions & 0 deletions frontend/providers/dbprovider/src/pages/api/pauseDBByName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { ApiResp } from '@/services/kubernet';
import { KbPgClusterType } from '@/types/cluster';
import { json2StartOrStop } from '@/utils/json2Yaml';
import { PatchUtils } from '@kubernetes/client-node';
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse<ApiResp>) {
try {
const { dbName } = req.body as {
dbName: string;
};

if (!dbName) {
return jsonRes(res, {
code: 400,
error: 'params error'
});
}

const { applyYamlList, k8sCustomObjects, namespace } = await getK8s({
kubeconfig: await authSession(req)
});

const { yaml, yamlObj } = json2StartOrStop({
dbName,
type: 'Stop'
});

const { body } = (await k8sCustomObjects.getNamespacedCustomObject(
'apps.kubeblocks.io',
'v1alpha1',
namespace,
'clusters',
dbName
)) as {
body: KbPgClusterType;
};

if (body.spec.backup?.enabled === true) {
const patch = [
{
op: 'replace',
path: '/spec/backup/enabled',
value: false
}
];
await k8sCustomObjects.patchNamespacedCustomObject(
'apps.kubeblocks.io',
'v1alpha1',
namespace,
'clusters',
dbName,
patch,
undefined,
undefined,
undefined,
{ headers: { 'Content-type': PatchUtils.PATCH_FORMAT_JSON_PATCH } }
);
}

await applyYamlList([yaml], 'update');

jsonRes(res, { data: 'pause success' });
} catch (err: any) {
jsonRes(res, {
code: 500,
error: err
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { KBBackupNameLabel } from '@/constants/db';
import { adaptPod } from '@/utils/adapt';

// get App Metrics By DeployName. compute average value
export default async function handler(req: NextApiRequest, res: NextApiResponse<ApiResp>) {
Expand Down Expand Up @@ -31,7 +32,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
);

jsonRes(res, {
data: pods
data: pods.map((pod) => adaptPod(pod))
});
} catch (err: any) {
// console.log(err, 'get metrics error')
Expand Down
75 changes: 75 additions & 0 deletions frontend/providers/dbprovider/src/pages/api/startDBByName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { ApiResp } from '@/services/kubernet';
import { KbPgClusterType } from '@/types/cluster';
import { json2StartOrStop } from '@/utils/json2Yaml';
import { PatchUtils } from '@kubernetes/client-node';
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req: NextApiRequest, res: NextApiResponse<ApiResp>) {
try {
const { dbName } = req.body as {
dbName: string;
};

if (!dbName) {
return jsonRes(res, {
code: 400,
error: 'params error'
});
}

const { applyYamlList, k8sCustomObjects, namespace } = await getK8s({
kubeconfig: await authSession(req)
});

const { yaml, yamlObj } = json2StartOrStop({
dbName,
type: 'Start'
});

const { body } = (await k8sCustomObjects.getNamespacedCustomObject(
'apps.kubeblocks.io',
'v1alpha1',
namespace,
'clusters',
dbName
)) as {
body: KbPgClusterType;
};

console.log(yamlObj, body.spec.backup, body.spec.backup?.enabled === false, 'yaml');

if (body.spec.backup?.enabled === false) {
const patch = [
{
op: 'replace',
path: '/spec/backup/enabled',
value: true
}
];

await k8sCustomObjects.patchNamespacedCustomObject(
'apps.kubeblocks.io',
'v1alpha1',
namespace,
'clusters',
dbName,
patch,
undefined,
undefined,
undefined,
{ headers: { 'Content-type': PatchUtils.PATCH_FORMAT_JSON_PATCH } }
);
}
await applyYamlList([yaml], 'update');

jsonRes(res, { data: 'start success' });
} catch (err: any) {
jsonRes(res, {
code: 500,
error: err
});
}
}
Loading

0 comments on commit 98fdc1a

Please sign in to comment.