From 52198e9c0c568498a268234e35fc6797ac52a379 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Sat, 16 Sep 2023 13:16:15 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=95=B0=E6=8D=AE=E5=BA=93=E9=83=A8?= =?UTF-8?q?=E5=88=86=E9=80=BB=E8=BE=91=E8=B0=83=E6=95=B4=20(#2316)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/database_mysql.go | 20 +-- backend/app/dto/database.go | 62 ++++--- backend/app/model/database.go | 2 +- backend/app/model/database_mysql.go | 4 +- backend/app/repo/databse_mysql.go | 6 +- backend/app/service/app_utils.go | 45 +++-- backend/app/service/backup_app.go | 12 +- backend/app/service/backup_mysql.go | 30 +--- backend/app/service/cronjob_helper.go | 10 +- backend/app/service/database.go | 10 +- backend/app/service/database_mysql.go | 132 ++++++-------- backend/constant/errs.go | 2 + backend/i18n/lang/en.yaml | 2 + backend/i18n/lang/zh-Hant.yaml | 2 + backend/i18n/lang/zh.yaml | 2 + backend/init/migration/migrate.go | 2 - backend/init/migration/migrations/init.go | 163 ++++++------------ backend/utils/mysql/client/info.go | 1 + backend/utils/mysql/client/local.go | 7 +- backend/utils/mysql/client/remote.go | 7 +- cmd/server/docs/docs.go | 119 ++++++++++--- cmd/server/docs/swagger.json | 119 ++++++++++--- cmd/server/docs/swagger.yaml | 96 ++++++++--- frontend/src/api/interface/database.ts | 31 +++- frontend/src/api/modules/database.ts | 22 +-- frontend/src/components/app-status/index.vue | 6 +- frontend/src/components/backup/index.vue | 8 +- frontend/src/components/upload/index.vue | 10 +- .../src/views/database/mysql/conn/index.vue | 9 +- .../src/views/database/mysql/create/index.vue | 3 - .../src/views/database/mysql/delete/index.vue | 6 + frontend/src/views/database/mysql/index.vue | 36 ++-- .../views/database/mysql/password/index.vue | 10 +- .../views/database/mysql/setting/index.vue | 18 +- .../database/mysql/setting/slow-log/index.vue | 6 +- .../database/mysql/setting/status/index.vue | 11 +- .../mysql/setting/variables/index.vue | 12 +- 37 files changed, 578 insertions(+), 465 deletions(-) diff --git a/backend/app/api/v1/database_mysql.go b/backend/app/api/v1/database_mysql.go index c9f743479..ff2853db5 100644 --- a/backend/app/api/v1/database_mysql.go +++ b/backend/app/api/v1/database_mysql.go @@ -233,11 +233,11 @@ func (b *BaseApi) ListDBName(c *gin.Context) { // @Summary Load mysql database from remote // @Description 从服务器获取 // @Accept json -// @Param request body dto.OperateByID true "request" +// @Param request body dto.MysqlLoadDB true "request" // @Security ApiKeyAuth // @Router /databases/load [post] func (b *BaseApi) LoadDBFromRemote(c *gin.Context) { - var req dto.OperateByID + var req dto.MysqlLoadDB if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return @@ -315,12 +315,12 @@ func (b *BaseApi) DeleteMysql(c *gin.Context) { // @Summary Load mysql base info // @Description 获取 mysql 基础信息 // @Accept json -// @Param request body dto.OperateByID true "request" +// @Param request body dto.OperationWithNameAndType true "request" // @Success 200 {object} dto.DBBaseInfo // @Security ApiKeyAuth // @Router /databases/baseinfo [post] func (b *BaseApi) LoadBaseinfo(c *gin.Context) { - var req dto.OperateByID + var req dto.OperationWithNameAndType if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return @@ -360,12 +360,12 @@ func (b *BaseApi) LoadDatabaseFile(c *gin.Context) { // @Summary Load mysql remote access // @Description 获取 mysql 远程访问权限 // @Accept json -// @Param request body dto.OperateByID true "request" +// @Param request body dto.OperationWithNameAndType true "request" // @Success 200 {boolean} isRemote // @Security ApiKeyAuth // @Router /databases/remote [post] func (b *BaseApi) LoadRemoteAccess(c *gin.Context) { - var req dto.OperateByID + var req dto.OperationWithNameAndType if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return @@ -383,12 +383,12 @@ func (b *BaseApi) LoadRemoteAccess(c *gin.Context) { // @Summary Load mysql status info // @Description 获取 mysql 状态信息 // @Accept json -// @Param request body dto.OperateByID true "request" +// @Param request body dto.OperationWithNameAndType true "request" // @Success 200 {object} dto.MysqlStatus // @Security ApiKeyAuth // @Router /databases/status [post] func (b *BaseApi) LoadStatus(c *gin.Context) { - var req dto.OperateByID + var req dto.OperationWithNameAndType if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return @@ -406,12 +406,12 @@ func (b *BaseApi) LoadStatus(c *gin.Context) { // @Summary Load mysql variables info // @Description 获取 mysql 性能参数信息 // @Accept json -// @Param request body dto.OperateByID true "request" +// @Param request body dto.OperationWithNameAndType true "request" // @Success 200 {object} dto.MysqlVariables // @Security ApiKeyAuth // @Router /databases/variables [post] func (b *BaseApi) LoadVariables(c *gin.Context) { - var req dto.OperateByID + var req dto.OperationWithNameAndType if err := c.ShouldBindJSON(&req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return diff --git a/backend/app/dto/database.go b/backend/app/dto/database.go index f21edafd0..6687debba 100644 --- a/backend/app/dto/database.go +++ b/backend/app/dto/database.go @@ -4,10 +4,10 @@ import "time" type MysqlDBSearch struct { PageInfo - Info string `json:"info"` - DatabaseID uint `json:"databaseID" validate:"required"` - OrderBy string `json:"orderBy"` - Order string `json:"order"` + Info string `json:"info"` + Database string `json:"database" validate:"required"` + OrderBy string `json:"orderBy"` + Order string `json:"order"` } type MysqlDBInfo struct { @@ -15,7 +15,7 @@ type MysqlDBInfo struct { CreatedAt time.Time `json:"createdAt"` Name string `json:"name"` From string `json:"from"` - DatabaseID uint `json:"databaseID"` + MysqlName string `json:"mysqlName"` Format string `json:"format"` Username string `json:"username"` Password string `json:"password"` @@ -25,18 +25,17 @@ type MysqlDBInfo struct { } type MysqlOption struct { - ID uint `json:"id"` - From string `json:"from"` - Type string `json:"type"` - DatabaseID uint `json:"databaseID"` - Database string `json:"database"` - Name string `json:"name"` + ID uint `json:"id"` + From string `json:"from"` + Type string `json:"type"` + Database string `json:"database"` + Name string `json:"name"` } type MysqlDBCreate struct { Name string `json:"name" validate:"required"` From string `json:"from" validate:"required,oneof=local remote"` - DatabaseID uint `json:"databaseID" validate:"required"` + Database string `json:"database" validate:"required"` Format string `json:"format" validate:"required,oneof=utf8mb4 utf8 gbk big5"` Username string `json:"username" validate:"required"` Password string `json:"password" validate:"required"` @@ -44,15 +43,24 @@ type MysqlDBCreate struct { Description string `json:"description"` } +type MysqlLoadDB struct { + From string `json:"from" validate:"required,oneof=local remote"` + Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Database string `json:"database" validate:"required"` +} + type MysqlDBDeleteCheck struct { - ID uint `json:"id" validate:"required"` - DatabaseID uint `json:"databaseID" validate:"required"` + ID uint `json:"id" validate:"required"` + Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Database string `json:"database" validate:"required"` } type MysqlDBDelete struct { - ID uint `json:"id" validate:"required"` - ForceDelete bool `json:"forceDelete"` - DeleteBackup bool `json:"deleteBackup"` + ID uint `json:"id" validate:"required"` + Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Database string `json:"database" validate:"required"` + ForceDelete bool `json:"forceDelete"` + DeleteBackup bool `json:"deleteBackup"` } type MysqlStatus struct { @@ -116,8 +124,9 @@ type MysqlVariables struct { } type MysqlVariablesUpdate struct { - DatabaseID uint `json:"databaseID" validate:"required"` - Variables []MysqlVariablesUpdateHelper `json:"variables"` + Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Database string `json:"database" validate:"required"` + Variables []MysqlVariablesUpdateHelper `json:"variables"` } type MysqlVariablesUpdateHelper struct { @@ -125,16 +134,17 @@ type MysqlVariablesUpdateHelper struct { Value interface{} `json:"value"` } type MysqlConfUpdateByFile struct { - DatabaseID uint `json:"databaseID" validate:"required"` - File string `json:"file"` + Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Database string `json:"database" validate:"required"` + File string `json:"file"` } type ChangeDBInfo struct { - ID uint `json:"id"` - From string `json:"from" validate:"required,oneof=local remote"` - Type string `json:"type" validate:"required,oneof=mysql mariadb"` - DatabaseID uint `json:"databaseID" validate:"required"` - Value string `json:"value" validate:"required"` + ID uint `json:"id"` + From string `json:"from" validate:"required,oneof=local remote"` + Type string `json:"type" validate:"required,oneof=mysql mariadb"` + Database string `json:"database" validate:"required"` + Value string `json:"value" validate:"required"` } type DBBaseInfo struct { diff --git a/backend/app/model/database.go b/backend/app/model/database.go index c2d9f5443..1123bf282 100644 --- a/backend/app/model/database.go +++ b/backend/app/model/database.go @@ -3,7 +3,7 @@ package model type Database struct { BaseModel AppInstallID uint `json:"appInstallID" gorm:"type:decimal"` - Name string `json:"name" gorm:"type:varchar(64);not null"` + Name string `json:"name" gorm:"type:varchar(64);not null;unique"` Type string `json:"type" gorm:"type:varchar(64);not null"` Version string `json:"version" gorm:"type:varchar(64);not null"` From string `json:"from" gorm:"type:varchar(64);not null"` diff --git a/backend/app/model/database_mysql.go b/backend/app/model/database_mysql.go index 3c70284bb..95bc41dbb 100644 --- a/backend/app/model/database_mysql.go +++ b/backend/app/model/database_mysql.go @@ -4,12 +4,10 @@ type DatabaseMysql struct { BaseModel Name string `json:"name" gorm:"type:varchar(256);not null"` From string `json:"from" gorm:"type:varchar(256);not null;default:local"` - MysqlName string `json:"mysqlName" gorm:"type:varchar(64);not null"` // 已废弃 + MysqlName string `json:"mysqlName" gorm:"type:varchar(64);not null"` Format string `json:"format" gorm:"type:varchar(64);not null"` Username string `json:"username" gorm:"type:varchar(256);not null"` Password string `json:"password" gorm:"type:varchar(256);not null"` Permission string `json:"permission" gorm:"type:varchar(256);not null"` Description string `json:"description" gorm:"type:varchar(256);"` - - DatabaseID uint `json:"databaseID" gorm:"type:decimal"` } diff --git a/backend/app/repo/databse_mysql.go b/backend/app/repo/databse_mysql.go index 6e8dbc2d0..47d107379 100644 --- a/backend/app/repo/databse_mysql.go +++ b/backend/app/repo/databse_mysql.go @@ -14,7 +14,7 @@ type MysqlRepo struct{} type IMysqlRepo interface { Get(opts ...DBOption) (model.DatabaseMysql, error) - WithByDatabase(databaseID uint) DBOption + WithByMysqlName(mysqlName string) DBOption WithByFrom(from string) DBOption List(opts ...DBOption) ([]model.DatabaseMysql, error) Page(limit, offset int, opts ...DBOption) (int64, []model.DatabaseMysql, error) @@ -107,9 +107,9 @@ func (u *MysqlRepo) Update(id uint, vars map[string]interface{}) error { return global.DB.Model(&model.DatabaseMysql{}).Where("id = ?", id).Updates(vars).Error } -func (u *MysqlRepo) WithByDatabase(databaseID uint) DBOption { +func (u *MysqlRepo) WithByMysqlName(mysqlName string) DBOption { return func(g *gorm.DB) *gorm.DB { - return g.Where("database_id = ?", databaseID) + return g.Where("mysql_name = ?", mysqlName) } } diff --git a/backend/app/service/app_utils.go b/backend/app/service/app_utils.go index c0373d6f7..5c19f9db4 100644 --- a/backend/app/service/app_utils.go +++ b/backend/app/service/app_utils.go @@ -187,25 +187,19 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall return buserr.New(constant.ErrDbUserNotValid) } } else { - if databaseID, ok := params["PANEL_DB_HOST_ID"]; ok { - database, err := databaseRepo.Get(commonRepo.WithByID(databaseID.(uint))) - if err != nil { - return err - } - var createMysql dto.MysqlDBCreate - createMysql.Name = dbConfig.DbName - createMysql.Username = dbConfig.DbUser - createMysql.DatabaseID = database.ID - createMysql.Format = "utf8mb4" - createMysql.Permission = "%" - createMysql.Password = dbConfig.Password - createMysql.From = "local" - mysqldb, err := NewIMysqlService().Create(ctx, createMysql) - if err != nil { - return err - } - resourceId = mysqldb.ID + var createMysql dto.MysqlDBCreate + createMysql.Name = dbConfig.DbName + createMysql.Username = dbConfig.DbUser + createMysql.Database = dbInstall.Name + createMysql.Format = "utf8mb4" + createMysql.Permission = "%" + createMysql.Password = dbConfig.Password + createMysql.From = "local" + mysqldb, err := NewIMysqlService().Create(ctx, createMysql) + if err != nil { + return err } + resourceId = mysqldb.ID } } var installResource model.AppInstallResource @@ -258,6 +252,7 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b if err := deleteLink(ctx, &install, deleteDB, forceDelete, deleteBackup); err != nil && !forceDelete { return err } + if DatabaseKeys[install.App.Key] > 0 { _ = databaseRepo.Delete(ctx, databaseRepo.WithAppInstallID(install.ID)) } @@ -267,10 +262,7 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b _ = websiteRepo.DeleteAll(ctx) _ = websiteDomainRepo.DeleteAll(ctx) case constant.AppMysql, constant.AppMariaDB: - database, _ := databaseRepo.Get(databaseRepo.WithAppInstallID(install.ID)) - if database.ID > 0 { - _ = mysqlRepo.Delete(ctx, mysqlRepo.WithByDatabase(database.ID)) - } + _ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name)) } _ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name)) @@ -292,6 +284,7 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b } func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, forceDelete bool, deleteBackup bool) error { + resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithAppInstallId(install.ID)) if len(resources) == 0 { return nil @@ -299,14 +292,16 @@ func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, f for _, re := range resources { mysqlService := NewIMysqlService() if (re.Key == constant.AppMysql || re.Key == constant.AppMariaDB) && deleteDB { - mysqlDatabase, _ := mysqlRepo.Get(commonRepo.WithByID(re.ResourceId)) - if mysqlDatabase.ID == 0 { + database, _ := mysqlRepo.Get(commonRepo.WithByID(re.ResourceId)) + if reflect.DeepEqual(database, model.DatabaseMysql{}) { continue } if err := mysqlService.Delete(ctx, dto.MysqlDBDelete{ - ID: mysqlDatabase.ID, + ID: database.ID, ForceDelete: forceDelete, DeleteBackup: deleteBackup, + Type: re.Key, + Database: database.MysqlName, }); err != nil && !forceDelete { return err } diff --git a/backend/app/service/backup_app.go b/backend/app/service/backup_app.go index 81618e6ba..f6dbe10de 100644 --- a/backend/app/service/backup_app.go +++ b/backend/app/service/backup_app.go @@ -111,7 +111,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro if err != nil { return err } - if err := handleMysqlBackup(db.DatabaseID, db.Name, tmpDir, fmt.Sprintf("%s.sql.gz", install.Name)); err != nil { + if err := handleMysqlBackup(db.MysqlName, db.Name, tmpDir, fmt.Sprintf("%s.sql.gz", install.Name)); err != nil { return err } } @@ -190,7 +190,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback return err } - newDB, envMap, err := reCreateDB(db, resourceApp, oldInstall.Env) + newDB, envMap, err := reCreateDB(db.ID, resourceApp, oldInstall.Env) if err != nil { return err } @@ -205,7 +205,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback _ = appInstallResourceRepo.BatchUpdateBy(map[string]interface{}{"resource_id": newDB.ID}, commonRepo.WithByID(resource.ID)) if err := handleMysqlRecover(dto.CommonRecover{ - Name: fmt.Sprintf("%d", newDB.DatabaseID), + Name: newDB.MysqlName, DetailName: newDB.Name, File: fmt.Sprintf("%s/%s.sql.gz", tmpPath, install.Name), }, true); err != nil { @@ -252,10 +252,10 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback return nil } -func reCreateDB(db model.DatabaseMysql, app model.AppInstall, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) { +func reCreateDB(dbID uint, app model.AppInstall, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) { mysqlService := NewIMysqlService() ctx := context.Background() - _ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: db.ID, DeleteBackup: true, ForceDelete: true}) + _ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, Database: app.Name, Type: app.App.Key, DeleteBackup: true, ForceDelete: true}) envMap := make(map[string]interface{}) if err := json.Unmarshal([]byte(oldEnv), &envMap); err != nil { @@ -267,7 +267,7 @@ func reCreateDB(db model.DatabaseMysql, app model.AppInstall, oldEnv string) (*m createDB, err := mysqlService.Create(context.Background(), dto.MysqlDBCreate{ Name: oldName, From: "local", - DatabaseID: db.DatabaseID, + Database: app.Name, Format: "utf8mb4", Username: oldUser, Password: oldPassword, diff --git a/backend/app/service/backup_mysql.go b/backend/app/service/backup_mysql.go index e70f06bfc..be4b409a6 100644 --- a/backend/app/service/backup_mysql.go +++ b/backend/app/service/backup_mysql.go @@ -5,7 +5,6 @@ import ( "os" "path" "path/filepath" - "strconv" "strings" "time" @@ -24,25 +23,16 @@ func (u *BackupService) MysqlBackup(req dto.CommonBackup) error { } timeNow := time.Now().Format("20060102150405") - databaseID, err := strconv.Atoi(req.Name) - if err != nil { - return err - } - database, err := databaseRepo.Get(commonRepo.WithByID(uint(databaseID))) - if err != nil { - return err - } - dirName := fmt.Sprintf("%s-%s", database.From, database.Name) - targetDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, dirName, req.DetailName)) + targetDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, req.Name, req.DetailName)) fileName := fmt.Sprintf("%s_%s.sql.gz", req.DetailName, timeNow) - if err := handleMysqlBackup(uint(databaseID), req.DetailName, targetDir, fileName); err != nil { + if err := handleMysqlBackup(req.Name, req.DetailName, targetDir, fileName); err != nil { return err } record := &model.BackupRecord{ Type: req.Type, - Name: fmt.Sprintf("%v", database.ID), + Name: req.Name, DetailName: req.DetailName, Source: "LOCAL", BackupType: "LOCAL", @@ -107,12 +97,12 @@ func (u *BackupService) MysqlRecoverByUpload(req dto.CommonRecover) error { return nil } -func handleMysqlBackup(databaseID uint, dbName, targetDir, fileName string) error { - cli, _, _, err := LoadMysqlClientByFrom(databaseID) +func handleMysqlBackup(database, dbName, targetDir, fileName string) error { + dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(dbName), mysqlRepo.WithByMysqlName(database)) if err != nil { return err } - dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(dbName), mysqlRepo.WithByDatabase(databaseID)) + cli, _, err := LoadMysqlClientByFrom(database) if err != nil { return err } @@ -137,15 +127,11 @@ func handleMysqlRecover(req dto.CommonRecover, isRollback bool) error { if !fileOp.Stat(req.File) { return errors.New(fmt.Sprintf("%s file is not exist", req.File)) } - databaseID, err := strconv.Atoi(req.Name) - if err != nil { - return err - } - cli, _, _, err := LoadMysqlClientByFrom(uint(databaseID)) + dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(req.DetailName), mysqlRepo.WithByMysqlName(req.Name)) if err != nil { return err } - dbInfo, err := mysqlRepo.Get(commonRepo.WithByName(req.DetailName), mysqlRepo.WithByDatabase(uint(databaseID))) + cli, _, err := LoadMysqlClientByFrom(req.Name) if err != nil { return err } diff --git a/backend/app/service/cronjob_helper.go b/backend/app/service/cronjob_helper.go index 0f816920d..c41c39f4b 100644 --- a/backend/app/service/cronjob_helper.go +++ b/backend/app/service/cronjob_helper.go @@ -292,16 +292,16 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, backup model.Back for _, dbInfo := range dbs { var record model.BackupRecord - database, _ := databaseRepo.Get(commonRepo.WithByID(dbInfo.DatabaseID)) + + database, _ := databaseRepo.Get(commonRepo.WithByName(dbInfo.MysqlName)) record.Type = database.Type record.Source = "LOCAL" record.BackupType = backup.Type - dirName := fmt.Sprintf("%s-%s", database.From, database.Name) - record.Name = fmt.Sprintf("%v", database.ID) - backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", database.Type, dirName, dbInfo.Name)) + record.Name = dbInfo.MysqlName + backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", database.Type, record.Name, dbInfo.Name)) record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format("20060102150405")) - if err = handleMysqlBackup(dbInfo.DatabaseID, dbInfo.Name, backupDir, record.FileName); err != nil { + if err = handleMysqlBackup(dbInfo.MysqlName, dbInfo.Name, backupDir, record.FileName); err != nil { return paths, err } diff --git a/backend/app/service/database.go b/backend/app/service/database.go index 54acdcbe1..e7f2e6f8b 100644 --- a/backend/app/service/database.go +++ b/backend/app/service/database.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/1Panel-dev/1Panel/backend/app/dto" + "github.com/1Panel-dev/1Panel/backend/buserr" "github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/utils/encrypt" "github.com/1Panel-dev/1Panel/backend/utils/mysql" @@ -87,12 +88,15 @@ func (u *DatabaseService) CheckDatabase(req dto.DatabaseCreate) bool { } func (u *DatabaseService) Create(req dto.DatabaseCreate) error { - db, _ := databaseRepo.Get(commonRepo.WithByName(req.Name), commonRepo.WithByType(req.Type), databaseRepo.WithByFrom(req.From)) + db, _ := databaseRepo.Get(commonRepo.WithByName(req.Name)) if db.ID != 0 { + if db.From == "local" { + return buserr.New(constant.ErrLocalExist) + } return constant.ErrRecordExist } if _, err := mysql.NewMysqlClient(client.DBInfo{ - From: req.From, + From: "remote", Address: req.Address, Port: req.Port, Username: req.Username, @@ -119,7 +123,7 @@ func (u *DatabaseService) Delete(id uint) error { return err } if db.From != "local" { - if err := mysqlRepo.Delete(context.Background(), mysqlRepo.WithByDatabase(db.ID)); err != nil { + if err := mysqlRepo.Delete(context.Background(), mysqlRepo.WithByMysqlName(db.Name)); err != nil { return err } } diff --git a/backend/app/service/database_mysql.go b/backend/app/service/database_mysql.go index 40bcc5940..4cd802238 100644 --- a/backend/app/service/database_mysql.go +++ b/backend/app/service/database_mysql.go @@ -35,6 +35,7 @@ type IMysqlService interface { SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) ListDBOption() ([]dto.MysqlOption, error) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) + LoadFromRemote(req dto.MysqlLoadDB) error ChangeAccess(info dto.ChangeDBInfo) error ChangePassword(info dto.ChangeDBInfo) error UpdateVariables(req dto.MysqlVariablesUpdate) error @@ -43,11 +44,10 @@ type IMysqlService interface { DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error) Delete(ctx context.Context, req dto.MysqlDBDelete) error - LoadFromRemote(req dto.OperateByID) error - LoadStatus(req dto.OperateByID) (*dto.MysqlStatus, error) - LoadVariables(req dto.OperateByID) (*dto.MysqlVariables, error) - LoadBaseInfo(req dto.OperateByID) (*dto.DBBaseInfo, error) - LoadRemoteAccess(req dto.OperateByID) (bool, error) + LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error) + LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error) + LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) + LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) LoadDatabaseFile(req dto.OperationWithNameAndType) (string, error) } @@ -58,11 +58,10 @@ func NewIMysqlService() IMysqlService { func (u *MysqlService) SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) { total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, - mysqlRepo.WithByDatabase(search.DatabaseID), + mysqlRepo.WithByMysqlName(search.Database), commonRepo.WithLikeName(search.Info), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order), ) - var dtoMysqls []dto.MysqlDBInfo for _, mysql := range mysqls { var item dto.MysqlDBInfo @@ -90,10 +89,10 @@ func (u *MysqlService) ListDBOption() ([]dto.MysqlOption, error) { if err := copier.Copy(&item, &mysql); err != nil { return nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) } + item.Database = mysql.MysqlName for _, database := range databases { - if database.ID == item.DatabaseID { + if database.Name == item.Database { item.Type = database.Type - item.Database = database.Name } } dbs = append(dbs, item) @@ -106,7 +105,7 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode return nil, buserr.New(constant.ErrCmdIllegal) } - mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name), mysqlRepo.WithByDatabase(req.DatabaseID)) + mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name), mysqlRepo.WithByMysqlName(req.Database), databaseRepo.WithByFrom(req.From)) if mysql.ID != 0 { return nil, constant.ErrRecordExist } @@ -116,14 +115,15 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode return nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) } - if req.Username == "root" { + if req.From == "local" && req.Username == "root" { return nil, errors.New("Cannot set root as user name") } - cli, version, _, err := LoadMysqlClientByFrom(req.DatabaseID) + cli, version, err := LoadMysqlClientByFrom(req.Database) if err != nil { return nil, err } + createItem.MysqlName = req.Database defer cli.Close() if err := cli.Create(client.CreateInfo{ Name: req.Name, @@ -144,13 +144,13 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode return &createItem, nil } -func (u *MysqlService) LoadFromRemote(req dto.OperateByID) error { - client, version, _, err := LoadMysqlClientByFrom(req.ID) +func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error { + client, version, err := LoadMysqlClientByFrom(req.Database) if err != nil { return err } - dbs, err := mysqlRepo.List(mysqlRepo.WithByDatabase(req.ID)) + databases, err := mysqlRepo.List(databaseRepo.WithByFrom(req.From)) if err != nil { return err } @@ -160,8 +160,8 @@ func (u *MysqlService) LoadFromRemote(req dto.OperateByID) error { } for _, data := range datas { hasOld := false - for _, oldData := range dbs { - if strings.EqualFold(oldData.Name, data.Name) { + for _, oldData := range databases { + if strings.EqualFold(oldData.Name, data.Name) && strings.EqualFold(oldData.MysqlName, data.MysqlName) { hasOld = true break } @@ -171,7 +171,6 @@ func (u *MysqlService) LoadFromRemote(req dto.OperateByID) error { if err := copier.Copy(&createItem, &data); err != nil { return errors.WithMessage(constant.ErrStructTransform, err.Error()) } - createItem.DatabaseID = req.ID if err := mysqlRepo.Create(context.Background(), &createItem); err != nil { return err } @@ -190,12 +189,9 @@ func (u *MysqlService) DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error) if err != nil { return appInUsed, err } - database, err := databaseRepo.Get(commonRepo.WithByID(req.DatabaseID)) - if err != nil { - return appInUsed, err - } + if db.From == "local" { - app, err := appInstallRepo.LoadBaseInfo(database.Type, database.Name) + app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database) if err != nil { return appInUsed, err } @@ -224,11 +220,7 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error if err != nil && !req.ForceDelete { return err } - database, err := databaseRepo.Get(commonRepo.WithByID(db.DatabaseID)) - if err != nil && !req.ForceDelete { - return err - } - cli, version, _, err := LoadMysqlClientByFrom(db.DatabaseID) + cli, version, err := LoadMysqlClientByFrom(req.Database) if err != nil { return err } @@ -243,24 +235,22 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error return err } - uploadDir2 := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/%s/%s-%s/%s", database.Type, database.From, database.Name, db.Name)) - if _, err := os.Stat(uploadDir2); err == nil { - _ = os.RemoveAll(uploadDir2) + uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/%s/%s/%s", req.Type, req.Database, db.Name)) + if _, err := os.Stat(uploadDir); err == nil { + _ = os.RemoveAll(uploadDir) } if req.DeleteBackup { localDir, err := loadLocalDir() if err != nil && !req.ForceDelete { return err } - backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s-%s/%s", database.Type, db.From, database.Name, db.Name)) + backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, db.MysqlName, db.Name)) if _, err := os.Stat(backupDir); err == nil { _ = os.RemoveAll(backupDir) } - global.LOG.Infof("delete database %s-%s backups successful", database.Name, db.Name) + global.LOG.Infof("delete database %s-%s backups successful", req.Database, db.Name) } - _ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(database.Type), - commonRepo.WithByName(fmt.Sprintf("%v", database.ID)), - backupRepo.WithByDetailName(db.Name)) + _ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(req.Type), commonRepo.WithByName(req.Database), backupRepo.WithByDetailName(db.Name)) _ = mysqlRepo.Delete(ctx, commonRepo.WithByID(db.ID)) return nil @@ -270,7 +260,7 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error { if cmd.CheckIllegal(req.Value) { return buserr.New(constant.ErrCmdIllegal) } - cli, version, database, err := LoadMysqlClientByFrom(req.DatabaseID) + cli, version, err := LoadMysqlClientByFrom(req.Database) if err != nil { return err } @@ -301,7 +291,7 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error { if req.ID != 0 { var appRess []model.AppInstallResource if req.From == "local" { - app, err := appInstallRepo.LoadBaseInfo(req.Type, database) + app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database) if err != nil { return err } @@ -333,7 +323,7 @@ func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error { return nil } - if err := updateInstallInfoInDB(req.Type, database, "password", false, req.Value); err != nil { + if err := updateInstallInfoInDB(req.Type, req.Database, "password", false, req.Value); err != nil { return err } return nil @@ -343,7 +333,7 @@ func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error { if cmd.CheckIllegal(req.Value) { return buserr.New(constant.ErrCmdIllegal) } - cli, version, _, err := LoadMysqlClientByFrom(req.DatabaseID) + cli, version, err := LoadMysqlClientByFrom(req.Database) if err != nil { return err } @@ -380,11 +370,11 @@ func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error { } func (u *MysqlService) UpdateConfByFile(req dto.MysqlConfUpdateByFile) error { - database, err := databaseRepo.Get(commonRepo.WithByID(req.DatabaseID)) + app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database) if err != nil { return err } - path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, database.Type, database.Name) + path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name) file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640) if err != nil { return err @@ -393,20 +383,20 @@ func (u *MysqlService) UpdateConfByFile(req dto.MysqlConfUpdateByFile) error { write := bufio.NewWriter(file) _, _ = write.WriteString(req.File) write.Flush() - if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, database.Type, database.Name)); err != nil { + if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil { return err } return nil } func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error { - database, err := databaseRepo.Get(commonRepo.WithByID(req.DatabaseID)) + app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database) if err != nil { return err } var files []string - path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, database.Type, database.Name) + path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name) lineBytes, err := os.ReadFile(path) if err != nil { return err @@ -415,7 +405,7 @@ func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error { group := "[mysqld]" for _, info := range req.Variables { - if !strings.HasPrefix(database.Version, "5.7") && !strings.HasPrefix(database.Version, "5.6") { + if !strings.HasPrefix(app.Version, "5.7") && !strings.HasPrefix(app.Version, "5.6") { if info.Param == "query_cache_size" { continue } @@ -437,20 +427,16 @@ func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error { return err } - if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, database.Type, database.Name)); err != nil { + if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil { return err } return nil } -func (u *MysqlService) LoadBaseInfo(req dto.OperateByID) (*dto.DBBaseInfo, error) { - database, err := databaseRepo.Get(commonRepo.WithByID(req.ID)) - if err != nil { - return nil, err - } +func (u *MysqlService) LoadBaseInfo(req dto.OperationWithNameAndType) (*dto.DBBaseInfo, error) { var data dto.DBBaseInfo - app, err := appInstallRepo.LoadBaseInfo(database.Type, database.Name) + app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name) if err != nil { return nil, err } @@ -461,12 +447,8 @@ func (u *MysqlService) LoadBaseInfo(req dto.OperateByID) (*dto.DBBaseInfo, error return &data, nil } -func (u *MysqlService) LoadRemoteAccess(req dto.OperateByID) (bool, error) { - database, err := databaseRepo.Get(commonRepo.WithByID(req.ID)) - if err != nil { - return false, err - } - app, err := appInstallRepo.LoadBaseInfo(database.Type, database.Name) +func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) { + app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name) if err != nil { return false, err } @@ -483,12 +465,8 @@ func (u *MysqlService) LoadRemoteAccess(req dto.OperateByID) (bool, error) { return false, nil } -func (u *MysqlService) LoadVariables(req dto.OperateByID) (*dto.MysqlVariables, error) { - database, err := databaseRepo.Get(commonRepo.WithByID(req.ID)) - if err != nil { - return nil, err - } - app, err := appInstallRepo.LoadBaseInfo(database.Type, database.Name) +func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error) { + app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name) if err != nil { return nil, err } @@ -505,12 +483,8 @@ func (u *MysqlService) LoadVariables(req dto.OperateByID) (*dto.MysqlVariables, return &info, nil } -func (u *MysqlService) LoadStatus(req dto.OperateByID) (*dto.MysqlStatus, error) { - database, err := databaseRepo.Get(commonRepo.WithByID(req.ID)) - if err != nil { - return nil, err - } - app, err := appInstallRepo.LoadBaseInfo(database.Type, database.Name) +func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error) { + app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name) if err != nil { return nil, err } @@ -648,7 +622,7 @@ func updateMyCnf(oldFiles []string, group string, param string, value interface{ return newFiles } -func LoadMysqlClientByFrom(databaseID uint) (mysql.MysqlClient, string, string, error) { +func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) { var ( dbInfo client.DBInfo version string @@ -656,12 +630,12 @@ func LoadMysqlClientByFrom(databaseID uint) (mysql.MysqlClient, string, string, ) dbInfo.Timeout = 300 - databaseItem, err := databaseRepo.Get(commonRepo.WithByID(databaseID)) + databaseItem, err := databaseRepo.Get(commonRepo.WithByName(database)) if err != nil { - return nil, "", databaseItem.Name, err + return nil, "", err } dbInfo.From = databaseItem.From - dbInfo.Database = databaseItem.Name + dbInfo.Database = database if dbInfo.From != "local" { dbInfo.Address = databaseItem.Address dbInfo.Port = databaseItem.Port @@ -670,9 +644,9 @@ func LoadMysqlClientByFrom(databaseID uint) (mysql.MysqlClient, string, string, version = databaseItem.Version } else { - app, err := appInstallRepo.LoadBaseInfo(databaseItem.Type, databaseItem.Name) + app, err := appInstallRepo.LoadBaseInfo(databaseItem.Type, database) if err != nil { - return nil, "", databaseItem.Name, err + return nil, "", err } dbInfo.Address = app.ContainerName dbInfo.Username = "root" @@ -682,7 +656,7 @@ func LoadMysqlClientByFrom(databaseID uint) (mysql.MysqlClient, string, string, cli, err := mysql.NewMysqlClient(dbInfo) if err != nil { - return nil, "", databaseItem.Name, err + return nil, "", err } - return cli, version, databaseItem.Name, nil + return cli, version, nil } diff --git a/backend/constant/errs.go b/backend/constant/errs.go index 973c2ddf8..02b3d2c23 100644 --- a/backend/constant/errs.go +++ b/backend/constant/errs.go @@ -96,6 +96,8 @@ var ( ErrUserIsExist = "ErrUserIsExist" ErrDatabaseIsExist = "ErrDatabaseIsExist" ErrExecTimeOut = "ErrExecTimeOut" + ErrRemoteExist = "ErrRemoteExist" + ErrLocalExist = "ErrLocalExist" ) // redis diff --git a/backend/i18n/lang/en.yaml b/backend/i18n/lang/en.yaml index dbc20f440..7f98ee4bd 100644 --- a/backend/i18n/lang/en.yaml +++ b/backend/i18n/lang/en.yaml @@ -82,6 +82,8 @@ ErrSSLCertificateFormat: 'Certificate file format error, please use pem format' ErrUserIsExist: "The current user already exists. Please enter a new user" ErrDatabaseIsExist: "The current database already exists. Please enter a new database" ErrExecTimeOut: "SQL execution timed out, please check the database" +ErrRemoteExist: "The remote database already exists with that name, please modify it and try again" +ErrLocalExist: "The local database already exists with that name, please modify it and try again" #redis ErrTypeOfRedis: "The recovery file type does not match the current persistence mode. Modify the file type and try again" diff --git a/backend/i18n/lang/zh-Hant.yaml b/backend/i18n/lang/zh-Hant.yaml index 7c7288129..5372c71b3 100644 --- a/backend/i18n/lang/zh-Hant.yaml +++ b/backend/i18n/lang/zh-Hant.yaml @@ -82,6 +82,8 @@ ErrSSLCertificateFormat: '證書文件格式錯誤,請使用 pem 格式' ErrUserIsExist: "當前用戶已存在,請重新輸入" ErrDatabaseIsExist: "當前資料庫已存在,請重新輸入" ErrExecTimeOut: "SQL 執行超時,請檢查數據庫" +ErrRemoteExist: "遠程數據庫已存在該名稱,請修改後重試" +ErrLocalExist: "本地數據庫已存在該名稱,請修改後重試" #redis ErrTypeOfRedis: "恢復文件類型與當前持久化方式不符,請修改後重試" diff --git a/backend/i18n/lang/zh.yaml b/backend/i18n/lang/zh.yaml index afec79309..4b46094b1 100644 --- a/backend/i18n/lang/zh.yaml +++ b/backend/i18n/lang/zh.yaml @@ -82,6 +82,8 @@ ErrSSLCertificateFormat: '证书文件格式错误,请使用 pem 格式' ErrUserIsExist: "当前用户已存在,请重新输入" ErrDatabaseIsExist: "当前数据库已存在,请重新输入" ErrExecTimeOut: "SQL 执行超时,请检查数据库" +ErrRemoteExist: "远程数据库已存在该名称,请修改后重试" +ErrLocalExist: "本地数据库已存在该名称,请修改后重试" #redis ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试" diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index 79b33f91e..582c433f2 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -43,8 +43,6 @@ func Init() { migrations.UpdateDatabase, migrations.UpdateAppInstallResource, migrations.DropDatabaseLocal, - migrations.AddDatabaseID, - migrations.UpdataBackupRecord, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index 79a6b47e6..ff698f34b 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -2,7 +2,6 @@ package migrations import ( "fmt" - "strconv" "strings" "time" @@ -572,76 +571,45 @@ var AddTableFirewall = &gormigrate.Migration{ var AddDatabases = &gormigrate.Migration{ ID: "20230831-add-databases", Migrate: func(tx *gorm.DB) error { - var ( - backups []model.BackupRecord - databases []model.Database - ) - _ = tx.Where("type = ? OR type = ?", "mysql", "mariadb").Find(&backups).Error - _ = tx.Where("from = ?", "remote").Find(&databases).Error - _ = tx.Where("name = ? AND address = ? AND type = ?", "local", "127.0.0.1", "mysql").Delete(&model.Database{}).Error - for _, backup := range backups { - for _, database := range databases { - if backup.Name == database.Name && backup.Type == database.Type { - _ = tx.Model(&model.BackupRecord{}).Where("id = ?", backup.ID).Updates(map[string]interface{}{ - "name": fmt.Sprintf("%v", database.ID), - }).Error - break - } - } - } installRepo := repo.NewIAppInstallRepo() - mysql := addDatabaseData("mysql", installRepo) + _ = tx.Where("name = ? AND address = ?", "local", "127.0.0.1").Delete(&model.Database{}).Error + mysql := addDatabaseData(tx, installRepo, "mysql") if mysql.AppInstallID != 0 { if err := tx.Create(mysql).Error; err != nil { return err } } - mariadb := addDatabaseData("mariadb", installRepo) + mariadb := addDatabaseData(tx, installRepo, "mariadb") if mariadb.AppInstallID != 0 { if err := tx.Create(mariadb).Error; err != nil { return err } } - redis := addDatabaseData("redis", installRepo) + redis := addDatabaseData(tx, installRepo, "redis") if redis.AppInstallID != 0 { if err := tx.Create(redis).Error; err != nil { return err } } - postgresql := addDatabaseData("postgresql", installRepo) + postgresql := addDatabaseData(tx, installRepo, "postgresql") if postgresql.AppInstallID != 0 { if err := tx.Create(postgresql).Error; err != nil { return err } } - mongodb := addDatabaseData("mongodb", installRepo) + mongodb := addDatabaseData(tx, installRepo, "mongodb") if mongodb.AppInstallID != 0 { if err := tx.Create(mongodb).Error; err != nil { return err } } - memcached := addDatabaseData("memcached", installRepo) + memcached := addDatabaseData(tx, installRepo, "memcached") if memcached.AppInstallID != 0 { if err := tx.Create(memcached).Error; err != nil { return err } } - _ = tx.Where("type = ? OR type = ?", "mysql", "mariadb").Find(&backups).Error - _ = tx.Where("from = ?", "local").Find(&databases).Error - for _, backup := range backups { - if _, err := strconv.Atoi(backup.Name); err == nil { - continue - } - for _, database := range databases { - if backup.Name == database.Name && backup.Type == database.Type { - _ = tx.Model(&model.BackupRecord{}).Where("id = ?", backup.ID).Updates(map[string]interface{}{ - "name": fmt.Sprintf("%v", database.ID), - }).Error - break - } - } - } return nil }, } @@ -715,80 +683,61 @@ var DropDatabaseLocal = &gormigrate.Migration{ }, } -var AddDatabaseID = &gormigrate.Migration{ - ID: "20230914-add-database-id", - Migrate: func(tx *gorm.DB) error { - if err := tx.AutoMigrate(&model.DatabaseMysql{}, &model.Database{}); err != nil { - return err - } - var ( - mysqls []model.DatabaseMysql - databases []model.Database - ) - _ = tx.Find(&mysqls).Error - if len(mysqls) == 0 { - return nil - } - _ = tx.Find(&databases).Error - for _, mysql := range mysqls { - for _, database := range databases { - if mysql.MysqlName == database.Name && mysql.From == database.From { - if err := tx.Model(&model.DatabaseMysql{}).Where("id = ?", mysql.ID).Updates(map[string]interface{}{ - "database_id": database.ID, - }).Error; err != nil { - return err +func addDatabaseData(tx *gorm.DB, installRepo repo.IAppInstallRepo, appType string) *model.Database { + dbInfo, err := installRepo.LoadBaseInfo(appType, "") + if err != nil { + return &model.Database{} + } + + if appType == "mysql" || appType == "redis" || appType == "mariadb" || appType == "memcached" { + dbInfo.UserName = "root" + } + database := &model.Database{ + AppInstallID: dbInfo.ID, + Name: dbInfo.Name, + Type: appType, + Version: dbInfo.Version, + From: "local", + Address: dbInfo.ServiceName, + Port: service.DatabaseKeys[appType], + Username: dbInfo.UserName, + Password: dbInfo.Password, + } + var dbItem model.Database + _ = global.DB.Where("name = ?", dbInfo.Name).First(&dbItem).Error + if dbItem.ID != 0 { + if appType == "mysql" { + var ( + backups []model.BackupRecord + mysqls []model.DatabaseMysql + ) + _ = tx.Where("name = ? AND type = ?", dbItem.Name, "mysql").Find(&backups) + _ = tx.Where("`from` = ?", "local").Find(&mysqls) + for _, item := range backups { + isLocal := false + for _, mysql := range mysqls { + if item.Name == mysql.MysqlName && item.DetailName == mysql.Name { + isLocal = true + break } - break } - } - } - return nil - }, -} - -var UpdataBackupRecord = &gormigrate.Migration{ - ID: "20230915-update-backup-record", - Migrate: func(tx *gorm.DB) error { - var ( - backups []model.BackupRecord - databases []model.Database - ) - _ = tx.Where("type = ? OR type = ?", "mysql", "mariadb").Find(&backups).Error - _ = tx.Find(&databases).Error - for _, backup := range backups { - if _, err := strconv.Atoi(backup.Name); err == nil { - continue - } - for _, database := range databases { - if backup.Name == database.Name && backup.Type == database.Type { - _ = tx.Model(&model.BackupRecord{}).Where("id = ?", backup.ID).Updates(map[string]interface{}{ - "name": fmt.Sprintf("%v", database.ID), + if !isLocal { + _ = tx.Model(&model.BackupRecord{}).Where("id = ?", item.ID).Updates(map[string]interface{}{ + "name": "remote-" + dbItem.Name, }).Error - break } } } - return nil - }, -} - -func addDatabaseData(appType string, installRepo repo.IAppInstallRepo) *model.Database { - dbInfo, err := installRepo.LoadBaseInfo(appType, "") - if err == nil { - if appType == "mysql" || appType == "redis" || appType == "mariadb" || appType == "memcached" { - dbInfo.UserName = "root" - } - return &model.Database{ - AppInstallID: dbInfo.ID, - Name: dbInfo.Name, - Type: appType, - Version: dbInfo.Version, - From: "local", - Address: dbInfo.ServiceName, - Port: service.DatabaseKeys[appType], - Username: dbInfo.UserName, - Password: dbInfo.Password, + if err := tx.Debug().Model(&model.DatabaseMysql{}).Where("mysql_name = ? AND `from` != ?", dbItem.Name, "local").Updates(map[string]interface{}{ + "mysql_name": "remote-" + dbItem.Name, + }).Error; err != nil { + fmt.Println(err) + } + if err := tx.Debug().Model(&model.Database{}).Where("name = ?", dbItem.Name).Updates(map[string]interface{}{ + "name": "remote-" + dbItem.Name, + }).Error; err != nil { + fmt.Println(err) } } - return &model.Database{} + return database } diff --git a/backend/utils/mysql/client/info.go b/backend/utils/mysql/client/info.go index 955b8190d..4e48bdd9f 100644 --- a/backend/utils/mysql/client/info.go +++ b/backend/utils/mysql/client/info.go @@ -79,6 +79,7 @@ type RecoverInfo struct { type SyncDBInfo struct { Name string `json:"name"` From string `json:"from"` + MysqlName string `json:"mysqlName"` Format string `json:"format"` Username string `json:"username"` Password string `json:"password"` diff --git a/backend/utils/mysql/client/local.go b/backend/utils/mysql/client/local.go index 44007ecaa..187a90079 100644 --- a/backend/utils/mysql/client/local.go +++ b/backend/utils/mysql/client/local.go @@ -273,9 +273,10 @@ func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) { continue } dataItem := SyncDBInfo{ - Name: parts[0], - From: "local", - Format: parts[1], + Name: parts[0], + From: "local", + MysqlName: r.Database, + Format: parts[1], } userLines, err := r.ExecSQLForRows(fmt.Sprintf("select user,host from mysql.db where db = '%s'", parts[0]), 300) if err != nil { diff --git a/backend/utils/mysql/client/remote.go b/backend/utils/mysql/client/remote.go index cde552d6b..062ea3534 100644 --- a/backend/utils/mysql/client/remote.go +++ b/backend/utils/mysql/client/remote.go @@ -283,9 +283,10 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) { continue } dataItem := SyncDBInfo{ - Name: dbName, - From: "remote", - Format: charsetName, + Name: dbName, + From: "remote", + MysqlName: r.Database, + Format: charsetName, } userRows, err := r.Client.Query("select user,host from mysql.db where db = ?", dbName) if err != nil { diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index c5ff0f006..6dbf5e4c3 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -3740,7 +3740,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.OperationWithNameAndType" } } ], @@ -4322,7 +4322,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.MysqlLoadDB" } } ], @@ -4685,7 +4685,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.OperationWithNameAndType" } } ], @@ -4757,7 +4757,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.OperationWithNameAndType" } } ], @@ -4793,7 +4793,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.OperationWithNameAndType" } } ], @@ -11900,14 +11900,14 @@ const docTemplate = `{ "dto.ChangeDBInfo": { "type": "object", "required": [ - "databaseID", + "database", "from", "type", "value" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "from": { "type": "string", @@ -13543,21 +13543,29 @@ const docTemplate = `{ "dto.MysqlConfUpdateByFile": { "type": "object", "required": [ - "databaseID" + "database", + "type" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "file": { "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] } } }, "dto.MysqlDBCreate": { "type": "object", "required": [ - "databaseID", + "database", "format", "from", "name", @@ -13566,8 +13574,8 @@ const docTemplate = `{ "username" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "description": { "type": "string" @@ -13605,9 +13613,14 @@ const docTemplate = `{ "dto.MysqlDBDelete": { "type": "object", "required": [ - "id" + "database", + "id", + "type" ], "properties": { + "database": { + "type": "string" + }, "deleteBackup": { "type": "boolean" }, @@ -13616,34 +13629,49 @@ const docTemplate = `{ }, "id": { "type": "integer" + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] } } }, "dto.MysqlDBDeleteCheck": { "type": "object", "required": [ - "databaseID", - "id" + "database", + "id", + "type" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "id": { "type": "integer" + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] } } }, "dto.MysqlDBSearch": { "type": "object", "required": [ - "databaseID", + "database", "page", "pageSize" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "info": { "type": "string" @@ -13662,14 +13690,38 @@ const docTemplate = `{ } } }, - "dto.MysqlOption": { + "dto.MysqlLoadDB": { "type": "object", + "required": [ + "database", + "from", + "type" + ], "properties": { "database": { "type": "string" }, - "databaseID": { - "type": "integer" + "from": { + "type": "string", + "enum": [ + "local", + "remote" + ] + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] + } + } + }, + "dto.MysqlOption": { + "type": "object", + "properties": { + "database": { + "type": "string" }, "from": { "type": "string" @@ -13857,11 +13909,19 @@ const docTemplate = `{ "dto.MysqlVariablesUpdate": { "type": "object", "required": [ - "databaseID" + "database", + "type" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] }, "variables": { "type": "array", @@ -17628,6 +17688,9 @@ const docTemplate = `{ }, "end": { "type": "boolean" + }, + "path": { + "type": "string" } } }, diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 192bd2a52..61c0b82c0 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -3733,7 +3733,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.OperationWithNameAndType" } } ], @@ -4315,7 +4315,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.MysqlLoadDB" } } ], @@ -4678,7 +4678,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.OperationWithNameAndType" } } ], @@ -4750,7 +4750,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.OperationWithNameAndType" } } ], @@ -4786,7 +4786,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.OperateByID" + "$ref": "#/definitions/dto.OperationWithNameAndType" } } ], @@ -11893,14 +11893,14 @@ "dto.ChangeDBInfo": { "type": "object", "required": [ - "databaseID", + "database", "from", "type", "value" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "from": { "type": "string", @@ -13536,21 +13536,29 @@ "dto.MysqlConfUpdateByFile": { "type": "object", "required": [ - "databaseID" + "database", + "type" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "file": { "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] } } }, "dto.MysqlDBCreate": { "type": "object", "required": [ - "databaseID", + "database", "format", "from", "name", @@ -13559,8 +13567,8 @@ "username" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "description": { "type": "string" @@ -13598,9 +13606,14 @@ "dto.MysqlDBDelete": { "type": "object", "required": [ - "id" + "database", + "id", + "type" ], "properties": { + "database": { + "type": "string" + }, "deleteBackup": { "type": "boolean" }, @@ -13609,34 +13622,49 @@ }, "id": { "type": "integer" + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] } } }, "dto.MysqlDBDeleteCheck": { "type": "object", "required": [ - "databaseID", - "id" + "database", + "id", + "type" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "id": { "type": "integer" + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] } } }, "dto.MysqlDBSearch": { "type": "object", "required": [ - "databaseID", + "database", "page", "pageSize" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" }, "info": { "type": "string" @@ -13655,14 +13683,38 @@ } } }, - "dto.MysqlOption": { + "dto.MysqlLoadDB": { "type": "object", + "required": [ + "database", + "from", + "type" + ], "properties": { "database": { "type": "string" }, - "databaseID": { - "type": "integer" + "from": { + "type": "string", + "enum": [ + "local", + "remote" + ] + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] + } + } + }, + "dto.MysqlOption": { + "type": "object", + "properties": { + "database": { + "type": "string" }, "from": { "type": "string" @@ -13850,11 +13902,19 @@ "dto.MysqlVariablesUpdate": { "type": "object", "required": [ - "databaseID" + "database", + "type" ], "properties": { - "databaseID": { - "type": "integer" + "database": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "mysql", + "mariadb" + ] }, "variables": { "type": "array", @@ -17621,6 +17681,9 @@ }, "end": { "type": "boolean" + }, + "path": { + "type": "string" } } }, diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 74180bfe1..d45279445 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -131,8 +131,8 @@ definitions: type: object dto.ChangeDBInfo: properties: - databaseID: - type: integer + database: + type: string from: enum: - local @@ -148,7 +148,7 @@ definitions: value: type: string required: - - databaseID + - database - from - type - value @@ -1241,17 +1241,23 @@ definitions: type: object dto.MysqlConfUpdateByFile: properties: - databaseID: - type: integer + database: + type: string file: type: string + type: + enum: + - mysql + - mariadb + type: string required: - - databaseID + - database + - type type: object dto.MysqlDBCreate: properties: - databaseID: - type: integer + database: + type: string description: type: string format: @@ -1275,7 +1281,7 @@ definitions: username: type: string required: - - databaseID + - database - format - from - name @@ -1285,29 +1291,44 @@ definitions: type: object dto.MysqlDBDelete: properties: + database: + type: string deleteBackup: type: boolean forceDelete: type: boolean id: type: integer + type: + enum: + - mysql + - mariadb + type: string required: + - database - id + - type type: object dto.MysqlDBDeleteCheck: properties: - databaseID: - type: integer + database: + type: string id: type: integer + type: + enum: + - mysql + - mariadb + type: string required: - - databaseID + - database - id + - type type: object dto.MysqlDBSearch: properties: - databaseID: - type: integer + database: + type: string info: type: string order: @@ -1319,16 +1340,33 @@ definitions: pageSize: type: integer required: - - databaseID + - database - page - pageSize type: object + dto.MysqlLoadDB: + properties: + database: + type: string + from: + enum: + - local + - remote + type: string + type: + enum: + - mysql + - mariadb + type: string + required: + - database + - from + - type + type: object dto.MysqlOption: properties: database: type: string - databaseID: - type: integer from: type: string id: @@ -1452,14 +1490,20 @@ definitions: type: object dto.MysqlVariablesUpdate: properties: - databaseID: - type: integer + database: + type: string + type: + enum: + - mysql + - mariadb + type: string variables: items: $ref: '#/definitions/dto.MysqlVariablesUpdateHelper' type: array required: - - databaseID + - database + - type type: object dto.MysqlVariablesUpdateHelper: properties: @@ -3972,6 +4016,8 @@ definitions: type: boolean end: type: boolean + path: + type: string type: object response.WebsiteNginxConfig: properties: @@ -6368,7 +6414,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/dto.OperateByID' + $ref: '#/definitions/dto.OperationWithNameAndType' responses: "200": description: OK @@ -6739,7 +6785,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/dto.OperateByID' + $ref: '#/definitions/dto.MysqlLoadDB' responses: {} security: - ApiKeyAuth: [] @@ -6966,7 +7012,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/dto.OperateByID' + $ref: '#/definitions/dto.OperationWithNameAndType' responses: "200": description: OK @@ -7010,7 +7056,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/dto.OperateByID' + $ref: '#/definitions/dto.OperationWithNameAndType' responses: "200": description: OK @@ -7032,7 +7078,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/dto.OperateByID' + $ref: '#/definitions/dto.OperationWithNameAndType' responses: "200": description: OK diff --git a/frontend/src/api/interface/database.ts b/frontend/src/api/interface/database.ts index 6a1117aa6..c94203187 100644 --- a/frontend/src/api/interface/database.ts +++ b/frontend/src/api/interface/database.ts @@ -1,17 +1,23 @@ +import { ReqPage } from '.'; + export namespace Database { export interface SearchDBWithPage { info: string; - databaseID: number; + database: string; page: number; pageSize: number; orderBy?: string; order?: string; } + export interface SearchBackupRecord extends ReqPage { + mysqlName: string; + dbName: string; + } export interface MysqlDBInfo { id: number; createdAt: Date; name: string; - databaseID: number; + mysqlName: string; from: string; format: string; username: string; @@ -28,25 +34,34 @@ export namespace Database { containerName: string; } export interface MysqlConfUpdateByFile { - databaseID: number; + type: string; + database: string; file: string; } export interface MysqlDBCreate { name: string; from: string; - databaseID: number; + database: string; format: string; username: string; password: string; permission: string; description: string; } + export interface MysqlLoadDB { + from: string; + type: string; + database: string; + } export interface MysqlDBDeleteCheck { id: number; - databaseID: number; + type: string; + database: string; } export interface MysqlDBDelete { id: number; + type: string; + database: string; forceDelete: boolean; deleteBackup: boolean; } @@ -71,7 +86,8 @@ export namespace Database { long_query_time: number; } export interface VariablesUpdate { - databaseID: number; + type: string; + database: string; variables: Array; } export interface VariablesUpdateHelper { @@ -119,7 +135,6 @@ export namespace Database { id: number; from: string; type: string; - databaseID: number; database: string; name: string; } @@ -127,7 +142,7 @@ export namespace Database { id: number; from: string; type: string; - databaseID: number; + database: string; value: string; } diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts index f613ff718..363c308d8 100644 --- a/frontend/src/api/modules/database.ts +++ b/frontend/src/api/modules/database.ts @@ -19,6 +19,9 @@ export const addMysqlDB = (params: Database.MysqlDBCreate) => { } return http.post(`/databases`, request); }; +export const loadDBFromRemote = (params: Database.MysqlLoadDB) => { + return http.post(`/databases/load`, params); +}; export const updateMysqlAccess = (params: Database.ChangeInfo) => { return http.post(`/databases/change/access`, params); }; @@ -45,20 +48,17 @@ export const deleteMysqlDB = (params: Database.MysqlDBDelete) => { return http.post(`/databases/del`, params); }; -export const loadDBFromRemote = (id: number) => { - return http.post(`/databases/load`, { id: id }); -}; -export const loadMysqlBaseInfo = (id: number) => { - return http.post(`/databases/baseinfo`, { id: id }); +export const loadMysqlBaseInfo = (type: string, database: string) => { + return http.post(`/databases/baseinfo`, { type: type, name: database }); }; -export const loadMysqlVariables = (id: number) => { - return http.post(`/databases/variables`, { id: id }); +export const loadMysqlVariables = (type: string, database: string) => { + return http.post(`/databases/variables`, { type: type, name: database }); }; -export const loadMysqlStatus = (id: number) => { - return http.post(`/databases/status`, { id: id }); +export const loadMysqlStatus = (type: string, database: string) => { + return http.post(`/databases/status`, { type: type, name: database }); }; -export const loadRemoteAccess = (id: number) => { - return http.post(`/databases/remote`, { id: id }); +export const loadRemoteAccess = (type: string, database: string) => { + return http.post(`/databases/remote`, { type: type, name: database }); }; export const loadDBOptions = () => { return http.get>(`/databases/options`); diff --git a/frontend/src/components/app-status/index.vue b/frontend/src/components/app-status/index.vue index dfc7909ab..952a4fccd 100644 --- a/frontend/src/components/app-status/index.vue +++ b/frontend/src/components/app-status/index.vue @@ -50,7 +50,7 @@ -
+