Add --keep-newer-than flag for rolling retention window

snapshot create --prune now accepts --keep-newer-than <duration> (e.g.
4w, 30d, 6mo) to keep a rolling window of snapshots instead of only
the latest. Supports d/w/mo/y units and combinations (2w3d).

Without --keep-newer-than, --prune still defaults to keep-latest-only.
This commit is contained in:
2026-06-09 13:22:24 -04:00
parent f719ab3adc
commit ee240faa32
5 changed files with 101 additions and 28 deletions
+22 -14
View File
@@ -22,10 +22,11 @@ import (
// SnapshotCreateOptions contains options for the snapshot create command
type SnapshotCreateOptions struct {
Cron bool
Prune bool
SkipErrors bool // Skip file read errors (log them loudly but continue)
Snapshots []string // Optional list of snapshot names to process (empty = all)
Cron bool
Prune bool
KeepNewerThan string // With --prune: keep snapshots newer than this duration (e.g. "4w"); default: keep only latest
SkipErrors bool // Skip file read errors (log them loudly but continue)
Snapshots []string // Optional list of snapshot names to process (empty = all)
}
// CreateSnapshot executes the snapshot creation operation
@@ -86,7 +87,7 @@ func (v *Vaultik) CreateSnapshot(opts *SnapshotCreateOptions) error {
}
if opts.Prune {
if err := v.runPostBackupPrune(snapshotNames); err != nil {
if err := v.runPostBackupPrune(snapshotNames, opts.KeepNewerThan); err != nil {
return fmt.Errorf("post-backup prune: %w", err)
}
}
@@ -94,19 +95,26 @@ func (v *Vaultik) CreateSnapshot(opts *SnapshotCreateOptions) error {
return nil
}
// runPostBackupPrune drops older snapshots of the given names (keeping only
// the latest of each) and removes orphan blobs from remote storage. Invoked
// when `snapshot create --prune` is used.
func (v *Vaultik) runPostBackupPrune(snapshotNames []string) error {
log.Info("Running post-backup prune", "snapshots", snapshotNames)
// runPostBackupPrune drops older snapshots of the given names and removes
// orphan blobs from remote storage. If keepNewerThan is set (e.g. "4w"),
// snapshots newer than that duration are kept. Otherwise only the latest
// snapshot of each name is kept.
func (v *Vaultik) runPostBackupPrune(snapshotNames []string, keepNewerThan string) error {
log.Info("Running post-backup prune", "snapshots", snapshotNames, "keep_newer_than", keepNewerThan)
v.printlnStdout("\n=== Post-backup prune ===")
purgeOpts := &SnapshotPurgeOptions{
KeepLatest: true,
Force: true,
Names: snapshotNames,
Quiet: true,
Force: true,
Names: snapshotNames,
Quiet: true,
}
if keepNewerThan != "" {
purgeOpts.OlderThan = keepNewerThan
} else {
purgeOpts.KeepLatest = true
}
if err := v.PurgeSnapshotsWithOptions(purgeOpts); err != nil {
return fmt.Errorf("purging old snapshots: %w", err)
}