from aiogram import F from aiogram.types import Message from app import dp from auth import is_admin_msg from keyboards import docker_kb, docker_inline_kb from services.docker import container_uptime, docker_cmd from state import DOCKER_MAP, LOG_FILTER_PENDING import time async def cmd_docker_status(msg: Message): try: if not DOCKER_MAP: await msg.answer( "⚠️ DOCKER_MAP пуст.\n" "Контейнеры не обнаружены.", reply_markup=docker_kb, ) return lines = ["🐳 Docker containers\n"] for alias, real in DOCKER_MAP.items(): rc, raw = await docker_cmd( ["inspect", "-f", "{{.State.Status}}|{{.State.StartedAt}}", real], timeout=10, ) if rc != 0: lines.append(f"🔴 {alias}: inspect error") continue raw = raw.strip() if "|" not in raw: lines.append(f"🟡 {alias}: invalid inspect output") continue status, started = raw.split("|", 1) up = container_uptime(started) icon = "🟢" if status == "running" else "🔴" lines.append(f"{icon} {alias}: {status} ({up})") await msg.answer("\n".join(lines), reply_markup=docker_kb) except Exception as e: # ⬅️ КРИТИЧЕСКИ ВАЖНО await msg.answer( "❌ Docker status crashed:\n" f"```{type(e).__name__}: {e}```", reply_markup=docker_kb, parse_mode="Markdown", ) @dp.message(F.text == "🔄 Restart") async def dr(msg: Message): if is_admin_msg(msg): await msg.answer( "🔄 Выберите контейнер для рестарта:", reply_markup=docker_inline_kb("restart") ) @dp.message(F.text == "📜 Logs") async def dl(msg: Message): if is_admin_msg(msg): await msg.answer( "📜 Выберите контейнер для логов:", reply_markup=docker_inline_kb("logs") ) @dp.message(F.text == "🐳 Status") async def ds(msg: Message): if is_admin_msg(msg): await cmd_docker_status(msg) @dp.message(F.text, F.func(lambda msg: msg.from_user and msg.from_user.id in LOG_FILTER_PENDING)) async def log_filter_input(msg: Message): if not is_admin_msg(msg): return pending = LOG_FILTER_PENDING.pop(msg.from_user.id, None) if not pending: return alias = pending["alias"] real = DOCKER_MAP.get(alias) if not real: await msg.answer("⚠️ Container not found", reply_markup=docker_kb) return needle = (msg.text or "").strip() if not needle: await msg.answer("⚠️ Empty filter text", reply_markup=docker_kb) return since_ts = str(int(time.time() - int(pending.get("since_sec", 1800)))) rc, out = await docker_cmd(["logs", "--since", since_ts, "--tail", "400", real]) if rc != 0: await msg.answer(out, reply_markup=docker_kb) return if not out.strip(): await msg.answer("⚠️ Нет логов за выбранный период", reply_markup=docker_kb) return lines = [line for line in out.splitlines() if needle.lower() in line.lower()] filtered = "\n".join(lines) if lines else "(no matches)" await msg.answer( f"📜 **Logs filter: {alias}**\n```{filtered}```", parse_mode="Markdown", reply_markup=docker_kb, )