From af8a50f6463976739d31b6215eba879fd093194f Mon Sep 17 00:00:00 2001 From: Jonas Kaninda Date: Sat, 17 Feb 2024 18:20:35 +0100 Subject: [PATCH] feat: add backup prune, to delete old backup --- Makefile | 2 +- README.md | 36 +++++++++++++++++++----------------- cmd/backup.go | 2 ++ cmd/root.go | 16 ---------------- pkg/backup.go | 48 +++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 65 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 4df9f37..e720a31 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ docker-build: docker build -f docker/Dockerfile -t jkaninda/pg-bkup:latest . docker-run: docker-build - docker run --rm --network internal --privileged --device /dev/fuse --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" jkaninda/pg-bkup bkup backup + docker run --rm --network internal --privileged --device /dev/fuse --name pg-bkup -e "DB_HOST=${DB_HOST}" -e "DB_NAME=${DB_NAME}" -e "DB_USERNAME=${DB_USERNAME}" -e "DB_PASSWORD=${DB_PASSWORD}" jkaninda/pg-bkup bkup backup --prune --keep-last 2 docker-run-scheduled: docker-build diff --git a/README.md b/README.md index 6c8515d..d0964ef 100644 --- a/README.md +++ b/README.md @@ -30,23 +30,25 @@ PostgreSQL Backup and Restoration tool. Backup database to AWS S3 storage or any ### Usage -| Options | Shorts | Usage | -|-----------------------|----------|--------------------------------------------------------------------| -| pg-bkup | bkup | CLI utility | -| backup | | Backup database operation | -| restore | | Restore database operation | -| history | | Show the history of backup | -| --storage | -s | Set storage. local or s3 (default: local) | -| --file | -f | Set file name for restoration | -| --path | | Set s3 path without file name. eg: /custom_path | -| --dbname | -d | Set database name | -| --port | -p | Set database port (default: 5432) | -| --mode | -m | Set execution mode. default or scheduled (default: default) | -| --disable-compression | | Disable database backup compression | -| --period | | Set crontab period for scheduled mode only. (default: "0 1 * * *") | -| --timeout | -t | Set timeout (default: 60s) | -| --help | -h | Print this help message and exit | -| --version | -V | Print version information and exit | +| Options | Shorts | Usage | +|-----------------------|--------|-----------------------------------------------------------------------| +| pg-bkup | bkup | CLI utility | +| backup | | Backup database operation | +| restore | | Restore database operation | +| history | | Show the history of backup | +| --storage | -s | Set storage. local or s3 (default: local) | +| --file | -f | Set file name for restoration | +| --path | | Set s3 path without file name. eg: /custom_path | +| --dbname | -d | Set database name | +| --port | -p | Set database port (default: 5432) | +| --mode | -m | Set execution mode. default or scheduled (default: default) | +| --disable-compression | | Disable database backup compression | +| --prune | | Delete old backup | +| --keep-last | | keep all backup and delete within this time interval, default 7 days | +| --period | | Set crontab period for scheduled mode only. (default: "0 1 * * *") | +| --timeout | -t | Set timeout (default: 60s) | +| --help | -h | Print this help message and exit | +| --version | -V | Print version information and exit | ## Environment variables diff --git a/cmd/backup.go b/cmd/backup.go index 456ac27..0f6ec8a 100644 --- a/cmd/backup.go +++ b/cmd/backup.go @@ -23,6 +23,8 @@ func init() { //Backup BackupCmd.PersistentFlags().StringP("mode", "m", "default", "Set execution mode. default or scheduled") BackupCmd.PersistentFlags().StringP("period", "", "0 1 * * *", "Set schedule period time") + BackupCmd.PersistentFlags().BoolP("prune", "", false, "Prune old backup") + BackupCmd.PersistentFlags().IntP("keep-last", "", 7, "keep all backup and delete within this time interval, default 7 days") BackupCmd.PersistentFlags().BoolP("disable-compression", "", false, "Disable backup compression") } diff --git a/cmd/root.go b/cmd/root.go index 180fde1..e92ca95 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,7 +5,6 @@ Copyright © 2024 Jonas Kaninda package cmd import ( - "fmt" "github.com/jkaninda/pg-bkup/utils" "github.com/spf13/cobra" "os" @@ -18,16 +17,6 @@ var rootCmd = &cobra.Command{ Long: `PostgreSQL Database backup and restoration tool. Backup database to AWS S3 storage or any S3 Alternatives for Object Storage.`, Example: utils.MainExample, Version: appVersion, - //TODO: To remove - //For old user || To remove - Run: func(cmd *cobra.Command, args []string) { - if operation != "" { - if operation == "backup" || operation == "restore" { - fmt.Println(utils.Notice) - utils.Fatal("New config required, please check --help") - } - } - }, } var operation = "" var s3Path = "/pg-bkup" @@ -49,11 +38,6 @@ func init() { rootCmd.PersistentFlags().IntP("port", "p", 5432, "Set database port") rootCmd.PersistentFlags().StringVarP(&operation, "operation", "o", "", "Set operation, for old version only") - rootCmd.PersistentFlags().StringP("mode", "m", "default", "Set execution mode. default or scheduled") - rootCmd.PersistentFlags().StringP("period", "", "0 1 * * *", "Set schedule period time") - rootCmd.PersistentFlags().BoolP("disable-compression", "", false, "Disable backup compression") - rootCmd.PersistentFlags().StringP("file", "f", "", "File name of database") - rootCmd.AddCommand(VersionCmd) rootCmd.AddCommand(BackupCmd) rootCmd.AddCommand(RestoreCmd) diff --git a/pkg/backup.go b/pkg/backup.go index c0660f5..ca8c96c 100644 --- a/pkg/backup.go +++ b/pkg/backup.go @@ -11,6 +11,7 @@ import ( "log" "os" "os/exec" + "path/filepath" "time" ) @@ -27,16 +28,18 @@ func StartBackup(cmd *cobra.Command) { s3Path = utils.GetEnv(cmd, "path", "S3_PATH") storage = utils.GetEnv(cmd, "storage", "STORAGE") file = utils.GetEnv(cmd, "file", "FILE_NAME") + keepLast, _ := cmd.Flags().GetInt("keep-last") + prune, _ := cmd.Flags().GetBool("prune") disableCompression, _ = cmd.Flags().GetBool("disable-compression") executionMode, _ = cmd.Flags().GetString("mode") if executionMode == "default" { if storage == "s3" { utils.Info("Backup database to s3 storage") - s3Backup(disableCompression, s3Path) + s3Backup(disableCompression, s3Path, prune, keepLast) } else { utils.Info("Backup database to local storage") - BackupDatabase(disableCompression) + BackupDatabase(disableCompression, prune, keepLast) } } else if executionMode == "scheduled" { @@ -75,7 +78,7 @@ func scheduledMode() { } // BackupDatabase backup database -func BackupDatabase(disableCompression bool) { +func BackupDatabase(disableCompression bool, prune bool, keepLast int) { dbHost = os.Getenv("DB_HOST") dbPassword = os.Getenv("DB_PASSWORD") dbUserName = os.Getenv("DB_USERNAME") @@ -151,6 +154,11 @@ func BackupDatabase(disableCompression bool) { } utils.Done("Database has been backed up") + //Delete old backup + if prune { + deleteOldBackup(keepLast) + } + } historyFile, err := os.OpenFile(fmt.Sprintf("%s/history.txt", storagePath), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) @@ -165,8 +173,38 @@ func BackupDatabase(disableCompression bool) { } -func s3Backup(disableCompression bool, s3Path string) { +func s3Backup(disableCompression bool, s3Path string, prune bool, keepLast int) { // Backup Database to S3 storage MountS3Storage(s3Path) - BackupDatabase(disableCompression) + BackupDatabase(disableCompression, prune, keepLast) +} +func deleteOldBackup(keepLast int) { + utils.Info("Deleting old backups...") + storagePath = os.Getenv("STORAGE_PATH") + // Define the directory path + backupDir := storagePath + "/" + // Get current time + currentTime := time.Now() + // Walk through files in the directory + err := filepath.Walk(backupDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + // Check if the file is older than defined day days + if info.Mode().IsRegular() && info.ModTime().Before(currentTime.AddDate(0, 0, -keepLast)) { + // Remove the file + err := os.Remove(path) + if err != nil { + utils.Fatal("Error removing file ", path, err) + } else { + utils.Done("Removed file: ", path) + } + } + return nil + }) + + if err != nil { + utils.Fatal("Error walking through directory: ", err) + } + }