1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-03-16 18:54:43 +08:00

fix: 调整计划任务备份账号字段名 (#3691)

This commit is contained in:
ssongliu 2024-01-25 11:20:42 +08:00 committed by GitHub
parent edd6b52f05
commit 45394598d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 175 additions and 225 deletions

View File

@ -7,18 +7,19 @@ type CronjobCreate struct {
Type string `json:"type" validate:"required"` Type string `json:"type" validate:"required"`
Spec string `json:"spec" validate:"required"` Spec string `json:"spec" validate:"required"`
Script string `json:"script"` Script string `json:"script"`
ContainerName string `json:"containerName"` ContainerName string `json:"containerName"`
AppID string `json:"appID"` AppID string `json:"appID"`
Website string `json:"website"` Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"` ExclusionRules string `json:"exclusionRules"`
DBType string `json:"dbType"` DBType string `json:"dbType"`
DBName string `json:"dbName"` DBName string `json:"dbName"`
URL string `json:"url"` URL string `json:"url"`
SourceDir string `json:"sourceDir"` SourceDir string `json:"sourceDir"`
TargetDirID int `json:"targetDirID"`
TargetAccountIDs string `json:"targetAccountIDs"` BackupAccounts string `json:"backupAccounts"`
RetainCopies int `json:"retainCopies" validate:"number,min=1"` DefaultDownload string `json:"defaultDownload"`
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
} }
type CronjobUpdate struct { type CronjobUpdate struct {
@ -26,18 +27,19 @@ type CronjobUpdate struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Spec string `json:"spec" validate:"required"` Spec string `json:"spec" validate:"required"`
Script string `json:"script"` Script string `json:"script"`
ContainerName string `json:"containerName"` ContainerName string `json:"containerName"`
AppID string `json:"appID"` AppID string `json:"appID"`
Website string `json:"website"` Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"` ExclusionRules string `json:"exclusionRules"`
DBType string `json:"dbType"` DBType string `json:"dbType"`
DBName string `json:"dbName"` DBName string `json:"dbName"`
URL string `json:"url"` URL string `json:"url"`
SourceDir string `json:"sourceDir"` SourceDir string `json:"sourceDir"`
TargetDirID int `json:"targetDirID"`
TargetAccountIDs string `json:"targetAccountIDs"` BackupAccounts string `json:"backupAccounts"`
RetainCopies int `json:"retainCopies" validate:"number,min=1"` DefaultDownload string `json:"defaultDownload"`
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
} }
type CronjobUpdateStatus struct { type CronjobUpdateStatus struct {
@ -66,20 +68,18 @@ type CronjobInfo struct {
Type string `json:"type"` Type string `json:"type"`
Spec string `json:"spec"` Spec string `json:"spec"`
Script string `json:"script"` Script string `json:"script"`
ContainerName string `json:"containerName"` ContainerName string `json:"containerName"`
AppID string `json:"appID"` AppID string `json:"appID"`
Website string `json:"website"` Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"` ExclusionRules string `json:"exclusionRules"`
DBType string `json:"dbType"` DBType string `json:"dbType"`
DBName string `json:"dbName"` DBName string `json:"dbName"`
URL string `json:"url"` URL string `json:"url"`
SourceDir string `json:"sourceDir"` SourceDir string `json:"sourceDir"`
TargetDir string `json:"targetDir"` BackupAccounts string `json:"backupAccounts"`
TargetDirID int `json:"targetDirID"` DefaultDownload string `json:"defaultDownload"`
TargetAccounts string `json:"targetAccounts"` RetainCopies int `json:"retainCopies"`
TargetAccountIDs string `json:"targetAccountIDs"`
RetainCopies int `json:"retainCopies"`
LastRecordTime string `json:"lastRecordTime"` LastRecordTime string `json:"lastRecordTime"`
Status string `json:"status"` Status string `json:"status"`

View File

@ -19,10 +19,13 @@ type Cronjob struct {
SourceDir string `gorm:"type:varchar(256)" json:"sourceDir"` SourceDir string `gorm:"type:varchar(256)" json:"sourceDir"`
ExclusionRules string `gorm:"longtext" json:"exclusionRules"` ExclusionRules string `gorm:"longtext" json:"exclusionRules"`
KeepLocal bool `gorm:"type:varchar(64)" json:"keepLocal"` // 已废弃
TargetDirID uint64 `gorm:"type:decimal" json:"targetDirID"` KeepLocal bool `gorm:"type:varchar(64)" json:"keepLocal"`
TargetAccountIDs string `gorm:"type:varchar(64)" json:"targetAccountIDs"` TargetDirID uint64 `gorm:"type:decimal" json:"targetDirID"`
RetainCopies uint64 `gorm:"type:decimal" json:"retainCopies"`
BackupAccounts string `gorm:"type:varchar(64)" json:"backupAccounts"`
DefaultDownload string `gorm:"type:varchar(64)" json:"defaultDownload"`
RetainCopies uint64 `gorm:"type:decimal" json:"retainCopies"`
Status string `gorm:"type:varchar(64)" json:"status"` Status string `gorm:"type:varchar(64)" json:"status"`
EntryIDs string `gorm:"type:varchar(64)" json:"entryIDs"` EntryIDs string `gorm:"type:varchar(64)" json:"entryIDs"`

View File

@ -20,7 +20,7 @@ type ICronjobRepo interface {
Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error) Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error)
Create(cronjob *model.Cronjob) error Create(cronjob *model.Cronjob) error
WithByJobID(id int) DBOption WithByJobID(id int) DBOption
WithByBackupID(id uint) DBOption WithByDefaultDownload(account string) DBOption
WithByRecordDropID(id int) DBOption WithByRecordDropID(id int) DBOption
WithByRecordFile(file string) DBOption WithByRecordFile(file string) DBOption
Save(id uint, cronjob model.Cronjob) error Save(id uint, cronjob model.Cronjob) error
@ -117,9 +117,9 @@ func (c *CronjobRepo) WithByJobID(id int) DBOption {
} }
} }
func (c *CronjobRepo) WithByBackupID(id uint) DBOption { func (c *CronjobRepo) WithByDefaultDownload(account string) DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("target_dir_id = ?", id) return g.Where("default_download = ?", account)
} }
} }

