From 4bffc9e92a587ac4e56cdb4fdb28e15a25e8e497 Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Thu, 8 Sep 2022 14:31:51 +0200 Subject: [PATCH] backup: Prune old backups This commit updates the backup command to prune old backups. --- cmd/backup.go | 7 +++++++ env/backup.go | 44 +++++++++++++++++++++++++++++++++++++++ internal/config/config.go | 2 +- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/cmd/backup.go b/cmd/backup.go index 44d164d..a31f468 100644 --- a/cmd/backup.go +++ b/cmd/backup.go @@ -15,6 +15,7 @@ import ( var Backup wisski_distillery.Command = backup{} type backup struct { + NoPrune bool `short:"no" long:"no-prune" description:"Do not prune older backup archives"` StagingOnly bool `short:"s" long:"staging-only" description:"Do not package into a backup archive, but only create a staging directory"` Positionals struct { Dest string `positional-arg-name:"DEST" description:"Destination path to write backup archive to. Defaults to the snapshots/archives/ directory"` @@ -40,6 +41,12 @@ func (bk backup) Run(context wisski_distillery.Context) error { dis := context.Environment var err error + if !bk.NoPrune { + defer logging.LogOperation(func() error { + return dis.PruneBackups(context.IOStream) + }, context.IOStream, "Pruning old backups") + } + // determine the target path for the archive var sPath string if !bk.StagingOnly { diff --git a/env/backup.go b/env/backup.go index 14270b2..a75df8c 100644 --- a/env/backup.go +++ b/env/backup.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "sync" + "time" "github.com/FAU-CDI/wisski-distillery/internal/fsx" "github.com/FAU-CDI/wisski-distillery/internal/logging" @@ -187,3 +188,46 @@ func (backup Backup) WriteReport(io stream.IOStream) error { return err }, io, "Writing backup report") } + +// ShouldPrune determines if a file with the provided modtime +func (dis *Distillery) ShouldPrune(modtime time.Time) bool { + return time.Since(modtime) > time.Duration(dis.Config.MaxBackupAge)*24*time.Hour +} + +// PruneBackups prunes all backups older than the maximum backup age +func (dis *Distillery) PruneBackups(io stream.IOStream) error { + sPath := dis.SnapshotsArchivePath() + + // list all the files + entries, err := os.ReadDir(sPath) + if err != nil { + return err + } + + for _, entry := range entries { + // skip directories + if entry.IsDir() { + continue + } + + // grab info about the file + info, err := entry.Info() + if err != nil { + return err + } + + // check if it should be pruned! + if !dis.ShouldPrune(info.ModTime()) { + continue + } + + // assemble path, and then remove the file! + path := filepath.Join(sPath, entry.Name()) + io.Printf("Removing %s cause it is older than %d days", path, dis.Config.MaxBackupAge) + + if err := os.Remove(path); err != nil { + return err + } + } + return nil +} diff --git a/internal/config/config.go b/internal/config/config.go index f2067c1..5caff52 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -39,7 +39,7 @@ type Config struct { // This email address can be configured here. CertbotEmail string `env:"CERTBOT_EMAIL" default:"" validator:"is_valid_email"` - // Maximum age for backup + // Maximum age for backup in days MaxBackupAge int `env:"MAX_BACKUP_AGE" default:"" validator:"is_valid_number"` // Each Drupal instance requires a corresponding system user, database users and databases.