Files
cloud-ip-validator/docs/DIAGRAMS.md
T
ayurishchevandClaude Sonnet 5.5 cd37b10f3b Add optional automatic check cycle (clear queue -> scan FIPs -> wait -> repeat)
An admin-controlled scenario that repeats what the operator does by hand:
clear the IP queue, scan and enqueue all free Floating IPs, wait until every
queued address reaches a terminal state (so results are in the Registry),
then wait a configurable interval and start over.

- control-api: new auto_cycle singleton table (migration 0008) holding
  enabled/interval/max-run settings and persisted phase state, so the cycle
  survives restarts; engine in orchestrator/autocycle.go driven from the
  existing loop tick with an injectable "now" for deterministic tests.
- Interval (default 1h, min 60s) and max wait (default unlimited, timeout
  outcome) are runtime settings, never hardcoded.
- The periodic fip_scan_interval_seconds scan is skipped while the cycle is
  enabled. An emptied queue mid-cycle counts as finished; stopping during
  the pause keeps the last cycle's outcome.
- API: GET/PUT /api/v1/admin/auto-cycle, POST .../start, POST .../stop.
- admin-dashboard: "Автоматический цикл" panel on /settings and an
  "Автоцикл активен" indicator on /overview.
- Tests for db, orchestrator, httpapi and dashboard; run-local-e2e.sh now
  exercises a full auto cycle; docs updated; bin/ rebuilt with refreshed
  SHA256SUMS.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 10:28:53 +03:00

