Files
MeshSate/app/diagnostic/docker_probe.py

127 lines
3.8 KiB
Python
Raw Normal View History

"""启动时 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