Update container documentation to reflect disk space adjustments and Docker log management
Expand the root disk size from 35 GB to 50 GB and implement log size limits for Docker containers. Add details about the new monitoring dashboard for homelab services, including deployment instructions and access URL. Ensure clarity on log rotation policies and risks associated with disk space usage.
This commit is contained in:
104
scripts/dashboard/dashboard-server.py
Normal file
104
scripts/dashboard/dashboard-server.py
Normal file
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
HTTP-сервер дашборда homelab: статика, /api/containers, прокси к Netdata.
|
||||
Порт: 19998 (по умолчанию).
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.request
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from pathlib import Path
|
||||
|
||||
PORT = int(os.environ.get("DASHBOARD_PORT", "19998"))
|
||||
NETDATA_URL = os.environ.get("NETDATA_URL", "http://127.0.0.1:19999")
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
EXPORTER = SCRIPT_DIR / "dashboard-exporter.py"
|
||||
|
||||
|
||||
class DashboardHandler(BaseHTTPRequestHandler):
|
||||
def log_message(self, format, *args):
|
||||
pass # подавить вывод в консоль
|
||||
|
||||
def send_json(self, data: dict, status: int = 200):
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", "application/json; charset=utf-8")
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(data, ensure_ascii=False).encode("utf-8"))
|
||||
|
||||
def send_html(self, html: bytes, status: int = 200):
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type", "text/html; charset=utf-8")
|
||||
self.send_header("Cache-Control", "no-cache")
|
||||
self.end_headers()
|
||||
self.wfile.write(html)
|
||||
|
||||
def do_GET(self):
|
||||
path = self.path.split("?")[0].rstrip("/") or "/"
|
||||
if path == "/":
|
||||
self.serve_index()
|
||||
elif path == "/api/containers":
|
||||
self.serve_containers()
|
||||
elif path.startswith("/api/netdata"):
|
||||
self.proxy_netdata()
|
||||
else:
|
||||
self.send_error(404)
|
||||
|
||||
def serve_index(self):
|
||||
html_file = SCRIPT_DIR / "index.html"
|
||||
if html_file.exists():
|
||||
self.send_html(html_file.read_bytes())
|
||||
else:
|
||||
self.send_error(404, "index.html not found")
|
||||
|
||||
def serve_containers(self):
|
||||
try:
|
||||
r = subprocess.run(
|
||||
[sys.executable, str(EXPORTER)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
cwd=str(SCRIPT_DIR),
|
||||
)
|
||||
if r.returncode != 0:
|
||||
self.send_json({"ok": False, "error": r.stderr or "exporter failed"}, 500)
|
||||
return
|
||||
data = json.loads(r.stdout)
|
||||
self.send_json(data)
|
||||
except subprocess.TimeoutExpired:
|
||||
self.send_json({"ok": False, "error": "timeout"}, 504)
|
||||
except json.JSONDecodeError as e:
|
||||
self.send_json({"ok": False, "error": str(e)}, 500)
|
||||
except Exception as e:
|
||||
self.send_json({"ok": False, "error": str(e)}, 500)
|
||||
|
||||
def proxy_netdata(self):
|
||||
qs = self.path.split("?", 1)[1] if "?" in self.path else ""
|
||||
url = f"{NETDATA_URL}/api/v1/data?{qs}" if qs else f"{NETDATA_URL}/api/v1/data"
|
||||
try:
|
||||
req = urllib.request.Request(url)
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
data = resp.read()
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", resp.headers.get("Content-Type", "application/json"))
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
except Exception as e:
|
||||
self.send_json({"error": str(e)}, 502)
|
||||
|
||||
|
||||
def main():
|
||||
server = HTTPServer(("0.0.0.0", PORT), DashboardHandler)
|
||||
print(f"Dashboard server on http://0.0.0.0:{PORT}", file=sys.stderr)
|
||||
try:
|
||||
server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user