Files
pobsync/src/pobsync_backend/management/commands/run_pobsync_backup.py
Peter van Arkel 728e5c740a (feature) Add optional verbose rsync output for manual backups
Expose a verbose rsync output option in the Django manual backup form and
store the selected value with the queued run request.

Propagate the option through the worker, direct management command, and
rsync command builder so real backups can emit itemized changes, file-list
progress, and stats when requested. Dry-runs continue to use verbose output
by default and report that consistently in requested options.

Cover the queue, worker, view, and rsync command behavior with focused
tests.
2026-05-19 22:13:33 +02:00

65 lines
2.8 KiB
Python

from __future__ import annotations
from pathlib import Path
from typing import Any
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from pobsync.paths import PobsyncPaths
from pobsync_backend.backup_runner import execute_backup_run
from pobsync_backend.models import BackupRun, HostConfig
class Command(BaseCommand):
help = "Run a pobsync backup and record the result in Django."
def add_arguments(self, parser) -> None:
parser.add_argument("host", help="Host to back up")
parser.add_argument("--prefix", default=settings.POBSYNC_HOME, help="Pobsync home directory")
parser.add_argument("--dry-run", action="store_true", help="Run rsync --dry-run")
parser.add_argument("--verbose-rsync", action="store_true", help="Write itemized rsync output to the run log")
parser.add_argument("--prune", action="store_true", help="Apply retention after a successful run")
parser.add_argument("--prune-max-delete", type=int, default=10)
parser.add_argument("--prune-protect-bases", action="store_true")
parser.add_argument("--manual", action="store_true", help="Record the run as manual instead of scheduled")
def handle(self, *args: Any, **options: Any) -> None:
host_name = options["host"]
paths = PobsyncPaths(home=Path(options["prefix"]))
try:
host = HostConfig.objects.get(host=host_name, enabled=True)
except HostConfig.DoesNotExist as exc:
raise CommandError(f"Missing enabled HostConfig {host_name!r}") from exc
run = BackupRun.objects.create(
host=host,
run_type=BackupRun.RunType.MANUAL if options["manual"] else BackupRun.RunType.SCHEDULED,
status=BackupRun.Status.RUNNING,
result={
"requested": {
"dry_run": bool(options["dry_run"]),
"verbose_output": bool(options["dry_run"] or options["verbose_rsync"]),
"prune": bool(options["prune"]),
"prune_max_delete": int(options["prune_max_delete"]),
"prune_protect_bases": bool(options["prune_protect_bases"]),
}
},
)
execute_backup_run(
run=run,
prefix=paths.home,
dry_run=bool(options["dry_run"]),
verbose_output=bool(options["dry_run"] or options["verbose_rsync"]),
prune=bool(options["prune"]),
prune_max_delete=int(options["prune_max_delete"]),
prune_protect_bases=bool(options["prune_protect_bases"]),
)
run.refresh_from_db()
if run.status == BackupRun.Status.SUCCESS:
self.stdout.write(self.style.SUCCESS(f"Backup completed for {host.host}."))
return
raise CommandError(f"Backup failed for {host.host}; run id={run.id}")