Files
DenozordecandCursor 3723ba7ed1
quality / commitlint (push) Skipped
quality / changes (push) Successful in 8s
quality / docker-check (push) Skipped
quality / openapi (push) Failing after 21s
quality / web (push) Successful in 55s
quality / go (push) Successful in 1m2s
quality / bird2 (push) Successful in 16s
CD / quality (push) Failing after 2m49s
CD / publish (push) Skipped
feat(httpapi): return replica docker install commands on speaker create
После создания реплики 201 отдаёт agent_secret, node_token и install.docker_commands (bird2 + agent + Traefik DNS-01). UI показывает шаг установки вместо закрытия диалога, чтобы секрет больше не терялся.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-21 13:51:06 +07:00

5098 lines
163 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
openapi: 3.1.0
info:
title: EvoBGP Control Plane API
version: 1.0.0
description: |
REST API управления префиксами, модулями ingest, ревизиями конфигурации BIRD и задачами (async jobs).
**Актуальная semver-сборка:** `GET /version` или `GET /v1/version` (поле `version`; совпадает с git-тегом `vX.Y.Z`).
**Соглашения:** префикс `/v1`; идентификаторы - UUID v7 или ULID (строки); время - ISO 8601 UTC.
Ошибки - `application/problem+json` ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)).
Пагинация списков - `cursor` + `limit`; ответ содержит `items`, `next_cursor`, `has_more`.
**Аутентификация (dual):**
- **API key** — `Authorization: Bearer <token>` из `EVOBGP_API_KEYS` / таблицы `api_key` (роли `viewer`/`editor`/`operator`/`node`/`firewall`).
- **Portal JWT** — HS256 от auth-portal; claim `apps` должен содержать `bgp`; права `bgp:<section>:<action>`; tenant из `tenants.bgp` / `bgp_tenant_id` или fallback `EVOBGP_PORTAL_TENANT_ID`.
Публично: `GET /v1/auth/config` → `{ required, portal_url }`.
**Роли API key** (матрица): `viewer`, `editor`, `operator`, `node`. Нода использует отдельные пути и ключ с ролью `node`.
JWT permissions мапятся на ту же лестницу (`:read`→viewer, `:write`→editor, `:admin`→operator).
Заголовок `X-Tenant-Id`: **не реализован в handlers** (документировано в docs/access.md).
Tenant всегда из API-ключа / portal JWT claim / `EVOBGP_PORTAL_TENANT_ID`. Спецификация сохраняет заголовок как reserved future; не полагаться на него в клиентах.
license:
name: Proprietary
identifier: LicenseRef-Proprietary
servers:
- url: https://api.example.com
description: Базовый URL инсталляции (замените на свой)
tags:
- name: System
description: Liveness, readiness и метаданные сборки. Обычно без чувствительных данных; доступ может быть шире.
- name: Modules
description: Экземпляры модулей префиксов (AS, CDN, домены, статические IP-диапазоны) и вложенные записи. Чтение - viewer+; изменение - editor+.
- name: Lookup
description: Быстрая проверка membership IP/FQDN в списках (entries + module prefix snapshots) и community. Чтение - viewer+.
- name: DoH profiles
description: Профили DNS-over-HTTPS для модулей типа домены. Секрет в ответах не возвращается.
- name: Communities
description: Справочник BGP community в скоупе tenant.
- name: Peers
description: BGP-пиры и политики; привязка к спикеру или ко всем спикерам.
- name: Speakers
description: Регистрация и метаданные экземпляров BIRD (master/replica/canary).
- name: Revisions
description: История ревизий конфигурации, снимки префиксов, превью и откат (часто асинхронно).
- name: Deploy
description: Применение ревизий на спикерах и опциональный reload BIRD. Требуется роль operator.
- name: Jobs
description: Асинхронные задачи; статус и отмена (best-effort).
- name: Node
description: "API для evobgp-node (бандлы ревизий и enrollment). Отдельный ключ или mTLS, роль node."
- name: Settings
description: Глобальные настройки и feature flags; изменение - только operator.
- name: API keys
description: Управление API-ключами tenant (operator). Секрет возвращается только при создании и ротации.
- name: Auth
description: Сессия текущего API-ключа (tenant и роль).
- name: Monitoring
description: Наблюдаемость PostgreSQL и корреляция (instance-level, viewer+). Maintenance — operator.
- name: Audit
description: Журнал CRUD-изменений tenant (локально + опциональный push в auth-portal). Чтение — bgp:monitoring:read.
- name: Maintenance
description: Политики обслуживания PostgreSQL (instance-scoped). CRUD и запуск — operator.
- name: RuntimeLogs
description: |
Файловые runtime-логи Docker-сервисов (каталог EVOBGP_RUNTIME_LOGS_DIR).
Доступно только в процессе evobgp-all с примонтированным volume; иначе 503.
Просмотр — viewer+; очистка — operator+ (синхронно, с audit).
- name: Firewall
description: Linux firewall blocklist clients, policy rules (block/accept), and data-plane sync.
security:
- bearerAuth: []
externalDocs:
description: Черновик и контекст API
url: ./evobgp-api-sketches.md
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: API-ключ в формате `Bearer <token>`. На edge может заменяться или дополняться mTLS.
parameters:
TenantId:
name: X-Tenant-Id
in: header
required: false
schema:
$ref: "#/components/schemas/ResourceId"
description: >
Явный tenant (только супер-роли). Без заголовка tenant определяется по API-ключу.
**Реализация v1:** заголовок в Go handlers не обрабатывается; tenant только из Bearer-токена (см. docs/access.md).
IdempotencyKey:
name: Idempotency-Key
in: header
required: false
schema:
type: string
maxLength: 256
description: Идемпотентность мутаций. Для `POST` apply и части refresh рекомендуется или обязателен по политике продукта.
Cursor:
name: cursor
in: query
schema:
type: string
description: Непрозрачный курсор из предыдущего ответа.
Limit:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 500
default: 50
description: Размер страницы (по умолчанию 50).
ModuleId:
name: module_id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
SpeakerId:
name: speaker_id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
RevisionId:
name: revision_id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
JobId:
name: job_id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
PeerId:
name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
DohProfileId:
name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
CommunityId:
name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
ApiKeyId:
name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
SourceId:
name: source_id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
EntryId:
name: entry_id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
RevisionA:
name: revision_a
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
RevisionB:
name: revision_b
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
ModuleTypeFilter:
name: type
in: query
schema:
$ref: "#/components/schemas/ModuleType"
ModuleEnabledFilter:
name: enabled
in: query
schema:
type: boolean
SpeakerFilter:
name: speaker_id
in: query
schema:
$ref: "#/components/schemas/ResourceId"
RevisionModuleFilter:
name: module_id
in: query
schema:
$ref: "#/components/schemas/ResourceId"
JobStatusFilter:
name: status
in: query
schema:
$ref: "#/components/schemas/JobStatus"
JobKindFilter:
name: kind
in: query
schema:
type: string
description: >
Фильтр по виду задачи; точный перечень расширяем.
Основные значения: `module_refresh`, `peer_reconcile`, `deploy_apply`, `revision_rollback`, `bird_reload`.
responses:
Unauthorized:
description: Нет или невалидный Bearer-токен.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
BadRequest:
description: Некорректный запрос (пустой или невалидный параметр).
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
Forbidden:
description: Недостаточно прав для операции.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
NotFound:
description: Ресурс не найден в скоупе tenant.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
Conflict:
description: Конфликт состояния (например, удаление DoH-профиля, который ещё используется).
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
UnprocessableEntity:
description: Семантическая ошибка запроса или валидации полей.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
DefaultProblem:
description: Ошибка (см. тело Problem).
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
schemas:
ResourceId:
type: string
description: UUID v7 или ULID.
pattern: "^[0-9A-Za-z_-]{20,36}$"
examples:
- 01JQXYZABCDEFGHIJKLMNOPQRS
Problem:
type: object
description: Problem Details (RFC 9457).
required:
- title
- status
properties:
type:
type: string
format: uri-reference
description: URI типа проблемы.
title:
type: string
status:
type: integer
detail:
type: string
instance:
type: string
format: uri-reference
errors:
type: array
items:
$ref: "#/components/schemas/FieldError"
additionalProperties: true
FieldError:
type: object
properties:
field:
type: string
description: Имя поля (или JSON Pointer).
pointer:
type: string
description: JSON Pointer к значению.
message:
type: string
additionalProperties: true
AsyncJobAccepted:
type: object
required:
- job_id
- status
properties:
job_id:
$ref: "#/components/schemas/ResourceId"
status:
type: string
enum: [queued]
description: Начальный статус задачи в очереди.
ModuleType:
type: string
enum:
- AS_PREFIXES
- CDN_CIDRS
- DOMAINS
- IP_RANGES
DohResolverPolicy:
type: string
description: |
Политика резолва доменов через DoH при нескольких профилях.
`primary_only` — только первый профиль; `failover` — по порядку до первого успешного;
`union` — объединение A/AAAA со всех профилей.
enum:
- primary_only
- failover
- union
default: primary_only
JobStatus:
type: string
description: Статус задачи; перечень может расширяться.
enum:
- queued
- running
- succeeded
- failed
- cancelled
ApplyStrategy:
type: string
description: Стратегия выбора спикеров для apply.
enum:
- all_speakers
Module:
type: object
required:
- id
- type
- name
- enabled
- priority
properties:
id:
$ref: "#/components/schemas/ResourceId"
type:
$ref: "#/components/schemas/ModuleType"
name:
type: string
enabled:
type: boolean
priority:
type: integer
doh_profile_id:
type: ["string", "null"]
description: Первый DoH-профиль (legacy); предпочтительно `doh_profile_ids`.
doh_profile_ids:
type: array
items:
$ref: "#/components/schemas/ResourceId"
description: Упорядоченный список DoH-профилей для модулей `DOMAINS`.
doh_resolver_policy:
$ref: "#/components/schemas/DohResolverPolicy"
refresh_interval_sec:
type: ["integer", "null"]
minimum: 0
cron_expr:
type: ["string", "null"]
default_community_id:
type: ["string", "null"]
last_refreshed_at:
type: ["string", "null"]
format: date-time
description: Время последнего успешного обновления данных модуля.
additionalProperties: true
ModuleCreate:
type: object
required:
- type
- name
properties:
type:
$ref: "#/components/schemas/ModuleType"
name:
type: string
enabled:
type: boolean
default: true
priority:
type: integer
default: 0
doh_profile_id:
type: ["string", "null"]
description: Первый DoH-профиль (legacy); предпочтительно `doh_profile_ids`.
doh_profile_ids:
type: array
items:
$ref: "#/components/schemas/ResourceId"
description: Упорядоченный список DoH-профилей для модулей `DOMAINS`.
doh_resolver_policy:
$ref: "#/components/schemas/DohResolverPolicy"
refresh_interval_sec:
type: ["integer", "null"]
last_refreshed_at:
type: ["string", "null"]
format: date-time
description: Время последнего успешного обновления этого CDN-источника.
cron_expr:
type: ["string", "null"]
default_community_id:
type: ["string", "null"]
ModulePatch:
type: object
properties:
name:
type: string
enabled:
type: boolean
priority:
type: integer
doh_profile_id:
type: ["string", "null"]
description: Первый DoH-профиль (legacy); предпочтительно `doh_profile_ids`.
doh_profile_ids:
type: array
items:
$ref: "#/components/schemas/ResourceId"
description: Упорядоченный список DoH-профилей для модулей `DOMAINS`.
doh_resolver_policy:
$ref: "#/components/schemas/DohResolverPolicy"
refresh_interval_sec:
type: ["integer", "null"]
cron_expr:
type: ["string", "null"]
default_community_id:
type: ["string", "null"]
CdnSource:
type: object
required:
- id
- url
- source_kind
properties:
id:
$ref: "#/components/schemas/ResourceId"
url:
type: string
format: uri
source_kind:
type: string
description: Формат скачанного списка / парсер.
prefix_path:
type: string
description: Путь до поля с префиксами для source_kind=json (например data.items[].cidr).
community_id:
type: ["string", "null"]
refresh_interval_sec:
type: ["integer", "null"]
CdnSourceCreate:
type: object
required:
- url
- source_kind
properties:
url:
type: string
format: uri
source_kind:
type: string
prefix_path:
type: string
community_id:
type: ["string", "null"]
CdnSourcePatch:
type: object
properties:
url:
type: string
format: uri
source_kind:
type: string
prefix_path:
type: string
community_id:
type: ["string", "null"]
refresh_interval_sec:
type: ["integer", "null"]
CdnPreviewRequest:
type: object
required: [url, source_kind]
properties:
url:
type: string
format: uri
source_kind:
type: string
prefix_path:
type: string
CdnPreviewResponse:
type: object
required: [items, total, truncated, source_url]
properties:
items:
type: array
items:
type: string
total:
type: integer
truncated:
type: boolean
source_url:
type: string
AsEntry:
type: object
required:
- id
- asn
properties:
id:
$ref: "#/components/schemas/ResourceId"
asn:
type: integer
minimum: 1
maximum: 4294967295
community_id:
type: ["string", "null"]
additionalProperties: true
AsEntryCreate:
type: object
required:
- asn
properties:
asn:
type: integer
minimum: 1
maximum: 4294967295
community_id:
type: ["string", "null"]
additionalProperties: true
AsEntryPatch:
type: object
properties:
asn:
type: integer
minimum: 1
maximum: 4294967295
community_id:
type: ["string", "null"]
additionalProperties: true
DomainEntry:
type: object
required:
- id
- fqdn
properties:
id:
$ref: "#/components/schemas/ResourceId"
fqdn:
type: string
community_id:
type: ["string", "null"]
DomainEntryCreate:
type: object
required:
- fqdn
properties:
fqdn:
type: string
community_id:
type: ["string", "null"]
IpRangeEntry:
type: object
required:
- id
- prefix
- community_id
properties:
id:
$ref: "#/components/schemas/ResourceId"
prefix:
type: string
description: IPv4/IPv6 CIDR.
example: 203.0.113.0/24
community_id:
$ref: "#/components/schemas/ResourceId"
IpRangeEntryCreate:
type: object
required:
- prefix
- community_id
properties:
prefix:
type: string
community_id:
$ref: "#/components/schemas/ResourceId"
DohProfile:
type: object
required:
- id
properties:
id:
$ref: "#/components/schemas/ResourceId"
name:
type: string
description: Отображаемое имя профиля (опционально).
url:
type: string
format: uri
timeout_ms:
type: integer
vault_secret_ref:
type: ["string", "null"]
description: Ссылка на секрет в vault; сырое значение не отдаётся в GET.
additionalProperties: true
DohProfileCreate:
type: object
required:
- url
properties:
name:
type: string
description: Отображаемое имя профиля (опционально).
url:
type: string
format: uri
timeout_ms:
type: integer
vault_secret_ref:
type: ["string", "null"]
AuthSession:
type: object
required: [tenant_id, kind]
properties:
tenant_id:
$ref: "#/components/schemas/ResourceId"
kind:
type: string
enum: [apikey, jwt]
description: apikey — Bearer API key; jwt — portal SSO token.
role:
type: string
description: >
API-key role (viewer|editor|operator|node). Empty string for portal JWT sessions.
user_id:
type: string
description: JWT sub (portal sessions only).
email:
type: string
description: JWT email claim (portal sessions only).
permissions:
type: array
items:
type: string
description: JWT permissions (bgp:*); portal sessions only.
is_admin:
type: boolean
description: Portal is_admin claim; grants all bgp permissions.
ApiKey:
type: object
required: [id, name, role, prefix, created_at, updated_at]
properties:
id:
$ref: "#/components/schemas/ResourceId"
name:
type: string
role:
type: string
enum: [viewer, editor, operator, node]
prefix:
type: string
description: Первые 8 символов токена для идентификации в UI.
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
expires_at:
type: ["string", "null"]
format: date-time
revoked_at:
type: ["string", "null"]
format: date-time
last_used_at:
type: ["string", "null"]
format: date-time
additionalProperties: true
ApiKeyCreate:
type: object
required: [name, role]
properties:
name:
type: string
role:
type: string
enum: [viewer, editor, operator, node]
expires_at:
type: ["string", "null"]
format: date-time
ApiKeyPatch:
type: object
properties:
name:
type: string
role:
type: string
enum: [viewer, editor, operator, node]
expires_at:
type: ["string", "null"]
format: date-time
ApiKeyCreated:
allOf:
- $ref: "#/components/schemas/ApiKey"
- type: object
required: [token]
properties:
token:
type: string
description: Полный Bearer-токен; показывается один раз.
BgpCommunity:
type: object
required:
- id
properties:
id:
$ref: "#/components/schemas/ResourceId"
community:
type: string
description: Техническое значение BGP community (строка для BIRD, например 65001:120 или large JSON в value_json).
title:
type: string
description: Человекочитаемое название для UI и фильтров.
additionalProperties: true
LookupQueryKind:
type: string
enum: [ip, domain, cidr]
description: Определённый тип запроса после нормализации.
LookupLayer:
type: string
enum: [entry, snapshot]
description: |
`entry` — сырые IP_RANGES / DOMAINS entries;
`snapshot` — материализованные префиксы `module_prefix_snapshot`.
LookupMatchKind:
type: string
enum: [ip_range, domain, prefix]
description: Вид совпадения (entry CIDR, entry FQDN или snapshot prefix).
LookupMatch:
type: object
required:
- layer
- module_id
- module_name
- module_type
- match_kind
- matched_value
properties:
layer:
$ref: "#/components/schemas/LookupLayer"
module_id:
$ref: "#/components/schemas/ResourceId"
module_name:
type: string
module_type:
$ref: "#/components/schemas/ModuleType"
match_kind:
$ref: "#/components/schemas/LookupMatchKind"
matched_value:
type: string
description: CIDR, FQDN или prefix, с которым совпал запрос.
entry_id:
type: string
description: ID entry (только для layer=entry).
source:
type: string
description: Источник строки snapshot (ip_range, domain, as, cdn, …).
community_id:
type: ["string", "null"]
community:
type: string
description: Техническое значение BGP community.
community_title:
type: string
description: Человекочитаемое название community.
resolved_ip:
type: string
description: |
IP, полученный DNS-resolve domain-запроса, из-за которого появился этот матч.
Пусто для прямого IP-запроса и для FQDN entry/snapshot без resolve.
LookupResponse:
type: object
required:
- query
- query_kind
- normalized
- matched
- match_count
- matches
properties:
query:
type: string
description: Исходная строка запроса.
query_kind:
$ref: "#/components/schemas/LookupQueryKind"
normalized:
type: string
description: Нормализованный IP, masked CIDR или FQDN.
matched:
type: boolean
description: true, если есть хотя бы одно совпадение.
match_count:
type: integer
minimum: 0
matches:
type: array
items:
$ref: "#/components/schemas/LookupMatch"
resolved_ips:
type: array
description: IP-адреса после live DNS resolve (только для query_kind=domain; A/AAAA).
items:
type: string
BgpPeer:
type: object
required:
- id
properties:
id:
$ref: "#/components/schemas/ResourceId"
neighbor:
type: string
description: IP соседа.
remote_asn:
type: integer
bgp_speaker_id:
type: ["string", "null"]
description: "`null` - политика для всех спикеров."
connected_speaker_id:
type: ["string", "null"]
description: >
Live (GET /v1/peers?live=1): спикер, на котором сессия Established; опрос CP birdc + agent /v1/agent/bird/protocols.
connected_speaker_label:
type: string
description: Человекочитаемая метка ноды из live-опроса.
session_on_speakers:
type: array
description: Состояние протокола пира на каждой опрошенной ноде.
items:
type: object
properties:
speaker_id:
type: string
label:
type: string
state:
type: string
established_on_speakers:
type: array
description: Ноды, где сессия в состоянии Established (один пир может быть на нескольких).
items:
type: object
properties:
speaker_id:
type: string
label:
type: string
state:
type: string
session_mismatch:
type: boolean
description: >
true если bgp_speaker_id задан, но на этой ноде нет Established
(сессия может быть на других нодах — это не ошибка для tenant-wide пиров).
policies_json:
type: string
description: >
JSON-объект (строка). Поля `local_ipv4`, `local_ipv6`, `local_asn` переопределяют
глобальные `bird_local_ipv4` / `bird_local_ipv6` / `bird_local_asn` тенанта.
Если эффективный локальный адрес или ASN пира отличается от дефолтов тенанта (`bird_local_*`),
в блок `protocol bgp … from bgp_template` добавляется строка `local … as …`.
additionalProperties: true
BgpSpeaker:
type: object
required:
- id
properties:
id:
$ref: "#/components/schemas/ResourceId"
role:
type: string
description: master, replica, canary и т.д.
endpoint:
type: string
last_applied_revision_id:
type: ["string", "null"]
published_revision_id:
type: ["string", "null"]
description: Последняя опубликованная на CP ревизия для этого спикера.
published_at:
type: ["string", "null"]
format: date-time
agent_domain:
type: string
description: FQDN agent API за Traefik (Address в UI, Remnawave-style).
node_ipv4:
type: string
description: IPv4 VPS; default для bird_bgp_source_ipv4.
bird_bgp_source_ipv4:
type: string
description: Per-speaker override router id / BGP local (см. pipeline overlay).
dispatch_status:
type: string
description: ok, error, skipped — последний Panel→Node wake-up.
sync_status:
type: string
description: synced, error — состояние sync на реплике.
last_dispatch_at:
type: string
format: date-time
last_dispatch_error:
type: string
meta_json:
type: object
description: >
Расширяемый объект. Ключи agent_domain, agent_secret (только при создании),
agent_port, node_ipv4, bird_bgp_source_ipv4, bird_bgp_source_ipv6.
live:
$ref: "#/components/schemas/SpeakerLiveStatus"
description: >
При GET /v1/speakers?live=1 — runtime-статус agent и BGP-опроса на ноде.
additionalProperties: true
SpeakerLiveStatus:
type: object
description: Live runtime snapshot for one speaker (GET /v1/speakers?live=1).
properties:
label:
type: string
description: Человекочитаемая метка ноды (agent domain или CP master).
agent_ok:
type: boolean
description: true если agent /v1/agent/health успешен (master — local birdc poll).
agent_error:
type: string
agent_last_sync_at:
type: string
format: date-time
agent_last_applied_revision_id:
type: string
bgp_poll_ok:
type: boolean
description: true если birdc (CP) или GET /v1/agent/bird/protocols (replica) успешен.
bgp_poll_error:
type: string
bgp_sessions_total:
type: integer
bgp_established:
type: integer
sessions:
type: array
items:
$ref: "#/components/schemas/BgpSessionLive"
additionalProperties: true
BgpSessionLive:
type: object
properties:
name:
type: string
neighbor:
type: string
neighbor_as:
type: integer
description: Remote ASN from birdc (`Neighbor AS:`).
neighbor_id:
type: string
description: BGP Identifier / Neighbor ID from birdc (`Neighbor ID:`).
state:
type: string
additionalProperties: true
LiveSpeakerPoll:
type: object
description: Метаданные опроса одной ноды в GET /v1/peers?live=1.
properties:
speaker_id:
type: string
label:
type: string
ok:
type: boolean
session_count:
type: integer
poll_error:
type: string
additionalProperties: true
PostgresOverview:
type: object
description: Instance-level PostgreSQL snapshot (GET /v1/monitoring/postgres/overview).
additionalProperties: true
PostgresQueriesResponse:
type: object
properties:
collected_at:
type: string
format: date-time
source:
type: string
enum: [live, snapshot]
items:
type: array
items:
type: object
additionalProperties: true
PostgresRecommendations:
type: object
properties:
collected_at:
type: string
format: date-time
items:
type: array
items:
type: object
properties:
severity:
type: string
code:
type: string
title:
type: string
detail:
type: string
refs:
type: array
items:
type: string
PostgresMaintenanceBody:
type: object
properties:
table:
type: string
dry_run:
type: boolean
default: false
policy:
type: string
description: Deprecated; use maintenance policies API.
limit:
type: integer
MaintenancePolicy:
type: object
required: [name, table_name, schedule, vacuum_strategy]
properties:
id:
$ref: "#/components/schemas/ResourceId"
name:
type: string
table_name:
type: string
condition:
type: string
default: "true"
retention_period_sec:
type: integer
minimum: 1
max_rows:
type: integer
minimum: 1
maximum: 100000
vacuum_strategy:
type: string
enum: [none, vacuum, analyze, vacuum_analyze, reindex]
schedule:
type: string
description: Cron expression (5-field, UTC).
enabled:
type: boolean
default: true
dry_run_enabled:
type: boolean
default: false
last_run_at:
type: string
format: date-time
last_status:
type: string
last_error:
type: string
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
MaintenancePolicyPatch:
type: object
properties:
name:
type: string
table_name:
type: string
condition:
type: string
retention_period_sec:
type: integer
max_rows:
type: integer
vacuum_strategy:
type: string
enum: [none, vacuum, analyze, vacuum_analyze, reindex]
schedule:
type: string
enabled:
type: boolean
dry_run_enabled:
type: boolean
MaintenanceRunBody:
type: object
required: [policy_id]
properties:
policy_id:
$ref: "#/components/schemas/ResourceId"
MaintenancePolicyList:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/MaintenancePolicy"
next_cursor:
type: string
has_more:
type: boolean
RuntimeLogCleanupMode:
type: string
enum: [truncate, delete]
description: |
truncate — обнулить файл (по умолчанию); delete — удалить файл с диска.
RuntimeLogFile:
type: object
required: [name, size_bytes, modified_at]
properties:
name:
type: string
description: Basename файла (*.log) в каталоге runtime-логов.
pattern: '^[a-z0-9][a-z0-9_.-]*\.log$'
size_bytes:
type: integer
format: int64
minimum: 0
modified_at:
type: string
format: date-time
RuntimeLogFileList:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: "#/components/schemas/RuntimeLogFile"
RuntimeLogTail:
type: object
required: [filename, content, truncated, lines_returned]
properties:
filename:
type: string
content:
type: string
description: UTF-8 текст хвоста файла.
truncated:
type: boolean
description: true если применён лимит bytes/lines.
lines_returned:
type: integer
minimum: 0
RuntimeLogCleanupResult:
type: object
required: [audit_id, filename, action, size_before]
properties:
audit_id:
$ref: "#/components/schemas/ResourceId"
filename:
type: string
action:
$ref: "#/components/schemas/RuntimeLogCleanupMode"
size_before:
type: integer
format: int64
size_after:
type: ["integer", "null"]
format: int64
RuntimeLogCleanupAudit:
type: object
required: [id, tenant_id, actor_prefix, filename, action, size_before, created_at]
properties:
id:
$ref: "#/components/schemas/ResourceId"
tenant_id:
$ref: "#/components/schemas/ResourceId"
actor_prefix:
type: string
filename:
type: string
action:
$ref: "#/components/schemas/RuntimeLogCleanupMode"
size_before:
type: integer
format: int64
size_after:
type: ["integer", "null"]
format: int64
detail:
type: object
additionalProperties: true
created_at:
type: string
format: date-time
RuntimeLogCleanupAuditList:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/RuntimeLogCleanupAudit"
next_cursor:
type: string
has_more:
type: boolean
AuditSeverity:
type: string
enum: [info, warning, critical]
AuditLogEntry:
type: object
required:
[id, tenant_id, event_id, source_app, action, severity, summary, created_at]
properties:
id:
$ref: "#/components/schemas/ResourceId"
tenant_id:
$ref: "#/components/schemas/ResourceId"
event_id:
type: string
description: Stable id for portal ingest deduplication (prefix bgp-).
source_app:
type: string
enum: [bgp]
action:
type: string
description: Machine action key (e.g. bgp.module.create).
severity:
$ref: "#/components/schemas/AuditSeverity"
actor_user_id:
type: ["string", "null"]
actor_email:
type: ["string", "null"]
actor_name:
type: ["string", "null"]
actor_api_key_prefix:
type: ["string", "null"]
target_type:
type: ["string", "null"]
enum: [app_resource, null]
target_id:
type: ["string", "null"]
summary:
type: string
details:
type: ["object", "null"]
additionalProperties: true
ip:
type: ["string", "null"]
created_at:
type: string
format: date-time
portal_pushed_at:
type: ["string", "null"]
format: date-time
AuditLogList:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: "#/components/schemas/AuditLogEntry"
next_cursor:
type: string
has_more:
type: boolean
RuntimeLogAutoPolicy:
type: object
properties:
enabled:
type: boolean
max_file_bytes:
type: integer
format: int64
schedule:
type: string
description: UTC cron (minute hour dom month dow).
mode:
$ref: "#/components/schemas/RuntimeLogCleanupMode"
RuntimeLogAutoEstimateItem:
type: object
required: [filename, size_bytes, would_cleanup]
properties:
filename:
type: string
size_bytes:
type: integer
format: int64
would_cleanup:
type: boolean
skip_reason:
type: string
description: under_threshold, too_large, или текст ошибки.
RuntimeLogAutoEstimate:
type: object
properties:
policy:
$ref: "#/components/schemas/RuntimeLogAutoPolicy"
items:
type: array
items:
$ref: "#/components/schemas/RuntimeLogAutoEstimateItem"
would_count:
type: integer
minimum: 0
RuntimeLogAutoRunResult:
type: object
additionalProperties: true
description: |
dry_run, trigger, policy, cleaned[], skipped[], cleaned_count, skipped_count.
BirdLocalStatus:
type: object
description: Статус локального BIRD на хосте API (GET /v1/bird/status).
properties:
birdc_configured:
type: boolean
message:
type: string
error:
type: string
protocols_excerpt:
type: string
bgp_sessions_total:
type: integer
bgp_established:
type: integer
healthy:
type: ["boolean", "null"]
additionalProperties: true
BundleSigningPublicKey:
type: object
required: [public_key_base64]
properties:
public_key_base64:
type: string
description: Ed25519 public key (base64) для verify-bundle на реплике.
ConfigRevision:
type: object
required:
- id
properties:
id:
$ref: "#/components/schemas/ResourceId"
parent_revision_id:
type: ["string", "null"]
content_hash:
type: string
created_at:
type: string
format: date-time
additionalProperties: true
RevisionPruneEstimate:
type: object
required:
- retention_minutes
- cutoff_at
- revision_count
- prefix_row_count
- orphan_snapshot_count
- bytes_estimate
properties:
retention_minutes:
type: integer
minimum: 15
maximum: 43200
cutoff_at:
type: string
format: date-time
revision_count:
type: integer
minimum: 0
prefix_row_count:
type: integer
minimum: 0
description: Строки prefix_snapshot_row в освобождаемых снимках.
orphan_snapshot_count:
type: integer
minimum: 0
bytes_estimate:
type: integer
format: int64
minimum: 0
description: Ориентировочный логический объём данных (байты).
RevisionPruneResult:
type: object
required:
- deleted_revisions
- deleted_prefix_snapshots
- deleted_prefix_rows
- bytes_estimate
properties:
deleted_revisions:
type: integer
minimum: 0
deleted_prefix_snapshots:
type: integer
minimum: 0
deleted_prefix_rows:
type: integer
minimum: 0
bytes_estimate:
type: integer
format: int64
minimum: 0
RevisionPruneRequest:
type: object
properties:
retention_minutes:
type: integer
minimum: 15
maximum: 43200
description: TTL в минутах; если не задан — из revision_retention_minutes tenant settings.
PrefixSnapshotItem:
type: object
description: >
Элемент материализованного снимка. Поле prefix обычно содержит CIDR;
для модулей AS_PREFIXES допускается ключ вида as:<номер_asn> (не CIDR).
additionalProperties: true
Job:
type: object
required:
- job_id
- kind
- status
- created_at
properties:
job_id:
$ref: "#/components/schemas/ResourceId"
kind:
type: string
status:
$ref: "#/components/schemas/JobStatus"
idempotency_key:
type: ["string", "null"]
created_at:
type: string
format: date-time
started_at:
type: ["string", "null"]
description: ISO 8601 UTC, если задача уже стартовала.
finished_at:
type: ["string", "null"]
description: ISO 8601 UTC по завершении.
error:
type: ["string", "null"]
meta:
type: object
additionalProperties: true
ApplyRequest:
type: object
properties:
revision_id:
$ref: "#/components/schemas/ResourceId"
strategy:
$ref: "#/components/schemas/ApplyStrategy"
dry_run:
type: boolean
default: false
VersionInfo:
type: object
properties:
version:
type: string
description: Semver сборки (git tag без префикса v).
example: "1.2.3"
api_version:
type: string
deprecated: true
description: Alias поля `version` (сохранён для обратной совместимости).
git_sha:
type: string
build_time:
type: string
format: date-time
additionalProperties: true
HealthStatus:
type: object
properties:
status:
type: string
example: ok
additionalProperties: true
ReadyStatus:
type: object
properties:
status:
type: string
example: ready
checks:
type: object
additionalProperties: true
additionalProperties: true
Settings:
type: object
description: |
KV настройки tenant/глобальные лимиты и feature flags.
Параметры BIRD (строки в `global_settings`, JSON-значения — обычно строка или число):
`bird_router_id`, `bird_local_ipv4`, `bird_local_ipv6`, `bird_local_asn`;
если задан `bird_bgp_source_ipv4`, он подставляется как BIRD `router id` (перекрывает `bird_router_id`).
Ключи `bird_bgp_source_ipv4` / `bird_bgp_source_ipv6` в сгенерированном BGP для пиров не используются (оставлены для совместимости API).
Шаблон BGP в конфиге: `local as <bird_local_asn>;` без локального IP.
properties:
bird_router_id:
type: string
description: BIRD `router id` (IPv4 dotted quad), если не задан `bird_bgp_source_ipv4`.
bird_local_ipv4:
type: string
bird_local_ipv6:
type: string
bird_local_asn:
type: integer
bird_bgp_source_ipv4:
type: string
description: |
Если задан — используется как BIRD `router id` (IPv4). В блоках `protocol bgp … from bgp_template` строка `source address` не генерируется.
bird_bgp_source_ipv6:
type: string
description: Зарезервировано; в текущей генерации BGP не используется.
revision_retention_minutes:
type: integer
minimum: 15
maximum: 43200
runtime_logs_auto_enabled:
type: boolean
description: Автоочистка *.log на evobgp-all по расписанию (только при FS volume).
runtime_logs_max_file_mb:
type: integer
minimum: 1
maximum: 512
description: Truncate/delete файлов строго больше порога (MiB).
runtime_logs_auto_schedule:
type: string
description: UTC cron для автоочистки (по умолчанию `0 */6 * * *`).
runtime_logs_auto_mode:
$ref: "#/components/schemas/RuntimeLogCleanupMode"
ui_show_quick_actions:
type: boolean
description: Показывать блок «Быстрые действия» на дашборде (UI preference).
default: true
additionalProperties: true
RevisionDiff:
type: object
description: |
Сравнение двух ревизий. Конкретный формат (JSON Patch, табличный diff и т.д.) задаётся реализацией - контракт может уточняться.
additionalProperties: true
NodeEnrollRequest:
type: object
description: Тело регистрации ноды; протокол обмена ключами уточняется отдельно.
properties:
public_key:
type: string
speaker_id:
$ref: "#/components/schemas/ResourceId"
additionalProperties: true
NodeEnrollResponse:
type: object
description: Подтверждение записи enrollment (метаданные спикера обновлены).
properties:
status:
type: string
example: enrolled
speaker_id:
$ref: "#/components/schemas/ResourceId"
tenant_id:
$ref: "#/components/schemas/ResourceId"
additionalProperties: true
DohProfilePatch:
type: object
properties:
name:
type: string
url:
type: string
format: uri
timeout_ms:
type: integer
vault_secret_ref:
type: ["string", "null"]
BgpCommunityCreate:
type: object
required: [community]
properties:
community:
type: string
title:
type: string
additionalProperties: true
BgpCommunityPatch:
type: object
properties:
community:
type: string
title:
type: string
additionalProperties: true
BgpPeerDiscovery:
type: object
required: [id, neighbor, status]
properties:
id:
$ref: "#/components/schemas/ResourceId"
speaker_id:
type: ["string", "null"]
neighbor_id:
type: string
description: BGP Identifier (Neighbor ID / router ID) from birdc.
neighbor:
type: string
description: Neighbor IP address.
remote_asn:
type: integer
protocol_name:
type: string
description: BIRD protocol name (evobgp_dyn_*).
session_state:
type: string
status:
type: string
enum: [pending, approved, rejected]
first_seen_at:
type: string
format: date-time
last_seen_at:
type: string
format: date-time
approved_peer_id:
type: ["string", "null"]
additionalProperties: true
BgpPeerDiscoveryApprove:
type: object
properties:
name:
type: string
bgp_speaker_id:
type: ["string", "null"]
enabled:
type: boolean
additionalProperties: false
BgpPeerCreate:
type: object
required: [neighbor, remote_asn]
properties:
neighbor:
type: string
remote_asn:
type: integer
bgp_speaker_id:
type: ["string", "null"]
additionalProperties: true
BgpPeerPatch:
type: object
properties:
neighbor:
type: string
remote_asn:
type: integer
bgp_speaker_id:
type: ["string", "null"]
additionalProperties: true
BgpSpeakerCreate:
type: object
required: [endpoint]
properties:
role:
type: string
default: replica
endpoint:
type: string
description: URL agent или https://AGENT_DOMAIN
meta_json:
oneOf:
- type: string
- type: object
description: >
JSON-объект (строка или object). Ключи node_ipv4, bird_bgp_source_ipv4
(default = node_ipv4), agent_domain, agent_secret (генерируется при создании если пуст).
letsencrypt_email:
type: string
description: Email ACME для Traefik на ноде. Только для генерации install.docker_commands, не сохраняется.
cf_dns_api_token:
type: string
description: Cloudflare DNS API token (Zone:DNS:Edit) для LE DNS-01. Только для install-сниппета, не сохраняется.
panel_ip_whitelist:
type: string
description: CIDR/IP панели для Traefik ipallowlist. Только для install-сниппета, не сохраняется.
control_plane_url:
type: string
format: uri
description: Публичный HTTPS URL панели (EVOBGP_CONTROL_PLANE_URL на реплике). Если пуст — из Origin / X-Forwarded-Host.
additionalProperties: true
SpeakerInstall:
type: object
description: Одноразовый пакет установки реплики (только POST /v1/speakers 201).
properties:
docker_commands:
type: string
description: >
Bash: sysctl, heredoc docker-compose.yaml (bird2 + agent + Traefik DNS-01) и docker compose up -d.
compose_yaml:
type: string
description: Тело docker-compose.yaml без heredoc (превью).
BgpSpeakerCreated:
allOf:
- $ref: "#/components/schemas/BgpSpeaker"
- type: object
properties:
agent_secret:
type: string
description: Bearer для Panel→Node (EVOBGP_AGENT_SECRET). Только в 201.
node_token:
type: string
description: API-ключ role=node (EVOBGP_NODE_TOKEN). Только в 201.
bundle_pubkey_base64:
type: string
description: Ed25519 pubkey для verify-bundle на ноде.
install:
$ref: "#/components/schemas/SpeakerInstall"
BgpSpeakerPatch:
type: object
properties:
role:
type: string
endpoint:
type: string
meta_json:
type: string
description: JSON-объект с ключами agent_domain, node_ipv4, bird_bgp_source_ipv4 и др.
additionalProperties: true
LatestRevisionPointer:
type: object
required:
- revision_id
properties:
revision_id:
$ref: "#/components/schemas/ResourceId"
published_at:
type: string
format: date-time
FirewallClient:
type: object
properties:
id:
$ref: "#/components/schemas/ResourceId"
name:
type: string
hostname:
type: string
token_prefix:
type: string
status:
type: string
enum: [pending, approved, revoked]
last_seen_at:
type: string
format: date-time
last_apply_at:
type: string
format: date-time
last_apply_status:
type: string
last_apply_prefix_count:
type: integer
last_apply_packets_dropped:
type: integer
format: int64
description: Cumulative packets dropped by blocklist rule (from client kernel counter).
last_apply_packets_accepted:
type: integer
format: int64
description: Cumulative packets accepted past blocklist chain (nft counter accept rule).
client_version:
type: string
FirewallInstallContext:
type: object
description: Контекст для one-liner установки firewall-клиента (только operator).
properties:
bundle_seed:
type: string
description: Значение EVOBGP_BUNDLE_SEED_HEX на control plane.
bundle_seed_configured:
type: boolean
suggested_cp_url:
type: string
format: uri
install_sh_url:
type: string
format: uri
FirewallRule:
type: object
properties:
id:
$ref: "#/components/schemas/ResourceId"
client_id:
$ref: "#/components/schemas/ResourceId"
nullable: true
priority:
type: integer
action:
type: string
enum: [block, accept]
community_id:
$ref: "#/components/schemas/ResourceId"
nullable: true
comment:
type: string
FirewallBlocklist:
type: object
properties:
client_id:
$ref: "#/components/schemas/ResourceId"
revision_id:
$ref: "#/components/schemas/ResourceId"
prefixes:
type: array
items:
type: string
total:
type: integer
hash:
type: string
paths:
/v1/health:
get:
tags: [System]
summary: Liveness
description: Проверка, что процесс API жив. Не обязана проверять БД или брокер.
operationId: getHealth
responses:
"200":
description: Процесс отвечает.
content:
application/json:
schema:
$ref: "#/components/schemas/HealthStatus"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/ready:
get:
tags: [System]
summary: Readiness
description: Готовность к трафику (БД, брокер сообщений при reference-архитектуре и т.д.).
operationId: getReady
responses:
"200":
description: Сервис готов принимать запросы.
content:
application/json:
schema:
$ref: "#/components/schemas/ReadyStatus"
"503":
description: Не готов (зависимости недоступны).
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
default:
$ref: "#/components/responses/DefaultProblem"
/version:
get:
tags: [System]
summary: Версия сборки (корневой путь)
description: |
Аналог `GET /v1/version`. Публичный маршрут без аутентификации.
Semver в поле `version` задаётся при сборке Docker-образов из git-тега.
operationId: getVersionRoot
responses:
"200":
description: Метаданные сборки.
content:
application/json:
schema:
$ref: "#/components/schemas/VersionInfo"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/version:
get:
tags: [System]
summary: Версия сборки
description: |
Semver control-plane и метаданные сборки (`git_sha`, `build_time`).
Дублирует `GET /version`.
operationId: getVersion
responses:
"200":
description: Метаданные сборки.
content:
application/json:
schema:
$ref: "#/components/schemas/VersionInfo"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules:
get:
tags: [Modules]
summary: Список модулей
description: Модули tenant с опциональными фильтрами по типу и флагу `enabled` (фильтры применяются сервером).
operationId: listModules
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/ModuleTypeFilter"
- $ref: "#/components/parameters/ModuleEnabledFilter"
responses:
"200":
description: Страница модулей.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/Module"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
"401":
$ref: "#/components/responses/Unauthorized"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/lookup:
get:
tags: [Lookup]
summary: Проверка IP, CIDR или домена в списках
description: |
Быстрая membership-проверка по tenant:
- **IP** — слой `entry` (`IP_RANGES`, `CIDR.Contains`) и слой `snapshot`
(все module prefix snapshots, `Prefix.Contains`);
- **CIDR** — слой `entry` (`IP_RANGES`, равенство masked-префикса или покрытие
запрошенной сети) и слой `snapshot` (то же правило);
- **Domain** — слой `entry` (нормализованный FQDN в `DOMAINS`) и слой `snapshot`
(префиксы `source=domain` у matched DOMAINS-модулей, если snapshot есть);
затем **live DNS resolve** (A/AAAA через системный резолвер) и проверка
каждого полученного IP так же, как для IP-запроса (ranges + все snapshots).
Community на матче: `entry.community_id || module.default_community_id` (entry)
или `PrefixRow.community_id` (snapshot), с join к справочнику communities.
Поля `resolved_ips` / `resolved_ip` заполняются только для domain-запросов
(после успешного DNS). Ошибка DNS не даёт 5xx: FQDN-слой всё равно возвращается.
operationId: lookupMembership
parameters:
- $ref: "#/components/parameters/TenantId"
- name: q
in: query
required: true
schema:
type: string
minLength: 1
maxLength: 253
description: IP-адрес, CIDR или FQDN для проверки.
responses:
"200":
description: Результат проверки (в т.ч. matched=false при отсутствии совпадений).
content:
application/json:
schema:
$ref: "#/components/schemas/LookupResponse"
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/router-lists/catalog:
get:
tags: [Modules]
summary: Агрегированный каталог для router-lists-ui
description: |
Возвращает в одном ответе:
- модули типов `DOMAINS`, `IP_RANGES`, `AS_PREFIXES`;
- entries по каждому модулю;
- справочник community (`id`, `community`, `title`).
operationId: getRouterListsCatalog
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Агрегированные данные для списков UI.
content:
application/json:
schema:
type: object
required: [modules, domains, asns, ip_ranges, communities]
properties:
modules:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: "#/components/schemas/Module"
domains:
type: object
required: [items]
properties:
items:
type: array
items:
type: object
required: [module_id, entry]
properties:
module_id:
$ref: "#/components/schemas/ResourceId"
entry:
$ref: "#/components/schemas/DomainEntry"
asns:
type: object
required: [items]
properties:
items:
type: array
items:
type: object
required: [module_id, entry]
properties:
module_id:
$ref: "#/components/schemas/ResourceId"
entry:
$ref: "#/components/schemas/AsEntry"
ip_ranges:
type: object
required: [items]
properties:
items:
type: array
items:
type: object
required: [module_id, entry]
properties:
module_id:
$ref: "#/components/schemas/ResourceId"
entry:
$ref: "#/components/schemas/IpRangeEntry"
communities:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: "#/components/schemas/BgpCommunity"
"401":
$ref: "#/components/responses/Unauthorized"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Modules]
summary: Создать модуль
description: |
Создаёт экземпляр модуля. Поле `type` задаёт вид (`AS_PREFIXES`, `CDN_CIDRS`, `DOMAINS`, `IP_RANGES`).
`module_id` в других путях - идентификатор экземпляра, не имя типа.
operationId: createModule
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ModuleCreate"
responses:
"201":
description: Модуль создан.
content:
application/json:
schema:
$ref: "#/components/schemas/Module"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
get:
tags: [Modules]
summary: Получить модуль
operationId: getModule
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/Module"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
patch:
tags: [Modules]
summary: Обновить модуль
description: Частичное обновление (расписание, DoH, приоритет, `enabled` и т.д.).
operationId: patchModule
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ModulePatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/Module"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Modules]
summary: Удалить модуль
description: Мягкое удаление или перевод в `enabled=false` - конкретное поведение задаётся реализацией.
operationId: deleteModule
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено или деактивировано.
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/cdn-sources:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
get:
tags: [Modules]
summary: Список CDN-источников
operationId: listCdnSources
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/CdnSource"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Modules]
summary: Добавить CDN-источник
description: URL, `source_kind`, опционально `community_id`.
operationId: createCdnSource
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CdnSourceCreate"
responses:
"201":
description: Ресурс создан.
content:
application/json:
schema:
$ref: "#/components/schemas/CdnSource"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/cdn-sources/{source_id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
- $ref: "#/components/parameters/SourceId"
patch:
tags: [Modules]
summary: Обновить CDN-источник
operationId: patchCdnSource
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CdnSourcePatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/CdnSource"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Modules]
summary: Удалить CDN-источник
operationId: deleteCdnSource
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено.
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/as-entries:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
get:
tags: [Modules]
summary: Список AS-записей
operationId: listAsEntries
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/AsEntry"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Modules]
summary: Добавить AS-запись
operationId: createAsEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AsEntryCreate"
responses:
"201":
description: Ресурс создан.
content:
application/json:
schema:
$ref: "#/components/schemas/AsEntry"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/as-entries/{entry_id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
- $ref: "#/components/parameters/EntryId"
patch:
tags: [Modules]
summary: Обновить AS-запись
operationId: patchAsEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AsEntryPatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/AsEntry"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Modules]
summary: Удалить AS-запись
operationId: deleteAsEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено.
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/domain-entries:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
get:
tags: [Modules]
summary: Список доменных записей
description: FQDN и привязка к community.
operationId: listDomainEntries
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/DomainEntry"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Modules]
summary: Добавить доменную запись
operationId: createDomainEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DomainEntryCreate"
responses:
"201":
description: Ресурс создан.
content:
application/json:
schema:
$ref: "#/components/schemas/DomainEntry"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/domain-entries/{entry_id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
- $ref: "#/components/parameters/EntryId"
patch:
tags: [Modules]
summary: Обновить доменную запись
operationId: patchDomainEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DomainEntryCreate"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/DomainEntry"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Modules]
summary: Удалить доменную запись
operationId: deleteDomainEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено.
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/ip-range-entries:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
get:
tags: [Modules]
summary: Список IP-диапазонов
description: "Только для модулей с типом IP_RANGES (статические CIDR и community_id)."
operationId: listIpRangeEntries
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/IpRangeEntry"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Modules]
summary: Добавить IP-диапазон
operationId: createIpRangeEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/IpRangeEntryCreate"
responses:
"201":
description: Ресурс создан.
content:
application/json:
schema:
$ref: "#/components/schemas/IpRangeEntry"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/ip-range-entries/{entry_id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
- $ref: "#/components/parameters/EntryId"
patch:
tags: [Modules]
summary: Обновить IP-диапазон
operationId: patchIpRangeEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/IpRangeEntryCreate"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/IpRangeEntry"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Modules]
summary: Удалить IP-диапазон
operationId: deleteIpRangeEntry
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено.
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/refresh:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
post:
tags: [Modules]
summary: Запустить ingest
description: |
Запуск обновления данных модуля (CDN / DoH / AS в зависимости от типа).
Итоговая ревизия и фрагменты BIRD строятся **по всем включённым модулям тенанта**:
обновляемый модуль пересчитывается заново, остальные — по текущему состоянию в БД/источниках,
так что префиксы ASN, CDN, IP и т.д. суммируются в одном конфиге.
Для `IP_RANGES` данные обычно только в БД: сервер может вернуть **204** (no-op) или **400**, если refresh не поддерживается - поведение фиксируется в реализации.
Рекомендуется передавать `Idempotency-Key`.
operationId: postModuleRefresh
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
description: Задача поставлена в очередь.
headers:
Location:
description: URL задачи `/v1/jobs/{job_id}`
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
"204":
description: Нет операции (например модуль `IP_RANGES` и no-op).
"400":
description: Тип модуля не поддерживает refresh.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/entries.csv:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
get:
tags: [Modules]
summary: Экспорт записей модуля в CSV
description: |
Доступно для типов модулей `AS_PREFIXES`, `DOMAINS`, `IP_RANGES`.
Возвращает CSV с колонками:
- AS: `asn,community`
- Домены: `domain,community`
- IP ranges: `ipRange,community`
operationId: exportModuleEntriesCsv
responses:
"200":
description: CSV-файл записей модуля.
content:
text/csv:
schema:
type: string
"404":
$ref: "#/components/responses/NotFound"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Modules]
summary: Импорт записей модуля из CSV
description: |
Импортирует CSV в модуль типов `AS_PREFIXES`, `DOMAINS`, `IP_RANGES`.
Поддерживаемые заголовки:
- `asn,community`
- `domain,community`
- `ipRange,community`
В поле `community` можно передавать либо ID community, либо её значение.
operationId: importModuleEntriesCsv
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
text/csv:
schema:
type: string
responses:
"200":
description: Импорт завершён.
content:
application/json:
schema:
type: object
required: [imported, module_type]
properties:
imported:
type: integer
minimum: 0
module_type:
type: string
"404":
$ref: "#/components/responses/NotFound"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/doh-profiles:
get:
tags: [DoH profiles]
summary: Список DoH-профилей
operationId: listDohProfiles
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/DohProfile"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [DoH profiles]
summary: Создать DoH-профиль
description: URL и таймауты; секрет - через vault id или отдельный вызов установки секрета.
operationId: createDohProfile
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DohProfileCreate"
responses:
"201":
description: Ресурс создан.
content:
application/json:
schema:
$ref: "#/components/schemas/DohProfile"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/modules/{module_id}/cdn-sources/preview:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ModuleId"
post:
tags: [Modules]
summary: Предпросмотр префиксов из CDN-источника
description: >
Синхронный запрос: conditional GET к URL (до 8 MiB тела ответа), парсинг plaintext или JSON,
возврат до 100 префиксов в `items` (полный счётчик в `total`). Выполняется в HTTP worker;
при таймауте клиента используйте короткий URL или меньший payload.
operationId: previewCdnSource
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CdnPreviewRequest"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/CdnPreviewResponse"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/doh-profiles/{id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/DohProfileId"
get:
tags: [DoH profiles]
summary: Получить DoH-профиль
description: Секрет в ответе не возвращается.
operationId: getDohProfile
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/DohProfile"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
patch:
tags: [DoH profiles]
summary: Обновить DoH-профиль
operationId: patchDohProfile
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DohProfilePatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/DohProfile"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [DoH profiles]
summary: Удалить DoH-профиль
description: Допустимо только если профиль не используется модулями.
operationId: deleteDohProfile
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено.
"409":
$ref: "#/components/responses/Conflict"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/communities:
get:
tags: [Communities]
summary: Список BGP community
operationId: listCommunities
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/BgpCommunity"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Communities]
summary: Создать community
operationId: createCommunity
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BgpCommunityCreate"
responses:
"201":
description: Ресурс создан.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpCommunity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/communities/{id}/prefixes:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/CommunityId"
- $ref: "#/components/parameters/Cursor"
- name: limit
in: query
schema:
type: integer
default: 500
maximum: 5000
get:
tags: [Communities]
summary: Префиксы community (latest revision per module)
description: |
Уникальные materialized-префиксы с данным community_id
из последней ревизии каждого модуля tenant.
Поле `prefixes` — плоский список для клиентов вроде EvoFirewall.
operationId: listCommunityPrefixes
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
type: object
required: [prefix]
properties:
prefix:
type: string
source:
type: string
prefixes:
type: array
items:
type: string
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/communities/{id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/CommunityId"
get:
tags: [Communities]
summary: Получить community
operationId: getCommunity
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpCommunity"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
patch:
tags: [Communities]
summary: Обновить community
operationId: patchCommunity
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BgpCommunityPatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpCommunity"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Communities]
summary: Удалить community
description: Только при отсутствии ссылок из других сущностей.
operationId: deleteCommunity
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено.
"409":
$ref: "#/components/responses/Conflict"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/peers:
get:
tags: [Peers]
summary: Список пиров
operationId: listPeers
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/SpeakerFilter"
- name: live
in: query
schema:
type: string
enum: ["1"]
description: >
Опрос birdc на CP и GET /v1/agent/bird/protocols на репликах; обогащает session_state и connected_speaker_*.
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/BgpPeer"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
live_speaker_poll:
type: array
description: >
При live=1 — результат опроса каждой ноды (CP birdc + agent protocols).
items:
$ref: "#/components/schemas/LiveSpeakerPoll"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Peers]
summary: Создать пира
description: >
Создаёт BGP-пира и инициирует быстрый reconcile пиров (job `peer_reconcile`) без module ingest.
После reconcile автоматически запускается apply на спикеры.
operationId: createPeer
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BgpPeerCreate"
responses:
"201":
description: Ресурс создан.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpPeer"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/peers/discovered:
get:
tags: [Peers]
summary: Список обнаруженных (неодобренных) пиров
description: >
Dynamic BGP-сессии (`evobgp_dyn_*`), которых ещё нет в `bgp_peer`.
По умолчанию возвращает `status=pending`. При листинге выполняет live-опрос birdc/agent и upsert pending.
operationId: listDiscoveredPeers
parameters:
- $ref: "#/components/parameters/TenantId"
- name: status
in: query
schema:
type: string
enum: [pending, approved, rejected, all]
default: pending
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items]
properties:
items:
type: array
items:
$ref: "#/components/schemas/BgpPeerDiscovery"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/peers/discovered/{id}/approve:
post:
tags: [Peers]
summary: Одобрить обнаруженного пира
description: >
Создаёт обычный `bgp_peer` из discovery-записи и запускает `peer_reconcile`.
operationId: approveDiscoveredPeer
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/PeerId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: false
content:
application/json:
schema:
$ref: "#/components/schemas/BgpPeerDiscoveryApprove"
responses:
"200":
description: Пир создан, discovery → approved.
content:
application/json:
schema:
type: object
properties:
peer:
$ref: "#/components/schemas/BgpPeer"
discovery:
$ref: "#/components/schemas/BgpPeerDiscovery"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/peers/discovered/{id}/reject:
post:
tags: [Peers]
summary: Отклонить обнаруженного пира
description: Помечает discovery как rejected; повторно не всплывает при sync.
operationId: rejectDiscoveredPeer
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/PeerId"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"200":
description: Discovery → rejected.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpPeerDiscovery"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/peers/{id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/PeerId"
get:
tags: [Peers]
summary: Получить пира
operationId: getPeer
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpPeer"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
patch:
tags: [Peers]
summary: Обновить пира
description: >
Политики (`policies_json`: `local_ipv4`, `local_ipv6`, `local_asn`), neighbor, ASN,
привязка к `bgp_speaker_id` или `null` для всех спикеров.
Изменение инициирует быстрый reconcile пиров (job `peer_reconcile`) без module ingest
и затем авто-apply на спикеры.
operationId: patchPeer
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BgpPeerPatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpPeer"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Peers]
summary: Удалить или отключить пира
description: >
Удаление/отключение инициирует быстрый reconcile пиров (job `peer_reconcile`) без module ingest
и затем авто-apply на спикеры.
operationId: deletePeer
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено / отключено.
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/bundle/signing-public-key:
get:
tags: [Bundles]
summary: Публичный ключ подписи бандлов
description: >
Ed25519 public key (base64) для `evobgp-node verify-bundle` / agent sync на реплике.
Роль viewer и выше.
operationId: getBundleSigningPublicKey
responses:
"200":
description: Ключ для env EVOBGP_BUNDLE_PUBKEY_BASE64 на реплике.
content:
application/json:
schema:
$ref: "#/components/schemas/BundleSigningPublicKey"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/speakers:
get:
tags: [Speakers]
summary: Список спикеров
description: Master / replica, endpoint и связанные поля.
operationId: listSpeakers
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: live
in: query
schema:
type: string
enum: ["1"]
description: >
Live-опрос agent /v1/agent/health и BGP protocols на репликах; CP — local birdc.
Обогащает каждый item полем `live`.
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/BgpSpeaker"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Speakers]
summary: Зарегистрировать спикер
description: >
Реплика или master. Для replica 201 содержит agent_secret, node_token и
install.docker_commands (bird2 + agent + Traefik LE DNS-01) — один раз.
operationId: createSpeaker
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BgpSpeakerCreate"
responses:
"201":
description: Ресурс создан. Для replica — одноразовый install-сниппет.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpSpeakerCreated"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/speakers/{id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/PeerId"
get:
tags: [Speakers]
summary: Получить спикер
description: В т.ч. `last_applied_revision_id`.
operationId: getSpeaker
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpSpeaker"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
patch:
tags: [Speakers]
summary: Обновить метаданные спикера
operationId: patchSpeaker
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/BgpSpeakerPatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/BgpSpeaker"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Speakers]
summary: Удалить спикер
description: >
Удаляет BGP-спикер. Пиры с `bgp_speaker_id` этого спикера остаются, привязка сбрасывается (ON DELETE SET NULL).
operationId: deleteSpeaker
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Удалено.
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/revisions:
get:
tags: [Revisions]
summary: История ревизий
operationId: listRevisions
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/RevisionModuleFilter"
responses:
"200":
description: Список ревизий с cursor-пагинацией; опциональный фильтр `module_id`.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/ConfigRevision"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
default:
$ref: "#/components/responses/DefaultProblem"
/v1/revisions/prune-estimate:
get:
tags: [Revisions]
summary: Оценка очистки ревизий по retention
description: >
Считает ревизии и ориентировочный объём данных, которые будут удалены при prune
(те же правила, что applyRevisionRetention: последняя ревизия tenant и раскатанные на спикерах сохраняются).
operationId: getRevisionPruneEstimate
parameters:
- $ref: "#/components/parameters/TenantId"
- name: retention_minutes
in: query
required: false
schema:
type: integer
minimum: 15
maximum: 43200
description: TTL в минутах; если не задан — из tenant settings (default 30d).
responses:
"200":
description: Оценка.
content:
application/json:
schema:
$ref: "#/components/schemas/RevisionPruneEstimate"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/revisions/prune:
post:
tags: [Revisions]
summary: Очистить старые ревизии (синхронно)
description: >
Удаляет ревизии старше cutoff по retention и GC неиспользуемых prefix_snapshot.
Operator-only.
operationId: pruneRevisions
parameters:
- $ref: "#/components/parameters/TenantId"
requestBody:
required: false
content:
application/json:
schema:
$ref: "#/components/schemas/RevisionPruneRequest"
responses:
"200":
description: Результат очистки.
content:
application/json:
schema:
$ref: "#/components/schemas/RevisionPruneResult"
"403":
$ref: "#/components/responses/Forbidden"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/revisions/{revision_id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/RevisionId"
get:
tags: [Revisions]
summary: Метаданные ревизии
description: Хэш, родитель, время, артефакты.
operationId: getRevision
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/ConfigRevision"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/revisions/{revision_id}/prefixes:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/RevisionId"
get:
tags: [Revisions]
summary: Снимок префиксов ревизии
operationId: getRevisionPrefixes
parameters:
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/PrefixSnapshotItem"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/revisions/{revision_id}/preview:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/RevisionId"
get:
tags: [Revisions]
summary: Превью фрагментов BIRD
description: Только чтение, без apply.
operationId: getRevisionPreview
responses:
"200":
description: Текст или структурированное представление - формат задаётся реализацией.
content:
application/json:
schema:
type: object
additionalProperties: true
text/plain:
schema:
type: string
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/revisions/{revision_id}/rollback:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/RevisionId"
post:
tags: [Revisions]
summary: Откат через новую ревизию
description: |
Создаёт **новую** ревизию с содержимым отката от указанной. Часто возвращает **202** с `Location` на задачу.
Рекомендуется `Idempotency-Key`.
operationId: postRevisionRollback
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
description: Откат поставлен в очередь.
headers:
Location:
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/revisions/{revision_a}/diff/{revision_b}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/RevisionA"
- $ref: "#/components/parameters/RevisionB"
get:
tags: [Revisions]
summary: Сравнить две ревизии
description: Формат diff (JSON Patch, табличный и т.д.) определяется реализацией.
operationId: getRevisionDiff
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/RevisionDiff"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/apply:
post:
tags: [Deploy]
summary: Применить конфигурацию
description: |
Применить целевую ревизию на спикерах (политика по умолчанию или из тела).
Ответ **202** с `Location` на `/v1/jobs/{job_id}`. **Рекомендуется или обязателен** `Idempotency-Key` по политике продукта.
operationId: postApply
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: false
content:
application/json:
schema:
$ref: "#/components/schemas/ApplyRequest"
responses:
"202":
description: Запрос принят, задача поставлена в очередь.
headers:
Location:
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/speakers/{id}/apply:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/PeerId"
post:
tags: [Deploy]
summary: Применить на одном спикере
description: Canary / точечный deploy. **202** + `Location` на job.
operationId: postSpeakerApply
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: false
content:
application/json:
schema:
$ref: "#/components/schemas/ApplyRequest"
responses:
"202":
description: Запрос принят, задача поставлена в очередь.
headers:
Location:
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/bird/status:
get:
tags: [Deploy]
summary: Статус локального BIRD на хосте API
description: >
Опрос birdc через EVOBGP_BIRDC_SOCKET на процессе API (обычно CP master).
На репликах без birdc на CP — birdc_configured=false.
operationId: getBirdStatus
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/BirdLocalStatus"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/bird/reload:
post:
tags: [Deploy]
summary: Мягкий reload BIRD
description: Опциональный явный reload политики, если отделён от apply; иначе может отсутствовать или быть частью apply.
operationId: postBirdReload
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
description: Задача reload поставлена (если реализовано как async).
headers:
Location:
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
"204":
description: Reload выполнен синхронно (если так реализовано).
"501":
description: Эндпоинт не используется в данной сборке.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/jobs:
get:
tags: [Jobs]
summary: Список задач
operationId: listJobs
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/JobStatusFilter"
- $ref: "#/components/parameters/JobKindFilter"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/Job"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
default:
$ref: "#/components/responses/DefaultProblem"
/v1/jobs/{job_id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/JobId"
get:
tags: [Jobs]
summary: Статус задачи
description: Прогресс, ошибка, связанные сущности в `meta`.
operationId: getJob
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/Job"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/jobs/{job_id}/cancel:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/JobId"
post:
tags: [Jobs]
summary: Запросить отмену задачи
description: Best-effort; гарантии зависят от вида задачи.
operationId: postJobCancel
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"202":
description: Запрос отмены принят.
content:
application/json:
schema:
$ref: "#/components/schemas/Job"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/speakers/{speaker_id}/revisions/latest:
parameters:
- $ref: "#/components/parameters/SpeakerId"
get:
tags: [Node]
summary: Последняя опубликованная ревизия для ноды
description: Вызывается **evobgp-node** с ключом роли `node`.
operationId: getSpeakerLatestRevision
security:
- bearerAuth: []
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/LatestRevisionPointer"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/speakers/{speaker_id}/bundle/{revision_id}:
parameters:
- $ref: "#/components/parameters/SpeakerId"
- $ref: "#/components/parameters/RevisionId"
get:
tags: [Node]
summary: Скачать подписанный бандл
description: |
Архив с `manifest.json` и подписью (например Ed25519). Целостность по SHA-256 в манифесте.
`Content-Type` - `application/octet-stream` или multipart; детали - в реализации.
operationId: getSpeakerBundle
security:
- bearerAuth: []
responses:
"200":
description: Бинарное тело бандла.
headers:
Content-Disposition:
schema:
type: string
content:
application/octet-stream:
schema:
type: string
format: binary
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/nodes/enroll:
post:
tags: [Node]
summary: Регистрация ноды
description: Обмен ключами и привязка к `speaker_id`; детали протокола уточняются отдельно.
operationId: postNodeEnroll
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NodeEnrollRequest"
responses:
"200":
description: Enrollment записан (node_public_key и время в meta спикера при наличии ключа).
content:
application/json:
schema:
$ref: "#/components/schemas/NodeEnrollResponse"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/auth/session:
get:
tags: [Auth]
summary: Текущая сессия API-ключа
operationId: getAuthSession
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/AuthSession"
"401":
$ref: "#/components/responses/Unauthorized"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/api-keys:
get:
tags: [API keys]
summary: Список API-ключей tenant
description: Только роль **operator**. Секреты не возвращаются.
operationId: listApiKeys
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
required: [items, has_more]
properties:
items:
type: array
items:
$ref: "#/components/schemas/ApiKey"
next_cursor:
type: ["string", "null"]
has_more:
type: boolean
"403":
$ref: "#/components/responses/Forbidden"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [API keys]
summary: Создать API-ключ
operationId: createApiKey
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKeyCreate"
responses:
"201":
description: Ключ создан; token в ответе один раз.
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKeyCreated"
"403":
$ref: "#/components/responses/Forbidden"
"422":
$ref: "#/components/responses/UnprocessableEntity"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/api-keys/{id}:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ApiKeyId"
get:
tags: [API keys]
summary: Получить метаданные API-ключа
operationId: getApiKey
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKey"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
patch:
tags: [API keys]
summary: Обновить API-ключ
operationId: patchApiKey
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKeyPatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKey"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [API keys]
summary: Отозвать API-ключ
operationId: revokeApiKey
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"204":
description: Отозван.
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/api-keys/{id}/rotate:
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/ApiKeyId"
post:
tags: [API keys]
summary: Ротировать секрет API-ключа
description: Выдаёт новый token; старый перестаёт работать сразу.
operationId: rotateApiKey
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKeyCreated"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/monitoring/postgres/overview:
get:
tags: [Monitoring]
summary: PostgreSQL overview (instance-level)
operationId: getPostgresOverview
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/PostgresOverview"
"503":
description: PostgreSQL backend не подключён.
default:
$ref: "#/components/responses/DefaultProblem"
/v1/monitoring/postgres/queries:
get:
tags: [Monitoring]
summary: Top queries (pg_stat_statements or snapshot)
operationId: getPostgresQueries
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/PostgresQueriesResponse"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/monitoring/postgres/locks:
get:
tags: [Monitoring]
summary: Active locks
operationId: getPostgresLocks
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
type: object
additionalProperties: true
default:
$ref: "#/components/responses/DefaultProblem"
/v1/monitoring/postgres/tables:
get:
tags: [Monitoring]
summary: Table sizes and scan stats
operationId: getPostgresTables
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
type: object
additionalProperties: true
default:
$ref: "#/components/responses/DefaultProblem"
/v1/monitoring/postgres/recommendations:
get:
tags: [Monitoring]
summary: Heuristic optimization recommendations
operationId: getPostgresRecommendations
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/PostgresRecommendations"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/monitoring/correlation:
get:
tags: [Monitoring]
summary: Timeline correlation (jobs vs cache hit)
operationId: getMonitoringCorrelation
parameters:
- $ref: "#/components/parameters/TenantId"
- name: window
in: query
schema:
type: integer
default: 60
description: Window in minutes (max 1440).
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
additionalProperties: true
default:
$ref: "#/components/responses/DefaultProblem"
/v1/postgres/vacuum:
post:
tags: [Monitoring]
summary: VACUUM (async job, operator)
operationId: postPostgresVacuum
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/PostgresMaintenanceBody"
responses:
"202":
description: Задача поставлена.
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
"403":
$ref: "#/components/responses/Forbidden"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/postgres/vacuum-analyze:
post:
tags: [Monitoring]
summary: VACUUM ANALYZE (async job, operator)
operationId: postPostgresVacuumAnalyze
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/PostgresMaintenanceBody"
responses:
"202":
description: Задача поставлена.
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/postgres/analyze:
post:
tags: [Monitoring]
summary: ANALYZE (async job, operator)
operationId: postPostgresAnalyze
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/PostgresMaintenanceBody"
responses:
"202":
description: Задача поставлена.
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/postgres/reindex:
post:
tags: [Monitoring]
summary: REINDEX TABLE (async job, operator)
operationId: postPostgresReindex
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/PostgresMaintenanceBody"
responses:
"202":
description: Задача поставлена.
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/postgres/cleanup:
post:
tags: [Monitoring]
summary: Retention cleanup (async job, operator)
operationId: postPostgresCleanup
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostgresMaintenanceBody"
responses:
"202":
description: Задача поставлена.
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/postgres/maintenance/logs:
get:
tags: [Monitoring]
summary: Maintenance audit log
operationId: listPostgresMaintenanceLogs
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
type: object
additionalProperties: true
next_cursor:
type: string
has_more:
type: boolean
default:
$ref: "#/components/responses/DefaultProblem"
/v1/maintenance/policies:
get:
tags: [Maintenance]
summary: List maintenance policies
operationId: listMaintenancePolicies
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenancePolicyList"
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Maintenance]
summary: Create maintenance policy
operationId: createMaintenancePolicy
parameters:
- $ref: "#/components/parameters/TenantId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenancePolicy"
responses:
"201":
description: Создано.
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenancePolicy"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/maintenance/policies/{id}:
get:
tags: [Maintenance]
summary: Get maintenance policy
operationId: getMaintenancePolicy
parameters:
- $ref: "#/components/parameters/TenantId"
- name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenancePolicy"
default:
$ref: "#/components/responses/DefaultProblem"
patch:
tags: [Maintenance]
summary: Update maintenance policy
operationId: patchMaintenancePolicy
parameters:
- $ref: "#/components/parameters/TenantId"
- name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenancePolicyPatch"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenancePolicy"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [Maintenance]
summary: Delete maintenance policy
operationId: deleteMaintenancePolicy
parameters:
- $ref: "#/components/parameters/TenantId"
- name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
responses:
"204":
description: Удалено.
default:
$ref: "#/components/responses/DefaultProblem"
/v1/maintenance/policies/{id}/hints:
get:
tags: [Maintenance]
summary: PostgreSQL hints for policy table
operationId: getMaintenancePolicyHints
parameters:
- $ref: "#/components/parameters/TenantId"
- name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
additionalProperties: true
default:
$ref: "#/components/responses/DefaultProblem"
/v1/maintenance/config-audit:
get:
tags: [Maintenance]
summary: Maintenance policy configuration audit log
operationId: listMaintenanceConfigAudit
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
type: object
additionalProperties: true
next_cursor:
type: string
has_more:
type: boolean
default:
$ref: "#/components/responses/DefaultProblem"
/v1/maintenance/run:
post:
tags: [Maintenance]
summary: Run maintenance policy (async job)
operationId: postMaintenanceRun
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenanceRunBody"
responses:
"202":
description: Задача поставлена.
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/maintenance/dry-run:
post:
tags: [Maintenance]
summary: Dry-run maintenance policy (async job)
operationId: postMaintenanceDryRun
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MaintenanceRunBody"
responses:
"202":
description: Задача поставлена.
content:
application/json:
schema:
$ref: "#/components/schemas/AsyncJobAccepted"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/runtime-logs/files:
get:
tags: [RuntimeLogs]
summary: Список runtime log-файлов
description: |
Список *.log в EVOBGP_RUNTIME_LOGS_DIR (размер и mtime).
Требуется evobgp-all с примонтированным volume.
operationId: listRuntimeLogFiles
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/RuntimeLogFileList"
"503":
description: Runtime logs недоступны (не evobgp-all или каталог не настроен).
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/runtime-logs/files/{filename}:
get:
tags: [RuntimeLogs]
summary: Хвост runtime log-файла
operationId: getRuntimeLogTail
parameters:
- $ref: "#/components/parameters/TenantId"
- name: filename
in: path
required: true
schema:
type: string
pattern: '^[a-z0-9][a-z0-9_.-]*\.log$'
description: Basename файла (без пути).
- name: lines
in: query
schema:
type: integer
minimum: 1
maximum: 2000
default: 200
- name: bytes
in: query
schema:
type: integer
minimum: 1
maximum: 262144
description: Альтернатива lines; при указании обоих — более строгий лимит.
- name: grep
in: query
schema:
type: string
maxLength: 128
description: Опциональный подстрочный фильтр (после чтения хвоста).
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/RuntimeLogTail"
"404":
$ref: "#/components/responses/NotFound"
"503":
description: Runtime logs недоступны.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
default:
$ref: "#/components/responses/DefaultProblem"
delete:
tags: [RuntimeLogs]
summary: Очистить runtime log-файл
description: |
Синхронная очистка (truncate по умолчанию или delete). Запись в cleanup audit.
Максимальный размер файла для очистки — 512 MiB. Только operator+.
operationId: deleteRuntimeLogFile
parameters:
- $ref: "#/components/parameters/TenantId"
- name: filename
in: path
required: true
schema:
type: string
pattern: '^[a-z0-9][a-z0-9_.-]*\.log$'
- name: mode
in: query
schema:
$ref: "#/components/schemas/RuntimeLogCleanupMode"
description: По умолчанию truncate.
responses:
"200":
description: Файл очищен.
content:
application/json:
schema:
$ref: "#/components/schemas/RuntimeLogCleanupResult"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"413":
description: Файл превышает лимит 512 MiB.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
"503":
description: Runtime logs недоступны.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/runtime-logs/auto-estimate:
get:
tags: [RuntimeLogs]
summary: Оценка автоочистки runtime log-файлов
description: |
Список файлов, которые будут затронуты текущей политикой tenant settings.
Требует evobgp-all с примонтированным каталогом runtime-logs.
operationId: estimateRuntimeLogAutoCleanup
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/RuntimeLogAutoEstimate"
"503":
description: FS API недоступен (не evobgp-all или нет volume).
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/runtime-logs/auto-run:
post:
tags: [RuntimeLogs]
summary: Запустить автоочистку runtime log-файлов
description: |
Немедленный прогон политики из tenant settings. `dry_run=true` — только оценка без FS-изменений.
Записи audit с `actor_prefix=auto:scheduler`.
operationId: runRuntimeLogAutoCleanup
parameters:
- $ref: "#/components/parameters/TenantId"
- name: dry_run
in: query
schema:
type: boolean
default: false
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/RuntimeLogAutoRunResult"
"503":
description: FS API недоступен.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/Problem"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/runtime-logs/cleanup-audit:
get:
tags: [RuntimeLogs]
summary: Audit очистки runtime log-файлов
operationId: listRuntimeLogCleanupAudit
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/RuntimeLogCleanupAuditList"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/audit:
get:
tags: [Audit]
summary: Журнал CRUD audit tenant
description: |
Локальный журнал изменений (modules, peers, settings, API keys и т.д.).
При настроенных `AUTH_PORTAL_URL` + `AUTH_AUDIT_INGEST_SECRET` события также
отправляются в auth-portal ingest (`source_app=bgp`).
operationId: listAuditLog
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/Cursor"
- $ref: "#/components/parameters/Limit"
- name: action
in: query
schema:
type: string
description: Filter by action prefix/key (exact match).
- name: severity
in: query
schema:
$ref: "#/components/schemas/AuditSeverity"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/AuditLogList"
"400":
$ref: "#/components/responses/BadRequest"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/settings:
get:
tags: [Settings]
summary: Получить настройки
description: KV (лимиты CDN, feature flags и т.д.).
operationId: getSettings
parameters:
- $ref: "#/components/parameters/TenantId"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/Settings"
default:
$ref: "#/components/responses/DefaultProblem"
patch:
tags: [Settings]
summary: Частично обновить настройки
description: Только роль **operator**.
operationId: patchSettings
parameters:
- $ref: "#/components/parameters/TenantId"
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Settings"
responses:
"200":
description: Успешно.
content:
application/json:
schema:
$ref: "#/components/schemas/Settings"
"403":
$ref: "#/components/responses/Forbidden"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/firewall/install-context:
get:
tags: [Firewall]
summary: Install context for firewall one-liner (operator)
operationId: getFirewallInstallContext
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/FirewallInstallContext"
"403":
$ref: "#/components/responses/Forbidden"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/firewall/enroll:
post:
tags: [Firewall]
summary: Enroll firewall client (public, X-EvoBGP-Seed)
security: []
operationId: firewallEnroll
parameters:
- name: X-EvoBGP-Seed
in: header
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, client_token]
properties:
name:
type: string
hostname:
type: string
client_token:
type: string
client_version:
type: string
responses:
"201":
description: Client created (pending).
default:
$ref: "#/components/responses/DefaultProblem"
/v1/firewall/clients:
get:
tags: [Firewall]
summary: List firewall clients
operationId: listFirewallClients
responses:
"200":
description: OK
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: "#/components/schemas/FirewallClient"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/firewall/clients/{id}/approve:
post:
tags: [Firewall]
summary: Approve pending client
operationId: approveFirewallClient
parameters:
- name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
responses:
"200":
description: Approved
content:
application/json:
schema:
$ref: "#/components/schemas/FirewallClient"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/firewall/clients/{id}/revoke:
post:
tags: [Firewall]
summary: Reject pending or revoke approved client
operationId: revokeFirewallClient
parameters:
- name: id
in: path
required: true
schema:
$ref: "#/components/schemas/ResourceId"
responses:
"200":
description: Revoked
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: [revoked]
default:
$ref: "#/components/responses/DefaultProblem"
/v1/firewall/rules:
get:
tags: [Firewall]
summary: List firewall rules
operationId: listFirewallRules
parameters:
- name: scope
in: query
schema:
type: string
enum: [tenant, client]
- name: client_id
in: query
schema:
$ref: "#/components/schemas/ResourceId"
responses:
"200":
description: OK
default:
$ref: "#/components/responses/DefaultProblem"
post:
tags: [Firewall]
summary: Create firewall rule
operationId: createFirewallRule
responses:
"201":
description: Created
default:
$ref: "#/components/responses/DefaultProblem"
/v1/firewall/blocklist:
get:
tags: [Firewall]
summary: Get evaluated blocklist (firewall client token)
operationId: getFirewallBlocklist
responses:
"200":
description: Blocklist
content:
application/json:
schema:
$ref: "#/components/schemas/FirewallBlocklist"
default:
$ref: "#/components/responses/DefaultProblem"
/v1/firewall/apply-report:
post:
tags: [Firewall]
summary: Report last apply status
operationId: firewallApplyReport
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: string
error:
type: string
prefix_count:
type: integer
ip_count:
type: integer
packets_dropped:
type: integer
format: int64
packets_accepted:
type: integer
format: int64
kernel_method:
type: string
source:
type: string
responses:
"200":
description: OK
default:
$ref: "#/components/responses/DefaultProblem"