(feature) Add cancellable backup runs and clearer dry-run logs
Add a cancel action for queued and running backup runs. Queued runs are cancelled immediately, while running runs are marked for cancellation and the worker terminates the active rsync process group. Make dry-run log paths run-specific and add a defensive default dry-run timeout so stuck dry-runs do not remain running indefinitely. Remove rsync exit codes from run overview tables while keeping detailed diagnostics available on the run detail payload.
This commit is contained in:
@@ -764,6 +764,44 @@ class ViewTests(TestCase):
|
||||
self.assertContains(response, ""ok": true")
|
||||
self.assertContains(response, reverse("snapshot_detail", args=[snapshot.id]))
|
||||
|
||||
def test_run_detail_offers_cancel_for_running_run(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
run = BackupRun.objects.create(host=host, status=BackupRun.Status.RUNNING)
|
||||
|
||||
response = self.client.get(reverse("run_detail", args=[run.id]))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Cancel run")
|
||||
self.assertContains(response, reverse("cancel_run", args=[run.id]))
|
||||
|
||||
def test_cancel_run_marks_queued_run_cancelled(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
run = BackupRun.objects.create(host=host, status=BackupRun.Status.QUEUED)
|
||||
|
||||
response = self.client.post(reverse("cancel_run", args=[run.id]), follow=True)
|
||||
|
||||
self.assertRedirects(response, reverse("run_detail", args=[run.id]))
|
||||
self.assertContains(response, "Cancellation requested")
|
||||
run.refresh_from_db()
|
||||
self.assertEqual(run.status, BackupRun.Status.CANCELLED)
|
||||
self.assertIsNotNone(run.ended_at)
|
||||
self.assertEqual(run.result["cancellation"]["previous_status"], BackupRun.Status.QUEUED)
|
||||
|
||||
def test_cancel_run_requests_running_run_cancellation(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
run = BackupRun.objects.create(host=host, status=BackupRun.Status.RUNNING)
|
||||
|
||||
response = self.client.post(reverse("cancel_run", args=[run.id]), follow=True)
|
||||
|
||||
self.assertRedirects(response, reverse("run_detail", args=[run.id]))
|
||||
run.refresh_from_db()
|
||||
self.assertEqual(run.status, BackupRun.Status.CANCELLED)
|
||||
self.assertIsNone(run.ended_at)
|
||||
self.assertEqual(run.result["cancellation"]["previous_status"], BackupRun.Status.RUNNING)
|
||||
|
||||
def test_snapshot_detail_renders_metadata_runs_and_children(self) -> None:
|
||||
self.client.force_login(self.staff_user)
|
||||
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
|
||||
|
||||
Reference in New Issue
Block a user