Refactor bot and integrate services
This commit is contained in:
114
services/docker.py
Normal file
114
services/docker.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import asyncio
|
||||
from datetime import datetime, timezone
|
||||
from typing import Dict
|
||||
from services.runner import run_cmd
|
||||
|
||||
|
||||
def container_uptime(started_at: str) -> str:
|
||||
"""
|
||||
started_at: 2026-02-06T21:14:33.123456789Z
|
||||
"""
|
||||
try:
|
||||
start = datetime.fromisoformat(
|
||||
started_at.replace("Z", "+00:00")
|
||||
).astimezone(timezone.utc)
|
||||
delta = datetime.now(timezone.utc) - start
|
||||
days = delta.days
|
||||
hours = delta.seconds // 3600
|
||||
minutes = (delta.seconds % 3600) // 60
|
||||
|
||||
if days > 0:
|
||||
return f"{days}d {hours}h"
|
||||
if hours > 0:
|
||||
return f"{hours}h {minutes}m"
|
||||
return f"{minutes}m"
|
||||
except Exception:
|
||||
return "unknown"
|
||||
|
||||
|
||||
async def build_docker_map(cfg) -> Dict[str, str]:
|
||||
docker_cfg = cfg.get("docker", {})
|
||||
|
||||
result: Dict[str, str] = {}
|
||||
|
||||
# 1. autodiscovery
|
||||
if docker_cfg.get("autodiscovery"):
|
||||
rc, raw = await run_cmd(
|
||||
["sudo", "docker", "ps", "--format", "{{.Names}}"],
|
||||
timeout=20
|
||||
)
|
||||
if rc == 0:
|
||||
names = raw.splitlines()
|
||||
patterns = docker_cfg.get("match", [])
|
||||
for name in names:
|
||||
if any(p in name for p in patterns):
|
||||
result[name] = name
|
||||
|
||||
# 2. aliases override
|
||||
aliases = docker_cfg.get("aliases", {})
|
||||
for alias, real in aliases.items():
|
||||
result[alias] = real
|
||||
|
||||
return result
|
||||
|
||||
|
||||
async def discover_containers(cfg) -> Dict[str, str]:
|
||||
"""
|
||||
returns: alias -> real container name
|
||||
"""
|
||||
docker_cfg = cfg.get("docker", {})
|
||||
result: Dict[str, str] = {}
|
||||
|
||||
# --- autodiscovery ---
|
||||
if docker_cfg.get("autodiscovery"):
|
||||
rc, raw = await run_cmd(
|
||||
["sudo", "docker", "ps", "--format", "{{.Names}}"],
|
||||
timeout=20
|
||||
)
|
||||
|
||||
if rc == 0:
|
||||
found = raw.splitlines()
|
||||
|
||||
label = docker_cfg.get("label")
|
||||
patterns = docker_cfg.get("match", [])
|
||||
|
||||
for name in found:
|
||||
# label-based discovery
|
||||
if label:
|
||||
key, val = label.split("=", 1)
|
||||
rc2, lbl = await run_cmd([
|
||||
"sudo", "docker", "inspect",
|
||||
"-f", f"{{{{ index .Config.Labels \"{key}\" }}}}",
|
||||
name
|
||||
])
|
||||
if rc2 == 0 and lbl.strip() == val:
|
||||
result[name] = name
|
||||
continue
|
||||
|
||||
# name-pattern discovery
|
||||
if any(p in name for p in patterns):
|
||||
result[name] = name
|
||||
|
||||
# --- manual aliases ALWAYS override ---
|
||||
aliases = docker_cfg.get("aliases", {})
|
||||
for alias, real in aliases.items():
|
||||
result[alias] = real
|
||||
|
||||
return result
|
||||
|
||||
|
||||
async def docker_watchdog(container_map, notify, bot, chat_id):
|
||||
last = {}
|
||||
while True:
|
||||
for alias, real in container_map.items():
|
||||
rc, state = await run_cmd(
|
||||
["docker", "inspect", "-f", "{{.State.Status}}", real],
|
||||
timeout=10
|
||||
)
|
||||
if rc != 0:
|
||||
state = "error"
|
||||
state = state.strip()
|
||||
if last.get(alias) != state:
|
||||
await notify(bot, chat_id, f"🐳 {alias}: {state}")
|
||||
last[alias] = state
|
||||
await asyncio.sleep(120)
|
||||
Reference in New Issue
Block a user