-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from KYVENetwork/feat/backup
Feat/backup
- Loading branch information
Showing
12 changed files
with
271 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
VERSION := v0.2.1 | ||
VERSION := v0.2.2 | ||
|
||
ldflags := $(LDFLAGS) | ||
ldflags += -X main.Version=$(VERSION) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package backup | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"sort" | ||
"strings" | ||
) | ||
|
||
func ClearBackups(srcPath string, threshold int) error { | ||
// Get and sort all created Backups | ||
entries, err := os.ReadDir(srcPath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
backups := []os.DirEntry{} | ||
for _, entry := range entries { | ||
if entry.IsDir() { | ||
// Make sure to only clear timestamped backups | ||
if strings.HasPrefix(entry.Name(), "20") && len(entry.Name()) == 15 { | ||
backups = append(backups, entry) | ||
} | ||
} | ||
} | ||
|
||
sort.Slice(backups, func(i, j int) bool { | ||
return backups[i].Name() < backups[j].Name() | ||
}) | ||
|
||
if len(backups) > threshold { | ||
for { | ||
oldestBackup := backups[0].Name() | ||
err = os.RemoveAll(filepath.Join(srcPath, oldestBackup)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
backups = backups[1:] | ||
|
||
if len(backups) <= threshold { | ||
break | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// CompressDirectory compresses a directory using Gzip and creates a .tar.gz file. | ||
func CompressDirectory(srcPath, compressionType string) error { | ||
var cmd *exec.Cmd | ||
|
||
switch compressionType { | ||
case "tar.gz": | ||
cmd = exec.Command("tar", "-zcvf", filepath.Base(srcPath)+"."+compressionType, filepath.Base(srcPath)) | ||
case "zip": | ||
cmd = exec.Command("zip", "-r", filepath.Base(srcPath)+"."+compressionType, filepath.Base(srcPath)) | ||
default: | ||
return fmt.Errorf("unsupported compression type") | ||
} | ||
|
||
cmd.Dir = filepath.Dir(srcPath) | ||
cmd.Stderr = os.Stderr | ||
|
||
// Run the command | ||
if err := cmd.Run(); err != nil { | ||
return err | ||
} | ||
|
||
if err := os.RemoveAll(srcPath); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func CopyDir(srcDir, destDir string) error { | ||
// Create the destination directory if it doesn't exist | ||
if err := os.MkdirAll(destDir, 0o755); err != nil { | ||
return err | ||
} | ||
|
||
// Walk through the source directory and copy its contents to the destination | ||
return filepath.Walk(srcDir, func(srcPath string, fileInfo os.FileInfo, err error) error { | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Construct the corresponding destination path | ||
destPath := filepath.Join(destDir, srcPath[len(srcDir):]) | ||
|
||
if fileInfo.IsDir() { | ||
// Create the destination directory if it doesn't exist | ||
return os.MkdirAll(destPath, 0o755) | ||
} else { | ||
// Open the source file for reading | ||
srcFile, err := os.Open(srcPath) | ||
if err != nil { | ||
return err | ||
} | ||
defer srcFile.Close() | ||
|
||
// Create the destination file | ||
destFile, err := os.Create(destPath) | ||
if err != nil { | ||
return err | ||
} | ||
defer destFile.Close() | ||
|
||
// Copy the contents from source to destination | ||
if _, err := io.Copy(destFile, srcFile); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/KYVENetwork/supervysor/backup" | ||
"github.com/KYVENetwork/supervysor/cmd/supervysor/helpers" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
compressionType string | ||
destPath string | ||
maxBackups int | ||
srcPath string | ||
) | ||
|
||
func init() { | ||
backupCmd.Flags().StringVar(&srcPath, "src-path", "", "source path of the directory to backup") | ||
if err := backupCmd.MarkFlagRequired("src-path"); err != nil { | ||
panic(fmt.Errorf("flag 'src-path' should be required: %w", err)) | ||
} | ||
|
||
backupCmd.Flags().StringVar(&destPath, "dest-path", "", "destination path of the written backup (default '~/.ksync/backups)'") | ||
|
||
backupCmd.Flags().StringVar(&compressionType, "compression", "", "compression type to compress backup directory ['tar.gz', 'zip', '']") | ||
|
||
backupCmd.Flags().IntVar(&maxBackups, "max-backups", 0, "number of kept backups (set 0 to keep all)") | ||
} | ||
|
||
var backupCmd = &cobra.Command{ | ||
Use: "backup", | ||
Short: "Backup data directory", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
backupDir, err := helpers.GetBackupDir() | ||
if err != nil { | ||
logger.Error("failed to get ksync home directory", "err", err) | ||
return | ||
} | ||
|
||
if destPath == "" { | ||
d, err := helpers.CreateDestPath(backupDir) | ||
if err != nil { | ||
return | ||
} | ||
destPath = d | ||
} | ||
|
||
if err := helpers.ValidatePaths(srcPath, destPath); err != nil { | ||
return | ||
} | ||
|
||
logger.Info("starting to copy backup", "from", srcPath, "to", destPath) | ||
|
||
if err := backup.CopyDir(srcPath, destPath); err != nil { | ||
logger.Error("error copying directory to backup destination", "err", err) | ||
} | ||
|
||
logger.Info("directory copied successfully") | ||
|
||
if compressionType != "" { | ||
if err := backup.CompressDirectory(destPath, compressionType); err != nil { | ||
logger.Error("compression failed", "err", err) | ||
} | ||
|
||
logger.Info("compressed backup successfully") | ||
} | ||
|
||
if maxBackups > 0 { | ||
logger.Info("starting to cleanup backup directory", "path", backupDir) | ||
if err := backup.ClearBackups(backupDir, maxBackups); err != nil { | ||
logger.Error("clearing backup directory failed", "err", err) | ||
return | ||
} | ||
} | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.