(release) Add explicit incomplete snapshot cleanup

Add a dedicated cleanup path for incomplete snapshots instead of letting
retention prune them implicitly. The retention plan now exposes a guarded
form that requires host and delete-count confirmation before removing
.incomplete snapshot directories and their SQL records.

Keep scheduled/manual retention behavior unchanged, add path safety checks,
and cover cleanup success, confirmation failures, max-delete limits, and
unexpected paths in tests.

Refs #10
This commit is contained in:
2026-05-21 03:26:21 +02:00
parent 4c8ed24561
commit d0c23deb72
7 changed files with 329 additions and 2 deletions

View File

@@ -274,6 +274,36 @@ class RetentionApplyForm(forms.Form):
return value
class IncompleteCleanupForm(forms.Form):
max_delete = forms.IntegerField(min_value=0, initial=0)
confirm_delete_count = forms.IntegerField(min_value=0)
confirm_host = forms.CharField()
def __init__(self, *args, host_name: str, expected_delete_count: int, **kwargs) -> None:
self.host_name = host_name
self.expected_delete_count = expected_delete_count
super().__init__(*args, **kwargs)
self.fields["confirm_host"].help_text = f"Type {host_name} to confirm incomplete snapshot cleanup."
self.fields["confirm_delete_count"].help_text = (
f"Type {expected_delete_count} to confirm the current number of incomplete snapshots."
)
self.fields["max_delete"].help_text = (
f"Must be at least {expected_delete_count} for the incomplete snapshots shown here."
)
def clean_confirm_host(self) -> str:
value = self.cleaned_data["confirm_host"].strip()
if value != self.host_name:
raise forms.ValidationError(f"Type {self.host_name} to confirm.")
return value
def clean_confirm_delete_count(self) -> int:
value = self.cleaned_data["confirm_delete_count"]
if value != self.expected_delete_count:
raise forms.ValidationError(f"Type {self.expected_delete_count} to confirm the incomplete count.")
return value
class ScheduleConfigForm(forms.ModelForm):
cron_expr = forms.CharField(
label="Schedule expression",