CI / changes (push) Successful in 9s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 24s
CI / web (push) Successful in 29s
CI / go (push) Successful in 43s
CI / bird2 (push) Successful in 15s
CI / release (push) Successful in 3m29s
- Introduced new schemas for `SpeakerLiveStatus`, `BgpSessionLive`, and `LiveSpeakerPoll` in OpenAPI documentation to support live status queries. - Enhanced the `/v1/speakers` endpoint to include a `live` query parameter, allowing retrieval of real-time speaker and BGP status. - Updated the HTTP API to collect and return live status data for speakers, improving monitoring capabilities. - Modified frontend components to display live status information, enhancing user visibility into speaker health and BGP session states. - Added a new endpoint `/v1/bird/status` for retrieving the local BIRD status, further enriching the network monitoring features.
3180 lines
102 KiB
YAML
3180 lines
102 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 и роль).
|
||
|
||
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
|
||
|
||
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
|
||
|
||
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 не используется.
|
||
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
|
||
|
||
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/{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/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"
|