(feature) Add read-only retention plan view
Add a staff-only retention plan page for each host using the SQL-backed retention service. Link it from the host detail page and show policy settings, keep reasons, and snapshots that would be deleted for scheduled, manual, or all snapshot kinds. Keep the flow non-destructive for now, validate query parameters, and cover the view with tests for rendering, base protection, and invalid kind handling.
This commit is contained in:
@@ -100,6 +100,58 @@ class ViewTests(TestCase):
|
||||
|
||||
self.assertEqual(response.status_code, 405)
|
||||
|
||||
def test_retention_plan_renders_keep_and_delete_sets(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(
|
||||
host="web-01",
|
||||
address="web-01.example.test",
|
||||
retention_daily=0,
|
||||
retention_weekly=0,
|
||||
retention_monthly=0,
|
||||
retention_yearly=0,
|
||||
)
|
||||
old_snapshot = self._snapshot(host, "20260518-021500Z__OLDSNAP")
|
||||
new_snapshot = self._snapshot(host, "20260519-021500Z__NEWSNAP")
|
||||
|
||||
response = self.client.get(reverse("host_retention_plan", args=[host.host]))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Retention Plan: web-01")
|
||||
self.assertContains(response, old_snapshot.dirname)
|
||||
self.assertContains(response, new_snapshot.dirname)
|
||||
self.assertContains(response, "newest")
|
||||
self.assertContains(response, "Would Delete")
|
||||
|
||||
def test_retention_plan_can_enable_base_protection(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(
|
||||
host="web-01",
|
||||
address="web-01.example.test",
|
||||
retention_daily=0,
|
||||
retention_weekly=0,
|
||||
retention_monthly=0,
|
||||
retention_yearly=0,
|
||||
)
|
||||
base = self._snapshot(host, "20260518-021500Z__BASESNAP")
|
||||
child = self._snapshot(host, "20260519-021500Z__CHILDSNP")
|
||||
child.base = base
|
||||
child.save(update_fields=["base"])
|
||||
|
||||
response = self.client.get(reverse("host_retention_plan", args=[host.host]), {"protect_bases": "1"})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Protect bases:</strong> yes")
|
||||
self.assertContains(response, f"base-of:{child.dirname}")
|
||||
|
||||
def test_retention_plan_rejects_invalid_kind(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
|
||||
response = self.client.get(reverse("host_retention_plan", args=[host.host]), {"kind": "weird"}, follow=True)
|
||||
|
||||
self.assertRedirects(response, reverse("host_detail", args=[host.host]))
|
||||
self.assertContains(response, "Retention kind must be scheduled, manual, or all.")
|
||||
|
||||
def _snapshot(self, host: HostConfig, dirname: str) -> SnapshotRecord:
|
||||
started_at = datetime.strptime(dirname.split("__", 1)[0], "%Y%m%d-%H%M%SZ").replace(tzinfo=timezone.utc)
|
||||
return SnapshotRecord.objects.create(
|
||||
|
||||
Reference in New Issue
Block a user