Controlla raggiungibilita share backup
This commit is contained in:
@@ -10,7 +10,7 @@ from pathlib import Path
|
||||
|
||||
from .config import AppConfig
|
||||
from .registry import ChangeEvent, ChangeRegistry
|
||||
from .server_check import check_server
|
||||
from .server_check import check_backup_target
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -23,7 +23,7 @@ class BackupResult:
|
||||
|
||||
|
||||
def run_backup(config: AppConfig, logger: logging.Logger) -> BackupResult:
|
||||
status = check_server(config.backup)
|
||||
status = check_backup_target(config.backup)
|
||||
if not status.reachable:
|
||||
message = f"Server backup non raggiungibile: {status.message}"
|
||||
logger.error(message)
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import socket
|
||||
import subprocess
|
||||
from dataclasses import asdict, dataclass
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
@@ -31,6 +32,49 @@ def check_server(config: BackupConfig) -> ServerStatus:
|
||||
return ServerStatus(False, checked_at, str(exc))
|
||||
|
||||
|
||||
def check_backup_target(config: BackupConfig) -> ServerStatus:
|
||||
if config.engine != "robocopy":
|
||||
return check_server(config)
|
||||
|
||||
checked_at = datetime.now(timezone.utc).isoformat()
|
||||
if not config.remote_destinations:
|
||||
return ServerStatus(False, checked_at, "No backup shares configured")
|
||||
|
||||
server_status = check_server(config)
|
||||
if not server_status.reachable:
|
||||
return server_status
|
||||
|
||||
unreachable = [
|
||||
destination
|
||||
for destination in config.remote_destinations
|
||||
if not share_is_reachable(destination, config.server_check.timeout_seconds)
|
||||
]
|
||||
if unreachable:
|
||||
return ServerStatus(
|
||||
False,
|
||||
checked_at,
|
||||
"Backup share unreachable: " + ", ".join(unreachable),
|
||||
)
|
||||
|
||||
return ServerStatus(True, checked_at, "Backup shares reachable")
|
||||
|
||||
|
||||
def share_is_reachable(destination: str, timeout_seconds: int) -> bool:
|
||||
probe = destination.rstrip("\\/") + "\\."
|
||||
command = ["cmd.exe", "/d", "/c", f'if exist "{probe}" (exit /b 0) else (exit /b 1)']
|
||||
try:
|
||||
completed = subprocess.run(
|
||||
command,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=max(timeout_seconds, 1),
|
||||
check=False,
|
||||
)
|
||||
except (OSError, subprocess.TimeoutExpired):
|
||||
return False
|
||||
return completed.returncode == 0
|
||||
|
||||
|
||||
def write_status(path: Path, status: ServerStatus, pending_count: int) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
payload = asdict(status)
|
||||
|
||||
@@ -9,7 +9,7 @@ from tkinter import messagebox
|
||||
from .config import load_config
|
||||
from .logging_setup import close_logger, configure_logging
|
||||
from .registry import ChangeRegistry
|
||||
from .server_check import ServerStatus, check_server, write_status
|
||||
from .server_check import ServerStatus, check_backup_target, write_status
|
||||
|
||||
|
||||
ALERT_MESSAGE = "Accendi il server di backup o verifica che sia connesso alla rete"
|
||||
@@ -19,7 +19,7 @@ def run_server_notifier(always_alert: bool = False) -> int:
|
||||
config = load_config()
|
||||
logger = configure_logging(config.storage.logs_dir, "server-notifier")
|
||||
try:
|
||||
status = check_server(config.backup)
|
||||
status = check_backup_target(config.backup)
|
||||
pending_count = ChangeRegistry(config.storage.change_registry).pending_count()
|
||||
write_status(config.storage.status_file, status, pending_count)
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<Exec>
|
||||
<Command>C:\Python314\python.exe</Command>
|
||||
<Arguments>-m bakrest.tray_app --nogui</Arguments>
|
||||
<WorkingDirectory>C:\devel\bak&rest</WorkingDirectory>
|
||||
<WorkingDirectory>C:\programmi\bak-and-rest</WorkingDirectory>
|
||||
</Exec>
|
||||
</Actions>
|
||||
</Task>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<Exec>
|
||||
<Command>C:\Python314\python.exe</Command>
|
||||
<Arguments>-m bakrest.server_notifier</Arguments>
|
||||
<WorkingDirectory>C:\devel\bak&rest</WorkingDirectory>
|
||||
<WorkingDirectory>C:\programmi\bak-and-rest</WorkingDirectory>
|
||||
</Exec>
|
||||
</Actions>
|
||||
</Task>
|
||||
|
||||
32
tests/test_server_check.py
Normal file
32
tests/test_server_check.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
|
||||
from bakrest.server_check import share_is_reachable
|
||||
|
||||
|
||||
def test_share_is_reachable_returns_true_on_zero_exit(monkeypatch) -> None:
|
||||
def fake_run(*args, **kwargs):
|
||||
return subprocess.CompletedProcess(args[0], 0)
|
||||
|
||||
monkeypatch.setattr("bakrest.server_check.subprocess.run", fake_run)
|
||||
|
||||
assert share_is_reachable("\\\\server\\share", 3)
|
||||
|
||||
|
||||
def test_share_is_reachable_returns_false_on_nonzero_exit(monkeypatch) -> None:
|
||||
def fake_run(*args, **kwargs):
|
||||
return subprocess.CompletedProcess(args[0], 1)
|
||||
|
||||
monkeypatch.setattr("bakrest.server_check.subprocess.run", fake_run)
|
||||
|
||||
assert not share_is_reachable("\\\\server\\share", 3)
|
||||
|
||||
|
||||
def test_share_is_reachable_returns_false_on_timeout(monkeypatch) -> None:
|
||||
def fake_run(*args, **kwargs):
|
||||
raise subprocess.TimeoutExpired(args[0], 3)
|
||||
|
||||
monkeypatch.setattr("bakrest.server_check.subprocess.run", fake_run)
|
||||
|
||||
assert not share_is_reachable("\\\\server\\share", 3)
|
||||
Reference in New Issue
Block a user