From 3da82255ff19691099446b9f6745ebf777467a72 Mon Sep 17 00:00:00 2001 From: kodi Date: Fri, 6 Mar 2026 18:38:58 +0100 Subject: [PATCH] feat (ui): exec fase 4 --- control/app_containers.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/control/app_containers.py b/control/app_containers.py index cf3715a..5eb8994 100644 --- a/control/app_containers.py +++ b/control/app_containers.py @@ -35,6 +35,8 @@ _EXEC_SESSIONS = {} # session_id -> _ExecSessionState _EXEC_SESSIONS_LOCK = threading.Lock() _EXEC_SESSION_IDLE_TTL_SECONDS = 60 * 60 _EXEC_SESSION_CLOSED_GC_SECONDS = 5 * 60 +_EXEC_SESSION_MAX_ACTIVE = 12 +_EXEC_INPUT_MAX_BYTES = 32 * 1024 class ExecStartRequest(BaseModel): @@ -246,6 +248,27 @@ def _parse_stats_interval_seconds() -> float: return v +def _parse_positive_int_env(name: str, default: int, minimum: int, maximum: int) -> int: + raw = os.getenv(name, str(default)) + try: + v = int(raw) + except Exception: + v = int(default) + if v < minimum: + v = minimum + if v > maximum: + v = maximum + return v + + +def _exec_max_active_sessions() -> int: + return _parse_positive_int_env("EXEC_SESSION_MAX_ACTIVE", _EXEC_SESSION_MAX_ACTIVE, 1, 500) + + +def _exec_max_input_bytes() -> int: + return _parse_positive_int_env("EXEC_INPUT_MAX_BYTES", _EXEC_INPUT_MAX_BYTES, 64, 1024 * 1024) + + async def _stats_poller_loop(): global _STATS_CACHE_BY_NAME, _STATS_CACHE_TS @@ -592,6 +615,15 @@ def init_containers_router( req = ExecStartRequest() cmd = req.cmd or ["/bin/sh"] + with _EXEC_SESSIONS_LOCK: + active = sum(1 for s in _EXEC_SESSIONS.values() if not s.closed) + max_active = _exec_max_active_sessions() + if active >= max_active: + raise HTTPException( + status_code=429, + detail=f"Too many active exec sessions ({active}/{max_active})", + ) + create_url = f"{podman_api_base}/libpod/containers/{name}/exec" payload = { "AttachStdin": True, @@ -714,6 +746,12 @@ def init_containers_router( data = (req.data or "").encode("utf-8") if not data: return {"ok": True, "session_id": session_id, "bytes": 0} + max_bytes = _exec_max_input_bytes() + if len(data) > max_bytes: + raise HTTPException( + status_code=413, + detail=f"Input too large ({len(data)} bytes > {max_bytes} bytes)", + ) try: sess.sock.sendall(data)