mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-13 22:20:13 +08:00
parent
684f20a5dc
commit
6a8bd490bf
16 changed files with 328 additions and 279 deletions
|
|
@ -76,14 +76,12 @@ type PortUpdate struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SnapshotStatus struct {
|
type SnapshotStatus struct {
|
||||||
Panel string `json:"panel"`
|
Panel string `json:"panel"`
|
||||||
PanelCtl string `json:"panelCtl"`
|
PanelInfo string `json:"panelInfo"`
|
||||||
PanelService string `json:"panelService"`
|
DaemonJson string `json:"daemonJson"`
|
||||||
PanelInfo string `json:"panelInfo"`
|
AppData string `json:"appData"`
|
||||||
DaemonJson string `json:"daemonJson"`
|
PanelData string `json:"panelData"`
|
||||||
AppData string `json:"appData"`
|
BackupData string `json:"backupData"`
|
||||||
PanelData string `json:"panelData"`
|
|
||||||
BackupData string `json:"backupData"`
|
|
||||||
|
|
||||||
Compress string `json:"compress"`
|
Compress string `json:"compress"`
|
||||||
Upload string `json:"upload"`
|
Upload string `json:"upload"`
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,13 @@ type Snapshot struct {
|
||||||
|
|
||||||
type SnapshotStatus struct {
|
type SnapshotStatus struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
SnapID uint `gorm:"type:decimal" json:"snapID"`
|
SnapID uint `gorm:"type:decimal" json:"snapID"`
|
||||||
Panel string `json:"panel" gorm:"type:varchar(64);default:Running"`
|
Panel string `json:"panel" gorm:"type:varchar(64);default:Running"`
|
||||||
PanelCtl string `json:"panelCtl" gorm:"type:varchar(64);default:Running"`
|
PanelInfo string `json:"panelInfo" gorm:"type:varchar(64);default:Running"`
|
||||||
PanelService string `json:"panelService" gorm:"type:varchar(64);default:Running"`
|
DaemonJson string `json:"daemonJson" gorm:"type:varchar(64);default:Running"`
|
||||||
PanelInfo string `json:"panelInfo" gorm:"type:varchar(64);default:Running"`
|
AppData string `json:"appData" gorm:"type:varchar(64);default:Running"`
|
||||||
DaemonJson string `json:"daemonJson" gorm:"type:varchar(64);default:Running"`
|
PanelData string `json:"panelData" gorm:"type:varchar(64);default:Running"`
|
||||||
AppData string `json:"appData" gorm:"type:varchar(64);default:Running"`
|
BackupData string `json:"backupData" gorm:"type:varchar(64);default:Running"`
|
||||||
PanelData string `json:"panelData" gorm:"type:varchar(64);default:Running"`
|
|
||||||
BackupData string `json:"backupData" gorm:"type:varchar(64);default:Running"`
|
|
||||||
|
|
||||||
Compress string `json:"compress" gorm:"type:varchar(64);default:Waiting"`
|
Compress string `json:"compress" gorm:"type:varchar(64);default:Waiting"`
|
||||||
Upload string `json:"upload" gorm:"type:varchar(64);default:Waiting"`
|
Upload string `json:"upload" gorm:"type:varchar(64);default:Waiting"`
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, inter
|
||||||
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 item.Type == "app" || item.Type == "website" || item.Type == "database" || item.Type == "directory" {
|
if item.Type == "app" || item.Type == "website" || item.Type == "database" || item.Type == "directory" || item.Type == "snapshot" {
|
||||||
backup, _ := backupRepo.Get(commonRepo.WithByID(uint(item.TargetDirID)))
|
backup, _ := backupRepo.Get(commonRepo.WithByID(uint(item.TargetDirID)))
|
||||||
if len(backup.Type) != 0 {
|
if len(backup.Type) != 0 {
|
||||||
item.TargetDir = backup.Type
|
item.TargetDir = backup.Type
|
||||||
|
|
@ -103,7 +103,7 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if req.CleanData && (cronjob.Type == "app" || cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory") {
|
if req.CleanData && (cronjob.Type == "app" || cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory" || cronjob.Type == "snapshot") {
|
||||||
cronjob.RetainCopies = 0
|
cronjob.RetainCopies = 0
|
||||||
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
|
@ -38,6 +39,10 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||||
message, err = u.handleShell(cronjob.Type, cronjob.Name, cronjob.Script)
|
message, err = u.handleShell(cronjob.Type, cronjob.Name, cronjob.Script)
|
||||||
}
|
}
|
||||||
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
|
u.HandleRmExpired("LOCAL", "", "", cronjob, nil)
|
||||||
|
case "snapshot":
|
||||||
|
messageItem := ""
|
||||||
|
messageItem, record.File, err = u.handleSnapshot(cronjob, record.StartTime)
|
||||||
|
message = []byte(messageItem)
|
||||||
case "curl":
|
case "curl":
|
||||||
if len(cronjob.URL) == 0 {
|
if len(cronjob.URL) == 0 {
|
||||||
return
|
return
|
||||||
|
|
@ -60,6 +65,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||||
global.LOG.Errorf("cut website log file failed, err: %v", err)
|
global.LOG.Errorf("cut website log file failed, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
|
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
|
||||||
return
|
return
|
||||||
|
|
@ -83,7 +89,7 @@ func (u *CronjobService) handleShell(cronType, cornName, script string) ([]byte,
|
||||||
}
|
}
|
||||||
stdout, err := cmd.ExecCronjobWithTimeOut(script, handleDir, 24*time.Hour)
|
stdout, err := cmd.ExecCronjobWithTimeOut(script, handleDir, 24*time.Hour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return []byte(stdout), err
|
||||||
}
|
}
|
||||||
return []byte(stdout), nil
|
return []byte(stdout), nil
|
||||||
}
|
}
|
||||||
|
|
@ -187,6 +193,10 @@ func (u *CronjobService) HandleRmExpired(backType, backupPath, localDir string,
|
||||||
fileItem = strings.TrimPrefix(file, localDir+"/")
|
fileItem = strings.TrimPrefix(file, localDir+"/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cronjob.Type == "snapshot" {
|
||||||
|
_ = snapshotRepo.Delete(commonRepo.WithByName(strings.TrimSuffix(path.Base(fileItem), ".tar.gz")))
|
||||||
|
}
|
||||||
_, _ = backClient.Delete(fileItem)
|
_, _ = backClient.Delete(fileItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -222,7 +232,7 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
|
||||||
path = sourceDir
|
path = sourceDir
|
||||||
}
|
}
|
||||||
|
|
||||||
commands := fmt.Sprintf("tar -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
commands := fmt.Sprintf("tar -zcf --warning=no-file-changed --ignore-failed-read %s %s %s", targetDir+"/"+name, excludeRules, path)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour)
|
stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -550,3 +560,27 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.Backu
|
||||||
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client)
|
u.HandleRmExpired(backup.Type, backup.BackupPath, localDir, &cronjob, client)
|
||||||
return paths, nil
|
return paths, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) handleSnapshot(cronjob *model.Cronjob, startTime time.Time) (string, string, error) {
|
||||||
|
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
client, err := NewIBackupService().NewClient(&backup)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
req := dto.SnapshotCreate{
|
||||||
|
From: backup.Type,
|
||||||
|
}
|
||||||
|
message, name, err := NewISnapshotService().HandleSnapshot(true, req, startTime.Format("20060102150405"))
|
||||||
|
if err != nil {
|
||||||
|
return message, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
path := path.Join(strings.TrimPrefix(backup.BackupPath, "/"), "system_snapshot", name+".tar.gz")
|
||||||
|
|
||||||
|
u.HandleRmExpired(backup.Type, backup.BackupPath, "", cronjob, client)
|
||||||
|
return message, path, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ type ISnapshotService interface {
|
||||||
|
|
||||||
UpdateDescription(req dto.UpdateDescription) error
|
UpdateDescription(req dto.UpdateDescription) error
|
||||||
readFromJson(path string) (SnapshotJson, error)
|
readFromJson(path string) (SnapshotJson, error)
|
||||||
|
|
||||||
|
HandleSnapshot(isCronjob bool, req dto.SnapshotCreate, timeNow string) (string, string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewISnapshotService() ISnapshotService {
|
func NewISnapshotService() ISnapshotService {
|
||||||
|
|
@ -128,103 +130,9 @@ type SnapshotJson struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
||||||
localDir, err := loadLocalDir()
|
if _, _, err := u.HandleSnapshot(false, req, time.Now().Format("20060102150405")); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
snap model.Snapshot
|
|
||||||
snapStatus model.SnapshotStatus
|
|
||||||
rootDir string
|
|
||||||
)
|
|
||||||
|
|
||||||
if req.ID == 0 {
|
|
||||||
timeNow := time.Now().Format("20060102150405")
|
|
||||||
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
|
||||||
rootDir = path.Join(localDir, fmt.Sprintf("system/1panel_%s_%s", versionItem.Value, timeNow))
|
|
||||||
|
|
||||||
snap = model.Snapshot{
|
|
||||||
Name: fmt.Sprintf("1panel_%s_%s", versionItem.Value, timeNow),
|
|
||||||
Description: req.Description,
|
|
||||||
From: req.From,
|
|
||||||
Version: versionItem.Value,
|
|
||||||
Status: constant.StatusWaiting,
|
|
||||||
}
|
|
||||||
_ = snapshotRepo.Create(&snap)
|
|
||||||
snapStatus.SnapID = snap.ID
|
|
||||||
_ = snapshotRepo.CreateStatus(&snapStatus)
|
|
||||||
} else {
|
|
||||||
snap, err = snapshotRepo.Get(commonRepo.WithByID(req.ID))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
snapStatus, _ = snapshotRepo.GetStatus(snap.ID)
|
|
||||||
if snapStatus.ID == 0 {
|
|
||||||
snapStatus.SnapID = snap.ID
|
|
||||||
_ = snapshotRepo.CreateStatus(&snapStatus)
|
|
||||||
}
|
|
||||||
rootDir = path.Join(localDir, fmt.Sprintf("system/%s", snap.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
itemHelper := snapHelper{SnapID: snap.ID, Wg: &wg, FileOp: files.NewFileOp(), Ctx: context.Background()}
|
|
||||||
backupPanelDir := path.Join(rootDir, "1panel")
|
|
||||||
_ = os.MkdirAll(backupPanelDir, os.ModePerm)
|
|
||||||
backupDockerDir := path.Join(rootDir, "docker")
|
|
||||||
_ = os.MkdirAll(backupDockerDir, os.ModePerm)
|
|
||||||
|
|
||||||
jsonItem := SnapshotJson{
|
|
||||||
BaseDir: global.CONF.System.BaseDir,
|
|
||||||
BackupDataDir: localDir,
|
|
||||||
PanelDataDir: path.Join(global.CONF.System.BaseDir, "1panel"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if snapStatus.PanelInfo != constant.StatusDone {
|
|
||||||
wg.Add(1)
|
|
||||||
go snapJson(itemHelper, snapStatus.ID, jsonItem, rootDir)
|
|
||||||
}
|
|
||||||
if snapStatus.Panel != constant.StatusDone {
|
|
||||||
wg.Add(1)
|
|
||||||
go snapPanel(itemHelper, snapStatus.ID, backupPanelDir)
|
|
||||||
}
|
|
||||||
if snapStatus.PanelCtl != constant.StatusDone {
|
|
||||||
wg.Add(1)
|
|
||||||
go snapPanelCtl(itemHelper, snapStatus.ID, backupPanelDir)
|
|
||||||
}
|
|
||||||
if snapStatus.PanelService != constant.StatusDone {
|
|
||||||
wg.Add(1)
|
|
||||||
go snapPanelService(itemHelper, snapStatus.ID, backupPanelDir)
|
|
||||||
}
|
|
||||||
if snapStatus.DaemonJson != constant.StatusDone {
|
|
||||||
wg.Add(1)
|
|
||||||
go snapDaemonJson(itemHelper, snapStatus.ID, backupDockerDir)
|
|
||||||
}
|
|
||||||
if snapStatus.AppData != constant.StatusDone {
|
|
||||||
wg.Add(1)
|
|
||||||
go snapAppData(itemHelper, snapStatus.ID, backupDockerDir)
|
|
||||||
}
|
|
||||||
if snapStatus.BackupData != constant.StatusDone {
|
|
||||||
wg.Add(1)
|
|
||||||
go snapBackup(itemHelper, snapStatus.ID, localDir, backupPanelDir)
|
|
||||||
}
|
|
||||||
if snapStatus.PanelData != constant.StatusDone {
|
|
||||||
wg.Add(1)
|
|
||||||
go snapPanelData(itemHelper, snapStatus.ID, localDir, backupPanelDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
if checkIsAllDone(snap.ID) {
|
|
||||||
snapCompress(itemHelper, snapStatus.ID, rootDir)
|
|
||||||
|
|
||||||
snapUpload(req.From, snapStatus.ID, fmt.Sprintf("%s.tar.gz", rootDir))
|
|
||||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusSuccess})
|
|
||||||
} else {
|
|
||||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -559,6 +467,127 @@ func (u *SnapshotService) readFromJson(path string) (SnapshotJson, error) {
|
||||||
return snap, nil
|
return snap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *SnapshotService) HandleSnapshot(isCronjob bool, req dto.SnapshotCreate, timeNow string) (string, string, error) {
|
||||||
|
localDir, err := loadLocalDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
rootDir string
|
||||||
|
snap model.Snapshot
|
||||||
|
snapStatus model.SnapshotStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
if req.ID == 0 {
|
||||||
|
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
||||||
|
name := fmt.Sprintf("1panel_%s_%s", versionItem.Value, timeNow)
|
||||||
|
if isCronjob {
|
||||||
|
name = fmt.Sprintf("snapshot_1panel_%s_%s", versionItem.Value, timeNow)
|
||||||
|
}
|
||||||
|
rootDir = path.Join(localDir, "system", name)
|
||||||
|
|
||||||
|
snap = model.Snapshot{
|
||||||
|
Name: name,
|
||||||
|
Description: req.Description,
|
||||||
|
From: req.From,
|
||||||
|
Version: versionItem.Value,
|
||||||
|
Status: constant.StatusWaiting,
|
||||||
|
}
|
||||||
|
_ = snapshotRepo.Create(&snap)
|
||||||
|
snapStatus.SnapID = snap.ID
|
||||||
|
_ = snapshotRepo.CreateStatus(&snapStatus)
|
||||||
|
} else {
|
||||||
|
snap, err = snapshotRepo.Get(commonRepo.WithByID(req.ID))
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
snapStatus, _ = snapshotRepo.GetStatus(snap.ID)
|
||||||
|
if snapStatus.ID == 0 {
|
||||||
|
snapStatus.SnapID = snap.ID
|
||||||
|
_ = snapshotRepo.CreateStatus(&snapStatus)
|
||||||
|
}
|
||||||
|
rootDir = path.Join(localDir, fmt.Sprintf("system/%s", snap.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
itemHelper := snapHelper{SnapID: snap.ID, Status: &snapStatus, Wg: &wg, FileOp: files.NewFileOp(), Ctx: context.Background()}
|
||||||
|
backupPanelDir := path.Join(rootDir, "1panel")
|
||||||
|
_ = os.MkdirAll(backupPanelDir, os.ModePerm)
|
||||||
|
backupDockerDir := path.Join(rootDir, "docker")
|
||||||
|
_ = os.MkdirAll(backupDockerDir, os.ModePerm)
|
||||||
|
|
||||||
|
jsonItem := SnapshotJson{
|
||||||
|
BaseDir: global.CONF.System.BaseDir,
|
||||||
|
BackupDataDir: localDir,
|
||||||
|
PanelDataDir: path.Join(global.CONF.System.BaseDir, "1panel"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if snapStatus.PanelInfo != constant.StatusDone {
|
||||||
|
wg.Add(1)
|
||||||
|
go snapJson(itemHelper, jsonItem, rootDir)
|
||||||
|
}
|
||||||
|
if snapStatus.Panel != constant.StatusDone {
|
||||||
|
wg.Add(1)
|
||||||
|
go snapPanel(itemHelper, backupPanelDir)
|
||||||
|
}
|
||||||
|
if snapStatus.DaemonJson != constant.StatusDone {
|
||||||
|
wg.Add(1)
|
||||||
|
go snapDaemonJson(itemHelper, backupDockerDir)
|
||||||
|
}
|
||||||
|
if snapStatus.AppData != constant.StatusDone {
|
||||||
|
wg.Add(1)
|
||||||
|
go snapAppData(itemHelper, backupDockerDir)
|
||||||
|
}
|
||||||
|
if snapStatus.BackupData != constant.StatusDone {
|
||||||
|
wg.Add(1)
|
||||||
|
go snapBackup(itemHelper, localDir, backupPanelDir)
|
||||||
|
}
|
||||||
|
if snapStatus.PanelData != constant.StatusDone {
|
||||||
|
wg.Add(1)
|
||||||
|
go snapPanelData(itemHelper, localDir, backupPanelDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isCronjob {
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
if !checkIsAllDone(snap.ID) {
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
snapCompress(itemHelper, rootDir)
|
||||||
|
if snapStatus.Compress != constant.StatusDone {
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
snapUpload(itemHelper, req.From, fmt.Sprintf("%s.tar.gz", rootDir))
|
||||||
|
if snapStatus.Upload != constant.StatusDone {
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||||
|
}()
|
||||||
|
return "", "", nil
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
if !checkIsAllDone(snap.ID) {
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
||||||
|
return loadLogByStatus(snapStatus), snap.Name, fmt.Errorf("snapshot %s backup failed", snap.Name)
|
||||||
|
}
|
||||||
|
snapCompress(itemHelper, rootDir)
|
||||||
|
if snapStatus.Compress != constant.StatusDone {
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
||||||
|
return loadLogByStatus(snapStatus), snap.Name, fmt.Errorf("snapshot %s compress failed", snap.Name)
|
||||||
|
}
|
||||||
|
snapUpload(itemHelper, req.From, fmt.Sprintf("%s.tar.gz", rootDir))
|
||||||
|
if snapStatus.Upload != constant.StatusDone {
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed})
|
||||||
|
return loadLogByStatus(snapStatus), snap.Name, fmt.Errorf("snapshot %s upload failed", snap.Name)
|
||||||
|
}
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||||
|
return loadLogByStatus(snapStatus), snap.Name, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *SnapshotService) handleDockerDatas(fileOp files.FileOp, operation string, source, target string) error {
|
func (u *SnapshotService) handleDockerDatas(fileOp files.FileOp, operation string, source, target string) error {
|
||||||
switch operation {
|
switch operation {
|
||||||
case "snapshot":
|
case "snapshot":
|
||||||
|
|
@ -644,7 +673,7 @@ func (u *SnapshotService) handlePanelBinary(fileOp files.FileOp, operation strin
|
||||||
if _, err := os.Stat(panelPath); err != nil {
|
if _, err := os.Stat(panelPath); err != nil {
|
||||||
return fmt.Errorf("1panel binary is not found in %s, err: %v", panelPath, err)
|
return fmt.Errorf("1panel binary is not found in %s, err: %v", panelPath, err)
|
||||||
} else {
|
} else {
|
||||||
if err := cpBinary(panelPath, target); err != nil {
|
if err := cpBinary([]string{panelPath}, target); err != nil {
|
||||||
return fmt.Errorf("backup 1panel binary failed, err: %v", err)
|
return fmt.Errorf("backup 1panel binary failed, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -653,7 +682,7 @@ func (u *SnapshotService) handlePanelBinary(fileOp files.FileOp, operation strin
|
||||||
if _, err := os.Stat(source); err != nil {
|
if _, err := os.Stat(source); err != nil {
|
||||||
return fmt.Errorf("1panel binary is not found in snapshot, err: %v", err)
|
return fmt.Errorf("1panel binary is not found in snapshot, err: %v", err)
|
||||||
} else {
|
} else {
|
||||||
if err := cpBinary(source, "/usr/local/bin/1panel"); err != nil {
|
if err := cpBinary([]string{source}, "/usr/local/bin/1panel"); err != nil {
|
||||||
return fmt.Errorf("recover 1panel binary failed, err: %v", err)
|
return fmt.Errorf("recover 1panel binary failed, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -668,7 +697,7 @@ func (u *SnapshotService) handlePanelctlBinary(fileOp files.FileOp, operation st
|
||||||
if _, err := os.Stat(panelctlPath); err != nil {
|
if _, err := os.Stat(panelctlPath); err != nil {
|
||||||
return fmt.Errorf("1pctl binary is not found in %s, err: %v", panelctlPath, err)
|
return fmt.Errorf("1pctl binary is not found in %s, err: %v", panelctlPath, err)
|
||||||
} else {
|
} else {
|
||||||
if err := cpBinary(panelctlPath, target); err != nil {
|
if err := cpBinary([]string{panelctlPath}, target); err != nil {
|
||||||
return fmt.Errorf("backup 1pctl binary failed, err: %v", err)
|
return fmt.Errorf("backup 1pctl binary failed, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -677,7 +706,7 @@ func (u *SnapshotService) handlePanelctlBinary(fileOp files.FileOp, operation st
|
||||||
if _, err := os.Stat(source); err != nil {
|
if _, err := os.Stat(source); err != nil {
|
||||||
return fmt.Errorf("1pctl binary is not found in snapshot, err: %v", err)
|
return fmt.Errorf("1pctl binary is not found in snapshot, err: %v", err)
|
||||||
} else {
|
} else {
|
||||||
if err := cpBinary(source, "/usr/local/bin/1pctl"); err != nil {
|
if err := cpBinary([]string{source}, "/usr/local/bin/1pctl"); err != nil {
|
||||||
return fmt.Errorf("recover 1pctl binary failed, err: %v", err)
|
return fmt.Errorf("recover 1pctl binary failed, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -692,7 +721,7 @@ func (u *SnapshotService) handlePanelService(fileOp files.FileOp, operation stri
|
||||||
if _, err := os.Stat(panelServicePath); err != nil {
|
if _, err := os.Stat(panelServicePath); err != nil {
|
||||||
return fmt.Errorf("1panel service is not found in %s, err: %v", panelServicePath, err)
|
return fmt.Errorf("1panel service is not found in %s, err: %v", panelServicePath, err)
|
||||||
} else {
|
} else {
|
||||||
if err := cpBinary(panelServicePath, target); err != nil {
|
if err := cpBinary([]string{panelServicePath}, target); err != nil {
|
||||||
return fmt.Errorf("backup 1panel service failed, err: %v", err)
|
return fmt.Errorf("backup 1panel service failed, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -701,7 +730,7 @@ func (u *SnapshotService) handlePanelService(fileOp files.FileOp, operation stri
|
||||||
if _, err := os.Stat(source); err != nil {
|
if _, err := os.Stat(source); err != nil {
|
||||||
return fmt.Errorf("1panel service is not found in snapshot, err: %v", err)
|
return fmt.Errorf("1panel service is not found in snapshot, err: %v", err)
|
||||||
} else {
|
} else {
|
||||||
if err := cpBinary(source, "/etc/systemd/system/1panel.service"); err != nil {
|
if err := cpBinary([]string{source}, "/etc/systemd/system/1panel.service"); err != nil {
|
||||||
return fmt.Errorf("recover 1panel service failed, err: %v", err)
|
return fmt.Errorf("recover 1panel service failed, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -798,10 +827,12 @@ func (u *SnapshotService) Delete(req dto.BatchDeleteReq) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, snap := range backups {
|
for _, snap := range backups {
|
||||||
itemFile := path.Join(localDir, fmt.Sprintf("system/%s/%s.tar.gz", snap.Name, snap.Name))
|
itemFile := path.Join(localDir, "system", snap.Name)
|
||||||
if _, err := os.Stat(itemFile); err == nil {
|
_ = os.RemoveAll(itemFile)
|
||||||
_ = os.Remove(itemFile)
|
|
||||||
}
|
itemTarFile := path.Join(global.CONF.System.TmpDir, "system", snap.Name+".tar.gz")
|
||||||
|
_ = os.Remove(itemTarFile)
|
||||||
|
|
||||||
_ = snapshotRepo.DeleteStatus(snap.ID)
|
_ = snapshotRepo.DeleteStatus(snap.ID)
|
||||||
}
|
}
|
||||||
if err := snapshotRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
|
if err := snapshotRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
|
||||||
|
|
@ -850,8 +881,8 @@ func updateRollbackStatus(id uint, status string, message string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cpBinary(src, dst string) error {
|
func cpBinary(src []string, dst string) error {
|
||||||
stderr, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", src, dst))
|
stderr, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(stderr)
|
return errors.New(stderr)
|
||||||
}
|
}
|
||||||
|
|
@ -981,12 +1012,6 @@ func checkIsAllDone(snapID uint) bool {
|
||||||
if status.Panel != constant.StatusDone {
|
if status.Panel != constant.StatusDone {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if status.PanelCtl != constant.StatusDone {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if status.PanelService != constant.StatusDone {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if status.PanelInfo != constant.StatusDone {
|
if status.PanelInfo != constant.StatusDone {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -1004,3 +1029,17 @@ func checkIsAllDone(snapID uint) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadLogByStatus(status model.SnapshotStatus) string {
|
||||||
|
logs := ""
|
||||||
|
logs += fmt.Sprintf("Write 1Panel basic information: %s \n", status.PanelInfo)
|
||||||
|
logs += fmt.Sprintf("Backup 1Panel system files: %s \n", status.Panel)
|
||||||
|
logs += fmt.Sprintf("Backup Docker configuration file: %s \n", status.DaemonJson)
|
||||||
|
logs += fmt.Sprintf("Backup installed apps from 1Panel: %s \n", status.AppData)
|
||||||
|
logs += fmt.Sprintf("Backup 1Panel data directory: %s \n", status.PanelData)
|
||||||
|
logs += fmt.Sprintf("Backup local backup directory for 1Panel: %s \n", status.BackupData)
|
||||||
|
logs += fmt.Sprintf("Create snapshot file: %s \n", status.BackupData)
|
||||||
|
logs += fmt.Sprintf("Upload snapshot file: %s \n", status.BackupData)
|
||||||
|
|
||||||
|
return logs
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
|
|
@ -19,76 +20,64 @@ import (
|
||||||
|
|
||||||
type snapHelper struct {
|
type snapHelper struct {
|
||||||
SnapID uint
|
SnapID uint
|
||||||
|
Status *model.SnapshotStatus
|
||||||
Ctx context.Context
|
Ctx context.Context
|
||||||
FileOp files.FileOp
|
FileOp files.FileOp
|
||||||
Wg *sync.WaitGroup
|
Wg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapJson(snap snapHelper, statusID uint, snapJson SnapshotJson, targetDir string) {
|
func snapJson(snap snapHelper, snapJson SnapshotJson, targetDir string) {
|
||||||
defer snap.Wg.Done()
|
defer snap.Wg.Done()
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel_info": constant.Running})
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel_info": constant.Running})
|
||||||
status := constant.StatusDone
|
status := constant.StatusDone
|
||||||
remarkInfo, _ := json.MarshalIndent(snapJson, "", "\t")
|
remarkInfo, _ := json.MarshalIndent(snapJson, "", "\t")
|
||||||
if err := os.WriteFile(fmt.Sprintf("%s/snapshot.json", targetDir), remarkInfo, 0640); err != nil {
|
if err := os.WriteFile(fmt.Sprintf("%s/snapshot.json", targetDir), remarkInfo, 0640); err != nil {
|
||||||
status = err.Error()
|
status = err.Error()
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel_info": status})
|
snap.Status.PanelInfo = status
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel_info": status})
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapPanel(snap snapHelper, statusID uint, targetDir string) {
|
func snapPanel(snap snapHelper, targetDir string) {
|
||||||
defer snap.Wg.Done()
|
defer snap.Wg.Done()
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel": constant.Running})
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel": constant.Running})
|
||||||
status := constant.StatusDone
|
status := constant.StatusDone
|
||||||
if err := cpBinary("/usr/local/bin/1panel", path.Join(targetDir, "1panel")); err != nil {
|
if err := cpBinary([]string{"/usr/local/bin/1panel", "/usr/local/bin/1pctl", "/etc/systemd/system/1panel.service"}, targetDir); err != nil {
|
||||||
status = err.Error()
|
status = err.Error()
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel": status})
|
snap.Status.Panel = status
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel": status})
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapPanelCtl(snap snapHelper, statusID uint, targetDir string) {
|
func snapDaemonJson(snap snapHelper, targetDir string) {
|
||||||
defer snap.Wg.Done()
|
defer snap.Wg.Done()
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel_ctl": constant.Running})
|
|
||||||
status := constant.StatusDone
|
status := constant.StatusDone
|
||||||
if err := cpBinary("/usr/local/bin/1pctl", path.Join(targetDir, "1pctl")); err != nil {
|
|
||||||
status = err.Error()
|
|
||||||
}
|
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel_ctl": status})
|
|
||||||
}
|
|
||||||
|
|
||||||
func snapPanelService(snap snapHelper, statusID uint, targetDir string) {
|
|
||||||
defer snap.Wg.Done()
|
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel_service": constant.Running})
|
|
||||||
status := constant.StatusDone
|
|
||||||
if err := cpBinary("/etc/systemd/system/1panel.service", path.Join(targetDir, "1panel.service")); err != nil {
|
|
||||||
status = err.Error()
|
|
||||||
}
|
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel_service": status})
|
|
||||||
}
|
|
||||||
|
|
||||||
func snapDaemonJson(snap snapHelper, statusID uint, targetDir string) {
|
|
||||||
defer snap.Wg.Done()
|
|
||||||
if !snap.FileOp.Stat("/etc/docker/daemon.json") {
|
if !snap.FileOp.Stat("/etc/docker/daemon.json") {
|
||||||
|
snap.Status.DaemonJson = status
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"daemon_json": status})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"daemon_json": constant.Running})
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"daemon_json": constant.Running})
|
||||||
status := constant.StatusDone
|
if err := cpBinary([]string{"/etc/docker/daemon.json"}, path.Join(targetDir, "daemon.json")); err != nil {
|
||||||
if err := cpBinary("/etc/docker/daemon.json", path.Join(targetDir, "daemon.json")); err != nil {
|
|
||||||
status = err.Error()
|
status = err.Error()
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"daemon_json": status})
|
snap.Status.DaemonJson = status
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"daemon_json": status})
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapAppData(snap snapHelper, statusID uint, targetDir string) {
|
func snapAppData(snap snapHelper, targetDir string) {
|
||||||
defer snap.Wg.Done()
|
defer snap.Wg.Done()
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"app_data": constant.Running})
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": constant.Running})
|
||||||
appInstalls, err := appInstallRepo.ListBy()
|
appInstalls, err := appInstallRepo.ListBy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"app_data": err.Error()})
|
snap.Status.AppData = err.Error()
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
runtimes, err := runtimeRepo.List()
|
runtimes, err := runtimeRepo.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"app_data": err.Error()})
|
snap.Status.AppData = err.Error()
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
imageRegex := regexp.MustCompile(`image:\s*(.*)`)
|
imageRegex := regexp.MustCompile(`image:\s*(.*)`)
|
||||||
|
|
@ -119,28 +108,31 @@ func snapAppData(snap snapHelper, statusID uint, targetDir string) {
|
||||||
global.LOG.Debugf("docker save %s | gzip -c > %s", strings.Join(imageSaveList, " "), path.Join(targetDir, "docker_image.tar"))
|
global.LOG.Debugf("docker save %s | gzip -c > %s", strings.Join(imageSaveList, " "), path.Join(targetDir, "docker_image.tar"))
|
||||||
std, err := cmd.Execf("docker save %s | gzip -c > %s", strings.Join(imageSaveList, " "), path.Join(targetDir, "docker_image.tar"))
|
std, err := cmd.Execf("docker save %s | gzip -c > %s", strings.Join(imageSaveList, " "), path.Join(targetDir, "docker_image.tar"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"app_data": std})
|
snap.Status.AppData = err.Error()
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": std})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"app_data": constant.StatusDone})
|
snap.Status.AppData = constant.StatusDone
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"app_data": constant.StatusDone})
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapBackup(snap snapHelper, statusID uint, localDir, targetDir string) {
|
func snapBackup(snap snapHelper, localDir, targetDir string) {
|
||||||
defer snap.Wg.Done()
|
defer snap.Wg.Done()
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"backup_data": constant.Running})
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"backup_data": constant.Running})
|
||||||
status := constant.StatusDone
|
status := constant.StatusDone
|
||||||
if err := handleSnapTar(localDir, targetDir, "1panel_backup.tar.gz", "./system;"); err != nil {
|
if err := handleSnapTar(localDir, targetDir, "1panel_backup.tar.gz", "./system;"); err != nil {
|
||||||
status = err.Error()
|
status = err.Error()
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"backup_data": status})
|
snap.Status.BackupData = status
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"backup_data": status})
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapPanelData(snap snapHelper, statusID uint, localDir, targetDir string) {
|
func snapPanelData(snap snapHelper, localDir, targetDir string) {
|
||||||
defer snap.Wg.Done()
|
defer snap.Wg.Done()
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel_data": constant.Running})
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel_data": constant.Running})
|
||||||
status := constant.StatusDone
|
status := constant.StatusDone
|
||||||
dataDir := path.Join(global.CONF.System.BaseDir, "1panel")
|
dataDir := path.Join(global.CONF.System.BaseDir, "1panel")
|
||||||
exclusionRules := "./tmp;./log;./cache;./db/1Panel.db-*;"
|
exclusionRules := "./tmp;./log;./cache;"
|
||||||
if strings.Contains(localDir, dataDir) {
|
if strings.Contains(localDir, dataDir) {
|
||||||
exclusionRules += ("." + strings.ReplaceAll(localDir, dataDir, "") + ";")
|
exclusionRules += ("." + strings.ReplaceAll(localDir, dataDir, "") + ";")
|
||||||
}
|
}
|
||||||
|
|
@ -150,48 +142,57 @@ func snapPanelData(snap snapHelper, statusID uint, localDir, targetDir string) {
|
||||||
status = err.Error()
|
status = err.Error()
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.Update(snap.SnapID, map[string]interface{}{"status": constant.StatusWaiting})
|
_ = snapshotRepo.Update(snap.SnapID, map[string]interface{}{"status": constant.StatusWaiting})
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"panel_data": status})
|
|
||||||
|
snap.Status.PanelData = status
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel_data": status})
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapCompress(snap snapHelper, statusID uint, rootDir string) {
|
func snapCompress(snap snapHelper, rootDir string) {
|
||||||
defer func() {
|
defer func() {
|
||||||
global.LOG.Debugf("remove snapshot file %s", rootDir)
|
global.LOG.Debugf("remove snapshot file %s", rootDir)
|
||||||
_ = os.RemoveAll(rootDir)
|
_ = os.RemoveAll(rootDir)
|
||||||
}()
|
}()
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"compress": constant.StatusRunning})
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": constant.StatusRunning})
|
||||||
tmpDir := path.Join(global.CONF.System.TmpDir, "system")
|
tmpDir := path.Join(global.CONF.System.TmpDir, "system")
|
||||||
fileName := fmt.Sprintf("%s.tar.gz", path.Base(rootDir))
|
fileName := fmt.Sprintf("%s.tar.gz", path.Base(rootDir))
|
||||||
if err := snap.FileOp.Compress([]string{rootDir}, tmpDir, fileName, files.TarGz); err != nil {
|
if err := snap.FileOp.Compress([]string{rootDir}, tmpDir, fileName, files.TarGz); err != nil {
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"compress": err.Error()})
|
snap.Status.Compress = err.Error()
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"compress": constant.StatusDone})
|
|
||||||
|
snap.Status.Compress = constant.StatusDone
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"compress": constant.StatusDone})
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapUpload(account string, statusID uint, file string) {
|
func snapUpload(snap snapHelper, account string, file string) {
|
||||||
source := path.Join(global.CONF.System.TmpDir, "system", path.Base(file))
|
source := path.Join(global.CONF.System.TmpDir, "system", path.Base(file))
|
||||||
defer func() {
|
defer func() {
|
||||||
global.LOG.Debugf("remove snapshot file %s", source)
|
global.LOG.Debugf("remove snapshot file %s", source)
|
||||||
_ = os.Remove(source)
|
_ = os.Remove(source)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"upload": constant.StatusUploading})
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": constant.StatusUploading})
|
||||||
backup, err := backupRepo.Get(commonRepo.WithByType(account))
|
backup, err := backupRepo.Get(commonRepo.WithByType(account))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"upload": err.Error()})
|
snap.Status.Upload = err.Error()
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
client, err := NewIBackupService().NewClient(&backup)
|
client, err := NewIBackupService().NewClient(&backup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"upload": err.Error()})
|
snap.Status.Upload = err.Error()
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
target := path.Join(backup.BackupPath, "system_snapshot", path.Base(file))
|
target := path.Join(backup.BackupPath, "system_snapshot", path.Base(file))
|
||||||
if _, err := client.Upload(source, target); err != nil {
|
if _, err := client.Upload(source, target); err != nil {
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"upload": err.Error()})
|
snap.Status.Upload = err.Error()
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.UpdateStatus(statusID, map[string]interface{}{"upload": constant.StatusDone})
|
snap.Status.Upload = constant.StatusDone
|
||||||
|
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"upload": constant.StatusDone})
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSnapTar(sourceDir, targetDir, name, exclusionRules string) error {
|
func handleSnapTar(sourceDir, targetDir, name, exclusionRules string) error {
|
||||||
|
|
@ -211,7 +212,7 @@ func handleSnapTar(sourceDir, targetDir, name, exclusionRules string) error {
|
||||||
exStr += exclude
|
exStr += exclude
|
||||||
}
|
}
|
||||||
|
|
||||||
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
|
commands := fmt.Sprintf("tar --warning=no-file-changed --ignore-failed-read -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
|
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -127,13 +127,13 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||||
}
|
}
|
||||||
global.LOG.Info("backup original data successful, now start to upgrade!")
|
global.LOG.Info("backup original data successful, now start to upgrade!")
|
||||||
|
|
||||||
if err := cpBinary(tmpDir+"/1panel", "/usr/local/bin/1panel"); err != nil {
|
if err := cpBinary([]string{tmpDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
|
||||||
u.handleRollback(fileOp, originalDir, 1)
|
u.handleRollback(fileOp, originalDir, 1)
|
||||||
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
|
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cpBinary(tmpDir+"/1pctl", "/usr/local/bin/1pctl"); err != nil {
|
if err := cpBinary([]string{tmpDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
|
||||||
u.handleRollback(fileOp, originalDir, 2)
|
u.handleRollback(fileOp, originalDir, 2)
|
||||||
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
|
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
|
||||||
return
|
return
|
||||||
|
|
@ -144,7 +144,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cpBinary(tmpDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
|
if err := cpBinary([]string{tmpDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
|
||||||
u.handleRollback(fileOp, originalDir, 3)
|
u.handleRollback(fileOp, originalDir, 3)
|
||||||
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
|
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
|
||||||
return
|
return
|
||||||
|
|
@ -179,22 +179,22 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
|
||||||
func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string, errStep int) {
|
func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string, errStep int) {
|
||||||
dbPath := global.CONF.System.DbPath + "/1Panel.db"
|
dbPath := global.CONF.System.DbPath + "/1Panel.db"
|
||||||
_ = settingRepo.Update("SystemStatus", "Free")
|
_ = settingRepo.Update("SystemStatus", "Free")
|
||||||
if err := cpBinary(originalDir+"/1Panel.db", dbPath); err != nil {
|
if err := cpBinary([]string{originalDir + "/1Panel.db"}, dbPath); err != nil {
|
||||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||||
}
|
}
|
||||||
if err := cpBinary(originalDir+"/1panel", "/usr/local/bin/1panel"); err != nil {
|
if err := cpBinary([]string{originalDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
|
||||||
global.LOG.Errorf("rollback 1pctl failed, err: %v", err)
|
global.LOG.Errorf("rollback 1pctl failed, err: %v", err)
|
||||||
}
|
}
|
||||||
if errStep == 1 {
|
if errStep == 1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := cpBinary(originalDir+"/1pctl", "/usr/local/bin/1pctl"); err != nil {
|
if err := cpBinary([]string{originalDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
|
||||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||||
}
|
}
|
||||||
if errStep == 2 {
|
if errStep == 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := cpBinary(originalDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
|
if err := cpBinary([]string{originalDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
|
||||||
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,12 +86,6 @@ func handleSnapStatus() {
|
||||||
if statu.Panel == constant.StatusRunning {
|
if statu.Panel == constant.StatusRunning {
|
||||||
updatas["panel"] = constant.StatusFailed
|
updatas["panel"] = constant.StatusFailed
|
||||||
}
|
}
|
||||||
if statu.PanelCtl == constant.StatusRunning {
|
|
||||||
updatas["panel_ctl"] = constant.StatusFailed
|
|
||||||
}
|
|
||||||
if statu.PanelService == constant.StatusRunning {
|
|
||||||
updatas["panel_service"] = constant.StatusFailed
|
|
||||||
}
|
|
||||||
if statu.PanelInfo == constant.StatusRunning {
|
if statu.PanelInfo == constant.StatusRunning {
|
||||||
updatas["panel_info"] = constant.StatusFailed
|
updatas["panel_info"] = constant.StatusFailed
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,8 +109,6 @@ export namespace Setting {
|
||||||
}
|
}
|
||||||
export interface SnapshotStatus {
|
export interface SnapshotStatus {
|
||||||
panel: string;
|
panel: string;
|
||||||
panelCtl: string;
|
|
||||||
panelService: string;
|
|
||||||
panelInfo: string;
|
panelInfo: string;
|
||||||
daemonJson: string;
|
daemonJson: string;
|
||||||
appData: string;
|
appData: string;
|
||||||
|
|
|
||||||
|
|
@ -709,6 +709,7 @@ const message = {
|
||||||
'This operation records all job execution records, backup files, and log files. Do you want to continue?',
|
'This operation records all job execution records, backup files, and log files. Do you want to continue?',
|
||||||
directory: 'Backup directory',
|
directory: 'Backup directory',
|
||||||
sourceDir: 'Backup directory',
|
sourceDir: 'Backup directory',
|
||||||
|
snapshot: 'System Snapshot',
|
||||||
allOptionHelper:
|
allOptionHelper:
|
||||||
'The current task plan is to back up all [{0}]. Direct download is not supported at the moment. You can check the backup list of [{0}] menu.',
|
'The current task plan is to back up all [{0}]. Direct download is not supported at the moment. You can check the backup list of [{0}] menu.',
|
||||||
exclusionRules: 'Exclusive rule',
|
exclusionRules: 'Exclusive rule',
|
||||||
|
|
@ -1110,15 +1111,13 @@ const message = {
|
||||||
|
|
||||||
snapshot: 'Snapshot',
|
snapshot: 'Snapshot',
|
||||||
status: 'Snapshot status',
|
status: 'Snapshot status',
|
||||||
panelBin: 'Backup 1Panel binary',
|
panelInfo: 'Write 1Panel basic information',
|
||||||
panelCtl: 'Backup 1Panel script',
|
panelBin: 'Backup 1Panel system files',
|
||||||
panelService: 'Backup 1Panel service',
|
daemonJson: 'Backup Docker configuration file',
|
||||||
panelInfo: 'Backup 1Panel basic information',
|
appData: 'Backup installed apps from 1Panel',
|
||||||
daemonJson: 'Backup Docker daemon.json',
|
|
||||||
appData: 'Backup 1Panel application',
|
|
||||||
panelData: 'Backup 1Panel data directory',
|
panelData: 'Backup 1Panel data directory',
|
||||||
backupData: 'Backup 1Panel local backup directory',
|
backupData: 'Backup local backup directory for 1Panel',
|
||||||
compress: 'Compress snapshot file',
|
compress: 'Create snapshot file',
|
||||||
upload: 'Upload snapshot file',
|
upload: 'Upload snapshot file',
|
||||||
thirdPartySupport: 'Only third-party accounts are supported',
|
thirdPartySupport: 'Only third-party accounts are supported',
|
||||||
recoverDetail: 'Recover detail',
|
recoverDetail: 'Recover detail',
|
||||||
|
|
|
||||||
|
|
@ -680,6 +680,7 @@ const message = {
|
||||||
cleanHelper: '該操作將所有任務執行記錄、備份文件和日誌文件,是否繼續?',
|
cleanHelper: '該操作將所有任務執行記錄、備份文件和日誌文件,是否繼續?',
|
||||||
directory: '備份目錄',
|
directory: '備份目錄',
|
||||||
sourceDir: '備份目錄',
|
sourceDir: '備份目錄',
|
||||||
|
snapshot: '系統快照',
|
||||||
allOptionHelper: '當前計劃任務為備份所有【{0}】,暫不支持直接下載,可在【{0}】備份列表中查看',
|
allOptionHelper: '當前計劃任務為備份所有【{0}】,暫不支持直接下載,可在【{0}】備份列表中查看',
|
||||||
exclusionRules: '排除規則',
|
exclusionRules: '排除規則',
|
||||||
saveLocal: '同時保留本地備份(和雲存儲保留份數一致)',
|
saveLocal: '同時保留本地備份(和雲存儲保留份數一致)',
|
||||||
|
|
@ -1001,15 +1002,13 @@ const message = {
|
||||||
|
|
||||||
snapshot: '快照',
|
snapshot: '快照',
|
||||||
status: '快照狀態',
|
status: '快照狀態',
|
||||||
panelBin: '備份 1Panel 二進製',
|
panelInfo: '寫入 1Panel 基礎信息',
|
||||||
panelCtl: '備份 1Panel 腳本',
|
panelBin: '備份 1Panel 系統文件',
|
||||||
panelService: '備份 1Panel 服務',
|
daemonJson: '備份 Docker 配置文件',
|
||||||
panelInfo: '備份 1Panel 基礎信息',
|
appData: '備份 1Panel 已安裝應用',
|
||||||
daemonJson: '備份 Docker 配置',
|
|
||||||
appData: '備份 1Panel 應用',
|
|
||||||
panelData: '備份 1Panel 數據目錄',
|
panelData: '備份 1Panel 數據目錄',
|
||||||
backupData: '備份 1Panel 本地備份目錄',
|
backupData: '備份 1Panel 本地備份目錄',
|
||||||
compress: '壓縮快照文件',
|
compress: '製作快照文件',
|
||||||
upload: '上傳快照文件',
|
upload: '上傳快照文件',
|
||||||
thirdPartySupport: '僅支持第三方賬號',
|
thirdPartySupport: '僅支持第三方賬號',
|
||||||
recoverDetail: '恢復詳情',
|
recoverDetail: '恢復詳情',
|
||||||
|
|
|
||||||
|
|
@ -680,6 +680,7 @@ const message = {
|
||||||
cleanHelper: '该操作将所有任务执行记录、备份文件和日志文件,是否继续?',
|
cleanHelper: '该操作将所有任务执行记录、备份文件和日志文件,是否继续?',
|
||||||
directory: '备份目录',
|
directory: '备份目录',
|
||||||
sourceDir: '备份目录',
|
sourceDir: '备份目录',
|
||||||
|
snapshot: '系统快照',
|
||||||
allOptionHelper: '当前计划任务为备份所有【{0}】,暂不支持直接下载,可在【{0}】备份列表中查看',
|
allOptionHelper: '当前计划任务为备份所有【{0}】,暂不支持直接下载,可在【{0}】备份列表中查看',
|
||||||
exclusionRules: '排除规则',
|
exclusionRules: '排除规则',
|
||||||
saveLocal: '同时保留本地备份(和云存储保留份数一致)',
|
saveLocal: '同时保留本地备份(和云存储保留份数一致)',
|
||||||
|
|
@ -1001,15 +1002,13 @@ const message = {
|
||||||
|
|
||||||
snapshot: '快照',
|
snapshot: '快照',
|
||||||
status: '快照状态',
|
status: '快照状态',
|
||||||
panelBin: '备份 1Panel 二进制',
|
panelInfo: '写入 1Panel 基础信息',
|
||||||
panelCtl: '备份 1Panel 脚本',
|
panelBin: '备份 1Panel 系统文件',
|
||||||
panelService: '备份 1Panel 服务',
|
daemonJson: '备份 Docker 配置文件',
|
||||||
panelInfo: '备份 1Panel 基础信息',
|
appData: '备份 1Panel 已安装应用',
|
||||||
daemonJson: '备份 Docker 配置',
|
|
||||||
appData: '备份 1Panel 应用',
|
|
||||||
panelData: '备份 1Panel 数据目录',
|
panelData: '备份 1Panel 数据目录',
|
||||||
backupData: '备份 1Panel 本地备份目录',
|
backupData: '备份 1Panel 本地备份目录',
|
||||||
compress: '压缩快照文件',
|
compress: '制作快照文件',
|
||||||
upload: '上传快照文件',
|
upload: '上传快照文件',
|
||||||
thirdPartySupport: '仅支持第三方账号',
|
thirdPartySupport: '仅支持第三方账号',
|
||||||
recoverDetail: '恢复详情',
|
recoverDetail: '恢复详情',
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
<el-option value="website" :label="$t('cronjob.website')" />
|
<el-option value="website" :label="$t('cronjob.website')" />
|
||||||
<el-option value="database" :label="$t('cronjob.database')" />
|
<el-option value="database" :label="$t('cronjob.database')" />
|
||||||
<el-option value="directory" :label="$t('cronjob.directory')" />
|
<el-option value="directory" :label="$t('cronjob.directory')" />
|
||||||
|
<el-option value="snapshot" :label="$t('cronjob.snapshot')" />
|
||||||
<el-option value="curl" :label="$t('cronjob.curl')" />
|
<el-option value="curl" :label="$t('cronjob.curl')" />
|
||||||
<el-option value="ntp" :label="$t('cronjob.ntp')" />
|
<el-option value="ntp" :label="$t('cronjob.ntp')" />
|
||||||
<el-option value="cutWebsiteLog" :label="$t('cronjob.cutWebsiteLog')" />
|
<el-option value="cutWebsiteLog" :label="$t('cronjob.cutWebsiteLog')" />
|
||||||
|
|
@ -165,12 +166,13 @@
|
||||||
<div v-if="isBackup()">
|
<div v-if="isBackup()">
|
||||||
<el-form-item :label="$t('cronjob.target')" prop="targetDirID">
|
<el-form-item :label="$t('cronjob.target')" prop="targetDirID">
|
||||||
<el-select class="selectClass" v-model="dialogData.rowData!.targetDirID">
|
<el-select class="selectClass" v-model="dialogData.rowData!.targetDirID">
|
||||||
<el-option
|
<div v-for="item in backupOptions" :key="item.label">
|
||||||
v-for="item in backupOptions"
|
<el-option
|
||||||
:key="item.label"
|
v-if="item.label !== $t('setting.LOCAL') || dialogData.rowData!.type !== 'snapshot'"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</el-select>
|
</el-select>
|
||||||
<span class="input-help">
|
<span class="input-help">
|
||||||
{{ $t('cronjob.targetHelper') }}
|
{{ $t('cronjob.targetHelper') }}
|
||||||
|
|
@ -184,7 +186,9 @@
|
||||||
</el-link>
|
</el-link>
|
||||||
</span>
|
</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="dialogData.rowData!.targetDirID !== localDirID">
|
<el-form-item
|
||||||
|
v-if="dialogData.rowData!.targetDirID !== localDirID && dialogData.rowData!.type !== 'snapshot'"
|
||||||
|
>
|
||||||
<el-checkbox v-model="dialogData.rowData!.keepLocal">
|
<el-checkbox v-model="dialogData.rowData!.keepLocal">
|
||||||
{{ $t('cronjob.saveLocal') }}
|
{{ $t('cronjob.saveLocal') }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
|
|
@ -448,6 +452,20 @@ const changeType = () => {
|
||||||
dialogData.value.rowData.hour = 1;
|
dialogData.value.rowData.hour = 1;
|
||||||
dialogData.value.rowData.minute = 30;
|
dialogData.value.rowData.minute = 30;
|
||||||
break;
|
break;
|
||||||
|
case 'snapshot':
|
||||||
|
dialogData.value.rowData.specType = 'perWeek';
|
||||||
|
dialogData.value.rowData.week = 1;
|
||||||
|
dialogData.value.rowData.hour = 1;
|
||||||
|
dialogData.value.rowData.minute = 30;
|
||||||
|
dialogData.value.rowData.keepLocal = false;
|
||||||
|
dialogData.value.rowData.targetDirID = null;
|
||||||
|
for (const item of backupOptions.value) {
|
||||||
|
if (item.label !== i18n.global.t('setting.LOCAL')) {
|
||||||
|
dialogData.value.rowData.targetDirID = item.value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'directory':
|
case 'directory':
|
||||||
dialogData.value.rowData.specType = 'perDay';
|
dialogData.value.rowData.specType = 'perDay';
|
||||||
dialogData.value.rowData.hour = 1;
|
dialogData.value.rowData.hour = 1;
|
||||||
|
|
@ -504,7 +522,8 @@ function isBackup() {
|
||||||
dialogData.value.rowData!.type === 'app' ||
|
dialogData.value.rowData!.type === 'app' ||
|
||||||
dialogData.value.rowData!.type === 'website' ||
|
dialogData.value.rowData!.type === 'website' ||
|
||||||
dialogData.value.rowData!.type === 'database' ||
|
dialogData.value.rowData!.type === 'database' ||
|
||||||
dialogData.value.rowData!.type === 'directory'
|
dialogData.value.rowData!.type === 'directory' ||
|
||||||
|
dialogData.value.rowData!.type === 'snapshot'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@
|
||||||
</template>
|
</template>
|
||||||
<span class="status-count">{{ dialogData.rowData!.targetDir }}</span>
|
<span class="status-count">{{ dialogData.rowData!.targetDir }}</span>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="currentRecord?.status === 'Success'"
|
v-if="currentRecord?.status === 'Success' && dialogData.rowData!.type !== 'snapshot'"
|
||||||
type="primary"
|
type="primary"
|
||||||
style="margin-left: 10px"
|
style="margin-left: 10px"
|
||||||
link
|
link
|
||||||
|
|
@ -238,6 +238,10 @@
|
||||||
</template>
|
</template>
|
||||||
<span class="status-count">{{ dialogData.rowData!.retainCopies }}</span>
|
<span class="status-count">{{ dialogData.rowData!.retainCopies }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
class="description"
|
||||||
|
v-if="dialogData.rowData!.type === 'snapshot'"
|
||||||
|
></el-form-item>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-form-item class="description" v-if=" dialogData.rowData!.type === 'directory'">
|
<el-form-item class="description" v-if=" dialogData.rowData!.type === 'directory'">
|
||||||
<template #label>
|
<template #label>
|
||||||
|
|
@ -678,7 +682,8 @@ function isBackup() {
|
||||||
dialogData.value.rowData!.type === 'app' ||
|
dialogData.value.rowData!.type === 'app' ||
|
||||||
dialogData.value.rowData!.type === 'website' ||
|
dialogData.value.rowData!.type === 'website' ||
|
||||||
dialogData.value.rowData!.type === 'database' ||
|
dialogData.value.rowData!.type === 'database' ||
|
||||||
dialogData.value.rowData!.type === 'directory'
|
dialogData.value.rowData!.type === 'directory' ||
|
||||||
|
dialogData.value.rowData!.type === 'snapshot'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function loadWeek(i: number) {
|
function loadWeek(i: number) {
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
<el-table-column :label="$t('commons.table.status')" min-width="80" prop="status">
|
<el-table-column :label="$t('commons.table.status')" min-width="80" prop="status">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button
|
<el-button
|
||||||
v-if="row.status === 'Waiting' || row.status === 'onSaveData'"
|
v-if="row.status === 'Waiting' || row.status === 'OnSaveData'"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="onLoadStatus(row)"
|
@click="onLoadStatus(row)"
|
||||||
link
|
link
|
||||||
|
|
|
||||||
|
|
@ -12,30 +12,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-loading="loading">
|
<div v-loading="loading">
|
||||||
<el-alert :type="loadStatus(status.panel)" :closable="false">
|
|
||||||
<template #title>
|
|
||||||
<el-button :icon="loadIcon(status.panel)" link>{{ $t('setting.panelBin') }}</el-button>
|
|
||||||
<div v-if="showErrorMsg(status.panel)" class="top-margin">
|
|
||||||
<span class="err-message">{{ status.panel }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-alert>
|
|
||||||
<el-alert :type="loadStatus(status.panelCtl)" :closable="false">
|
|
||||||
<template #title>
|
|
||||||
<el-button :icon="loadIcon(status.panelCtl)" link>{{ $t('setting.panelCtl') }}</el-button>
|
|
||||||
<div v-if="showErrorMsg(status.panelCtl)" class="top-margin">
|
|
||||||
<span class="err-message">{{ status.panelCtl }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-alert>
|
|
||||||
<el-alert :type="loadStatus(status.panelService)" :closable="false">
|
|
||||||
<template #title>
|
|
||||||
<el-button :icon="loadIcon(status.panelService)" link>{{ $t('setting.panelService') }}</el-button>
|
|
||||||
<div v-if="showErrorMsg(status.panelService)" class="top-margin">
|
|
||||||
<span class="err-message">{{ status.panelService }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-alert>
|
|
||||||
<el-alert :type="loadStatus(status.panelInfo)" :closable="false">
|
<el-alert :type="loadStatus(status.panelInfo)" :closable="false">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-button :icon="loadIcon(status.panelInfo)" link>{{ $t('setting.panelInfo') }}</el-button>
|
<el-button :icon="loadIcon(status.panelInfo)" link>{{ $t('setting.panelInfo') }}</el-button>
|
||||||
|
|
@ -44,6 +20,14 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
|
<el-alert :type="loadStatus(status.panel)" :closable="false">
|
||||||
|
<template #title>
|
||||||
|
<el-button :icon="loadIcon(status.panel)" link>{{ $t('setting.panelBin') }}</el-button>
|
||||||
|
<div v-if="showErrorMsg(status.panel)" class="top-margin">
|
||||||
|
<span class="err-message">{{ status.panel }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-alert>
|
||||||
<el-alert :type="loadStatus(status.daemonJson)" :closable="false">
|
<el-alert :type="loadStatus(status.daemonJson)" :closable="false">
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-button :icon="loadIcon(status.daemonJson)" link>{{ $t('setting.daemonJson') }}</el-button>
|
<el-button :icon="loadIcon(status.daemonJson)" link>{{ $t('setting.daemonJson') }}</el-button>
|
||||||
|
|
@ -113,8 +97,6 @@ import { nextTick, onBeforeUnmount, reactive, ref } from 'vue';
|
||||||
|
|
||||||
const status = reactive<Setting.SnapshotStatus>({
|
const status = reactive<Setting.SnapshotStatus>({
|
||||||
panel: '',
|
panel: '',
|
||||||
panelCtl: '',
|
|
||||||
panelService: '',
|
|
||||||
panelInfo: '',
|
panelInfo: '',
|
||||||
daemonJson: '',
|
daemonJson: '',
|
||||||
appData: '',
|
appData: '',
|
||||||
|
|
@ -158,8 +140,6 @@ const loadCurrentStatus = async () => {
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
status.panel = res.data.panel;
|
status.panel = res.data.panel;
|
||||||
status.panelCtl = res.data.panelCtl;
|
|
||||||
status.panelService = res.data.panelService;
|
|
||||||
status.panelInfo = res.data.panelInfo;
|
status.panelInfo = res.data.panelInfo;
|
||||||
status.daemonJson = res.data.daemonJson;
|
status.daemonJson = res.data.daemonJson;
|
||||||
status.appData = res.data.appData;
|
status.appData = res.data.appData;
|
||||||
|
|
@ -196,8 +176,6 @@ const onWatch = () => {
|
||||||
if (keepLoadStatus()) {
|
if (keepLoadStatus()) {
|
||||||
const res = await loadSnapStatus(snapID.value);
|
const res = await loadSnapStatus(snapID.value);
|
||||||
status.panel = res.data.panel;
|
status.panel = res.data.panel;
|
||||||
status.panelCtl = res.data.panelCtl;
|
|
||||||
status.panelService = res.data.panelService;
|
|
||||||
status.panelInfo = res.data.panelInfo;
|
status.panelInfo = res.data.panelInfo;
|
||||||
status.daemonJson = res.data.daemonJson;
|
status.daemonJson = res.data.daemonJson;
|
||||||
status.appData = res.data.appData;
|
status.appData = res.data.appData;
|
||||||
|
|
@ -214,12 +192,6 @@ const keepLoadStatus = () => {
|
||||||
if (status.panel === 'Running') {
|
if (status.panel === 'Running') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (status.panelCtl === 'Running') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (status.panelService === 'Running') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (status.panelInfo === 'Running') {
|
if (status.panelInfo === 'Running') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -255,12 +227,6 @@ const showRetry = () => {
|
||||||
if (status.panel !== 'Running' && status.panel !== 'Done') {
|
if (status.panel !== 'Running' && status.panel !== 'Done') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (status.panelCtl !== 'Running' && status.panelCtl !== 'Done') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (status.panelService !== 'Running' && status.panelService !== 'Done') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (status.panelInfo !== 'Running' && status.panelInfo !== 'Done') {
|
if (status.panelInfo !== 'Running' && status.panelInfo !== 'Done') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue