CI / changes (push) Successful in 11s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 29s
CI / web (push) Successful in 1m6s
CI / go (push) Successful in 1m23s
CI / bird2 (push) Successful in 17s
CI / release (push) Successful in 4m42s
Enhanced the firewall client functionality by introducing packet statistics tracking, including the cumulative count of packets dropped and accepted. Updated the API to support these new fields and modified the database schema accordingly. Improved the firewall scripts to collect and report packet statistics, ensuring better visibility into client performance. Adjusted the UI components to display packet counts in the clients table, enhancing user experience and monitoring capabilities.
4588 lines
144 KiB
YAML
4588 lines
144 KiB
YAML
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`.
|
||
|
||
**Роли** (матрица доступа): `viewer`, `editor`, `operator`, `node`. Нода использует отдельные пути и ключ с ролью `node`.
|
||
|
||
Заголовок `X-Tenant-Id` допускается только для супер-ролей (явный tenant); иначе tenant берётся из API-ключа.
|
||
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: 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: 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"
|
||
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, role]
|
||
properties:
|
||
tenant_id:
|
||
$ref: "#/components/schemas/ResourceId"
|
||
role:
|
||
type: string
|
||
enum: [viewer, editor, operator, node]
|
||
|
||
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
|
||
|
||
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
|
||
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
|
||
|
||
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"
|
||
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
|
||
|
||
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:
|
||
type: string
|
||
description: >
|
||
JSON-объект. Ключи node_ipv4, bird_bgp_source_ipv4 (default = node_ipv4),
|
||
agent_domain, agent_secret (генерируется при создании если пуст).
|
||
additionalProperties: true
|
||
|
||
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/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}:
|
||
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/{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: Реплика, canary и т.д.
|
||
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: Ресурс создан.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: "#/components/schemas/BgpSpeaker"
|
||
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/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"
|