fix: Fix the backup account synchronization exception (#8083)

This commit is contained in:
ssongliu 2025-03-06 16:25:05 +08:00 committed by GitHub
parent 9c238ce7aa
commit b13302775e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 91 additions and 33 deletions

View file

@ -17,7 +17,7 @@ func (b *BaseApi) CheckBackupUsed(c *gin.Context) {
return
}
if err := backupService.CheckUsed(name); err != nil {
if err := backupService.CheckUsed(name, true); err != nil {
helper.BadRequest(c, err)
return
}

View file

@ -68,13 +68,13 @@ func WithByDetailName(detailName string) DBOption {
func WithByType(tp string) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("type = ?", tp)
return g.Where("`type` = ?", tp)
}
}
func WithTypes(types []string) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("type in (?)", types)
return db.Where("`type` in (?)", types)
}
}

View file

@ -28,7 +28,7 @@ import (
type BackupService struct{}
type IBackupService interface {
CheckUsed(name string) error
CheckUsed(name string, isPublic bool) error
Sync(req dto.SyncFromMaster) error
LoadBackupOptions() ([]dto.BackupOption, error)
@ -152,7 +152,7 @@ func (u *BackupService) Create(req dto.BackupOperate) error {
return err
}
}
if req.Type != "LOCAL" {
if req.Type != constant.Local {
isOk, err := u.checkBackupConn(&backup)
if err != nil || !isOk {
return buserr.WithMap("ErrBackupCheck", map[string]interface{}{"err": err.Error()}, err)
@ -212,6 +212,9 @@ func (u *BackupService) Delete(id uint) error {
if backup.Type == constant.Local {
return buserr.New("ErrBackupLocalDelete")
}
if err := u.CheckUsed(backup.Name, false); err != nil {
return err
}
return backupRepo.Delete(repo.WithByID(id))
}
@ -238,15 +241,8 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
}
newBackup.Credential = string(itemCredential)
if backup.Type == constant.Local {
if newBackup.Vars != backup.Vars {
oldPath := backup.BackupPath
newPath := newBackup.BackupPath
if strings.HasSuffix(newPath, "/") && newPath != "/" {
newPath = newPath[:strings.LastIndex(newPath, "/")]
}
if err := files.NewFileOp().CopyDir(oldPath, newPath); err != nil {
return err
}
if err := changeLocalBackup(backup.BackupPath, newBackup.BackupPath); err != nil {
return err
}
}
@ -255,7 +251,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
return err
}
}
if backup.Type != "LOCAL" {
if backup.Type != constant.Local {
isOk, err := u.checkBackupConn(&newBackup)
if err != nil || !isOk {
return buserr.WithMap("ErrBackupCheck", map[string]interface{}{"err": err.Error()}, err)
@ -271,6 +267,8 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
return err
}
newBackup.ID = backup.ID
newBackup.CreatedAt = backup.CreatedAt
newBackup.UpdatedAt = backup.UpdatedAt
if err := backupRepo.Save(&newBackup); err != nil {
return err
}
@ -372,6 +370,8 @@ func (u *BackupService) Sync(req dto.SyncFromMaster) error {
return buserr.New("ErrRecordNotFound")
}
accountItem.ID = account.ID
accountItem.CreatedAt = account.CreatedAt
accountItem.UpdatedAt = account.UpdatedAt
return backupRepo.Save(&accountItem)
default:
return fmt.Errorf("not support such operation %s", req.Operation)
@ -394,8 +394,8 @@ func (u *BackupService) LoadBackupOptions() ([]dto.BackupOption, error) {
return data, nil
}
func (u *BackupService) CheckUsed(name string) error {
account, _ := backupRepo.Get(repo.WithByName(name), backupRepo.WithByPublic(true))
func (u *BackupService) CheckUsed(name string, isPublic bool) error {
account, _ := backupRepo.Get(repo.WithByName(name), backupRepo.WithByPublic(isPublic))
if account.ID == 0 {
return nil
}
@ -542,3 +542,38 @@ func loadBackupNamesByID(accountIDs string, downloadID uint) ([]string, string,
}
return accounts, downloadAccount, nil
}
func changeLocalBackup(oldPath, newPath string) error {
fileOp := files.NewFileOp()
if fileOp.Stat(path.Join(oldPath, "app")) {
if err := fileOp.Mv(path.Join(oldPath, "app"), newPath); err != nil {
return err
}
}
if fileOp.Stat(path.Join(oldPath, "database")) {
if err := fileOp.Mv(path.Join(oldPath, "database"), newPath); err != nil {
return err
}
}
if fileOp.Stat(path.Join(oldPath, "directory")) {
if err := fileOp.Mv(path.Join(oldPath, "directory"), newPath); err != nil {
return err
}
}
if fileOp.Stat(path.Join(oldPath, "system_snapshot")) {
if err := fileOp.Mv(path.Join(oldPath, "system_snapshot"), newPath); err != nil {
return err
}
}
if fileOp.Stat(path.Join(oldPath, "website")) {
if err := fileOp.CopyDir(path.Join(oldPath, "website"), newPath); err != nil {
return err
}
}
if fileOp.Stat(path.Join(oldPath, "log")) {
if err := fileOp.Mv(path.Join(oldPath, "log"), newPath); err != nil {
return err
}
}
return nil
}

View file

@ -112,7 +112,7 @@ func (u *BackupRecordService) DownloadRecord(info dto.DownloadRecord) (string, e
}
if exist, _ := client.Exist(srcPath); exist {
isOK, err := client.Download(srcPath, targetPath)
if !isOK {
if !isOK || err != nil {
return "", fmt.Errorf("cloud storage download failed, err: %v", err)
}
}

View file

@ -256,7 +256,7 @@ func (u *DeviceService) Clean(req []dto.Clean) {
case "task_log":
pathItem := path.Join(global.Dir.BaseDir, logPath, item.Name)
dropFileOrDir(pathItem)
if len(item.Name) == 0 {
if len(item.Name) != 0 {
_ = taskRepo.Delete(repo.WithByType(item.Name))
}
case "images":

View file

@ -1,7 +1,6 @@
package log
import (
"github.com/1Panel-dev/1Panel/agent/constant"
"log"
"os"
"path"
@ -12,6 +11,7 @@ import (
"time"
"unsafe"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global"
)
@ -85,7 +85,7 @@ func NewWriterFromConfig(c *Config) (RollingWriter, error) {
return nil, err
}
filepath := FilePath(c)
file, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_APPEND, constant.DirPerm)
file, err := os.OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_APPEND, constant.FilePerm)
if err != nil {
return nil, err
}

View file

@ -229,10 +229,12 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
return err
}
newBackup.ID = backup.ID
newBackup.CreatedAt = backup.CreatedAt
newBackup.UpdatedAt = backup.UpdatedAt
if err := backupRepo.Save(&newBackup); err != nil {
return err
}
go syncAccountToAgent(backup, "update")
go syncAccountToAgent(newBackup, "update")
return nil
}

View file

@ -62,7 +62,9 @@ var WebUrlMap = map[string]struct{}{
"/containers/setting": {},
"/containers/dashboard": {},
"/cronjobs": {},
"/cronjobs": {},
"/cronjobs/cronjob": {},
"/cronjobs/library": {},
"/databases": {},
"/databases/mysql": {},
@ -146,7 +148,7 @@ var WebUrlMap = map[string]struct{}{
}
var DynamicRoutes = []string{
`^/containers/container/operate/[^/]+$`,
`^/containers/container/operate/[^?]+$`,
`^/containers/composeDetail/[^/]+$`,
`^/databases/mysql/setting/[^/]+/[^/]+$`,
`^/databases/postgresql/setting/[^/]+/[^/]+$`,

View file

@ -74,9 +74,13 @@
<br />
{{ $t('setting.refreshTime') + ':' + row.varsJson['refresh_time'] }}
</template>
<el-tag @click="refreshItemToken(row)" class="ml-1">
{{ 'Token ' + $t('commons.button.refresh') }}
</el-tag>
<el-button
type="primary"
link
icon="Refresh"
@click="refreshItemToken(row)"
class="ml-1"
/>
</el-tooltip>
</template>
</el-table-column>
@ -279,6 +283,9 @@ const buttons = [
},
{
label: i18n.global.t('commons.button.delete'),
disabled: (row: Backup.BackupInfo) => {
return row.type === 'LOCAL';
},
click: (row: Backup.BackupInfo) => {
onDelete(row);
},

View file

@ -51,7 +51,7 @@
</el-radio-group>
</el-form-item>
<el-form-item v-if="hasAccessKey()" label="Access Key ID" prop="accessKey" :rules="Rules.requiredInput">
<el-input v-model.trim="dialogData.rowData!.accessKey" />
<el-input clearable v-model.trim="dialogData.rowData!.accessKey" />
</el-form-item>
<el-form-item v-if="hasAccessKey()" label="Secret Key" prop="credential" :rules="Rules.requiredInput">
<el-input show-password clearable v-model.trim="dialogData.rowData!.credential" />
@ -85,7 +85,7 @@
</el-form-item>
<div v-if="dialogData.rowData!.type === 'SFTP'">
<el-form-item :label="$t('setting.address')" prop="varsJson.address" :rules="Rules.host">
<el-input v-model.trim="dialogData.rowData!.varsJson['address']" />
<el-input v-model.trim="dialogData.rowData!.varsJson['address']" clearable />
</el-form-item>
<el-form-item :label="$t('commons.table.port')" prop="varsJson.port" :rules="[Rules.port]">
<el-input-number :min="0" :max="65535" v-model.number="dialogData.rowData!.varsJson['port']" />
@ -171,14 +171,14 @@
</template>
</el-input>
</el-form-item>
<el-form-item v-if="hasAccessKey()" label="Bucket" :rules="Rules.requiredInput">
<el-form-item v-if="hasAccessKey()" label="Bucket" prop="bucket" :rules="Rules.requiredInput">
<el-checkbox v-model="dialogData.rowData!.bucketInput" :label="$t('container.input')" />
<el-input clearable v-if="dialogData.rowData!.bucketInput" v-model="dialogData.rowData!.bucket" />
<div v-else class="w-full">
<el-select class="!w-4/5" v-model="dialogData.rowData!.bucket">
<el-option v-for="item in buckets" :key="item" :value="item" />
</el-select>
<el-button class="!w-1/5" plain @click="getBuckets()">
<el-button class="!w-1/5" plain @click="getBuckets(formRef)">
{{ $t('setting.loadBucket') }}
</el-button>
</div>
@ -630,7 +630,15 @@ const handleClose = () => {
drawerVisible.value = false;
};
const getBuckets = async () => {
const getBuckets = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
const result1 = await formEl.validateField('varsJson.endpointItem', callback);
const result2 = await formEl.validateField('accessKey', callback);
const result3 = await formEl.validateField('credential', callback);
const result4 = await formEl.validateField('varsJson.region', callback);
if (!result1 || !result2 || !result3 || !result4) {
return;
}
loading.value = true;
let item = deepCopy(dialogData.value.rowData!.varsJson);
if (dialogData.value.rowData!.type === 'KODO') {
@ -668,7 +676,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
} else {
dialogData.value.rowData!.varsJson['endpoint'] = itemEndpoint;
}
dialogData.value.rowData!.varsJson['endpointItem'] = undefined;
dialogData.value.rowData!.varsJson['endpointItem'] = itemEndpoint;
}
if (isALIYUNYUN()) {
dialogData.value.rowData!.varsJson['token'] = undefined;

View file

@ -642,6 +642,10 @@ function load18n(label: string) {
case 'App':
case 'System':
return i18n.global.t('menu.' + label.toLowerCase());
case 'RuntimeExtension':
return i18n.global.t('website.runtime');
case 'Image':
return i18n.global.t('container.image');
case 'Snapshot':
return i18n.global.t('setting.snapshot');
case 'AppStore':