Follow the section layout used in the ipam_control project: quick start, configuration tables, architecture with a directory tree, data-model rules (queue states, results, registry, auto-cycle), API table, security notes, operations, dashboard pages, tests, docs index and change history. Details stay in docs/ and are linked rather than duplicated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Cloud IP Validator
Система проверки освобождённых публичных IPv4-адресов перед их повторной выдачей. Каждый адрес временно привязывается как Floating IP
к ВМ-валидатору в облаке (OpenStack) и проверяется в двух направлениях одновременно: исходящий трафик валидатора (egress: HTTPS/ICMP/опционально SSH
до внешних целей) и входящая доступность самого адреса с нескольких независимых внешних площадок (inbound: TCP 22/80/443/8080 + ICMP).
Итог по каждому адресу — pass/partial/fail; полная история проверок сохраняется в реестре даже после удаления адреса из очереди.
Быстрый старт
go build ./... && go test ./... # сборка и юнит-тесты
scripts/run-local-e2e.sh # офлайн-прогон всей системы: mock OpenStack, без облака и интернета
cd deploy/docker
cp .env.example .env
cp control-api/control-api.docker.example.yaml control-api/control-api.docker.yaml
docker compose up -d --build # весь стенд на одной машине в mock-режиме (профили control-plane, dashboard, prober, validator)
- UI:
http://<хост>:8090/, API:http://<хост>:8080/api/v1, проверка живости:GET /healthz. - Docker-стенд работает с
openstack.mode: mockи тестовыми адресами203.0.113.10–12; реальный OpenStack и учётные данные не нужны. - Реальный стенд (systemd или Docker на нескольких хостах) — по шагам в docs/SETUP.md.
Конфигурация
Каждый компонент читает свой YAML (примеры — configs/*.example.yaml). Учётные данные OpenStack в YAML не хранятся — только имена переменных окружения.
control-api (control-api.yaml)
| Ключ | Назначение |
|---|---|
server.listen_addr |
Адрес API (:8080) |
database.path |
Файл SQLite (/var/lib/cloud-ip-validator/control-api.db) |
openstack.mode |
real или mock (встроенная заглушка OpenStack для разработки и тестов) |
openstack.auth_method |
token (готовый токен проекта из OS_TOKEN, сам не обновляется) или password (логин/пароль Keystone, токен перевыпускается автоматически) |
openstack.*_env |
Имена переменных окружения: OS_AUTH_URL, OS_PROJECT_ID, OS_REGION_NAME, OS_INTERFACE, OS_TOKEN либо OS_USERNAME/OS_USER_DOMAIN_NAME/OS_PASSWORD |
orchestrator.poll_interval_seconds |
Период такта оркестратора (5) |
orchestrator.self_check_timeout_seconds, max_self_check_retries |
Ожидание self-check валидатора (60) и число его повторов (3) |
orchestrator.checking_window_seconds |
Сколько ждать результаты проверок, прежде чем подвести итог (120) |
orchestrator.lease_ttl_seconds, max_retries |
Лизинг адреса за валидатором (180) и число возвратов в очередь при его истечении (3) |
orchestrator.heartbeat_timeout_seconds |
После скольких секунд тишины валидатор или площадка считаются потерянными (30) |
orchestrator.fip_settle_seconds |
Только начальное значение: пауза между привязкой FIP и self-check; далее управляется на лету. Должно выполняться fip_settle_seconds + self_check_timeout_seconds < lease_ttl_seconds |
orchestrator.fip_scan_interval_seconds |
Периодический скан Floating IP (0 — выключен). Не выполняется, пока включён автоматический цикл |
aggregation.missing_counts_as_fail |
Отсутствие ответа источника засчитывается как провал (true) |
validators, sites, check_types, targets, inbound_checks |
Начальная загрузка пустой БД: валидаторы (validator_id + os_port_id), внешние площадки, типы и цели egress-проверок, порты inbound-проверок. Дальше источник истины — БД, правки через API/UI |
ip_addresses |
Адреса, которые доливаются в очередь при каждом старте (только новые) |
Остальные компоненты
| Компонент | Ключи |
|---|---|
validator-agent |
validator_id, control_api_url, poll_interval_seconds, self_check.* (таймаут, ip_echo_urls), checks.* (таймауты HTTPS/ICMP, число ICMP-пакетов, ssh.*) |
prober |
site_id, control_api_url, poll_interval_seconds, checks.* (таймауты TCP/ICMP, число ICMP-пакетов) |
admin-dashboard |
server.listen_addr (:8090), control_api.base_url, control_api.timeout_seconds, overview.last_completed_count (20), overview.poll_interval_seconds (5) |
Настройки, меняющиеся на лету (пауза перед self-check, глубина истории, типы inbound-проверок, автоматический цикл, валидаторы, площадки, цели), хранятся в БД и правятся через API или страницу /settings.
Архитектура
| Слой | Технологии |
|---|---|
| Backend | Go 1.26, net/http (маршруты Go 1.22), SQLite (чистый Go-драйвер modernc.org/sqlite, WAL, одно соединение), встроенные миграции 0001–0008 |
| Облако | Интерфейс FloatingIPClient: реальный клиент OpenStack Neutron и MockClient |
| UI | Серверный рендеринг (Go-шаблоны) + htmx и Alpine.js, шрифты и скрипты лежат в репозитории, внешних зависимостей нет |
| Сборка | Статические бинарники (CGO_ENABLED=0) в bin/, Docker-образы, systemd-юниты |
| Компонент | Роль | Состояние | Где работает |
|---|---|---|---|
control-api |
Ведёт очередь адресов и реестр их истории, назначает валидаторов, агрегирует результаты. Единственная точка, с которой общаются все остальные компоненты | Хранит (SQLite) | Одна управляющая машина |
validator-agent |
Привязывает к себе выданный Floating IP и прогоняет egress-проверки до внешних целей | Без состояния | Каждая ВМ-валидатор в облаке |
prober |
Проверяет входящую доступность адреса снаружи (TCP/ICMP) — с независимой от облака сети | Без состояния | Каждая внешняя тестовая площадка |
admin-dashboard |
Браузерная админ-панель — то же, что API control-api, но графически. Опционален |
Без состояния | Любая машина с доступом к control-api |
Все четыре общаются только через HTTP API control-api. Pull-модель: validator-agent и prober сами опрашивают control-api, он к ним не обращается.
Схемы control/data plane — docs/DIAGRAMS.md.
cmd/ control-api validator-agent prober admin-dashboard
internal/ config db orchestrator httpapi openstack dashboard agentcore probercore checkrunner apiclient
db/migrations/ схема SQLite (0001–0008)
configs/ примеры конфигураций компонентов
deploy/ docker/ (compose, Dockerfile, RUN.txt) systemd/ (юниты)
rxprod-compose/ compose реального стенда (control-api на :8081, дашборд на :8091)
scripts/ run-local-e2e.sh httpstub/ (заглушки целей для e2e)
bin/ готовые бинарники linux/amd64 и SHA256SUMS
docs/ документация и планы доработок
Модель данных и правила
ip_queue (текущая очередь) · ip_registry (все адреса, когда-либо бывшие в очереди) · checks (результаты по циклам) · events (журнал) · validators · sites · target_groups · check_types · settings · inbound_checks_settings · auto_cycle.
Очередь и состояния
- Путь адреса:
queued→assigning_fip→awaiting_self_check→checking→aggregating→doneилиfailed. Все переходы, кроме команд оператора, выполняет оркестратор сам по таймеру. - Терминальные состояния:
done,failed,occupied.occupied— Floating IP к моменту привязки уже занят чужим портом: цикл проверки не стартует,overall_resultпуст, это неfail. - Оператор может отменить проверку (
failed+cancelled), перепроверить завершённый адрес (возврат вqueued) или удалить адрес из очереди. - Адреса обрабатываются в порядке
sequence; каждый свободный валидатор получает следующийqueued-адрес под лизинг. Истёкший лизинг возвращает адрес в очередь, послеmax_retries— вfailed.
Итоговый результат
pass— прошли все проверки: исходящие и все настроенные площадки по всем портам и ICMP.partial— часть прошла, часть нет.fail— не прошла ни одна проверка или адрес не дошёл до проверок (self-check не подтвердился).cancelled— остановлено оператором.- Итог подводится, когда отчитались валидатор и все настроенные площадки либо истекло
checking_window_seconds. Молчание источника — провал (aggregation.missing_counts_as_fail). - Площадки опциональны: с пустым списком
sitesитог строится только по egress-проверкам.
Реестр
- Запись реестра создаётся при первой постановке адреса и не удаляется: она переживает удаление из очереди и повторное добавление.
- История проверок хранится по циклам;
history_retention_cyclesограничивает глубину (0 — без ограничения), сама запись реестра остаётся.
Автоматический цикл (опционально, по умолчанию выключен)
- Один цикл: очистить очередь → просканировать Floating IP → дождаться, пока все адреса станут терминальными → пауза
interval_seconds→ заново. Пауза считается от завершения цикла. interval_seconds— по умолчанию 3600, минимум 60;max_run_seconds— максимальное ожидание проверок (0 — без лимита), по истечении исходtimeout.- Исходы цикла:
completed,no_free_ips,timeout,error,stopped. Опустевшая очередь посреди цикла считается завершением. - Состояние хранится в БД и переживает перезапуск; выключение не прерывает идущие проверки. Подробности — docs/USAGE.md.
Удаление и сканирование
- Удаление (точечное, списком, «очистить всё») убирает строку очереди, но не историю в реестре.
- Скан Floating IP ставит в очередь только свободные адреса (не привязанные ни к одному порту); уже идущие проверки не трогаются.
API (/api/v1)
| Область | Эндпоинты |
|---|---|
| Валидатор | POST /agents/register, POST /agents/{id}/heartbeat, GET /agents/{id}/assignment, POST /agents/{id}/self-check|events|results|complete |
| Пробер | POST /probers/register, POST /probers/{site_id}/heartbeat, GET /probers/{site_id}/assignments, POST /probers/{site_id}/results |
| Очередь | GET /admin/status, GET|POST /admin/ips, GET /admin/ips/{ip}, POST /admin/ips/{ip}/cancel, DELETE /admin/ips/{ip}, POST /admin/ips/delete|clear|scan |
| Реестр | GET /admin/registry, GET /admin/registry/{ip} |
| Автоцикл | GET|PUT /admin/auto-cycle, POST /admin/auto-cycle/start|stop |
| Конфигурация | /admin/config/validators, /sites, /targets, /check-types, GET|PUT /admin/config/orchestrator, GET|PUT /admin/config/inbound-checks |
| Служебное | GET /admin/validators, GET /healthz |
Соглашения
- Тело запросов и ответов — JSON. Успех —
200,204— когда данных нет (например, у валидатора нет назначения). - Ошибки —
4xx/5xxс телом{"error": "..."}; неизвестная сущность —404, конфликт состояния —409, неверные данные —400, ошибка OpenStack при скане —502. - Времена — RFC 3339. Полная спецификация и примеры
curl— docs/API.md.
Безопасность
- Аутентификации API нет — это известное ограничение текущей версии: эндпоинты, включая административные, доступны любому, кто достучится до порта
control-api. Доступ ограничивается на уровне сети/файрвола (docs/SETUP.md); bearer-токен — направление доработки. - Дашборд — тонкий прокси к API без собственных учётных записей и состояния; публиковать его так же нужно только в доверенном сегменте или за reverse-proxy с авторизацией.
- Учётные данные OpenStack передаются только через переменные окружения процесса (
EnvironmentFile=в systemd,OS_*в Docker) и не попадают в YAML; режимpasswordперевыпускает токен сам, режимtoken— нет. - Компоненты работают по pull-модели: на валидаторах и площадках не нужно открывать входящие порты для
control-api. - Бинарники статические, без
cgo; целостность проверяетсяsha256sum -c bin/SHA256SUMS.
Публикация и эксплуатация
- Бинарники. Готовые linux/amd64 лежат в
bin/и не обновляются автоматически: после правок кода пересоберите их и обновитеSHA256SUMS(команды — docs/SETUP.md); Dockerfile копируют именноbin/*. - systemd. Юниты в
deploy/systemd/; уcontrol-api—EnvironmentFileс учётными данными OpenStack. - Docker.
deploy/docker/docker-compose.yml+docker-compose.override.yml(dev, mock) илиdocker-compose.prod.yml(без публикации портов,restart: unless-stopped). Какие сервисы поднимаются на хосте, задаётCOMPOSE_PROFILES:control-plane,dashboard,prober,validator. БД — volumecloud-ip-validator-db. - Реальный стенд.
rxprod-compose/— compose с готовыми образами, собственнымcontrol-api.yamlи каталогом БДcapi-db/;.envс учётными данными в репозиторий не входит. - Миграции применяются при старте
control-api; версия схемы —PRAGMA user_version. Начальная загрузка (validators,sites,targets,check_types,inbound_checks) выполняется только в пустые таблицы. - Остановка (
SIGTERM) корректно завершает HTTP-сервер и фоновые циклы. Состояние автоцикла и очереди сохраняется в БД.
Интерфейс
Страницы admin-dashboard (подробно — docs/DASHBOARD.md):
| Страница | Назначение |
|---|---|
/overview |
Счётчики по состояниям, «текущая» и «последние завершённые» проверки, поиск по IP и фильтр по статусу, индикатор автоцикла; обновляется без перезагрузки |
/ips, /ips/{ip} |
Очередь: добавление адресов, «Сканировать Floating IP», перепроверка, отмена, удаление (в том числе списком и «Очистить всё»); детали и события адреса |
/registry, /registry/{ip} |
Реестр всех адресов и полная история проверок адреса; поиск и фильтр сохраняются в адресной строке |
/validators, /sites, /targets, /check-types |
Управление валидаторами, внешними площадками, группами целей и типами проверок |
/settings |
Панель «Автоматический цикл», пауза перед self-check, глубина истории, TCP-порты и ICMP для inbound-проверок |
- Порядок блоков на
/overviewфиксирован: статистика → фильтр → таблицы; поллится только блок таблиц, поэтому набранный в фильтре текст не сбрасывается. - Ошибки control-api показываются баннером; при недоступном API страница остаётся рабочей.
- Тёмная и светлая темы, переключатель в шапке.
Тесты
go build ./... && go vet ./... && go test ./... # юнит-тесты: db, orchestrator, httpapi, dashboard, agentcore, probercore, checkrunner, openstack
go test -race ./internal/orchestrator ./internal/httpapi ./internal/dashboard ./internal/db
scripts/run-local-e2e.sh # сквозной прогон: lease-reclaim, перепроверка, автоматический цикл
Юнит-тесты используют временную SQLite и MockClient, внешних ресурсов не требуют. E2E поднимает все компоненты локальными процессами и завершается ненулевым кодом при провале проверок автоцикла — docs/LOCAL_E2E.md.
Документация
| Документ | Для чего |
|---|---|
| docs/SETUP.md | Развёртывание с нуля: бинарники или сборка из исходников, конфигурация, systemd и Docker/docker-compose — пошагово |
| docs/USAGE.md | Повседневная работа: очередь, сканирование Floating IP, автоматический цикл, статус, реестр и история, разбор результатов |
| docs/API.md | Спецификация HTTP API control-api и примеры запросов (curl) |
| docs/DASHBOARD.md | Устройство admin-dashboard: страницы, поиск и фильтр, обработка ошибок |
| docs/DIAGRAMS.md | Диаграммы потоков данных: control plane, egress-проверка, телеметрия |
| docs/LOCAL_E2E.md | Полностью офлайн-прогон всей системы одним скриптом |
| docs/CONTROL_DATA_PLANE.html | Презентационные схемы control/data plane для docker-compose-деплоя — открыть в браузере |
История изменений
Дизайн крупных доработок зафиксирован в планах docs/PLAN_*.md; остальное — в истории git (git log).
| Изменение | Документ |
|---|---|
Веб-панель администратора admin-dashboard |
план · описание |
| Динамическое управление конфигурацией и очередью через API | план · API |
| Удаление адресов: точечное, массовое, «очистить всё» | план |
Пауза перед self-check после привязки Floating IP (fip_settle_seconds) |
план · USAGE |
| Механизм аутентификации OpenStack-клиента (token / password) | план |
| Дата | Веха | Документ |
|---|---|---|
| 2026-10-01 | Автоматический цикл проверок по сценарию: очистка → скан FIP → проверка → пауза | USAGE · API |
| 2026-09-23 | Сканирование Floating IP и устойчивый реестр адресов с настраиваемой глубиной истории | USAGE |
| 2026-09-23 | Поиск по IP и фильтр по статусу на «Обзоре» и «Реестре» | DASHBOARD |
| 2026-09-23 | Пошаговое руководство по развёртыванию в Docker | SETUP |
| 2026-09-18 | Массовая перепроверка в дашборде; compose реального стенда rxprod-compose |
DASHBOARD |
| 2026-09-13 | Состояние occupied: пропуск цикла для уже занятого Floating IP; схемы control/data plane |
DIAGRAMS |
| 2026-08-26 | Управление внешними площадками и heartbeat пробера, новый UI дашборда, переключатель темы | DASHBOARD |