feat: 快照恢复原文件备份目录修改

This commit is contained in:
ssongliu 2023-02-09 16:36:28 +08:00 committed by ssongliu
parent eb9ec322f8
commit de6dcc53b0
9 changed files with 59 additions and 54 deletions

View File

@ -67,7 +67,6 @@ func ErrorWithDetail(ctx *gin.Context, code int, msgKey string, err error) {
} else {
res.Message = i18n.GetMsgWithMap(msgKey, map[string]interface{}{"detail": err})
}
global.LOG.Errorf("request: %s, error: %s", ctx.Request.URL.Path, res.Message)
ctx.JSON(http.StatusOK, res)
ctx.Abort()
}

View File

@ -167,7 +167,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
return
}
defer res.Body.Close()
global.LOG.Debugf("build image %s successful!", req.Name)
global.LOG.Infof("build image %s successful!", req.Name)
_, _ = io.Copy(file, res.Body)
}()
@ -199,7 +199,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
return
}
defer out.Close()
global.LOG.Debugf("pull image %s successful!", req.ImageName)
global.LOG.Infof("pull image %s successful!", req.ImageName)
_, _ = io.Copy(file, out)
}()
return pathItem, nil
@ -230,7 +230,7 @@ func (u *ImageService) ImagePull(req dto.ImagePull) (string, error) {
return
}
defer out.Close()
global.LOG.Debugf("pull image %s successful!", req.ImageName)
global.LOG.Infof("pull image %s successful!", req.ImageName)
_, _ = io.Copy(file, out)
}()
return pathItem, nil
@ -333,7 +333,7 @@ func (u *ImageService) ImagePush(req dto.ImagePush) (string, error) {
return
}
defer out.Close()
global.LOG.Debugf("push image %s successful!", req.Name)
global.LOG.Infof("push image %s successful!", req.Name)
_, _ = io.Copy(file, out)
}()

View File

