Switche: optionaler SSH-Port statt fest 22

- Neue Spalte switches.ssh_port (nullable INTEGER), Migration für
  bestehende DBs in _ensure_schema(), Feld in create_db.py ergänzt.
- Formular (Anlegen/Bearbeiten): optionales SSH-Port-Feld, Validierung
  1-65535, leer -> NULL (= Standard 22 überall, SWITCH_DEFAULT_SSH_PORT).
  Switch-Liste zeigt den effektiven Port inkl. "(Standard)"-Hinweis.
- generate_ips.py liefert den effektiven Port (Fallback 22) als eigenes
  Pipe-Feld an poe.sh; poe.sh übernimmt es in disable_poe/enable_poe und
  reicht es als "ssh -p <port>" an die expect-Skripte durch (Default
  weiterhin 22 falls Parameter fehlt).
- Web-Terminal (Verbindungstest) sendet den im Formular eingetragenen
  Port statt hartkodiert 22.
- Live getestet: gültiger/leerer/ungültiger Port beim Anlegen, korrekte
  Weitergabe durch generate_ips.py inkl. Feldreihenfolge, die poe.sh
'read' erwartet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 19:56:23 +02:00
co-authored by Claude Sonnet 5
parent 813b17d002
commit 06db4c1382
6 changed files with 75 additions and 20 deletions
+33 -7
View File
@@ -77,6 +77,10 @@ FERNET_KEY_PATH = os.environ.get("POE_FERNET_KEY", os.path.join(BASE_DIR, "ferne
SSH_KNOWN_HOSTS_PATH = os.environ.get("POE_KNOWN_HOSTS", os.path.join(BASE_DIR, "known_hosts"))
SECRET_KEY_PATH = os.environ.get("POE_SECRET_KEY_FILE", os.path.join(BASE_DIR, "secret.key"))
AVATAR_DIR = os.path.join(BASE_DIR, "static", "uploads", "avatars")
# Wird verwendet, wenn ein Switch keinen eigenen ssh_port hinterlegt hat
# (Feld leer gelassen) — deckt den Standardfall ab, ohne dass er überall
# explizit eingetragen werden muss.
SWITCH_DEFAULT_SSH_PORT = 22
ALLOWED_AVATAR_EXT = {"png", "jpg", "jpeg", "gif", "webp"}
os.makedirs(AVATAR_DIR, exist_ok=True)
@@ -519,6 +523,10 @@ def _ensure_schema():
conn.execute("ALTER TABLE switches ADD COLUMN last_modified_by TEXT")
if "last_modified_at" not in switch_cols:
conn.execute("ALTER TABLE switches ADD COLUMN last_modified_at TEXT")
# SSH-Port je Switch (falls nicht Standard 22) — NULL/leer bedeutet
# überall "22 verwenden" (siehe SWITCH_DEFAULT_SSH_PORT-Fallback).
if "ssh_port" not in switch_cols:
conn.execute("ALTER TABLE switches ADD COLUMN ssh_port INTEGER")
# Migration: bestehende, direkt am Switch hinterlegte Zugangsdaten
# (ältere DB-Version) in eigene Credentials-Datensätze überführen.
@@ -1509,6 +1517,18 @@ def _resolve_credential_choice(conn):
return None, "Bitte Zugangsdaten auswählen oder neue anlegen."
def _parse_ssh_port(form):
"""Liest das optionale SSH-Port-Feld aus dem Formular. Leer -> None (=
Fallback auf SWITCH_DEFAULT_SSH_PORT überall, wo der Port gebraucht
wird). Gibt (port_or_none, error_message) zurück."""
raw = (form.get("ssh_port") or "").strip()
if not raw:
return None, None
if not raw.isdigit() or not (1 <= int(raw) <= 65535):
return None, "SSH-Port muss eine Zahl zwischen 1 und 65535 sein (oder leer für Standard 22)!"
return int(raw), None
@app.route("/switches", methods=["GET", "POST"])
@login_required
def switches():
@@ -1524,14 +1544,17 @@ def switches():
return redirect(url_for("switches"))
hostname = request.form["hostname"]
ip = request.form["ip"]
ssh_port, port_error = _parse_ssh_port(request.form)
credential_id, cred_error = _resolve_credential_choice(conn)
if cred_error:
if port_error:
flash(port_error, "danger")
elif cred_error:
flash(cred_error, "danger")
else:
try:
conn.execute(
"INSERT INTO switches (hostname, ip, credential_id) VALUES (?, ?, ?)",
(hostname, ip, credential_id),
"INSERT INTO switches (hostname, ip, ssh_port, credential_id) VALUES (?, ?, ?, ?)",
(hostname, ip, ssh_port, credential_id),
)
touch_record(conn, "switches", "hostname", hostname)
conn.commit()
@@ -1547,14 +1570,17 @@ def switches():
old_hostname = request.form["old_hostname"]
hostname = request.form["hostname"]
ip = request.form["ip"]
ssh_port, port_error = _parse_ssh_port(request.form)
credential_id, cred_error = _resolve_credential_choice(conn)
if cred_error:
if port_error:
flash(port_error, "danger")
elif cred_error:
flash(cred_error, "danger")
else:
try:
conn.execute(
"UPDATE switches SET hostname=?, ip=?, credential_id=? WHERE hostname=?",
(hostname, ip, credential_id, old_hostname),
"UPDATE switches SET hostname=?, ip=?, ssh_port=?, credential_id=? WHERE hostname=?",
(hostname, ip, ssh_port, credential_id, old_hostname),
)
if hostname != old_hostname:
conn.execute(
@@ -1569,7 +1595,7 @@ def switches():
flash("Hostname existiert bereits oder Eingabefehler!", "danger")
switch_rows = conn.execute("""
SELECT switches.hostname, switches.ip, switches.credential_id,
SELECT switches.hostname, switches.ip, switches.ssh_port, switches.credential_id,
credentials.name AS credential_name, credentials.username AS credential_username
FROM switches
LEFT JOIN credentials ON credentials.id = switches.credential_id