mirror of
https://github.com/eiblog/eiblog.git
synced 2026-03-01 00:34:58 +08:00
chore: update backup
This commit is contained in:
@@ -35,11 +35,11 @@ func init() {
|
|||||||
logrus.Infof("Run mode:%s", mode)
|
logrus.Infof("Run mode:%s", mode)
|
||||||
|
|
||||||
// 加载配置文件
|
// 加载配置文件
|
||||||
dir, err := config.WalkWorkDir()
|
etc, err := config.WorkEtcPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
path := filepath.Join(dir, "etc", "app.yml")
|
path := filepath.Join(etc, "app.yml")
|
||||||
|
|
||||||
data, err := os.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
7
cmd/backup/handler/timer/db/db.go
Normal file
7
cmd/backup/handler/timer/db/db.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
// Storage 备份恢复器
|
||||||
|
type Storage interface {
|
||||||
|
Backup(name string) (string, error)
|
||||||
|
Restore(path string) error
|
||||||
|
}
|
||||||
72
cmd/backup/handler/timer/db/mgodb.go
Normal file
72
cmd/backup/handler/timer/db/mgodb.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/eiblog/eiblog/cmd/backup/config"
|
||||||
|
"github.com/eiblog/eiblog/pkg/connector/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MongoStorage 备份恢复器
|
||||||
|
type MongoStorage struct{}
|
||||||
|
|
||||||
|
// Backup 备份
|
||||||
|
func (r MongoStorage) Backup(name string) (string, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// dump
|
||||||
|
u, err := url.Parse(config.Conf.Database.Source)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
arg := fmt.Sprintf("mongodump -h %s -d eiblog -o /tmp", u.Host)
|
||||||
|
cmd := exec.CommandContext(ctx, "sh", "-c", arg)
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// tar
|
||||||
|
arg = fmt.Sprintf("tar czf /tmp/%s -C /tmp eiblog", name)
|
||||||
|
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return "/tmp/" + name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore 恢复
|
||||||
|
func (r MongoStorage) Restore(path string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// drop database
|
||||||
|
mdb, err := db.NewMDB(config.Conf.Database)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = mdb.Drop(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// unarchive
|
||||||
|
arg := fmt.Sprintf("tar xzf %s -C /tmp", path)
|
||||||
|
cmd := exec.CommandContext(ctx, "sh", "-c", arg)
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// restore
|
||||||
|
u, err := url.Parse(config.Conf.Database.Source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
arg = fmt.Sprintf("mongorestore -h %s -d eiblog /tmp/eiblog", u.Host)
|
||||||
|
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
package qiniu
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/eiblog/eiblog/cmd/backup/config"
|
|
||||||
"github.com/eiblog/eiblog/cmd/backup/handler/internal"
|
|
||||||
"github.com/eiblog/eiblog/pkg/connector/db"
|
|
||||||
"github.com/eiblog/eiblog/pkg/third/qiniu"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BackupRestorer qiniu backup restorer
|
|
||||||
type BackupRestorer struct{}
|
|
||||||
|
|
||||||
// Backup implements timer.BackupRestorer
|
|
||||||
func (s BackupRestorer) Backup(now time.Time) error {
|
|
||||||
switch config.Conf.Database.Driver {
|
|
||||||
case "mongodb":
|
|
||||||
return backupFromMongoDB(now)
|
|
||||||
default:
|
|
||||||
return errors.New("unsupported source backup to qiniu: " +
|
|
||||||
config.Conf.Database.Driver)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore implements timer.BackupRestorer
|
|
||||||
func (s BackupRestorer) Restore() error {
|
|
||||||
switch config.Conf.Database.Driver {
|
|
||||||
case "mongodb":
|
|
||||||
return restoreToMongoDB()
|
|
||||||
default:
|
|
||||||
return errors.New("unsupported source restore from qiniu: " +
|
|
||||||
config.Conf.Database.Driver)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func backupFromMongoDB(now time.Time) error {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*20)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// dump
|
|
||||||
u, err := url.Parse(config.Conf.Database.Source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
arg := fmt.Sprintf("mongodump -h %s -d eiblog -o /tmp", u.Host)
|
|
||||||
cmd := exec.CommandContext(ctx, "sh", "-c", arg)
|
|
||||||
err = cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// tar
|
|
||||||
name := fmt.Sprintf("eiblog-%s.tar.gz", now.Format("2006-01-02"))
|
|
||||||
arg = fmt.Sprintf("tar czf /tmp/%s -C /tmp eiblog", name)
|
|
||||||
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
|
|
||||||
err = cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// upload file
|
|
||||||
f, err := os.Open("/tmp/" + name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s, err := f.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
uploadParams := qiniu.UploadParams{
|
|
||||||
Name: filepath.Join("blog", name), // blog/eiblog-xx.tar.gz
|
|
||||||
Size: s.Size(),
|
|
||||||
Data: f,
|
|
||||||
NoCompletePath: true,
|
|
||||||
}
|
|
||||||
_, err = internal.QiniuClient.Upload(uploadParams)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// after days delete
|
|
||||||
deleteParams := qiniu.DeleteParams{
|
|
||||||
Name: filepath.Join("blog", name), // blog/eiblog-xx.tar.gz
|
|
||||||
Days: config.Conf.Validity,
|
|
||||||
NoCompletePath: true,
|
|
||||||
}
|
|
||||||
return internal.QiniuClient.Delete(deleteParams)
|
|
||||||
}
|
|
||||||
|
|
||||||
func restoreToMongoDB() error {
|
|
||||||
// backup file
|
|
||||||
params := qiniu.ContentParams{
|
|
||||||
Prefix: "blog/",
|
|
||||||
}
|
|
||||||
raw, err := internal.QiniuClient.Content(params)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f, err := os.OpenFile("/tmp/eiblog.tar.gz", os.O_WRONLY|os.O_CREATE, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, _ = f.Write(raw)
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*20)
|
|
||||||
defer cancel()
|
|
||||||
// drop database
|
|
||||||
mdb, err := db.NewMDB(config.Conf.Database)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = mdb.Drop(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// unarchive
|
|
||||||
arg := "tar xzf /tmp/eiblog.tar.gz -C /tmp"
|
|
||||||
cmd := exec.CommandContext(ctx, "sh", "-c", arg)
|
|
||||||
err = cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// restore
|
|
||||||
u, err := url.Parse(config.Conf.Database.Source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
arg = fmt.Sprintf("mongorestore -h %s -d eiblog /tmp/eiblog", u.Host)
|
|
||||||
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
@@ -2,49 +2,71 @@ package timer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/eiblog/eiblog/cmd/backup/config"
|
"github.com/eiblog/eiblog/cmd/backup/config"
|
||||||
"github.com/eiblog/eiblog/cmd/backup/handler/timer/qiniu"
|
"github.com/eiblog/eiblog/cmd/backup/handler/timer/db"
|
||||||
|
"github.com/eiblog/eiblog/cmd/backup/handler/timer/to"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BackupRestorer 备份恢复器
|
|
||||||
type BackupRestorer interface {
|
|
||||||
Backup(now time.Time) error
|
|
||||||
Restore() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start to backup with ticker
|
// Start to backup with ticker
|
||||||
func Start(restore bool) (err error) {
|
func Start(restore bool) (err error) {
|
||||||
var storage BackupRestorer
|
var (
|
||||||
|
storage db.Storage
|
||||||
|
backupTo to.BackupRestorer
|
||||||
|
)
|
||||||
|
|
||||||
// backup instance
|
// backup from
|
||||||
|
switch config.Conf.Database.Driver {
|
||||||
|
case "mongodb":
|
||||||
|
storage = db.MongoStorage{}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return errors.New("timer: unknown backup from driver: " +
|
||||||
|
config.Conf.Database.Driver)
|
||||||
|
}
|
||||||
|
|
||||||
|
// backup to
|
||||||
switch config.Conf.BackupTo {
|
switch config.Conf.BackupTo {
|
||||||
case "qiniu":
|
case "qiniu":
|
||||||
storage = qiniu.BackupRestorer{}
|
backupTo = to.QiniuBackupRestorer{}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return errors.New("timer: unknown backup to driver: " +
|
return errors.New("timer: unknown backup to driver: " +
|
||||||
config.Conf.BackupTo)
|
config.Conf.BackupTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore
|
||||||
if restore {
|
if restore {
|
||||||
err = storage.Restore()
|
path, err := backupTo.Download()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = storage.Restore(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logrus.Info("timer: Restore success")
|
logrus.Info("timer: Restore success")
|
||||||
}
|
}
|
||||||
// parse duration
|
|
||||||
|
// backup
|
||||||
interval, err := ParseDuration(config.Conf.Interval)
|
interval, err := ParseDuration(config.Conf.Interval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
t := time.NewTicker(interval)
|
t := time.NewTicker(interval)
|
||||||
for now := range t.C {
|
for now := range t.C {
|
||||||
err = storage.Backup(now)
|
name := fmt.Sprintf("eiblog-%s.tar.gz", now.Format("2006-01-02"))
|
||||||
|
path, err := storage.Backup(name)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("timer: Start.Backup: ", now.Format(time.RFC3339), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = backupTo.Upload(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error("timer: Start.Backup: ", now.Format(time.RFC3339), err)
|
logrus.Error("timer: Start.Backup: ", now.Format(time.RFC3339), err)
|
||||||
}
|
}
|
||||||
|
|||||||
66
cmd/backup/handler/timer/to/qiniu.go
Normal file
66
cmd/backup/handler/timer/to/qiniu.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package to
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/eiblog/eiblog/cmd/backup/config"
|
||||||
|
"github.com/eiblog/eiblog/cmd/backup/handler/internal"
|
||||||
|
"github.com/eiblog/eiblog/pkg/third/qiniu"
|
||||||
|
)
|
||||||
|
|
||||||
|
// QiniuBackupRestorer qiniu backup restorer
|
||||||
|
type QiniuBackupRestorer struct{}
|
||||||
|
|
||||||
|
// Upload implements timer.BackupRestorer
|
||||||
|
func (s QiniuBackupRestorer) Upload(path string) error {
|
||||||
|
name := filepath.Base(path)
|
||||||
|
|
||||||
|
// upload file
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
uploadParams := qiniu.UploadParams{
|
||||||
|
Name: filepath.Join("blog", name), // blog/eiblog-xx.tar.gz
|
||||||
|
Size: fi.Size(),
|
||||||
|
Data: f,
|
||||||
|
NoCompletePath: true,
|
||||||
|
}
|
||||||
|
_, err = internal.QiniuClient.Upload(uploadParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// after days delete
|
||||||
|
deleteParams := qiniu.DeleteParams{
|
||||||
|
Name: filepath.Join("blog", name), // blog/eiblog-xx.tar.gz
|
||||||
|
Days: config.Conf.Validity,
|
||||||
|
NoCompletePath: true,
|
||||||
|
}
|
||||||
|
return internal.QiniuClient.Delete(deleteParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download implements timer.BackupRestorer
|
||||||
|
func (s QiniuBackupRestorer) Download() (string, error) {
|
||||||
|
// backup file
|
||||||
|
params := qiniu.ContentParams{
|
||||||
|
Prefix: "blog/",
|
||||||
|
}
|
||||||
|
raw, err := internal.QiniuClient.Content(params)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
path := filepath.Join("/tmp", "eiblog.tar.gz")
|
||||||
|
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
_, _ = f.Write(raw)
|
||||||
|
defer f.Close()
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
7
cmd/backup/handler/timer/to/to.go
Normal file
7
cmd/backup/handler/timer/to/to.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package to
|
||||||
|
|
||||||
|
// BackupRestorer 备份存储接口
|
||||||
|
type BackupRestorer interface {
|
||||||
|
Upload(path string) error
|
||||||
|
Download() (path string, err error)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user