85 lines
2.0 KiB
Go
85 lines
2.0 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"scm.bstein.dev/bstein/soteria/internal/longhorn"
|
|
)
|
|
|
|
const (
|
|
longhornLabelNamespace = "soteria.bstein.dev/namespace"
|
|
longhornLabelPVC = "soteria.bstein.dev/pvc"
|
|
)
|
|
|
|
func (s *Server) pruneLonghornBackups(ctx context.Context, volumeName, namespace, pvc string, keepLast int) error {
|
|
if keepLast <= 0 {
|
|
return nil
|
|
}
|
|
|
|
backups, err := s.longhorn.ListBackups(ctx, volumeName)
|
|
if err != nil {
|
|
if longhorn.IsNotFound(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
completed := make([]longhorn.Backup, 0, len(backups))
|
|
toDelete := []longhorn.Backup{}
|
|
for _, backup := range backups {
|
|
if !longhornBackupMatchesPVC(backup, namespace, pvc) {
|
|
continue
|
|
}
|
|
switch strings.ToLower(strings.TrimSpace(backup.State)) {
|
|
case "completed":
|
|
completed = append(completed, backup)
|
|
case "error", "failed":
|
|
toDelete = append(toDelete, backup)
|
|
}
|
|
}
|
|
|
|
sort.Slice(completed, func(i, j int) bool {
|
|
left := longhornBackupCreatedAt(completed[i])
|
|
right := longhornBackupCreatedAt(completed[j])
|
|
if left.Equal(right) {
|
|
return completed[i].Name > completed[j].Name
|
|
}
|
|
return left.After(right)
|
|
})
|
|
|
|
if len(completed) > keepLast {
|
|
toDelete = append(toDelete, completed[keepLast:]...)
|
|
}
|
|
|
|
for _, backup := range toDelete {
|
|
if strings.TrimSpace(backup.Name) == "" {
|
|
continue
|
|
}
|
|
if err := s.longhorn.DeleteBackup(ctx, volumeName, backup.Name); err != nil {
|
|
return fmt.Errorf("delete old Longhorn backup %s for %s/%s: %w", backup.Name, namespace, pvc, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func longhornBackupMatchesPVC(backup longhorn.Backup, namespace, pvc string) bool {
|
|
return backup.Labels[longhornLabelNamespace] == namespace && backup.Labels[longhornLabelPVC] == pvc
|
|
}
|
|
|
|
func longhornBackupCreatedAt(backup longhorn.Backup) time.Time {
|
|
created := strings.TrimSpace(backup.Created)
|
|
if created == "" {
|
|
return time.Time{}
|
|
}
|
|
ts, err := time.Parse(time.RFC3339, created)
|
|
if err != nil {
|
|
return time.Time{}
|
|
}
|
|
return ts
|
|
}
|