Extract fail2ban restart orchestration into jail_service

This commit is contained in:
2026-04-17 15:23:54 +02:00
parent c21cf82e9e
commit 33643880ed
5 changed files with 109 additions and 60 deletions

View File

@@ -33,7 +33,6 @@ from app.services import (
jail_service,
log_service,
)
from app.utils.config_file_utils import start_daemon, wait_for_fail2ban
log: structlog.stdlib.BoundLogger = structlog.get_logger()
@@ -187,9 +186,11 @@ async def restart_fail2ban(
"""
start_cmd_parts: list[str] = start_cmd.split()
# Step 1: stop the daemon via socket.
try:
await jail_service.restart(socket_path)
restarted = await jail_service.restart_daemon(
socket_path,
start_cmd_parts,
)
except JailOperationError as exc:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
@@ -198,16 +199,7 @@ async def restart_fail2ban(
except Fail2BanConnectionError as exc:
raise _bad_gateway(exc) from exc
# Step 2: start the daemon via subprocess.
await start_daemon(start_cmd_parts)
# Step 3: probe the socket until fail2ban is responsive or the budget
# expires.
fail2ban_running: bool = await wait_for_fail2ban(
socket_path,
max_wait_seconds=10.0,
)
if not fail2ban_running:
if not restarted:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail=(

View File

@@ -29,6 +29,7 @@ from app.models.jail import (
JailStatus,
JailSummary,
)
from app.utils.config_file_utils import start_daemon, wait_for_fail2ban
from app.utils.fail2ban_client import (
Fail2BanClient,
Fail2BanCommand,
@@ -759,6 +760,48 @@ async def restart(socket_path: str) -> None:
raise JailOperationError(str(exc)) from exc
async def restart_daemon(
socket_path: str,
start_cmd_parts: list[str],
max_wait_seconds: float = _SOCKET_TIMEOUT,
) -> bool:
"""Restart the fail2ban daemon and verify it comes back online.
This function stops the daemon through the socket, starts it with the
configured command, and probes the socket until fail2ban accepts status
requests again.
Args:
socket_path: Path to the fail2ban Unix domain socket.
start_cmd_parts: The configured fail2ban start command split into
executable and arguments.
max_wait_seconds: The maximum number of seconds to wait for the daemon
to become responsive after starting.
Returns:
``True`` when the daemon is started and responsive.
``False`` when the command failed or fail2ban never became responsive.
Raises:
JailOperationError: If the stop command failed.
~app.utils.fail2ban_client.Fail2BanConnectionError: If the socket
cannot be reached while stopping fail2ban.
"""
await restart(socket_path)
if not await start_daemon(start_cmd_parts):
log.warning(
"fail2ban_start_command_failed",
command=" ".join(start_cmd_parts),
)
return False
return await wait_for_fail2ban(
socket_path,
max_wait_seconds=max_wait_seconds,
)
# ---------------------------------------------------------------------------
# Public API — Ban / Unban
# ---------------------------------------------------------------------------