mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 20:48:42 +08:00
307 lines
8.1 KiB
Go
307 lines
8.1 KiB
Go
// Package services 备份服务
|
|
package services
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/goravel/framework/support/carbon"
|
|
|
|
"panel/app/models"
|
|
"panel/pkg/tools"
|
|
)
|
|
|
|
type Backup interface {
|
|
WebsiteList() ([]BackupFile, error)
|
|
WebSiteBackup(website models.Website) error
|
|
WebsiteRestore(website models.Website, backupFile string) error
|
|
MysqlList() ([]BackupFile, error)
|
|
MysqlBackup(database string) error
|
|
MysqlRestore(database string, backupFile string) error
|
|
PostgresqlList() ([]BackupFile, error)
|
|
PostgresqlBackup(database string) error
|
|
PostgresqlRestore(database string, backupFile string) error
|
|
}
|
|
|
|
type BackupFile struct {
|
|
Name string `json:"name"`
|
|
Size string `json:"size"`
|
|
}
|
|
|
|
type BackupImpl struct {
|
|
setting Setting
|
|
}
|
|
|
|
func NewBackupImpl() *BackupImpl {
|
|
return &BackupImpl{
|
|
setting: NewSettingImpl(),
|
|
}
|
|
}
|
|
|
|
// WebsiteList 网站备份列表
|
|
func (s *BackupImpl) WebsiteList() ([]BackupFile, error) {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath)
|
|
if len(backupPath) == 0 {
|
|
return []BackupFile{}, nil
|
|
}
|
|
|
|
backupPath += "/website"
|
|
if !tools.Exists(backupPath) {
|
|
tools.Mkdir(backupPath, 0644)
|
|
}
|
|
|
|
files, err := os.ReadDir(backupPath)
|
|
if err != nil {
|
|
return []BackupFile{}, err
|
|
}
|
|
var backupList []BackupFile
|
|
for _, file := range files {
|
|
info, err := file.Info()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
backupList = append(backupList, BackupFile{
|
|
Name: file.Name(),
|
|
Size: tools.FormatBytes(float64(info.Size())),
|
|
})
|
|
}
|
|
|
|
return backupList, nil
|
|
}
|
|
|
|
// WebSiteBackup 网站备份
|
|
func (s *BackupImpl) WebSiteBackup(website models.Website) error {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath)
|
|
if len(backupPath) == 0 {
|
|
return errors.New("未正确配置备份路径")
|
|
}
|
|
|
|
backupPath += "/website"
|
|
if !tools.Exists(backupPath) {
|
|
tools.Mkdir(backupPath, 0644)
|
|
}
|
|
|
|
backupFile := backupPath + "/" + website.Name + "_" + carbon.Now().ToShortDateTimeString() + ".zip"
|
|
tools.Exec(`cd '` + website.Path + `' && zip -r '` + backupFile + `' .`)
|
|
|
|
return nil
|
|
}
|
|
|
|
// WebsiteRestore 网站恢复
|
|
func (s *BackupImpl) WebsiteRestore(website models.Website, backupFile string) error {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath)
|
|
if len(backupPath) == 0 {
|
|
return errors.New("未正确配置备份路径")
|
|
}
|
|
|
|
backupPath += "/website"
|
|
if !tools.Exists(backupPath) {
|
|
tools.Mkdir(backupPath, 0644)
|
|
}
|
|
|
|
backupFile = backupPath + "/" + backupFile
|
|
if !tools.Exists(backupFile) {
|
|
return errors.New("备份文件不存在")
|
|
}
|
|
|
|
tools.Exec(`rm -rf '` + website.Path + `/*'`)
|
|
tools.Exec(`unzip -o '` + backupFile + `' -d '` + website.Path + `' 2>&1`)
|
|
tools.Chmod(website.Path, 0755)
|
|
tools.Chown(website.Path, "www", "www")
|
|
|
|
return nil
|
|
}
|
|
|
|
// MysqlList MySQL备份列表
|
|
func (s *BackupImpl) MysqlList() ([]BackupFile, error) {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath)
|
|
if len(backupPath) == 0 {
|
|
return []BackupFile{}, nil
|
|
}
|
|
|
|
backupPath += "/mysql"
|
|
if !tools.Exists(backupPath) {
|
|
tools.Mkdir(backupPath, 0644)
|
|
}
|
|
|
|
files, err := os.ReadDir(backupPath)
|
|
if err != nil {
|
|
return []BackupFile{}, err
|
|
}
|
|
var backupList []BackupFile
|
|
for _, file := range files {
|
|
info, err := file.Info()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
backupList = append(backupList, BackupFile{
|
|
Name: file.Name(),
|
|
Size: tools.FormatBytes(float64(info.Size())),
|
|
})
|
|
}
|
|
|
|
return backupList, nil
|
|
}
|
|
|
|
// MysqlBackup MySQL备份
|
|
func (s *BackupImpl) MysqlBackup(database string) error {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath) + "/mysql"
|
|
rootPassword := s.setting.Get(models.SettingKeyMysqlRootPassword)
|
|
backupFile := database + "_" + carbon.Now().ToShortDateTimeString() + ".sql"
|
|
if !tools.Exists(backupPath) {
|
|
tools.Mkdir(backupPath, 0644)
|
|
}
|
|
err := os.Setenv("MYSQL_PWD", rootPassword)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tools.Exec("/www/server/mysql/bin/mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile)
|
|
tools.Exec("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile)
|
|
tools.Remove(backupPath + "/" + backupFile)
|
|
_ = os.Unsetenv("MYSQL_PWD")
|
|
|
|
return nil
|
|
}
|
|
|
|
// MysqlRestore MySQL恢复
|
|
func (s *BackupImpl) MysqlRestore(database string, backupFile string) error {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath) + "/mysql"
|
|
rootPassword := s.setting.Get(models.SettingKeyMysqlRootPassword)
|
|
ext := filepath.Ext(backupFile)
|
|
backupFile = backupPath + "/" + backupFile
|
|
if !tools.Exists(backupFile) {
|
|
return errors.New("备份文件不存在")
|
|
}
|
|
|
|
err := os.Setenv("MYSQL_PWD", rootPassword)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch ext {
|
|
case ".zip":
|
|
tools.Exec("unzip -o " + backupFile + " -d " + backupPath)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
case ".gz":
|
|
if strings.HasSuffix(backupFile, ".tar.gz") {
|
|
// 解压.tar.gz文件
|
|
tools.Exec("tar -zxvf " + backupFile + " -C " + backupPath)
|
|
backupFile = strings.TrimSuffix(backupFile, ".tar.gz")
|
|
} else {
|
|
// 解压.gz文件
|
|
tools.Exec("gzip -d " + backupFile)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
}
|
|
case ".bz2":
|
|
tools.Exec("bzip2 -d " + backupFile)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
case ".tar":
|
|
tools.Exec("tar -xvf " + backupFile + " -C " + backupPath)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
case ".rar":
|
|
tools.Exec("unrar x " + backupFile + " " + backupPath)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
}
|
|
|
|
if !tools.Exists(backupFile) {
|
|
return errors.New("自动解压失败,请手动解压")
|
|
}
|
|
|
|
tools.Exec("/www/server/mysql/bin/mysql -uroot " + database + " < " + backupFile)
|
|
_ = os.Unsetenv("MYSQL_PWD")
|
|
|
|
return nil
|
|
}
|
|
|
|
// PostgresqlList PostgreSQL备份列表
|
|
func (s *BackupImpl) PostgresqlList() ([]BackupFile, error) {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath)
|
|
if len(backupPath) == 0 {
|
|
return []BackupFile{}, nil
|
|
}
|
|
|
|
backupPath += "/postgresql"
|
|
if !tools.Exists(backupPath) {
|
|
tools.Mkdir(backupPath, 0644)
|
|
}
|
|
|
|
files, err := os.ReadDir(backupPath)
|
|
if err != nil {
|
|
return []BackupFile{}, err
|
|
}
|
|
var backupList []BackupFile
|
|
for _, file := range files {
|
|
info, err := file.Info()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
backupList = append(backupList, BackupFile{
|
|
Name: file.Name(),
|
|
Size: tools.FormatBytes(float64(info.Size())),
|
|
})
|
|
}
|
|
|
|
return backupList, nil
|
|
}
|
|
|
|
// PostgresqlBackup PostgreSQL备份
|
|
func (s *BackupImpl) PostgresqlBackup(database string) error {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath) + "/postgresql"
|
|
backupFile := database + "_" + carbon.Now().ToShortDateTimeString() + ".sql"
|
|
if !tools.Exists(backupPath) {
|
|
tools.Mkdir(backupPath, 0644)
|
|
}
|
|
|
|
tools.Exec(`su - postgres -c "pg_dump ` + database + `" > ` + backupPath + "/" + backupFile)
|
|
tools.Exec("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile)
|
|
tools.Remove(backupPath + "/" + backupFile)
|
|
|
|
return nil
|
|
}
|
|
|
|
// PostgresqlRestore PostgreSQL恢复
|
|
func (s *BackupImpl) PostgresqlRestore(database string, backupFile string) error {
|
|
backupPath := s.setting.Get(models.SettingKeyBackupPath) + "/postgresql"
|
|
ext := filepath.Ext(backupFile)
|
|
backupFile = backupPath + "/" + backupFile
|
|
if !tools.Exists(backupFile) {
|
|
return errors.New("备份文件不存在")
|
|
}
|
|
|
|
switch ext {
|
|
case ".zip":
|
|
tools.Exec("unzip -o " + backupFile + " -d " + backupPath)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
case ".gz":
|
|
if strings.HasSuffix(backupFile, ".tar.gz") {
|
|
// 解压.tar.gz文件
|
|
tools.Exec("tar -zxvf " + backupFile + " -C " + backupPath)
|
|
backupFile = strings.TrimSuffix(backupFile, ".tar.gz")
|
|
} else {
|
|
// 解压.gz文件
|
|
tools.Exec("gzip -d " + backupFile)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
}
|
|
case ".bz2":
|
|
tools.Exec("bzip2 -d " + backupFile)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
case ".tar":
|
|
tools.Exec("tar -xvf " + backupFile + " -C " + backupPath)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
case ".rar":
|
|
tools.Exec("unrar x " + backupFile + " " + backupPath)
|
|
backupFile = strings.TrimSuffix(backupFile, ext)
|
|
}
|
|
|
|
if !tools.Exists(backupFile) {
|
|
return errors.New("自动解压失败,请手动解压")
|
|
}
|
|
|
|
tools.Exec(`su - postgres -c "psql ` + database + `" < ` + backupFile)
|
|
|
|
return nil
|
|
}
|