mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-06 15:22:47 +01:00
Release catalyst
This commit is contained in:
149
backup.go
Normal file
149
backup.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package catalyst
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/storage"
|
||||
)
|
||||
|
||||
func BackupHandler(catalystStorage *storage.Storage, c *database.Config) gin.HandlerFunc {
|
||||
return func(context *gin.Context) {
|
||||
context.Header("Content-Disposition", "attachment; filename=backup.zip")
|
||||
context.Header("Content-Type", "application/zip")
|
||||
err := Backup(catalystStorage, c, context.Writer)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
context.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type WriterAtBuffer struct {
|
||||
bytes.Buffer
|
||||
}
|
||||
|
||||
func (fw WriterAtBuffer) WriteAt(p []byte, offset int64) (n int, err error) {
|
||||
return fw.Write(p)
|
||||
}
|
||||
|
||||
func Backup(catalystStorage *storage.Storage, c *database.Config, writer io.Writer) error {
|
||||
archive := zip.NewWriter(writer)
|
||||
defer archive.Close()
|
||||
|
||||
archive.SetComment(GetVersion())
|
||||
|
||||
// S3
|
||||
if err := backupS3(catalystStorage, archive); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Arango
|
||||
return backupArango(c, archive)
|
||||
}
|
||||
|
||||
func backupS3(catalystStorage *storage.Storage, archive *zip.Writer) error {
|
||||
buckets, err := catalystStorage.S3().ListBuckets(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, bucket := range buckets.Buckets {
|
||||
objects, err := catalystStorage.S3().ListObjectsV2(&s3.ListObjectsV2Input{
|
||||
Bucket: bucket.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, content := range objects.Contents {
|
||||
rbuf := &WriterAtBuffer{}
|
||||
_, err := catalystStorage.Downloader().Download(rbuf, &s3.GetObjectInput{
|
||||
Bucket: bucket.Name,
|
||||
Key: content.Key,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, err := archive.Create(path.Join("minio", *bucket.Name, *content.Key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(a, rbuf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func backupArango(c *database.Config, archive *zip.Writer) error {
|
||||
dir, err := os.MkdirTemp("", "catalyst-backup")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
if err := arangodump(dir, c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return zipDump(dir, archive)
|
||||
}
|
||||
|
||||
func zipDump(dir string, archive *zip.Writer) error {
|
||||
fsys := os.DirFS(dir)
|
||||
return fs.WalkDir(fsys, ".", func(p string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
a, err := archive.Create(path.Join("arango", p))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := fsys.Open(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(a, f); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func arangodump(dir string, config *database.Config) error {
|
||||
host := strings.Replace(config.Host, "http", "tcp", 1)
|
||||
|
||||
name := config.Name
|
||||
if config.Name == "" {
|
||||
name = database.Name
|
||||
}
|
||||
args := []string{
|
||||
"--output-directory", dir, "--server.endpoint", host,
|
||||
"--server.username", config.User, "--server.password", config.Password,
|
||||
"--server.database", name,
|
||||
}
|
||||
cmd := exec.Command("arangodump", args...)
|
||||
return cmd.Run()
|
||||
}
|
||||
Reference in New Issue
Block a user