Require password to access logs page
This commit is contained in:
65
app.py
65
app.py
@@ -2,15 +2,18 @@ import os
|
||||
import json
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from flask import Flask, jsonify, render_template
|
||||
from flask import Flask, jsonify, render_template, request, session, redirect, url_for
|
||||
from functools import wraps
|
||||
import re
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = os.getenv("SECRET_KEY", "change-this-in-production-please")
|
||||
|
||||
POLL_SECONDS = int(os.getenv("POLL_SECONDS", "10"))
|
||||
APP_DOMAIN = os.getenv("APP_DOMAIN", "peterstockings.com")
|
||||
DOCKER = os.getenv("DOCKER_BIN", "/usr/bin/docker")
|
||||
SHOW_INFRA = os.getenv("SHOW_INFRA", "1") == "1"
|
||||
LOGS_PASSWORD = os.getenv("LOGS_PASSWORD", "dokkustatus123") # Change via environment variable
|
||||
|
||||
_UNIT = {
|
||||
"b": 1,
|
||||
@@ -200,7 +203,6 @@ def collect():
|
||||
"mem_limit": s.get("mem_limit", ""),
|
||||
"mem_pct": s.get("mem_pct", ""),
|
||||
"restarts": docker_inspect_restart_count(name),
|
||||
"logs": get_container_logs(name, lines=50),
|
||||
}
|
||||
|
||||
if is_app_web_container(name):
|
||||
@@ -286,6 +288,32 @@ def collect():
|
||||
"warnings": warnings,
|
||||
}
|
||||
|
||||
def collect_logs_only():
|
||||
"""
|
||||
Lightweight version that only collects app names and logs.
|
||||
Much faster than collect() since it skips stats, metrics, and system info.
|
||||
"""
|
||||
ps_rows = docker_ps_all()
|
||||
apps = []
|
||||
|
||||
for r in ps_rows:
|
||||
name = r["name"]
|
||||
|
||||
if is_app_web_container(name):
|
||||
app_name = infer_app_name(name)
|
||||
apps.append({
|
||||
"app": app_name,
|
||||
"container": name,
|
||||
"logs": get_container_logs(name, lines=50),
|
||||
})
|
||||
|
||||
# Sort by app name
|
||||
apps.sort(key=lambda x: x["app"])
|
||||
|
||||
return {
|
||||
"apps": apps,
|
||||
}
|
||||
|
||||
def parse_human_bytes(s: str) -> int:
|
||||
# Handles "58.84MiB", "145.1MB", "423B"
|
||||
s = s.strip()
|
||||
@@ -317,3 +345,36 @@ def partial_apps():
|
||||
@app.get("/api/status")
|
||||
def api_status():
|
||||
return jsonify(collect())
|
||||
|
||||
# Authentication decorator
|
||||
def login_required(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if not session.get('logged_in'):
|
||||
return redirect(url_for('login'))
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
# Login routes
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if request.method == "POST":
|
||||
password = request.form.get("password", "")
|
||||
if password == LOGS_PASSWORD:
|
||||
session['logged_in'] = True
|
||||
return redirect(url_for('logs'))
|
||||
else:
|
||||
return render_template("login.html", error="Invalid password")
|
||||
return render_template("login.html", error=None)
|
||||
|
||||
@app.get("/logout")
|
||||
def logout():
|
||||
session.pop('logged_in', None)
|
||||
return redirect(url_for('index'))
|
||||
|
||||
# Protected logs page
|
||||
@app.get("/logs")
|
||||
@login_required
|
||||
def logs():
|
||||
data = collect_logs_only()
|
||||
return render_template("logs.html", data=data, poll_seconds=POLL_SECONDS)
|
||||
|
||||
Reference in New Issue
Block a user