@ -6,7 +6,6 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
@ -21,7 +20,9 @@ import (
"github.com/pkg/errors"
)
type SnapshotService struct{}
type SnapshotService struct {
OriginalPath string
}
type ISnapshotService interface {
SearchWithPage(req dto.PageInfo) (int64, interface{}, error)
@ -89,9 +90,10 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
Description: req.Description,
From: req.From,
Version: versionItem.Value,
Status: constant.StatusWaiting,
Status: constant.StatusSuccess,
}
_ = snapshotRepo.Create(&snap)
_ = settingRepo.Update("SystemStatus", "Snapshoting")
go func() {
defer func() {
_ = os.RemoveAll(rootDir)
@ -136,6 +138,7 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusWaiting})
snapJson := SnapshotJson{DockerDataDir: dockerDataDir, BackupDataDir: localDir, PanelDataDir: global.CONF.BaseDir + "/1panel", LiveRestoreEnabled: liveRestoreStatus}
if err := u.saveJson(snapJson, rootDir); err != nil {
@ -147,6 +150,9 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
return
}
_ = settingRepo.Update("SystemStatus", "Free")
global.LOG.Infof("start to upload snapshot to %s, please wait", backup.Type)
localPath := fmt.Sprintf("%s/system/1panel_snapshot_%s.tar.gz", localDir, timeNow)
if ok, err := backupAccont.Upload(localPath, fmt.Sprintf("system_snapshot/1panel_snapshot_%s.tar.gz", timeNow)); err != nil || !ok {
@ -193,6 +199,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
}
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"recover_status": constant.StatusWaiting})
_ = settingRepo.Update("SystemStatus", "Recovering")
go func() {
operation := "recover"
if isReTry {
@ -223,7 +230,8 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
isReTry = false
}
rootDir := fmt.Sprintf("%s/%s", baseDir, snap.Name)
originalDir := fmt.Sprintf("%s/original/", baseDir)
u.OriginalPath = fmt.Sprintf("%s/original_%s", global.CONF.BaseDir, snap.Name)
_ = os.MkdirAll(u.OriginalPath, os.ModePerm)
snapJson, err := u.readFromJson(fmt.Sprintf("%s/snapshot.json", rootDir))
if err != nil {
@ -264,7 +272,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
isReTry = false
}
if !isReTry || snap.InterruptStep == "DaemonJson" {
if err := u.handleDaemonJson(fileOp, operation, rootDir+"/docker/daemon.json", originalDir); err != nil {
if err := u.handleDaemonJson(fileOp, operation, rootDir+"/docker/daemon.json", u.OriginalPath); err != nil {
updateRecoverStatus(snap.ID, "DaemonJson", constant.StatusFailed, err.Error())
return
}
@ -273,21 +281,21 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
_, _ = cmd.Exec("systemctl restart docker")
if !isReTry || snap.InterruptStep == "1PanelBinary" {
if err := u.handlePanelBinary(fileOp, operation, recoverPanelDir+"/1panel", originalDir+"/1panel"); err != nil {
if err := u.handlePanelBinary(fileOp, operation, recoverPanelDir+"/1panel", u.OriginalPath+"/1panel"); err != nil {
updateRecoverStatus(snap.ID, "1PanelBinary", constant.StatusFailed, err.Error())
return
}
isReTry = false
}
if !isReTry || snap.InterruptStep == "1PctlBinary" {
if err := u.handlePanelctlBinary(fileOp, operation, recoverPanelDir+"/1pctl", originalDir+"/1pctl"); err != nil {
if err := u.handlePanelctlBinary(fileOp, operation, recoverPanelDir+"/1pctl", u.OriginalPath+"/1pctl"); err != nil {
updateRecoverStatus(snap.ID, "1PctlBinary", constant.StatusFailed, err.Error())
return
}
isReTry = false
}
if !isReTry || snap.InterruptStep == "1PanelService" {
if err := u.handlePanelService(fileOp, operation, recoverPanelDir+"/1panel.service", originalDir+"/1panel.service"); err != nil {
if err := u.handlePanelService(fileOp, operation, recoverPanelDir+"/1panel.service", u.OriginalPath+"/1panel.service"); err != nil {
updateRecoverStatus(snap.ID, "1PanelService", constant.StatusFailed, err.Error())
return
}
@ -303,7 +311,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
}
if !isReTry || snap.InterruptStep == "1PanelData" {
if err := u.handlePanelDatas(fileOp, operation, rootDir, snapJson.PanelDataDir, "", ""); err != nil {
if err := u.handlePanelDatas(fileOp, operation, rootDir, snapJson.PanelDataDir, localDir, snapJson.OldDockerDataDir); err != nil {
updateRecoverStatus(snap.ID, "1PanelData", constant.StatusFailed, err.Error())
return
}
@ -312,7 +320,6 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
_ = os.RemoveAll(rootDir)
global.LOG.Info("recover successful")
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
updateRecoverStatus(snap.ID, "", constant.StatusSuccess, "")
}()
return nil
}
@ -333,8 +340,8 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
fileOp := files.NewFileOp()
rootDir := fmt.Sprintf("%s/system/%s/%s", localDir, snap.Name, snap.Name)
originalDir := fmt.Sprintf("%s/system/%s/original", localDir, snap.Name)
if _, err := os.Stat(originalDir); err != nil && os.IsNotExist(err) {
u.OriginalPath = fmt.Sprintf("%s/original_%s", global.CONF.BaseDir, snap.Name)
if _, err := os.Stat(u.OriginalPath); err != nil && os.IsNotExist(err) {
return fmt.Errorf("load original dir failed, err: %s", err)
}
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"rollback_status": constant.StatusWaiting})
@ -345,7 +352,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
}
_, _ = cmd.Exec("systemctl stop docker")
if err := u.handleDockerDatas(fileOp, "rollback", originalDir, snapJson.OldDockerDataDir); err != nil {
if err := u.handleDockerDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldDockerDataDir); err != nil {
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
return err
}
@ -354,7 +361,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
return nil
}
if err := u.handleDaemonJson(fileOp, "rollback", originalDir+"/daemon.json", ""); err != nil {
if err := u.handleDaemonJson(fileOp, "rollback", u.OriginalPath+"/daemon.json", ""); err != nil {
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
return err
}
@ -373,7 +380,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
return nil
}
if err := u.handlePanelBinary(fileOp, "rollback", originalDir+"/1panel", ""); err != nil {
if err := u.handlePanelBinary(fileOp, "rollback", u.OriginalPath+"/1panel", ""); err != nil {
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
return err
}
@ -381,7 +388,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
return nil
}
if err := u.handlePanelctlBinary(fileOp, "rollback", originalDir+"/1pctl", ""); err != nil {
if err := u.handlePanelctlBinary(fileOp, "rollback", u.OriginalPath+"/1pctl", ""); err != nil {
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
return err
}
@ -389,7 +396,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
return nil
}
if err := u.handlePanelService(fileOp, "rollback", originalDir+"/1panel.service", ""); err != nil {
if err := u.handlePanelService(fileOp, "rollback", u.OriginalPath+"/1panel.service", ""); err != nil {
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
return err
}
@ -398,7 +405,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
return nil
}
if err := u.handleBackupDatas(fileOp, "rollback", originalDir, snapJson.OldBackupDataDir); err != nil {
if err := u.handleBackupDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldBackupDataDir); err != nil {
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
return err
}
@ -407,7 +414,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
return nil
}
if err := u.handlePanelDatas(fileOp, "rollback", originalDir, snapJson.OldPanelDataDir, "", ""); err != nil {
if err := u.handlePanelDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldPanelDataDir, "", ""); err != nil {
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
return err
}
@ -453,7 +460,7 @@ func (u *SnapshotService) handleDockerDatas(fileOp files.FileOp, operation strin
return fmt.Errorf("backup docker data failed, err: %v", err)
}
case "recover":
if err := u.handleTar(target, fmt.Sprintf("%s/original", filepath.Join(source, "../")), "docker_data.tar.gz", ""); err != nil {
if err := u.handleTar(target, u.OriginalPath, "docker_data.tar.gz", ""); err != nil {
return fmt.Errorf("backup docker data failed, err: %v", err)
}
if err := u.handleUnTar(source+"/docker/docker_data.tar.gz", target); err != nil {
@ -574,11 +581,11 @@ func (u *SnapshotService) handlePanelService(fileOp files.FileOp, operation stri
func (u *SnapshotService) handleBackupDatas(fileOp files.FileOp, operation string, source, target string) error {
switch operation {
case "snapshot":
if err := u.handleTar(source, target, "1panel_backup.tar.gz", "./system"); err != nil {
if err := u.handleTar(source, target, "1panel_backup.tar.gz", "./system;"); err != nil {
return fmt.Errorf("backup panel local backup dir data failed, err: %v", err)
}
case "recover":
if err := u.handleTar(target, fmt.Sprintf("%s/original", filepath.Join(source, "../")), "1panel_backup.tar.gz", "./system"); err != nil {
if err := u.handleTar(target, u.OriginalPath, "1panel_backup.tar.gz", "./system;"); err != nil {
return fmt.Errorf("restore original local backup dir data failed, err: %v", err)
}
if err := u.handleUnTar(source+"/1panel/1panel_backup.tar.gz", target); err != nil {
@ -600,7 +607,7 @@ func (u *SnapshotService) handleBackupDatas(fileOp files.FileOp, operation strin
func (u *SnapshotService) handlePanelDatas(fileOp files.FileOp, operation string, source, target, backupDir, dockerDir string) error {
switch operation {
case "snapshot":
exclusionRules := ""
exclusionRules := "./data/tmp;./data/cache;"
if strings.Contains(backupDir, source) {
exclusionRules += ("." + strings.ReplaceAll(backupDir, source, "") + ";")
}
@ -611,14 +618,14 @@ func (u *SnapshotService) handlePanelDatas(fileOp files.FileOp, operation string
return fmt.Errorf("backup panel data failed, err: %v", err)
}
case "recover":
exclusionRules := ""
exclusionRules := "./data/tmp/;./data/cache;"
if strings.Contains(backupDir, target) {
exclusionRules += ("1panel" + strings.ReplaceAll(backupDir, target, "") + ";")
exclusionRules += ("." + strings.ReplaceAll(backupDir, target, "") + ";")
}
if strings.Contains(dockerDir, target) {
exclusionRules += ("1panel" + strings.ReplaceAll(dockerDir, target, "") + ";")
exclusionRules += ("." + strings.ReplaceAll(dockerDir, target, "") + ";")
}
if err := u.handleTar(target, fmt.Sprintf("%s/original", filepath.Join(source, "../")), "1panel_data.tar.gz", exclusionRules); err != nil {
if err := u.handleTar(target, u.OriginalPath, "1panel_data.tar.gz", exclusionRules); err != nil {
return fmt.Errorf("restore original panel data failed, err: %v", err)
}
@ -634,8 +641,6 @@ func (u *SnapshotService) handlePanelDatas(fileOp files.FileOp, operation string
return fmt.Errorf("rollback panel data failed, err: %v", err)
}
}
global.LOG.Info("handle panel data successful!")
return nil
}
@ -679,6 +684,7 @@ func updateSnapshotStatus(id uint, status string, message string) {
}); err != nil {
global.LOG.Errorf("update snap snapshot status failed, err: %v", err)
}
_ = settingRepo.Update("SystemStatus", "Free")
}
func updateRecoverStatus(id uint, interruptStep, status string, message string) {
if status != constant.StatusSuccess {
@ -692,6 +698,7 @@ func updateRecoverStatus(id uint, interruptStep, status string, message string)
}); err != nil {
global.LOG.Errorf("update snap recover status failed, err: %v", err)
}
_ = settingRepo.Update("SystemStatus", "Free")
}
func updateRollbackStatus(id uint, status string, message string) {
if status == constant.StatusSuccess {
@ -789,8 +796,8 @@ func (u *SnapshotService) handleTar(sourceDir, targetDir, name, exclusionRules s
exStr += exclude
}
ss := fmt.Sprintf("tar zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
fmt.Println(ss)
ss := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
global.LOG.Debug(ss)
stdout, err := cmd.Exec(ss)
if err != nil {
return errors.New(stdout)

View File

@ -90,16 +90,12 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
}
}
panelName := fmt.Sprintf("1panel-%s-%s", "linux", runtime.GOARCH)
fileName := fmt.Sprintf("1panel-online-installer-%s.tar.gz", req.Version)
fileName := fmt.Sprintf("1panel-%s-%s-%s.tar.gz", req.Version, "linux", runtime.GOARCH)
_ = settingRepo.Update("SystemStatus", "Upgrading")
go func() {
if err := fileOp.DownloadFile(downloadPath+panelName, rootDir+"/1panel"); err != nil {
global.LOG.Errorf("download panel file failed, err: %v", err)
return
}
if err := fileOp.DownloadFile(downloadPath+fileName, rootDir+"/service.tar.gz"); err != nil {
global.LOG.Errorf("download service file failed, err: %v", err)
_ = settingRepo.Update("SystemStatus", "Free")
return
}
global.LOG.Info("download all file successful!")
@ -108,11 +104,13 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
}()
if err := fileOp.Decompress(rootDir+"/service.tar.gz", rootDir, files.TarGz); err != nil {
global.LOG.Errorf("decompress file failed, err: %v", err)
_ = settingRepo.Update("SystemStatus", "Free")
return
}
if err := u.handleBackup(fileOp, originalDir); err != nil {
global.LOG.Errorf("handle backup original file failed, err: %v", err)
_ = settingRepo.Update("SystemStatus", "Free")
return
}
global.LOG.Info("backup original data successful, now start to upgrade!")
@ -122,21 +120,11 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
return
}
if err := fileOp.Chmod("/usr/local/bin/1panel", 0755); err != nil {
u.handleRollback(fileOp, originalDir, 1)
global.LOG.Errorf("chmod 1panel failed, err: %v", err)
return
}
if err := cpBinary(fmt.Sprintf("%s/1panel-online-installer-%s/1pctl", rootDir, req.Version), "/usr/local/bin/1pctl"); err != nil {
u.handleRollback(fileOp, originalDir, 2)
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
return
}
if err := fileOp.Chmod("/usr/local/bin/1pctl", 0755); err != nil {
u.handleRollback(fileOp, originalDir, 1)
global.LOG.Errorf("chmod 1pctl failed, err: %v", err)
return
}
if err := cpBinary(fmt.Sprintf("%s/1panel-online-installer-%s/1panel/conf/1panel.service", rootDir, req.Version), "/etc/systemd/system/1panel.service"); err != nil {
u.handleRollback(fileOp, originalDir, 3)
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
@ -170,6 +158,7 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string, errStep int) {
dbPath := global.CONF.System.DbPath + "/1Panel.db"
_ = settingRepo.Update("SystemStatus", "Free")
if err := cpBinary(originalDir+"/1Panel.db", dbPath); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
@ -188,6 +177,7 @@ func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string,
if err := cpBinary(originalDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
}
func (u *UpgradeService) loadLatestFromGithub() (dto.UpgradeInfo, error) {

View File

@ -17,7 +17,7 @@ func Init() {
constant.AppInstallDir = path.Join(constant.DataDir, "apps")
constant.TmpDir = path.Join(constant.DataDir, "tmp")
dirs := []string{constant.DataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir}
dirs := []string{constant.DataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir, global.CONF.System.Backup}
fileOp := files.NewFileOp()
for _, dir := range dirs {

View File

@ -3,9 +3,10 @@ package viper
import (
"bytes"
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"strings"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/configs"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/cmd/server/conf"

View File

@ -65,6 +65,8 @@ export default {
loadingText: {
Upgrading: 'System upgrade, please wait...',
Restarting: 'System restart, please wait...',
Snapshoting: 'Making snapshots, please wait...',
Recovering: 'Recovering from snapshot, please wait...',
},
msg: {
delete: 'This operation cannot be rolled back. Do you want to continue',

View File

@ -68,6 +68,8 @@ export default {
loadingText: {
Upgrading: '系统升级中请稍候...',
Restarting: '系统重启中请稍候...',
Snapshoting: '制作快照中请稍候...',
Recovering: '从快照恢复中请稍候...',
},
msg: {
delete: '删除 操作不可回滚是否继续',

View File

@ -198,6 +198,7 @@ const acceptParams = (params: DialogProps): void => {
snapInfo.value = params.snapInfo;
drawerVisiable.value = true;
};
const emit = defineEmits<{ (e: 'search'): void }>();
const handleClose = () => {
drawerVisiable.value = false;
@ -207,6 +208,7 @@ const doRecover = async (isNew: boolean) => {
loading.value = true;
await snapshotRecover({ id: snapInfo.value.id, isNew: isNew, reDownload: reDownload.value })
.then(() => {
emit('search');
loading.value = false;
dialogVisiable.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
@ -235,7 +237,9 @@ const rollbackSnapshot = async () => {
loading.value = true;
await snapshotRollback({ id: snapInfo.value.id, isNew: false, reDownload: false })
.then(() => {
emit('search');
loading.value = false;
dialogVisiable.value = false;
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {