fix: Split snapshot application backup (#9244)

This commit is contained in:
ssongliu 2025-06-23 18:40:13 +08:00 committed by GitHub
parent 8f18497551
commit 9aa852370c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 86 additions and 24 deletions

View file

@ -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))

View file

@ -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'

View file

@ -333,7 +333,10 @@ SnapDeleteLoginLog: 'アクセスログを削除する'
SnapDeleteMonitor: '監視データを削除する'
SnapRemoveSystemIP: 'システム IP を削除します'
SnapBaseInfo: '1Panel の基本情報を書き込む'
SnapInstallApp: '1Panel にインストールされたアプリケーションをバックアップする'
SnapInstallAppImage: '1Panelインストール済みアプリケーションイメージのバックアップ'
SnapInstallAppImageEmpty: 'アプリケーションイメージが選択されていないため、スキップします...'
SnapInstallApp: '1Panelインストール済みアプリケーションのバックアップ'
SnapBackup: '{{ .app }}のバックアップ'
SnapDockerSave: 'インストールされたアプリケーションを圧縮する'
SnapLocalBackup: '1Panel ローカル バックアップ ディレクトリをバックアップします'
SnapCompressBackup: 'ローカル バックアップ ディレクトリを圧縮する'

View file

@ -333,7 +333,10 @@ SnapDeleteLoginLog: '액세스 로그 삭제'
SnapDeleteMonitor: '모니터링 데이터 삭제'
SnapRemoveSystemIP: '시스템 IP 제거'
SnapBaseInfo: '1패널 기본 정보 쓰기'
SnapInstallAppImage: '1Panel 설치된 애플리케이션 이미지 백업'
SnapInstallAppImageEmpty: '애플리케이션 이미지가 선택되지 않아 건너뜁니다...'
SnapInstallApp: '1Panel 설치된 애플리케이션 백업'
SnapBackup: '{{ .app }} 백업'
SnapDockerSave: '설치된 애플리케이션 압축'
SnapLocalBackup: '1Panel 로컬 백업 디렉토리 백업'
SnapCompressBackup: '로컬 백업 디렉토리 압축'

View file

@ -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'

View file

@ -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'

View file

@ -333,7 +333,10 @@ SnapDeleteLoginLog: 'Удалить журнал доступа'
SnapDeleteMonitor: 'Удалить данные мониторинга'
SnapRemoveSystemIP: 'Удалить системный IP'
SnapBaseInfo: 'Записать основную информацию 1Panel'
SnapInstallApp: 'Резервное копирование установленных приложений 1Panel'
SnapInstallAppImage: 'Резервное копирование образов приложений, установленных в 1Panel'
SnapInstallAppImageEmpty: 'Образы приложений не выбраны, пропускаем...'
SnapInstallApp: 'Резервное копирование приложений, установленных в 1Panel'
SnapBackup: 'Резервная копия {{ .app }}'
SnapDockerSave: 'Сжать установленные приложения'
SnapLocalBackup: 'Резервное копирование локального каталога резервных копий 1Panel'
SnapCompressBackup: 'Сжать локальный каталог резервных копий'

View file

@ -332,7 +332,10 @@ SnapDeleteLoginLog: '刪除存取日誌'
SnapDeleteMonitor: '刪除監控資料'
SnapRemoveSystemIP: '移除系統IP'
SnapBaseInfo: '寫入1Panel 基本資料'
SnapInstallApp: '備份1Panel 已安裝應用程式'
SnapInstallAppImage: '備份 1Panel 已安裝應用鏡像'
SnapInstallAppImageEmpty: '當前未勾選應用鏡像,跳過...'
SnapInstallApp: '備份 1Panel 已安裝應用'
SnapBackup: '備份 {{ .app }}'
SnapDockerSave: '壓縮已安裝應用'
SnapLocalBackup: '備份1Panel 本機備份目錄'
SnapCompressBackup: '壓縮本機備份目錄'

View file

@ -332,7 +332,10 @@ SnapDeleteLoginLog: "删除访问日志"
SnapDeleteMonitor: "删除监控数据"
SnapRemoveSystemIP: "移除系统 IP"
SnapBaseInfo: "写入 1Panel 基本信息"
SnapInstallAppImage: "备份 1Panel 已安装应用镜像"
SnapInstallAppImageEmpty: "当前未勾选应用镜像,跳过..."
SnapInstallApp: "备份 1Panel 已安装应用"
SnapBackup: "备份 {{ .app }}"
SnapDockerSave: "压缩已安装应用"
SnapLocalBackup: "备份 1Panel 本地备份目录"
SnapCompressBackup: "压缩本地备份目录"