Files
telemt-api/docs/AGGREGATE.md
T
Denozordec 8c8ccce6ee
Publish telemt-api gateway Docker image / test (push) Successful in 24s
Publish telemt-api gateway Docker image / build-and-push (push) Successful in 1m58s
Enhance API and UI for incident management and live updates
- Added a new endpoint `/api/agg/incidents` to provide a normalized snapshot of incidents for fleet triage, including severity and recommended actions.
- Implemented live event streaming via `/api/live/events` for real-time updates on fleet status and incidents, enhancing observability.
- Updated the Web UI to include dedicated sections for incidents and live updates, improving user navigation and access to critical information.
- Enhanced API documentation to reflect new endpoints and their functionalities, ensuring clarity for developers and users.
2026-03-30 19:17:29 +07:00

9.7 KiB
Raw Blame History

Агрегирующие эндпоинты шлюза (/api/agg/)

Шлюз telemt-api опрашивает несколько upstream Telemt Control API и отдаёт сводные JSON-ответы.

  • Большинство маршрутов агрегации используют GET /v1/stats/users на каждом сервере из конфигурации.
  • GET /api/agg/fleet-status дополнительно вызывает на каждом upstream GET /v1/health и GET /v1/system/info (параллельно по серверам).

Единицы трафика в агрегатах: поля *_megabytes — это двоичные мегабайты (MiB), 1 MiB = 1024² октетов (как у Telemt в ответе считаются октеты, шлюз делит на MiB для удобства).

Доступ к одному инстансу по-прежнему через прокси: GET /api/{alias}/… (например /api/gt1/v1/stats/users) — там по-прежнему total_octets как в API.md.

Успешный ответ (общий контракт)

{
  "ok": true,
  "data": {},
  "generated_at": "2026-03-30T12:00:00.000000000Z",
  "partial": true
}
  • generated_at — UTC, RFC3339Nano; время формирования ответа шлюза.
  • partial — присутствует и равно true, если хотя бы один upstream в этом запросе завершился с ошибкой (HTTP не 200, сеть, ok: false в теле и т.д.), либо для fleet-status — если не оба подзапроса (health и system/info) успешны для какой-либо ноды. Если все вызовы успешны, поле partial не включается.

Маршруты

Метод Путь Описание
GET /api/agg/summary Сводка по флоту, список опросов upstream, fleet_total_megabytes / fleet_total_connections. Два топа (размер задаётся top_n): top_users — самые «прожорливые» по суммарному трафику (MiB) по всем серверам; top_users_by_unique_ips — по максимальному active_unique_ips среди серверов для пользователя (как в Telemt, снимок).
GET /api/agg/traffic Трафик по каждому пользователю в разрезе серверов: servers.<alias>.total_megabytes.
GET /api/agg/unique-ips Уникальные IP по пользователю: на каких серверах IP есть в active/recent списках снимка. При geoip.enabled в конфиге — из City: country_code, country_name, city_name, а также latitude, longitude (если доступны); при наличии ASN-БД — asn, as_organization (см. GEOIP.md); отключить гео для запроса: ?geo=false.
GET /api/agg/users Объединённый список пользователей с by_server, суммарным total_megabytes и смерженными лимитами (см. ниже).
GET /api/agg/user/{username} Один пользователь в том же формате, что элементы /api/agg/users (без списка всех). Имя в пути: [A-Za-z0-9_.-]+. Ответ 404, если пользователь не найден ни на одном успешном upstream.
GET /api/agg/fleet-status По каждому алиасу: параллельно health + system/info; в data.servers[] — статусы подзапросов и тела health / system_info при успехе. См. AGGREGATE_OPENAPI.yaml.
GET /api/agg/incidents Нормализованный snapshot инцидентов для triage-панели: critical/warning/info, affected_aliases, рекомендуемые actions (runbook/deep links), счётчики по severity.

Все методы — GET; действует тот же whitelist, что и для остального API шлюза.

Слияние лимитов в users и user/…

