fix(backups): degrade gracefully when the backup dir is not accessible

This commit is contained in:
Juan Denis committed 2026-11-03 12:57:58 -05:00
1 parent dd9003d458
commit 9b93cb34ef
3 files changed
+42 -2

No files matched your search

+19 -2
View File
@@ -1,3 +1,4 @@
import logging
import os
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required
@@ -11,6 +12,10 @@ from app.exceptions import field_required, not_found
from app.api._request import json_object
backups_bp = Blueprint('backups', __name__)
logger = logging.getLogger(__name__)
_STORAGE_UNAVAILABLE = ('Backup storage is not accessible: the panel cannot create or read '
'its backup directory. Check its ownership and permissions.')
# UI-facing metadata for the CORE target types. Extension kinds
@@ -62,7 +67,12 @@ def list_target_types():
def list_backups():
"""List all backups."""
backup_type = request.args.get('type')
backups = BackupService.list_backups(backup_type)
try:
backups = BackupService.list_backups(backup_type)
except OSError:
# e.g. PermissionError creating /var/backups/serverkit: keep the page usable.
logger.exception('Backup directory is not accessible')
return jsonify({'backups': [], 'warning': _STORAGE_UNAVAILABLE}), 200
return jsonify({'backups': backups}), 200
@@ -70,7 +80,14 @@ def list_backups():
@admin_required
def get_stats():
"""Get backup statistics."""
stats = BackupService.get_backup_stats()
try:
stats = BackupService.get_backup_stats()
except OSError:
logger.exception('Backup directory is not accessible')
stats = {'total_backups': 0, 'application_backups': 0, 'database_backups': 0,
'file_backups': 0, 'total_size': 0, 'total_size_human': '0 B',
'remote_count': 0, 'remote_size': 0, 'remote_size_human': '0 B',
'warning': _STORAGE_UNAVAILABLE}
return jsonify(stats), 200
@@ -0,0 +1,22 @@
"""GET /backups must not 500 when the backup directory cannot be created."""
import pytest
from app.services.backup_service import BackupService
@pytest.fixture
def unwritable(monkeypatch):
def deny():
raise PermissionError(13, 'Permission denied', '/var/backups/serverkit')
monkeypatch.setattr(BackupService, 'ensure_backup_dirs', deny)
@pytest.mark.parametrize('path', ['/api/v1/backups', '/api/v1/backups/stats'])
def test_get_degrades_with_a_warning(client, auth_headers, unwritable, path):
resp = client.get(path, headers=auth_headers)
assert resp.status_code == 200
body = resp.get_json()
assert 'not accessible' in body['warning']
assert '/var/backups' not in body['warning']
assert body.get('backups', []) == []
+1
View File
@@ -216,6 +216,7 @@ const Backups = () => {
]);
setBackups(backupsRes.backups || []);
if (backupsRes.warning) setError(backupsRes.warning);
setStats(statsRes);
setConfig(configRes);
if (refreshSchedules) await reloadSchedules();