Зафиксированы очередь job, семантика метрик, лимиты бандла и исходящих запросов, а также чеклист продакшена для пула соединений. Co-authored-by: Cursor <cursoragent@cursor.com>
17 KiB
REST API: обзор и ссылки
Полный контракт запросов и ответов описан в openapi.yaml (OpenAPI 3.1). Этот файл — источник правды. Краткий контекст и ранние таблицы — в evobgp-api-sketches.md (черновик, не заменяет OpenAPI).
Базовый URL и версия
- Все функциональные маршруты API используют префикс
/v1(напримерhttps://api.example.com/v1/modules). - Версия сборки:
GET /v1/version(публичный маршрут, без Bearer).
Публичные маршруты (без Authorization)
| Метод | Путь | Назначение |
|---|---|---|
GET |
/v1/health |
Liveness |
GET |
/v1/ready |
Readiness (зависимости, например БД) |
GET |
/v1/version |
Версия / метаданные сборки |
Дополнительно на корне сервера (вне /v1):
| Метод | Путь | Назначение |
|---|---|---|
GET |
/metrics |
Метрики Prometheus |
Все остальные запросы под /v1/..., кроме перечисленных выше трёх GET, проходят через middleware и требуют Authorization: Bearer <api_key> (см. access.md).
Ограничение тела запроса
После аутентификации все непубличные /v1/... запросы проверяются целиком до вызова handler: максимум 8 MiB (8388608 bytes). Проверка действует для любого метода, включая GET, без зависимости от Content-Type или Content-Length; JSON с большим хвостом whitespace не позволяет выполнить мутацию до обнаружения превышения. Ответ — 413 application/problem+json, без выполнения запрошенной мутации. Ошибка чтения возвращает 400, отмена/таймаут чтения — 408.
Запросы с телом допускаются без очереди ожидания: по умолчанию 4 одновременно на API instance. EVOBGP_API_BODY_MAX_CONCURRENT задаёт число от 1 до 64; невалидное значение выбирает default 4. Слот удерживается до завершения handler, пока его request buffer может использоваться. При занятых слотах — немедленный 429 с Retry-After: 1. Пустые http.NoBody запросы, включая обычные node GET/pull, слота не занимают; указание Content-Length: 0 при фактически существующем body не отключает ограничение.
CSV сохраняет отдельные ограничения своей операции: 8 MiB, 10000 строк данных, 64 поля. Тело запроса проверяется до импорта; SSE ограничивается только на входе и продолжает потоковый ответ. Предел буферов ограничивает память входящих тел, а не всю память разбора JSON, работы handler или response.
Группы маршрутов (соответствие тегам OpenAPI)
Ниже — обзор того, что реализовано в коде (internal/httpapi/routes.go, routes_crud.go). Детали тел, кодов ответов и схем — только в OpenAPI.
Modules
GET /v1/modules,GET /v1/modules/{module_id}POST /v1/modules,PATCH /v1/modules/{module_id},DELETE /v1/modules/{module_id}GET|POST|PATCH|DELETEдля.../cdn-sources,.../as-entries,.../domain-entries,.../ip-range-entriesPOST /v1/modules/{module_id}/refreshGET /v1/router-lists/catalog— агрегированный каталог модулей/entries/communities
Lookup
GET /v1/lookup?q=— быстрая проверка IP или FQDN в списках (viewer+).- Слой
entry:IP_RANGES(CIDR.Contains) /DOMAINS(нормализованный FQDN). - Слой
snapshot: материализованныеmodule_prefix_snapshot(для IP — Contains по всем модулям; для домена —source=domainу matched DOMAINS-модулей). - В каждом матче — community (
community_id/ значение / title). - Live DoH не выполняется. Контракт: OpenAPI
lookupMembership.
- Слой
DoH profiles
GET|POST /v1/doh-profilesGET|PATCH|DELETE /v1/doh-profiles/{id}
Communities
GET|POST /v1/communitiesGET|PATCH|DELETE /v1/communities/{id}
API keys
GET /v1/auth/session— tenant и роль текущего ключаGET|POST /v1/api-keys— список и создание (operator)GET|PATCH|DELETE /v1/api-keys/{id},POST /v1/api-keys/{id}/rotate
Peers
GET /v1/peers,POST /v1/peersGET|PATCH|DELETE /v1/peers/{id}- Для
POST|PATCH|DELETEpeer запускается быстрый jobpeer_reconcile(без module ingest/сбора префиксов); после него автоматически ставится apply на спикеры.
Live-состояние следует читать вместе с live_observation (схема LiveObservation в OpenAPI). Отсутствующее наблюдение не означает ноль сессий или отказ BGP: session_state может быть null, а сохранённое значение вынесено в last_known_session_state. Для назначенного пира состояние вычисляется по его speaker; успешный опрос другого узла не делает его healthy. У speakers отдельно представлены качество опроса BGP и агента; счётчики без успешного опроса nullable.
Speakers
GET /v1/speakers,POST /v1/speakersGET|PATCH /v1/speakers/{speaker_id}(в коде идентификатор в пути —speaker_id; в части маршрутов apply используется{id}— смотрите OpenAPI и реализацию)
Уточнение по коду: для apply на одном спикере зарегистрирован маршрут POST /speakers/{id}/apply внутри v1 mux → POST /v1/speakers/{id}/apply.
Revisions
GET /v1/revisions,GET /v1/revisions/{revision_id}GET /v1/revisions/{revision_id}/prefixesGET /v1/revisions/{revision_id}/previewGET /v1/revisions/{revision_a}/diff/{revision_b}POST /v1/revisions/{revision_id}/rollback
Deploy и BIRD
POST /v1/applyPOST /v1/speakers/{id}/applyPOST /v1/bird/reload
Ответ 202 подтверждает принятие задания. Результат доставки удалённому агенту не равен применению: старый 2xx без явного revision ID имеет уровень unconfirmed; совпадающий явный ACK — agent_reported. Локальный успешный apply — local_applied. Подтверждение хеша работающего BIRD-конфига (verified) пока не реализовано. Job содержит частичные результаты по speakers; ошибка одного узла не скрывается общим успехом, отмена сохраняет выполненную часть и останавливает публикацию следующим узлам. Границы совместимости и одного активного deploy writer описаны в backend-compatibility.md.
Jobs
GET /v1/jobs,GET /v1/jobs/{job_id}POST /v1/jobs/{job_id}/cancel
Node (роль node)
GET /v1/speakers/{speaker_id}/revisions/latestGET /v1/speakers/{speaker_id}/bundle/{revision_id}POST /v1/nodes/enroll
Settings
GET /v1/settings,PATCH /v1/settings— tenant KV (global_settings): BIRD,revision_retention_minutes,runtime_logs_*(автоочистка FS), произвольные ключи. Чтение — viewer+;PATCH— operator+.
RuntimeLogs
Файловые логи Docker-сервисов (sidecar stack-runtime-logs). FS API только в процессе evobgp-all при EVOBGP_SERVICE=evobgp-all и EVOBGP_RUNTIME_LOGS_DIR (см. access.md). Иначе GET/DELETE по файлам → 503 (runtime_logs_unavailable).
| Метод | Путь | Роль | Назначение |
|---|---|---|---|
GET |
/v1/runtime-logs/files |
viewer+ | Список *.log (имя, размер, mtime) |
GET |
/v1/runtime-logs/files/{filename} |
viewer+ | Хвост файла (?lines=, ?bytes=, ?grep=) |
DELETE |
/v1/runtime-logs/files/{filename} |
operator+ | Синхронная очистка (?mode=truncate|delete, default truncate); max 512 MiB |
GET |
/v1/runtime-logs/cleanup-audit |
viewer+ | Пагинированный audit очистки (cursor, limit); без FS volume |
GET |
/v1/runtime-logs/auto-estimate |
operator+ | Файлы выше порога из tenant settings |
POST |
/v1/runtime-logs/auto-run |
operator+ | Немедленный прогон (?dry_run=true); audit с actor_prefix=auto:scheduler |
{filename} — только basename, паттерн ^[a-z0-9][a-z0-9_.-]*\.log$. Очистка пишет строку в таблицу runtime_log_cleanup_audit (миграция 000026).
CRUD audit (/v1/audit)
Локальный журнал изменений CRUD (modules, peers, settings, API keys, …). Миграция 000030_audit_log. Чтение — bgp:monitoring:read (viewer+).
| Метод | Путь | Роль | Назначение |
|---|---|---|---|
GET |
/v1/audit |
viewer+ | Пагинированный audit (cursor, limit, опционально action, severity) |
При AUTH_PORTAL_URL + AUTH_AUDIT_INGEST_SECRET каждая запись дополнительно отправляется в auth-portal (POST /api/v1/ingest/audit, source_app=bgp).
Соглашения из OpenAPI
- Ошибки в стиле RFC 9457 (
application/problem+json):type,title,status,detail, и т.д. - Пагинация списков: query-параметры
cursor,limit; в ответе частоitems,next_cursor,has_more. - Заголовок
Idempotency-Keyдля идемпотентных мутаций (рекомендации — в описаниях операций в OpenAPI). - Заголовок
X-Tenant-Idописан в спецификации для супер-ролей; в текущей реализации Go tenant берётся только из API-ключа, заголовок в обработчиках не переключает контекст (см. access.md).
Как смотреть документацию API
- Статическая страница Redoc: openapi.html (инструкции для Gitea и пересборки — OPENAPI-GITEA.md).
- Пересборка после правок YAML (из корня репозитория, PowerShell):
.\scripts\build-openapi-html.ps1
Примеры вызовов
PowerShell, список модулей (подставьте свой токен и URL):
$base = "http://localhost:8080"
$token = "opkey"
$h = @{ Authorization = "Bearer $token" }
Invoke-RestMethod -Uri "$base/v1/modules" -Headers $h
Эквивалент с curl (если установлен):
curl -s -H "Authorization: Bearer opkey" http://localhost:8080/v1/modules
CORS для браузерных клиентов настраивается переменной EVOBGP_CORS_ORIGINS на стороне API.
Квоты preview и lookup
Синхронные GET /lookup, CDN preview и revision preview используют общий локальный пул: по умолчанию 4 активных операции на процесс API, не более 2 на tenant. Для каждого tenant действуют отдельные минутные счётчики: 120 lookup, 30 CDN preview и 30 revision preview. При заполнении возвращается 429 с Retry-After, без очереди ожидания. Отмена клиента не освобождает место, пока обработчик действительно не завершил работу. Retry-After доступен также клиентам через CORS.
| Переменная | По умолчанию | Допустимый диапазон |
|---|---|---|
EVOBGP_API_EXPENSIVE_MAX_CONCURRENT |
4 | 1–64 |
EVOBGP_API_EXPENSIVE_TENANT_CONCURRENT |
2 | 1–64 |
EVOBGP_API_LOOKUP_PER_MINUTE |
120 | 1–100000 |
EVOBGP_API_CDN_PREVIEW_PER_MINUTE |
30 | 1–100000 |
EVOBGP_API_REVISION_PREVIEW_PER_MINUTE |
30 | 1–100000 |
Некорректное значение заменяется значением по умолчанию. Состояние ограничено 4096 tenant; действующие счётчики и активная работа не вытесняются ради новых tenant. Квоты локальны: несколько API-реплик умножают доступную нагрузку. Они не являются общей кластерной квотой. Refresh/retry управляются отдельной durable queue с её лимитами и replay исходного запроса; legacy bundle/latest endpoints не используют квоту preview/lookup. Общий admission входного тела может вернуть 429 до проверки replay, поэтому такой POST можно повторить с тем же idempotency key.
Ограничения CSV-импорта
CSV-импорт ограничен 8 MiB полного тела запроса, 10000 строк данных без заголовка и 64 полями в одной записи. Превышение возвращает 413 до создания записей, включая запросы без Content-Length; отправляйте большие списки частями. Синтаксически корректный префикс слишком большого файла больше не импортируется молча. Отмена запроса останавливает последующие записи. Ошибки данных или БД после начала импорта всё ещё могут оставить уже созданные строки: импорт не является общей транзакцией.
Сохранённый отчёт доставки
GET /v1/jobs/{job_id}/report требует bgp:operations:read и возвращает deployment_progress независимо от промежуточной meta. Для recovery job поле source_deployment_job_id указывает исходную операцию в том же tenant. Пока собственных записей нет, отчёт показывает исходный прогресс; после начала recovery — собственный. Каждый элемент содержит job_id, поэтому происхождение результата видно явно.
health_received_at — время получения наблюдения control plane, health_source_at — необязательная отметка агента. Отсутствие этого поля у 2.56.2 не препятствует доставке. unknown и unconfirmed нельзя интерпретировать как подтверждённое применение или отказ BIRD. Полный HTTP-контракт: OpenAPI, getJobReport.
Связанные документы
- access.md — ключи и роли.
- overview.md — продуктовые возможности.