Kontomigration



Überblick

Die Kontomigration überträgt ausgewählte Konten — mit ihren Benutzern, Rollen, Digitalen Zwillingen, Virtuellen Geräten, Konnektoren, Integrationsflows, Dashboards und Protokollen — von einer niotix-Instanz auf eine andere. Die IDs bleiben dabei erhalten: Konten, Zugriffsbereiche, Benutzer und Rollen behalten auf dem Zielsystem dieselben Kennungen wie auf dem Quellsystem.

Ausgeführt wird die Migration mit dem Kommandozeilenwerkzeug tenant-migrate. Es arbeitet in zwei getrennten Hälften:

  • export verbindet sich ausschließlich mit der Quelldatenbank und liest ausschließlich lesend. Ergebnis ist ein Snapshot — ein Verzeichnis mit einer JSONL-Datei je Datenbanktabelle plus Metadaten.
  • import verbindet sich ausschließlich mit der Zieldatenbank und spielt einen solchen Snapshot ein.

Zwischen den beiden Hälften besteht keine Netzwerkverbindung. Die Übergabe erfolgt als Datei-Übergabe des Snapshot-Verzeichnisses. Damit lässt sich die Migration auch über Organisationsgrenzen hinweg durchführen: DIGIMONDO exportiert aus der Quellinstanz, der Betreiber der Zielinstanz importiert den übergebenen Snapshot.

%%{ init: { 'theme': 'base', 'themeVariables': { 'primaryColor': '#FFFFFF', 'primaryTextColor': '#031403', 'primaryBorderColor': '#606060', 'lineColor': '#606060', 'secondaryColor': '#2fcbff', 'tertiaryColor': '#E7E6E6', 'primary_font' : 'Poppins:wght@300;400;500;600;700;800', 'primary_font_type' : 'sans-serif' } } }%% flowchart TB A([ Quellinstanz ]) --> |export, nur lesend| B([ Snapshot als JSONL ]) B --> |Abschlussprüfung im Export| C([ Prüfbericht _audit.json ]) C --> |Verschlüsselte Übergabe| D([ import in einer Transaktion ]) D --> E([ Zielinstanz ])

Migriert werden ausschließlich die Daten der relationalen Datenbank (PostgreSQL). Zeitreihendaten — also die historischen Messwerte in der Zeitreihendatenbank — sind nicht Teil dieses Werkzeugs; für sie existiert ein eigenes Migrationswerkzeug. Die Übertragung der Zeitreihendaten ist daher mit dem DIGIMONDO-Ansprechpartner separat zu planen.

Anwendungsfälle

  • Wechsel des Betriebsmodells: Ein Konto samt Unterkonten wird von der von DIGIMONDO betriebenen Instanz auf eine eigenbetriebene oder anderweitig gehostete niotix-Instanz überführt.
  • Übergabe an einen anderen Betreiber: Ein Kundenkonto wechselt den Plattformbetreiber; Benutzer, Rollen und Objektstrukturen sollen unverändert weiterbestehen.
  • Zusammenführung von Instanzen: Konten mehrerer Instanzen werden auf einer Zielinstanz gebündelt — bei Bedarf in mehreren aufeinanderfolgenden Migrationsschritten.
  • Herauslösen eines Teilbaums: Aus einer Kontenhierarchie wird ein Teilbaum migriert, einzelne Unterkonten werden dabei ausgenommen.

Was migriert wird

Der Umfang ist über eine Tabellenliste im Werkzeug fest definiert. Sie umfasst 74 Tabellenspezifikationen, von denen 72 exportiert werden; zwei Historientabellen sind bewusst ausgenommen (siehe Nicht migrierte Daten).

Inhaltlich abgedeckt sind:

Bereich Inhalt
Kontenhierarchie Konten und Zugriffsbereiche einschließlich ihrer Ebenen
Identität und Rechte Benutzer, API-Schlüssel, Rollen, Berechtigungen, Kontozuordnungen
Geräte und Zwillinge Virtuelle Geräte, Gerätetreiber, Gerätetemplates, Digitale Zwillinge, Zwillingstemplates
Zustände und Historie Datenpunkte, Zwillingszustände und deren zugehörige Verknüpfungen
Integrationen Konnektoren, Integrationsflows, Filter, Transformationen, zugehörige Jobs
Oberfläche Dashboards mit allen 18 abhängigen Detailtabellen
Protokolle und Meldungen Systemprotokolle, Alarmprotokolle, Einstellungen, Meldungen der Objektverwaltung

Die Hierarchie-Hilfstabellen für Konten, Zugriffsbereiche und Digitale Zwillinge werden nicht übertragen, sondern beim Import aus den migrierten Datensätzen neu aufgebaut.

Bei Konnektoren wird der Laufzeitzustand beim Export bewusst zurückgesetzt: Die Zuordnung zu einem Ausführungsslot wird entfernt und der Zustand auf Warten gesetzt. Die Konnektoren verbinden sich auf der Zielinstanz also neu.

Nicht migrierte Daten

