mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-11 16:06:02 +08:00
feat: The result of the scheduled task execution is based on the task (#7586)
This commit is contained in:
parent
72c86c3525
commit
ba1d65f35f
23 changed files with 438 additions and 266 deletions
|
@ -36,7 +36,7 @@ func (b *BaseApi) CreateSnapshot(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := snapshotService.SnapshotCreate(req); err != nil {
|
if err := snapshotService.SnapshotCreate(req, false); err != nil {
|
||||||
helper.InternalServer(c, err)
|
helper.InternalServer(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,7 @@ type SearchRecord struct {
|
||||||
|
|
||||||
type Record struct {
|
type Record struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
|
TaskID string `json:"taskID"`
|
||||||
StartTime string `json:"startTime"`
|
StartTime string `json:"startTime"`
|
||||||
Records string `json:"records"`
|
Records string `json:"records"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
|
"github.com/google/uuid"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -146,6 +147,7 @@ func (u *CronjobRepo) StartRecords(cronjobID uint, targetPath string) model.JobR
|
||||||
var record model.JobRecords
|
var record model.JobRecords
|
||||||
record.StartTime = time.Now()
|
record.StartTime = time.Now()
|
||||||
record.CronjobID = cronjobID
|
record.CronjobID = cronjobID
|
||||||
|
record.TaskID = uuid.New().String()
|
||||||
record.Status = constant.StatusWaiting
|
record.Status = constant.StatusWaiting
|
||||||
if err := global.DB.Create(&record).Error; err != nil {
|
if err := global.DB.Create(&record).Error; err != nil {
|
||||||
global.LOG.Errorf("create record status failed, err: %v", err)
|
global.LOG.Errorf("create record status failed, err: %v", err)
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) error {
|
func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, taskID string) error {
|
||||||
var apps []model.AppInstall
|
var apps []model.AppInstall
|
||||||
if cronjob.AppID == "all" {
|
if cronjob.AppID == "all" {
|
||||||
apps, _ = appInstallRepo.ListBy()
|
apps, _ = appInstallRepo.ListBy()
|
||||||
|
@ -46,7 +46,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
|
||||||
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
||||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
|
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("app/%s/%s", app.App.Key, app.Name))
|
||||||
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
record.FileName = fmt.Sprintf("app_%s_%s.tar.gz", app.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||||
if err := handleAppBackup(&app, nil, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret, ""); err != nil {
|
if err := handleAppBackup(&app, nil, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret, taskID); 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))
|
||||||
|
@ -63,7 +63,7 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time) e
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Time) error {
|
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Time, taskID string) error {
|
||||||
webs := loadWebsForJob(cronjob)
|
webs := loadWebsForJob(cronjob)
|
||||||
if len(webs) == 0 {
|
if len(webs) == 0 {
|
||||||
return errors.New("no such website in database!")
|
return errors.New("no such website in database!")
|
||||||
|
@ -82,7 +82,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
||||||
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
record.DownloadAccountID, record.SourceAccountIDs = cronjob.DownloadAccountID, cronjob.SourceAccountIDs
|
||||||
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(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", web.PrimaryDomain, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||||
if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret, ""); err != nil {
|
if err := handleWebsiteBackup(&web, backupDir, record.FileName, cronjob.ExclusionRules, cronjob.Secret, taskID); 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))
|
||||||
|
@ -99,7 +99,7 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Time) error {
|
func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Time, taskID string) error {
|
||||||
dbs := loadDbsForJob(cronjob)
|
dbs := loadDbsForJob(cronjob)
|
||||||
if len(dbs) == 0 {
|
if len(dbs) == 0 {
|
||||||
return errors.New("no such db in database!")
|
return errors.New("no such db in database!")
|
||||||
|
@ -120,11 +120,11 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, startTime time.Ti
|
||||||
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s/%s", dbInfo.DBType, record.Name, dbInfo.Name))
|
backupDir := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("database/%s/%s/%s", dbInfo.DBType, record.Name, dbInfo.Name))
|
||||||
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbInfo.Name, startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5))
|
||||||
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
|
||||||
if err := handleMysqlBackup(dbInfo, nil, backupDir, record.FileName, ""); err != nil {
|
if err := handleMysqlBackup(dbInfo, nil, backupDir, record.FileName, taskID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := handlePostgresqlBackup(dbInfo, nil, backupDir, record.FileName, ""); err != nil {
|
if err := handlePostgresqlBackup(dbInfo, nil, backupDir, record.FileName, taskID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,11 +212,15 @@ func (u *CronjobService) handleSystemLog(cronjob model.Cronjob, startTime time.T
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Time) error {
|
func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Time, taskID string) error {
|
||||||
accountMap, err := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
|
accountMap, err := NewBackupClientMap(strings.Split(cronjob.SourceAccountIDs, ","))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
itemData, err := NewISnapshotService().LoadSnapshotData()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var record model.BackupRecord
|
var record model.BackupRecord
|
||||||
record.From = "cronjob"
|
record.From = "cronjob"
|
||||||
|
@ -227,14 +231,28 @@ func (u *CronjobService) handleSnapshot(cronjob model.Cronjob, startTime time.Ti
|
||||||
record.FileDir = "system_snapshot"
|
record.FileDir = "system_snapshot"
|
||||||
|
|
||||||
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
||||||
|
scope := "core"
|
||||||
|
if !global.IsMaster {
|
||||||
|
scope = "agent"
|
||||||
|
}
|
||||||
req := dto.SnapshotCreate{
|
req := dto.SnapshotCreate{
|
||||||
Name: fmt.Sprintf("snapshot-1panel-%s-linux-%s-%s", versionItem.Value, loadOs(), startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5)),
|
Name: fmt.Sprintf("snapshot-1panel-%s-%s-linux-%s-%s", scope, versionItem.Value, loadOs(), startTime.Format(constant.DateTimeSlimLayout)+common.RandStrAndNum(5)),
|
||||||
Secret: cronjob.Secret,
|
Secret: cronjob.Secret,
|
||||||
|
TaskID: taskID,
|
||||||
|
|
||||||
SourceAccountIDs: record.SourceAccountIDs,
|
SourceAccountIDs: record.SourceAccountIDs,
|
||||||
DownloadAccountID: cronjob.DownloadAccountID,
|
DownloadAccountID: cronjob.DownloadAccountID,
|
||||||
|
AppData: itemData.AppData,
|
||||||
|
PanelData: itemData.PanelData,
|
||||||
|
BackupData: itemData.BackupData,
|
||||||
|
WithMonitorData: true,
|
||||||
|
WithLoginLog: true,
|
||||||
|
WithOperationLog: true,
|
||||||
|
WithSystemLog: true,
|
||||||
|
WithTaskLog: true,
|
||||||
}
|
}
|
||||||
if err := NewISnapshotService().HandleSnapshot(req); err != nil {
|
|
||||||
|
if err := NewISnapshotService().SnapshotCreate(req, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
record.FileName = req.Name + ".tar.gz"
|
record.FileName = req.Name + ".tar.gz"
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
|
@ -31,36 +32,26 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||||
if len(cronjob.Script) == 0 {
|
if len(cronjob.Script) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
record.Records = u.generateLogsPath(*cronjob, record.StartTime)
|
err = u.handleShell(*cronjob, record.TaskID)
|
||||||
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
|
|
||||||
err = u.handleShell(*cronjob, record.Records)
|
|
||||||
u.removeExpiredLog(*cronjob)
|
|
||||||
case "curl":
|
case "curl":
|
||||||
if len(cronjob.URL) == 0 {
|
if len(cronjob.URL) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
record.Records = u.generateLogsPath(*cronjob, record.StartTime)
|
err = u.handleCurl(*cronjob, record.TaskID)
|
||||||
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
|
|
||||||
err = cmd.ExecShell(record.Records, 24*time.Hour, "bash", "-c", "curl", cronjob.URL)
|
|
||||||
u.removeExpiredLog(*cronjob)
|
|
||||||
case "ntp":
|
case "ntp":
|
||||||
err = u.handleNtpSync()
|
err = u.handleNtpSync(*cronjob, record.TaskID)
|
||||||
u.removeExpiredLog(*cronjob)
|
|
||||||
case "cutWebsiteLog":
|
case "cutWebsiteLog":
|
||||||
var messageItem []string
|
var messageItem []string
|
||||||
messageItem, record.File, err = u.handleCutWebsiteLog(cronjob, record.StartTime)
|
messageItem, record.File, err = u.handleCutWebsiteLog(cronjob, record.StartTime)
|
||||||
message = []byte(strings.Join(messageItem, "\n"))
|
message = []byte(strings.Join(messageItem, "\n"))
|
||||||
case "clean":
|
case "clean":
|
||||||
messageItem := ""
|
err = u.handleSystemClean(*cronjob, record.TaskID)
|
||||||
messageItem, err = u.handleSystemClean()
|
|
||||||
message = []byte(messageItem)
|
|
||||||
u.removeExpiredLog(*cronjob)
|
|
||||||
case "website":
|
case "website":
|
||||||
err = u.handleWebsite(*cronjob, record.StartTime)
|
err = u.handleWebsite(*cronjob, record.StartTime, record.TaskID)
|
||||||
case "app":
|
case "app":
|
||||||
err = u.handleApp(*cronjob, record.StartTime)
|
err = u.handleApp(*cronjob, record.StartTime, record.TaskID)
|
||||||
case "database":
|
case "database":
|
||||||
err = u.handleDatabase(*cronjob, record.StartTime)
|
err = u.handleDatabase(*cronjob, record.StartTime, record.TaskID)
|
||||||
case "directory":
|
case "directory":
|
||||||
if len(cronjob.SourceDir) == 0 {
|
if len(cronjob.SourceDir) == 0 {
|
||||||
return
|
return
|
||||||
|
@ -70,7 +61,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||||
err = u.handleSystemLog(*cronjob, record.StartTime)
|
err = u.handleSystemLog(*cronjob, record.StartTime)
|
||||||
case "snapshot":
|
case "snapshot":
|
||||||
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
|
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
|
||||||
err = u.handleSnapshot(*cronjob, record.StartTime)
|
err = u.handleSnapshot(*cronjob, record.StartTime, record.TaskID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -90,53 +81,95 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) handleShell(cronjob model.Cronjob, logPath string) error {
|
func (u *CronjobService) handleShell(cronjob model.Cronjob, taskID string) error {
|
||||||
if len(cronjob.ContainerName) != 0 {
|
taskItem, err := task.NewTaskWithOps(fmt.Sprintf("cronjob-%s", cronjob.Name), task.TaskHandle, task.TaskScopeCronjob, taskID, cronjob.ID)
|
||||||
command := "sh"
|
if err != nil {
|
||||||
if len(cronjob.Command) != 0 {
|
global.LOG.Errorf("new task for exec shell failed, err: %v", err)
|
||||||
command = cronjob.Command
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
taskItem.AddSubTask(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error {
|
||||||
|
if len(cronjob.ContainerName) != 0 {
|
||||||
|
command := "sh"
|
||||||
|
if len(cronjob.Command) != 0 {
|
||||||
|
command = cronjob.Command
|
||||||
|
}
|
||||||
|
scriptFile, _ := os.ReadFile(cronjob.Script)
|
||||||
|
return cmd.ExecShellWithTask(taskItem, 24*time.Hour, "docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(string(scriptFile), "\"", "\\\""))
|
||||||
}
|
}
|
||||||
scriptFile, _ := os.ReadFile(cronjob.Script)
|
if len(cronjob.Executor) == 0 {
|
||||||
return cmd.ExecShell(logPath, 24*time.Hour, "docker", "exec", cronjob.ContainerName, command, "-c", strings.ReplaceAll(string(scriptFile), "\"", "\\\""))
|
cronjob.Executor = "bash"
|
||||||
|
}
|
||||||
|
if cronjob.ScriptMode == "input" {
|
||||||
|
fileItem := pathUtils.Join(global.CONF.System.BaseDir, "1panel", "task", "shell", cronjob.Name, cronjob.Name+".sh")
|
||||||
|
_ = os.MkdirAll(pathUtils.Dir(fileItem), os.ModePerm)
|
||||||
|
shellFile, err := os.OpenFile(fileItem, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, constant.FilePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer shellFile.Close()
|
||||||
|
if _, err := shellFile.WriteString(cronjob.Script); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(cronjob.User) == 0 {
|
||||||
|
return cmd.ExecShellWithTask(taskItem, 24*time.Hour, cronjob.Executor, fileItem)
|
||||||
|
}
|
||||||
|
return cmd.ExecShellWithTask(taskItem, 24*time.Hour, "sudo", "-u", cronjob.User, cronjob.Executor, fileItem)
|
||||||
|
}
|
||||||
|
if len(cronjob.User) == 0 {
|
||||||
|
return cmd.ExecShellWithTask(taskItem, 24*time.Hour, cronjob.Executor, cronjob.Script)
|
||||||
|
}
|
||||||
|
if err := cmd.ExecShellWithTask(taskItem, 24*time.Hour, "sudo", "-u", cronjob.User, cronjob.Executor, cronjob.Script); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
return taskItem.Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) handleCurl(cronjob model.Cronjob, taskID string) error {
|
||||||
|
taskItem, err := task.NewTaskWithOps(fmt.Sprintf("cronjob-%s", cronjob.Name), task.TaskHandle, task.TaskScopeCronjob, taskID, cronjob.ID)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("new task for exec shell failed, err: %v", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if len(cronjob.Executor) == 0 {
|
|
||||||
cronjob.Executor = "bash"
|
taskItem.AddSubTask(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error {
|
||||||
|
if err := cmd.ExecShellWithTask(taskItem, 24*time.Hour, "bash", "-c", "curl", cronjob.URL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
return taskItem.Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) handleNtpSync(cronjob model.Cronjob, taskID string) error {
|
||||||
|
taskItem, err := task.NewTaskWithOps(fmt.Sprintf("cronjob-%s", cronjob.Name), task.TaskHandle, task.TaskScopeCronjob, taskID, cronjob.ID)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("new task for exec shell failed, err: %v", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if cronjob.ScriptMode == "input" {
|
|
||||||
fileItem := pathUtils.Join(global.CONF.System.BaseDir, "1panel", "task", "shell", cronjob.Name, cronjob.Name+".sh")
|
taskItem.AddSubTask(i18n.GetMsgByKey("HandleNtpSync"), func(t *task.Task) error {
|
||||||
_ = os.MkdirAll(pathUtils.Dir(fileItem), os.ModePerm)
|
ntpServer, err := settingRepo.Get(settingRepo.WithByKey("NtpSite"))
|
||||||
shellFile, err := os.OpenFile(fileItem, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, constant.FilePerm)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer shellFile.Close()
|
taskItem.Logf("ntp server: %s", ntpServer.Value)
|
||||||
if _, err := shellFile.WriteString(cronjob.Script); err != nil {
|
ntime, err := ntp.GetRemoteTime(ntpServer.Value)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(cronjob.User) == 0 {
|
if err := ntp.UpdateSystemTime(ntime.Format(constant.DateTimeLayout)); err != nil {
|
||||||
return cmd.ExecShell(logPath, 24*time.Hour, cronjob.Executor, fileItem)
|
return err
|
||||||
}
|
}
|
||||||
return cmd.ExecShell(logPath, 24*time.Hour, "sudo", "-u", cronjob.User, cronjob.Executor, fileItem)
|
return nil
|
||||||
}
|
}, nil)
|
||||||
if len(cronjob.User) == 0 {
|
return taskItem.Execute()
|
||||||
return cmd.ExecShell(logPath, 24*time.Hour, cronjob.Executor, cronjob.Script)
|
|
||||||
}
|
|
||||||
return cmd.ExecShell(logPath, 24*time.Hour, "sudo", "-u", cronjob.User, cronjob.Executor, cronjob.Script)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *CronjobService) handleNtpSync() error {
|
|
||||||
ntpServer, err := settingRepo.Get(settingRepo.WithByKey("NtpSite"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ntime, err := ntp.GetRemoteTime(ntpServer.Value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := ntp.UpdateSystemTime(ntime.Format(constant.DateTimeLayout)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime time.Time) ([]string, string, error) {
|
func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime time.Time) ([]string, string, error) {
|
||||||
|
@ -201,8 +234,13 @@ func backupLogFile(dstFilePath, websiteLogDir string, fileOp files.FileOp) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) handleSystemClean() (string, error) {
|
func (u *CronjobService) handleSystemClean(cronjob model.Cronjob, taskID string) error {
|
||||||
return NewIDeviceService().CleanForCronjob()
|
taskItem, err := task.NewTaskWithOps(fmt.Sprintf("cronjob-%s", cronjob.Name), task.TaskHandle, task.TaskScopeCronjob, taskID, cronjob.ID)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("new task for system clean failed, err: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return systemClean(taskItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, accountMap map[string]backupClientHelper, file string) (string, error) {
|
func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, accountMap map[string]backupClientHelper, file string) (string, error) {
|
||||||
|
@ -274,16 +312,6 @@ func (u *CronjobService) removeExpiredLog(cronjob model.Cronjob) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) generateLogsPath(cronjob model.Cronjob, startTime time.Time) string {
|
|
||||||
dir := fmt.Sprintf("%s/task/%s/%s", constant.DataDir, cronjob.Type, cronjob.Name)
|
|
||||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
|
||||||
_ = os.MkdirAll(dir, os.ModePerm)
|
|
||||||
}
|
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s.log", dir, startTime.Format(constant.DateTimeSlimLayout))
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasBackup(cronjobType string) bool {
|
func hasBackup(cronjobType string) bool {
|
||||||
return cronjobType == "app" || cronjobType == "database" || cronjobType == "website" || cronjobType == "directory" || cronjobType == "snapshot" || cronjobType == "log"
|
return cronjobType == "app" || cronjobType == "database" || cronjobType == "website" || cronjobType == "directory" || cronjobType == "snapshot" || cronjobType == "log"
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ type IDeviceService interface {
|
||||||
|
|
||||||
Scan() dto.CleanData
|
Scan() dto.CleanData
|
||||||
Clean(req []dto.Clean)
|
Clean(req []dto.Clean)
|
||||||
CleanForCronjob() (string, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIDeviceService() IDeviceService {
|
func NewIDeviceService() IDeviceService {
|
||||||
|
|
|
@ -10,11 +10,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||||
"github.com/1Panel-dev/1Panel/agent/global"
|
"github.com/1Panel-dev/1Panel/agent/global"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||||
|
@ -290,64 +292,71 @@ func (u *DeviceService) Clean(req []dto.Clean) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *DeviceService) CleanForCronjob() (string, error) {
|
func systemClean(taskItem *task.Task) error {
|
||||||
logs := ""
|
taskItem.AddSubTask(i18n.GetMsgByKey("HandleSystemClean"), func(t *task.Task) error {
|
||||||
size := int64(0)
|
size := int64(0)
|
||||||
fileCount := 0
|
fileCount := 0
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, "1panel_original"), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, "1panel_original"), taskItem, &size, &fileCount)
|
||||||
|
|
||||||
upgradePath := path.Join(global.CONF.System.BaseDir, upgradePath)
|
upgradePath := path.Join(global.CONF.System.BaseDir, upgradePath)
|
||||||
upgradeFiles, _ := os.ReadDir(upgradePath)
|
upgradeFiles, _ := os.ReadDir(upgradePath)
|
||||||
if len(upgradeFiles) != 0 {
|
if len(upgradeFiles) != 0 {
|
||||||
sort.Slice(upgradeFiles, func(i, j int) bool {
|
sort.Slice(upgradeFiles, func(i, j int) bool {
|
||||||
return upgradeFiles[i].Name() > upgradeFiles[j].Name()
|
return upgradeFiles[i].Name() > upgradeFiles[j].Name()
|
||||||
})
|
})
|
||||||
for i := 0; i < len(upgradeFiles); i++ {
|
for i := 0; i < len(upgradeFiles); i++ {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
dropFileOrDirWithLog(path.Join(upgradePath, upgradeFiles[i].Name()), &logs, &size, &fileCount)
|
dropWithTask(path.Join(upgradePath, upgradeFiles[i].Name()), taskItem, &size, &fileCount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, snapshotTmpPath), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, snapshotTmpPath), taskItem, &size, &fileCount)
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.Backup, "system"), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.Backup, "system"), taskItem, &size, &fileCount)
|
||||||
|
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, rollbackPath, "app"), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, rollbackPath, "app"), taskItem, &size, &fileCount)
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, rollbackPath, "website"), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, rollbackPath, "website"), taskItem, &size, &fileCount)
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, rollbackPath, "database"), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, rollbackPath, "database"), taskItem, &size, &fileCount)
|
||||||
|
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, oldOriginalPath), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, oldOriginalPath), taskItem, &size, &fileCount)
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, oldAppBackupPath), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, oldAppBackupPath), taskItem, &size, &fileCount)
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, oldDownloadPath), &logs, &size, &fileCount)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, oldDownloadPath), taskItem, &size, &fileCount)
|
||||||
oldUpgradePath := path.Join(global.CONF.System.BaseDir, oldUpgradePath)
|
oldUpgradePath := path.Join(global.CONF.System.BaseDir, oldUpgradePath)
|
||||||
oldUpgradeFiles, _ := os.ReadDir(oldUpgradePath)
|
oldUpgradeFiles, _ := os.ReadDir(oldUpgradePath)
|
||||||
if len(oldUpgradeFiles) != 0 {
|
if len(oldUpgradeFiles) != 0 {
|
||||||
for i := 0; i < len(oldUpgradeFiles); i++ {
|
for i := 0; i < len(oldUpgradeFiles); i++ {
|
||||||
dropFileOrDirWithLog(path.Join(oldUpgradePath, oldUpgradeFiles[i].Name()), &logs, &size, &fileCount)
|
dropWithTask(path.Join(oldUpgradePath, oldUpgradeFiles[i].Name()), taskItem, &size, &fileCount)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, tmpUploadPath), &logs, &size, &fileCount)
|
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, uploadPath), &logs, &size, &fileCount)
|
|
||||||
dropFileOrDirWithLog(path.Join(global.CONF.System.BaseDir, downloadPath), &logs, &size, &fileCount)
|
|
||||||
|
|
||||||
logPath := path.Join(global.CONF.System.BaseDir, logPath)
|
|
||||||
logFiles, _ := os.ReadDir(logPath)
|
|
||||||
if len(logFiles) != 0 {
|
|
||||||
for i := 0; i < len(logFiles); i++ {
|
|
||||||
if logFiles[i].Name() != "1Panel.log" {
|
|
||||||
dropFileOrDirWithLog(path.Join(logPath, logFiles[i].Name()), &logs, &size, &fileCount)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
timeNow := time.Now().Format(constant.DateTimeLayout)
|
|
||||||
logs += fmt.Sprintf("\n%s: total clean: %s, total count: %d", timeNow, common.LoadSizeUnit2F(float64(size)), fileCount)
|
|
||||||
|
|
||||||
_ = settingRepo.Update("LastCleanTime", timeNow)
|
dropWithTask(path.Join(global.CONF.System.BaseDir, tmpUploadPath), taskItem, &size, &fileCount)
|
||||||
_ = settingRepo.Update("LastCleanSize", fmt.Sprintf("%v", size))
|
dropWithTask(path.Join(global.CONF.System.BaseDir, uploadPath), taskItem, &size, &fileCount)
|
||||||
_ = settingRepo.Update("LastCleanData", fmt.Sprintf("%v", fileCount))
|
dropWithTask(path.Join(global.CONF.System.BaseDir, downloadPath), taskItem, &size, &fileCount)
|
||||||
|
|
||||||
return logs, nil
|
logPath := path.Join(global.CONF.System.BaseDir, logPath)
|
||||||
|
logFiles, _ := os.ReadDir(logPath)
|
||||||
|
if len(logFiles) != 0 {
|
||||||
|
for i := 0; i < len(logFiles); i++ {
|
||||||
|
if logFiles[i].IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if logFiles[i].Name() != "1Panel.log" {
|
||||||
|
dropWithTask(path.Join(logPath, logFiles[i].Name()), taskItem, &size, &fileCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeNow := time.Now().Format(constant.DateTimeLayout)
|
||||||
|
if fileCount != 0 {
|
||||||
|
taskItem.LogSuccessF("%s: total clean: %s, total count: %d", timeNow, common.LoadSizeUnit2F(float64(size)), fileCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = settingRepo.Update("LastCleanTime", timeNow)
|
||||||
|
_ = settingRepo.Update("LastCleanSize", fmt.Sprintf("%v", size))
|
||||||
|
_ = settingRepo.Update("LastCleanData", fmt.Sprintf("%v", fileCount))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
return taskItem.Execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSnapshotTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
func loadSnapshotTree(fileOp fileUtils.FileOp) []dto.CleanTree {
|
||||||
|
@ -695,18 +704,19 @@ func dropVolumes() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func dropFileOrDirWithLog(itemPath string, log *string, size *int64, count *int) {
|
func dropWithTask(itemPath string, taskItem *task.Task, size *int64, count *int) {
|
||||||
itemSize := int64(0)
|
itemSize := int64(0)
|
||||||
itemCount := 0
|
itemCount := 0
|
||||||
scanFile(itemPath, &itemSize, &itemCount)
|
scanFile(itemPath, &itemSize, &itemCount)
|
||||||
*size += itemSize
|
*size += itemSize
|
||||||
*count += itemCount
|
*count += itemCount
|
||||||
if err := os.RemoveAll(itemPath); err != nil {
|
if err := os.RemoveAll(itemPath); err != nil {
|
||||||
global.LOG.Errorf("drop file %s failed, err %v", itemPath, err)
|
taskItem.LogFailed(fmt.Sprintf("drop file %s, err %v", itemPath, err))
|
||||||
*log += fmt.Sprintf("- drop file %s failed, err: %v \n\n", itemPath, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*log += fmt.Sprintf("+ drop file %s successful!, size: %s, count: %d \n\n", itemPath, common.LoadSizeUnit2F(float64(itemSize)), itemCount)
|
if itemCount != 0 {
|
||||||
|
taskItem.LogSuccessF("drop file %s, size: %s, count: %d", itemPath, common.LoadSizeUnit2F(float64(itemSize)), itemCount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanFile(pathItem string, size *int64, count *int) {
|
func scanFile(pathItem string, size *int64, count *int) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ type ISnapshotService interface {
|
||||||
SearchWithPage(req dto.PageSnapshot) (int64, interface{}, error)
|
SearchWithPage(req dto.PageSnapshot) (int64, interface{}, error)
|
||||||
LoadSize(req dto.SearchWithPage) ([]dto.SnapshotFile, error)
|
LoadSize(req dto.SearchWithPage) ([]dto.SnapshotFile, error)
|
||||||
LoadSnapshotData() (dto.SnapshotData, error)
|
LoadSnapshotData() (dto.SnapshotData, error)
|
||||||
SnapshotCreate(req dto.SnapshotCreate) error
|
SnapshotCreate(req dto.SnapshotCreate, isCron bool) error
|
||||||
SnapshotReCreate(id uint) error
|
SnapshotReCreate(id uint) error
|
||||||
SnapshotRecover(req dto.SnapshotRecover) error
|
SnapshotRecover(req dto.SnapshotRecover) error
|
||||||
SnapshotRollback(req dto.SnapshotRecover) error
|
SnapshotRollback(req dto.SnapshotRecover) error
|
||||||
|
@ -38,8 +38,6 @@ type ISnapshotService interface {
|
||||||
Delete(req dto.SnapshotBatchDelete) error
|
Delete(req dto.SnapshotBatchDelete) error
|
||||||
|
|
||||||
UpdateDescription(req dto.UpdateDescription) error
|
UpdateDescription(req dto.UpdateDescription) error
|
||||||
|
|
||||||
HandleSnapshot(req dto.SnapshotCreate) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewISnapshotService() ISnapshotService {
|
func NewISnapshotService() ISnapshotService {
|
||||||
|
@ -87,6 +85,8 @@ func (u *SnapshotService) LoadSize(req dto.SearchWithPage) ([]dto.SnapshotFile,
|
||||||
backupName := fmt.Sprintf("%s - %s", backup.Type, backup.Name)
|
backupName := fmt.Sprintf("%s - %s", backup.Type, backup.Name)
|
||||||
clientMap[uint(itemVal)] = loadSizeHelper{backupPath: strings.TrimLeft(backup.BackupPath, "/"), client: client, isOk: true, backupName: backupName}
|
clientMap[uint(itemVal)] = loadSizeHelper{backupPath: strings.TrimLeft(backup.BackupPath, "/"), client: client, isOk: true, backupName: backupName}
|
||||||
accountNames = append(accountNames, backupName)
|
accountNames = append(accountNames, backupName)
|
||||||
|
} else {
|
||||||
|
accountNames = append(accountNames, clientMap[uint(itemVal)].backupName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.DefaultDownload = clientMap[records[i].DownloadAccountID].backupName
|
data.DefaultDownload = clientMap[records[i].DownloadAccountID].backupName
|
||||||
|
|
|
@ -24,10 +24,16 @@ import (
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate, isCron bool) error {
|
||||||
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
||||||
|
|
||||||
req.Name = fmt.Sprintf("1panel-%s-linux-%s-%s", versionItem.Value, loadOs(), time.Now().Format(constant.DateTimeSlimLayout))
|
scope := "core"
|
||||||
|
if !global.IsMaster {
|
||||||
|
scope = "agent"
|
||||||
|
}
|
||||||
|
if !isCron {
|
||||||
|
req.Name = fmt.Sprintf("1panel-%s-%s-linux-%s-%s", versionItem.Value, scope, loadOs(), time.Now().Format(constant.DateTimeSlimLayout))
|
||||||
|
}
|
||||||
appItem, _ := json.Marshal(req.AppData)
|
appItem, _ := json.Marshal(req.AppData)
|
||||||
panelItem, _ := json.Marshal(req.PanelData)
|
panelItem, _ := json.Marshal(req.PanelData)
|
||||||
backupItem, _ := json.Marshal(req.BackupData)
|
backupItem, _ := json.Marshal(req.BackupData)
|
||||||
|
@ -57,9 +63,16 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
req.ID = snap.ID
|
req.ID = snap.ID
|
||||||
if err := u.HandleSnapshot(req); err != nil {
|
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskCreate, task.TaskScopeSnapshot, req.TaskID, req.ID)
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("new task for create snapshot failed, err: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !isCron {
|
||||||
|
go handleSnapshot(req, taskItem)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
handleSnapshot(req, taskItem)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,101 +98,95 @@ func (u *SnapshotService) SnapshotReCreate(id uint) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
req.TaskID = taskModel.ID
|
req.TaskID = taskModel.ID
|
||||||
if err := u.HandleSnapshot(req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *SnapshotService) HandleSnapshot(req dto.SnapshotCreate) error {
|
|
||||||
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskCreate, task.TaskScopeSnapshot, req.TaskID, req.ID)
|
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskCreate, task.TaskScopeSnapshot, req.TaskID, req.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("new task for create snapshot failed, err: %v", err)
|
global.LOG.Errorf("new task for create snapshot failed, err: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
go handleSnapshot(req, taskItem)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSnapshot(req dto.SnapshotCreate, taskItem *task.Task) {
|
||||||
rootDir := path.Join(global.CONF.System.BaseDir, "1panel/tmp/system", req.Name)
|
rootDir := path.Join(global.CONF.System.BaseDir, "1panel/tmp/system", req.Name)
|
||||||
itemHelper := snapHelper{SnapID: req.ID, Task: *taskItem, FileOp: files.NewFileOp(), Ctx: context.Background()}
|
itemHelper := snapHelper{SnapID: req.ID, Task: *taskItem, FileOp: files.NewFileOp(), Ctx: context.Background()}
|
||||||
baseDir := path.Join(rootDir, "base")
|
baseDir := path.Join(rootDir, "base")
|
||||||
_ = os.MkdirAll(baseDir, os.ModePerm)
|
_ = os.MkdirAll(baseDir, os.ModePerm)
|
||||||
|
|
||||||
go func() {
|
taskItem.AddSubTaskWithAlias(
|
||||||
|
"SnapDBInfo",
|
||||||
|
func(t *task.Task) error { return loadDbConn(&itemHelper, rootDir, req) },
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapBaseInfo" {
|
||||||
taskItem.AddSubTaskWithAlias(
|
taskItem.AddSubTaskWithAlias(
|
||||||
"SnapDBInfo",
|
"SnapBaseInfo",
|
||||||
func(t *task.Task) error { return loadDbConn(&itemHelper, rootDir, req) },
|
func(t *task.Task) error { return snapBaseData(itemHelper, baseDir) },
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
req.InterruptStep = ""
|
||||||
|
}
|
||||||
|
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapInstallApp" {
|
||||||
|
taskItem.AddSubTaskWithAlias(
|
||||||
|
"SnapInstallApp",
|
||||||
|
func(t *task.Task) error { return snapAppImage(itemHelper, req, rootDir) },
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
req.InterruptStep = ""
|
||||||
|
}
|
||||||
|
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapLocalBackup" {
|
||||||
|
taskItem.AddSubTaskWithAlias(
|
||||||
|
"SnapLocalBackup",
|
||||||
|
func(t *task.Task) error { return snapBackupData(itemHelper, req, rootDir) },
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
req.InterruptStep = ""
|
||||||
|
}
|
||||||
|
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapPanelData" {
|
||||||
|
taskItem.AddSubTaskWithAlias(
|
||||||
|
"SnapPanelData",
|
||||||
|
func(t *task.Task) error { return snapPanelData(itemHelper, req, rootDir) },
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
req.InterruptStep = ""
|
||||||
|
}
|
||||||
|
|
||||||
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapBaseInfo" {
|
taskItem.AddSubTask(
|
||||||
taskItem.AddSubTaskWithAlias(
|
"SnapCloseDBConn",
|
||||||
"SnapBaseInfo",
|
func(t *task.Task) error {
|
||||||
func(t *task.Task) error { return snapBaseData(itemHelper, baseDir) },
|
taskItem.Log("---------------------- 6 / 8 ----------------------")
|
||||||
nil,
|
common.CloseDB(itemHelper.snapAgentDB)
|
||||||
)
|
common.CloseDB(itemHelper.snapCoreDB)
|
||||||
req.InterruptStep = ""
|
return nil
|
||||||
}
|
},
|
||||||
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapInstallApp" {
|
nil,
|
||||||
taskItem.AddSubTaskWithAlias(
|
)
|
||||||
"SnapInstallApp",
|
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapCompress" {
|
||||||
func(t *task.Task) error { return snapAppImage(itemHelper, req, rootDir) },
|
taskItem.AddSubTaskWithAlias(
|
||||||
nil,
|
"SnapCompress",
|
||||||
)
|
func(t *task.Task) error { return snapCompress(itemHelper, rootDir, req.Secret) },
|
||||||
req.InterruptStep = ""
|
nil,
|
||||||
}
|
)
|
||||||
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapLocalBackup" {
|
req.InterruptStep = ""
|
||||||
taskItem.AddSubTaskWithAlias(
|
}
|
||||||
"SnapLocalBackup",
|
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapUpload" {
|
||||||
func(t *task.Task) error { return snapBackupData(itemHelper, req, rootDir) },
|
taskItem.AddSubTaskWithAlias(
|
||||||
nil,
|
"SnapUpload",
|
||||||
)
|
|
||||||
req.InterruptStep = ""
|
|
||||||
}
|
|
||||||
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapPanelData" {
|
|
||||||
taskItem.AddSubTaskWithAlias(
|
|
||||||
"SnapPanelData",
|
|
||||||
func(t *task.Task) error { return snapPanelData(itemHelper, req, rootDir) },
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
req.InterruptStep = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
taskItem.AddSubTask(
|
|
||||||
"SnapCloseDBConn",
|
|
||||||
func(t *task.Task) error {
|
func(t *task.Task) error {
|
||||||
taskItem.Log("---------------------- 6 / 8 ----------------------")
|
return snapUpload(itemHelper, req.SourceAccountIDs, fmt.Sprintf("%s.tar.gz", rootDir))
|
||||||
common.CloseDB(itemHelper.snapAgentDB)
|
|
||||||
common.CloseDB(itemHelper.snapCoreDB)
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapCompress" {
|
req.InterruptStep = ""
|
||||||
taskItem.AddSubTaskWithAlias(
|
}
|
||||||
"SnapCompress",
|
if err := taskItem.Execute(); err != nil {
|
||||||
func(t *task.Task) error { return snapCompress(itemHelper, rootDir, req.Secret) },
|
_ = snapshotRepo.Update(req.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error(), "interrupt_step": taskItem.Task.CurrentStep})
|
||||||
nil,
|
return
|
||||||
)
|
}
|
||||||
req.InterruptStep = ""
|
_ = snapshotRepo.Update(req.ID, map[string]interface{}{"status": constant.StatusSuccess, "interrupt_step": ""})
|
||||||
}
|
_ = os.RemoveAll(rootDir)
|
||||||
if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapUpload" {
|
|
||||||
taskItem.AddSubTaskWithAlias(
|
|
||||||
"SnapUpload",
|
|
||||||
func(t *task.Task) error {
|
|
||||||
return snapUpload(itemHelper, req.SourceAccountIDs, fmt.Sprintf("%s.tar.gz", rootDir))
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
req.InterruptStep = ""
|
|
||||||
}
|
|
||||||
if err := taskItem.Execute(); err != nil {
|
|
||||||
_ = snapshotRepo.Update(req.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error(), "interrupt_step": taskItem.Task.CurrentStep})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_ = snapshotRepo.Update(req.ID, map[string]interface{}{"status": constant.StatusSuccess, "interrupt_step": ""})
|
|
||||||
_ = os.RemoveAll(rootDir)
|
|
||||||
}()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type snapHelper struct {
|
type snapHelper struct {
|
||||||
|
|
|
@ -3,13 +3,14 @@ package task
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
|
@ -68,6 +69,7 @@ const (
|
||||||
TaskScopeRuntime = "Runtime"
|
TaskScopeRuntime = "Runtime"
|
||||||
TaskScopeDatabase = "Database"
|
TaskScopeDatabase = "Database"
|
||||||
TaskScopeCronjob = "Cronjob"
|
TaskScopeCronjob = "Cronjob"
|
||||||
|
TaskScopeSystem = "System"
|
||||||
TaskScopeAppStore = "AppStore"
|
TaskScopeAppStore = "AppStore"
|
||||||
TaskScopeSnapshot = "Snapshot"
|
TaskScopeSnapshot = "Snapshot"
|
||||||
TaskScopeContainer = "Container"
|
TaskScopeContainer = "Container"
|
||||||
|
@ -234,14 +236,14 @@ func (t *Task) DeleteLogFile() {
|
||||||
|
|
||||||
func (t *Task) LogWithStatus(msg string, err error) {
|
func (t *Task) LogWithStatus(msg string, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logger.Printf(i18n.GetWithNameAndErr("FailedStatus", msg, err))
|
t.Logger.Print(i18n.GetWithNameAndErr("FailedStatus", msg, err))
|
||||||
} else {
|
} else {
|
||||||
t.Logger.Printf(i18n.GetWithName("SuccessStatus", msg))
|
t.Logger.Print(i18n.GetWithName("SuccessStatus", msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) Log(msg string) {
|
func (t *Task) Log(msg string) {
|
||||||
t.Logger.Printf(msg)
|
t.Logger.Print(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Task) Logf(format string, v ...any) {
|
func (t *Task) Logf(format string, v ...any) {
|
||||||
|
|
|
@ -187,6 +187,9 @@ ErrFirewallBoth: "Both firewalld and ufw services are detected on the system. To
|
||||||
#cronjob
|
#cronjob
|
||||||
ErrCutWebsiteLog: "{{ .name }} website log cutting failed, error {{ .err }}"
|
ErrCutWebsiteLog: "{{ .name }} website log cutting failed, error {{ .err }}"
|
||||||
CutWebsiteLogSuccess: "{{ .name }} website log cut successfully, backup path {{ .path }}"
|
CutWebsiteLogSuccess: "{{ .name }} website log cut successfully, backup path {{ .path }}"
|
||||||
|
HandleShell: "Execute script {{ .name }}"
|
||||||
|
HandleNtpSync: "System time synchronization"
|
||||||
|
HandleSystemClean: "System cache cleanup"
|
||||||
|
|
||||||
#toolbox
|
#toolbox
|
||||||
ErrNotExistUser: "The current user does not exist. Please modify and retry!"
|
ErrNotExistUser: "The current user does not exist. Please modify and retry!"
|
||||||
|
|
|
@ -188,6 +188,9 @@ ErrFirewallBoth: "檢測到系統同時存在 firewalld 或 ufw 服務,為避
|
||||||
#cronjob
|
#cronjob
|
||||||
ErrCutWebsiteLog: "{{ .name }} 網站日誌切割失敗,錯誤 {{ .err }}"
|
ErrCutWebsiteLog: "{{ .name }} 網站日誌切割失敗,錯誤 {{ .err }}"
|
||||||
CutWebsiteLogSuccess: "{{ .name }} 網站日誌切割成功,備份路徑 {{ .path }}"
|
CutWebsiteLogSuccess: "{{ .name }} 網站日誌切割成功,備份路徑 {{ .path }}"
|
||||||
|
HandleShell: "執行腳本 {{ .name }}"
|
||||||
|
HandleNtpSync: "系統時間同步"
|
||||||
|
HandleSystemClean: "系統快取清理"
|
||||||
|
|
||||||
#toolbox
|
#toolbox
|
||||||
ErrNotExistUser: "當前使用者不存在,請修改後重試!"
|
ErrNotExistUser: "當前使用者不存在,請修改後重試!"
|
||||||
|
|
|
@ -186,6 +186,9 @@ ErrFirewallBoth: "检测到系统同时存在 firewalld 或 ufw 服务,为避
|
||||||
#cronjob
|
#cronjob
|
||||||
ErrCutWebsiteLog: "{{ .name }} 网站日志切割失败,错误 {{ .err }}"
|
ErrCutWebsiteLog: "{{ .name }} 网站日志切割失败,错误 {{ .err }}"
|
||||||
CutWebsiteLogSuccess: "{{ .name }} 网站日志切割成功,备份路径 {{ .path }}"
|
CutWebsiteLogSuccess: "{{ .name }} 网站日志切割成功,备份路径 {{ .path }}"
|
||||||
|
HandleShell: "执行脚本 {{ .name }}"
|
||||||
|
HandleNtpSync: "系统时间同步"
|
||||||
|
HandleSystemClean: "系统缓存清理"
|
||||||
|
|
||||||
#toolbox
|
#toolbox
|
||||||
ErrNotExistUser: "当前用户不存在,请修改后重试!"
|
ErrNotExistUser: "当前用户不存在,请修改后重试!"
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
)
|
)
|
||||||
|
@ -137,6 +138,39 @@ func ExecShell(outPath string, timeout time.Duration, name string, arg ...string
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CustomWriter struct {
|
||||||
|
taskItem *task.Task
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *CustomWriter) Write(p []byte) (n int, err error) {
|
||||||
|
cw.taskItem.Log(string(p))
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
func ExecShellWithTask(taskItem *task.Task, timeout time.Duration, name string, arg ...string) error {
|
||||||
|
customWriter := &CustomWriter{taskItem: taskItem}
|
||||||
|
cmd := exec.Command(name, arg...)
|
||||||
|
cmd.Stdout = customWriter
|
||||||
|
cmd.Stderr = customWriter
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
done := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
done <- cmd.Wait()
|
||||||
|
}()
|
||||||
|
after := time.After(timeout)
|
||||||
|
select {
|
||||||
|
case <-after:
|
||||||
|
_ = cmd.Process.Kill()
|
||||||
|
return buserr.New(constant.ErrCmdTimeout)
|
||||||
|
case err := <-done:
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func Execf(cmdStr string, a ...interface{}) (string, error) {
|
func Execf(cmdStr string, a ...interface{}) (string, error) {
|
||||||
cmd := exec.Command("bash", "-c", fmt.Sprintf(cmdStr, a...))
|
cmd := exec.Command("bash", "-c", fmt.Sprintf(cmdStr, a...))
|
||||||
var stdout, stderr bytes.Buffer
|
var stdout, stderr bytes.Buffer
|
||||||
|
|
|
@ -105,6 +105,7 @@ export namespace Cronjob {
|
||||||
}
|
}
|
||||||
export interface Record {
|
export interface Record {
|
||||||
id: number;
|
id: number;
|
||||||
|
taskID: string;
|
||||||
file: string;
|
file: string;
|
||||||
startTime: string;
|
startTime: string;
|
||||||
records: string;
|
records: string;
|
||||||
|
|
|
@ -4,7 +4,13 @@
|
||||||
<el-checkbox border v-model="tailLog" class="float-left" @change="changeTail(false)" v-if="showTail">
|
<el-checkbox border v-model="tailLog" class="float-left" @change="changeTail(false)" v-if="showTail">
|
||||||
{{ $t('commons.button.watch') }}
|
{{ $t('commons.button.watch') }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
<el-button class="ml-2.5" @click="onDownload" icon="Download" :disabled="logs.length === 0">
|
<el-button
|
||||||
|
class="ml-2.5"
|
||||||
|
v-if="showDownload"
|
||||||
|
@click="onDownload"
|
||||||
|
icon="Download"
|
||||||
|
:disabled="logs.length === 0"
|
||||||
|
>
|
||||||
{{ $t('file.download') }}
|
{{ $t('file.download') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<span v-if="$slots.button" class="ml-2.5">
|
<span v-if="$slots.button" class="ml-2.5">
|
||||||
|
@ -67,6 +73,10 @@ const props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
showDownload: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const stopSignals = [
|
const stopSignals = [
|
||||||
'docker-compose up failed!',
|
'docker-compose up failed!',
|
||||||
|
|
22
frontend/src/components/task-log/log-without-dialog.vue
Normal file
22
frontend/src/components/task-log/log-without-dialog.vue
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<LogFile :config="config" :showTail="false" :showDownload="false" :heightDiff="heightDiff"></LogFile>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
taskID: String,
|
||||||
|
heightDiff: Number,
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = reactive({
|
||||||
|
taskID: props.taskID,
|
||||||
|
type: 'task',
|
||||||
|
taskOperate: '',
|
||||||
|
resourceID: 0,
|
||||||
|
taskType: '',
|
||||||
|
tail: false,
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1658,6 +1658,8 @@ const message = {
|
||||||
'Backup files not in the current backup list, please try downloading from the file directory and importing for backup.',
|
'Backup files not in the current backup list, please try downloading from the file directory and importing for backup.',
|
||||||
|
|
||||||
snapshot: 'Snapshot',
|
snapshot: 'Snapshot',
|
||||||
|
noAppData: 'No system applications available for selection',
|
||||||
|
noBackupData: 'No backup data available for selection',
|
||||||
stepBaseData: 'Base Data',
|
stepBaseData: 'Base Data',
|
||||||
stepAppData: 'System Application',
|
stepAppData: 'System Application',
|
||||||
stepPanelData: 'System Data',
|
stepPanelData: 'System Data',
|
||||||
|
|
|
@ -1469,6 +1469,8 @@ const message = {
|
||||||
backupJump: '未在當前備份列表中的備份檔案,請嘗試從檔案目錄中下載後導入備份。',
|
backupJump: '未在當前備份列表中的備份檔案,請嘗試從檔案目錄中下載後導入備份。',
|
||||||
|
|
||||||
snapshot: '快照',
|
snapshot: '快照',
|
||||||
|
noAppData: '暫無可選擇系統應用',
|
||||||
|
noBackupData: '暫無可選擇備份數據',
|
||||||
stepBaseData: '基礎數據',
|
stepBaseData: '基礎數據',
|
||||||
stepAppData: '系統應用',
|
stepAppData: '系統應用',
|
||||||
stepPanelData: '系統數據',
|
stepPanelData: '系統數據',
|
||||||
|
|
|
@ -1470,6 +1470,8 @@ const message = {
|
||||||
backupJump: '未在当前备份列表中的备份文件,请尝试从文件目录中下载后导入备份。',
|
backupJump: '未在当前备份列表中的备份文件,请尝试从文件目录中下载后导入备份。',
|
||||||
|
|
||||||
snapshot: '快照',
|
snapshot: '快照',
|
||||||
|
noAppData: '暂无可选择系统应用',
|
||||||
|
noBackupData: '暂无可选择备份数据',
|
||||||
stepBaseData: '基础数据',
|
stepBaseData: '基础数据',
|
||||||
stepAppData: '系统应用',
|
stepAppData: '系统应用',
|
||||||
stepPanelData: '系统数据',
|
stepPanelData: '系统数据',
|
||||||
|
|
|
@ -368,7 +368,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item :label="$t('cronjob.backupContent')">
|
<el-form-item v-if="dialogData.rowData!.type === 'directory'" :label="$t('cronjob.backupContent')">
|
||||||
<el-radio-group v-model="dialogData.rowData!.isDir">
|
<el-radio-group v-model="dialogData.rowData!.isDir">
|
||||||
<el-radio :value="true">{{ $t('file.dir') }}</el-radio>
|
<el-radio :value="true">{{ $t('file.dir') }}</el-radio>
|
||||||
<el-radio :value="false">{{ $t('file.file') }}</el-radio>
|
<el-radio :value="false">{{ $t('file.file') }}</el-radio>
|
||||||
|
|
|
@ -172,6 +172,14 @@
|
||||||
></highlightjs>
|
></highlightjs>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-row v-if="currentRecord?.taskID">
|
||||||
|
<TaskLog
|
||||||
|
class="w-full"
|
||||||
|
:taskID="currentRecord?.taskID"
|
||||||
|
:key="currentRecord?.taskID"
|
||||||
|
:heightDiff="200"
|
||||||
|
/>
|
||||||
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -221,6 +229,7 @@ import { MsgSuccess } from '@/utils/message';
|
||||||
import { listDbItems } from '@/api/modules/database';
|
import { listDbItems } from '@/api/modules/database';
|
||||||
import { ListAppInstalled } from '@/api/modules/app';
|
import { ListAppInstalled } from '@/api/modules/app';
|
||||||
import { shortcuts } from '@/utils/shortcuts';
|
import { shortcuts } from '@/utils/shortcuts';
|
||||||
|
import TaskLog from '@/components/task-log/log-without-dialog.vue';
|
||||||
|
|
||||||
const loading = ref();
|
const loading = ref();
|
||||||
const refresh = ref(false);
|
const refresh = ref(false);
|
||||||
|
|
|
@ -53,31 +53,36 @@
|
||||||
</el-form>
|
</el-form>
|
||||||
</fu-step>
|
</fu-step>
|
||||||
<fu-step id="appData" :title="$t('setting.stepAppData')">
|
<fu-step id="appData" :title="$t('setting.stepAppData')">
|
||||||
<el-checkbox
|
<div class="mt-5 mb-5" v-if="!form.appData || form.appData.length === 0">
|
||||||
class="ml-6"
|
<span class="input-help">{{ $t('setting.noAppData') }}</span>
|
||||||
v-model="form.backupAllImage"
|
</div>
|
||||||
@change="selectAllImage"
|
<div v-else>
|
||||||
:label="$t('setting.selectAllImage')"
|
<el-checkbox
|
||||||
size="large"
|
class="ml-6"
|
||||||
/>
|
v-model="form.backupAllImage"
|
||||||
<el-tree
|
@change="selectAllImage"
|
||||||
style="max-width: 600px"
|
:label="$t('setting.selectAllImage')"
|
||||||
ref="appRef"
|
size="large"
|
||||||
node-key="id"
|
/>
|
||||||
:data="form.appData"
|
<el-tree
|
||||||
:props="defaultProps"
|
style="max-width: 600px"
|
||||||
@check-change="onChangeAppData"
|
ref="appRef"
|
||||||
show-checkbox
|
node-key="id"
|
||||||
>
|
:data="form.appData"
|
||||||
<template #default="{ data }">
|
:props="defaultProps"
|
||||||
<div class="float-left">
|
@check-change="onChangeAppData"
|
||||||
<span>{{ loadApp18n(data.label) }}</span>
|
show-checkbox
|
||||||
</div>
|
>
|
||||||
<div class="ml-4 float-left">
|
<template #default="{ data }">
|
||||||
<span v-if="data.size">{{ computeSize(data.size) }}</span>
|
<div class="float-left">
|
||||||
</div>
|
<span>{{ loadApp18n(data.label) }}</span>
|
||||||
</template>
|
</div>
|
||||||
</el-tree>
|
<div class="ml-4 float-left">
|
||||||
|
<span v-if="data.size">{{ computeSize(data.size) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-tree>
|
||||||
|
</div>
|
||||||
</fu-step>
|
</fu-step>
|
||||||
<fu-step id="panelData" :title="$t('setting.stepPanelData')">
|
<fu-step id="panelData" :title="$t('setting.stepPanelData')">
|
||||||
<el-tree
|
<el-tree
|
||||||
|
@ -99,23 +104,28 @@
|
||||||
</el-tree>
|
</el-tree>
|
||||||
</fu-step>
|
</fu-step>
|
||||||
<fu-step id="backupData" :title="$t('setting.stepBackupData')">
|
<fu-step id="backupData" :title="$t('setting.stepBackupData')">
|
||||||
<el-tree
|
<div class="mt-5 mb-5" v-if="!form.appData || form.appData.length === 0">
|
||||||
style="max-width: 600px"
|
<span class="input-help">{{ $t('setting.noBackupData') }}</span>
|
||||||
ref="backupRef"
|
</div>
|
||||||
node-key="id"
|
<div v-else>
|
||||||
:data="form.backupData"
|
<el-tree
|
||||||
:props="defaultProps"
|
style="max-width: 600px"
|
||||||
show-checkbox
|
ref="backupRef"
|
||||||
>
|
node-key="id"
|
||||||
<template #default="{ node, data }">
|
:data="form.backupData"
|
||||||
<div class="float-left">
|
:props="defaultProps"
|
||||||
<span>{{ load18n(node, data.label) }}</span>
|
show-checkbox
|
||||||
</div>
|
>
|
||||||
<div class="ml-4 float-left">
|
<template #default="{ node, data }">
|
||||||
<span v-if="data.size">{{ computeSize(data.size) }}</span>
|
<div class="float-left">
|
||||||
</div>
|
<span>{{ load18n(node, data.label) }}</span>
|
||||||
</template>
|
</div>
|
||||||
</el-tree>
|
<div class="ml-4 float-left">
|
||||||
|
<span v-if="data.size">{{ computeSize(data.size) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-tree>
|
||||||
|
</div>
|
||||||
</fu-step>
|
</fu-step>
|
||||||
<fu-step id="otherData" :title="$t('setting.stepOtherData')">
|
<fu-step id="otherData" :title="$t('setting.stepOtherData')">
|
||||||
<div class="ml-5">
|
<div class="ml-5">
|
||||||
|
@ -239,16 +249,20 @@ const beforeLeave = async (stepItem: any) => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case 'appData':
|
case 'appData':
|
||||||
let appChecks = appRef.value.getCheckedNodes();
|
if (form.appData && form.appData.length !== 0) {
|
||||||
loadCheckForSubmit(appChecks, form.appData);
|
let appChecks = appRef.value.getCheckedNodes();
|
||||||
|
loadCheckForSubmit(appChecks, form.appData);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
case 'panelData':
|
case 'panelData':
|
||||||
let panelChecks = panelRef.value.getCheckedNodes();
|
let panelChecks = panelRef.value.getCheckedNodes();
|
||||||
loadCheckForSubmit(panelChecks, form.panelData);
|
loadCheckForSubmit(panelChecks, form.panelData);
|
||||||
return true;
|
return true;
|
||||||
case 'backupData':
|
case 'backupData':
|
||||||
let backupChecks = backupRef.value.getCheckedNodes();
|
if (form.backupData && form.backupData.length !== 0) {
|
||||||
loadCheckForSubmit(backupChecks, form.backupData);
|
let backupChecks = backupRef.value.getCheckedNodes();
|
||||||
|
loadCheckForSubmit(backupChecks, form.backupData);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue