feat: inspector page, link debug enhancements, security hardening
- Add /inspector page: visual model-accurate switch chassis diagrams (USF5P, USL8A, US24PRO, USPPDUP, USMINI), clickable port blocks with color coding (green=up, amber=PoE, cyan=uplink, grey=down), detail panel with stats/PoE/LLDP, LLDP-based path debug side-by-side - Link Debug: port number badges (#N), LLDP neighbor line, PoE class/max, collapsible host/switch panels with sessionStorage persistence - monitor.py: collect LLDP neighbor map + PoE class/max/mode per switch port; PulseClient uses requests.Session() for HTTP keep-alive; add shlex.quote() around interface names (defense-in-depth) - Security: suppress buttons use data-* attrs + delegated click handler instead of inline onclick with Jinja2 variable interpolation; remove | safe filter from user-controlled fields in suppressions.html; setDuration() takes explicit el param instead of implicit event global - db.py: thread-local connection reuse with ping(reconnect=True) to avoid a new TCP handshake per query - .gitignore: add config.json (contains credentials), __pycache__ - README: full rewrite covering architecture, all 4 pages, alert logic, config reference, deployment, troubleshooting, security notes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
35
db.py
35
db.py
@@ -1,6 +1,7 @@
|
||||
"""Database operations for Gandalf network monitor."""
|
||||
import json
|
||||
import logging
|
||||
import threading
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional
|
||||
@@ -11,6 +12,7 @@ import pymysql.cursors
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_config_cache = None
|
||||
_local = threading.local()
|
||||
|
||||
|
||||
def _config() -> dict:
|
||||
@@ -23,22 +25,25 @@ def _config() -> dict:
|
||||
|
||||
@contextmanager
|
||||
def get_conn():
|
||||
"""Yield a per-thread cached database connection, reconnecting as needed."""
|
||||
cfg = _config()
|
||||
conn = pymysql.connect(
|
||||
host=cfg['host'],
|
||||
port=cfg.get('port', 3306),
|
||||
user=cfg['user'],
|
||||
password=cfg['password'],
|
||||
database=cfg['name'],
|
||||
autocommit=True,
|
||||
cursorclass=pymysql.cursors.DictCursor,
|
||||
connect_timeout=10,
|
||||
charset='utf8mb4',
|
||||
)
|
||||
try:
|
||||
yield conn
|
||||
finally:
|
||||
conn.close()
|
||||
conn = getattr(_local, 'conn', None)
|
||||
if conn is None:
|
||||
conn = pymysql.connect(
|
||||
host=cfg['host'],
|
||||
port=cfg.get('port', 3306),
|
||||
user=cfg['user'],
|
||||
password=cfg['password'],
|
||||
database=cfg['name'],
|
||||
autocommit=True,
|
||||
cursorclass=pymysql.cursors.DictCursor,
|
||||
connect_timeout=10,
|
||||
charset='utf8mb4',
|
||||
)
|
||||
_local.conn = conn
|
||||
else:
|
||||
conn.ping(reconnect=True)
|
||||
yield conn
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user