Move Fail2Ban exceptions into central app.exceptions module

This commit is contained in:
2026-04-15 10:22:48 +02:00
parent a79f5339bc
commit 328f3575e2
18 changed files with 305 additions and 365 deletions

View File

@@ -27,6 +27,24 @@ class ServerOperationError(Exception):
"""Raised when a server control command (e.g. refresh) fails."""
class Fail2BanConnectionError(Exception):
"""Raised when the fail2ban socket is unreachable or returns an error."""
def __init__(self, message: str, socket_path: str) -> None:
"""Initialize with a human-readable message and the socket path.
Args:
message: Description of the connection problem.
socket_path: The fail2ban socket path that was targeted.
"""
self.socket_path: str = socket_path
super().__init__(f"{message} (socket: {socket_path})")
class Fail2BanProtocolError(Exception):
"""Raised when the response from fail2ban cannot be parsed."""
class FilterInvalidRegexError(Exception):
"""Raised when a regex pattern fails to compile."""

View File

@@ -44,7 +44,7 @@ from app.routers import (
setup,
)
from app.startup import startup_shared_resources
from app.utils.fail2ban_client import Fail2BanConnectionError, Fail2BanProtocolError
from app.exceptions import Fail2BanConnectionError, Fail2BanProtocolError
from app.utils.runtime_state import ApplicationState, RuntimeState
from app.utils.session_cache import InMemorySessionCache, NoOpSessionCache
from app.utils.setup_state import is_setup_complete_cached, set_setup_complete_cache
@@ -162,7 +162,7 @@ async def _fail2ban_connection_handler(
Args:
request: The incoming FastAPI request.
exc: The :class:`~app.utils.fail2ban_client.Fail2BanConnectionError`.
exc: The :class:`~app.exceptions.Fail2BanConnectionError`.
Returns:
A :class:`fastapi.responses.JSONResponse` with status 502.
@@ -187,7 +187,7 @@ async def _fail2ban_protocol_handler(
Args:
request: The incoming FastAPI request.
exc: The :class:`~app.utils.fail2ban_client.Fail2BanProtocolError`.
exc: The :class:`~app.exceptions.Fail2BanProtocolError`.
Returns:
A :class:`fastapi.responses.JSONResponse` with status 502.

View File

@@ -23,7 +23,7 @@ from app.exceptions import JailNotFoundError, JailOperationError
from app.models.ban import ActiveBanListResponse, BanRequest, UnbanAllResponse, UnbanRequest
from app.models.jail import JailCommandResponse
from app.services import jail_service
from app.utils.fail2ban_client import Fail2BanConnectionError
from app.exceptions import Fail2BanConnectionError
router: APIRouter = APIRouter(prefix="/api/bans", tags=["Bans"])

View File

@@ -20,7 +20,7 @@ from app.models.config import (
ServiceStatusResponse,
)
from app.services import config_file_service, config_service, jail_service, log_service, setup_service
from app.utils.fail2ban_client import Fail2BanConnectionError
from app.exceptions import Fail2BanConnectionError
log: structlog.stdlib.BoundLogger = structlog.get_logger()

View File

@@ -24,7 +24,7 @@ from app.dependencies import (
)
from app.models.geo import GeoCacheStatsResponse, GeoReResolveResponse, IpLookupResponse
from app.services import geo_service, jail_service
from app.utils.fail2ban_client import Fail2BanConnectionError
from app.exceptions import Fail2BanConnectionError
router: APIRouter = APIRouter(prefix="/api/geo", tags=["Geo"])

View File

@@ -46,7 +46,7 @@ from app.services import (
filter_config_service,
jail_config_service,
)
from app.utils.fail2ban_client import Fail2BanConnectionError
from app.exceptions import Fail2BanConnectionError
from app.utils.runtime_state import (
clear_activation_record,
clear_pending_recovery,

View File

@@ -40,7 +40,7 @@ from app.models.jail import (
JailListResponse,
)
from app.services import jail_service
from app.utils.fail2ban_client import Fail2BanConnectionError
from app.exceptions import Fail2BanConnectionError
router: APIRouter = APIRouter(prefix="/api/jails", tags=["Jails"])

View File

@@ -16,7 +16,7 @@ from app.dependencies import AuthDep, Fail2BanSocketDep
from app.models.server import ServerSettingsResponse, ServerSettingsUpdate
from app.services import server_service
from app.exceptions import ServerOperationError
from app.utils.fail2ban_client import Fail2BanConnectionError
from app.exceptions import Fail2BanConnectionError
router: APIRouter = APIRouter(prefix="/api/server", tags=["Server"])

View File

@@ -27,6 +27,8 @@ from typing import TYPE_CHECKING, Protocol
import structlog
from app.exceptions import Fail2BanConnectionError, Fail2BanProtocolError
# ---------------------------------------------------------------------------
# Types
# ---------------------------------------------------------------------------
@@ -125,23 +127,6 @@ _RETRY_INITIAL_BACKOFF: float = 0.15 # seconds; doubles on each attempt
_COMMAND_SEMAPHORE_CONCURRENCY: int = 10
class Fail2BanConnectionError(Exception):
"""Raised when the fail2ban socket is unreachable or returns an error."""
def __init__(self, message: str, socket_path: str) -> None:
"""Initialise with a human-readable message and the socket path.
Args:
message: Description of the connection problem.
socket_path: The fail2ban socket path that was targeted.
"""
self.socket_path: str = socket_path
super().__init__(f"{message} (socket: {socket_path})")
class Fail2BanProtocolError(Exception):
"""Raised when the response from fail2ban cannot be parsed."""
def _send_command_sync(
socket_path: str,