Add container info as well

This commit is contained in:
Peter Stockings
2025-12-23 23:28:54 +11:00
parent 45bee0504b
commit 78e71b3895
5 changed files with 795 additions and 8 deletions

80
app.py
View File

@@ -159,6 +159,62 @@ def get_container_logs(container_name: str, lines: int = 50) -> list[dict]:
except Exception:
return []
def get_container_detail(container_name: str) -> dict:
"""
Get detailed container information using docker inspect.
Returns parsed container metadata.
"""
try:
out = sh([DOCKER, "inspect", container_name])
inspect_data = json.loads(out)
if not inspect_data:
return {}
container = inspect_data[0]
# Extract useful information
config = container.get("Config", {})
state = container.get("State", {})
network_settings = container.get("NetworkSettings", {})
mounts = container.get("Mounts", [])
return {
"name": container.get("Name", "").lstrip("/"),
"id": container.get("Id", "")[:12],
"image": config.get("Image", ""),
"created": container.get("Created", ""),
"state": {
"status": state.get("Status", ""),
"running": state.get("Running", False),
"paused": state.get("Paused", False),
"restarting": state.get("Restarting", False),
"started_at": state.get("StartedAt", ""),
"finished_at": state.get("FinishedAt", ""),
},
"env": config.get("Env", []),
"cmd": config.get("Cmd", []),
"entrypoint": config.get("Entrypoint", []),
"working_dir": config.get("WorkingDir", ""),
"exposed_ports": list(config.get("ExposedPorts", {}).keys()),
"ports": network_settings.get("Ports", {}),
"networks": list(network_settings.get("Networks", {}).keys()),
"ip_address": network_settings.get("IPAddress", ""),
"mounts": [
{
"type": m.get("Type", ""),
"source": m.get("Source", ""),
"destination": m.get("Destination", ""),
"mode": m.get("Mode", ""),
"rw": m.get("RW", False),
}
for m in mounts
],
"restart_policy": container.get("HostConfig", {}).get("RestartPolicy", {}),
}
except Exception as e:
return {"error": str(e)}
def is_app_web_container(name: str) -> bool:
# Dokku apps typically have containers like "<app>.web.1"
return name.endswith(".web.1") and not name.startswith("dokku.")
@@ -362,7 +418,7 @@ def login():
password = request.form.get("password", "")
if password == LOGS_PASSWORD:
session['logged_in'] = True
return redirect(url_for('logs'))
return redirect(url_for('admin'))
else:
return render_template("login.html", error="Invalid password")
return render_template("login.html", error=None)
@@ -372,9 +428,23 @@ def logout():
session.pop('logged_in', None)
return redirect(url_for('index'))
# Protected logs page
@app.get("/logs")
# Protected admin page (logs + container details)
@app.get("/admin")
@login_required
def logs():
def admin():
data = collect_logs_only()
return render_template("logs.html", data=data, poll_seconds=POLL_SECONDS)
return render_template("admin.html", data=data, poll_seconds=POLL_SECONDS)
# Protected container detail page
@app.get("/admin/container/<container_name>")
@login_required
def container_detail(container_name):
detail = get_container_detail(container_name)
return render_template("container_detail.html", container=detail, container_name=container_name)
# API endpoint for container details (used by admin panel)
@app.get("/api/container/<container_name>")
@login_required
def api_container_detail(container_name):
detail = get_container_detail(container_name)
return jsonify(detail)