(feature) Add Django retention apply flow
Expose retention apply from the host retention plan page so planned snapshot deletions can be executed from the Django UI. The form requires explicit host confirmation, carries through the selected retention kind and base-protection setting, and uses max_delete as a deletion guard. The view delegates to the SQL retention apply service and reports predictable pobsync errors back through Django messages instead of surfacing a server error. Add view coverage for confirmed deletion, invalid confirmation, and POST-only enforcement.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
@@ -9,12 +10,19 @@ from django.db.models import Count
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
from pobsync.errors import ConfigError
|
||||
from pobsync.errors import PobsyncError
|
||||
|
||||
from .backup_runner import queue_backup_run
|
||||
from .forms import CreateHostConfigForm, GlobalConfigForm, HostConfigForm, ManualBackupForm, ScheduleConfigForm
|
||||
from .forms import (
|
||||
CreateHostConfigForm,
|
||||
GlobalConfigForm,
|
||||
HostConfigForm,
|
||||
ManualBackupForm,
|
||||
RetentionApplyForm,
|
||||
ScheduleConfigForm,
|
||||
)
|
||||
from .models import BackupRun, GlobalConfig, HostConfig, ScheduleConfig, SnapshotRecord
|
||||
from .retention import run_sql_retention_plan
|
||||
from .retention import run_sql_retention_apply, run_sql_retention_plan
|
||||
from .snapshot_discovery import discover_snapshots, inspect_snapshot_discovery
|
||||
|
||||
|
||||
@@ -196,7 +204,7 @@ def host_retention_plan(request, host: str):
|
||||
protect_bases = request.GET.get("protect_bases") in {"1", "true", "on", "yes"}
|
||||
try:
|
||||
plan = run_sql_retention_plan(host=host_config.host, kind=kind, protect_bases=protect_bases)
|
||||
except ConfigError as exc:
|
||||
except PobsyncError as exc:
|
||||
messages.error(request, str(exc))
|
||||
return redirect("host_detail", host=host_config.host)
|
||||
context = {
|
||||
@@ -204,10 +212,51 @@ def host_retention_plan(request, host: str):
|
||||
"kind": kind,
|
||||
"protect_bases": protect_bases,
|
||||
"plan": plan,
|
||||
"apply_form": RetentionApplyForm(
|
||||
host_name=host_config.host,
|
||||
initial={
|
||||
"kind": kind,
|
||||
"protect_bases": protect_bases,
|
||||
"max_delete": len(plan["delete"]),
|
||||
},
|
||||
),
|
||||
}
|
||||
return render(request, "pobsync_backend/retention_plan.html", context)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@require_POST
|
||||
def apply_host_retention(request, host: str):
|
||||
host_config = get_object_or_404(HostConfig, host=host)
|
||||
form = RetentionApplyForm(request.POST, host_name=host_config.host)
|
||||
if not form.is_valid():
|
||||
messages.error(request, "Retention apply confirmation is invalid.")
|
||||
return redirect("host_retention_plan", host=host_config.host)
|
||||
|
||||
kind = form.cleaned_data["kind"]
|
||||
protect_bases = bool(form.cleaned_data["protect_bases"])
|
||||
try:
|
||||
result = run_sql_retention_apply(
|
||||
prefix=Path(settings.POBSYNC_HOME),
|
||||
host=host_config.host,
|
||||
kind=kind,
|
||||
protect_bases=protect_bases,
|
||||
yes=True,
|
||||
max_delete=form.cleaned_data["max_delete"],
|
||||
)
|
||||
except PobsyncError as exc:
|
||||
messages.error(request, str(exc))
|
||||
else:
|
||||
messages.success(request, f"Retention deleted {len(result['deleted'])} snapshot(s) for {host_config.host}.")
|
||||
|
||||
target = redirect("host_retention_plan", host=host_config.host)
|
||||
query = f"kind={kind}"
|
||||
if protect_bases:
|
||||
query += "&protect_bases=1"
|
||||
target["Location"] = f"{target['Location']}?{query}"
|
||||
return target
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def edit_host_config(request, host: str):
|
||||
host_config = get_object_or_404(HostConfig, host=host)
|
||||
|
||||
Reference in New Issue
Block a user