- 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.
9.7 KiB
Агрегирующие эндпоинты шлюза (/api/agg/)
Шлюз telemt-api опрашивает несколько upstream Telemt Control API и отдаёт сводные JSON-ответы.
- Большинство маршрутов агрегации используют
GET /v1/stats/usersна каждом сервере из конфигурации. GET /api/agg/fleet-statusдополнительно вызывает на каждом upstreamGET /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"