Add Floating IP scanning and a durable address registry with configurable history depth

Adds POST /api/v1/admin/ips/scan (plus an optional periodic ticker) to
discover free Floating IPs in the OpenStack project and feed them straight
into the check queue. More importantly, decouples check/event history from
ip_queue's lifecycle: a new ip_registry table (migration 0007) gives every
address ever submitted a durable identity, so deleting it from the queue no
longer destroys its history — it's still reachable via the new
GET /api/v1/admin/registry[/{ip}] endpoints and the dashboard's /registry
pages, with retention depth configurable in check cycles per address
(history_retention_cycles, 0 = unlimited).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ayurishchevandClaude Sonnet 5 committed 2026-09-23 09:52:01 +03:00
1 parent 78b20fa5be
commit 582b44f314
47 files changed
+1781 -107

No files matched your search

+29 -9
View File
@@ -49,13 +49,15 @@ admin-dashboard -config /etc/cloud-ip-validator/admin-dashboard.yaml
| Страница | Назначение |
|---|---|
| `/overview` | Сводная статистика: счётчики по состояниям, «текущая проверка» (live-снимок всех IP не в терминальном состоянии) и «последние N завершённых» (по умолчанию 20, `overview.last_completed_count`) с разбивкой pass/partial/fail/cancelled. Обновляется каждые `overview.poll_interval_seconds` секунд без перезагрузки страницы. |
| `/ips` | Полная очередь. Форма сверху принимает список адресов (по одному на строке или через запятую) и отправляет их в `POST /api/v1/admin/ips` — **один и тот же вызов** добавляет новые адреса и принудительно перезапускает уже завершённые (см. ниже). У каждого адреса — кнопка «Перепроверить» (для `done`/`failed`) или «Отменить» (для активных состояний), и всегда — «Удалить» (безвозвратно, в отличие от «Отменить», см. ниже). Чекбоксы у строк + кнопка «Удалить выбранные» удаляют список одним вызовом; «Очистить всё» удаляет вообще всё, включая активные проверки — обе операции требуют явного подтверждения. Пока не истекла настроенная на `/settings` пауза (`fip_settle_seconds`), только что привязавший Floating IP адрес показывает отдельный бейдж «прогрев FIP» вместо обычного статуса. Если на момент попытки привязки Floating IP оказался уже занят другим портом (дрейф состояния облака или ошибочно переданный адрес), цикл проверки для него не запускается — адрес показывает отдельный бейдж «занят» (отличный от «fail») и строку `fip_occupied` в списке событий на его странице; кнопка «Перепроверить» ставит его в очередь заново. |
| `/ips/{ip}` | Детали одного адреса: все проверки текущей попытки и вся история событий. |
| `/ips` | Полная очередь. Форма сверху принимает список адресов (по одному на строке или через запятую) и отправляет их в `POST /api/v1/admin/ips` — **один и тот же вызов** добавляет новые адреса и принудительно перезапускает уже завершённые (см. ниже). Кнопка «Сканировать Floating IP» делает то же самое автоматически: находит в проекте OpenStack все свободные (не привязанные к порту) Floating IP и сразу ставит их в очередь (`POST /api/v1/admin/ips/scan`, см. [API.md](API.md#post-apiv1adminipsscan)) — то же сканирование можно включить по расписанию через `orchestrator.fip_scan_interval_seconds`. У каждого адреса — кнопка «Перепроверить» (для `done`/`failed`) или «Отменить» (для активных состояний), и всегда — «Удалить» (безвозвратно убирает адрес из очереди, но не из реестра — см. ниже). Чекбоксы у строк + кнопка «Удалить выбранные» удаляют список одним вызовом; «Очистить всё» удаляет вообще всё, включая активные проверки — обе операции требуют явного подтверждения. Пока не истекла настроенная на `/settings` пауза (`fip_settle_seconds`), только что привязавший Floating IP адрес показывает отдельный бейдж «прогрев FIP» вместо обычного статуса. Если на момент попытки привязки Floating IP оказался уже занят другим портом (дрейф состояния облака или ошибочно переданный адрес), цикл проверки для него не запускается — адрес показывает отдельный бейдж «занят» (отличный от «fail») и строку `fip_occupied` в списке событий на его странице; кнопка «Перепроверить» ставит его в очередь заново. |
| `/ips/{ip}` | Детали одного адреса, пока он в очереди: все проверки текущей попытки и вся история событий, плюс ссылка на полную историю в реестре (см. ниже). |
| `/registry` | **Реестр** — все адреса, когда-либо поставленные на проверку, независимо от того, стоят ли они сейчас в очереди. Переживает удаление адреса из `/ips` и повторное добавление того же адреса позже (см. «Реестр адресов» ниже). |
| `/registry/{ip}` | Полная сохранённая история проверок одного адреса по всем циклам (не только текущему) — в отличие от `/ips/{ip}`, которая показывает только текущую попытку. |
| `/validators` | Список валидаторов + создание/изменение `os_port_id`/удаление. |
| `/sites` | Площадки — число слотов не ограничено, форма сверху добавляет новый слот, назначить/сменить/освободить `site_id` в каждой строке; колонка «Статус» показывает бейдж подключения пробера (`unregistered`/`idle`/`unreachable`, по аналогии с `/validators`), см. [USAGE.md](USAGE.md#состояния-площадки). |
| `/targets` | Группы целей для egress-проверок — создание/редактирование/удаление. |
| `/check-types` | Типы проверок (`https`/`icmp`/`ssh`/...), включение/выключение, привязка к группам целей. |
| `/settings` | Две формы: `fip_settle_seconds` — пауза (в секундах) между привязкой Floating IP и началом self-check («прогрев» дата-плейна OpenStack, см. [USAGE.md](USAGE.md#пауза-перед-self-check-fip_settle_seconds)); и типы проверок пробера — TCP-порты (через запятую) + чекбокс ICMP, общие для всех площадок (см. [USAGE.md](USAGE.md#управление-типами-проверок-пробера)). |
| `/settings` | Три формы: `fip_settle_seconds` — пауза (в секундах) между привязкой Floating IP и началом self-check («прогрев» дата-плейна OpenStack, см. [USAGE.md](USAGE.md#пауза-перед-self-check-fip_settle_seconds)); `history_retention_cycles` — сколько последних циклов проверки хранить на адрес в реестре (0 — без ограничения); и типы проверок пробера — TCP-порты (через запятую) + чекбокс ICMP, общие для всех площадок (см. [USAGE.md](USAGE.md#управление-типами-проверок-пробера)). |
### «Текущая» и «последняя завершённая» проверка
@@ -83,20 +85,38 @@ admin-dashboard -config /etc/cloud-ip-validator/admin-dashboard.yaml
(дашборд честно показывает это в таблице, а не делает вид, что запрос
ничего не значил).
### Удаление адресов — безвозвратно, в отличие от «Отменить»
### Удаление адресов — безвозвратно из очереди, но не из реестра
«Отменить» (`POST .../cancel`) останавливает проверку, но сохраняет
адрес и его историю как `failed`/`cancelled` — он остаётся виден в
очереди. «Удалить» (кнопка в строке, «Удалить выбранные» по чекбоксам,
«Очистить всё») стирает строку и всю её историю проверок/событий
физически, без возможности восстановления — работает из любого
состояния, включая активно проверяемое (Floating IP отвязывается,
«Очистить всё») убирает строку из `/ips` безвозвратно — работает из
любого состояния, включая активно проверяемое (Floating IP отвязывается,
валидатор освобождается). Все три операции удаления в UI защищены
`hx-confirm` с формулировкой, отражающей необратимость — «Очистить всё»
предупреждает отдельно, так как затрагивает и активные проверки. Подробнее
— [API.md](API.md#delete-apiv1adminipsip-post-apiv1adminipsdelete-post-apiv1adminipsclear)
предупреждает отдельно, так как затрагивает и активные проверки.
**Накопленная история при этом не теряется** — она остаётся в
[реестре](#реестр-адресов) (`/registry/{ip}`) даже после того, как адрес
пропал из `/ips`, и продолжает пополняться, если адрес позже добавят
заново. Подробнее —
[API.md](API.md#delete-apiv1adminipsip-post-apiv1adminipsdelete-post-apiv1adminipsclear)
и [USAGE.md](USAGE.md#удаление-адресов-из-очереди).
### Реестр адресов
`/registry` решает задачу, которую `/ips` принципиально не может: история
проверок конкретного адреса не должна теряться только из-за того, что его
временно вывели из очереди (например, адрес переиспользуют для другой
цели) и позже добавили обратно — возможно, под другим циклом проверки.
Каждая запись реестра живёт всё время, что адрес когда-либо существовал в
системе, и не удаляется вместе со строкой `ip_queue`. Единственное, что
можно ограничить — глубину детальной истории проверок на один адрес
(`history_retention_cycles` на `/settings`, по циклам, а не по времени);
сама запись в реестре (когда адрес впервые встречен, сколько всего было
циклов) остаётся всегда. Подробнее —
[API.md](API.md#реестр-адресов-и-история-проверок).
## Конфигурация
См. `configs/admin-dashboard.example.yaml`. Ключевые поля: