Scan floating IPs in the background, page by page, so thousands of addresses work
The "Scan Floating IP" button failed with a client timeout: the project now holds ~6.4k floating IPs and the scan listed them all in one unpaginated, timeout-less Neutron request on the HTTP request context. openstack: ListFreeFloatingIPs reads marker-based pages (fields= keeps them small) with per-page retry/backoff on transport errors, 5xx and 429, and every request now has a timeout (also ends hangs inside the orchestrator tick). orchestrator: the scan is a single-flight background job on the process context with progress (clearing/listing/enqueuing/done/error), dry_run, full discovery before anything is enqueued, then SubmitIPs in chunks of 500 in ascending IP order; a failed read leaves the queue untouched. The auto-cycle gets a "scanning" phase that polls the job, so the control loop and autoCycleMu are never held across OpenStack/DB work; it recovers after a restart and waits for (instead of adopting) a scan started by someone else. db: migration 0009 (indexes), paged ListIPsPage/ListRegistryPage, GROUP BY counters, EXISTS completion check, set-based ClearAllIPs. API: POST /admin/ips/scan -> 202 (dry_run, wait), GET /admin/ips/scan, paging and filters on /admin/ips and /admin/registry (bare arrays without limit), results_by_overall in /admin/status. dashboard: scan progress panel and dry-run button, paginated /ips and /registry with server-side filters, Overview on counters and capped lists with progress/ETA, "select all N by filter", hx-params fix for per-row buttons, real counts in confirmations. Also: docs (API, USAGE, DASHBOARD, README), plan and review under docs/changes/, bin/ rebuilt with new SHA256SUMS. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
debf2afed2
commit
aff8fe38b5
61 files changed
+5833
-536
No files matched your search
+40
-27
@@ -49,7 +49,7 @@ 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` секунд без перезагрузки страницы. Поиск по IP и фильтр по статусу (`pass`/`partial`/`fail`/`cancelled`) над обеими таблицами — набранное/выбранное не сбрасывается очередным обновлением. Пока включён [автоматический цикл](USAGE.md#автоматический-цикл-проверок), под счётчиками показывается индикатор «Автоцикл активен» с текущей фазой и временем следующего запуска; управляется цикл на `/settings`. |
|
||||
| `/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` | Очередь **постранично** (по 50 адресов; 25/50/100/200) с поиском по IP и фильтром по состоянию/итогу на сервере; кнопка «Сканировать Floating IP» запускает фоновое сканирование с панелью прогресса, «Пробное сканирование» ничего не ставит в очередь (подробности — «Очередь из тысяч адресов» ниже). Форма сверху принимает список адресов (по одному на строке или через запятую) и отправляет их в `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` и повторное добавление того же адреса позже (см. «Реестр адресов» ниже). Поиск по IP и фильтр по статусу — то же самое, что на `/overview`, плюс отражается в адресной строке (`?q=&status=`), так что отфильтрованную ссылку можно сохранить/переслать. |
|
||||
| `/registry/{ip}` | Полная сохранённая история проверок одного адреса по всем циклам (не только текущему) — в отличие от `/ips/{ip}`, которая показывает только текущую попытку. |
|
||||
@@ -59,41 +59,37 @@ admin-dashboard -config /etc/cloud-ip-validator/admin-dashboard.yaml
|
||||
| `/check-types` | Типы проверок (`https`/`icmp`/`ssh`/...), включение/выключение, привязка к группам целей. |
|
||||
| `/settings` | Четыре блока. Первый — панель **«Автоматический цикл»**: статус и фаза, время последнего/следующего запуска, результат последнего цикла, поля «Интервал между циклами (мин)» и «Максимальная длительность проверки (мин, 0 = без лимита)» с кнопкой «Сохранить» и кнопка «Включить»/«Выключить» (показывается та, что сейчас применима). Значения вводятся в минутах (допустимы дробные), в control-api уходят секундами; минимум интервала — 1 минута (`60` с), нарушение приходит предупреждением в баннере. Подробности — [USAGE.md](USAGE.md#автоматический-цикл-проверок), API — [API.md](API.md#автоматический-цикл-проверок). Далее три формы: `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#управление-типами-проверок-пробера)). |
|
||||
|
||||
### «Текущая» и «последняя завершённая» проверка
|
||||
### «В работе», «в очереди» и «последняя завершённая» проверка
|
||||
|
||||
В `control-api` нет понятия «запуска»/«цикла проверки» как отдельной
|
||||
сущности — есть только общая очередь IP-адресов
|
||||
(`docs/PLAN_ADMIN_DASHBOARD.md`). Дашборд ничего не меняет в этом
|
||||
устройстве и не заводит своего состояния:
|
||||
устройстве и не заводит своего состояния. Очередь может содержать тысячи
|
||||
адресов, поэтому `/overview` **никогда не загружает её целиком** — на каждое
|
||||
обновление запрашиваются счётчики и несколько ограниченных списков:
|
||||
|
||||
- **Текущая проверка** — все адреса, которые прямо сейчас не в
|
||||
состоянии `done`/`failed` (`queued`, `assigning_fip`,
|
||||
`awaiting_self_check`, `checking`, `aggregating`), вычисляется заново на
|
||||
каждый запрос из `GET /api/v1/admin/status` + `GET /api/v1/admin/ips`.
|
||||
- **Последняя завершённая проверка** — последние N адресов, перешедших в
|
||||
`done`/`failed`, отсортированные по `AggregatedAt` по убыванию (не
|
||||
«последний запуск», а именно скользящее окно последних по времени
|
||||
завершений).
|
||||
- **Счётчики** — `GET /api/v1/admin/status` (по состояниям и `results_by_overall`).
|
||||
- **В работе** — адреса в `assigning_fip`, `awaiting_self_check`, `checking`, `aggregating`
|
||||
(не более 100; естественный предел — число валидаторов).
|
||||
- **В очереди: Q** — счётчик `queued` со ссылкой на `/ips?state=queued` и несколько ближайших адресов.
|
||||
- **Последние N завершённых** — последние N адресов в `done`/`failed` по `AggregatedAt` по убыванию
|
||||
(не «последний запуск», а скользящее окно последних по времени завершений).
|
||||
- **Прогресс** в блоке статистики: «Готово D из T (P%) · в работе A · в очереди Q» с полосой и оценкой
|
||||
оставшегося времени (по скорости последних завершений, когда их не меньше пяти). `occupied` считается
|
||||
завершённым состоянием.
|
||||
|
||||
### Поиск по IP и фильтр по статусу
|
||||
|
||||
На `/overview` и `/registry` есть форма из двух полей — поиск по IP
|
||||
(подстрока, без учёта регистра) и выпадающий список статуса
|
||||
(`pass`/`partial`/`fail`/`cancelled`). Оба поля работают вместе (И, а не
|
||||
ИЛИ) и применяются целиком на стороне дашборда — `client.ListIPs`/
|
||||
`client.ListRegistry` всегда получают от `control-api` полный список,
|
||||
`internal/httpapi`/`internal/db` про фильтр вообще не знают.
|
||||
На `/overview`, `/ips` и `/registry` есть поиск по IP (подстрока) и фильтр по статусу/итогу (`pass`/`partial`/`fail`/`cancelled`;
|
||||
на `/ips` — ещё по состоянию очереди). Поля работают вместе (И, а не ИЛИ). Фильтрация выполняется **на стороне `control-api`**
|
||||
(параметры `q`, `state`, `result`/`last_result` у `GET /admin/ips` и `GET /admin/registry`), а дашборд получает только нужную страницу, поэтому
|
||||
фильтр работает быстро при любом размере очереди.
|
||||
|
||||
- **`/overview`** — фильтр действует на обе таблицы сразу («Текущая
|
||||
проверка» и «Последние N завершённых»). Статус — это фильтр по
|
||||
итоговому результату (`OverallResult`), поэтому выбор конкретного
|
||||
статуса скрывает «Текущую проверку» целиком: у ещё идущих проверок
|
||||
результата попросту нет. Панель статистики (счётчики сверху) фильтру не
|
||||
подчиняется — это агрегаты по всей очереди, а не по видимым строкам.
|
||||
- **`/registry`** — тот же принцип, но по одной таблице (`LastResult`), и
|
||||
значения полей отражаются в адресной строке (`?q=&status=`) через
|
||||
`hx-replace-url` — отфильтрованную ссылку можно сохранить или переслать,
|
||||
а обновление страницы (F5) сохраняет применённый фильтр.
|
||||
- **`/overview`** — `q` и статус передаются в списки «В работе» и «Последние N завершённых». Статус — это фильтр по
|
||||
итоговому результату (`OverallResult`), поэтому выбор конкретного статуса скрывает «В работе» и «В очереди»: у ещё идущих проверок
|
||||
результата попросту нет. Панель статистики (счётчики сверху) фильтру не подчиняется — это агрегаты по всей очереди, а не по видимым строкам.
|
||||
- **`/registry` и `/ips`** — таблица постраничная; значения полей и страница отражаются в адресной строке (`?q=&status=&page=`) через
|
||||
`hx-replace-url` — отфильтрованную ссылку можно сохранить или переслать, а обновление страницы (F5) сохраняет применённый фильтр.
|
||||
|
||||
**Раскладка `/overview` сверху вниз**: панель статистики → форма
|
||||
фильтра → таблицы. Панель статистики и форма фильтра физически лежат
|
||||
@@ -157,6 +153,23 @@ auto-refresh на `/ips`, см. git-историю). Опрашивается т
|
||||
циклов) остаётся всегда. Подробнее —
|
||||
[API.md](API.md#реестр-адресов-и-история-проверок).
|
||||
|
||||
## Очередь из тысяч адресов
|
||||
|
||||
После сканирования проекта в очереди может оказаться несколько тысяч адресов, поэтому тяжёлые страницы работают постранично:
|
||||
|
||||
- **`/ips` и `/registry`** — параметры `page` и `per_page` (по умолчанию 50; допустимо 25/50/100/200), «Показано a–b из N» и кнопки ‹ ›.
|
||||
Поиск (`q`), состояние/итог и размер страницы применяются **на стороне control-api** (`GET /admin/ips?limit=…`, `GET /admin/registry?limit=…`),
|
||||
поэтому страница весит десятки килобайт независимо от длины очереди. Фильтры и страница отражены в адресной строке.
|
||||
- **Массовые операции.** Чекбоксы выбирают строки текущей страницы (счётчик «Выбрано на странице: k из P»). Если отмечен заголовок таблицы и записей
|
||||
больше страницы, появляется ссылка «Выбрать все N по фильтру»: тогда «Перепроверить»/«Удалить» применяются ко **всем** адресам по текущему фильтру
|
||||
(адреса разрешаются на сервере и отправляются кусками по 500). Подтверждения показывают реальное число: «Удалить ВСЕ 6440 адресов…».
|
||||
«Очистить всё» очищает очередь целиком одной быстрой операцией.
|
||||
- **Сканирование.** Кнопка «Сканировать Floating IP» мгновенно возвращает панель прогресса под кнопкой; пока задание идёт, панель сама
|
||||
обновляется каждые 2 секунды, по окончании опрос прекращается и таблица перезагружается. Во время сканирования кнопки заблокированы; повторное
|
||||
нажатие присоединяется к идущему заданию. Ошибка (например, OpenStack недоступен) показывается в панели с причиной.
|
||||
Саму таблицу `/ips` по таймеру по-прежнему не обновляем — она не сбрасывает ввод оператора.
|
||||
- Долгие операции (`Очистить всё`, массовое удаление/перепроверка) выполняются с увеличенным таймаутом (120 с), остальные запросы к control-api — с `control_api.timeout_seconds`.
|
||||
|
||||
## Вход и сессия
|
||||
|
||||
Если заданы `ADMIN_DASHBOARD_USERNAME` и `ADMIN_DASHBOARD_PASSWORD`, все страницы, кроме `/login` и `/static/*`, требуют входа.
|
||||
|
||||
Reference in new issue
Block a user