Перейти к содержанию

Импорт из Hasura

Provisa может преобразовать существующие метаданные Hasura в Provisa config.yaml, сохраняя отслеживаемые таблицы, связи, разрешения и удалённые схемы.

Интерактивный импорт (Admin → Import Hasura Config)

Административная поверхность запускает те же конвертеры, поэтому импорт не требует доступа к оболочке и не требует прохождения через файл конфигурации туда-обратно. Требуется возможность (capability) org_settings; импорт попадает в организацию, от имени которой действует сессия.

  1. Загрузка. Выберите заархивированный каталог метаданных Hasura v2, заархивированный проект DDN, консолидированный экспорт метаданных (.yaml/.json, включая конверт {resource_version, metadata}, который возвращает API метаданных), либо один файл .hml. Оставьте формат на Detect automatically, если только загружаемый файл не является неоднозначным.
  2. Сопоставление доменов (необязательно). Каждая пара сопоставляет схему v2 или подграф DDN с доменом Provisa; всё, что не сопоставлено, сохраняет исходное имя.
  3. Преобразование и предпросмотр. Сервер преобразует и возвращает счётчики, отчёт о преобразовании (см. Отчёт) и сгенерированную конфигурацию. На этом шаге ничего не записывается. предупреждения конвертера и сгенерированную конфигурацию. На этом шаге ничего не записывается.
  4. Проверка и редактирование. Конфигурацию можно редактировать на месте — реквизиты подключения, имена доменов, имена ролей. Применяется именно то, что показано.
  5. Применение. Применить к этой организации загружает конфигурацию и перестраивает схемы организации. Импорт всегда объединяется с тем, что уже есть у организации.

Конечные точки: POST /admin/import/hasura/preview и POST /admin/import/hasura/apply.


Hasura v2

Экспорт метаданных

Преобразуются оба формата экспорта.

Каталог метаданных CLI. hasura metadata export записывает каталог. databases/databases.yaml перечисляет каждый источник с его видом и подключением и указывает на его таблицы и функции через индексы !include:

hasura metadata export
# 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:

python -m provisa.hasura_v2 ./metadata -o config.yaml

Опустите -o, чтобы вывести конфигурацию в stdout. Если что-то осталось переделать вручную, отчёт выводится в stderr.

Флаги:

Флаг Назначение
-o, --output Путь к выходному YAML (по умолчанию: stdout)
--source-overrides YAML-файл с переопределениями подключения по источникам (хост, порт, учётные данные), с ключами — именами источников
--domain-map Сопоставления схема-домен в виде пар SCHEMA=DOMAIN
--auth-env-file Файл .env с конфигурацией аутентификации; преобразует JWT/JWK, секрет администратора и карту claims
--dry-run Разобрать и проверить без записи результата

Отчёт

Каждое преобразование раскладывает найденное на три части. Читайте их в таком порядке.

  1. Перенесено как есть. У объекта есть прямой аналог в Provisa, и он преобразуется без изменения смысла: источники, таблицы, одобренные связи, разрешения select, cron-триггеры.
  2. Сопоставлено с лучшей функцией Provisa. В Provisa есть функция, которая решает задачу лучше, чем функция Hasura, поэтому объект становится ею. Каждая запись объясняет почему. Сюда попадают event-триггеры, actions, remote schemas, дополнительные имена корневых полей и роли, унаследованные от нескольких ролей.
  3. Переделать вручную. У объекта нет аналога в 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.

Преобразование

python -m provisa.ddn ./my-ddn-project -o config.yaml

Опустите -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 может потребоваться скорректировать

После импорта

  1. Просмотрите сгенерированный config.yaml и отчёт — начните с записей Redo by hand
  2. Проверьте учётные данные подключения. Подключение, которое экспорт читал из переменной окружения, приходит пустым; отчёт называет его
  3. Запустите Provisa и убедитесь, что таблицы отображаются в Explorer
  4. Запустите существующие GraphQL-запросы — схема совместима для типовых паттернов
  5. Прежде чем включать управление (governance) для продакшена, отправьте запросы на утверждение через Admin API или UI