feat(revisions): add pruning estimate and cleanup endpoints
CI / changes (push) Successful in 8s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 25s
CI / web (push) Successful in 32s
CI / go (push) Successful in 57s
CI / bird2 (push) Successful in 15s
CI / release (push) Successful in 3m18s
CI / changes (push) Successful in 8s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 25s
CI / web (push) Successful in 32s
CI / go (push) Successful in 57s
CI / bird2 (push) Successful in 15s
CI / release (push) Successful in 3m18s
Implemented new endpoints for estimating and pruning revisions, including detailed schemas for requests and responses. The `RevisionPruneEstimate` and `RevisionPruneResult` components were added to the OpenAPI documentation, enhancing the API's functionality for managing revision retention. Updated the backend to support these operations and integrated them into the tenant settings UI for improved user interaction.
This commit is contained in:
@@ -31,10 +31,7 @@ const (
|
||||
birdFilterNameV4 = "evobgp_export_v4"
|
||||
birdFilterNameV6 = "evobgp_export_v6"
|
||||
auxBirdFullExpanded = "_bird_full_expanded.conf"
|
||||
revisionTTLKey = "revision_retention_minutes"
|
||||
revisionMinTTLMin = 15
|
||||
revisionMaxTTLMin = 30 * 24 * 60
|
||||
revisionDefaultTTL = 30 * 24 * time.Hour
|
||||
revisionTTLKey = RevisionRetentionKey
|
||||
)
|
||||
|
||||
// AuxBirdFullExpandedKey returns the preview map key for the expanded BIRD config (generated on demand).
|
||||
@@ -969,17 +966,7 @@ func applyRevisionRetention(st store.Backend, tenantID string) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ttl := revisionDefaultTTL
|
||||
if minutes := intFromSettingsMap(settings, revisionTTLKey); minutes > 0 {
|
||||
if minutes < revisionMinTTLMin {
|
||||
minutes = revisionMinTTLMin
|
||||
}
|
||||
if minutes > revisionMaxTTLMin {
|
||||
minutes = revisionMaxTTLMin
|
||||
}
|
||||
ttl = time.Duration(minutes) * time.Minute
|
||||
}
|
||||
cutoff := time.Now().UTC().Add(-ttl)
|
||||
cutoff := RevisionRetentionCutoff(settings)
|
||||
_, _ = st.PruneRevisionsBefore(tenantID, cutoff)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// RevisionRetentionKey is the global_settings KV for revision TTL (minutes).
|
||||
RevisionRetentionKey = "revision_retention_minutes"
|
||||
RevisionMinTTLMin = 15
|
||||
RevisionMaxTTLMin = 30 * 24 * 60
|
||||
RevisionDefaultTTL = 30 * 24 * time.Hour
|
||||
)
|
||||
|
||||
// RevisionCutoffFromMinutes returns created_at cutoff for revision prune (UTC now minus clamped TTL).
|
||||
func RevisionCutoffFromMinutes(minutes int) time.Time {
|
||||
ttl := RevisionDefaultTTL
|
||||
if minutes > 0 {
|
||||
m := minutes
|
||||
if m < RevisionMinTTLMin {
|
||||
m = RevisionMinTTLMin
|
||||
}
|
||||
if m > RevisionMaxTTLMin {
|
||||
m = RevisionMaxTTLMin
|
||||
}
|
||||
ttl = time.Duration(m) * time.Minute
|
||||
}
|
||||
return time.Now().UTC().Add(-ttl)
|
||||
}
|
||||
|
||||
// RevisionRetentionMinutesFromSettings reads revision_retention_minutes from tenant KV (0 if unset).
|
||||
func RevisionRetentionMinutesFromSettings(settings map[string]any) int {
|
||||
if settings == nil {
|
||||
return 0
|
||||
}
|
||||
v, ok := settings[RevisionRetentionKey]
|
||||
if !ok || v == nil {
|
||||
return 0
|
||||
}
|
||||
switch x := v.(type) {
|
||||
case float64:
|
||||
return int(x)
|
||||
case int:
|
||||
return x
|
||||
case int64:
|
||||
return int(x)
|
||||
case string:
|
||||
n, err := strconv.Atoi(strings.TrimSpace(x))
|
||||
if err == nil {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// RevisionRetentionCutoff resolves tenant revision_retention_minutes from settings (default 30d).
|
||||
func RevisionRetentionCutoff(settings map[string]any) time.Time {
|
||||
return RevisionCutoffFromMinutes(RevisionRetentionMinutesFromSettings(settings))
|
||||
}
|
||||
|
||||
// ClampRevisionRetentionMinutes normalizes user input to the allowed range.
|
||||
func ClampRevisionRetentionMinutes(minutes int) int {
|
||||
if minutes <= 0 {
|
||||
return int(RevisionDefaultTTL / time.Minute)
|
||||
}
|
||||
if minutes < RevisionMinTTLMin {
|
||||
return RevisionMinTTLMin
|
||||
}
|
||||
if minutes > RevisionMaxTTLMin {
|
||||
return RevisionMaxTTLMin
|
||||
}
|
||||
return minutes
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestClampRevisionRetentionMinutes(t *testing.T) {
|
||||
if got := ClampRevisionRetentionMinutes(0); got != int(RevisionDefaultTTL/time.Minute) {
|
||||
t.Fatalf("default: got %d", got)
|
||||
}
|
||||
if got := ClampRevisionRetentionMinutes(5); got != RevisionMinTTLMin {
|
||||
t.Fatalf("min clamp: got %d", got)
|
||||
}
|
||||
if got := ClampRevisionRetentionMinutes(999999); got != RevisionMaxTTLMin {
|
||||
t.Fatalf("max clamp: got %d", got)
|
||||
}
|
||||
if got := ClampRevisionRetentionMinutes(120); got != 120 {
|
||||
t.Fatalf("unchanged: got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevisionCutoffFromMinutes(t *testing.T) {
|
||||
before := time.Now().UTC()
|
||||
cutoff := RevisionCutoffFromMinutes(60)
|
||||
after := time.Now().UTC().Add(-59 * time.Minute)
|
||||
if cutoff.After(before.Add(-59*time.Minute)) || cutoff.Before(after.Add(-2*time.Minute)) {
|
||||
t.Fatalf("cutoff out of range: %v", cutoff)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user