From 9aa852370c70d3e04615c8fba3df7a2789f41c01 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:40:13 +0800 Subject: [PATCH] fix: Split snapshot application backup (#9244) --- agent/app/service/snapshot_create.go | 76 +++++++++++++++++++++------- agent/i18n/lang/en.yaml | 3 ++ agent/i18n/lang/ja.yaml | 5 +- agent/i18n/lang/ko.yaml | 3 ++ agent/i18n/lang/ms.yaml | 5 +- agent/i18n/lang/pt-BR.yaml | 5 +- agent/i18n/lang/ru.yaml | 5 +- agent/i18n/lang/zh-Hant.yaml | 5 +- agent/i18n/lang/zh.yaml | 3 ++ 9 files changed, 86 insertions(+), 24 deletions(-) diff --git a/agent/app/service/snapshot_create.go b/agent/app/service/snapshot_create.go index 375eb8e3f..5d2fd7377 100644 --- a/agent/app/service/snapshot_create.go +++ b/agent/app/service/snapshot_create.go @@ -118,6 +118,11 @@ func (u *SnapshotService) SnapshotReCreate(id uint) error { return nil } +type appInstall struct { + Name string + Path string +} + func handleSnapshot(req dto.SnapshotCreate, taskItem *task.Task, jobID, retry, timeout uint) error { rootDir := path.Join(global.Dir.TmpDir, "system", req.Name) openrestyDir, _ := settingRepo.GetValueByKey("WEBSITE_DIR") @@ -125,6 +130,15 @@ func handleSnapshot(req dto.SnapshotCreate, taskItem *task.Task, jobID, retry, t baseDir := path.Join(rootDir, "base") _ = os.MkdirAll(baseDir, os.ModePerm) + var appList []appInstall + for _, item := range req.AppData { + for _, itemApp := range item.Children { + if itemApp.Label == "appData" && itemApp.IsCheck { + appList = append(appList, appInstall{Name: item.Name, Path: path.Join(global.CONF.Base.InstallDir, "1panel/apps", item.Key, item.Name)}) + } + } + } + if timeout == 0 { timeout = 1800 } @@ -150,14 +164,42 @@ func handleSnapshot(req dto.SnapshotCreate, taskItem *task.Task, jobID, retry, t ) req.InterruptStep = "" } - if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapInstallApp" { + + if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapInstallAppImage" { taskItem.AddSubTaskWithAliasAndOps( - "SnapInstallApp", + "SnapInstallAppImage", func(t *task.Task) error { return snapAppImage(itemHelper, req, rootDir) }, nil, int(retry), time.Duration(timeout)*time.Second, ) req.InterruptStep = "" } + + if len(req.InterruptStep) == 0 || strings.HasPrefix(req.InterruptStep, "SnapInstallApp-") { + taskItem.AddSubTaskWithAliasAndOps( + "SnapInstallApp", + func(t *task.Task) error { + itemHelper.Task.Log("---------------------- 4 / 9 ----------------------") + itemHelper.Task.LogStart(i18n.GetMsgByKey("SnapInstallApp")) + start := false + for _, itemApp := range appList { + if !start && (req.InterruptStep == "SnapInstallApp-"+itemApp.Name || len(req.InterruptStep) == 0) { + start = true + } + if !start { + continue + } + taskItem.Log(i18n.GetMsgWithMap("SnapBackup", map[string]interface{}{"app": itemApp.Name})) + if err := itemHelper.FileOp.TarGzCompressPro(false, itemApp.Path, path.Join(rootDir, "apps", itemApp.Name+".tar.gz"), "", ""); err != nil { + return err + } + } + return nil + }, + nil, int(retry), time.Duration(timeout)*time.Second, + ) + req.InterruptStep = "" + } + if len(req.InterruptStep) == 0 || req.InterruptStep == "SnapLocalBackup" { taskItem.AddSubTaskWithAliasAndOps( "SnapLocalBackup", @@ -178,7 +220,7 @@ func handleSnapshot(req dto.SnapshotCreate, taskItem *task.Task, jobID, retry, t taskItem.AddSubTaskWithAliasAndOps( "SnapCloseDBConn", func(t *task.Task) error { - taskItem.Log("---------------------- 6 / 8 ----------------------") + taskItem.Log("---------------------- 7 / 9 ----------------------") common.CloseDB(itemHelper.snapAgentDB) common.CloseDB(itemHelper.snapCoreDB) return nil @@ -224,7 +266,7 @@ type snapHelper struct { } func loadDbConn(snap *snapHelper, targetDir string, req dto.SnapshotCreate) error { - snap.Task.Log("---------------------- 1 / 8 ----------------------") + snap.Task.Log("---------------------- 1 / 9 ----------------------") snap.Task.LogStart(i18n.GetMsgByKey("SnapDBInfo")) pathDB := path.Join(global.Dir.DataDir, "db") @@ -285,7 +327,7 @@ func loadDbConn(snap *snapHelper, targetDir string, req dto.SnapshotCreate) erro } func snapBaseData(snap snapHelper, targetDir string) error { - snap.Task.Log("---------------------- 2 / 8 ----------------------") + snap.Task.Log("---------------------- 2 / 9 ----------------------") snap.Task.LogStart(i18n.GetMsgByKey("SnapBaseInfo")) if global.IsMaster { @@ -344,8 +386,8 @@ func snapBaseData(snap snapHelper, targetDir string) error { } func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) error { - snap.Task.Log("---------------------- 3 / 8 ----------------------") - snap.Task.LogStart(i18n.GetMsgByKey("SnapInstallApp")) + snap.Task.Log("---------------------- 3 / 9 ----------------------") + snap.Task.LogStart(i18n.GetMsgByKey("SnapInstallAppImage")) var appInstalls []model.AppInstall _ = snap.snapAgentDB.Where("1 = 1").Find(&appInstalls).Error @@ -377,8 +419,8 @@ func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) err } } - snap.Task.Log(strings.Join(imageList, " ")) if len(imageList) != 0 { + snap.Task.Log(strings.Join(imageList, " ")) snap.Task.Logf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")) std, err := cmd.NewCommandMgr(cmd.WithTimeout(10*time.Minute)).RunWithStdoutBashCf("docker save %s | gzip -c > %s", strings.Join(imageList, " "), path.Join(targetDir, "images.tar.gz")) if err != nil { @@ -386,12 +428,14 @@ func snapAppImage(snap snapHelper, req dto.SnapshotCreate, targetDir string) err return errors.New(std) } snap.Task.LogSuccess(i18n.GetMsgByKey("SnapDockerSave")) + } else { + snap.Task.Log(i18n.GetMsgByKey("SnapInstallAppImageEmpty")) } return nil } func snapBackupData(snap snapHelper, req dto.SnapshotCreate, targetDir string) error { - snap.Task.Log("---------------------- 4 / 8 ----------------------") + snap.Task.Log("---------------------- 5 / 9 ----------------------") snap.Task.LogStart(i18n.GetMsgByKey("SnapLocalBackup")) excludes := loadBackupExcludes(snap, req.BackupData) @@ -440,19 +484,13 @@ func loadAppBackupExcludes(req []dto.DataTree) []string { } func snapPanelData(snap snapHelper, req dto.SnapshotCreate, targetDir string) error { - snap.Task.Log("---------------------- 5 / 8 ----------------------") + snap.Task.Log("---------------------- 6 / 9 ----------------------") snap.Task.LogStart(i18n.GetMsgByKey("SnapPanelData")) excludes := loadPanelExcludes(req.PanelData) - for _, item := range req.AppData { - for _, itemApp := range item.Children { - if itemApp.Label == "appData" { - excludes = append(excludes, loadPanelExcludes([]dto.DataTree{itemApp})...) - } - } - } excludes = append(excludes, "./cache") excludes = append(excludes, "./db") + excludes = append(excludes, "./apps") excludes = append(excludes, "./tmp") if !req.WithSystemLog { excludes = append(excludes, "./log/1Panel*") @@ -506,7 +544,7 @@ func loadPanelExcludes(req []dto.DataTree) []string { } func snapCompress(snap snapHelper, rootDir string, secret string) error { - snap.Task.Log("---------------------- 7 / 8 ----------------------") + snap.Task.Log("---------------------- 8 / 9 ----------------------") snap.Task.LogStart(i18n.GetMsgByKey("SnapCompress")) tmpDir := path.Join(global.Dir.TmpDir, "system") @@ -530,7 +568,7 @@ func snapCompress(snap snapHelper, rootDir string, secret string) error { } func snapUpload(snap snapHelper, accounts string, file string) error { - snap.Task.Log("---------------------- 8 / 8 ----------------------") + snap.Task.Log("---------------------- 9 / 9 ----------------------") snap.Task.LogStart(i18n.GetMsgByKey("SnapUpload")) source := path.Join(global.Dir.TmpDir, "system", path.Base(file)) diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index 06769188a..259d63f4c 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -333,7 +333,10 @@ SnapDeleteLoginLog: 'Delete access log' SnapDeleteMonitor: 'Delete monitoring data' SnapRemoveSystemIP: 'Remove system IP' SnapBaseInfo: 'Write 1Panel basic information' +SnapInstallAppImage: 'Backup 1Panel installed application images' +SnapInstallAppImageEmpty: 'No application images selected, skipping...' SnapInstallApp: 'Backup 1Panel installed applications' +SnapBackup: 'Backup {{ .app }}' SnapDockerSave: 'Compress installed applications' SnapLocalBackup: 'Backup 1Panel local backup directory' SnapCompressBackup: 'Compress local backup directory' diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index 9c7cb5131..426015531 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -333,7 +333,10 @@ SnapDeleteLoginLog: 'アクセスログを削除する' SnapDeleteMonitor: '監視データを削除する' SnapRemoveSystemIP: 'システム IP を削除します' SnapBaseInfo: '1Panel の基本情報を書き込む' -SnapInstallApp: '1Panel にインストールされたアプリケーションをバックアップする' +SnapInstallAppImage: '1Panelインストール済みアプリケーションイメージのバックアップ' +SnapInstallAppImageEmpty: 'アプリケーションイメージが選択されていないため、スキップします...' +SnapInstallApp: '1Panelインストール済みアプリケーションのバックアップ' +SnapBackup: '{{ .app }}のバックアップ' SnapDockerSave: 'インストールされたアプリケーションを圧縮する' SnapLocalBackup: '1Panel ローカル バックアップ ディレクトリをバックアップします' SnapCompressBackup: 'ローカル バックアップ ディレクトリを圧縮する' diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index 839c96285..47fe329ef 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -333,7 +333,10 @@ SnapDeleteLoginLog: '액세스 로그 삭제' SnapDeleteMonitor: '모니터링 데이터 삭제' SnapRemoveSystemIP: '시스템 IP 제거' SnapBaseInfo: '1패널 기본 정보 쓰기' +SnapInstallAppImage: '1Panel 설치된 애플리케이션 이미지 백업' +SnapInstallAppImageEmpty: '애플리케이션 이미지가 선택되지 않아 건너뜁니다...' SnapInstallApp: '1Panel 설치된 애플리케이션 백업' +SnapBackup: '{{ .app }} 백업' SnapDockerSave: '설치된 애플리케이션 압축' SnapLocalBackup: '1Panel 로컬 백업 디렉토리 백업' SnapCompressBackup: '로컬 백업 디렉토리 압축' diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index 675af0423..cb51738f8 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -332,7 +332,10 @@ SnapDeleteLoginLog: 'Padam log akses' SnapDeleteMonitor: 'Padamkan data pemantauan' SnapRemoveSystemIP: 'Alih keluar IP sistem' SnapBaseInfo: 'Tulis maklumat asas 1Panel' -SnapInstallApp: 'Aplikasi yang dipasang sandaran 1Panel' +SnapInstallAppImage: 'Sandaran imej aplikasi terpasang 1Panel' +SnapInstallAppImageEmpty: 'Tiada imej aplikasi dipilih, dilangkau...' +SnapInstallApp: 'Sandaran aplikasi terpasang 1Panel' +SnapBackup: 'Sandaran {{ .app }}' SnapDockerSave: 'Mampatkan aplikasi yang dipasang' SnapLocalBackup: 'Sandaran 1Panel direktori sandaran tempatan' SnapCompressBackup: 'Mampatkan direktori sandaran tempatan' diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index 69bd54177..7507488ed 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -333,7 +333,10 @@ SnapDeleteLoginLog: 'Excluir log de acesso' SnapDeleteMonitor: 'Excluir dados de monitoramento' SnapRemoveSystemIP: 'Remover IP do sistema' SnapBaseInfo: 'Escreva informações básicas do 1Panel' -SnapInstallApp: 'Fazer backup dos aplicativos instalados do 1Panel' +SnapInstallAppImage: 'Backup das imagens de aplicativos instalados do 1Panel' +SnapInstallAppImageEmpty: 'Nenhuma imagem de aplicativo selecionada, pulando...' +SnapInstallApp: 'Backup dos aplicativos instalados do 1Panel' +SnapBackup: 'Backup do {{ .app }}' SnapDockerSave: 'Compactar aplicativos instalados' SnapLocalBackup: 'Backup do diretório de backup local do 1Panel' SnapCompressBackup: 'Compactar diretório de backup local' diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index b923b18c7..1e7230a32 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -333,7 +333,10 @@ SnapDeleteLoginLog: 'Удалить журнал доступа' SnapDeleteMonitor: 'Удалить данные мониторинга' SnapRemoveSystemIP: 'Удалить системный IP' SnapBaseInfo: 'Записать основную информацию 1Panel' -SnapInstallApp: 'Резервное копирование установленных приложений 1Panel' +SnapInstallAppImage: 'Резервное копирование образов приложений, установленных в 1Panel' +SnapInstallAppImageEmpty: 'Образы приложений не выбраны, пропускаем...' +SnapInstallApp: 'Резервное копирование приложений, установленных в 1Panel' +SnapBackup: 'Резервная копия {{ .app }}' SnapDockerSave: 'Сжать установленные приложения' SnapLocalBackup: 'Резервное копирование локального каталога резервных копий 1Panel' SnapCompressBackup: 'Сжать локальный каталог резервных копий' diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index 3716b1680..230cff753 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -332,7 +332,10 @@ SnapDeleteLoginLog: '刪除存取日誌' SnapDeleteMonitor: '刪除監控資料' SnapRemoveSystemIP: '移除系統IP' SnapBaseInfo: '寫入1Panel 基本資料' -SnapInstallApp: '備份1Panel 已安裝應用程式' +SnapInstallAppImage: '備份 1Panel 已安裝應用鏡像' +SnapInstallAppImageEmpty: '當前未勾選應用鏡像,跳過...' +SnapInstallApp: '備份 1Panel 已安裝應用' +SnapBackup: '備份 {{ .app }}' SnapDockerSave: '壓縮已安裝應用' SnapLocalBackup: '備份1Panel 本機備份目錄' SnapCompressBackup: '壓縮本機備份目錄' diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index fe26b9860..d220ef128 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -332,7 +332,10 @@ SnapDeleteLoginLog: "删除访问日志" SnapDeleteMonitor: "删除监控数据" SnapRemoveSystemIP: "移除系统 IP" SnapBaseInfo: "写入 1Panel 基本信息" +SnapInstallAppImage: "备份 1Panel 已安装应用镜像" +SnapInstallAppImageEmpty: "当前未勾选应用镜像,跳过..." SnapInstallApp: "备份 1Panel 已安装应用" +SnapBackup: "备份 {{ .app }}" SnapDockerSave: "压缩已安装应用" SnapLocalBackup: "备份 1Panel 本地备份目录" SnapCompressBackup: "压缩本地备份目录"