Bewusst nicht übertragen werden:

  • Laufzeitzustand der Zielinstanz: Ausführungsslots und Registrierung der Konnektoren, Hintergrundjobs und die Tabellen der Zeitplanung. Diese Daten entstehen auf dem Zielsystem neu.
  • Kurzlebige Anmeldedaten: OAuth2- und OIDC-Tokens, Autorisierungscodes sowie die Protokollierung fehlgeschlagener Anmeldeversuche.
  • Berechtigungs-Cache: Die aufgelösten Zugriffsbereiche der Benutzer werden bei der nächsten Anmeldung neu berechnet.
  • Instanzweite Grundausstattung: Regeldefinitionen des Systems, Übersetzungen, Schemaverwaltung und Migrationsstände — diese bringt die Zielinstanz selbst mit.
  • Zwei Historientabellen: die Ausführungshistorie der Geotrigger und die Historie der Regelausführungen. Sie erreichen das Zielsystem nicht; die zugehörigen Regeln und Geofences dagegen schon.
  • Der Systembenutzer der Superadministration sowie Kontozuordnungen migrierter Benutzer, die auf Konten außerhalb der Auswahl verweisen.

Ein Dashboard-Widget, das auf ein Dashboard außerhalb des migrierten Umfangs verweist, wird mitübertragen. Das Navigationsziel ist auf der Zielinstanz dann nicht vorhanden. Dieser Fall ist bekannt und wird bewusst nicht als Fehler gemeldet.

Voraussetzungen

Zielinstanz

  • Eine bereits vollständig eingerichtete niotix-Instanz mit eigenem Wurzelkonto, eingespieltem Datenbankschema, abgeschlossenen Migrationen und der instanzweiten Regel-Grundausstattung.
  • Genau ein Wurzelkonto. Findet der Import keines oder mehrere, bricht er ab.
  • Dieselbe niotix-Version wie die Quellinstanz. Weicht der Migrationsstand des Schemas ab, meldet der Import dies und bricht bei unverträglichen Unterschieden ab.

Werkzeug und Laufzeitumgebung

  • Node.js 22 für den direkten Aufruf aus dem Repository; die einzigen Abhängigkeiten sind die PostgreSQL-Treiber.
  • Für den Import beim Betreiber der Zielinstanz alternativ Docker Engine 20.10 oder neuer mit Compose-Plugin sowie Zugriff auf das Container-Image registry.gitlab.com/digimondo-code/niotix/tenant-migrate — entweder aus der Registry oder als übergebenes Image-Archiv.
  • Der Image-Tag muss zur Werkzeugversion des Snapshots passen (aktuell 1.1.0). Die Compose-Konfiguration hat bewusst keinen Standard-Tag: Ohne gesetzten Tag verweigert Compose den Start.

Zugänge

  • Für den Export ein API-Schlüssel der Quellinstanz mit der Berechtigung all.manage auf jedem ausgewählten Konto oder einem übergeordneten Zugriffsbereich — dieselbe Befugnis, die zum Löschen des Kontos nötig wäre. Details unter Berechtigungen.
  • Ein Datenbankbenutzer mit Leserechten auf der Quelldatenbank sowie ein Datenbankbenutzer mit Schreibrechten auf der Zieldatenbank.
  • Netzwerkzugang jeweils nur zur eigenen Datenbank. Eine Verbindung zwischen Quell- und Zielumgebung ist nicht erforderlich.

Organisatorisch

  • Abgestimmte Konten-IDs einschließlich des festgelegten Ankerkontos.
  • Ausreichend Plattenplatz für den Snapshot auf beiden Seiten und für das Wachstum der Zieldatenbank.
  • Ein Empfängerschlüssel zur Verschlüsselung des Snapshots und ein abgestimmter Übertragungsweg.
  • Ein benannter Ansprechpartner auf Seiten der Zielinstanz, der während des Wartungsfensters erreichbar ist. Vor dem Import ist eine Datenbanksicherung der Zielinstanz zu erstellen.

Ankerkonto

Das Ankerkonto ist das oberste der zu migrierenden Konten. Es ist das einzige Konto, das beim Import unter das Wurzelkonto der Zielinstanz gehängt wird; alle übrigen migrierten Konten behalten ihre Eltern-Kind-Beziehungen innerhalb der Auswahl.

Für den Anker gilt:

  • Er muss Teil der migrierten Konten dieses Schritts sein.
  • Er muss das oberste Konto der Auswahl sein — ist sein Elternkonto ebenfalls in der Auswahl, bricht der Export ab.
  • Er darf nicht mit dem Wurzelkonto der Zielinstanz identisch sein.

Ebenen und Elternbeziehungen werden beim Import anhand des Zielsystems neu berechnet, nicht aus dem Snapshot übernommen.

Einfrieren der Quellkonten

Änderungen während der Migration gehen verloren. Eine Migration ist eine Momentaufnahme: Alles, was ab dem Start des Exports in die Quellkonten geschrieben wird — neue Messwerte, angelegte oder bearbeitete Geräte, Alarme, Benutzeraktionen —, gelangt nicht in die Migration und fehlt anschließend auf der Zielinstanz. Deshalb sind laufende Datenflüsse vor dem Export zu stoppen und die Quellkonten für die Dauer der Migration einzufrieren.

Der Grund dafür liegt in der Arbeitsweise des Exports: Er liest die Tabellen nacheinander und ohne gemeinsamen Transaktions-Snapshot — bei einem fortgesetzten Export sogar über mehrere Prozesse hinweg. Schreibvorgänge, die zwischen dem Lesen zweier Tabellen stattfinden, landen also nur teilweise oder gar nicht im Snapshot.

Das Einfrieren der Quellkonten wird von der Software nicht erzwungen, und ein ausgelassenes Einfrieren fällt auch nicht auf: Es entsteht dennoch ein Snapshot, der die Prüfungen besteht und sich sauber importieren lässt — er ist dann aber in sich inkonsistent, etwa weil ein Gerät migriert wurde, die zugehörige Messreihe aber nicht. Das Einfrieren ist während einer mehrschrittigen Migration über alle Schritte hinweg aufrechtzuerhalten.

Zum Einfrieren gehören:

  1. Die API-Schlüssel der betroffenen Konten sperren — mit Ausnahme des für die Migration verwendeten Schlüssels.
  2. Datenaufnahme stoppen, also die Konnektoren der betroffenen Konten anhalten. Daten, die während der Migration ohnehin nicht übernommen würden, bleiben so beim Quellsystem stehen und lassen sich nach der Umschaltung gezielt nachziehen.
  3. Zeitgesteuerte Aufgaben, Hintergrundverarbeitung und die Alarmauswertung deaktivieren.
  4. Benutzer bis zur Umschaltung auf die Zielinstanz von der Quellinstanz fernhalten.

Lässt sich ein Datenfluss nicht anhalten, ist vor der Umschaltung zu klären, wie die in dieser Zeit angefallenen Daten nachgetragen werden — ein zweiter Export ersetzt den ersten nicht, sondern ist ein eigener Migrationsschritt.

Zugriff & Navigation

Die Kontomigration ist kein Bestandteil der niotix-Weboberfläche — es gibt keinen Menüpunkt und keine Ansicht dafür. Sie wird ausschließlich über die Kommandozeile ausgeführt:

  • Auf der Quellseite aus dem niotix-Repository heraus über das npm-Skript migrate:tenant bzw. direkt über bin/tenant-migrate.js.
  • Auf der Zielseite in der Regel über das bereitgestellte Container-Image, gesteuert per Docker Compose (siehe Beispiel: Import über Docker Compose).

Alle Protokollausgaben schreibt das Werkzeug auf stderr; stdout bleibt frei. Eine Protokolldatei legt das Werkzeug nicht selbst an — die Ausgabe ist bei Bedarf umzuleiten.

Ablauf einer Migration

Phasen des Exports

  1. Start und Hinweise — die beiden ausgenommenen Historientabellen werden ausdrücklich als nicht exportiert gemeldet.
  2. Prüfung des API-Schlüssels — Existenz, Typ, Aktivzustand und Gültigkeitsdatum.
  3. Auflösung der Auswahl — Kontenmenge, zugehörige Zugriffsbereiche einschließlich der Zwillings-Unterbereiche, Benutzer- und Zwillings-IDs.
  4. Rechteprüfung je Konto — für jedes ausgewählte Konto wird all.manage verlangt.
  5. Vorabbericht zu den Gerätetreibern — noch bevor die erste Zeile geschrieben wird zeigt eine Übersicht, welche Gerätetreiber mitgehen, welche geerbt und welche nicht migrierbar sind.
  6. Vorbereitung des Snapshot-Verzeichnisses — Prüfung auf Fortsetzung oder Bereinigung, Schreiben der Metadaten _meta.json inklusive Migrationsstand und Spaltenschema der Quelle.
  7. Export der Tabellen — Tabelle für Tabelle, gekennzeichnet als [n/72]. Jede Tabelle wird zunächst als .jsonl.partial geschrieben und erst nach vollständigem Durchlauf umbenannt. Nach jeder Tabelle wird _summary.json aktualisiert.
  8. Abschlussprüfung — der fertige Snapshot wird von der Platte neu gelesen und geprüft; Ergebnis ist _audit.json.
  9. Abschlussmeldung mit den Zeilenzahlen je Tabelle.

Schlägt die Abschlussprüfung fehl, wird das Verzeichnis in <Verzeichnis>.REJECTED umbenannt und das Werkzeug beendet sich mit Code 3. Ein solcher Snapshot darf weder übergeben noch importiert werden.

Phasen des Imports

Alle Prüfungen, die ohne Schreibzugriff möglich sind, laufen vor dem Transaktionsbeginn:

  1. _meta.json muss vorhanden und lesbar sein.
  2. Prüfbericht _audit.json muss vorliegen, das Urteil pass tragen und zu Kontenmenge und API-Schlüssel des Snapshots passen.
  3. Werkzeugversion des Snapshots muss der Version des ausführenden Werkzeugs entsprechen.
  4. Migrationsstand von Quelle und Ziel wird verglichen — Abweichungen werden als Warnung gemeldet.
  5. Schemavergleich Spalte für Spalte zwischen Snapshot und Zieldatenbank.

Anschließend beginnt eine einzige Transaktion:

  1. Zeitlimits werden gesetzt: unbegrenzte Laufzeit für die eigene Arbeit, begrenzte Wartezeit auf fremde Sperren.
  2. Wurzelkonto der Zielinstanz ermitteln und gegen das Ankerkonto prüfen.
  3. Kollisionsvorprüfung — in Blöcken von 5.000 IDs wird geprüft, ob bereits fremde Datensätze auf den zu vergebenden IDs liegen.
  4. Einspielen der Tabellen in festgelegter Reihenfolge; berücksichtigt werden nur Tabellen, für die eine Datei vorliegt.
  5. Vollständigkeitsprüfung — gelesene Zeilen gegen die im Export protokollierten Zeilenzahlen.
  6. Neuaufbau der Hierarchie-Hilfstabellen und Nachziehen der Sequenzen.
  7. Bestätigung der Transaktion mit einer Übersicht gelesener und eingefügter Zeilen.

Der Import ist nicht fortsetzbar und kennt keine Zwischenstände: Bricht er an irgendeiner Stelle ab, wird die gesamte Transaktion zurückgerollt und die Zielinstanz bleibt unverändert. Die Meldung lautet dann „import rolled back; the target is unchanged. Fix the cause and re-run the same import." Ein erneuter Aufruf desselben Imports ist gefahrlos möglich — bereits vorhandene Zeilen werden übersprungen.

Einen Probelauf-Modus gibt es nicht. Ein „Testexport" bedeutet, den Export gegen eine Kopie der Quelldatenbank laufen zu lassen — es existiert kein entsprechender Schalter am Werkzeug.

Schnellstart für den Import

Für den Betreiber der Zielinstanz, der einen übergebenen Snapshot einspielt:

  1. Wartungsfenster vereinbaren und eine Sicherung der Zieldatenbank erstellen.

  2. Snapshot-Archiv entschlüsseln, entpacken und die Prüfsummen gegen die übergebenen Werte vergleichen.

  3. Image-Tag setzen, der zur Werkzeugversion des Snapshots passt, und die Verbindungsdaten der Zieldatenbank in der Umgebungsdatei hinterlegen.

  4. Import ausführen und die Ausgabe mitschreiben:

    docker compose run --rm tenant-migrate 2> import.log; echo "exit=$?"
    
  5. Rückgabewert prüfen: 0 bedeutet, dass die Transaktion bestätigt wurde. Jeder andere Wert bedeutet, dass die Zielinstanz unverändert ist.

  6. Zielinstanz verifizieren (siehe Verifikation und Rückabwicklung).

  7. Snapshot und Übertragungskopien sicher vernichten.

Kommandos und Optionen

Das Werkzeug kennt genau zwei Kommandos: export und import. Positionelle Argumente sind nicht zulässig, unbekannte Optionen führen zum Abbruch. Ein Aufruf ohne Argumente gibt die Kurzhilfe aus und endet mit Rückgabewert 1; --help bzw. -h gibt die Hilfe aus und endet mit 0.

Kommando export

Option Wert Pflicht Bedeutung
--src-url=<url> postgres://benutzer:passwort@host:port/datenbank ja Quelldatenbank; wird ausschließlich gelesen. Alternativ über MIGRATE_SRC_URL.
--api-key=<uuid> UUID ja Autorisierender API-Schlüssel der Quellinstanz. Alternativ über MIGRATE_API_KEY.
--out=<verzeichnis> Pfad ja Zielverzeichnis des Snapshots.
--anchor=<id> positive Ganzzahl eines von beiden Ankerkonto dieses Schritts.
--accounts=<id,id> Liste positiver Ganzzahlen eines von beiden Konten dieses Schritts. Ohne Angabe gilt das Ankerkonto.
--mode=single|recursive Zeichenkette nein, Standard single recursive nimmt die angegebenen Konten samt allen Unterkonten auf.
--exclude=<id,id> Liste nein Nimmt die genannten Konten samt ihren Teilbäumen aus.
--resume Schalter nein Setzt einen abgebrochenen Export fort.

--exclude ist ausschließlich mit --mode=recursive zulässig; in Verbindung mit --mode=single bricht der Export mit der Meldung „–exclude is only valid with –mode=recursive" ab. Werden --anchor und --accounts gemeinsam angegeben, bestimmt --accounts die Kontenmenge, und --anchor wird lediglich dagegen geprüft.

Die Fortsetzung mit --resume arbeitet auf Tabellenebene: Bereits vollständig geschriebene Tabellen werden nicht erneut abgefragt. Weichen die Rahmenbedingungen der Fortsetzung von denen des ursprünglichen Laufs ab — andere Konten, anderer API-Schlüssel, andere Quelldatenbank, veränderte Tabellenauswahl —, verweigert das Werkzeug die Fortsetzung und benennt das abweichende Merkmal.

Kommando import

Option Wert Pflicht Bedeutung
--dst-url=<url> postgres://benutzer:passwort@host:port/datenbank ja Zieldatenbank; die einzige Datenbank, in die geschrieben wird. Alternativ über MIGRATE_DST_URL.
--in=<verzeichnis> Pfad ja Einzuspielendes Snapshot-Verzeichnis.

Das Ankerkonto und die Kontenauswahl werden dem Snapshot entnommen — beim Import sind sie nicht erneut anzugeben.

Da beide Kommandos dieselbe Optionsliste teilen, akzeptiert import auch reine Export-Optionen wie --resume oder --anchor, ohne sie auszuwerten und ohne Warnung. Für den Import sind ausschließlich --dst-url und --in wirksam.

Konfiguration

Eine Konfigurationsdatei besitzt das Werkzeug nicht. Gesteuert wird es über Kommandozeilenoptionen und Umgebungsvariablen; alle übrigen Werte sind fest hinterlegt.

Umgebungsvariablen

Variable Standard Bedeutung
MIGRATE_SRC_URL Ersetzt --src-url.
MIGRATE_DST_URL Ersetzt --dst-url.
MIGRATE_API_KEY Ersetzt --api-key.
MIGRATE_LOCK_TIMEOUT 30s Wartezeit des Imports auf konkurrierende Datenbanksperren, als PostgreSQL-Intervallangabe.
MIGRATE_DEBUG nicht gesetzt Mit 1 werden zusätzliche Diagnosemeldungen ausgegeben.
MIGRATE_ALLOW_VERSION_SKEW nicht gesetzt Mit 1 wird die Versionsprüfung zur Warnung herabgesetzt. Nur nach Abstimmung mit DIGIMONDO verwenden.
MIGRATE_COLOR automatisch 1 erzwingt farbige Ausgabe, 0 schaltet sie ab.
NO_COLOR nicht gesetzt Schaltet farbige Ausgabe ab.
TENANT_MIGRATE_IMAGE registry.gitlab.com/digimondo-code/niotix/tenant-migrate Container-Image für den Import über Compose.
TENANT_MIGRATE_TAG kein Standard Image-Tag, z. B. 1.1.0. Ohne Angabe startet Compose nicht.

Der Wert von MIGRATE_LOCK_TIMEOUT wird unverändert an PostgreSQL übergeben und nicht vorab geprüft. Eine ungültige Angabe fällt erst innerhalb der Import-Transaktion auf — der Import bricht dann ab, ohne etwas zu schreiben.

Feste Werte im Werkzeug

Wert Größe Bedeutung
Werkzeugversion 1.1.0 Muss zwischen Snapshot und ausführendem Werkzeug übereinstimmen.
Leseblock beim Export 1.000 Zeilen Blockgröße des serverseitigen Cursors.
Schreibblock beim Import 1.000 Zeilen Zeilen je Sammel-INSERT.
Block der Kollisionsvorprüfung 5.000 IDs IDs je Prüfabfrage.
Fortschrittsmeldung alle 5 Sekunden Lebenszeichen je laufender Tabelle.
Verbindungen im Pool maximal 5 Tatsächlich genutzt wird eine Verbindung je Lauf.
Verbindungsaufbau 10 Sekunden Zeitlimit für den Aufbau der Datenbankverbindung.
Leerlauf einer Verbindung 30 Sekunden Zeitlimit für ungenutzte Verbindungen.
Zeitlimit im Import unbegrenzt Für Anweisungen und Leerlauf innerhalb der Transaktion.
Sperrwartezeit im Import 30 Sekunden Über MIGRATE_LOCK_TIMEOUT anpassbar.
Nachgezogene Sequenzen 40 Werden nach dem Import auf den höchsten migrierten Wert gesetzt.
Gemeldete Verstöße im Prüfbericht bis zu 50 gespeichert, 10 protokolliert Umfang der Fehlerausgabe der Abschlussprüfung.

Eine Parallelisierung ist nicht vorgesehen: Export und Import arbeiten Tabelle für Tabelle über eine einzige Datenbankverbindung. Blockgrößen und Nebenläufigkeit sind nicht konfigurierbar. Wiederholversuche kennt das Werkzeug nicht — die Wiederherstellung erfolgt über --resume beim Export bzw. über einen erneuten Aufruf desselben Imports.

Beispiele

Die folgenden Aufrufe verwenden die Umgebungsvariablen $SRC, $DST und $KEY für Verbindungsdaten und API-Schlüssel.

Beispiel: Konto mit allen Unterkonten

export MIGRATE_SRC_URL='postgres://benutzer:passwort@host:5432/niotix'
export MIGRATE_API_KEY='<UUID des all.manage-Schlüssels>'

tenant-migrate export --anchor=23 --mode=recursive --out=/snapshot

Anschließend auf der Zielseite:

export MIGRATE_DST_URL='postgres://benutzer:passwort@host:5432/niotix'

tenant-migrate import --in=/snapshot

Beispiel: Teilbaum ohne einzelne Unterkonten

npm run migrate:tenant -- export --src-url=$SRC --api-key=$KEY \
  --anchor=23 --mode=recursive --exclude=99 --out=./snap/a

Konto 99 wird samt seinem Teilbaum ausgenommen.

Beispiel: Migration in mehreren Schritten

Große Kontenbäume lassen sich in mehreren Schritten migrieren. Der erste Schritt trägt das Ankerkonto, die folgenden hängen weitere Konten an die bereits migrierte Struktur:

npm run migrate:tenant -- export --src-url=$SRC --api-key=$KEY --anchor=23 --out=./snap/step1
npm run migrate:tenant -- import  --dst-url=$DST --in=./snap/step1

npm run migrate:tenant -- export --src-url=$SRC --api-key=$KEY --accounts=24 --out=./snap/step2
npm run migrate:tenant -- import  --dst-url=$DST --in=./snap/step2

Jeder Schritt setzt voraus, dass das Elternkonto bereits auf dem Zielsystem vorhanden ist — andernfalls bricht der Import mit dem Hinweis auf die Reihenfolge Eltern-vor-Kind ab. Das Einfrieren der Quellkonten gilt über alle Schritte hinweg.

Beispiel: Import über Docker Compose

Die mitgelieferte Compose-Konfiguration führt fest das Kommando import --in=/snapshot aus und bindet das lokale Verzeichnis ./snapshot schreibgeschützt ein. Zu setzen sind lediglich der Image-Tag und die Verbindungsdaten der Zieldatenbank in der Umgebungsdatei:

export TENANT_MIGRATE_TAG=1.1.0

