(bugfix) Enable rsync progress output for live real runs

Default queued and management-command backups to verbose rsync output so live
run views show progress for long-running real backups, matching dry-run
visibility.

Add a quiet-rsync escape hatch for operators who intentionally want less noisy
real-run logs.
This commit is contained in:
2026-05-28 21:42:40 +02:00
parent 41ceab5a40
commit 29f455a153
7 changed files with 62 additions and 8 deletions

View File

@@ -39,13 +39,20 @@ class BackupWorkerTests(TestCase):
},
)
def test_queue_backup_run_can_request_verbose_output(self) -> None:
def test_queue_backup_run_enables_verbose_output_by_default(self) -> None:
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
run = queue_backup_run(host=host, verbose_output=True)
run = queue_backup_run(host=host)
self.assertTrue(run.result["requested"]["verbose_output"])
def test_queue_backup_run_can_disable_verbose_output(self) -> None:
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
run = queue_backup_run(host=host, verbose_output=False)
self.assertFalse(run.result["requested"]["verbose_output"])
def test_worker_executes_next_queued_run(self) -> None:
with TemporaryDirectory() as tmp:
backup_root = Path(tmp) / "backups"

View File

@@ -39,12 +39,16 @@ class RunBackupRecordsSnapshotTests(TestCase):
"host": host.host,
"snapshot": str(snapshot_dir),
"base": None,
"verbose_output": True,
"rsync": {"exit_code": 0},
}
call_command("run_pobsync_backup", host.host, prefix=str(Path(tmp) / "home"), stdout=StringIO())
run_scheduled.assert_called_once()
self.assertTrue(run_scheduled.call_args.kwargs["verbose_output"])
self.assertEqual(BackupRun.objects.count(), 1)
run = BackupRun.objects.get()
self.assertTrue(run.result["verbose_output"])
self.assertEqual(SnapshotRecord.objects.count(), 1)
record = SnapshotRecord.objects.get()
self.assertEqual(run.snapshot, record)
@@ -52,6 +56,45 @@ class RunBackupRecordsSnapshotTests(TestCase):
self.assertEqual(record.kind, "scheduled")
self.assertEqual(record.status, "success")
def test_backup_command_can_skip_default_verbose_rsync_output(self) -> None:
with TemporaryDirectory() as tmp:
backup_root = Path(tmp) / "backups"
GlobalConfig.objects.create(name="default", backup_root=str(backup_root))
host = HostConfig.objects.create(host="web-01", address="web-01.example.test")
snapshot_dir = backup_root / host.host / "scheduled" / "20260519-021500Z__ABCDEFGH"
meta_dir = snapshot_dir / "meta"
meta_dir.mkdir(parents=True)
write_yaml_atomic(
meta_dir / "meta.yaml",
{
"status": "success",
"started_at": "2026-05-19T02:15:00Z",
"ended_at": "2026-05-19T02:16:00Z",
},
)
with patch("pobsync_backend.backup_runner.run_scheduled") as run_scheduled:
run_scheduled.return_value = {
"ok": True,
"dry_run": False,
"host": host.host,
"snapshot": str(snapshot_dir),
"base": None,
"verbose_output": False,
"rsync": {"exit_code": 0},
}
call_command(
"run_pobsync_backup",
host.host,
prefix=str(Path(tmp) / "home"),
quiet_rsync=True,
stdout=StringIO(),
)
run_scheduled.assert_called_once()
self.assertFalse(run_scheduled.call_args.kwargs["verbose_output"])
self.assertFalse(BackupRun.objects.get().result["verbose_output"])
def test_prune_uses_sql_retention_after_snapshot_record_is_created(self) -> None:
with TemporaryDirectory() as tmp:
backup_root = Path(tmp) / "backups"

View File

@@ -1372,7 +1372,7 @@ class ViewTests(TestCase):
response = self.client.post(
reverse("queue_manual_backup", args=[host.host]),
{"prune_max_delete": "10"},
{"verbose_output": "on", "prune_max_delete": "10"},
follow=True,
)
@@ -1610,7 +1610,7 @@ class ViewTests(TestCase):
response = self.client.post(
reverse("queue_manual_backup", args=[host.host]),
{"prune_max_delete": "10"},
{"verbose_output": "on", "prune_max_delete": "10"},
follow=True,
)
@@ -1620,7 +1620,7 @@ class ViewTests(TestCase):
run.result["requested"],
{
"dry_run": False,
"verbose_output": False,
"verbose_output": True,
"prune": False,
"prune_max_delete": 10,
"prune_protect_bases": False,