View File

@ -290,7 +290,7 @@ func (u *BackupService) Delete(id uint) error {
if backup.Type == constant.OneDrive { if backup.Type == constant.OneDrive {
global.Cron.Remove(global.OneDriveCronID) global.Cron.Remove(global.OneDriveCronID)
} }
cronjobs, _ := cronjobRepo.List(cronjobRepo.WithByBackupID(id)) cronjobs, _ := cronjobRepo.List(cronjobRepo.WithByDefaultDownload(backup.Type))
if len(cronjobs) != 0 { if len(cronjobs) != 0 {
return buserr.New(constant.ErrBackupInUsed) return buserr.New(constant.ErrBackupInUsed)
} }

View File

@ -34,7 +34,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
itemDir := fmt.Sprintf("website/%s", req.Name) itemDir := fmt.Sprintf("website/%s", req.Name)
backupDir := path.Join(localDir, itemDir) backupDir := path.Join(localDir, itemDir)
fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow) fileName := fmt.Sprintf("%s_%s.tar.gz", website.PrimaryDomain, timeNow)
if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil { if err := handleWebsiteBackup(&website, backupDir, fileName, ""); err != nil {
return err return err
} }
@ -106,7 +106,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
isOk := false isOk := false
if !isRollback { if !isRollback {
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405"))) rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405")))
if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile)); err != nil { if err := handleWebsiteBackup(website, path.Dir(rollbackFile), path.Base(rollbackFile), ""); err != nil {
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err) return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
} }
defer func() { defer func() {
@ -181,7 +181,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
return nil return nil
} }
func handleWebsiteBackup(website *model.Website, backupDir, fileName string) error { func handleWebsiteBackup(website *model.Website, backupDir, fileName, exclusionRules string) error {
fileOp := files.NewFileOp() fileOp := files.NewFileOp()
tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", "")) tmpDir := fmt.Sprintf("%s/%s", backupDir, strings.ReplaceAll(fileName, ".tar.gz", ""))
if !fileOp.Stat(tmpDir) { if !fileOp.Stat(tmpDir) {
@ -233,11 +233,11 @@ func handleWebsiteBackup(website *model.Website, backupDir, fileName string) err
} }
websiteDir := fmt.Sprintf("%s/openresty/%s/www/sites/%s", constant.AppInstallDir, nginxInfo.Name, website.Alias) websiteDir := fmt.Sprintf("%s/openresty/%s/www/sites/%s", constant.AppInstallDir, nginxInfo.Name, website.Alias)
if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), ""); err != nil { if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.Alias), exclusionRules); err != nil {
return err return err
} }
global.LOG.Info("put web.tar.gz into tmp dir successful, now start to tar tmp dir") global.LOG.Info("put web.tar.gz into tmp dir successful, now start to tar tmp dir")
if err := handleTar(tmpDir, backupDir, fileName, ""); err != nil { if err := handleTar(tmpDir, backupDir, fileName, exclusionRules); err != nil {
return err return err
} }

View File