docker compose run --rm tenant-migrate

Mit Protokollierung und Auswertung des Rückgabewerts:

docker compose run --rm tenant-migrate 2> import.log; echo "exit=$?"

Artefakte des Snapshots

Im Verzeichnis aus --out entstehen:

Datei Inhalt
_meta.json Zeitpunkt, Werkzeugversion, Kennung des Laufs, Auswahlmodus mit Anker-, Konten-, Zugriffsbereichs- und Ausschluss-IDs, Anzahl und Prüfsumme der Benutzer, Tabellenliste, gekürzte Quell-Verbindungsangabe, Angaben zur Autorisierung, Migrationsstand und Spaltenschema der Quelle
_summary.json Exportierte Zeilenzahl je Tabelle — Grundlage der Vollständigkeitsprüfung beim Import
_audit.json Urteil der Abschlussprüfung, Prüfzeitpunkt, Fingerabdruck des API-Schlüssels, geprüfte Konten, Gesamtzahlen zu Dateien, Zeilen und Verstößen sowie die Verstöße im Einzelnen
<tabelle>.jsonl Je Datenbanktabelle eine Datei mit einer Zeile je Datensatz — 72 Dateien bei vollständigem Export
<tabelle>.jsonl.partial Nur während des Laufs vorhanden; wird nach vollständigem Export der Tabelle umbenannt
<verzeichnis>.REJECTED Umbenanntes Verzeichnis nach fehlgeschlagener Abschlussprüfung. Eine frühere Zurückweisung wird nie überschrieben.

In _meta.json werden keine Benutzer-IDs hinterlegt, sondern nur deren Anzahl und eine Prüfsumme; die Verbindungsangabe zur Quelle wird gekürzt gespeichert.

Ein Archivierungs- oder Verschlüsselungsschritt ist nicht Teil des Werkzeugs. Packen, Prüfsummenbildung, Verschlüsselung und Vernichtung des Snapshots sind organisatorische Schritte des Migrationsablaufs.

Prüfungen und Schutzmechanismen

Im Export

  • Rechteprüfung je Konto vor dem ersten Schreibvorgang: Fehlt all.manage für ein ausgewähltes Konto, bricht der Export ab und nennt die Konten, für die der Schlüssel zulässig wäre.
  • Warnung bei Wurzelbereich: Trägt der API-Schlüssel all.manage auf dem Wurzelbereich der Instanz, kann er jedes Konto exportieren — das Werkzeug weist ausdrücklich darauf hin.
  • Abschlussprüfung des geschriebenen Snapshots mit vier Verstoßarten: Datensätze außerhalb der Berechtigung, Datensätze außerhalb der Auswahl, Verweise ins Leere sowie Dateien und Datensätze, die keiner Regel der Tabellenliste zugeordnet werden können.
  • Vorabbericht zu Gerätetreibern: gemeldet werden fehlende Treiber, Treiber fremder Konten, die nicht mitgehen können, sowie geerbte, aber nicht öffentlich sichtbare Treiber, die auf dem Zielsystem an das Wurzelkonto gehängt werden und dort nur mit entsprechender Berechtigung auflösbar sind.

Im Import

  • Prüfberichtssperre: Ohne _audit.json mit dem Urteil pass wird nicht importiert. Der Bericht muss zur Kontenmenge und zum API-Schlüssel des Snapshots passen — ein von anderswo hineinkopierter Prüfbericht wird erkannt.
  • Versionssperre zwischen Snapshot und Werkzeug.
  • Schemavergleich: Fehlt eine Spalte des Snapshots auf dem Ziel, fehlt eine ganze Tabelle oder besitzt das Ziel eine neue Pflichtspalte ohne Standardwert, bricht der Import ab. Zusätzliche Zielspalten mit Standardwert sowie abweichende Spaltentypen führen nur zu einer Warnung.
  • Kollisionsvorprüfung: Liegt auf einer zu vergebenden ID bereits ein anderer Datensatz, bricht der Import unter Angabe von Tabelle, ID und abweichendem Feld ab.
  • Vollständigkeitsprüfung gegen _summary.json. Verglichen werden gelesene, nicht eingefügte Zeilen — damit ein zweiter Aufruf desselben Imports nicht als unvollständig gilt.
  • Genau eine Hauptkontozuordnung je migriertem Benutzer wird erzwungen.

Verifikation und Rückabwicklung

Nach dem Import zu prüfen

  1. Zeilenzahlen auf der Zielinstanz gegen _summary.json abgleichen.
  2. Einordnung des Ankerkontos und die Hierarchieebenen der migrierten Konten kontrollieren.
  3. Stichproben auf erhaltene IDs bei Konten, Benutzern, Rollen, Digitalen Zwillingen und Virtuellen Geräten.
  4. Anmeldung eines realen Benutzers auf der Zielinstanz durchführen.
  5. Auflösung der Gerätetreiber prüfen — insbesondere bei geerbten Treibern, die an das Wurzelkonto gehängt wurden.
  6. Dashboards öffnen und auf vollständige Darstellung prüfen.
  7. Neuanlage testen — etwa ein neues Konto, einen Digitalen Zwilling oder eine Rolle —, um die nachgezogenen Sequenzen zu bestätigen.
  8. Verbindungsaufbau der Konnektoren auf der Zielinstanz kontrollieren.
  9. Die Verknüpfungen der Zwillingszustands-Aggregate gegenprüfen: Ein Teil dieser Datensätze entsteht auf dem Zielsystem über einen Datenbank-Trigger neu und wird in der Import-Übersicht ausdrücklich zur manuellen Prüfung ausgewiesen.