240 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Диаграммы потоков данных
Три диаграммы, поясняющие устройство системы на уровне потоков данных —
дополнение к [API.md](API.md) (протокол) и [USAGE.md](USAGE.md) (работа
оператора). Диаграммы — в формате Mermaid, рендерятся нативно на
GitHub/GitLab и в большинстве современных Markdown-просмотрщиков.
Презентационная версия этих же двух разрезов (control plane и data plane)
под микросервисный (docker-compose) деплой, с топологией по хостам и
профилям `COMPOSE_PROFILES` — [CONTROL_DATA_PLANE.html](CONTROL_DATA_PLANE.html)
(самодостаточный HTML-файл, открыть в браузере).
## Как читать диаграммы
Единое условное обозначение стрелок для всех диаграмм:
| Обозначение | Значение |
|---|---|
| `-->` тонкая сплошная | Управляющий вызов / API-запрос |
| `-.->` пунктирная | Ответ, уведомление, асинхронный результат |
| `==>` жирная сплошная | Реальный сетевой трафик проверки (data-plane) — именно то, что валидируется, а не служебный вызов |
## Содержание
- [1. Control plane сервиса](#1-control-plane-сервиса)
- [2. Поток данных: от валидатора к целевому серверу (egress-проверка)](#2-поток-данных-от-валидатора-к-целевому-серверу-egress-проверка)
- [3. Поток данных телеметрии](#3-поток-данных-телеметрии)
---
## 1. Control plane сервиса
Кто кем управляет и через какой канал: конфигурация оператора, HTTP API
control-api, фоновый оркестратор, база данных, вызовы к OpenStack и опрос
со стороны validator-agent/prober.
```mermaid
flowchart TB
subgraph OP["Оператор"]
CFG["control-api.yaml<br/>(bootstrap пустой БД:<br/>validators, sites, targets,<br/>check_types, ip_addresses)"]
ENV["control-api.env<br/>(OS_AUTH_URL, OS_TOKEN, ...)"]
ADMIN["curl /api/v1/admin/*<br/>(status/ips/validators,<br/>ips submit/cancel,<br/>auto-cycle start/stop,<br/>config CRUD)"]
end
subgraph CAPI["control-api (управляющая машина, 1 экземпляр)"]
HTTP["HTTP API<br/>/api/v1/agents/*<br/>/api/v1/probers/*<br/>/api/v1/admin/*<br/>/healthz"]
ORCH["Оркестратор: Tick раз в<br/>poll_interval_seconds<br/>claim → associate FIP →<br/>ожидание self-check →<br/>checking → aggregate → release<br/>+ lease sweep + heartbeat sweep<br/>+ автоцикл (если включён):<br/>очистка → скан FIP → ожидание →<br/>пауза interval_seconds"]
DB[("SQLite<br/>validators / ip_queue / sites /<br/>target_groups / check_types /<br/>checks / events / auto_cycle")]
OSCLIENT["OpenStack-клиент<br/>(mode: mock | real)"]
end
OS["OpenStack Neutron<br/>Floating IP API"]
VA["validator-agent ×N<br/>(на каждой ВМ-валидаторе)"]
PR["prober ×3<br/>(на каждой внешней площадке)"]
CFG -->|"читается только один раз,<br/>на пустых таблицах (bootstrap)"| DB
ENV -->|"переменные окружения процесса"| OSCLIENT
ADMIN --> HTTP
HTTP -->|"config/queue CRUD:<br/>источник истины после<br/>первого изменения"| DB
HTTP --> ORCH
ORCH <--> DB
ORCH --> OSCLIENT
OSCLIENT -->|"associate / disassociate<br/>floating ip"| OS
VA <-->|"register, heartbeat,<br/>GET assignment,<br/>POST self-check/events/<br/>results/complete"| HTTP
PR <-->|"register,<br/>GET assignments,<br/>POST results"| HTTP
```
**Пояснение.** `control-api` — единственный компонент с состоянием и
единственная точка принятия решений (какой IP кому назначить, когда
считать проверку завершённой). `control-api.yaml` используется только как
одноразовый bootstrap для четырёх секций (`validators`, `sites`,
`targets`, `check_types`) — читается лишь пока соответствующая таблица в
БД пуста; `ip_addresses` — отдельный, всегда аддитивный путь постановки в
очередь при каждом старте. После bootstrap все изменения этих сущностей,
включая состав очереди и принудительные повтор/остановку проверки, идут
через `/api/v1/admin/*` — «на лету», без `systemctl restart control-api`
(см. [API.md](API.md#управление-очередью-и-конфигурацией)). Оркестратор
работает по таймеру независимо от HTTP-запросов — назначение IP
валидаторам и агрегация результатов не привязаны к конкретному входящему
запросу, читая актуальную конфигурацию из БД на каждом проходе, а не
единожды при старте. Опциональный автоцикл — часть того же оркестратора:
на каждом тике он читает из таблицы `auto_cycle` флаг `enabled`, интервал и
фазу (`idle`/`running`/`waiting`), поэтому включение, выключение и смена
интервала действуют без перезапуска, а состояние переживает рестарт (см.
[USAGE.md](USAGE.md#автоматический-цикл-проверок)). `validator-agent` и `prober` — активная сторона: они
сами инициируют все HTTP-запросы к control-api (pull-модель), сам
control-api к ним не обращается.
---
## 2. Поток данных: от валидатора к целевому серверу (egress-проверка)
Как валидатор проверяет, что через назначенный ему публичный адрес
реально работает исходящий доступ в интернет.
```mermaid
flowchart LR
subgraph VM["ВМ-валидатор (сервисный проект OpenStack)"]
AGENT["validator-agent"]
end
FIP(["Floating IP<br/>203.0.113.10<br/>(адрес под проверкой,<br/>привязан оркестратором заранее)"])
IPECHO["Внешний IP-echo сервис<br/>(api.ipify.org и т.п.,<br/>вне облака)"]
CAPI["control-api"]
subgraph TARGETS["Целевые серверы (targets из конфига)"]
T1["hub.docker.com"]
T2["github.com"]
T3["packages.ubuntu.com"]
end
AGENT ==>|"1 self-check: исходящий трафик<br/>ВМ идёт через FIP (SNAT облака)"| FIP
FIP ==>|"1 GET"| IPECHO
IPECHO -.->|"2 наблюдаемый исходящий IP"| AGENT
AGENT -->|"3 POST self-check {success}"| CAPI
AGENT ==>|"4 проверки: тоже через FIP"| FIP
FIP ==>|"4 HTTPS GET"| T1
FIP ==>|"4 HTTPS GET"| T2
FIP ==>|"4 ICMP echo"| T3
```
**Пояснение.** Шаги 1–2 — самопроверка (self-check): агент сам (без
участия control-api) обращается к внешнему IP-echo сервису и сравнивает
адрес, с которого пришёл его собственный запрос, с адресом, который ему
назначен. Ресурс для сравнения обязан быть вне облака: OpenStack
применяет SNAT через Floating IP только к трафику, уходящему через
внешнюю сеть — обращение к чему-либо внутри проекта (включая сам
control-api, если он в той же внутренней сети) показало бы приватный
адрес валидатора независимо от корректности привязки FIP. Итог
самопроверки агент затем сообщает control-api отдельным вызовом (шаг 3) —
это уже управляющий, а не проверяемый трафик. Только после успешного
self-check агент переходит к шагу 4 и выполняет проверки из
`check_config` (HTTPS/ICMP/опционально SSH) против целей из конфига —
тем же путём, через тот же FIP. Каждый результат отправляется обратно в
control-api сразу после выполнения (см. диаграмму телеметрии ниже) — сам
этот data-plane трафик (шаги 1 и 4) в control-api не проходит и им не
наблюдается напрямую, control-api видит только заявленный агентом
результат.
### Дополнительно: обратное направление (пробер к валидатору)
Тот же Floating IP одновременно проверяется и «снаружи» — с трёх внешних
площадок, независимо от исходящих проверок агента:
```mermaid
flowchart LR
subgraph SITES["3 внешние площадки"]
P1["prober site-1"]
P2["prober site-2"]
P3["prober site-3"]
end
FIP(["тот же Floating IP<br/>203.0.113.10"])
VM["ВМ-валидатор<br/>(слушает 22/80/443/8080)"]
P1 ==>|"TCP connect + ICMP echo"| FIP
P2 ==>|"TCP connect + ICMP echo"| FIP
P3 ==>|"TCP connect + ICMP echo"| FIP
FIP -.-> VM
```
Именно сочетание двух направлений (egress от валидатора и inbound от трёх
площадок) и даёт полную картину: адрес может нормально работать «наружу»,
но быть заблокирован для конкретных внешних сетей — это увидит только
inbound-проверка, и наоборот.
---
## 3. Поток данных телеметрии
Как результаты проверок и события аудита от validator-agent и трёх
проберов попадают в базу данных control-api, агрегируются в итоговый
результат и становятся видны оператору.
```mermaid
flowchart TB
subgraph SOURCES["Источники телеметрии"]
VA["validator-agent<br/>(egress-проверки + self-check)"]
P1["prober site-1"]
P2["prober site-2"]
P3["prober site-3"]
end
subgraph API["HTTP API control-api"]
EP1["POST /agents/{id}/events"]
EP2["POST /agents/{id}/self-check"]
EP3["POST /agents/{id}/results"]
EP4["POST /probers/{site_id}/results"]
end
subgraph DB["SQLite (control-api)"]
EVENTS[("events<br/>журнал аудита")]
CHECKS[("checks<br/>результаты проверок,<br/>source=egress|inbound-site-N")]
IPQ[("ip_queue<br/>state, *_complete,<br/>overall_result")]
end
AGG["Агрегация (оркестратор):<br/>по достижении всех *_complete<br/>или по таймауту checking_window_seconds"]
ADMIN["Оператор:<br/>GET /api/v1/admin/status<br/>GET /api/v1/admin/ips<br/>GET /api/v1/admin/ips/{ip}"]
VA -->|"config_received,<br/>self_check_result, ..."| EP1 --> EVENTS
VA -->|"success, detected_egress_ip"| EP2 --> EVENTS
EP2 -.->|"успех → egress_complete"| IPQ
VA -->|"check_type, target,<br/>success, latency_ms"| EP3 --> CHECKS
P1 & P2 & P3 -->|"check_type, success,<br/>latency_ms, complete"| EP4 --> CHECKS
EP4 -.->|"complete=true → siteN_complete"| IPQ
CHECKS --> AGG
IPQ --> AGG
AGG -->|"overall_result:<br/>pass / partial / fail"| IPQ
EVENTS --> ADMIN
CHECKS --> ADMIN
IPQ --> ADMIN
```
**Пояснение.** Телеметрия стекается в БД из четырёх независимых потоков
(один от агента-валидатора, три — по одному с каждой площадки),
записываясь в две таблицы: `events` — сырой журнал аудита (что и когда
произошло), `checks` — результат каждой отдельной проверки с указанием
источника (`source`: `egress` для валидатора, `inbound-site-1/2/3` для
площадок). Отдельно, по мере поступления данных, выставляются флаги
завершения (`egress_complete`, `site1/2/3_complete`) в `ip_queue`. Как
только все ожидаемые флаги выставлены — либо истекло время ожидания
(`checking_window_seconds`) — фоновая агрегация суммирует все строки
`checks` по текущей попытке и записывает итог (`pass`/`partial`/`fail`)
обратно в `ip_queue`. Оператор в любой момент читает уже накопленные
данные через административные `GET`-методы, не дожидаясь завершения
проверки — подробнее о значениях полей см.
[USAGE.md](USAGE.md#значения-полей-ip).
> На диаграмме показан пример с тремя площадками — это лишь иллюстрация,
> не ограничение. Площадки опциональны и их число не ограничено: сколько
> их ожидать, определяется списком `sites` в конфиге control-api (пустой
> список — ни одного потока `inbound-site-N`, агрегация ждёт только
> `egress_complete`; N площадок — N параллельных потоков телеметрии). См.
> [USAGE.md](USAGE.md#управление-площадками-проберами).