CI / changes (push) Successful in 7s
CI / openapi (push) Successful in 23s
CI / go (push) Failing after 30s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Successful in 1m5s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Successful in 1m3s
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / docker-go-prime (push) Has been skipped
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Has been skipped
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Has been skipped
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Has been skipped
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Has been skipped
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Has been skipped
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Has been skipped
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Has been skipped
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Has been skipped
Added a new job type `peer_reconcile` to handle fast reconciliation of BGP peers without module ingestion. Updated API documentation to reflect the new job's functionality and its automatic application to speakers post-reconciliation. Enhanced the HTTP API to enqueue reconciliation jobs during peer creation, updates, and deletions, ensuring efficient state management for BGP configurations.
2604 lines
82 KiB
YAML
2604 lines
82 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: >
|
||
Фильтр по виду задачи; точный перечень расширяем.
|
||
Основные значения: `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
|
||
|
||
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: Формат скачанного списка / парсер.
|
||
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"
|
||
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"
|
||
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` - политика для всех спикеров."
|
||
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 `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:
|
||
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
|
||
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"
|
||
|
||
/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: >
|
||
Загружает URL, парсит как plaintext или json и возвращает список извлечённых префиксов (до 100 записей).
|
||
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"
|
||
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: Создать пира
|
||
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/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"
|