mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-04 00:10:25 +08:00
221 lines
7.9 KiB
Go
221 lines
7.9 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"mayfly-go/internal/db/api/form"
|
|
"mayfly-go/internal/db/api/vo"
|
|
"mayfly-go/internal/db/application"
|
|
"mayfly-go/internal/db/domain/entity"
|
|
"mayfly-go/pkg/biz"
|
|
"mayfly-go/pkg/req"
|
|
"mayfly-go/pkg/utils/timex"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type DbBackup struct {
|
|
backupApp *application.DbBackupApp `inject:"DbBackupApp"`
|
|
dbApp application.Db `inject:"DbApp"`
|
|
restoreApp *application.DbRestoreApp `inject:"DbRestoreApp"`
|
|
}
|
|
|
|
// todo: 鉴权,避免未经授权进行数据库备份和恢复
|
|
|
|
// GetPageList 获取数据库备份任务
|
|
// @router /api/dbs/:dbId/backups [GET]
|
|
func (d *DbBackup) GetPageList(rc *req.Ctx) {
|
|
dbId := uint64(rc.PathParamInt("dbId"))
|
|
biz.IsTrue(dbId > 0, "无效的 dbId: %v", dbId)
|
|
db, err := d.dbApp.GetById(new(entity.Db), dbId, "db_instance_id", "database")
|
|
biz.ErrIsNilAppendErr(err, "获取数据库信息失败: %v")
|
|
|
|
queryCond, page := req.BindQueryAndPage[*entity.DbBackupQuery](rc, new(entity.DbBackupQuery))
|
|
queryCond.DbInstanceId = db.InstanceId
|
|
queryCond.InDbNames = strings.Fields(db.Database)
|
|
res, err := d.backupApp.GetPageList(queryCond, page, new([]vo.DbBackup))
|
|
biz.ErrIsNilAppendErr(err, "获取数据库备份任务失败: %v")
|
|
rc.ResData = res
|
|
}
|
|
|
|
// Create 保存数据库备份任务
|
|
// @router /api/dbs/:dbId/backups [POST]
|
|
func (d *DbBackup) Create(rc *req.Ctx) {
|
|
backupForm := req.BindJsonAndValid(rc, &form.DbBackupForm{})
|
|
rc.ReqParam = backupForm
|
|
|
|
dbNames := strings.Fields(backupForm.DbNames)
|
|
biz.IsTrue(len(dbNames) > 0, "解析数据库备份任务失败:数据库名称未定义")
|
|
|
|
dbId := uint64(rc.PathParamInt("dbId"))
|
|
biz.IsTrue(dbId > 0, "无效的 dbId: %v", dbId)
|
|
db, err := d.dbApp.GetById(new(entity.Db), dbId, "instanceId")
|
|
biz.ErrIsNilAppendErr(err, "获取数据库信息失败: %v")
|
|
jobs := make([]*entity.DbBackup, 0, len(dbNames))
|
|
for _, dbName := range dbNames {
|
|
job := &entity.DbBackup{
|
|
DbInstanceId: db.InstanceId,
|
|
DbName: dbName,
|
|
Enabled: true,
|
|
Repeated: backupForm.Repeated,
|
|
StartTime: backupForm.StartTime,
|
|
Interval: backupForm.Interval,
|
|
Name: backupForm.Name,
|
|
}
|
|
jobs = append(jobs, job)
|
|
}
|
|
biz.ErrIsNilAppendErr(d.backupApp.Create(rc.MetaCtx, jobs), "添加数据库备份任务失败: %v")
|
|
}
|
|
|
|
// Update 保存数据库备份任务
|
|
// @router /api/dbs/:dbId/backups/:backupId [PUT]
|
|
func (d *DbBackup) Update(rc *req.Ctx) {
|
|
backupForm := &form.DbBackupForm{}
|
|
req.BindJsonAndValid(rc, backupForm)
|
|
rc.ReqParam = backupForm
|
|
|
|
job := &entity.DbBackup{}
|
|
job.Id = backupForm.Id
|
|
job.Name = backupForm.Name
|
|
job.StartTime = backupForm.StartTime
|
|
job.Interval = backupForm.Interval
|
|
job.MaxSaveDays = backupForm.MaxSaveDays
|
|
biz.ErrIsNilAppendErr(d.backupApp.Update(rc.MetaCtx, job), "保存数据库备份任务失败: %v")
|
|
}
|
|
|
|
func (d *DbBackup) walk(rc *req.Ctx, paramName string, fn func(ctx context.Context, id uint64) error) error {
|
|
idsStr := rc.PathParam(paramName)
|
|
biz.NotEmpty(idsStr, paramName+" 为空")
|
|
rc.ReqParam = idsStr
|
|
ids := strings.Fields(idsStr)
|
|
for _, v := range ids {
|
|
value, err := strconv.Atoi(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
backupId := uint64(value)
|
|
err = fn(rc.MetaCtx, backupId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Delete 删除数据库备份任务
|
|
// @router /api/dbs/:dbId/backups/:backupId [DELETE]
|
|
func (d *DbBackup) Delete(rc *req.Ctx) {
|
|
err := d.walk(rc, "backupId", d.backupApp.Delete)
|
|
biz.ErrIsNilAppendErr(err, "删除数据库备份任务失败: %v")
|
|
}
|
|
|
|
// Enable 启用数据库备份任务
|
|
// @router /api/dbs/:dbId/backups/:backupId/enable [PUT]
|
|
func (d *DbBackup) Enable(rc *req.Ctx) {
|
|
err := d.walk(rc, "backupId", d.backupApp.Enable)
|
|
biz.ErrIsNilAppendErr(err, "启用数据库备份任务失败: %v")
|
|
}
|
|
|
|
// Disable 禁用数据库备份任务
|
|
// @router /api/dbs/:dbId/backups/:backupId/disable [PUT]
|
|
func (d *DbBackup) Disable(rc *req.Ctx) {
|
|
err := d.walk(rc, "backupId", d.backupApp.Disable)
|
|
biz.ErrIsNilAppendErr(err, "禁用数据库备份任务失败: %v")
|
|
}
|
|
|
|
// Start 禁用数据库备份任务
|
|
// @router /api/dbs/:dbId/backups/:backupId/start [PUT]
|
|
func (d *DbBackup) Start(rc *req.Ctx) {
|
|
err := d.walk(rc, "backupId", d.backupApp.StartNow)
|
|
biz.ErrIsNilAppendErr(err, "运行数据库备份任务失败: %v")
|
|
}
|
|
|
|
// GetDbNamesWithoutBackup 获取未配置定时备份的数据库名称
|
|
// @router /api/dbs/:dbId/db-names-without-backup [GET]
|
|
func (d *DbBackup) GetDbNamesWithoutBackup(rc *req.Ctx) {
|
|
dbId := uint64(rc.PathParamInt("dbId"))
|
|
db, err := d.dbApp.GetById(new(entity.Db), dbId, "instance_id", "database")
|
|
biz.ErrIsNilAppendErr(err, "获取数据库信息失败: %v")
|
|
dbNames := strings.Fields(db.Database)
|
|
dbNamesWithoutBackup, err := d.backupApp.GetDbNamesWithoutBackup(db.InstanceId, dbNames)
|
|
biz.ErrIsNilAppendErr(err, "获取未配置定时备份的数据库名称失败: %v")
|
|
rc.ResData = dbNamesWithoutBackup
|
|
}
|
|
|
|
// GetHistoryPageList 获取数据库备份历史
|
|
// @router /api/dbs/:dbId/backups/:backupId/histories [GET]
|
|
func (d *DbBackup) GetHistoryPageList(rc *req.Ctx) {
|
|
dbId := uint64(rc.PathParamInt("dbId"))
|
|
biz.IsTrue(dbId > 0, "无效的 dbId: %v", dbId)
|
|
db, err := d.dbApp.GetById(new(entity.Db), dbId, "db_instance_id", "database")
|
|
biz.ErrIsNilAppendErr(err, "获取数据库信息失败: %v")
|
|
|
|
backupHistoryCond, page := req.BindQueryAndPage[*entity.DbBackupHistoryQuery](rc, new(entity.DbBackupHistoryQuery))
|
|
backupHistoryCond.DbInstanceId = db.InstanceId
|
|
backupHistoryCond.InDbNames = strings.Fields(db.Database)
|
|
backupHistories := make([]*vo.DbBackupHistory, 0, page.PageSize)
|
|
res, err := d.backupApp.GetHistoryPageList(backupHistoryCond, page, &backupHistories)
|
|
biz.ErrIsNilAppendErr(err, "获取数据库备份历史失败: %v")
|
|
historyIds := make([]uint64, 0, len(backupHistories))
|
|
for _, history := range backupHistories {
|
|
historyIds = append(historyIds, history.Id)
|
|
}
|
|
restores := make([]*entity.DbRestore, 0, page.PageSize)
|
|
if err := d.restoreApp.GetRestoresEnabled(&restores, historyIds...); err != nil {
|
|
biz.ErrIsNilAppendErr(err, "获取数据库备份恢复记录失败")
|
|
}
|
|
for _, history := range backupHistories {
|
|
for _, restore := range restores {
|
|
if restore.DbBackupHistoryId == history.Id {
|
|
history.LastStatus = restore.LastStatus
|
|
history.LastResult = restore.LastResult
|
|
history.LastTime = restore.LastTime
|
|
break
|
|
}
|
|
}
|
|
}
|
|
rc.ResData = res
|
|
}
|
|
|
|
// RestoreHistories 从数据库备份历史中恢复数据库
|
|
// @router /api/dbs/:dbId/backup-histories/:backupHistoryId/restore [POST]
|
|
func (d *DbBackup) RestoreHistories(rc *req.Ctx) {
|
|
pm := rc.PathParam("backupHistoryId")
|
|
biz.NotEmpty(pm, "backupHistoryId 为空")
|
|
idsStr := strings.Fields(pm)
|
|
ids := make([]uint64, 0, len(idsStr))
|
|
for _, s := range idsStr {
|
|
id, err := strconv.ParseUint(s, 10, 64)
|
|
biz.ErrIsNilAppendErr(err, "从数据库备份历史恢复数据库失败: %v")
|
|
ids = append(ids, id)
|
|
}
|
|
histories := make([]*entity.DbBackupHistory, 0, len(ids))
|
|
err := d.backupApp.GetHistories(ids, &histories)
|
|
biz.ErrIsNilAppendErr(err, "添加数据库恢复任务失败: %v")
|
|
restores := make([]*entity.DbRestore, 0, len(histories))
|
|
now := time.Now()
|
|
for _, history := range histories {
|
|
job := &entity.DbRestore{
|
|
DbInstanceId: history.DbInstanceId,
|
|
DbName: history.DbName,
|
|
Enabled: true,
|
|
Repeated: false,
|
|
StartTime: now,
|
|
Interval: 0,
|
|
PointInTime: timex.NewNullTime(time.Time{}),
|
|
DbBackupId: history.DbBackupId,
|
|
DbBackupHistoryId: history.Id,
|
|
DbBackupHistoryName: history.Name,
|
|
}
|
|
restores = append(restores, job)
|
|
}
|
|
biz.ErrIsNilAppendErr(d.restoreApp.Create(rc.MetaCtx, restores), "添加数据库恢复任务失败: %v")
|
|
}
|
|
|
|
// DeleteHistories 删除数据库备份历史
|
|
// @router /api/dbs/:dbId/backup-histories/:backupHistoryId [DELETE]
|
|
func (d *DbBackup) DeleteHistories(rc *req.Ctx) {
|
|
err := d.walk(rc, "backupHistoryId", d.backupApp.DeleteHistory)
|
|
biz.ErrIsNilAppendErr(err, "删除数据库备份历史失败: %v")
|
|
}
|