diff --git a/app.py b/app.py index a5ac8dc..0ab878f 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,8 @@ import json import os +import re import subprocess +from datetime import datetime, timezone import requests from flask import Flask, jsonify, redirect, render_template_string, request @@ -13,20 +15,50 @@ SELF_NAME = os.environ.get("SELF_CONTAINER_NAME", "") API_TOKEN = os.environ["PANEL_API_TOKEN"] SERVER_IP = os.environ.get("SERVER_IP", "148.135.181.126") +ROUTER_RULE_RE = re.compile(r"^traefik\.http\.routers\.[^.]+\.rule$") + def check_auth(): auth = request.headers.get("Authorization", "") return auth == f"Bearer {API_TOKEN}" -def extract_hostname(labels, name): - key = f"traefik.http.routers.{name}.rule" - rule = labels.get(key, "") - if "`" in rule: - return rule.split("`")[1] +def extract_hostname(labels): + """Scan ALL traefik router rule labels, not just one matching the + container's own name — compose-based containers get auto-generated + docker names that no longer match the Traefik router name.""" + for key, value in labels.items(): + if ROUTER_RULE_RE.match(key) and "`" in value: + return value.split("`")[1] return None +def human_relative(iso_ts): + if not iso_ts or iso_ts.startswith("0001-01-01"): + return None + try: + dt = datetime.fromisoformat(iso_ts.replace("Z", "+00:00")) + except ValueError: + return None + secs = int((datetime.now(timezone.utc) - dt).total_seconds()) + if secs < 60: + return f"{secs} sn önce" + mins = secs // 60 + if mins < 60: + return f"{mins} dk önce" + hours = mins // 60 + if hours < 24: + return f"{hours} sa önce" + days = hours // 24 + return f"{days} gün önce" + + +def inspect_all(cid): + return json.loads(subprocess.run( + ["docker", "inspect", cid], capture_output=True, text=True, check=True + ).stdout)[0] + + def list_projects(): out = subprocess.run( ["docker", "ps", "-a", "--filter", "label=traefik.enable=true", "--format", "{{.ID}}"], @@ -35,18 +67,19 @@ def list_projects(): projects = [] for cid in out: - info = json.loads(subprocess.run( - ["docker", "inspect", cid], capture_output=True, text=True, check=True - ).stdout)[0] + info = inspect_all(cid) name = info["Name"].lstrip("/") if name == SELF_NAME: continue labels = info["Config"]["Labels"] or {} - hostname = extract_hostname(labels, name) + state = info["State"] + status = state["Status"] + when = human_relative(state.get("StartedAt") if status == "running" else state.get("FinishedAt")) projects.append({ "name": name, - "hostname": hostname, - "status": info["State"]["Status"], + "hostname": extract_hostname(labels), + "status": status, + "since": when, "image": info["Config"]["Image"], }) projects.sort(key=lambda p: p["name"]) @@ -59,7 +92,7 @@ def find_container_hostname(name): return None info = json.loads(result.stdout)[0] labels = info["Config"]["Labels"] or {} - return extract_hostname(labels, name) + return extract_hostname(labels) def ensure_dns(hostname): @@ -103,23 +136,36 @@ TEMPLATE = """
| Proje | Adres | Durum | İmaj | ||
|---|---|---|---|---|---|
| {{ p.name }} | {% if p.hostname %}{{ p.hostname }}{% else %}—{% endif %} | -{{ p.status }} | ++ {{ p.status }} + {% if p.since %}{{ p.since }}{% endif %} + | {{ p.image }} |
-
+
+ Loglar
+
+
+
|