Migration von Hasura v2 zu Provisa¶
Voraussetzungen¶
- Eine laufende Hasura-v2-Instanz (v2.x) mit exportierten Metadaten.
- Exportieren Sie die Metadaten in einem der beiden Layouts:
Das Metadatenverzeichnis der CLI:
Dadurch wird ein Verzeichnis metadata/ erstellt. databases/databases.yaml listet jede Quelle
mit Art und Verbindung auf und verweist über !include-Indizes auf ihre Tabellen und Funktionen;
actions.yaml, cron_triggers.yaml, inherited_roles.yaml, remote_schemas.yaml und die
übrigen Dateien liegen daneben. Das ältere flache Layout (tables.yaml im Wurzelverzeichnis)
lässt sich ebenfalls konvertieren.
Das einzelne Dokument der Metadaten-API:
curl -X POST http://localhost:8080/v1/metadata \
-H "X-Hasura-Admin-Secret: <secret>" \
-d '{"type":"export_metadata","args":{}}' > metadata.json
Sowohl das reine Objekt als auch die Hülle {resource_version, metadata} funktionieren. Der
Admin-Import (Admin, Hasura-Konfiguration importieren) nimmt diese Form entgegen; der
nachfolgende Kommandozeilen-Konverter liest Verzeichnisse.
3. Python 3.11+ mit installiertem Paket provisa.
Verwendung der CLI¶
Argumente¶
| Argument | Erforderlich | Beschreibung |
|---|---|---|
metadata_dir |
Ja | Pfad zum exportierten Hasura-v2-Metadatenverzeichnis |
Optionen¶
| Option | Standard | Beschreibung |
|---|---|---|
-o, --output FILE |
stdout | Pfad der YAML-Ausgabedatei |
--source-overrides FILE |
Keine | YAML-Datei mit Verbindungsüberschreibungen pro Quelle |
--domain-map KEY=VAL ... |
Keine | Schema-zu-Domäne-Zuordnungen (z. B. public=core hr=people) |
--auth-env-file FILE |
Keine | Pfad zur .env-Datei mit der JWT/Admin-Secret-Authentifizierungskonfiguration |
--dry-run |
aus | Analysiert und validiert, ohne die Ausgabe zu schreiben |
Datei mit Quellenüberschreibungen¶
Eine YAML-Datei, die nach Quellenname indiziert ist und Verbindungseigenschaften enthält, die überschrieben werden sollen:
default:
host: prod-db.example.com
port: 5432
database: myapp
username: provisa_user
password: "${env:PROD_DB_PASSWORD}"
Datei für die Authentifizierungsumgebung¶
Eine Datei im .env-Stil mit der zu konvertierenden Hasura-Authentifizierungskonfiguration. Der Konverter
ordnet Folgendes zu:
- JWT mit
jwk_url-> Provisaprovider: oauth. - JWT
claims_map-> Provisarole_mapping[]. - Admin Secret -> Provisa
superuser. - Webhook-Authentifizierung -> es wird eine Warnung ausgegeben (kein Provisa-Äquivalent).
Der Bericht¶
Die Konvertierung endet mit einem Bericht in drei Teilen:
- Unverändert übernommen. Das Objekt hat eine Provisa-Entsprechung und wird ohne Bedeutungsänderung konvertiert.
- Auf ein besseres Provisa-Feature abgebildet. Jeder Eintrag nennt, warum das Provisa-Feature die Aufgabe besser erledigt.
- Von Hand nacharbeiten. Jeder Eintrag nennt, was zu tun ist. Das sind die Warnungen.
Der Kommandozeilen-Konverter gibt den Bericht auf stderr als Carried as, Mapped to und Redo by hand mit jeweils einer Anzahl aus, wenn etwas nachzuarbeiten bleibt. Der Admin-Import liefert die drei Listen mit der Vorschau.
Feature-Paritätsmatrix¶
| Hasura-v2-Feature | Teil | Provisa-Entsprechung | Hinweise |
|---|---|---|---|
| Quellen (postgres, mysql, mssql, bigquery, citus) | übernommen | sources[] |
Art abgebildet: pg/postgres -> postgresql, mssql -> sqlserver. Eine ausgeschriebene Verbindungs-URL wird in Host/Port/Datenbank/Benutzername/Passwort zerlegt. Pool-Größe bleibt erhalten. Eine aus einer Umgebungsvariable gelesene URL wird nicht erraten (siehe unten). |
| Tabellen (getrackte Tabellen) | übernommen | tables[] |
Schema und Tabellenname bleiben erhalten. source_id verknüpft mit der Quelle. |
Benutzerdefinierte Tabellennamen (custom_name, custom_root_fields.select) |
übernommen | tables[].alias |
Der erste Nicht-Null-Wert aus select, select_by_pk, custom_name. |
Benutzerdefinierte Spaltennamen (column_config, älteres custom_column_names) |
übernommen | columns[].alias |
Der benutzerdefinierte Name jeder Spalte wird zu ihrem Alias. |
Weitere Wurzelfeldnamen (select_by_pk, select_aggregate, insert, ...) |
abgebildet | Das eine Feld der Tabelle | Namentlich gemeldet. Ein Lesezugriff über den Schlüssel ist ein Filter auf der Tabelle, ein Aggregat ihr Feld _aggregate, ein Schreibvorgang ihre Mutation. |
| Select-Berechtigungen (Spalten, Filter) | übernommen | columns[].visible_to[], rls_rules[] |
Spaltenlisten werden zu visible_to; * wird unterstützt. Filter werden zu SQL; Sitzungsvariablen werden zu current_setting('provisa.<name>'). |
| Filter über Relationships | übernommen | EXISTS-Unterabfragen in rls_rules[] |
Die Regel folgt der Relationship bis zu ihrer Tabelle. |
| Insert-, Update- und Delete-Berechtigungen | übernommen | tables[].write_grants[] |
Eine Berechtigung je Rolle und Operation: Spalten aus columns, rows aus filter, check aus check, Presets aus set. Rollen erhalten das Recht write. |
| Admin-Rolle | übernommen | org_admin |
Hält jede Berechtigung über jede Spalte und Zeile und wird in jeder importierten Spalte genannt. |
| Object-Relationships | übernommen | relationships[] mit cardinality: many-to-one |
Genehmigt. Das GraphQL-Feld ist der Name der Hasura-Relationship. |
| Array-Relationships | übernommen | relationships[] mit cardinality: one-to-many |
Genehmigt. Das GraphQL-Feld ist der Name der Hasura-Relationship. |
| Geerbte Rollen (eine Rolle) | übernommen | roles[].parent_role_id |
Die Rolle wird zum Elternteil. |
| Geerbte Rollen (mehrere Rollen) | abgebildet | Eine Rolle, die die Vereinigung ihrer Berechtigungen hält | Provisa-Rollen haben einen Elternteil, daher wird die Vereinigung auf der Rolle ausgeschrieben. |
| Computed Fields | nacharbeiten | Eine Sichtspalte | Der Export nennt die Funktion, nicht ihren Rumpf. Der Bericht nennt das hinzuzufügende SELECT. |
| Getrackte Funktionen | übernommen, sonst nacharbeiten | functions[]-Befehle |
Die Vorschau liest die Signatur aus der Datenbank. Ohne sie fügen Sie die Funktion auf der Seite Commands hinzu. |
| Actions | abgebildet | Befehle, die den Handler aufrufen | {{VAR}} in der Handler-URL wird als ${env:VAR} geschrieben und beim Aufruf des Befehls aufgelöst. |
| Cron Triggers | übernommen | scheduled_triggers[] |
Cron-Ausdruck, URL, Payload und Enabled-Flag. Wiederholungen werden nicht übernommen (gewarnt). |
| Event Triggers | abgebildet | scheduled_triggers[] auf die Änderung der Tabelle |
Feuert je Änderungsstapel bei jeder Änderung. Wiederholungen werden nicht übernommen (gewarnt). |
| Remote Schemas | abgebildet | sources[] (graphql_remote), als Tabellen gelandet |
Name, URL, Header und Authentifizierung bleiben erhalten; Wurzelfelder werden zu governten Tabellen. |
| Enum-Tabellen | übernommen | Tabelle angelegt | Das Flag is_enum wird nicht übernommen (keine Provisa-Entsprechung). |
| Allow Lists, Query Collections, REST-Endpunkte | nacharbeiten | Keine | Werden gemeldet, wenn sie in einem konsolidierten Export vorkommen; nicht konvertiert. |
Relationships¶
- Das GraphQL-Feld jeder Relationship ist der Hasura-Name. Hat die Tabelle bereits ein Feld mit diesem Namen, erhält die Relationship den Namen, den Provisa vergibt, und der Bericht warnt.
- Zwei Relationships, die denselben Join deklarieren, werden zu einer zusammengeführt. Der Bericht nennt, welche in welche eingegangen ist.
- Eine Relationship über mehrere Spaltenpaare wird gewarnt und nicht angelegt, da eine Provisa-Beziehung über ein Paar verbindet. Zeilenregeln über sie werden dennoch konvertiert.
- Eine allein über eine Fremdschlüsselspalte deklarierte Object-Relationship wird über die inverse Array-Relationship aufgelöst; ohne eine solche wird gewarnt.
Schreibberechtigungen¶
Eine Berechtigung legt fest, was eine Rolle mit einer Operation in eine Tabelle schreiben darf. Ein leeres filter oder check steht für jede Zeile (TRUE). Ein set-Wert X-Hasura-User-Id wird zu einem session-Preset von hasura_user_id; jeder andere Wert wird zu einem literal-Preset. Eine Preset-Spalte steht nicht zusätzlich in den Spalten der Berechtigung.
Actions, getrackte Funktionen und Trigger¶
- Eine Action wird zu einem Befehl, der ihren Handler aufruft, sichtbar für die Rollen, die ihre Berechtigungen nennen (nur für
org_admin, wenn sie keine nennen). Eine asynchrone Action wird gewarnt: Der Befehl wartet auf die Antwort des Handlers. - Eine getrackte Funktion wird zu einem Befehl, wenn die Vorschau ihre Argumente und ihre Rückgabetabelle aus einer PostgreSQL-Quelle lesen kann. Offline, und für jede Funktion, die fehlt, überladen ist oder eine Tabelle zurückgibt, die der Import nicht registriert, geht sie in die Nacharbeit.
- Ein Event Trigger feuert bei jeder Änderung seiner Tabelle, einmal je Stapel, und sendet die Tabelle und die geänderten Zeilen statt eines Ereignisses je Zeile mit alten und neuen Werten. Ein Trigger, der auf weniger als alle drei Operationen hörte, wird gewarnt.
Schritte nach der Konvertierung¶
- Prüfen Sie den Bericht. Beginnen Sie mit
Redo by hand. - Quellverbindungen konfigurieren. Eine Verbindung, die der Export ausschreibt, wird wie geschrieben konvertiert. Eine aus einer Umgebungsvariable gelesene kommt leer an. Verwenden Sie
--source-overridesoder bearbeiten Sie die Ausgabe direkt. - Domänenzuordnungen prüfen. Ohne
--domain-maplanden alle Tabellen indefault. Ordnen Sie Schemas mit--domain-map public=core analytics=reportingDomänen zu. - Zeilenregeln prüfen. Filter werden zu SQL konvertiert. Prüfen Sie komplexe boolesche
Ausdrücke (verschachtelte
_and/_or/_exists) und Filter über Relationships. - Aufgelistetes nacharbeiten. Computed Fields, getrackte Funktionen, die die Vorschau nicht lesen konnte, Wiederholungen bei Triggern und Webhook-Authentifizierung werden nicht automatisch konvertiert.
- Authentifizierung einrichten. Wenn Ihre Hasura-Instanz JWT-/Webhook-Authentifizierung verwendet, erstellen Sie eine
Auth-Env-Datei und führen Sie den Lauf mit
--auth-env-fileerneut aus. - Sitzungsvariablen senden. Konfigurieren Sie den Identitätsanbieter so, dass das Token jede Sitzungsvariable trägt, die der Bericht unter „zugeordnet zu“ aufführt (zum Beispiel
x-hasura-user-id, auf oberster Ebene oder im Hasura-Claims-Objekt), oder erfassen Sie sie je Mitglied als Attribut. - Testen. Starten Sie den Provisa-Server und prüfen Sie Abfragen gegen Ihre Datenquellen.
Häufige Probleme und Fehlerbehebung¶
Die Verbindung kommt aus einer Umgebungsvariable¶
Ist die database_url der Quelle eine Referenz auf eine Umgebungsvariable ({"from_env": "PG_URL"}),
steht ihr Wert nicht im Export. Der Konverter errät keinen: Die Quelle hat leere Werte für
Host, Datenbank, Benutzername und Passwort, und der Bericht führt sie unter Redo by hand auf.
Tragen Sie die Verbindung in den Quelleinstellungen des Imports (oder mit --source-overrides) ein und konvertieren Sie
erneut.
Platzhalterspalten¶
Wenn eine Berechtigung columns: "*" gewährt, erstellt der Konverter einen einzelnen
Platzhalter-Spalteneintrag. Nach der Konvertierung möchten Sie diesen möglicherweise durch explizite
Spaltenlisten ersetzen, indem Sie das tatsächliche Datenbankschema prüfen.
Genauigkeit von Event-Triggern¶
Ein Event Trigger wird zu einem Trigger auf Änderungen seiner Tabelle, der denselben Webhook aufruft. Er feuert je Änderungsstapel bei jeder Änderung, ob die Änderung über Provisa oder direkt in die Datenbank kam, und sendet die Tabelle und die geänderten Zeilen. Die alten und neuen Werte je Zeile, die Filterung je Operation und Wiederholungen von Hasura werden nicht übernommen; der Bericht warnt bei jedem, der zutrifft. Lassen Sie den Handler auf die Zeilen reagieren, für die er gedacht ist, und wiederholen Sie in ihm, wenn ein verpasster Aufruf zählt.
Fehlende Rollen¶
Rollen werden aus Tabellenberechtigungen, Action-Berechtigungen und geerbten Rollen gesammelt. Existiert eine Rolle in Hasura, kommt aber in keiner davon vor, erscheint sie nicht in der Ausgabe.
Benutzerdefinierte Root-Felder¶
Die Wurzelfeldnamen select und select_by_pk ergeben den Tabellen-Alias. Die übrigen benutzerdefinierten Wurzelfelder
(select_aggregate, insert, update, delete) werden namentlich gemeldet: Provisa stellt
eine Tabelle als ein Feld bereit, mit Aggregaten und Schreibvorgängen als ihrem Feld _aggregate und ihren Mutationen.
Beispiel¶
Konvertierung eines typischen Hasura-v2-Projekts mit zwei Schemas, die Domänen zugeordnet sind:
# Export metadata from Hasura
hasura metadata export --endpoint http://localhost:8080
# Convert with domain mapping and source overrides
python -m provisa.hasura_v2 metadata/ \
-o provisa.yaml \
--domain-map public=core hr=people \
--source-overrides overrides.yaml \
--auth-env-file auth.env
# Dry run first to check for warnings
python -m provisa.hasura_v2 metadata/ --dry-run
Struktur der Ausgabe (gekürzt):
sources:
- id: default
type: postgresql
host: prod-db.example.com
port: 5432
database: myapp
domains:
- id: core
- id: people
tables:
- source_id: default
domain_id: core
schema_name: public
table_name: users
columns:
- name: id
visible_to: [org_admin, user]
- name: email
visible_to: [org_admin, user]
write_grants:
- role: user
operation: update
columns: [email]
rows: "id = current_setting('provisa.hasura_user_id')"
check: "TRUE"
- role: org_admin
operation: insert
columns: [id, email]
check: "TRUE"
- role: org_admin
operation: update
columns: [id, email]
rows: "TRUE"
check: "TRUE"
- role: org_admin
operation: delete
rows: "TRUE"
roles:
- id: user
capabilities: [query_development, write]
domain_access: ["*"]
rls_rules:
- table_id: users
role_id: user
filter: "id = current_setting('provisa.hasura_user_id')"
relationships:
- id: orders.user
source_table_id: orders
target_table_id: users
source_column: user_id
target_column: id
cardinality: many-to-one
graphql_alias: user