初始化2

This commit is contained in:
2026-07-10 17:33:33 +08:00
parent b51ee98afa
commit 94f6ecf901
59 changed files with 3893 additions and 980 deletions

View File

@@ -197,23 +197,25 @@ func (s *BackupService) doBackup(policy *model.BackupPolicy, log *model.BackupLo
s.cleanOldBackups(policy)
}
// backupDatabase 备份数据库
// backupDatabase 备份数据库(根据数据库类型选择工具)
func (s *BackupService) backupDatabase(tarWriter *tar.Writer, timestamp string) (int64, error) {
dbCfg := config.AppConfig.Database
dumpFile := filepath.Join(os.TempDir(), fmt.Sprintf("db_dump_%s.sql", timestamp))
mysqldumpPath := s.findTool("mysqldump", config.AppConfig.Backup.MysqlDumpPath)
var dumpFile string
var cmd *exec.Cmd
var err error
cmd := exec.Command(mysqldumpPath,
"-h", dbCfg.Host,
"-P", fmt.Sprintf("%d", dbCfg.Port),
"-u", dbCfg.Username,
"-p"+dbCfg.Password,
"--single-transaction",
"--routines",
"--triggers",
dbCfg.DBName,
)
switch dbCfg.Type {
case "sqlserver":
dumpFile, cmd, err = s.buildSQLServerDump(dbCfg, timestamp)
case "postgres":
dumpFile, cmd, err = s.buildPostgresDump(dbCfg, timestamp)
default:
dumpFile, cmd, err = s.buildMySQLDump(dbCfg, timestamp)
}
if err != nil {
return 0, err
}
outFile, err := os.Create(dumpFile)
if err != nil {
@@ -225,18 +227,16 @@ func (s *BackupService) backupDatabase(tarWriter *tar.Writer, timestamp string)
if err := cmd.Run(); err != nil {
outFile.Close()
os.Remove(dumpFile)
return 0, fmt.Errorf("mysqldump执行失败: %w", err)
return 0, fmt.Errorf("数据库备份命令执行失败: %w", err)
}
outFile.Close()
// 获取文件大小
info, _ := os.Stat(dumpFile)
dbSize := int64(0)
if info != nil {
dbSize = info.Size()
}
// 写入tar
file, err := os.Open(dumpFile)
if err != nil {
os.Remove(dumpFile)
@@ -264,6 +264,51 @@ func (s *BackupService) backupDatabase(tarWriter *tar.Writer, timestamp string)
return dbSize, nil
}
// buildMySQLDump 构建 mysqldump 命令
func (s *BackupService) buildMySQLDump(dbCfg config.DatabaseConfig, timestamp string) (string, *exec.Cmd, error) {
dumpFile := filepath.Join(os.TempDir(), fmt.Sprintf("db_dump_%s.sql", timestamp))
mysqldumpPath := s.findTool("mysqldump", config.AppConfig.Backup.MysqlDumpPath)
cmd := exec.Command(mysqldumpPath,
"-h", dbCfg.Host,
"-P", fmt.Sprintf("%d", dbCfg.Port),
"-u", dbCfg.Username,
"-p"+dbCfg.Password,
"--single-transaction", "--routines", "--triggers",
dbCfg.DBName,
)
return dumpFile, cmd, nil
}
// buildPostgresDump 构建 pg_dump 命令
func (s *BackupService) buildPostgresDump(dbCfg config.DatabaseConfig, timestamp string) (string, *exec.Cmd, error) {
dumpFile := filepath.Join(os.TempDir(), fmt.Sprintf("db_dump_%s.sql", timestamp))
pgDumpPath := s.findTool("pg_dump", config.AppConfig.Backup.PgDumpPath)
cmd := exec.Command(pgDumpPath,
"-h", dbCfg.Host,
"-p", fmt.Sprintf("%d", dbCfg.Port),
"-U", dbCfg.Username,
"-F", "p", // plain text SQL
"--no-owner",
dbCfg.DBName,
)
cmd.Env = append(os.Environ(), "PGPASSWORD="+dbCfg.Password)
return dumpFile, cmd, nil
}
// buildSQLServerDump 构建 sqlcmd 导出命令
func (s *BackupService) buildSQLServerDump(dbCfg config.DatabaseConfig, timestamp string) (string, *exec.Cmd, error) {
dumpFile := filepath.Join(os.TempDir(), fmt.Sprintf("db_dump_%s.sql", timestamp))
sqlCmdPath := s.findTool("sqlcmd", config.AppConfig.Backup.SqlCmdPath)
cmd := exec.Command(sqlCmdPath,
"-S", fmt.Sprintf("%s,%d", dbCfg.Host, dbCfg.Port),
"-U", dbCfg.Username,
"-P", dbCfg.Password,
"-d", dbCfg.DBName,
"-Q", fmt.Sprintf("BACKUP DATABASE [%s] TO DISK='%s' WITH FORMAT", dbCfg.DBName, dumpFile),
)
return dumpFile, cmd, nil
}
// backupFiles 备份文件
func (s *BackupService) backupFiles(tarWriter *tar.Writer) (int64, int, error) {
basePath := config.AppConfig.Storage.LocalBasePath
@@ -525,12 +570,23 @@ func (s *BackupService) extractTarGz(tarGzPath, destDir string) error {
return nil
}
// restoreDatabase 从SQL文件恢复数据库
// restoreDatabase 从SQL文件恢复数据库(根据数据库类型选择工具)
func (s *BackupService) restoreDatabase(sqlFilePath string) error {
dbCfg := config.AppConfig.Database
mysqlPath := s.findTool("mysql", config.AppConfig.Backup.MysqlPath)
switch dbCfg.Type {
case "postgres":
return s.restorePostgres(dbCfg, sqlFilePath)
case "sqlserver":
return s.restoreSQLServer(dbCfg, sqlFilePath)
default:
return s.restoreMySQL(dbCfg, sqlFilePath)
}
}
// restoreMySQL mysql恢复
func (s *BackupService) restoreMySQL(dbCfg config.DatabaseConfig, sqlFilePath string) error {
mysqlPath := s.findTool("mysql", config.AppConfig.Backup.MysqlPath)
cmd := exec.Command(mysqlPath,
"-h", dbCfg.Host,
"-P", fmt.Sprintf("%d", dbCfg.Port),
@@ -538,16 +594,42 @@ func (s *BackupService) restoreDatabase(sqlFilePath string) error {
"-p"+dbCfg.Password,
dbCfg.DBName,
)
sqlFile, err := os.Open(sqlFilePath)
if err != nil {
return err
}
defer sqlFile.Close()
cmd.Stdin = sqlFile
cmd.Stderr = os.Stderr
return cmd.Run()
}
// restorePostgres psql恢复
func (s *BackupService) restorePostgres(dbCfg config.DatabaseConfig, sqlFilePath string) error {
psqlPath := s.findTool("psql", config.AppConfig.Backup.PsqlPath)
cmd := exec.Command(psqlPath,
"-h", dbCfg.Host,
"-p", fmt.Sprintf("%d", dbCfg.Port),
"-U", dbCfg.Username,
"-d", dbCfg.DBName,
"-f", sqlFilePath,
)
cmd.Env = append(os.Environ(), "PGPASSWORD="+dbCfg.Password)
cmd.Stderr = os.Stderr
return cmd.Run()
}
// restoreSQLServer sqlcmd恢复
func (s *BackupService) restoreSQLServer(dbCfg config.DatabaseConfig, sqlFilePath string) error {
sqlCmdPath := s.findTool("sqlcmd", config.AppConfig.Backup.SqlCmdPath)
cmd := exec.Command(sqlCmdPath,
"-S", fmt.Sprintf("%s,%d", dbCfg.Host, dbCfg.Port),
"-U", dbCfg.Username,
"-P", dbCfg.Password,
"-d", dbCfg.DBName,
"-i", sqlFilePath,
)
cmd.Stderr = os.Stderr
return cmd.Run()
}