Files
MeshSate/app/diagnostic/docker_probe.py
zhaolei 16f134e328 feat: MeshSafe 文件摆渡安全卫士 v1.0 初始提交
核心功能:
- 6 层检测管线: L0 结构分析 → L1 ClamAV → L2 文档深度检测 → L3 关键词匹配 → L4 YARA → L5 PE/二进制
- FastAPI + PostgreSQL + Redis + Docker Compose 架构
- 客户端 HMAC-SHA256 签名鉴权 + 限流 + 幂等性
- 控制台 UI (登录/Dashboard/诊断中心/策略管理/任务列表/测试中心/产品介绍页)
- 三层诊断定时器 (error_scan 30s / db_aggregate 30s / container_check 5min)

并发与稳定性修复:
- 诊断定时器 Redis 时间槽位锁 (多 worker 同一槽位只有一个执行)
- JSONL 存储 fcntl 跨进程排他锁 + 容错解码 + 原子重写
- 移除 SQLite fallback, 统一 PostgreSQL
- API_CLIENTS 脱敏为环境变量, .env 已 .gitignore
2026-10-28 19:07:11 +08:00

127 lines
3.8 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""启动时 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