Импорт из Hasura¶
Provisa может преобразовать существующие метаданные Hasura в Provisa config.yaml, сохраняя отслеживаемые таблицы, связи, разрешения и удалённые схемы.
Интерактивный импорт (Admin → Import Hasura Config)¶
Административная поверхность запускает те же конвертеры, поэтому импорт не требует доступа к
оболочке и не требует прохождения через файл конфигурации туда-обратно. Требуется возможность (capability)
org_settings; импорт попадает в организацию, от имени которой действует сессия.
- Загрузка. Выберите заархивированный каталог метаданных Hasura v2, заархивированный проект
DDN, консолидированный экспорт метаданных (
.yaml/.json, включая конверт{resource_version, metadata}, который возвращает API метаданных), либо один файл.hml. Оставьте формат на Detect automatically, если только загружаемый файл не является неоднозначным. - Сопоставление доменов (необязательно). Каждая пара сопоставляет схему v2 или подграф DDN с доменом Provisa; всё, что не сопоставлено, сохраняет исходное имя.
- Преобразование и предпросмотр. Сервер преобразует и возвращает счётчики, отчёт о преобразовании (см. Отчёт) и сгенерированную конфигурацию. На этом шаге ничего не записывается. предупреждения конвертера и сгенерированную конфигурацию. На этом шаге ничего не записывается.
- Проверка и редактирование. Конфигурацию можно редактировать на месте — реквизиты подключения, имена доменов, имена ролей. Применяется именно то, что показано.
- Применение. Применить к этой организации загружает конфигурацию и перестраивает схемы организации. Импорт всегда объединяется с тем, что уже есть у организации.
Конечные точки: POST /admin/import/hasura/preview и POST /admin/import/hasura/apply.
Hasura v2¶
Экспорт метаданных¶
Преобразуются оба формата экспорта.
Каталог метаданных CLI. hasura metadata export записывает каталог. databases/databases.yaml перечисляет каждый источник с его видом и подключением и указывает на его таблицы и функции через индексы !include:
# metadata/databases/databases.yaml
- name: default
kind: postgres
configuration:
connection_info:
database_url:
from_env: HASURA_GRAPHQL_DATABASE_URL
tables: "!include default/tables/tables.yaml"
functions: "!include default/functions/functions.yaml"
Плоская раскладка (tables.yaml и actions.yaml в корне) тоже преобразуется.
Единый документ API метаданных. API метаданных возвращает весь экспорт одним объектом, с configuration каждого источника, для которой в раскладке каталога нет места:
curl -X POST http://localhost:8080/v1/metadata \
-H "X-Hasura-Admin-Secret: <secret>" \
-d '{"type":"export_metadata","args":{}}' \
> metadata.json
Принимаются и голый объект, и конверт {resource_version, metadata}. Административный импорт принимает эту форму (см. Интерактивный импорт); консольный конвертер читает только каталоги.
Преобразование¶
Консольный конвертер читает каталог метаданных Hasura (раскладку, которую создаёт hasura metadata export, или плоскую раскладку tables.yaml / actions.yaml) и записывает конфигурацию Provisa:
Опустите -o, чтобы вывести конфигурацию в stdout. Если что-то осталось переделать вручную, отчёт выводится в stderr.
Флаги:
| Флаг | Назначение |
|---|---|
-o, --output |
Путь к выходному YAML (по умолчанию: stdout) |
--source-overrides |
YAML-файл с переопределениями подключения по источникам (хост, порт, учётные данные), с ключами — именами источников |
--domain-map |
Сопоставления схема-домен в виде пар SCHEMA=DOMAIN |
--auth-env-file |
Файл .env с конфигурацией аутентификации; преобразует JWT/JWK, секрет администратора и карту claims |
--dry-run |
Разобрать и проверить без записи результата |
Отчёт¶
Каждое преобразование раскладывает найденное на три части. Читайте их в таком порядке.
- Перенесено как есть. У объекта есть прямой аналог в Provisa, и он преобразуется без изменения смысла: источники, таблицы, одобренные связи, разрешения select, cron-триггеры.
- Сопоставлено с лучшей функцией Provisa. В Provisa есть функция, которая решает задачу лучше, чем функция Hasura, поэтому объект становится ею. Каждая запись объясняет почему. Сюда попадают event-триггеры, actions, remote schemas, дополнительные имена корневых полей и роли, унаследованные от нескольких ролей.
- Переделать вручную. У объекта нет аналога в Provisa, или в экспорте не хватает того, что нужно преобразованию. Каждая запись говорит, что делать. Это предупреждения.
Предпросмотр возвращает три части списками. Консольный конвертер выводит их в stderr как Carried as, Mapped to и Redo by hand, каждую со счётчиком. Преобразование, в третьей части которого ничего нет, завершено.
Что преобразуется¶
| Понятие Hasura | Часть | Результат в Provisa |
|---|---|---|
Источник (kind, connection_info) |
перенесено | sources[]. Подключение, записанное в экспорте, преобразуется в хост, порт, базу данных и учётные данные. Подключение, читаемое из переменной окружения, не угадывается (см. Подключения и домены). |
| Отслеживаемая таблица | перенесено | Зарегистрированная таблица. Её пользовательское имя (или её корневое поле select) становится алиасом таблицы. |
Пользовательские имена колонок (column_config или прежний custom_column_names) |
перенесено | alias колонки. |
Имена корневых полей помимо select (select_by_pk, select_aggregate, insert, ...) |
сопоставлено | Сообщаются по имени. Provisa отдаёт таблицу одним полем: чтение по ключу — это фильтр по нему, агрегат — его поле _aggregate, запись — его мутация. Проверьте, что запросы приложения имеют такую форму. |
| Object- и array-relationship | перенесено | Одобренная связь (many-to-one для object, one-to-many для array), у которой поле GraphQL — имя relationship из Hasura. Отличающиеся случаи описаны ниже. (REQ-1680) |
| Разрешение select | перенесено | Разрешения на колонки (visible_to) и правило строк. Терм с переменной сеанса (X-Hasura-User-Id) становится current_setting('provisa.hasura_user_id'), которое запрос привязывает во время выполнения из claims идентичности или атрибутов участника. Переменная сеанса Hasura сохраняет собственное имя; provisa.user_id остаётся вошедшей идентичностью. (REQ-1682) |
| Правило строк через relationship | перенесено | Подзапрос EXISTS по связанной таблице. |
| Разрешение insert, update и delete | перенесено | Разрешения на запись в таблицу: по одному на роль и операцию. columns становятся колонками разрешения, filter — его rows, check — его check, set — его пресетами. |
| Роль, унаследованная от одной роли | перенесено | Эта роль как parent_role_id. |
| Роль, унаследованная от нескольких ролей | сопоставлено | Роль, держащая объединение их разрешений, выписанное явно: у роли Provisa один родитель. |
| Computed field | переделать | Колонка представления над таблицей. |
| Отслеживаемая функция | перенесено | Команда; см. ниже. Иначе — переделать. |
| Action | сопоставлено | Команда, вызывающая обработчик action. |
| Cron-триггер | перенесено | Запланированный триггер. |
| Event-триггер | сопоставлено | Триггер на изменения таблицы. |
| Remote schema | сопоставлено | Источник graphql_remote, чьи корневые поля попадают как управляемые таблицы. (REQ-1681) |
Случаи relationships:
- Коллизия. Если у таблицы уже есть поле с именем relationship, relationship получает имя, которое даёт Provisa, и отчёт предупреждает. Переименуйте её на странице Relationships, если приложению нужно другое имя.
- Один и тот же join дважды. Вторая relationship, объявляющая уже объявленный join, сливается с первой. Отчёт сообщает об этом среди перенесённого.
- Несколько пар колонок. Связь Provisa соединяет по одной паре колонок. Relationship, соединяющая по нескольким, получает предупреждение и не создаётся, но правила строк через неё переносятся.
- Только колонка внешнего ключа. Object-relationship, объявленная через
foreign_key_constraint_on: artist_id, не называет в экспорте цель. Конвертер разрешает её через обратную array-relationship и предупреждает, если такой нет.
Подробности разрешений на запись:
- Пустой
filterилиcheckозначает любую строку, записывается какTRUE. - Значение
set, являющееся переменной сеанса (X-Hasura-User-Id), становится пресетомsessionсоответствующей переменной сеанса (X-Hasura-User-Idстановитсяhasura_user_id). Любое другое значение становится пресетомliteral. Колонка с пресетом не входит также в колонки разрешения. - Неявный admin Hasura держит все разрешения. Он становится ролью
org_admin, которая держит разрешения insert, update и delete на все колонки и все строки и названа в каждой импортированной колонке. (REQ-1684) - Каждая роль с разрешением insert, update или delete получает также право
write.
Подробности команд:
- Отслеживаемая функция. Экспорт называет функцию и роли, которые её вызывают, но не её аргументы и не то, что она возвращает. Предпросмотр читает и то и другое из каталога базы данных и регистрирует команду с найденной сигнатурой. Если источник недостижим, это не PostgreSQL, либо функции нет, она перегружена или возвращает строки таблицы, которую импорт не регистрирует, функция переходит в «переделать». Консольный конвертер никогда не достигает базы данных, поэтому каждая найденная им отслеживаемая функция переходит в «переделать».
- Action. Команда вызывает обработчик action через
POST.{{VAR}}в URL обработчика записывается как${env:VAR}и разрешается при вызове команды. Команда видна ролям, которые называют разрешения action, или толькоorg_admin, если они не называют ни одной. Асинхронная action получает предупреждение: её команда ждёт ответа обработчика. Тип возврата, поля которого экспорт не содержит, получает предупреждение. - Event-триггер. Триггер срабатывает при каждом изменении таблицы, один раз на пакет изменений, и отправляет таблицу и изменённые строки. Он не срабатывает построчно со старыми и новыми значениями. Триггер Hasura, слушающий меньше трёх операций, получает предупреждение, так как триггер Provisa срабатывает на все. Повторные попытки не переносятся: триггер Hasura с
num_retriesполучает предупреждение, потому что триггер Provisa вызывает один раз. Повторяйте в обработчике, если важен пропущенный вызов. - Cron-триггер. Cron-выражение, URL, payload и флаг enabled переносятся. Повторные попытки не переносятся и сопровождаются таким же предупреждением.
Сводный документ содержит также разделы, для которых у конвертера нет цели: query_collections, allowlist, rest_endpoints, network и opentelemetry. Если один из них присутствует, отчёт перечисляет его среди того, что нужно переделать. Читатель каталога никогда не открывает их файлы.
Подключения и домены на вкладке импорта¶
Подключение, которое экспорт записывает явно, преобразуется как есть. Если экспорт читает URL базы данных из переменной окружения (database_url: {from_env: HASURA_GRAPHQL_DATABASE_URL}), значения переменной в экспорте нет, поэтому преобразование его не угадывает. Источник регистрируется с пустыми полями подключения, а отчёт требует переделать его: введите хост, порт, базу данных, пользователя и пароль источника в настройках источников импорта и преобразуйте снова. Передаются только изменённые вами поля — как переопределения источника. Строки доменов охватывают каждую схему, подграф и remote schema, которые несёт загрузка; каждая — это выбор среди существующих доменов организации, который принимает и введённое имя, помеченное как «новый домен», если оно не совпадает ни с одним. Применение сливается с тем, что у организации уже есть. (REQ-1687)
Типы берутся из источника при предпросмотре¶
Экспорт Hasura называет колонки без типов, а отслеживаемая таблица без разрешений не называет колонок. Предпросмотр выполняется с подключениями к источникам, которые вы указали, поэтому он читает information_schema.columns каждого доступного SQL-источника: каждая колонка без типа получает тип источника, отображённый на словарь IR, а таблица без колонок получает все колонки источника, видимые только org_admin, поскольку Hasura не открывала её ни одной другой роли. Источник, недоступный для предпросмотра, указывается в предупреждении [sources], и его колонки остаются без типов, чтобы вы дополнили их перед применением. (REQ-1691, REQ-1684)
Ограничения¶
- Computed fields переделываются вручную: экспорт называет функцию базы данных, но не определяет её. Добавьте её как колонку представления над таблицей или вычисляйте в приложении.
- Remote schemas попадают как таблицы из SDL разрешений ролей. Remote schema без разрешений ничего не приносит, так как экспорт не содержит другого описания её формы. (REQ-1681)
- Отслеживаемым функциям при предпросмотре нужна база данных, чтобы прочитать сигнатуру; без подключения их переделывают на странице Commands.
- Повторные попытки event- и cron-триггеров не переносятся.
Hasura DDN (v3)¶
Расположение проекта HML¶
Конвертер DDN читает каталог проекта DDN с файлами .hml напрямую — шаг сборки supergraph не
требуется. Первый компонент пути под корнем проекта берётся как имя подграфа; файлы под globals/
относятся к подграфу globals.
Преобразование¶
Опустите -o, чтобы вывести конфигурацию в stdout.
Флаги:
| Флаг | Назначение |
|---|---|
-o, --output |
Путь к выходному YAML-файлу (по умолчанию: stdout) |
--source-overrides |
YAML-файл с переопределениями подключения для отдельных источников |
--domain-map |
Сопоставления «подграф → домен» в виде пар SUBGRAPH=DOMAIN |
--aggregates-output |
Путь для вспомогательного файла агрегатных выражений (по умолчанию: <output>-aggregates.yaml) |
--dry-run |
Разобрать и провалидировать без записи результата |
Метаданные AggregateExpression сохраняются во вспомогательном файле *-aggregates.yaml.
Что преобразуется¶
| Понятие DDN | Эквивалент в Provisa |
|---|---|
| Модель подграфа | tables[] внутри источника |
| Связь (relationship) | relationships[] |
| Правило разрешения | Фильтр RLS |
| Command | Mutation-webhook или представление |
| Коннектор | Запись источника с реквизитами подключения |
Ограничения¶
- Lambda-коннекторы (функции на TypeScript/Python) требуют ручной настройки webhook
- Плагины жизненного цикла (lifecycle plugins) не имеют прямого эквивалента
- Режимы аутентификации DDN сопоставляются с провайдерами аутентификации Provisa, но пути claim в JWT может потребоваться скорректировать
После импорта¶
- Просмотрите сгенерированный
config.yamlи отчёт — начните с записейRedo by hand - Проверьте учётные данные подключения. Подключение, которое экспорт читал из переменной окружения, приходит пустым; отчёт называет его
- Запустите Provisa и убедитесь, что таблицы отображаются в Explorer
- Запустите существующие GraphQL-запросы — схема совместима для типовых паттернов
- Прежде чем включать управление (governance) для продакшена, отправьте запросы на утверждение через Admin API или UI