CI / changes (push) Successful in 6s
CI / openapi (push) Successful in 27s
CI / go (push) Successful in 26s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Has been skipped
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Has been skipped
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Successful in 16s
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Successful in 1m4s
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Successful in 1m29s
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Successful in 1m28s
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Successful in 1m25s
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Has been cancelled
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Has been cancelled
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Has been cancelled
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Has been cancelled
2373 lines
74 KiB
YAML
2373 lines
74 KiB
YAML
openapi: 3.1.0
|
||
info:
|
||
title: EvoBGP Control Plane API
|
||
version: 0.1.0
|
||
description: |
|
||
REST API управления префиксами, модулями ingest, ревизиями конфигурации BIRD и задачами (async jobs).
|
||
|
||
**Соглашения:** префикс `/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.
|
||
|
||
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 определяется по ключу.
|
||
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"
|
||
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: Фильтр по виду задачи; точный перечень расширяем.
|
||
|
||
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
|
||
|
||
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"]
|
||
refresh_interval_sec:
|
||
type: ["integer", "null"]
|
||
minimum: 0
|
||
cron_expr:
|
||
type: ["string", "null"]
|
||
default_community_id:
|
||
type: ["string", "null"]
|
||
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"]
|
||
refresh_interval_sec:
|
||
type: ["integer", "null"]
|
||
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"]
|
||
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: Формат скачанного списка / парсер.
|
||
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
|
||
community_id:
|
||
type: ["string", "null"]
|
||
|
||
CdnSourcePatch:
|
||
type: object
|
||
properties:
|
||
url:
|
||
type: string
|
||
format: uri
|
||
source_kind:
|
||
type: string
|
||
community_id:
|
||
type: ["string", "null"]
|
||
refresh_interval_sec:
|
||
type: ["integer", "null"]
|
||
|
||
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"
|
||
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:
|
||
url:
|
||
type: string
|
||
format: uri
|
||
timeout_ms:
|
||
type: integer
|
||
vault_secret_ref:
|
||
type: ["string", "null"]
|
||
|
||
BgpCommunity:
|
||
type: object
|
||
required:
|
||
- id
|
||
properties:
|
||
id:
|
||
$ref: "#/components/schemas/ResourceId"
|
||
name:
|
||
type: string
|
||
kind:
|
||
type: string
|
||
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` - политика для всех спикеров."
|
||
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"]
|
||
additionalProperties: true
|
||
|
||
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:
|
||
api_version:
|
||
type: string
|
||
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_bgp_source_ipv6` — для `source address` у BGP-пиров (если не заданы — эффективный `bird_local_ipv4` / политика пира).
|
||
Если задан `bird_bgp_source_ipv4`, он же подставляется как BIRD `router id` (перекрывает `bird_router_id`).
|
||
Шаблон 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: |
|
||
Исходящий IPv4 для `source address` у пиров; также задаёт `router id`, если указан.
|
||
На стороне MikroTik в BGP Connection поле **Remote address** должно совпадать с этим адресом (или с тем, с которого реально устанавливается TCP-сессия к 179/tcp), иначе сессия не поднимется.
|
||
bird_bgp_source_ipv6:
|
||
type: string
|
||
description: Исходящий IPv6 для `source address` у пиров IPv6.
|
||
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:
|
||
url:
|
||
type: string
|
||
format: uri
|
||
timeout_ms:
|
||
type: integer
|
||
vault_secret_ref:
|
||
type: ["string", "null"]
|
||
|
||
BgpCommunityCreate:
|
||
type: object
|
||
required: [name]
|
||
properties:
|
||
name:
|
||
type: string
|
||
kind:
|
||
type: string
|
||
additionalProperties: true
|
||
|
||
BgpCommunityPatch:
|
||
type: object
|
||
properties:
|
||
name:
|
||
type: string
|
||
kind:
|
||
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
|
||
endpoint:
|
||
type: string
|
||
additionalProperties: true
|
||
|
||
BgpSpeakerPatch:
|
||
type: object
|
||
properties:
|
||
role:
|
||
type: string
|
||
endpoint:
|
||
type: string
|
||
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"
|
||
|
||
/v1/version:
|
||
get:
|
||
tags: [System]
|
||
summary: Версия сборки
|
||
description: Версия API и control-plane (`git_sha`, `build_time` и др.).
|
||
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"
|
||
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/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/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"
|
||
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
|
||
default:
|
||
$ref: "#/components/responses/DefaultProblem"
|
||
post:
|
||
tags: [Peers]
|
||
summary: Создать пира
|
||
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` для всех спикеров.
|
||
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: Удалить или отключить пира
|
||
operationId: deletePeer
|
||
parameters:
|
||
- $ref: "#/components/parameters/IdempotencyKey"
|
||
responses:
|
||
"204":
|
||
description: Удалено / отключено.
|
||
"404":
|
||
$ref: "#/components/responses/NotFound"
|
||
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"
|
||
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"
|
||
|
||
/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/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/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"
|