Compare commits

..
1 Commits
Author SHA1 Message Date
alientim 292ea622a7 Version 2.8.1: das Upgrade von 1.2.8 nimmt die Freigaben mit 2026-09-12 19:06:52 +02:00
3 changed files with 106 additions and 15 deletions

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "tesm"
version = "2.8.0"
version = "2.8.1"
description = "TESM -- Verwaltung und Ueberwachung von PoE-Endgeraeten und Aruba-Switchen"
requires-python = ">=3.11"
dependencies = [
+88 -11
View File
@@ -16,10 +16,18 @@ eingelesen. Ein eigener Schreibpfad fuer Altdaten waere eine zweite Stelle, an
der Fremdeingaben in die Datenbank gelangen -- und die zweite Stelle ist die,
die niemand pflegt.
Uebersetzt werden Clients, Switche, Zugangsdaten und die DHCP-Konfiguration.
Was in der Datei sonst noch steht, wird nicht stillschweigend verworfen,
sondern im Bericht benannt -- damit sichtbar bleibt, was von Hand nachzuziehen
ist.
Uebersetzt werden Clients, Switche, Zugangsdaten, die DHCP-Konfiguration und
die Freigabe-Zuordnungen. Was in der Datei sonst noch steht, wird nicht
stillschweigend verworfen, sondern im Bericht benannt -- damit sichtbar bleibt,
was von Hand nachzuziehen ist.
Die Freigaben standen bis 2.8.0 auf der Liste "von Hand nachtragen", obwohl es
dafuer keinen Grund gab: der Vorgaenger fuehrt sie in
``ldap_fileshare_mappings`` mit denselben vier Angaben, die diese Anwendung in
``fileshare_mappings`` braucht (Verzeichnisgruppe, deren Name, Beschriftung,
UNC-Pfad), und einen Import dafuer gibt es hier ohnehin. Was sich uebernehmen
laesst, soll man nicht abtippen muessen -- ein UNC-Pfad von Hand ist ein
Tippfehler, der erst auffaellt, wenn jemand die Freigabe braucht.
"""
from __future__ import annotations
@@ -35,8 +43,10 @@ from typing import Any
LEGACY_KDF_ITERATIONS = 390000
LEGACY_APP_TAG = "tesm"
#: Diese Abschnitte werden uebersetzt.
SUPPORTED = ("credentials", "switches", "devices", "dhcp")
#: Diese Abschnitte werden uebersetzt. "ldap" nur zum Teil -- daraus kommen die
#: Freigabe-Zuordnungen, waehrend Servereinstellungen und Gruppen-Zuordnungen
#: dort bleiben (siehe KNOWN_UNSUPPORTED).
SUPPORTED = ("credentials", "switches", "devices", "dhcp", "ldap")
#: Was der alte Export sonst enthaelt. Wird gemeldet, nicht uebersetzt.
KNOWN_UNSUPPORTED: dict[str, str] = {
@@ -46,9 +56,12 @@ KNOWN_UNSUPPORTED: dict[str, str] = {
"Zweck. Konten neu anlegen."
),
"groups": "Gruppen und Rechte: die Rechteschlüssel wurden neu geschnitten.",
# Nur noch der Teil, der wirklich nicht uebertragbar ist: Server, Bind-Konto
# und die Gruppen-Zuordnung (dort zeigen die Namen auf Gruppen, deren
# Rechteschluessel neu geschnitten wurden). Die Freigaben kommen mit.
"ldap": (
"Verzeichnisdienst: Einstellungen, Gruppen- und Freigabe-Zuordnungen von "
"Hand übertragen."
"Verzeichnisdienst: Server, Bind-Konto und die Gruppen-Zuordnung von Hand "
"übertragen. Die Freigabe-Zuordnungen wurden übernommen."
),
"nginx": "Webserver: Domain, Ports und Zertifikat von Hand übertragen.",
"logs": "Auditlog: bleibt bewusst beim alten System.",
@@ -272,6 +285,48 @@ def _devices(items: Any, credentials: list[dict[str, Any]], report: Report) -> l
return ergebnis
def _freigaben(data: Any, report: Report) -> list[dict[str, Any]]:
"""Freigabe-Zuordnungen aus dem Abschnitt "ldap" des alten Exports.
Der Vorgaenger legt sie unter ``ldap.fileshare_mappings`` ab; beim Lesen
einer Installation stehen sie unmittelbar in der Tabelle. Beides landet
hier, damit es nur eine Stelle gibt, die die Felder umbenennt.
"""
if isinstance(data, dict):
eintraege = _liste(data.get("fileshare_mappings"))
else:
eintraege = _liste(data)
ergebnis: list[dict[str, Any]] = []
ohne_pfad = 0
for eintrag in eintraege:
# "share_label"/"share_unc" heissen hier "label"/"unc" -- dieselbe
# Angabe, kuerzerer Name, weil die Tabelle schon "fileshare" heisst.
unc = str(eintrag.get("share_unc") or eintrag.get("unc") or "").strip()
gruppe = str(eintrag.get("ad_group_dn") or "").strip()
if not unc or not gruppe:
ohne_pfad += 1
continue
beschriftung = str(eintrag.get("share_label") or eintrag.get("label") or "").strip()
ergebnis.append(
{
"ad_group_dn": gruppe,
"ad_group_name": str(eintrag.get("ad_group_name") or "").strip() or gruppe,
# Ohne Beschriftung der letzte Teil des Pfades -- besser als
# eine Freigabe ohne Namen. Beide Trenner: der Vorgaenger
# speichert "//server/share", getippt wird "\server\share".
"label": beschriftung
or unc.replace(chr(92), "/").rstrip("/").rsplit("/", 1)[-1],
"unc": unc,
}
)
if ohne_pfad:
report.note(
f"{ohne_pfad} Freigabe-Zuordnung(en) ohne Verzeichnisgruppe oder UNC-Pfad "
"übersprungen."
)
return ergebnis
def _dhcp(data: Any, report: Report) -> tuple[dict[str, Any], dict[str, str]]:
"""DHCP-Teil uebersetzen. Rueckgabe: ``(dhcp, settings)``."""
if not isinstance(data, dict):
@@ -382,6 +437,10 @@ def convert(legacy: dict[str, Any]) -> tuple[dict[str, Any], Report]:
if devices:
payload["devices"] = devices
freigaben = _freigaben(legacy.get("ldap") or legacy.get("fileshare"), report)
if freigaben:
payload["fileshare"] = freigaben
dhcp, settings = _dhcp(legacy.get("dhcp"), report)
if dhcp:
payload["dhcp"] = dhcp
@@ -417,8 +476,8 @@ def convert(legacy: dict[str, Any]) -> tuple[dict[str, Any], Report]:
if not payload:
raise LegacyTransferError(
"Die Datei enthält keine Clients, Switche, Zugangsdaten oder DHCP-Daten. "
"Beim Export im alten TESM diese Kategorien mitwählen."
"Die Datei enthält keine Clients, Switche, Zugangsdaten, DHCP-Daten oder "
"Freigaben. Beim Export im alten TESM diese Kategorien mitwählen."
)
return payload, report
@@ -634,6 +693,21 @@ def read_installation(root: Path) -> tuple[dict[str, Any], Report]:
else:
report.note("Tabelle 'credentials' fehlt in der alten Datenbank.")
# Die Freigaben reisen im Abschnitt "ldap" -- genau dort, wo der alte
# Export sie auch hat. So liest die Uebersetzung beide Wege gleich.
if "ldap_fileshare_mappings" in vorhanden:
freigaben = [
dict(row)
for row in conn.execute(
"SELECT ad_group_dn, ad_group_name, share_label, share_unc "
"FROM ldap_fileshare_mappings"
).fetchall()
]
if freigaben:
payload["ldap"] = {"fileshare_mappings": freigaben}
else:
report.note("Tabelle 'ldap_fileshare_mappings' fehlt in der alten Datenbank.")
dhcp = _alt_dhcp(conn, vorhanden)
if dhcp:
payload["dhcp"] = dhcp
@@ -644,9 +718,12 @@ def read_installation(root: Path) -> tuple[dict[str, Any], Report]:
if not payload:
raise LegacyTransferError(
f"In {root} stehen keine übernehmbaren Daten (Clients, Switche, "
"Zugangsdaten, DHCP)."
"Zugangsdaten, DHCP, Freigaben)."
)
for abschnitt, inhalt in payload.items():
if abschnitt == "ldap" and isinstance(inhalt, dict):
report.took("Freigaben", len(_liste(inhalt.get("fileshare_mappings"))))
continue
report.took(abschnitt, len(inhalt) if isinstance(inhalt, list) else 1)
return payload, report
+17 -3
View File
@@ -534,19 +534,33 @@ def apply_import(
if "fileshare" in wanted:
for entry in payload.get("fileshare", []):
gruppe = str(entry.get("ad_group_dn") or "")
pfad = str(entry.get("unc") or "")
if not gruppe or not pfad:
bump("fileshare", "skipped")
continue
# Vorher nachsehen, damit der Bericht die Wahrheit sagt: bisher
# stand dort auch bei einer frischen Installation "2 aktualisiert",
# obwohl zwei Zuordnungen **angelegt** wurden. Wer einen Import
# prueft, liest genau diese Zahlen.
vorhanden = Database.value(
conn,
"SELECT 1 FROM fileshare_mappings WHERE ad_group_dn=? AND unc=? LIMIT 1",
(gruppe, pfad),
)
conn.execute(
"INSERT INTO fileshare_mappings (ad_group_dn, ad_group_name, label, unc, created_at) "
"VALUES (?,?,?,?,?) ON CONFLICT(ad_group_dn, unc) DO UPDATE SET "
"label=excluded.label, ad_group_name=excluded.ad_group_name",
(
str(entry.get("ad_group_dn") or ""),
gruppe,
str(entry.get("ad_group_name") or ""),
str(entry.get("label") or ""),
str(entry.get("unc") or ""),
pfad,
stamp,
),
)
bump("fileshare", "updated")
bump("fileshare", "updated" if vorhanden else "created")
if "groups" in wanted:
for entry in payload.get("groups", []):