Rückabwicklung

Ein Kommando zum Zurückrollen existiert nicht — der Schutz liegt in der Atomarität des Imports: Jeder Rückgabewert ungleich 0 bedeutet, dass die Zielinstanz vollständig unverändert ist.

Zeitpunkt des Abbruchs Vorgehen
Während des Exports Snapshot-Verzeichnis löschen und den Export erneut ausführen, oder mit --resume fortsetzen.
Vor dem Transaktionsbeginn des Imports, Rückgabewert 3 oder 4 Ursache beheben und denselben Import erneut ausführen.
Innerhalb der Import-Transaktion Der Rollback ist bereits erfolgt; die Zielinstanz ist unverändert. Ursache beheben und erneut importieren.
Nach bestätigter Transaktion, Verifikation schlägt fehl Die Quellkonten nicht löschen. Die eingefrorene Quellinstanz ist die Rückfallebene; der Fall ist zu eskalieren.
Nach bestätigter Transaktion und bereits gelöschten Quellkonten Eine Rückabwicklung ist nicht möglich.

Der Punkt ohne Wiederkehr ist die Bestätigung der Import-Transaktion. Die Quellkonten sind erst zu löschen, nachdem die Verifikation auf der Zielinstanz vollständig abgeschlossen ist.

Berechtigungen

Auf der Quellinstanz autorisiert ein API-Schlüssel den Export. Er muss:

  • als API-Schlüssel-Benutzer angelegt und aktiv sein,
  • innerhalb seines Gültigkeitsdatums liegen und
  • die Berechtigung all.manage auf dem Wurzelbereich jedes ausgewählten Kontos oder einem übergeordneten Zugriffsbereich tragen.

Damit entspricht die verlangte Befugnis genau der, die zum Löschen des Kontos über die API nötig wäre. Ein persönlicher Anmeldezugang kann einen Export nicht autorisieren. Ein etwaiges Abfragekontingent des Schlüssels wird bewusst nicht ausgewertet. Grundlagen zum Rechtemodell: Berechtigungen und Berechtigungskonzept.

Datenbankrechte

Seite Benötigte Rechte
Quelldatenbank Leserechte auf den Tabellen der Tabellenliste, auf information_schema sowie auf die Tabelle mit dem Migrationsstand
Zieldatenbank INSERT und DELETE auf den Tabellen der Tabellenliste und den Hierarchie-Hilfstabellen, Setzen von Sequenzwerten sowie Lesezugriff auf information_schema

Fehlermeldungen & Troubleshooting

Die Meldungen des Werkzeugs sind englischsprachig. Der Rückgabewert ordnet die Fehlerklasse zu:

Rückgabewert Bedeutung
0 Erfolgreich abgeschlossen
1 Aufruf- oder Laufzeitfehler, einschließlich verweigerter Fortsetzung
2 Problem mit dem API-Schlüssel
3 Problem mit dem Snapshot — fehlender, fehlgeschlagener oder unvollständiger Prüfbericht bzw. abgeschnittener Snapshot
4 Unverträgliches Schema oder abweichende Werkzeugversion

„Refusing to export: the supplied x-api-key does not hold all.manage on account(s) …" Ursache: Der API-Schlüssel besitzt nicht auf allen ausgewählten Konten die Berechtigung all.manage. Die Meldung nennt die Konten, für die der Schlüssel zulässig wäre. Lösung: Auswahl auf diese Konten einschränken oder einen Schlüssel mit ausreichender Berechtigung auf einem übergeordneten Zugriffsbereich verwenden.

„The –api-key value is not a UUID" / „No user exists on the source for the supplied –api-key" / „…belongs to a regular user, not an api-key user" Ursache: Es wurde keine gültige Schlüssel-Kennung übergeben oder es handelt sich um einen persönlichen Zugang. Lösung: Die Kennung des API-Schlüssel-Benutzers der Quellinstanz verwenden.

„Anchor tenant N is not among the migrated accounts" / „Anchor tenant N has parent M, which is also in this selection" Ursache: Das Ankerkonto gehört nicht zur Auswahl oder ist nicht deren oberstes Konto. Lösung: Anker gemäß Ankerkonto korrigieren.

„–exclude is only valid with –mode=recursive" Ursache: --exclude wurde ohne rekursiven Modus verwendet. Lösung: --mode=recursive ergänzen oder den Ausschluss entfernen.

„Refusing to –resume: this export does not match the snapshot in –out" Ursache: Die Rahmenbedingungen weichen vom ursprünglichen Lauf ab; die Meldung nennt das abweichende Merkmal. Lösung: Ursprüngliche Parameter verwenden, oder --resume weglassen und in ein frisches Verzeichnis exportieren.

„Snapshot audit FAILED — … quarantined to .REJECTED" Ursache: Die Abschlussprüfung hat Datensätze gefunden, zu deren Export der Schlüssel nicht befugt war, Datensätze außerhalb der Auswahl, Verweise ins Leere oder nicht zuordenbare Dateien. Lösung: _audit.json im zurückgewiesenen Verzeichnis auswerten und den Auslöser klären. Ein solcher Snapshot darf nicht übergeben oder importiert werden.