@ -43,32 +43,11 @@ func NewICronjobService() ICronjobService {
func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) { func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order)) total, cronjobs, err := cronjobRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info), commonRepo.WithOrderRuleBy(search.OrderBy, search.Order))
var dtoCronjobs []dto.CronjobInfo var dtoCronjobs []dto.CronjobInfo
accounts, _ := backupRepo.List()
for _, cronjob := range cronjobs { for _, cronjob := range cronjobs {
var item dto.CronjobInfo var item dto.CronjobInfo
if err := copier.Copy(&item, &cronjob); err != nil { if err := copier.Copy(&item, &cronjob); err != nil {
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
} }
if hasBackup(item.Type) {
for _, account := range accounts {
if int(account.ID) == item.TargetDirID {
item.TargetDir = account.Type
}
}
itemAccounts := strings.Split(item.TargetAccountIDs, ",")
var targetAccounts []string
for _, itemAccount := range itemAccounts {
for _, account := range accounts {
if itemAccount == fmt.Sprintf("%d", account.ID) {
targetAccounts = append(targetAccounts, account.Type)
break
}
}
}
item.TargetAccounts = strings.Join(targetAccounts, ",")
} else {
item.TargetDir = "-"
}
record, _ := cronjobRepo.RecordFirst(cronjob.ID) record, _ := cronjobRepo.RecordFirst(cronjob.ID)
if record.ID != 0 { if record.ID != 0 {
item.LastRecordTime = record.StartTime.Format("2006-01-02 15:04:05") item.LastRecordTime = record.StartTime.Format("2006-01-02 15:04:05")
@ -120,7 +99,7 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
} }
if req.CleanData { if req.CleanData {
if hasBackup(cronjob.Type) { if hasBackup(cronjob.Type) {
accountMap, err := u.loadClientMap(cronjob.TargetAccountIDs) accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil { if err != nil {
return err return err
} }
@ -294,8 +273,9 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
upMap["db_name"] = req.DBName upMap["db_name"] = req.DBName
upMap["url"] = req.URL upMap["url"] = req.URL
upMap["source_dir"] = req.SourceDir upMap["source_dir"] = req.SourceDir
upMap["target_dir_id"] = req.TargetDirID
upMap["target_account_ids"] = req.TargetAccountIDs upMap["backup_accounts"] = req.BackupAccounts
upMap["default_download"] = req.DefaultDownload
upMap["retain_copies"] = req.RetainCopies upMap["retain_copies"] = req.RetainCopies
return cronjobRepo.Update(id, upMap) return cronjobRepo.Update(id, upMap)
} }

View File

@ -26,7 +26,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
} }
apps = append(apps, app) apps = append(apps, app)
} }
accountMap, err := u.loadClientMap(cronjob.TargetAccountIDs) accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil { if err != nil {
return err return err
} }
@ -59,7 +59,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Time) error { func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Time) error {
webs := loadWebsForJob(cronjob) webs := loadWebsForJob(cronjob)
accountMap, err := u.loadClientMap(cronjob.TargetAccountIDs) accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil { if err != nil {
return err return err
} }
@ -73,7 +73,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
record.Source, record.BackupType = loadRecordPath(cronjob, accountMap) record.Source, record.BackupType = loadRecordPath(cronjob, accountMap)
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain)) backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s", web.PrimaryDomain))
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format("20060102150405")) record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format("20060102150405"))
if err := handleWebsiteBackup(&web, backupDir, record.FileName); err != nil { if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules); err != nil {
return err return err
} }
downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName)) downloadPath, err := u.uploadCronjobBackFile(cronjob, accountMap, path.Join(backupDir, record.FileName))
@ -92,7 +92,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Time) error { func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Time) error {
dbs := loadDbsForJob(cronjob) dbs := loadDbsForJob(cronjob)
accountMap, err := u.loadClientMap(cronjob.TargetAccountIDs) accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil { if err != nil {
return err return err
} }
@ -132,7 +132,7 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
} }
func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.Time) error { func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.Time) error {
accountMap, err := u.loadClientMap(cronjob.TargetAccountIDs) accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil { if err != nil {
return err return err
} }
@ -163,7 +163,7 @@ func (u *CronjobService) handleDirectory(cronjob model.Cronjob, startTime time.T
} }
func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.Time) error { func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.Time) error {
accountMap, err := u.loadClientMap(cronjob.TargetAccountIDs) accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil { if err != nil {
return err return err
} }
@ -194,7 +194,7 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
} }
func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Time, logPath string) error { func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Time, logPath string) error {
accountMap, err := u.loadClientMap(cronjob.TargetAccountIDs) accountMap, err := loadClientMap(cronjob.BackupAccounts)
if err != nil { if err != nil {
return err return err
} }
@ -288,8 +288,8 @@ func loadWebsForJob(cronjob model.Cronjob) []model.Website {
} }
func loadRecordPath(cronjob model.Cronjob, accountMap map[string]cronjobUploadHelper) (string, string) { func loadRecordPath(cronjob model.Cronjob, accountMap map[string]cronjobUploadHelper) (string, string) {
source := accountMap[fmt.Sprintf("%v", cronjob.TargetDirID)].backType source := accountMap[fmt.Sprintf("%v", cronjob.DefaultDownload)].backType
targets := strings.Split(cronjob.TargetAccountIDs, ",") targets := strings.Split(cronjob.BackupAccounts, ",")
var itemAccounts []string var itemAccounts []string
for _, target := range targets { for _, target := range targets {
if len(target) == 0 { if len(target) == 0 {

View File

@ -247,19 +247,19 @@ func (u *CronjobService) handleSystemClean() (string, error) {
return NewIDeviceService().CleanForCronjob() return NewIDeviceService().CleanForCronjob()
} }
func (u *CronjobService) loadClientMap(targetAccountIDs string) (map[string]cronjobUploadHelper, error) { func loadClientMap(backupAccounts string) (map[string]cronjobUploadHelper, error) {
clients := make(map[string]cronjobUploadHelper) clients := make(map[string]cronjobUploadHelper)
accounts, err := backupRepo.List() accounts, err := backupRepo.List()
if err != nil { if err != nil {
return nil, err return nil, err
} }
targets := strings.Split(targetAccountIDs, ",") targets := strings.Split(backupAccounts, ",")
for _, target := range targets { for _, target := range targets {
if len(target) == 0 { if len(target) == 0 {
continue continue
} }
for _, account := range accounts { for _, account := range accounts {
if target == fmt.Sprintf("%v", account.ID) { if target == account.Type {
client, err := NewIBackupService().NewClient(&account) client, err := NewIBackupService().NewClient(&account)
if err != nil { if err != nil {
return nil, err return nil, err
@ -286,11 +286,11 @@ func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, accountMap
defer func() { defer func() {
_ = os.Remove(file) _ = os.Remove(file)
}() }()
targets := strings.Split(cronjob.TargetAccountIDs, ",") accounts := strings.Split(cronjob.BackupAccounts, ",")
cloudSrc := strings.TrimPrefix(file, global.CONF.System.TmpDir+"/") cloudSrc := strings.TrimPrefix(file, global.CONF.System.TmpDir+"/")
for _, target := range targets { for _, account := range accounts {
if len(target) != 0 { if len(account) != 0 {
if _, err := accountMap[target].client.Upload(file, path.Join(accountMap[target].backupPath, cloudSrc)); err != nil { if _, err := accountMap[account].client.Upload(file, path.Join(accountMap[account].backupPath, cloudSrc)); err != nil {
return "", err return "", err
} }
} }
@ -314,18 +314,18 @@ func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap m
return return
} }
for i := int(cronjob.RetainCopies); i < len(records); i++ { for i := int(cronjob.RetainCopies); i < len(records); i++ {
targets := strings.Split(cronjob.TargetAccountIDs, ",") accounts := strings.Split(cronjob.BackupAccounts, ",")
if cronjob.Type == "snapshot" { if cronjob.Type == "snapshot" {
for _, target := range targets { for _, account := range accounts {
if len(target) != 0 { if len(account) != 0 {
_, _ = accountMap[target].client.Delete(path.Join(accountMap[target].backupPath, "system_snapshot", records[i].FileName)) _, _ = accountMap[account].client.Delete(path.Join(accountMap[account].backupPath, "system_snapshot", records[i].FileName))
} }
} }
_ = snapshotRepo.Delete(commonRepo.WithByName(strings.TrimSuffix(records[i].FileName, ".tar.gz"))) _ = snapshotRepo.Delete(commonRepo.WithByName(strings.TrimSuffix(records[i].FileName, ".tar.gz")))
} else { } else {
for _, target := range targets { for _, account := range accounts {
if len(target) != 0 { if len(account) != 0 {
_, _ = accountMap[target].client.Delete(path.Join(accountMap[target].backupPath, records[i].FileDir, records[i].FileName)) _, _ = accountMap[account].client.Delete(path.Join(accountMap[account].backupPath, records[i].FileDir, records[i].FileName))
} }
} }
} }

View File

@ -489,11 +489,12 @@ func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto
rootDir = path.Join(localDir, "system", name) rootDir = path.Join(localDir, "system", name)
snap = model.Snapshot{ snap = model.Snapshot{
Name: name, Name: name,
Description: req.Description, Description: req.Description,
From: req.From, From: req.From,
Version: versionItem.Value, DefaultDownload: req.DefaultDownload,
Status: constant.StatusWaiting, Version: versionItem.Value,
Status: constant.StatusWaiting,
} }
_ = snapshotRepo.Create(&snap) _ = snapshotRepo.Create(&snap)
snapStatus.SnapID = snap.ID snapStatus.SnapID = snap.ID
@ -577,18 +578,21 @@ func (u *SnapshotService) HandleSnapshot(isCronjob bool, logPath string, req dto
loadLogByStatus(snapStatus, logPath) loadLogByStatus(snapStatus, logPath)
return snap.Name, fmt.Errorf("snapshot %s backup failed", snap.Name) return snap.Name, fmt.Errorf("snapshot %s backup failed", snap.Name)
} }
loadLogByStatus(snapStatus, logPath)
snapPanelData(itemHelper, localDir, backupPanelDir) snapPanelData(itemHelper, localDir, backupPanelDir)
if snapStatus.PanelData != constant.StatusDone { if snapStatus.PanelData != constant.StatusDone {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed}) _ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
loadLogByStatus(snapStatus, logPath) loadLogByStatus(snapStatus, logPath)
return snap.Name, fmt.Errorf("snapshot %s 1panel data failed", snap.Name) return snap.Name, fmt.Errorf("snapshot %s 1panel data failed", snap.Name)
} }
loadLogByStatus(snapStatus, logPath)
snapCompress(itemHelper, rootDir) snapCompress(itemHelper, rootDir)
if snapStatus.Compress != constant.StatusDone { if snapStatus.Compress != constant.StatusDone {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed}) _ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
loadLogByStatus(snapStatus, logPath) loadLogByStatus(snapStatus, logPath)
return snap.Name, fmt.Errorf("snapshot %s compress failed", snap.Name) return snap.Name, fmt.Errorf("snapshot %s compress failed", snap.Name)
} }
loadLogByStatus(snapStatus, logPath)
snapUpload(itemHelper, req.From, fmt.Sprintf("%s.tar.gz", rootDir)) snapUpload(itemHelper, req.From, fmt.Sprintf("%s.tar.gz", rootDir))
if snapStatus.Upload != constant.StatusDone { if snapStatus.Upload != constant.StatusDone {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed}) _ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})

View File

@ -183,7 +183,7 @@ func snapUpload(snap snapHelper, accounts string, file string) {
}() }()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": constant.StatusUploading}) _ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": constant.StatusUploading})
accountMap, err := loadClientMapForSnapshot(accounts) accountMap, err := loadClientMap(accounts)
if err != nil { if err != nil {
snap.Status.Upload = err.Error() snap.Status.Upload = err.Error()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": err.Error()}) _ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": err.Error()})
@ -237,32 +237,3 @@ func checkPointOfWal() {
global.LOG.Errorf("handle check point failed, err: %v", err) global.LOG.Errorf("handle check point failed, err: %v", err)
} }
} }
func loadClientMapForSnapshot(from string) (map[string]cronjobUploadHelper, error) {
clients := make(map[string]cronjobUploadHelper)
accounts, err := backupRepo.List()
if err != nil {
return nil, err
}
targets := strings.Split(from, ",")
for _, target := range targets {
if len(target) == 0 {
continue
}
for _, account := range accounts {
if target == fmt.Sprintf("%v", account.ID) {
client, err := NewIBackupService().NewClient(&account)
if err != nil {
return nil, err
}
pathItem := account.BackupPath
clients[target] = cronjobUploadHelper{
client: client,
backupPath: pathItem,
backType: account.Type,
}
}
}
}
return clients, nil
}

View File

@ -271,31 +271,22 @@ var UpdateCronjobSpec = &gormigrate.Migration{
var ( var (
jobs []model.Cronjob jobs []model.Cronjob
backupAccounts []model.BackupAccount backupAccounts []model.BackupAccount
localAccountID uint
) )
mapAccount := make(map[uint]string) mapAccount := make(map[uint]string)
mapAccountName := make(map[string]model.BackupAccount)
if err := tx.Find(&jobs).Error; err != nil { if err := tx.Find(&jobs).Error; err != nil {
return err return err
} }
_ = tx.Find(&backupAccounts).Error _ = tx.Find(&backupAccounts).Error
for _, item := range backupAccounts { for _, item := range backupAccounts {
mapAccount[item.ID] = item.Type mapAccount[item.ID] = item.Type
mapAccountName[item.Type] = item
if item.Type == constant.Local {
localAccountID = item.ID
}
}
if localAccountID == 0 {
return errors.New("local backup account is unset!")
} }
for _, job := range jobs { for _, job := range jobs {
if job.KeepLocal { if job.KeepLocal {
if err := tx.Model(&model.Cronjob{}). if err := tx.Model(&model.Cronjob{}).
Where("id = ?", job.ID). Where("id = ?", job.ID).
Updates(map[string]interface{}{ Updates(map[string]interface{}{
"target_account_ids": fmt.Sprintf("%v,%v", job.TargetDirID, localAccountID), "backup_accounts": fmt.Sprintf("%v,%v", mapAccount[uint(job.TargetDirID)], constant.Local),
"target_dir_id": localAccountID, "default_download": constant.Local,
}).Error; err != nil { }).Error; err != nil {
return err return err
} }
@ -303,7 +294,8 @@ var UpdateCronjobSpec = &gormigrate.Migration{
if err := tx.Model(&model.Cronjob{}). if err := tx.Model(&model.Cronjob{}).
Where("id = ?", job.ID). Where("id = ?", job.ID).
Updates(map[string]interface{}{ Updates(map[string]interface{}{
"target_account_ids": job.TargetDirID, "backup_accounts": mapAccount[uint(job.TargetDirID)],
"default_download": mapAccount[uint(job.TargetDirID)],
}).Error; err != nil { }).Error; err != nil {
return err return err
} }

View File

@ -14958,6 +14958,9 @@ const docTemplate = `{
"appID": { "appID": {
"type": "string" "type": "string"
}, },
"backupAccounts": {
"type": "string"
},
"containerName": { "containerName": {
"type": "string" "type": "string"
}, },
@ -14967,6 +14970,9 @@ const docTemplate = `{
"dbType": { "dbType": {
"type": "string" "type": "string"
}, },
"defaultDownload": {
"type": "string"
},
"exclusionRules": { "exclusionRules": {
"type": "string" "type": "string"
}, },
@ -14986,12 +14992,6 @@ const docTemplate = `{
"spec": { "spec": {
"type": "string" "type": "string"
}, },
"targetAccountIDs": {
"type": "string"
},
"targetDirID": {
"type": "integer"
},
"type": { "type": {
"type": "string" "type": "string"
}, },
@ -15029,6 +15029,9 @@ const docTemplate = `{
"appID": { "appID": {
"type": "string" "type": "string"
}, },
"backupAccounts": {
"type": "string"
},
"containerName": { "containerName": {
"type": "string" "type": "string"
}, },
@ -15038,6 +15041,9 @@ const docTemplate = `{
"dbType": { "dbType": {
"type": "string" "type": "string"
}, },
"defaultDownload": {
"type": "string"
},
"exclusionRules": { "exclusionRules": {
"type": "string" "type": "string"
}, },
@ -15060,12 +15066,6 @@ const docTemplate = `{
"spec": { "spec": {
"type": "string" "type": "string"
}, },
"targetAccountIDs": {
"type": "string"
},
"targetDirID": {
"type": "integer"
},
"url": { "url": {
"type": "string" "type": "string"
}, },
@ -17892,9 +17892,13 @@ const docTemplate = `{
"dto.SnapshotCreate": { "dto.SnapshotCreate": {
"type": "object", "type": "object",
"required": [ "required": [
"defaultDownload",
"from" "from"
], ],
"properties": { "properties": {
"defaultDownload": {
"type": "string"
},
"description": { "description": {
"type": "string", "type": "string",
"maxLength": 256 "maxLength": 256

View File

@ -14951,6 +14951,9 @@
"appID": { "appID": {
"type": "string" "type": "string"
}, },
"backupAccounts": {
"type": "string"
},
"containerName": { "containerName": {
"type": "string" "type": "string"
}, },
@ -14960,6 +14963,9 @@
"dbType": { "dbType": {
"type": "string" "type": "string"
}, },
"defaultDownload": {
"type": "string"
},
"exclusionRules": { "exclusionRules": {
"type": "string" "type": "string"
}, },
@ -14979,12 +14985,6 @@
"spec": { "spec": {
"type": "string" "type": "string"
}, },
"targetAccountIDs": {
"type": "string"
},
"targetDirID": {
"type": "integer"
},
"type": { "type": {
"type": "string" "type": "string"
}, },
@ -15022,6 +15022,9 @@
"appID": { "appID": {
"type": "string" "type": "string"
}, },
"backupAccounts": {
"type": "string"
},
"containerName": { "containerName": {
"type": "string" "type": "string"
}, },
@ -15031,6 +15034,9 @@
"dbType": { "dbType": {
"type": "string" "type": "string"
}, },
"defaultDownload": {
"type": "string"
},
"exclusionRules": { "exclusionRules": {
"type": "string" "type": "string"
}, },
@ -15053,12 +15059,6 @@
"spec": { "spec": {
"type": "string" "type": "string"
}, },
"targetAccountIDs": {
"type": "string"
},
"targetDirID": {
"type": "integer"
},
"url": { "url": {
"type": "string" "type": "string"
}, },
@ -17885,9 +17885,13 @@
"dto.SnapshotCreate": { "dto.SnapshotCreate": {
"type": "object", "type": "object",
"required": [ "required": [
"defaultDownload",
"from" "from"
], ],
"properties": { "properties": {
"defaultDownload": {
"type": "string"
},
"description": { "description": {
"type": "string", "type": "string",
"maxLength": 256 "maxLength": 256

View File

@ -580,12 +580,16 @@ definitions:
properties: properties:
appID: appID:
type: string type: string
backupAccounts:
type: string
containerName: containerName:
type: string type: string
dbName: dbName:
type: string type: string
dbType: dbType:
type: string type: string
defaultDownload:
type: string
exclusionRules: exclusionRules:
type: string type: string
name: name:
@ -599,10 +603,6 @@ definitions:
type: string type: string
spec: spec:
type: string type: string
targetAccountIDs:
type: string
targetDirID:
type: integer
type: type:
type: string type: string
url: url:
@ -628,12 +628,16 @@ definitions:
properties: properties:
appID: appID:
type: string type: string
backupAccounts:
type: string
containerName: containerName:
type: string type: string
dbName: dbName:
type: string type: string
dbType: dbType:
type: string type: string
defaultDownload:
type: string
exclusionRules: exclusionRules:
type: string type: string
id: id:
@ -649,10 +653,6 @@ definitions:
type: string type: string
spec: spec:
type: string type: string
targetAccountIDs:
type: string
targetDirID:
type: integer
url: url:
type: string type: string
website: website:
@ -2564,6 +2564,8 @@ definitions:
type: object type: object
dto.SnapshotCreate: dto.SnapshotCreate:
properties: properties:
defaultDownload:
type: string
description: description:
maxLength: 256 maxLength: 256
type: string type: string
@ -2572,6 +2574,7 @@ definitions:
id: id:
type: integer type: integer
required: required:
- defaultDownload
- from - from
type: object type: object
dto.SnapshotImport: dto.SnapshotImport:

View File

@ -18,9 +18,10 @@ export namespace Cronjob {
dbName: string; dbName: string;
url: string; url: string;
sourceDir: string; sourceDir: string;
targetDirID: number;
targetAccountIDs: string; backupAccounts: string;
targetAccountIDList: Array<number>; defaultDownload: string;
backupAccountList: Array<string>;
retainCopies: number; retainCopies: number;
status: string; status: string;
} }
@ -37,8 +38,9 @@ export namespace Cronjob {
dbName: string; dbName: string;
url: string; url: string;
sourceDir: string; sourceDir: string;
targetDirID: number;
targetAccountIDs: string; backupAccounts: string;
defaultDownload: string;
retainCopies: number; retainCopies: number;
} }
export interface SpecObj { export interface SpecObj {
@ -60,8 +62,9 @@ export namespace Cronjob {
dbName: string; dbName: string;
url: string; url: string;
sourceDir: string; sourceDir: string;
targetDirID: number;
targetAccountIDs: string; backupAccounts: string;
defaultDownload: string;
retainCopies: number; retainCopies: number;
} }
export interface CronjobDelete { export interface CronjobDelete {

View File

@ -113,12 +113,12 @@
{{ row.lastRecordTime }} {{ row.lastRecordTime }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :min-width="80" :label="$t('cronjob.target')" prop="targetDir"> <el-table-column :min-width="80" :label="$t('cronjob.target')" prop="defaultDownload">
<template #default="{ row }"> <template #default="{ row }">
<div v-for="(item, index) of row.targetAccounts.split(',')" :key="index" class="mt-1"> <div v-for="(item, index) of row.backupAccounts.split(',')" :key="index" class="mt-1">
<div v-if="row.accountExpand || (!row.accountExpand && index < 3)"> <div v-if="row.accountExpand || (!row.accountExpand && index < 3)">
<el-tag v-if="row.targetAccounts"> <el-tag v-if="row.backupAccounts">
<span v-if="item === row.targetDir"> <span v-if="item === row.defaultDownload">
<el-icon><Star /></el-icon> <el-icon><Star /></el-icon>
{{ $t('setting.' + item) }} {{ $t('setting.' + item) }}
</span> </span>
@ -129,12 +129,12 @@
<span v-else>-</span> <span v-else>-</span>
</div> </div>
</div> </div>
<div v-if="!row.accountExpand && row.targetAccounts.split(',').length > 3"> <div v-if="!row.accountExpand && row.backupAccounts.split(',').length > 3">
<el-button type="primary" link @click="row.accountExpand = true"> <el-button type="primary" link @click="row.accountExpand = true">
{{ $t('commons.button.expand') }}... {{ $t('commons.button.expand') }}...
</el-button> </el-button>
</div> </div>
<div v-if="row.accountExpand && row.targetAccounts.split(',').length > 3"> <div v-if="row.accountExpand && row.backupAccounts.split(',').length > 3">
<el-button type="primary" link @click="row.accountExpand = false"> <el-button type="primary" link @click="row.accountExpand = false">
{{ $t('commons.button.collapse') }} {{ $t('commons.button.collapse') }}
</el-button> </el-button>
@ -221,16 +221,16 @@ const search = async (column?: any) => {
loading.value = false; loading.value = false;
data.value = res.data.items || []; data.value = res.data.items || [];
for (const item of data.value) { for (const item of data.value) {
item.targetAccounts = item.targetAccounts.split(',') || []; let itemAccounts = item.backupAccounts.split(',') || [];
let accounts = []; let accounts = [];
for (const account of item.targetAccounts) { for (const account of itemAccounts) {
if (account == item.targetDir) { if (account == item.defaultDownload) {
accounts.unshift(account); accounts.unshift(account);
} else { } else {
accounts.push(account); accounts.push(account);
} }
} }
item.targetAccounts = accounts.join(','); item.itemAccounts = accounts.join(',');
} }
paginationConfig.total = res.data.total; paginationConfig.total = res.data.total;
}) })

View File

@ -141,12 +141,7 @@
</el-form-item> </el-form-item>
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script"> <el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
<el-input <el-input clearable type="textarea" :rows="4" v-model="dialogData.rowData!.script" />
clearable
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
v-model="dialogData.rowData!.script"
/>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -240,11 +235,11 @@
</el-form-item> </el-form-item>
<div v-if="isBackup()"> <div v-if="isBackup()">
<el-form-item :label="$t('cronjob.target')" prop="targetAccountIDList"> <el-form-item :label="$t('cronjob.target')" prop="backupAccountList">
<el-select <el-select
multiple multiple
class="selectClass" class="selectClass"
v-model="dialogData.rowData!.targetAccountIDList" v-model="dialogData.rowData!.backupAccountList"
@change="changeAccount" @change="changeAccount"
> >
<div v-for="item in backupOptions" :key="item.label"> <div v-for="item in backupOptions" :key="item.label">
@ -263,8 +258,8 @@
</el-link> </el-link>
</span> </span>
</el-form-item> </el-form-item>
<el-form-item :label="$t('cronjob.default_download_path')" prop="targetDirID"> <el-form-item :label="$t('cronjob.default_download_path')" prop="defaultDownload">
<el-select class="selectClass" v-model="dialogData.rowData!.targetDirID"> <el-select class="selectClass" v-model="dialogData.rowData!.defaultDownload">
<div v-for="item in accountOptions" :key="item.label"> <div v-for="item in accountOptions" :key="item.label">
<el-option :value="item.value" :label="item.label" /> <el-option :value="item.value" :label="item.label" />
</div> </div>
@ -288,14 +283,14 @@
</el-form-item> </el-form-item>
<el-form-item <el-form-item
v-if="dialogData.rowData!.type === 'directory'" v-if="dialogData.rowData!.type === 'directory' || dialogData.rowData!.type === 'website'"
:label="$t('cronjob.exclusionRules')" :label="$t('cronjob.exclusionRules')"
prop="exclusionRules" prop="exclusionRules"
> >
<el-input <el-input
type="textarea" type="textarea"
:placeholder="$t('cronjob.rulesHelper')" :placeholder="$t('cronjob.rulesHelper')"
:autosize="{ minRows: 3, maxRows: 6 }" :rows="4"
clearable clearable
v-model="dialogData.rowData!.exclusionRules" v-model="dialogData.rowData!.exclusionRules"
/> />
@ -358,12 +353,8 @@ const acceptParams = (params: DialogProps): void => {
changeType(); changeType();
dialogData.value.rowData.dbType = 'mysql'; dialogData.value.rowData.dbType = 'mysql';
} }
if (dialogData.value.rowData.targetAccountIDs) { if (dialogData.value.rowData.backupAccounts) {
dialogData.value.rowData.targetAccountIDList = []; dialogData.value.rowData.backupAccountList = dialogData.value.rowData.backupAccounts.split(',');
let ids = dialogData.value.rowData.targetAccountIDs.split(',');
for (const id of ids) {
dialogData.value.rowData.targetAccountIDList.push(Number(id));
}
} }
title.value = i18n.global.t('cronjob.' + dialogData.value.title); title.value = i18n.global.t('cronjob.' + dialogData.value.title);
if (dialogData.value?.rowData?.exclusionRules) { if (dialogData.value?.rowData?.exclusionRules) {
@ -393,8 +384,6 @@ const handleClose = () => {
drawerVisible.value = false; drawerVisible.value = false;
}; };
const localDirID = ref();
const containerOptions = ref([]); const containerOptions = ref([]);
const websiteOptions = ref([]); const websiteOptions = ref([]);
const backupOptions = ref([]); const backupOptions = ref([]);
@ -464,8 +453,8 @@ const rules = reactive({
dbName: [Rules.requiredSelect], dbName: [Rules.requiredSelect],
url: [Rules.requiredInput], url: [Rules.requiredInput],
sourceDir: [Rules.requiredInput], sourceDir: [Rules.requiredInput],
targetAccountIDList: [Rules.requiredSelect], backupAccounts: [Rules.requiredSelect],
targetDirID: [Rules.requiredSelect, Rules.number], defaultDownload: [Rules.requiredSelect],
retainCopies: [Rules.number], retainCopies: [Rules.number],
}); });
@ -511,17 +500,14 @@ const handleSpecDelete = (index: number) => {
const loadBackups = async () => { const loadBackups = async () => {
const res = await getBackupList(); const res = await getBackupList();
backupOptions.value = []; backupOptions.value = [];
if (!dialogData.value.rowData!.backupAccountList) {
dialogData.value.rowData!.backupAccountList = ['LOCAL'];
}
for (const item of res.data) { for (const item of res.data) {
if (item.id === 0) { if (item.id === 0) {
continue; continue;
} }
if (item.type === 'LOCAL') { backupOptions.value.push({ label: i18n.global.t('setting.' + item.type), value: item.type });
localDirID.value = item.id;
if (!dialogData.value.rowData!.targetAccountIDList) {
dialogData.value.rowData!.targetAccountIDList = [item.id];
}
}
backupOptions.value.push({ label: i18n.global.t('setting.' + item.type), value: item.id });
} }
changeAccount(); changeAccount();
}; };
@ -530,7 +516,7 @@ const changeAccount = async () => {
accountOptions.value = []; accountOptions.value = [];
for (const item of backupOptions.value) { for (const item of backupOptions.value) {
let exit = false; let exit = false;
for (const ac of dialogData.value.rowData.targetAccountIDList) { for (const ac of dialogData.value.rowData.backupAccountList) {
if (item.value == ac) { if (item.value == ac) {
exit = true; exit = true;
break; break;
@ -586,7 +572,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
} }
specs.push(itemSpec); specs.push(itemSpec);
} }
dialogData.value.rowData.targetAccountIDs = dialogData.value.rowData.targetAccountIDList.join(','); dialogData.value.rowData.backupAccounts = dialogData.value.rowData.backupAccountList.join(',');
dialogData.value.rowData.spec = specs.join(','); dialogData.value.rowData.spec = specs.join(',');
if (!formEl) return; if (!formEl) return;
formEl.validate(async (valid) => { formEl.validate(async (valid) => {