docs: update EvoBGP architecture plan with detailed REST API section, including general agreements, system endpoints, and prefix module specifications. Enhanced clarity on API structure and added references to OpenAPI documentation.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: EvoBGP архитектура
|
||||
overview: Оба профиля по умолчанию на PostgreSQL (один движок, одни миграции). reference — микросервисы + PG + брокер; microVPS — evobgp-all + контейнер PG (жёсткий тюнинг). SQLite — опция только для одного контейнера без PG.
|
||||
overview: Оба профиля по умолчанию на PostgreSQL (один движок, одни миграции). reference — микросервисы + PG + брокер; microVPS — evobgp-all + контейнер PG (жёсткий тюнинг). SQLite — опция только для одного контейнера без PG. REST API проработан в §7 плана (пути /v1, jobs, бандлы нод); OpenAPI — канон при появлении схемы.
|
||||
todos:
|
||||
- id: schema-db
|
||||
content: "Схема БД: PostgreSQL (основной); опционально SQLite (microVPS single-container); модули, ревизии, jobs"
|
||||
@@ -54,6 +54,21 @@ Control-plane на **Go**, анонс префиксов через **BIRD**, п
|
||||
5. [База данных, ETL, ER-схема](#5-база-данных-etl-er-схема)
|
||||
6. [Модули префиксов и FQDN](#6-модули-префиксов-as-cdn-домены)
|
||||
7. [REST API](#7-rest-api)
|
||||
- [7.1. Общие соглашения](#71-общие-соглашения)
|
||||
- [7.2. Системные и служебные](#72-системные-и-служебные)
|
||||
- [7.3. Модули префиксов](#73-модули-префиксов-module)
|
||||
- [7.4. DoH-профили](#74-doh-профили-doh_profile)
|
||||
- [7.5. BGP community](#75-bgp-community-bgp_community)
|
||||
- [7.6. Пиры](#76-пиры-bgp_peer)
|
||||
- [7.7. Спикеры BIRD](#77-спикеры-bird-bgp_speaker)
|
||||
- [7.8. Ревизии конфигурации](#78-ревизии-конфигурации-config_revision)
|
||||
- [7.9. Применение конфигурации](#79-применение-конфигурации-deploy-bird)
|
||||
- [7.10. Задачи](#710-задачи-job_audit)
|
||||
- [7.11. Реплики и бандлы](#711-реплики-evobgp-node-бандлы)
|
||||
- [7.12. Глобальные настройки](#712-глобальные-настройки-опционально)
|
||||
- [7.13. Матрица прав](#713-матрица-прав-роли)
|
||||
- [7.14. Следующие итерации](#714-следующие-итерации-api)
|
||||
- [7.15. Связь API с разделами плана](#715-связь-api-с-разделами-плана)
|
||||
8. [Генерация BIRD и ревизии](#8-генерация-bird-и-ревизии)
|
||||
9. [Эксплуатация и масштаб пиров](#9-эксплуатация-и-масштаб)
|
||||
10. [Реплика evobgp-node](#10-реплика-evobgp-node)
|
||||
@@ -460,15 +475,281 @@ erDiagram
|
||||
|
||||
## 7. REST API
|
||||
|
||||
Наброски путей, ролей и контрактов вынесены в **[docs/evobgp-api-sketches.md](docs/evobgp-api-sketches.md)** (`/v1`, задачи, бандлы нод).
|
||||
**Статус:** черновик для согласования и реализации; каноничная машиночитаемая форма — **[docs/openapi.yaml](docs/openapi.yaml)** (по мере заполнения). Ниже — **единая проработка** путей и семантики (консолидация с [docs/evobgp-api-sketches.md](docs/evobgp-api-sketches.md)). Базовый префикс: `**/v1`**. Термины: [§3](#3-логическая-модель-общая-для-обоих-профилей), [§5](#5-база-данных-etl-er-схема), [§6](#6-модули-префиксов-as-cdn-домены).
|
||||
|
||||
- `POST /modules/{id}/refresh`
|
||||
- `POST /apply`, `POST /speakers/{id}/apply` или `/bird/apply`
|
||||
- `GET /revisions`, `POST /revisions/{id}/rollback`
|
||||
- `POST|PATCH /peers`, CRUD DoH / community / модулей
|
||||
- Реплики: `GET /v1/speakers/{id}/bundle/{revision}`, `GET .../revisions/latest`, enrollment нод
|
||||
- Асинхронно: **202** + `job_id`, `GET /jobs/{id}`
|
||||
- Auth: API keys / mTLS
|
||||
### 7.1. Общие соглашения
|
||||
|
||||
|
||||
| Тема | Решение (набросок) |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Аутентификация** | Заголовок `Authorization: Bearer <api_key>` или mTLS на edge; ключи привязаны к tenant и роли. |
|
||||
| **Multi-tenant** | Все сущности в скоупе tenant: либо из ключа, либо явный префикс `X-Tenant-Id` (только для супер-ролей). |
|
||||
| **Идентификаторы** | UUID v7 или ULID в URL; в JSON — строки. |
|
||||
| **Время** | ISO 8601 UTC (`2026-04-03T12:00:00Z`). |
|
||||
| **Ошибки** | Тело `application/problem+json` (RFC 9457): `type`, `title`, `status`, `detail`, `instance`, опционально `errors[]` по полям. |
|
||||
| **Идемпотентность** | Для мутаций, создающих задачи или побочные эффекты: заголовок `Idempotency-Key` (опционально обязателен для `POST` apply/refresh). |
|
||||
| **Пагинация** | `?cursor=<opaque>&limit=50` (cursor-based); ответ: `items`, `next_cursor`, `has_more`. |
|
||||
| **Асинхронные операции** | `202 Accepted`, заголовок `Location: /v1/jobs/{job_id}`; тело `{ "job_id", "status": "queued" }`. |
|
||||
| **Версионирование** | Несовместимые изменения — новый префикс `/v2`. |
|
||||
|
||||
|
||||
### 7.2. Системные и служебные
|
||||
|
||||
|
||||
| Метод | Путь | Назначение |
|
||||
| ----- | ------------- | ------------------------------------------------------------ |
|
||||
| `GET` | `/v1/health` | Liveness (процесс жив). |
|
||||
| `GET` | `/v1/ready` | Readiness (БД, брокер при reference, и т.д.). |
|
||||
| `GET` | `/v1/version` | Версия сборки API и control-plane (`git_sha`, `build_time`). |
|
||||
|
||||
|
||||
### 7.3. Модули префиксов (`module`)
|
||||
|
||||
**Связь с продуктом.** В продуктовой формулировке **ASN / CDN / DOMAINS / IP-диапазоны** — это **четыре вида модулей**. Поле `**type`** в `POST /v1/modules` выбирает вид: `AS_PREFIXES`, `CDN_CIDRS`, `DOMAINS` или `**IP_RANGES`**. Дочерние ресурсы: `**as-entries`**, `**cdn-sources**`, `**domain-entries**`; `**ip-range-entries**` — статические **CIDR + `community_id`** (без ASN и без URL). `**module_id**` в пути — идентификатор **конкретного экземпляра** модуля, а не имя типа (согласовано с [§6](#6-модули-префиксов-as-cdn-домены)).
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| -------- | ------------------------- | ----------------------------------------------------------------- |
|
||||
| `GET` | `/v1/modules` | Список модулей tenant (фильтры: `?type=`, `?enabled=`). |
|
||||
| `POST` | `/v1/modules` | Создать модуль. |
|
||||
| `GET` | `/v1/modules/{module_id}` | Детали модуля. |
|
||||
| `PATCH` | `/v1/modules/{module_id}` | Частичное обновление (расписание, DoH, приоритет, `enabled`). |
|
||||
| `DELETE` | `/v1/modules/{module_id}` | Мягкое удаление или `enabled=false` — зафиксировать в реализации. |
|
||||
|
||||
|
||||
**CDN-источники модуля**
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| -------- | ------------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| `GET` | `/v1/modules/{module_id}/cdn-sources` | Список строк CDN. |
|
||||
| `POST` | `/v1/modules/{module_id}/cdn-sources` | Добавить источник (URL + `source_kind` + опционально `community_id`). |
|
||||
| `PATCH` | `/v1/modules/{module_id}/cdn-sources/{source_id}` | URL, `source_kind`, `community_id`, свой `refresh_interval_sec`. |
|
||||
| `DELETE` | `/v1/modules/{module_id}/cdn-sources/{source_id}` | Удалить. |
|
||||
|
||||
|
||||
**Записи AS / домены**
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| -------- | --------------------------------------------------- | --------------------- |
|
||||
| `GET` | `/v1/modules/{module_id}/as-entries` | Список ASN/префиксов. |
|
||||
| `POST` | `/v1/modules/{module_id}/as-entries` | Добавить. |
|
||||
| `PATCH` | `/v1/modules/{module_id}/as-entries/{entry_id}` | Обновить. |
|
||||
| `DELETE` | `/v1/modules/{module_id}/as-entries/{entry_id}` | Удалить. |
|
||||
| `GET` | `/v1/modules/{module_id}/domain-entries` | FQDN + community. |
|
||||
| `POST` | `/v1/modules/{module_id}/domain-entries` | Добавить. |
|
||||
| `PATCH` | `/v1/modules/{module_id}/domain-entries/{entry_id}` | Обновить. |
|
||||
| `DELETE` | `/v1/modules/{module_id}/domain-entries/{entry_id}` | Удалить. |
|
||||
|
||||
|
||||
**Записи IP-диапазонов** (только для `type: IP_RANGES`)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| -------- | ----------------------------------------------------- | ------------------------------------ |
|
||||
| `GET` | `/v1/modules/{module_id}/ip-range-entries` | Список CIDR + `community_id`. |
|
||||
| `POST` | `/v1/modules/{module_id}/ip-range-entries` | Добавить (`prefix`, `community_id`). |
|
||||
| `PATCH` | `/v1/modules/{module_id}/ip-range-entries/{entry_id}` | Обновить. |
|
||||
| `DELETE` | `/v1/modules/{module_id}/ip-range-entries/{entry_id}` | Удалить. |
|
||||
|
||||
|
||||
**Refresh (ingest)**
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| ------ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `POST` | `/v1/modules/{module_id}/refresh` | Запуск ingest для модуля (CDN / DoH / AS по типу). Для `**IP_RANGES`** обычно **не требуется** (данные только в БД); возможен `**204`** / no-op или `**400`**, если тип не поддерживает refresh — зафиксировать в реализации. |
|
||||
|
||||
|
||||
**Пример тела создания модуля (набросок)**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "CDN_CIDRS",
|
||||
"name": "edge-v4",
|
||||
"enabled": true,
|
||||
"priority": 10,
|
||||
"doh_profile_id": null,
|
||||
"refresh_interval_sec": 3600,
|
||||
"cron_expr": null,
|
||||
"default_community_id": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
Пример модуля `**IP_RANGES**`: `type: "IP_RANGES"`, `doh_profile_id: null`, далее строки через `ip-range-entries` с полями `prefix` (например `203.0.113.0/24`) и `community_id`.
|
||||
|
||||
### 7.4. DoH-профили (`doh_profile`)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| -------- | ----------------------- | ------------------------------------------------------------------------------------- |
|
||||
| `GET` | `/v1/doh-profiles` | Список. |
|
||||
| `POST` | `/v1/doh-profiles` | Создать (URL, таймауты; секрет — ссылка на vault id или отдельный `POST .../secret`). |
|
||||
| `GET` | `/v1/doh-profiles/{id}` | Детали (без раскрытия секрета). |
|
||||
| `PATCH` | `/v1/doh-profiles/{id}` | Обновить. |
|
||||
| `DELETE` | `/v1/doh-profiles/{id}` | Удалить, если не используется модулями. |
|
||||
|
||||
|
||||
### 7.5. BGP community (bgp_community)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| -------- | ---------------------- | ------------------------------ |
|
||||
| `GET` | `/v1/communities` | Список справочника. |
|
||||
| `POST` | `/v1/communities` | Создать. |
|
||||
| `GET` | `/v1/communities/{id}` | Детали. |
|
||||
| `PATCH` | `/v1/communities/{id}` | Обновить. |
|
||||
| `DELETE` | `/v1/communities/{id}` | Удалить при отсутствии ссылок. |
|
||||
|
||||
|
||||
### 7.6. Пиры (`bgp_peer`)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| -------- | ---------------- | ------------------------------------------------------------------------------ |
|
||||
| `GET` | `/v1/peers` | Список (`?speaker_id=`, пагинация). |
|
||||
| `POST` | `/v1/peers` | Создать пира. |
|
||||
| `GET` | `/v1/peers/{id}` | Детали. |
|
||||
| `PATCH` | `/v1/peers/{id}` | Политики, neighbor, ASN, привязка к `bgp_speaker_id` или `null` = все спикеры. |
|
||||
| `DELETE` | `/v1/peers/{id}` | Удалить / отключить. |
|
||||
|
||||
|
||||
### 7.7. Спикеры BIRD (`bgp_speaker`)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| ------- | ------------------- | ------------------------------------------ |
|
||||
| `GET` | `/v1/speakers` | Список (master / replica, endpoint). |
|
||||
| `POST` | `/v1/speakers` | Зарегистрировать спикер (реплика, canary). |
|
||||
| `GET` | `/v1/speakers/{id}` | Детали + `last_applied_revision_id`. |
|
||||
| `PATCH` | `/v1/speakers/{id}` | Метаданные, endpoint. |
|
||||
|
||||
|
||||
### 7.8. Ревизии конфигурации (config_revision)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| ------ | -------------------------------------- | --------------------------------------------------------------- |
|
||||
| `GET` | `/v1/revisions` | История ревизий (`?module_id=`, `?limit=`). |
|
||||
| `GET` | `/v1/revisions/{revision_id}` | Метаданные: хэш, родитель, время, артефакты. |
|
||||
| `GET` | `/v1/revisions/{revision_id}/prefixes` | Материализованный снимок префиксов (пагинация). |
|
||||
| `GET` | `/v1/revisions/{revision_id}/preview` | Превью фрагментов BIRD (read-only, без apply). |
|
||||
| `POST` | `/v1/revisions/{revision_id}/rollback` | Создать **новую** ревизию с содержимым отката; часто `**202`**. |
|
||||
|
||||
|
||||
**Сравнение ревизий (набросок)**
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| ----- | ---------------------------- | ----------------------------------------------------------------------------- |
|
||||
| `GET` | `/v1/revisions/{a}/diff/{b}` | Diff префиксов / метаданных (формат зафиксировать: JSON patch или табличный). |
|
||||
|
||||
|
||||
### 7.9. Применение конфигурации (deploy, BIRD)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| ------ | ------------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `POST` | `/v1/apply` | Применить текущую целевую ревизию на всех спикерах (или по политике по умолчанию). `**202`**. |
|
||||
| `POST` | `/v1/speakers/{id}/apply` | Применить на одном спикере (canary). `**202`**. |
|
||||
| `POST` | `/v1/bird/reload` | Опционально: явный мягкий reload политики (если отделён от apply); иначе часть `apply`. |
|
||||
|
||||
|
||||
**Тело `POST /v1/apply` (набросок, опционально)**
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_id": "01JQXYZ...",
|
||||
"strategy": "all_speakers",
|
||||
"dry_run": false
|
||||
}
|
||||
```
|
||||
|
||||
Связь с безопасным применением: [§13](#13-снижение-рисков-меры-и-процессы) (двухфазный deploy, LKG).
|
||||
|
||||
### 7.10. Задачи (job_audit)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| ------ | -------------------------- | --------------------------------------------- |
|
||||
| `GET` | `/v1/jobs` | Список задач (`?status=`, `?kind=`, cursor). |
|
||||
| `GET` | `/v1/jobs/{job_id}` | Статус, прогресс, ошибка, связанные сущности. |
|
||||
| `POST` | `/v1/jobs/{job_id}/cancel` | Запрос отмены (best-effort). |
|
||||
|
||||
|
||||
**Пример ответа `GET /v1/jobs/{id}`**
|
||||
|
||||
```json
|
||||
{
|
||||
"job_id": "01JQXYZ...",
|
||||
"kind": "module_refresh",
|
||||
"status": "running",
|
||||
"idempotency_key": "client-abc-123",
|
||||
"created_at": "2026-04-03T10:00:00Z",
|
||||
"started_at": "2026-04-03T10:00:01Z",
|
||||
"finished_at": null,
|
||||
"error": null,
|
||||
"meta": { "module_id": "01JQM..." }
|
||||
}
|
||||
```
|
||||
|
||||
### 7.11. Реплики evobgp-node: бандлы
|
||||
|
||||
Вызываются **нодой** с отдельным ключом / mTLS (роль `node`). См. также [§10](#10-реплика-evobgp-node).
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| ------ | ------------------------------------------------ | -------------------------------------------------------------------------------------- |
|
||||
| `GET` | `/v1/speakers/{speaker_id}/revisions/latest` | Указатель на последнюю опубликованную ревизию для ноды. |
|
||||
| `GET` | `/v1/speakers/{speaker_id}/bundle/{revision_id}` | Скачивание подписанного бандла (архив + `manifest.json` + подпись). |
|
||||
| `POST` | `/v1/nodes/enroll` | Регистрация ноды (обмен ключами, привязка к `speaker_id`) — детали протокола отдельно. |
|
||||
|
||||
|
||||
Заголовки для бандла: `Content-Type: application/octet-stream` или multipart; целостность по `manifest` (SHA-256) и подписи (например Ed25519) — обязательно на ноде в production ([§13](#13-снижение-рисков-меры-и-процессы)).
|
||||
|
||||
### 7.12. Глобальные настройки (опционально)
|
||||
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
| ------- | -------------- | ------------------------------------------------------- |
|
||||
| `GET` | `/v1/settings` | KV вроде `global_settings` (лимиты CDN, feature flags). |
|
||||
| `PATCH` | `/v1/settings` | Частичное обновление (только роль operator). |
|
||||
|
||||
|
||||
### 7.13. Матрица прав (роли)
|
||||
|
||||
|
||||
| Ресурс | `viewer` | `editor` | `operator` | `node` |
|
||||
| -------------------------- | -------- | -------- | ---------- | ------ |
|
||||
| GET модули, ревизии, peers | да | да | да | нет* |
|
||||
| PATCH модули, peers | нет | да | да | нет |
|
||||
| apply, rollback | нет | нет | да | нет |
|
||||
| bundle / enroll | нет | нет | нет | да |
|
||||
|
||||
|
||||
Нода не ходит в общий CRUD; только [§7.11](#711-реплики-evobgp-node-бандлы).
|
||||
|
||||
### 7.14. Следующие итерации API
|
||||
|
||||
- Полная **OpenAPI 3.1** в `docs/openapi.yaml` по этому разделу.
|
||||
- Webhooks: `POST` на URL клиента по завершении `job` (опционально).
|
||||
- SSE/WebSocket для стрима статуса долгих jobs.
|
||||
- Rate limits по ключу и по tenant в ответах (`RateLimit-*` заголовки).
|
||||
|
||||
### 7.15. Связь API с разделами плана
|
||||
|
||||
|
||||
| Тема плана | Подраздел §7 |
|
||||
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| REST, jobs, идемпотентность | [7.1](#71-общие-соглашения), [7.10](#710-задачи-job_audit) |
|
||||
| refresh, apply, rollback, preview, `IP_RANGES` | [7.3](#73-модули-префиксов-module), [7.8](#78-ревизии-конфигурации-config_revision), [7.9](#79-применение-конфигурации-deploy-bird) |
|
||||
| peers, speakers, communities, DoH | [7.4](#74-doh-профили-doh_profile)–[7.7](#77-спикеры-bird-bgp_speaker) |
|
||||
| bundle API, нода | [7.11](#711-реплики-evobgp-node-бандлы) |
|
||||
| Контрактные тесты HTTP | [§14](#14-тестирование-bird2-и-матрица-сценариев) + `openapi.yaml` |
|
||||
|
||||
|
||||
Черновик в репозитории [docs/evobgp-api-sketches.md](docs/evobgp-api-sketches.md) держать **синхронным** с §7 при согласовании изменений (или пометить файл указателем на план как единый источник).
|
||||
|
||||
---
|
||||
|
||||
@@ -644,7 +925,7 @@ Raft, HTTP/`gorqlite`; для HA control-plane; не замена дефолтн
|
||||
|
||||
1. **Unit / snapshot (Go):** пакет `internal/birdfmt` — вход из фикстур, выход сравнивается с `*.golden` или `txtar`.
|
||||
2. **Синтаксис BIRD в CI:** для каждого сценария с `bird.conf` выполняется `**bird -c … -p`** в контейнере с **той же major/minor версией BIRD 2**, что в production ([§13](#13-снижение-рисков-меры-и-процессы)).
|
||||
3. **Позже:** контрактные тесты HTTP по `docs/openapi.yaml` после реализации `internal/httpapi`.
|
||||
3. **Позже:** контрактные тесты HTTP по `docs/openapi.yaml` и сценариям из [§7](#7-rest-api) после реализации `internal/httpapi`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -267,4 +267,4 @@
|
||||
| peers, speakers, communities, DoH | §4 - §7 |
|
||||
| bundle API, нода | §11 |
|
||||
|
||||
Файл плана: `.cursor/plans/evobgp_архитектура_0e73ef02.plan.md` (§6 REST API).
|
||||
Файл плана: `.cursor/plans/evobgp_архитектура_0e73ef02.plan.md` (§7 REST API).
|
||||
|
||||
Reference in New Issue
Block a user