diff options
author | Steve Manuel <nilslice@gmail.com> | 2017-06-26 16:33:41 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-26 16:33:41 -0700 |
commit | 08bab226d6b998eb5cf87e4be1db45e89fb9f772 (patch) | |
tree | aba0be8dbd8c0ed630439a302fffcf5c078eeb21 /system | |
parent | cd6be5ebe16f3ee815e12d3022dfb79e4163d867 (diff) | |
parent | 0a1d7d9cd8ad1ac01c8fcd4d3b4fef57cffd4cb0 (diff) |
Merge pull request #168 from tom-f/ponzu-dev
Add backup routine to search
Diffstat (limited to 'system')
-rw-r--r-- | system/admin/handlers.go | 9 | ||||
-rw-r--r-- | system/admin/upload/backup.go | 91 | ||||
-rw-r--r-- | system/backup/archive.go | 95 | ||||
-rw-r--r-- | system/search/backup.go | 57 |
4 files changed, 168 insertions, 84 deletions
diff --git a/system/admin/handlers.go b/system/admin/handlers.go index 0700003..c70dd86 100644 --- a/system/admin/handlers.go +++ b/system/admin/handlers.go @@ -23,6 +23,7 @@ import ( "github.com/ponzu-cms/ponzu/system/api/analytics" "github.com/ponzu-cms/ponzu/system/db" "github.com/ponzu-cms/ponzu/system/item" + "github.com/ponzu-cms/ponzu/system/search" "github.com/gorilla/schema" emailer "github.com/nilslice/email" @@ -224,6 +225,14 @@ func backupHandler(res http.ResponseWriter, req *http.Request) { return } + case "search": + err := search.Backup(ctx, res) + if err != nil { + log.Println("Failed to run backup on search:", err) + res.WriteHeader(http.StatusInternalServerError) + return + } + default: res.WriteHeader(http.StatusBadRequest) } diff --git a/system/admin/upload/backup.go b/system/admin/upload/backup.go index b4f6393..9dc9e31 100644 --- a/system/admin/upload/backup.go +++ b/system/admin/upload/backup.go @@ -1,8 +1,6 @@ package upload import ( - "archive/tar" - "compress/gzip" "context" "fmt" "io" @@ -10,6 +8,8 @@ import ( "os" "path/filepath" "time" + + "github.com/ponzu-cms/ponzu/system/backup" ) // Backup creates an archive of a project's uploads and writes it @@ -18,105 +18,28 @@ func Backup(ctx context.Context, res http.ResponseWriter) error { ts := time.Now().Unix() filename := fmt.Sprintf("uploads-%d.bak.tar.gz", ts) tmp := os.TempDir() - backup := filepath.Join(tmp, filename) + bk := filepath.Join(tmp, filename) // create uploads-{stamp}.bak.tar.gz - f, err := os.Create(backup) + f, err := os.Create(bk) if err != nil { return err } - // loop through directory and gzip files - // add all to uploads.bak.tar.gz tarball - gz := gzip.NewWriter(f) - tarball := tar.NewWriter(gz) - - errChan := make(chan error, 1) - walkFn := func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - hdr, err := tar.FileInfoHeader(info, "") - if err != nil { - return err - } - - hdr.Name = path - - err = tarball.WriteHeader(hdr) - if err != nil { - return err - } - - if !info.IsDir() { - src, err := os.Open(path) - if err != nil { - return err - } - defer src.Close() - - _, err = io.Copy(tarball, src) - if err != nil { - return err - } - - err = tarball.Flush() - if err != nil { - return err - } - - err = gz.Flush() - if err != nil { - return err - } - } - - return nil - } - - // stop processing if we get a cancellation signal - err = filepath.Walk("uploads", func(path string, info os.FileInfo, err error) error { - go func() { errChan <- walkFn(path, info, err) }() + err = backup.ArchiveFS(ctx, "uploads", f) - select { - case <-ctx.Done(): - if err := ctx.Err(); err != nil { - return err - } - case err := <-errChan: - if err != nil { - return err - } - } - - return nil - }) - if err != nil { - fmt.Println(err) - return err - } - - err = gz.Close() - if err != nil { - return err - } - err = tarball.Close() - if err != nil { - return err - } err = f.Close() if err != nil { return err } // write data to response - data, err := os.Open(backup) + data, err := os.Open(bk) if err != nil { return err } defer data.Close() - defer os.Remove(backup) + defer os.Remove(bk) disposition := `attachment; filename=%s` info, err := data.Stat() diff --git a/system/backup/archive.go b/system/backup/archive.go new file mode 100644 index 0000000..0a8b964 --- /dev/null +++ b/system/backup/archive.go @@ -0,0 +1,95 @@ +package backup + +import ( + "archive/tar" + "compress/gzip" + "context" + "fmt" + "io" + "os" + "path/filepath" +) + +// ArchiveFS walks the filesystem starting from basedir writing files encountered +// tarred and gzipped to the provided writer +func ArchiveFS(ctx context.Context, basedir string, w io.Writer) error { + gz := gzip.NewWriter(w) + tarball := tar.NewWriter(gz) + + errChan := make(chan error, 1) + walkFn := func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + hdr, err := tar.FileInfoHeader(info, "") + if err != nil { + return err + } + + hdr.Name = path + + err = tarball.WriteHeader(hdr) + if err != nil { + return err + } + + if !info.IsDir() { + src, err := os.Open(path) + if err != nil { + return err + } + defer src.Close() + + _, err = io.Copy(tarball, src) + if err != nil { + return err + } + + err = tarball.Flush() + if err != nil { + return err + } + + err = gz.Flush() + if err != nil { + return err + } + } + + return nil + } + + // stop processing if we get a cancellation signal + err := filepath.Walk(basedir, func(path string, info os.FileInfo, err error) error { + go func() { errChan <- walkFn(path, info, err) }() + + select { + case <-ctx.Done(): + if err := ctx.Err(); err != nil { + return err + } + case err := <-errChan: + if err != nil { + return err + } + } + + return nil + }) + if err != nil { + fmt.Println(err) + return err + } + + err = gz.Close() + if err != nil { + return err + } + err = tarball.Close() + if err != nil { + return err + } + + return nil +} diff --git a/system/search/backup.go b/system/search/backup.go new file mode 100644 index 0000000..9223636 --- /dev/null +++ b/system/search/backup.go @@ -0,0 +1,57 @@ +package search + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "time" + + "github.com/ponzu-cms/ponzu/system/backup" +) + +// Backup creates an archive of a project's search index and writes it +// to the response as a download +func Backup(ctx context.Context, res http.ResponseWriter) error { + ts := time.Now().Unix() + filename := fmt.Sprintf("search-%d.bak.tar.gz", ts) + tmp := os.TempDir() + bk := filepath.Join(tmp, filename) + + // create search-{stamp}.bak.tar.gz + f, err := os.Create(bk) + if err != nil { + return err + } + + backup.ArchiveFS(ctx, "search", f) + + err = f.Close() + if err != nil { + return err + } + + // write data to response + data, err := os.Open(bk) + if err != nil { + return err + } + defer data.Close() + defer os.Remove(bk) + + disposition := `attachment; filename=%s` + info, err := data.Stat() + if err != nil { + return err + } + + res.Header().Set("Content-Type", "application/octet-stream") + res.Header().Set("Content-Disposition", fmt.Sprintf(disposition, ts)) + res.Header().Set("Content-Length", fmt.Sprintf("%d", info.Size())) + + _, err = io.Copy(res, data) + + return err +} |