„No _audit.json in " / „…records verdict … with N violation(s)" / „…the audit does not belong to this snapshot" Ursache: Der Snapshot wurde nie geprüft, hat die Prüfung nicht bestanden, oder Prüfbericht und Metadaten passen nicht zusammen. Lösung: Export erneut ausführen; einen nicht bestandenen Snapshot nicht importieren.

„Refusing to commit: the snapshot does not hold every row the export wrote" Ursache: Beim Übertragen wurde der Snapshot abgeschnitten. Lösung: Snapshot erneut übertragen, Prüfsummen abgleichen und den Import wiederholen.

„Refusing to import: snapshot was written by tenant-migrate X, this is 1.1.0" Ursache: Snapshot und Werkzeug stammen aus unterschiedlichen Versionen und können unterschiedliche Spalten erwarten. Lösung: Das Image mit dem passenden Tag verwenden. Die Umgehung über MIGRATE_ALLOW_VERSION_SKEW=1 ist nur nach Abstimmung mit DIGIMONDO vorgesehen.

„Refusing to import: the target schema cannot accept this snapshot" Ursache: Zielschema und Snapshot passen nicht zusammen — fehlende Spalte, fehlende Tabelle oder neue Pflichtspalte ohne Standardwert. Es wurde nichts geschrieben. Lösung: Die Zielinstanz auf denselben Migrationsstand wie die Quelle bringen und denselben Import erneut ausführen.

„Could not find a target root tenant" / „Found N candidate root tenants on target" Ursache: Auf der Zielinstanz existiert kein oder mehr als ein Wurzelkonto. Lösung: Zielinstanz korrekt bereitstellen; der Import benötigt genau ein Wurzelkonto.

„ID collision on .<Schlüssel>: target … but snapshot …" Ursache: Auf einer zu vergebenden ID liegt bereits ein anderer Datensatz. Lösung: Ursache mit DIGIMONDO klären; die Zielinstanz ist unverändert.

id=N: parent M is not present on the target … Migrate the parent first" Ursache: Bei einer mehrschrittigen Migration fehlt das Elternkonto auf dem Zielsystem. Lösung: Zuerst den Schritt mit dem Elternkonto importieren.

„permission denied" beim Lesen von /snapshot Ursache: Der Container läuft unprivilegiert und darf das eingebundene Verzeichnis nicht lesen. Lösung: Leserechte für das Snapshot-Verzeichnis setzen, etwa mit chmod -R a+rX snapshot.

Compose startet nicht und verlangt einen Tag Ursache: TENANT_MIGRATE_TAG ist nicht gesetzt; einen Standardwert gibt es bewusst nicht. Lösung: Den zur Werkzeugversion des Snapshots passenden Tag setzen.

Der Import läuft länger als das Wartungsfenster Ursache: Ein Teilimport existiert nicht — die Transaktion läuft bis zum Ende oder wird zurückgerollt. Lösung: Fall eskalieren und mit DIGIMONDO ein Vorgehen abstimmen; die Zielinstanz bleibt bei einem Abbruch unverändert.

Leistung, Limits & Betrieb

Aspekt Wert
Tabellenspezifikationen insgesamt 74
Exportierte Tabellen 72
Leseweise beim Export Serverseitiger Cursor, 1.000 Zeilen je Block; keine Tabelle wird vollständig im Speicher gehalten
Schreibweise beim Import Sammel-INSERT mit 1.000 Zeilen je Anweisung
Zeilenweise Verarbeitung Konten, Zugriffsbereiche und Kontozuordnungen — hierarchie- bzw. regelbedingt
Nebenläufigkeit keine; eine Datenbankverbindung je Lauf
Wiederholversuche keine; Wiederherstellung über --resume oder erneuten Import
Zeitlimit im Import unbegrenzt für eigene Anweisungen, 30 Sekunden Wartezeit auf fremde Sperren
Fortsetzbarkeit Export auf Tabellenebene; Import nicht fortsetzbar
Plattenplatz je Zeile Richtwert etwa 200 Byte JSONL
Fortschrittsmeldung alle 5 Sekunden je laufender Tabelle

Betriebshinweise:

  • Sperrverhalten: Der Import wartet begrenzt auf konkurrierende Sperren. Der Neuaufbau der Hierarchie-Hilfstabellen ist auf die migrierten Datensätze beschränkt und sperrt gleichzeitige Lesezugriffe nicht aus.
  • Kein Probelauf: Zum Erproben ist der Export gegen eine Kopie der Quelldatenbank auszuführen.
  • Kein Teilimport: Ein Import ist entweder vollständig bestätigt oder vollständig zurückgerollt. Das Wartungsfenster ist entsprechend zu bemessen.
  • Keine Vorabprüfung des Plattenplatzes: Ein volles Dateisystem während des Exports äußert sich lediglich als allgemeiner Abbruch beim Schreiben.

Zur Abschätzung der Laufzeit liegen ausschließlich Messwerte aus einem lokalen Testdatensatz vor — bei rund 415.000 Zeilen und 81 MB etwa 6 Sekunden für Export samt Prüfung und etwa 15 Sekunden für den Import. Diese Werte sind nicht auf Produktionsdatenbanken übertragbar und nicht zur Planung eines Wartungsfensters geeignet. Die Laufzeit ist stattdessen an einer Kopie der Quelldatenbank zu messen.

Verwandte Seiten