diff --git a/backend/app/api/v1/backup.go b/backend/app/api/v1/backup.go index e3da49673..620dd09a9 100644 --- a/backend/app/api/v1/backup.go +++ b/backend/app/api/v1/backup.go @@ -2,6 +2,8 @@ package v1 import ( "encoding/base64" + "fmt" + "path" "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "github.com/1Panel-dev/1Panel/backend/app/dto" @@ -356,6 +358,14 @@ func (b *BaseApi) Recover(c *gin.Context) { return } + if req.Source != "LOCAL" { + downloadPath, err := backupService.DownloadRecord(dto.DownloadRecord{Source: req.Source, FileDir: path.Dir(req.File), FileName: path.Base(req.File)}) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("download file failed, err: %v", err)) + return + } + req.File = downloadPath + } switch req.Type { case "mysql": if err := backupService.MysqlRecover(req); err != nil { diff --git a/backend/app/dto/backup.go b/backend/app/dto/backup.go index a180d1586..e26c4a7cb 100644 --- a/backend/app/dto/backup.go +++ b/backend/app/dto/backup.go @@ -36,6 +36,7 @@ type CommonBackup struct { DetailName string `json:"detailName"` } type CommonRecover struct { + Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO"` Type string `json:"type" validate:"required,oneof=app mysql redis website"` Name string `json:"name"` DetailName string `json:"detailName"` diff --git a/backend/app/service/backup.go b/backend/app/service/backup.go index 3b2d62346..5337b7980 100644 --- a/backend/app/service/backup.go +++ b/backend/app/service/backup.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "os" + "path" "strings" "github.com/1Panel-dev/1Panel/backend/app/dto" @@ -109,15 +110,15 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error) if err != nil { return "", fmt.Errorf("new cloud storage client failed, err: %v", err) } - tempPath := fmt.Sprintf("%sdownload%s", constant.DataDir, info.FileDir) - if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) { - if err = os.MkdirAll(tempPath, os.ModePerm); err != nil { - global.LOG.Errorf("mkdir %s failed, err: %v", tempPath, err) + targetPath := fmt.Sprintf("%s/download/%s/%s", constant.DataDir, info.FileDir, info.FileName) + if _, err := os.Stat(path.Base(targetPath)); err != nil && os.IsNotExist(err) { + if err = os.MkdirAll(path.Base(targetPath), os.ModePerm); err != nil { + global.LOG.Errorf("mkdir %s failed, err: %v", path.Base(targetPath), err) } } - targetPath := tempPath + info.FileName - if _, err = os.Stat(targetPath); err != nil && os.IsNotExist(err) { - isOK, err := backClient.Download(info.FileName, targetPath) + srcPath := fmt.Sprintf("%s/%s", info.FileDir, info.FileName) + if exist, _ := backClient.Exist(srcPath); exist { + isOK, err := backClient.Download(srcPath, targetPath) if !isOK { return "", fmt.Errorf("cloud storage download failed, err: %v", err) } @@ -179,7 +180,7 @@ func (u *BackupService) BatchDeleteRecord(ids []uint) error { global.LOG.Errorf("remove file %s failed, err: %v", record.FileDir+record.FileName, err) } } else { - backupAccount, err := backupRepo.Get(commonRepo.WithByName(record.Source)) + backupAccount, err := backupRepo.Get(commonRepo.WithByType(record.Source)) if err != nil { return err } diff --git a/backend/utils/cloud_storage/client/cos.go b/backend/utils/cloud_storage/client/cos.go index 232099d61..cd615ca5b 100644 --- a/backend/utils/cloud_storage/client/cos.go +++ b/backend/utils/cloud_storage/client/cos.go @@ -67,10 +67,11 @@ func (cos cosClient) Exist(path string) (bool, error) { if err != nil { return false, err } - if _, err := client.Object.IsExist(context.Background(), path); err != nil { - return true, err + exist, err := client.Object.IsExist(context.Background(), path) + if err != nil { + return false, err } - return false, nil + return exist, nil } func (cos cosClient) Delete(path string) (bool, error) { diff --git a/backend/utils/cloud_storage/client/kodo.go b/backend/utils/cloud_storage/client/kodo.go index 4aba74c08..599404b7d 100644 --- a/backend/utils/cloud_storage/client/kodo.go +++ b/backend/utils/cloud_storage/client/kodo.go @@ -59,9 +59,9 @@ func (kodo kodoClient) Exist(path string) (bool, error) { return false, err } if _, err := kodo.client.Stat(bucket, path); err != nil { - return true, err + return false, err } - return false, nil + return true, nil } func (kodo kodoClient) Delete(path string) (bool, error) { diff --git a/backend/utils/cloud_storage/client/minio.go b/backend/utils/cloud_storage/client/minio.go index e0b21de35..dacf4ef76 100644 --- a/backend/utils/cloud_storage/client/minio.go +++ b/backend/utils/cloud_storage/client/minio.go @@ -81,9 +81,9 @@ func (minIo minIoClient) Exist(path string) (bool, error) { if _, ok := minIo.Vars["bucket"]; ok { _, err := minIo.client.GetObject(context.Background(), minIo.Vars["bucket"].(string), path, minio.GetObjectOptions{}) if err != nil { - return true, err + return false, err } - return false, nil + return true, nil } else { return false, constant.ErrInvalidParams } diff --git a/backend/utils/cloud_storage/client/minio_test.go b/backend/utils/cloud_storage/client/minio_test.go deleted file mode 100644 index 4ef469939..000000000 --- a/backend/utils/cloud_storage/client/minio_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package client - -import ( - "encoding/json" - "fmt" - "testing" - - "github.com/1Panel-dev/1Panel/backend/app/model" - "github.com/1Panel-dev/1Panel/backend/constant" - "github.com/1Panel-dev/1Panel/backend/global" - "github.com/1Panel-dev/1Panel/backend/init/db" - "github.com/1Panel-dev/1Panel/backend/init/log" - "github.com/1Panel-dev/1Panel/backend/init/viper" -) - -func TestMinio(t *testing.T) { - viper.Init() - log.Init() - db.Init() - - var backup model.BackupAccount - if err := global.DB.Where("id = ?", 3).First(&backup).Error; err != nil { - fmt.Println(err) - } - - varMap := make(map[string]interface{}) - if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil { - fmt.Println(err) - } - varMap["type"] = backup.Type - varMap["bucket"] = backup.Bucket - switch backup.Type { - case constant.Sftp: - varMap["password"] = backup.Credential - case constant.OSS, constant.S3, constant.MinIo: - varMap["secretKey"] = backup.Credential - } - client, _ := NewMinIoClient(varMap) - _, _ = client.ListObjects("directory/directory-test-minio/") -} diff --git a/frontend/src/api/interface/backup.ts b/frontend/src/api/interface/backup.ts index 8e4417d0e..6ee755ed3 100644 --- a/frontend/src/api/interface/backup.ts +++ b/frontend/src/api/interface/backup.ts @@ -49,6 +49,7 @@ export namespace Backup { detailName: string; } export interface Recover { + source: string; type: string; name: string; detailName: string; diff --git a/frontend/src/components/backup/index.vue b/frontend/src/components/backup/index.vue index 0a4098a71..4d73709f5 100644 --- a/frontend/src/components/backup/index.vue +++ b/frontend/src/components/backup/index.vue @@ -124,6 +124,7 @@ const onBackup = async () => { const onRecover = async (row: Backup.RecordInfo) => { let params = { + source: row.source, type: type.value, name: name.value, detailName: detailName.value,