fix(backups): answer 503 backup_dir_unavailable when the backup dir is not writable

This commit is contained in:
Juan Denis committed 2026-11-03 13:10:27 -05:00
1 parent cb176ab678
commit 60a5e0a18a
2 files changed
+19 -1

No files matched your search

+8 -1
View File
@@ -8,7 +8,7 @@ from app.services.backup_service import BackupService
from app.services.backup_policy_service import BackupPolicyService, BackupPolicyError
from app.services.storage_provider_service import StorageProviderService
from app import db, paths
from app.exceptions import field_required, not_found
from app.exceptions import DependencyUnavailableError, field_required, not_found
from app.api._request import json_object
backups_bp = Blueprint('backups', __name__)
@@ -18,6 +18,13 @@ _STORAGE_UNAVAILABLE = ('Backup storage is not accessible: the panel cannot crea
'its backup directory. Check its ownership and permissions.')
@backups_bp.errorhandler(PermissionError)
def _backup_dir_unavailable(exc):
logger.error('Backup directory is not writable: %s', exc)
err = DependencyUnavailableError('Backup directory is not writable', code='backup_dir_unavailable')
return jsonify(err.to_dict()), err.status_code
# UI-facing metadata for the CORE target types. Extension kinds
# carry their own label/scopes in backup_kind_registry. 'server' is listed
# but flagged unimplemented so the UI never shows a dead whole-server button.
@@ -20,3 +20,14 @@ def test_get_degrades_with_a_warning(client, auth_headers, unwritable, path):
assert 'not accessible' in body['warning']
assert '/var/backups' not in body['warning']
assert body.get('backups', []) == []
def test_create_returns_503_with_code_when_dir_unwritable(client, auth_headers, unwritable):
resp = client.post('/api/v1/backups/database', headers=auth_headers,
json={'db_type': 'mysql', 'db_name': 'x'})
assert resp.status_code == 503
body = resp.get_json()
assert body['code'] == 'backup_dir_unavailable'
assert body['error'] == 'Backup directory is not writable'
assert '/var/backups' not in resp.get_data(as_text=True)