mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-27 00:00:14 +00:00
190 lines
6.0 KiB
Go
190 lines
6.0 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/1Panel-dev/1Panel/core/global"
|
|
"github.com/1Panel-dev/1Panel/core/i18n"
|
|
cmdUtils "github.com/1Panel-dev/1Panel/core/utils/cmd"
|
|
"github.com/1Panel-dev/1Panel/core/utils/common"
|
|
"github.com/1Panel-dev/1Panel/core/utils/controller"
|
|
"github.com/1Panel-dev/1Panel/core/utils/ctl_conf"
|
|
"github.com/1Panel-dev/1Panel/core/utils/files"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func init() {
|
|
RootCmd.AddCommand(restoreCmd)
|
|
}
|
|
|
|
var restoreCmd = &cobra.Command{
|
|
Use: "restore",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
i18n.UseI18nForCmd(language)
|
|
if !isRoot() {
|
|
fmt.Println(i18n.GetMsgWithMapForCmd("SudoHelper", map[string]interface{}{"cmd": "sudo 1pctl restore"}))
|
|
return nil
|
|
}
|
|
baseDir, err := ctl_conf.LoadFromFile("/usr/local/bin/1pctl", "BASE_DIR")
|
|
if err != nil {
|
|
return fmt.Errorf("handle load `BASE_DIR` failed, err: %v", err)
|
|
}
|
|
upgradeDir := path.Join(baseDir, "1panel", "tmp", "upgrade")
|
|
|
|
tmpPath, err := loadRestorePath(upgradeDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if tmpPath == "no such file" {
|
|
fmt.Println(i18n.GetMsgByKeyForCmd("RestoreNoSuchFile"))
|
|
return nil
|
|
}
|
|
tmpPath = path.Join(upgradeDir, tmpPath, "original")
|
|
|
|
fmt.Println(i18n.GetMsgWithMapForCmd("RestoreStep1", map[string]interface{}{"name": tmpPath}))
|
|
if err := files.CopyItem(false, true, path.Join(tmpPath, "1panel-agent"), "/usr/local/bin"); err != nil {
|
|
return err
|
|
}
|
|
if err := files.CopyItem(false, true, path.Join(tmpPath, "1panel-core"), "/usr/local/bin"); err != nil {
|
|
return err
|
|
}
|
|
if err := files.CopyItem(true, true, path.Join(tmpPath, "lang"), "/usr/local/bin"); err != nil {
|
|
return err
|
|
}
|
|
if err := files.CopyItem(false, true, path.Join(tmpPath, "GeoIP.mmdb"), path.Join(baseDir, "1panel/geo")); err != nil {
|
|
return err
|
|
}
|
|
_, _ = cmdUtils.NewCommandMgr().RunWithStdout("chmod", "755", "/usr/local/bin/1panel-agent", "/usr/local/bin/1panel-core")
|
|
|
|
fmt.Println(i18n.GetMsgByKeyForCmd("RestoreStep2"))
|
|
if err := files.CopyItem(false, true, path.Join(tmpPath, "1pctl"), "/usr/local/bin"); err != nil {
|
|
return err
|
|
}
|
|
_, _ = cmdUtils.NewCommandMgr().RunWithStdout("chmod", "755", "/usr/local/bin/1pctl")
|
|
_, _ = cmdUtils.NewCommandMgr().RunWithStdout("cp", "-r", path.Join(tmpPath, "lang"), "/usr/local/bin")
|
|
geoPath := path.Join(global.CONF.Base.InstallDir, "1panel/geo")
|
|
_ = os.MkdirAll(geoPath, os.ModePerm)
|
|
_, _ = cmdUtils.NewCommandMgr().RunWithStdout("cp", path.Join(tmpPath, "GeoIP.mmdb"), geoPath+"/")
|
|
|
|
fmt.Println(i18n.GetMsgByKeyForCmd("RestoreStep3"))
|
|
svcBasePath, _ := controller.GetServicePath("")
|
|
svcCoreName, _ := controller.LoadServiceName("1panel-core")
|
|
selCoreName, _ := controller.SelectInitScript("1panel-core")
|
|
scriptCoreName, _ := controller.GetScriptName("1panel-core")
|
|
svcAgentName, _ := controller.LoadServiceName("1panel-agent")
|
|
selAgentName, _ := controller.SelectInitScript("1panel-agent")
|
|
scriptAgentName, _ := controller.GetScriptName("1panel-agent")
|
|
if err := files.CopyItem(false, true, path.Join(tmpPath, svcCoreName), svcBasePath); err != nil {
|
|
if err := files.CopyItem(false, true, path.Join(tmpPath, selCoreName), path.Join(svcBasePath, scriptCoreName)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := files.CopyItem(false, true, path.Join(tmpPath, svcAgentName), svcBasePath); err != nil {
|
|
if err := files.CopyItem(false, true, path.Join(tmpPath, selAgentName), path.Join(svcBasePath, scriptAgentName)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
fmt.Println(i18n.GetMsgByKeyForCmd("RestoreStep4"))
|
|
if _, err := os.Stat(path.Join(tmpPath, "db")); err == nil {
|
|
if err := os.Chmod(path.Join(tmpPath, "db"), 0700); err != nil {
|
|
return err
|
|
}
|
|
dbPath := path.Join(baseDir, "1panel")
|
|
targetDBDir := path.Join(dbPath, "db")
|
|
if err := os.RemoveAll(targetDBDir); err != nil {
|
|
global.LOG.Errorf("rollback 1panel db cleanup failed, err: %v", err)
|
|
}
|
|
if err := files.CopyItem(true, true, path.Join(tmpPath, "db"), dbPath); err != nil {
|
|
global.LOG.Errorf("rollback 1panel db failed, err: %v", err)
|
|
}
|
|
if err := cleanOrphanSQLiteSidecars(targetDBDir); err != nil {
|
|
global.LOG.Errorf("rollback 1panel db sidecar cleanup failed, err: %v", err)
|
|
}
|
|
}
|
|
|
|
fmt.Println(i18n.GetMsgByKeyForCmd("RestoreStep5"))
|
|
version := loadRollbackVersion(tmpPath)
|
|
fmt.Println(i18n.GetMsgWithMapForCmd("RestoreSuccessful", map[string]interface{}{"version": version}))
|
|
|
|
controller.RestartPanel(true, true, true)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func loadRestorePath(upgradeDir string) (string, error) {
|
|
if _, err := os.Stat(upgradeDir); err != nil && os.IsNotExist(err) {
|
|
return "no such file", nil
|
|
}
|
|
files, err := os.ReadDir(upgradeDir)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
var folders []string
|
|
for _, file := range files {
|
|
if file.IsDir() {
|
|
folders = append(folders, file.Name())
|
|
}
|
|
}
|
|
if len(folders) == 0 {
|
|
return "no such file", nil
|
|
}
|
|
sort.Slice(folders, func(i, j int) bool {
|
|
return common.ComparePanelVersion(folders[i], folders[j])
|
|
})
|
|
return folders[0], nil
|
|
}
|
|
|
|
func loadRollbackVersion(upgradeDir string) string {
|
|
info, err := ctl_conf.LoadFromFile(path.Join(upgradeDir, "1pctl"), "ORIGINAL_VERSION")
|
|
if err != nil {
|
|
return "-"
|
|
}
|
|
if len(info) == 0 || info == `""` {
|
|
return "-"
|
|
}
|
|
return info
|
|
}
|
|
|
|
func cleanOrphanSQLiteSidecars(dbDir string) error {
|
|
entries, err := os.ReadDir(dbDir)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
if entry.IsDir() {
|
|
continue
|
|
}
|
|
|
|
name := entry.Name()
|
|
var mainDB string
|
|
switch {
|
|
case strings.HasSuffix(name, ".db-wal"):
|
|
mainDB = strings.TrimSuffix(name, "-wal")
|
|
case strings.HasSuffix(name, ".db-shm"):
|
|
mainDB = strings.TrimSuffix(name, "-shm")
|
|
default:
|
|
continue
|
|
}
|
|
|
|
if _, statErr := os.Stat(path.Join(dbDir, mainDB)); statErr != nil {
|
|
if !os.IsNotExist(statErr) {
|
|
return statErr
|
|
}
|
|
if removeErr := os.Remove(path.Join(dbDir, name)); removeErr != nil && !os.IsNotExist(removeErr) {
|
|
return removeErr
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|