feat: add restore function

This commit is contained in:
2025-11-05 15:54:01 +01:00
parent cb3f7ddc3b
commit 494cf4bdbc
5 changed files with 209 additions and 11 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
backup/
backups/
config.yaml
compose.yaml
ddbb

1
go.mod
View File

@@ -5,7 +5,6 @@ go 1.25.2
require (
github.com/docker/docker v28.5.1+incompatible
github.com/gin-gonic/gin v1.11.0
gopkg.in/yaml.v3 v3.0.1
)
require (

8
go.sum
View File

@@ -63,10 +63,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -99,8 +95,6 @@ github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg=
github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -166,8 +160,6 @@ google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

125
pkg/backup/backup.go Normal file
View File

@@ -0,0 +1,125 @@
package backup
import (
"fmt"
"log"
"os"
"os/exec"
)
type Config struct {
Id string
Kind string
Host string
Port string
Database string
User string
Password string
}
type ConfigList struct {
Jobs []Config
}
var outFileRoot = "/backups/"
func BackupJob(job Config) {
var err error
switch kind := job.Kind; kind {
case "mariadb":
err = backupMariaDB(job)
case "postgres":
err = backupPostgres(job)
case "mongodb":
err = backupMongoDB(job)
default:
log.Printf("Invalid database kind for job %s", job.Id)
}
if err != nil {
log.Printf("%v", err)
}
}
func backupMariaDB(cfg Config) error {
log.Printf("Starting dump of mariadb database %s on %s", cfg.Database, cfg.Host)
outFileName := outFileRoot + cfg.Host + ".sql"
outFile, err := os.Create(outFileName)
if err != nil {
log.Fatalf("failed to create output file: %v", err)
return err
}
defer outFile.Close()
cmd := exec.Command(
"mariadb-dump",
"--ssl-verify-server-cert=FALSE",
"-h", cfg.Host,
"-u", cfg.User,
"-p"+cfg.Password,
"-P", cfg.Port,
cfg.Database,
)
cmd.Stdout = outFile
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatalf("Mariadb dump failed: %v", err)
return err
}
log.Printf("Database backup saved to %s", outFileName)
return nil
}
func backupPostgres(cfg Config) error {
outFileName := outFileRoot + cfg.Host + ".sql"
outFile, err := os.Create(outFileName)
if err != nil {
log.Fatalf("failed to create output file: %v", err)
return err
}
defer outFile.Close()
// Build pg_dump command
cmd := exec.Command(
"pg_dump",
"--dbname="+fmt.Sprintf("postgresql://%s:%s@%s:%s/%s", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Database),
)
cmd.Stdout = outFile
cmd.Stderr = os.Stderr
log.Printf("Running pg_dump for database %s", cfg.Database)
if err := cmd.Run(); err != nil {
log.Fatalf("pg_dump failed: %v", err)
return err
}
log.Printf("Database backup saved to %s", outFileName)
return nil
}
func backupMongoDB(cfg Config) error {
outFileName := outFileRoot + cfg.Host + ".gz"
cmd := exec.Command(
"mongodump",
"--uri",
fmt.Sprintf("mongodb://%s:%s@%s:%s/%s?authSource=admin", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Database),
"--archive="+outFileName,
"--gzip",
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Printf("Running mongodump for database %s with gzip compression to file %s", cfg.Database, outFileName)
if err := cmd.Run(); err != nil {
log.Fatalf("mongodump failed: %v", err)
return err
}
log.Printf("MongoDB backup saved to compressed archive %s", outFileName)
return nil
}

View File

@@ -2,9 +2,91 @@ package restore
import (
"ddbb/pkg/backup"
"fmt"
"log"
"os"
"os/exec"
"strings"
)
var dumFileRoot = "/backups/"
func RestoreJob(cfg backup.Config) {
log.Printf("Restore: %v, not yet implemented", cfg.Id)
switch strings.ToLower(cfg.Kind) {
case "mariadb":
restoreMySQL(cfg)
case "postgres":
restorePostgres(cfg)
case "mongodb":
restoreMongo(cfg)
default:
log.Printf("unsupported database kind: %s", cfg.Kind)
}
}
func restoreMySQL(cfg backup.Config) error {
cmd := exec.Command(
"mysql", "-h", cfg.Host, "-u", cfg.User, fmt.Sprintf("-p%s", cfg.Password),
cfg.Database,
)
dumpFileName := dumFileRoot + cfg.Host + ".sql"
dumpFile, err := os.Open(dumpFileName)
if err != nil {
return err
}
defer dumpFile.Close()
cmd.Stdin = dumpFile
output, err := cmd.CombinedOutput()
if err != nil {
log.Printf("mysql restore failed: %s, output: %s", err, output)
return err
}
log.Printf("Restore job with ID %s completed successfully", cfg.Id)
return nil
}
func restorePostgres(cfg backup.Config) error {
cmd := exec.Command(
"psql", "-h", cfg.Host, "-U", cfg.User, "-d", cfg.Database,
"-f", "-", // read input from stdin
)
dumpFileName := dumFileRoot + cfg.Host + ".sql"
dumpFile, err := os.Open(dumpFileName)
if err != nil {
return err
}
defer dumpFile.Close()
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", cfg.Password))
cmd.Stdin = dumpFile
output, err := cmd.CombinedOutput()
if err != nil {
log.Printf("postgres restore failed: %s, output: %s", err, output)
return err
}
log.Printf("Restore job with ID %s completed successfully", cfg.Id)
return nil
}
func restoreMongo(cfg backup.Config) error {
dumpFileName := dumFileRoot + cfg.Host + ".sql"
cmd := exec.Command(
"mongorestore", "--gzip", "--drop", "--archive="+dumpFileName,
"--host", cfg.Host,
"--username", cfg.User,
"--password", cfg.Password,
"--db", cfg.Database,
)
output, err := cmd.CombinedOutput()
if err != nil {
log.Printf("mongodb restore failed: %s, output: %s", err, output)
return err
}
log.Printf("Restore job with ID %s completed successfully", cfg.Id)
return nil
}