(feature) Add remote host connection preflight
Add an on-demand host preflight action that verifies SSH reachability, remote rsync availability, and remote source root access. Persist the latest preflight result on the host config, render it in Django, and block real backups when the last remote preflight failed.
This commit is contained in:
@@ -31,7 +31,7 @@ from .forms import (
|
||||
)
|
||||
from .host_ops import ensure_host_directories
|
||||
from .models import BackupRun, GlobalConfig, HostConfig, ScheduleConfig, SnapshotRecord, SshCredential
|
||||
from .preflight import collect_backup_gate, effective_host_config_preview
|
||||
from .preflight import collect_backup_gate, effective_host_config_preview, run_remote_preflight
|
||||
from .retention import run_sql_retention_apply, run_sql_retention_plan
|
||||
from .self_check import collect_self_checks, summarize_self_checks
|
||||
from .scheduler import next_due_after
|
||||
@@ -280,6 +280,7 @@ def host_detail(request, host: str):
|
||||
"host_checks": backup_gate.checks,
|
||||
"host_check_summary": summarize_self_checks(backup_gate.checks),
|
||||
"backup_gate": backup_gate,
|
||||
"last_preflight": (host_config.config or {}).get("last_preflight") if isinstance(host_config.config, dict) else {},
|
||||
"effective_config": effective_host_config_preview(host_config, global_config) if global_config else {},
|
||||
"stats_summary": stats_summary,
|
||||
"manual_backup_form": ManualBackupForm(initial=_default_manual_backup_initial(host_config)),
|
||||
@@ -336,6 +337,34 @@ def scan_host_known_key(request, host: str):
|
||||
return redirect("host_detail", host=host_config.host)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@require_POST
|
||||
def run_host_preflight(request, host: str):
|
||||
host_config = get_object_or_404(HostConfig, host=host)
|
||||
if not host_config.enabled:
|
||||
messages.error(request, f"Cannot run preflight for disabled host {host_config.host}.")
|
||||
return redirect("host_detail", host=host_config.host)
|
||||
if not GlobalConfig.objects.filter(name="default").exists():
|
||||
messages.error(request, "Create the default global config before running preflight.")
|
||||
return redirect("host_detail", host=host_config.host)
|
||||
|
||||
try:
|
||||
result = run_remote_preflight(host_config)
|
||||
except Exception as exc:
|
||||
messages.error(request, f"Connection preflight failed for {host_config.host}: {exc}")
|
||||
else:
|
||||
if result.get("ok"):
|
||||
messages.success(request, f"Connection preflight passed for {host_config.host}.")
|
||||
else:
|
||||
failed = [
|
||||
str(check.get("name"))
|
||||
for check in result.get("checks", [])
|
||||
if isinstance(check, dict) and not check.get("ok")
|
||||
]
|
||||
messages.error(request, f"Connection preflight failed for {host_config.host}: {', '.join(failed)}.")
|
||||
return redirect("host_detail", host=host_config.host)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
@require_POST
|
||||
def queue_manual_backup(request, host: str):
|
||||
|
||||
Reference in New Issue
Block a user