"""启动时 Docker 能力检测(用 python docker SDK)。 返回三档: full — docker.sock 可访问,日志和 inspect 都能用 partial — 能连 socket 但权限受限 none — 完全不可用(没挂 socket / 包没装) """ from __future__ import annotations import os from datetime import datetime, timezone from typing import Any, Dict, List, Optional _PROBE_CONTAINER = "meshsafe-api" def _try_client() -> Optional["docker.DockerClient"]: """尝试创建 Docker client。失败返回 None。""" try: import docker # noqa: F401 except ImportError: return None try: import docker # from_env() 会自动读 DOCKER_HOST,没设的话走 unix:///var/run/docker.sock client = docker.from_env(timeout=5) client.ping() # 真正连一下 return client except Exception: # noqa: BLE001 return None def detect_docker_access(mode: str = "auto") -> Dict[str, Any]: now = datetime.now(timezone.utc).isoformat() sock_exists = os.path.exists("/var/run/docker.sock") client = _try_client() if mode == "false": return { "mode": "false", "status": "none", "docker.sock_exists": sock_exists, "docker_python_available": client is not None, "can_logs": False, "can_inspect": False, "containers": None, "message": "配置强制关闭 Docker 能力(diagnostics.docker.enabled=false)", "detected_at": now, } if client is None: if mode == "true": msg = "配置强制启用但 Docker Python SDK 不可用 — pip install docker" else: msg = "Docker SDK 未就绪 — 日志匹配/容器状态类规则已跳过" return { "mode": mode, "status": "none", "docker.sock_exists": sock_exists, "docker_python_available": False, "can_logs": False, "can_inspect": False, "containers": None, "message": msg, "detected_at": now, } # 真测 can_logs = False can_inspect = False containers: Optional[List[str]] = None try: c = client.containers.get(_PROBE_CONTAINER) c.logs(tail=1) can_logs = True c.attrs # 读取属性 can_inspect = True except Exception: # noqa: BLE001 pass try: containers = [c.name for c in client.containers.list(all=True)] except Exception: # noqa: BLE001 containers = None if can_logs and can_inspect: status = "full" msg = "Docker 访问正常 — 日志匹配 + 容器状态检测全部启用" elif can_logs or can_inspect: status = "partial" msg = f"Docker SDK 可用但权限受限(logs={can_logs}, inspect={can_inspect})" else: status = "none" msg = "docker.sock 未挂或权限不足 — 日志匹配类规则已跳过" if mode == "true" and status != "full": msg = f"配置强制启用但检测结果为 {status} — 检查 docker.sock 挂载" return { "mode": mode, "status": status, "docker.sock_exists": sock_exists, "docker_python_available": True, "can_logs": can_logs, "can_inspect": can_inspect, "containers": containers, "message": msg, "detected_at": now, } def status_message(status: str) -> str: return { "full": "✅ Docker 能力完整", "partial": "⚠️ Docker 访问受限", "none": "ℹ️ Docker 日志检测未启用", }.get(status, status) def get_client(): """获取共享 docker client(给 dumper / rules 用)。失败返回 None。""" try: import docker return docker.from_env(timeout=10) except Exception: # noqa: BLE001 return None