Поля в строке пользователя (кроме счётчиков и by_server):

Поле Политика
user_ad_tag Первое непустое значение при обходе серверов в лексикографическом порядке алиаса.
expiration_rfc3339 Самая ранняя дата среди заданных на серверах (по разбору RFC3339 / RFC3339Nano).
max_tcp_conns, data_quota_bytes, max_unique_ips Минимум среди заданных на серверах (самый строгий лимит).

Ссылки links при include_links=true по-прежнему берутся из первой успешной записи по пользователю (как раньше).

Query-параметры

Параметр Где Значение
aliases все Список алиасов через запятую (например gt1,gt2). Если не задан — см. aggregate.include_aliases в YAML или все серверы из servers.
top_n summary Размер топа пользователей (по умолчанию 10, максимум 1000).
include_links users, user/… true — добавить сгенерированные tg://proxy ссылки (берётся первая успешная запись по пользователю).
min_total_megabytes users Порог суммарного трафика пользователя в MiB (строго больше 0).
min_total_octets users Устаревший вариант порога в октетах (если задан min_total_megabytes, он приоритетнее).
aliases incidents Список алиасов через запятую; позволяет строить incidents snapshot по выбранной группе нод.

Live stream (SSE)

Для оперативного режима NOC доступен поток событий:

  • GET /api/live/events (text/event-stream)
  • query: aliases (опционально, как в /api/agg/*)
  • событие: event: snapshot
  • payload: JSON со статусом флота (healthy/degraded/critical), partial, и массивом incidents

Поток рассчитан на UI-клиент с авто-reconnect (на фронте используется экспоненциальный backoff).

Конфигурация (опционально)

# SPA на другом origin: список разрешённых Origin или "*" (без учётных данных cookie к шлюзу).
cors_allowed_origins:
  - "http://localhost:5173"

aggregate:
  include_aliases:
    - gt1
    - gt2
  # Кэш только для успешных (HTTP 200) ответов /api/agg/*, ключ = путь + query. 0 = выкл. Макс. 60000 мс.
  cache_ttl_ms: 2000

Если блок aggregate отсутствует или include_aliases пуст, по умолчанию участвуют все записи servers.

Имя алиаса agg в servers запрещено (зарезервировано под префикс /api/agg/).

CORS

Если задан непустой cors_allowed_origins, шлюз для подходящего заголовка Origin добавляет заголовки CORS и отвечает на OPTIONS кодом 204 без тела (preflight). Совпадение: точное равенство строки origin или "*". Whitelist IP по-прежнему применяется до обработки запроса.

Ограничения

  • Один и тот же username на разных серверах может соответствовать разным учётным записям; агрегатор сопоставляет строки по имени — учитывайте при интерпретации сумм.
  • У Telemt в UserInfo нет поля «IP последний раз подключался к серверу X». В unique-ips поле primary_server заполняется только если ровно один сервер видит IP в active_unique_ips_list на момент запроса; иначе primary_server отсутствует или несколько серверов в списках — это снимок, не история.

Машиночитаемый контракт

Черновик схемы OpenAPI 3 для /api/agg/*: AGGREGATE_OPENAPI.yaml (удобно для генерации типов на фронтенде).

Примеры

curl -sS "http://127.0.0.1:8080/api/agg/summary"
curl -sS "http://127.0.0.1:8080/api/agg/traffic?aliases=gt1,gt2"
curl -sS "http://127.0.0.1:8080/api/agg/unique-ips"
curl -sS "http://127.0.0.1:8080/api/agg/users?include_links=false&min_total_megabytes=1"
curl -sS "http://127.0.0.1:8080/api/agg/fleet-status"
curl -sS "http://127.0.0.1:8080/api/agg/user/myuser?aliases=gt1"
curl -sS "http://127.0.0.1:8080/api/agg/incidents?aliases=gt1,gt2"

# SSE поток snapshot-событий (пример с curl)
curl -N "http://127.0.0.1:8080/api/live/events?aliases=gt1,gt2"