- Überblick
- Anwendungsfälle
- Was migriert wird
- Voraussetzungen
- Zugriff & Navigation
- Ablauf einer Migration
- Schnellstart für den Import
- Kommandos und Optionen
- Konfiguration
- Beispiele
- Artefakte des Snapshots
- Prüfungen und Schutzmechanismen
- Verifikation und Rückabwicklung
- Berechtigungen
- Fehlermeldungen & Troubleshooting
- Leistung, Limits & Betrieb
- Verwandte Seiten
Ü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:
exportverbindet 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.importverbindet 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.
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.manageauf 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:
- Die API-Schlüssel der betroffenen Konten sperren — mit Ausnahme des für die Migration verwendeten Schlüssels.
- 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.
- Zeitgesteuerte Aufgaben, Hintergrundverarbeitung und die Alarmauswertung deaktivieren.
- 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:tenantbzw. direkt überbin/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
- Start und Hinweise — die beiden ausgenommenen Historientabellen werden ausdrücklich als nicht exportiert gemeldet.
- Prüfung des API-Schlüssels — Existenz, Typ, Aktivzustand und Gültigkeitsdatum.
- Auflösung der Auswahl — Kontenmenge, zugehörige Zugriffsbereiche einschließlich der Zwillings-Unterbereiche, Benutzer- und Zwillings-IDs.
- Rechteprüfung je Konto — für jedes ausgewählte Konto wird
all.manageverlangt. - 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.
- Vorbereitung des Snapshot-Verzeichnisses — Prüfung auf Fortsetzung oder Bereinigung, Schreiben der Metadaten
_meta.jsoninklusive Migrationsstand und Spaltenschema der Quelle. - Export der Tabellen — Tabelle für Tabelle, gekennzeichnet als
[n/72]. Jede Tabelle wird zunächst als.jsonl.partialgeschrieben und erst nach vollständigem Durchlauf umbenannt. Nach jeder Tabelle wird_summary.jsonaktualisiert. - Abschlussprüfung — der fertige Snapshot wird von der Platte neu gelesen und geprüft; Ergebnis ist
_audit.json. - 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:
_meta.jsonmuss vorhanden und lesbar sein.- Prüfbericht
_audit.jsonmuss vorliegen, das Urteilpasstragen und zu Kontenmenge und API-Schlüssel des Snapshots passen. - Werkzeugversion des Snapshots muss der Version des ausführenden Werkzeugs entsprechen.
- Migrationsstand von Quelle und Ziel wird verglichen — Abweichungen werden als Warnung gemeldet.
- Schemavergleich Spalte für Spalte zwischen Snapshot und Zieldatenbank.
Anschließend beginnt eine einzige Transaktion:
- Zeitlimits werden gesetzt: unbegrenzte Laufzeit für die eigene Arbeit, begrenzte Wartezeit auf fremde Sperren.
- Wurzelkonto der Zielinstanz ermitteln und gegen das Ankerkonto prüfen.
- Kollisionsvorprüfung — in Blöcken von 5.000 IDs wird geprüft, ob bereits fremde Datensätze auf den zu vergebenden IDs liegen.
- Einspielen der Tabellen in festgelegter Reihenfolge; berücksichtigt werden nur Tabellen, für die eine Datei vorliegt.
- Vollständigkeitsprüfung — gelesene Zeilen gegen die im Export protokollierten Zeilenzahlen.
- Neuaufbau der Hierarchie-Hilfstabellen und Nachziehen der Sequenzen.
- 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:
-
Wartungsfenster vereinbaren und eine Sicherung der Zieldatenbank erstellen.
-
Snapshot-Archiv entschlüsseln, entpacken und die Prüfsummen gegen die übergebenen Werte vergleichen.
-
Image-Tag setzen, der zur Werkzeugversion des Snapshots passt, und die Verbindungsdaten der Zieldatenbank in der Umgebungsdatei hinterlegen.
-
Import ausführen und die Ausgabe mitschreiben:
docker compose run --rm tenant-migrate 2> import.log; echo "exit=$?" -
Rückgabewert prüfen:
0bedeutet, dass die Transaktion bestätigt wurde. Jeder andere Wert bedeutet, dass die Zielinstanz unverändert ist. -
Zielinstanz verifizieren (siehe Verifikation und Rückabwicklung).
-
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.managefü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.manageauf 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.jsonmit dem Urteilpasswird 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
- Zeilenzahlen auf der Zielinstanz gegen
_summary.jsonabgleichen. - Einordnung des Ankerkontos und die Hierarchieebenen der migrierten Konten kontrollieren.
- Stichproben auf erhaltene IDs bei Konten, Benutzern, Rollen, Digitalen Zwillingen und Virtuellen Geräten.
- Anmeldung eines realen Benutzers auf der Zielinstanz durchführen.
- Auflösung der Gerätetreiber prüfen — insbesondere bei geerbten Treibern, die an das Wurzelkonto gehängt wurden.
- Dashboards öffnen und auf vollständige Darstellung prüfen.
- Neuanlage testen — etwa ein neues Konto, einen Digitalen Zwilling oder eine Rolle —, um die nachgezogenen Sequenzen zu bestätigen.
- Verbindungsaufbau der Konnektoren auf der Zielinstanz kontrollieren.
- 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.manageauf 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 _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
„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
„
„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.