80 lines
2.6 KiB
Python
80 lines
2.6 KiB
Python
"""System administration (spec sections 29, 41, 46).
|
|
|
|
Broker status and restart through the control sidecar. The restart
|
|
primitive is SIGTERM to PID 1 in the broker's (shared) PID namespace —
|
|
the broker shuts down gracefully (persistence saved) and Docker's
|
|
`restart: unless-stopped` policy brings the container back. No Docker
|
|
socket is involved (spec section 29).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, Request
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app import audit
|
|
from app.db import get_db
|
|
from app.deps import CurrentUser, require_roles
|
|
from app.models import ManagementRole
|
|
from app.routers.broker import _call_control, restart_required
|
|
|
|
router = APIRouter(prefix="/api/v1/system", tags=["system"])
|
|
|
|
BrokerAdmin = Annotated[CurrentUser, Depends(require_roles(ManagementRole.BROKER_ADMIN))]
|
|
AnyReader = Annotated[
|
|
CurrentUser,
|
|
Depends(
|
|
require_roles(
|
|
ManagementRole.BROKER_ADMIN,
|
|
ManagementRole.OPERATOR,
|
|
ManagementRole.AUDITOR,
|
|
)
|
|
),
|
|
]
|
|
DbDep = Annotated[Session, Depends(get_db)]
|
|
|
|
|
|
@router.get("/status")
|
|
def system_status(db: DbDep, _user: AnyReader):
|
|
"""Broker process state + pending-restart flag (spec section 46).
|
|
|
|
Used by the sidebar indicator (polls lightly) and the System page.
|
|
The control call is allowed to fail — an unreachable sidecar is a
|
|
status, not an error.
|
|
"""
|
|
try:
|
|
control = _call_control("/status", method="GET")
|
|
broker_alive = bool(control.get("broker_pid_alive"))
|
|
except Exception: # noqa: BLE001 - status endpoint must not 500
|
|
broker_alive = False
|
|
return {
|
|
"broker_alive": broker_alive,
|
|
"restart_required": restart_required(db),
|
|
}
|
|
|
|
|
|
@router.post("/broker/restart")
|
|
def restart_broker(request: Request, db: DbDep, user: BrokerAdmin):
|
|
"""Restart the broker via the control sidecar (spec section 29).
|
|
|
|
The sidecar acknowledges and then SIGTERMs PID 1; Docker restarts
|
|
the container. The pending-restart flag is cleared here — the config
|
|
on disk is what the broker will boot with, so listener changes take
|
|
effect by definition once the restart completes.
|
|
"""
|
|
from app.routers.broker import _set_restart_required
|
|
|
|
response = _call_control("/restart")
|
|
_set_restart_required(db, False)
|
|
audit.record(
|
|
db,
|
|
"BROKER_RESTARTED",
|
|
request=request,
|
|
user=user.username,
|
|
object_type="broker",
|
|
object_id="mosquitto",
|
|
result="initiated",
|
|
)
|
|
return {"status": "restarting", "broker_alive": False} |