-- Migration 0012: RDP-Zugangsdaten als eigenstaendige, wiederverwendbare -- Objekte -- analog zu ssh_keys/host_ssh_key_map, und aus demselben Grund: -- bisher gab es GENAU einen RDP-Zugangsdatensatz pro Host -- (rdp_credentials.host_id war PRIMARY KEY), angelegt direkt im -- Serverformular ("Server" -> Host-Detail -> "RDP-Zugangsdaten"). Auf -- ausdruecklichen Wunsch des Users: "RDP-Zugangsdaten auch unter -- Zugangsdaten UND dem Server zuweisbar, nicht im Serverobjekt zu -- erstellen" -- ein Zugangsdatensatz (Label/Benutzer/Domaene/Passwort) -- laesst sich jetzt EINMAL im Reiter "Zugangsdaten" anlegen und danach -- MEHREREN Hosts zuweisen, genau wie ein SSH-Key. -- Alte 1:1-Tabelle bleibt als Datenquelle fuer die Uebernahme unten -- erhalten, wird aber umbenannt, damit der Name "rdp_credentials" frei wird -- fuer das neue, eigenstaendige Objekt (Konvention dieses Projekts: Altes -- bleibt lesbar erhalten statt geloescht zu werden, siehe z.B. -- hosts.ssh_username/rdp_username in Migration 0010). ALTER TABLE rdp_credentials RENAME TO rdp_credentials_legacy; CREATE TABLE IF NOT EXISTS rdp_credentials ( id INTEGER PRIMARY KEY, label TEXT NOT NULL, username TEXT NOT NULL, domain TEXT, password_enc BLOB NOT NULL, tenant_id INTEGER NOT NULL REFERENCES tenants(id), created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), rotated_at TEXT ); CREATE INDEX IF NOT EXISTS idx_rdp_credentials_tenant ON rdp_credentials(tenant_id); -- Genau EIN zugewiesener Zugangsdatensatz je Host (PRIMARY KEY = host_id) -- -- aber derselbe Zugangsdatensatz darf in mehreren Zeilen (= mehreren Hosts) -- auftauchen. Das ist die eigentliche Wiederverwendbarkeit, die diese -- Migration einfuehrt. CREATE TABLE IF NOT EXISTS host_rdp_credential_map ( host_id INTEGER PRIMARY KEY REFERENCES hosts(id) ON DELETE CASCADE, rdp_credential_id INTEGER NOT NULL REFERENCES rdp_credentials(id) ); -- Datenuebernahme: jeder bisherige 1:1-Datensatz wird zu einem eigenen -- Zugangsdaten-Objekt (Label aus dem Hostnamen abgeleitet, da die alte -- Tabelle keinen eigenen Namen kennt) und dem jeweiligen Host zugeordnet. -- Die Korrelation zwischen den beiden folgenden INSERTs laeuft bewusst ueber -- password_enc statt ueber eine temporaere ID-Spalte: jede Verschluesselung -- verwendet einen frischen Zufalls-Nonce (siehe app/security/crypto.py), -- zwei Zeilen der Alttabelle koennen also nie denselben password_enc-Wert -- haben -- der Ruecksprung von rdp_credentials auf rdp_credentials_legacy -- ist damit eindeutig. INSERT INTO rdp_credentials (label, username, domain, password_enc, tenant_id, created_at) SELECT 'Migriert: ' || h.hostname, COALESCE(NULLIF(TRIM(rcl.username), ''), '(kein Benutzername)'), rcl.domain, rcl.password_enc, COALESCE(hg.tenant_id, 1), rcl.updated_at FROM rdp_credentials_legacy rcl JOIN hosts h ON h.id = rcl.host_id LEFT JOIN host_groups hg ON hg.id = h.host_group_id; INSERT INTO host_rdp_credential_map (host_id, rdp_credential_id) SELECT rcl.host_id, rc.id FROM rdp_credentials_legacy rcl JOIN rdp_credentials rc ON rc.password_enc = rcl.password_enc;