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>
800 lines
60 KiB
Markdown
800 lines
60 KiB
Markdown
# Работа со стендом
|
||
|
||
Этот документ — для оператора, который уже развернул стенд (см.
|
||
[SETUP.md](SETUP.md)) и теперь использует его в повседневной работе:
|
||
добавляет адреса на проверку, следит за очередью, разбирается в
|
||
результатах и реагирует на проблемы. Прямые вызовы API описаны в
|
||
[API.md](API.md) — здесь мы используем их только как инструмент, не
|
||
углубляясь в протокол.
|
||
|
||
> **Токен в примерах.** Если на стенде включена аутентификация
|
||
> ([SETUP.md](SETUP.md#5-аутентификация-токены-и-пароль-дашборда)), к вызовам
|
||
> `/api/v1/admin/*` в примерах `curl` ниже нужно добавлять заголовок
|
||
> `-H "Authorization: Bearer $ADMIN_TOKEN"` (значение `CONTROL_API_ADMIN_TOKEN`);
|
||
> для краткости он опущен. Дашборд запрашивает логин и пароль.
|
||
|
||
## Содержание
|
||
|
||
- [Как устроена работа с системой](#как-устроена-работа-с-системой)
|
||
- [Добавление новых IP в очередь](#добавление-новых-ip-в-очередь)
|
||
- [Сканирование Floating IP из OpenStack](#сканирование-floating-ip-из-openstack)
|
||
- [Автоматический цикл проверок](#автоматический-цикл-проверок)
|
||
- [Наблюдение за очередью](#наблюдение-за-очередью)
|
||
- [Значения полей IP](#значения-полей-ip)
|
||
- [Как читать итоговый результат (pass/partial/fail)](#как-читать-итоговый-результат-passpartialfail)
|
||
- [Просмотр деталей и истории по конкретному адресу](#просмотр-деталей-и-истории-по-конкретному-адресу)
|
||
- [Реестр адресов и глубина истории](#реестр-адресов-и-глубина-истории)
|
||
- [Управление валидаторами](#управление-валидаторами)
|
||
- [Управление площадками (проберами)](#управление-площадками-проберами)
|
||
- [Управление типами проверок пробера](#управление-типами-проверок-пробера)
|
||
- [Управление целями проверки](#управление-целями-проверки)
|
||
- [Повторная проверка адреса](#повторная-проверка-адреса)
|
||
- [Принудительная остановка проверки](#принудительная-остановка-проверки)
|
||
- [Удаление адресов из очереди](#удаление-адресов-из-очереди)
|
||
- [Пауза перед self-check (fip_settle_seconds)](#пауза-перед-self-check-fip_settle_seconds)
|
||
- [Частые проблемы и что с ними делать](#частые-проблемы-и-что-с-ними-делать)
|
||
|
||
## Как устроена работа с системой
|
||
|
||
Оператор не взаимодействует с валидаторами и проберами напрямую — вся
|
||
работа идёт через `control-api`. Цикл жизни одного IP-адреса:
|
||
|
||
1. Адрес встаёт в очередь (`queued`).
|
||
2. Control-api сам находит свободный валидатор, привязывает адрес к нему
|
||
как Floating IP.
|
||
3. Валидатор проверяет, что действительно вышел в интернет именно через
|
||
этот адрес (self-check), затем прогоняет исходящие проверки (HTTPS,
|
||
ICMP, опционально SSH до заданных внешних целей).
|
||
4. Одновременно три внешние площадки проверяют, что этот адрес доступен
|
||
*снаружи* (входящие TCP-подключения на 22/80/443/8080 и ICMP) — это
|
||
ловит блокировки/чёрные списки на конкретных внешних сетях.
|
||
5. Как только все источники (валидатор + 3 площадки) отчитались — или
|
||
истекло время ожидания — control-api подводит итог и освобождает
|
||
адрес (отвязывает Floating IP).
|
||
|
||
Всё это происходит автоматически, без участия оператора. Задача оператора
|
||
— положить адреса в очередь и снять с них результат.
|
||
|
||
## Добавление новых IP в очередь
|
||
|
||
Основной способ — API, без перезапуска процесса:
|
||
|
||
```bash
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/ips \
|
||
-d '{"addresses": ["203.0.113.10", "203.0.113.11"]}'
|
||
```
|
||
|
||
```json
|
||
{"added": ["203.0.113.10", "203.0.113.11"], "requeued": [], "reordered": [], "skipped_in_progress": []}
|
||
```
|
||
|
||
Адреса обрабатываются в порядке, в котором перечислены в `addresses` —
|
||
именно в этом порядке они и встанут в очередь друг за другом. Метод
|
||
идемпотентен относительно уже идущих проверок: адрес, который сейчас
|
||
активно проверяется, в ответе окажется в `skipped_in_progress` и не будет
|
||
тронут (см. [«Повторная проверка адреса»](#повторная-проверка-адреса)
|
||
ниже — тот же метод форсирует перепроверку уже завершённых адресов).
|
||
|
||
Также по-прежнему можно добавить адреса через `ip_addresses` в
|
||
`/etc/cloud-ip-validator/control-api.yaml` и перезапустить control-api —
|
||
при каждом старте control-api доливает в очередь только новые адреса из
|
||
этого списка (уже обработанные ранее не сбрасываются и повторно не
|
||
проверяются). Держать `control-api.yaml` под версионным контролем (git)
|
||
по-прежнему полезно как журнал того, что изначально ставилось в очередь
|
||
при разворачивании стенда — но для повседневного добавления адресов проще
|
||
и быстрее пользоваться API выше.
|
||
|
||
## Сканирование Floating IP из OpenStack
|
||
|
||
Вместо того чтобы перечислять адреса вручную, можно попросить control-api
|
||
самому найти их в облаке:
|
||
|
||
```bash
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/ips/scan # 202: сканирование запущено в фоне
|
||
curl -s http://<control-api>:8080/api/v1/admin/ips/scan # ход и результат
|
||
```
|
||
|
||
Сканируются все Floating IP текущего проекта OpenStack, но в очередь
|
||
ставятся только **свободные** — те, что не привязаны сейчас ни к одному
|
||
порту (это и есть пул адресов, ожидающих проверки перед повторной
|
||
выдачей). Уже привязанные к чему-то Floating IP игнорируются. Внутри
|
||
вызов делает то же самое, что и обычное добавление — новые адреса
|
||
встают в очередь, уже завершённые перезапускаются, активно проверяемые не
|
||
трогаются (см. [выше](#добавление-новых-ip-в-очередь)).
|
||
|
||
**Сколько адресов — не важно.** Сканирование работает в фоне и читает список из OpenStack
|
||
**страницами** (по 200 адресов, с повторами при обрывах), поэтому подходит и для проекта с
|
||
тысячами Floating IP: на стенде с 6441 адресом чтение занимает около 1,5–2 минут. Сначала
|
||
обнаруживаются **все** адреса, и только потом они ставятся в очередь (кусками по 500, в порядке
|
||
возрастания IP); сразу после этого начинаются проверки. Если чтение сорвалось даже после повторов,
|
||
в очередь не попадает ничего — очередь остаётся как была, а на панели виден `error` и причина.
|
||
Одновременно идёт одно сканирование: повторное нажатие присоединяется к текущему.
|
||
|
||
В `admin-dashboard` — кнопка «Сканировать Floating IP» на странице `/ips`: она сразу отвечает, а под
|
||
кнопкой появляется панель прогресса (читаются страницы → ставятся в очередь → готово: прочитано
|
||
страниц, найдено, свободных, добавлено, время), по окончании таблица обновляется сама. Рядом —
|
||
«Пробное сканирование»: оно проходит все страницы и показывает, сколько свободных адресов нашлось,
|
||
**не меняя очередь** (удобно проверить, что облако отвечает и сколько адресов будет поставлено).
|
||
|
||
Параметры чтения (`control-api.yaml`): `openstack.list_page_size` (200), `openstack.request_timeout_seconds`
|
||
(60 — таймаут одного запроса к OpenStack), `openstack.list_page_retries` (5), `orchestrator.fip_scan_timeout_seconds`
|
||
(1800 — предел всего сканирования).
|
||
|
||
Если хочется, чтобы сканирование происходило само по расписанию, а не
|
||
только по запросу — задайте `orchestrator.fip_scan_interval_seconds`
|
||
(в секундах) в `control-api.yaml`; `0` (по умолчанию) оставляет только
|
||
ручной запуск через ручку/кнопку выше. Пока включён
|
||
[автоматический цикл](#автоматический-цикл-проверок), это периодическое
|
||
сканирование не выполняется — цикл сам управляет очередью.
|
||
|
||
> **Сколько займут проверки.** Один адрес занимает около 50 секунд на валидаторе (из них 30 с — пауза
|
||
> `fip_settle_seconds`). Поэтому очередь из 6440 адресов — примерно 18 часов на 5 валидаторах,
|
||
> 9 часов на 10, 4,5 часа на 20. Ускорить можно числом валидаторов и (осторожно) `fip_settle_seconds`;
|
||
> на странице «Обзор» виден прогресс «Готово D из T» и оценка оставшегося времени.
|
||
|
||
## Автоматический цикл проверок
|
||
|
||
Опциональный режим, который сам повторяет то, что оператор делает руками:
|
||
по умолчанию **выключен**, включается и настраивается администратором.
|
||
Один цикл — это пять шагов:
|
||
|
||
1. Очередь очищается целиком — то же, что кнопка «Очистить всё» (см.
|
||
[«Удаление адресов из очереди»](#удаление-адресов-из-очереди)). История
|
||
в [реестре](#реестр-адресов-и-глубина-истории) при этом сохраняется.
|
||
2. Control-api находит все свободные Floating IP и ставит их в очередь —
|
||
то же, что «Сканировать Floating IP» (см.
|
||
[выше](#сканирование-floating-ip-из-openstack)). Шаги 1–2 выполняются одним
|
||
фоновым заданием, поэтому долгое чтение тысяч адресов не блокирует работу
|
||
оркестратора (назначение валидаторов, лизинги, heartbeat).
|
||
3. Проверки запускаются сами — как для любого адреса в очереди.
|
||
4. Цикл ждёт, пока **все** адреса очереди дойдут до конечного состояния
|
||
(`done`, `failed` или `occupied`). К этому моменту результат каждого
|
||
адреса уже записан в реестр.
|
||
5. Выдерживается пауза `interval_seconds`, после чего цикл начинается заново
|
||
с шага 1. Пауза отсчитывается от **завершения** предыдущего цикла, а не
|
||
от его начала.
|
||
|
||
### Параметры
|
||
|
||
| Параметр | По умолчанию | Смысл |
|
||
|---|---|---|
|
||
| `interval_seconds` | `3600` (1 час) | Пауза между циклами. Не меньше `60`: слишком частые сканы нагружают API OpenStack. |
|
||
| `max_run_seconds` | `0` (без лимита) | Сколько максимум ждать на шаге 4 (отсчёт — **от конца сканирования**). По истечении цикл фиксирует `timeout` и переходит к паузе — защита от зависания (нет свободных валидаторов, недоступна площадка). Очередь при этом не трогается: следующий цикл её очистит, а до тех пор видно, что именно не дошло до конца. **При тысячах адресов оставьте `0`** (или задайте больше расчётного времени: 6440 адресов — часы). |
|
||
|
||
Параметры хранятся в базе и меняются на лету, без перезапуска; в `control-api.yaml`
|
||
ничего задавать не нужно. Новый `interval_seconds` применяется к паузе
|
||
**со следующего цикла** — уже идущая пауза досчитывается по старому значению.
|
||
|
||
### Управление
|
||
|
||
Через API (подробности — в [API.md](API.md#автоматический-цикл-проверок)):
|
||
|
||
```bash
|
||
# задать параметры (любое из полей можно опустить)
|
||
curl -s -X PUT http://<control-api>:8080/api/v1/admin/auto-cycle \
|
||
-d '{"interval_seconds": 7200, "max_run_seconds": 1800}'
|
||
|
||
# включить: первый цикл начнётся сразу
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/auto-cycle/start
|
||
|
||
# выключить
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/auto-cycle/stop
|
||
|
||
# посмотреть состояние
|
||
curl -s http://<control-api>:8080/api/v1/admin/auto-cycle
|
||
```
|
||
|
||
В `admin-dashboard` — панель «Автоматический цикл» на странице `/settings`: поля
|
||
«Интервал между циклами» и «Максимальная длительность проверки» (в минутах),
|
||
кнопки «Включить»/«Выключить». Пока автоцикл включён, на странице `/overview`
|
||
в блоке статистики показывается индикатор «Автоцикл активен» с фазой и временем
|
||
следующего запуска.
|
||
|
||
### Фазы и результат последнего цикла
|
||
|
||
`phase` показывает, что происходит сейчас: `idle` (автоцикл выключен или ещё не
|
||
стартовал), `scanning` (шаги 1–2: очистка очереди и чтение/постановка Floating IP),
|
||
`running` (идут проверки — шаги 3–4) и `waiting` (пауза между циклами,
|
||
шаг 5; время следующего запуска — `next_run_at`). Результат последнего цикла
|
||
(`last_outcome`):
|
||
|
||
| Значение | Что произошло |
|
||
|---|---|
|
||
| `completed` | Все адреса дошли до конечного состояния; `runs_total` растёт на 1. |
|
||
| `no_free_ips` | Сканирование не нашло свободных Floating IP — ждать нечего, цикл сразу ушёл в паузу. |
|
||
| `timeout` | Проверки не уложились в `max_run_seconds`. |
|
||
| `error` | Не удалось очистить очередь или просканировать облако; причина — в `last_error`. Повтор — через `interval_seconds`. |
|
||
| `stopped` | Автоцикл выключили в момент, когда шёл цикл. Выключение в паузе предыдущий результат не затирает. |
|
||
|
||
### Что важно знать
|
||
|
||
- **Выключение не прерывает проверки**, которые уже идут: они закончатся и попадут
|
||
в реестр, остановится только повторение. Если выключить цикл во время фазы `scanning`,
|
||
сканирование отменяется (уже поставленные в очередь куски остаются).
|
||
- Автоцикл **владеет очередью**: каждый цикл начинается с её полной очистки,
|
||
поэтому адреса, добавленные вручную, будут удалены (их история в реестре
|
||
остаётся). Ручные «Очистить всё» и «Сканировать Floating IP» во время цикла
|
||
не ломают его: если очередь опустела, цикл считается завершённым.
|
||
- Состояние хранится в базе и **переживает перезапуск** control-api: идущий цикл
|
||
продолжит ждать, а пауза — досчитается до прежнего `next_run_at`.
|
||
- События цикла (`auto_cycle_started`, `auto_cycle_completed`, `auto_cycle_timeout`,
|
||
`auto_cycle_error`, `auto_cycle_stopped`) пишутся в журнал событий вместе с
|
||
`queue_cleared` и `fip_scan`.
|
||
- Если в момент старта цикла уже идёт чужое сканирование (ручное, пробное или по расписанию),
|
||
цикл **дожидается** его окончания и запускает собственное (с очисткой очереди) — присоединяться
|
||
к чужому нельзя: оно могло ничего не поставить в очередь.
|
||
- Если сканирование завершилось ошибкой, очередь уже очищена (шаг 1) и остаётся пустой до следующего
|
||
цикла (`interval_seconds`); исход цикла — `error` с причиной в `last_error`.
|
||
- Цикл на тысячах адресов длится часы; пауза `interval_seconds` отсчитывается после его завершения.
|
||
- В реальном OpenStack отвязка Floating IP после очистки очереди может
|
||
отразиться с задержкой; если скан сразу после неё не увидел свободных адресов,
|
||
цикл завершится с `no_free_ips` и повторится через `interval_seconds`.
|
||
|
||
## Наблюдение за очередью
|
||
|
||
Общая сводка:
|
||
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/status | python3 -m json.tool
|
||
```
|
||
|
||
```json
|
||
{
|
||
"total_ips": 25,
|
||
"ips_by_state": {"queued": 10, "awaiting_self_check": 1, "checking": 3, "done": 10, "failed": 1},
|
||
"total_validators": 4
|
||
}
|
||
```
|
||
|
||
`ips_by_state` — сколько адресов в каждом состоянии прямо сейчас. Если
|
||
хотите наблюдать за прогрессом в реальном времени:
|
||
|
||
```bash
|
||
watch -n 2 'curl -s http://<control-api>:8080/api/v1/admin/status | python3 -m json.tool'
|
||
```
|
||
|
||
Полный список всех адресов со всеми полями:
|
||
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/ips | python3 -m json.tool
|
||
```
|
||
|
||
Только финальные результаты (уже готовые адреса), с помощью `jq`:
|
||
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/ips \
|
||
| jq '[.[] | select(.State=="done" or .State=="failed") | {IPAddress, State, OverallResult}]'
|
||
```
|
||
|
||
В `admin-dashboard` то же самое — страница `/overview`, с поиском по IP и
|
||
фильтром по статусу (`pass`/`partial`/`fail`/`cancelled`) над обеими
|
||
таблицами сразу (см. [DASHBOARD.md](DASHBOARD.md)).
|
||
|
||
## Значения полей IP
|
||
|
||
| Поле | Значение |
|
||
|---|---|
|
||
| `IPAddress` | Проверяемый адрес |
|
||
| `Sequence` | Позиция в очереди (порядок постановки — из конфига при первом старте либо из последнего вызова `POST /api/v1/admin/ips`) |
|
||
| `State` | Текущий этап: `queued`, `assigning_fip`, `awaiting_self_check`, `checking`, `aggregating`, `done`, `failed`, `occupied` (см. ниже) |
|
||
| `OwnerValidatorID` | Какой валидатор сейчас (или последним) занимался этим адресом |
|
||
| `FIPID` | Идентификатор Floating IP в OpenStack, к которому привязан адрес (пусто, если ещё/уже не привязан) |
|
||
| `AttemptNumber` | Номер попытки — растёт при каждом requeue (сбой привязки, сбой self-check, реклейм по таймауту) |
|
||
| `RetryCount` | Сколько раз адрес уже переставлялся в очередь заново |
|
||
| `EgressComplete` | Валидатор закончил исходящие проверки |
|
||
| `OverallResult` | Итог: `pass`, `partial`, `fail`, `cancelled` (принудительно остановлена, см. [«Принудительная остановка проверки»](#принудительная-остановка-проверки)), либо пусто, пока проверка не завершена |
|
||
| `AssignedAt` / `AggregatedAt` / `FIPReleasedAt` | Метки времени соответствующих этапов |
|
||
|
||
> Завершённость входящих проверок по каждой конкретной площадке в этом
|
||
> списке не отображается (площадок теперь может быть сколько угодно, а не
|
||
> фиксированные три) — детали по конкретной площадке смотрите в массиве
|
||
> `checks` ответа `GET /api/v1/admin/ips/{ip}` (`Source: "inbound-site-N"`).
|
||
|
||
## Как читать итоговый результат (pass/partial/fail)
|
||
|
||
- **`pass`** — прошли все проверки: все исходящие, плюс все площадки по
|
||
всем портам и ICMP — если площадки вообще настроены (`sites` в конфиге
|
||
control-api может быть пустым, см.
|
||
[«Управление площадками»](#управление-площадками-проберами) — тогда
|
||
учитываются только исходящие). Адрес можно считать пригодным к
|
||
повторной выдаче.
|
||
- **`partial`** — часть проверок прошла, часть — нет (например, площадка
|
||
site-2 не смогла достучаться по 8080/tcp, но остальное в порядке).
|
||
Означает частичную деградацию — например, адрес заблокирован в
|
||
отдельном сегменте сети/у отдельного провайдера. Требует решения
|
||
оператора: годится ли адрес для данного случая использования.
|
||
- **`fail`** — либо ни одна проверка не прошла, либо адрес вообще не
|
||
дошёл до стадии проверок (например, self-check не подтвердился —
|
||
трафик валидатора не пошёл через назначенный FIP — и попытки
|
||
исчерпались). Смотрите `events` по этому адресу (см. ниже), чтобы
|
||
понять, на каком шаге и почему.
|
||
- **`cancelled`** — проверку остановил оператор через `POST
|
||
/api/v1/admin/ips/{ip}/cancel` (`State` при этом — `failed`), а не
|
||
система по итогам проверок. Отличать от обычного `fail` полезно, чтобы
|
||
не путать «адрес не прошёл проверку» с «проверку прервали вручную».
|
||
|
||
Отдельно от `OverallResult` стоит состояние **`State: "occupied"`** —
|
||
облако живое, и список адресов, переданный как «свободные» (из конфига
|
||
или через `POST /api/v1/admin/ips`), мог с тех пор разойтись с
|
||
реальностью, либо адрес мог быть передан на проверку по ошибке уже
|
||
занятым. Если при попытке привязки Floating IP control-api видит, что тот
|
||
уже привязан к чужому порту, адрес переводится в `occupied` **до начала**
|
||
цикла проверки — `OverallResult` при этом остаётся пустым, это не `fail`:
|
||
`fail` означает «проверка стартовала и не прошла», `occupied` — «проверка
|
||
не стартовала, адрес занят кем-то другим». В `events` по адресу
|
||
появляется строка `fip_occupied`. Автоматических повторных попыток нет
|
||
(Neutron сам не освобождает адрес) — верните адрес в работу вручную через
|
||
`POST /api/v1/admin/ips`, когда убедитесь, что конфликт в облаке
|
||
разрешился; в дашборде для таких адресов также показывается кнопка
|
||
«Перепроверить» вместо «Отменить».
|
||
|
||
Отсутствие ответа от источника (площадка не прислала результат до
|
||
истечения `checking_window_seconds`) засчитывается как провал — это
|
||
управляется настройкой `aggregation.missing_counts_as_fail` в конфиге
|
||
control-api (по умолчанию включено).
|
||
|
||
## Просмотр деталей и истории по конкретному адресу
|
||
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/ips/203.0.113.10 | python3 -m json.tool
|
||
```
|
||
|
||
Ответ содержит три части:
|
||
- `ip` — те же поля, что и в списке `admin/ips`, но для одного адреса;
|
||
- `checks` — все отдельные проверки текущей попытки: кто проверял
|
||
(`Source`: `egress` или `inbound-site-N`), что именно (`CheckType`,
|
||
`Target`), результат (`Success`), задержка (`LatencyMS`), и
|
||
человекочитаемая деталь (`Detail`, например текст ошибки при отказе);
|
||
- `events` — журнал аудита по этому адресу в хронологическом порядке
|
||
(регистрация, привязка FIP, self-check, агрегация и т.д.) — полезен,
|
||
чтобы восстановить точную последовательность событий при разборе
|
||
инцидента.
|
||
|
||
Пример: почему адрес получил `fail`?
|
||
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/ips/203.0.113.10 \
|
||
| jq '.checks[] | select(.Success==false)'
|
||
```
|
||
|
||
Это — только текущая попытка. Полная история адреса за всё время, включая
|
||
предыдущие попытки и даже периоды, когда адрес не стоял в очереди вовсе,
|
||
смотрится через реестр — см. следующий раздел.
|
||
|
||
## Реестр адресов и глубина истории
|
||
|
||
`GET /api/v1/admin/ips/{ip}` (и `/ips/{ip}` в дашборде) показывает только
|
||
*текущую* попытку проверки. Но если адрес удалили из очереди и позже
|
||
добавили заново, это уже новая попытка — а куда девается история старой?
|
||
Она не пропадает: control-api ведёт отдельный **реестр** (`ip_registry`) —
|
||
запись обо всех адресах, когда-либо поставленных на проверку, вместе с
|
||
полной накопленной историей проверок по каждому, независимо от того,
|
||
удалялся ли адрес из очереди и добавлялся ли повторно.
|
||
|
||
```bash
|
||
# все адреса, когда-либо ставившиеся на проверку, с краткой сводкой
|
||
curl -s http://<control-api>:8080/api/v1/admin/registry | python3 -m json.tool
|
||
|
||
# полная история проверок одного адреса, по всем циклам, не только текущему
|
||
curl -s http://<control-api>:8080/api/v1/admin/registry/203.0.113.10 | python3 -m json.tool
|
||
```
|
||
|
||
В `admin-dashboard` — страницы `/registry` (список) и `/registry/{ip}`
|
||
(история конкретного адреса), со ссылкой туда со страницы `/ips/{ip}`.
|
||
На `/registry` — тот же поиск по IP и фильтр по статусу, что и на
|
||
`/overview`, плюс он отражается в адресной строке (`?q=&status=`), так что
|
||
отфильтрованную ссылку можно сохранить или переслать.
|
||
|
||
**Глубина хранения.** Чтобы история не росла бесконечно на адресах,
|
||
которые перепроверяют очень часто, можно ограничить, сколько последних
|
||
циклов проверки хранить на каждый адрес — `history_retention_cycles` на
|
||
странице `/settings` (или `PUT /api/v1/admin/config/orchestrator`, см.
|
||
[API.md](API.md#настройки-оркестратора-apiv1adminconfigorchestrator)).
|
||
`0` (по умолчанию) — хранить без ограничения. Ограничение действует только
|
||
на глубину детальной истории проверок; сама запись в реестре (что адрес
|
||
существует, когда впервые встречен, сколько всего было циклов) не
|
||
удаляется никогда.
|
||
|
||
## Управление валидаторами
|
||
|
||
Список валидаторов и их текущее состояние:
|
||
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/validators | python3 -m json.tool
|
||
```
|
||
|
||
Состояния валидатора: `unregistered` (в конфиге есть, агент ещё не
|
||
подключался), `idle` (свободен, готов взять адрес), `assigned`/`checking`
|
||
(занят), `unreachable` (пропустил heartbeat дольше
|
||
`orchestrator.heartbeat_timeout_seconds`).
|
||
|
||
**Добавление нового валидатора (без перезапуска control-api):**
|
||
1. Поднимите новую ВМ в сервисном проекте облака, узнайте её Neutron
|
||
`port_id`.
|
||
2. Зарегистрируйте валидатора через API:
|
||
```bash
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/config/validators \
|
||
-d '{"validator_id": "validator_05", "os_port_id": "port-abc123"}'
|
||
```
|
||
3. Разверните и запустите `validator-agent` на новой ВМ с тем же
|
||
`validator_id` в его конфиге (см. [SETUP.md](SETUP.md#развёртывание-validator-agent-на-вм-валидаторах)).
|
||
|
||
Сменить `os_port_id` уже существующего валидатора (например, после
|
||
пересоздания ВМ) — `PUT /api/v1/admin/config/validators/{id}` с телом
|
||
`{"os_port_id": "новый-port-id"}`.
|
||
|
||
Полный список зарегистрированных валидаторов — `GET
|
||
/api/v1/admin/config/validators` (в отличие от `GET
|
||
/api/v1/admin/validators`, отдаёт `snake_case` и без текущего IP —
|
||
только конфигурационные поля).
|
||
|
||
**Вывод валидатора из эксплуатации:** остановите на нём
|
||
`validator-agent` (`systemctl stop validator-agent`). Он перестанет
|
||
получать новые задания после того, как закончит текущее (если оно было);
|
||
если он был убит посреди работы — control-api сам заберёт у него
|
||
незавершённый адрес обратно в очередь по истечении
|
||
`orchestrator.lease_ttl_seconds`. Удалять регистрацию валидатора не
|
||
обязательно — просто выключенный агент не будет ничего забирать. Если всё
|
||
же нужно убрать валидатора из системы совсем:
|
||
```bash
|
||
curl -s -X DELETE http://<control-api>:8080/api/v1/admin/config/validators/validator_05
|
||
```
|
||
Возвращает `409`, если валидатор прямо сейчас владеет каким-то IP —
|
||
дождитесь освобождения (или принудительно остановите его проверку, см.
|
||
[«Принудительная остановка проверки»](#принудительная-остановка-проверки))
|
||
перед удалением.
|
||
|
||
> Правки через `validators[]` в `control-api.yaml` тоже поддерживаются,
|
||
> но только как bootstrap пустой базы данных при самом первом старте — как
|
||
> только в БД есть хотя бы один валидатор, YAML для этой секции
|
||
> игнорируется при всех последующих рестартах (см.
|
||
> [SETUP.md](SETUP.md#развёртывание-control-api)). Для стенда, который уже
|
||
> хоть раз запускался, используйте API выше.
|
||
|
||
## Управление площадками (проберами)
|
||
|
||
**Входящие (inbound/prober) проверки полностью опциональны, а число
|
||
площадок не ограничено.** Список `sites` в конфиге control-api и есть
|
||
переключатель: пусто — inbound-проверки выключены целиком, итоговый
|
||
результат считается только по исходящим (egress) проверкам, и агрегация
|
||
не ждёт вообще ни одного пробера. Указано N слотов — ждём именно их.
|
||
Явного отдельного флага "включить/выключить" нет — самого списка `sites`
|
||
достаточно.
|
||
|
||
Чтобы добавить площадку (без перезапуска control-api) — назначьте
|
||
`site_id` любому свободному слоту (`index` — любое целое `>= 1`, слотов
|
||
может быть сколько угодно) через API:
|
||
```bash
|
||
curl -s -X PUT http://<control-api>:8080/api/v1/admin/config/sites/1 \
|
||
-d '{"site_id": "site-1"}'
|
||
```
|
||
и разверните на площадке `prober` с тем же `site_id`. Чтобы отключить
|
||
конкретную площадку — освободите слот:
|
||
```bash
|
||
curl -s -X DELETE http://<control-api>:8080/api/v1/admin/config/sites/1
|
||
```
|
||
процесс `prober` на ней можно не останавливать (он просто перестанет
|
||
получать назначения — `POST /api/v1/probers/register` для отвязанного
|
||
`site_id` начнёт отвечать `400`). Текущее распределение слотов — `GET
|
||
/api/v1/admin/config/sites`.
|
||
|
||
> Правки через `sites[]` в `control-api.yaml` тоже поддерживаются, но
|
||
> только как bootstrap пустой базы данных при самом первом старте — как
|
||
> только в БД есть хотя бы одна площадка, YAML для этой секции
|
||
> игнорируется при всех последующих рестартах. Для стенда, который уже
|
||
> хоть раз запускался, используйте API выше.
|
||
|
||
### Состояния площадки
|
||
|
||
По аналогии с валидаторами (см. [«Управление
|
||
валидаторами»](#управление-валидаторами) выше), у каждой площадки есть
|
||
состояние подключения — видно и в `GET /api/v1/admin/config/sites`
|
||
(поля `hostname`/`state`/`last_heartbeat_at`), и на странице `/sites`
|
||
дашборда бейджем:
|
||
- **`unregistered`** — слот сконфигурирован, но процесс `prober` на этой
|
||
площадке ещё ни разу не подключался (не вызывал `POST
|
||
/api/v1/probers/register`).
|
||
- **`idle`** — площадка на связи: `prober` зарегистрирован и присылает
|
||
heartbeat (`POST /api/v1/probers/{site_id}/heartbeat`) на каждом опросе.
|
||
- **`unreachable`** — площадка пропустила heartbeat дольше
|
||
`orchestrator.heartbeat_timeout_seconds` (тот же параметр, что и для
|
||
валидаторов) — вероятно, процесс `prober` упал или потерял сеть до
|
||
control-api.
|
||
|
||
В отличие от валидатора, у площадки нет состояний `assigned`/`checking`
|
||
— пробер не привязан к одному IP, а на каждом опросе обрабатывает сразу
|
||
весь активный набор.
|
||
|
||
## Управление типами проверок пробера
|
||
|
||
Список TCP-портов и флаг ICMP, которые `prober` проверяет на каждой
|
||
настроенной площадке — единый глобальный набор, общий для всех площадок
|
||
сразу (не то же самое, что список `sites` выше: `sites` решает, *сколько*
|
||
точек его применяют, а этот набор — *что именно* они проверяют).
|
||
|
||
Посмотреть текущий набор:
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/config/inbound-checks | python3 -m json.tool
|
||
```
|
||
|
||
Изменить набор портов и/или ICMP (без перезапуска control-api — новое
|
||
значение сразу видно и следующему опросу пробера, и уже идущей агрегации):
|
||
```bash
|
||
curl -s -X PUT http://<control-api>:8080/api/v1/admin/config/inbound-checks \
|
||
-d '{"ports": [22, 80, 443, 8080], "icmp": true}'
|
||
```
|
||
|
||
Порты должны быть в диапазоне `1..65535` и не повторяться — иначе `400`.
|
||
Пустой список портов вместе с `"icmp": false` — штатный способ временно
|
||
отключить inbound-проверки целиком, не трогая список площадок:
|
||
```bash
|
||
curl -s -X PUT http://<control-api>:8080/api/v1/admin/config/inbound-checks \
|
||
-d '{"ports": [], "icmp": false}'
|
||
```
|
||
|
||
То же самое — на странице `/settings` дашборда, второй формой рядом с
|
||
паузой перед self-check (см. ниже): текстовое поле с портами через запятую
|
||
и чекбокс ICMP.
|
||
|
||
Порты `22` и `443` в этом списке трактуются особо: помимо базового
|
||
TCP-connect (`tcp-22`/`tcp-443`) пробер дополнительно выполняет настоящий
|
||
обмен SSH-банером (`ssh`) и настоящий TLS-хендшейк (`tls-443`) —
|
||
голого открытого TCP-порта недостаточно, чтобы считать SSH/HTTPS
|
||
рабочими. Отдельного переключателя для этих доп.проверок нет: они
|
||
включаются и выключаются вместе с самим портом в `ports`. Если на порту
|
||
22/443 у площадки на самом деле слушает что-то, кроме SSH/HTTPS,
|
||
доп.проверка будет закономерно проваливаться — заведите для такого сервиса
|
||
другой порт.
|
||
|
||
> Правки через `orchestrator.inbound_checks` в `control-api.yaml` тоже
|
||
> поддерживаются, но только как bootstrap пустой базы данных при самом
|
||
> первом старте — как только в БД есть эта настройка (а она появляется
|
||
> сразу же при первом старте, значение по умолчанию — из YAML), YAML для
|
||
> этой секции игнорируется при всех последующих рестартах. Для стенда,
|
||
> который уже хоть раз запускался, используйте API выше.
|
||
|
||
## Управление целями проверки
|
||
|
||
Набор egress-целей (`targets`) и типов проверок (`check_types`,
|
||
привязывающих тип — `https`/`icmp`/`ssh` — к одной или нескольким группам
|
||
целей) управляется через API так же, как валидаторы и площадки —
|
||
изменения подхватываются немедленно, следующим же назначением от
|
||
оркестратора, без перезапуска.
|
||
|
||
Посмотреть текущий набор:
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/config/targets | python3 -m json.tool
|
||
curl -s http://<control-api>:8080/api/v1/admin/config/check-types | python3 -m json.tool
|
||
```
|
||
|
||
Создать/заменить группу целей и включить тип проверки, ссылающийся на
|
||
неё:
|
||
```bash
|
||
curl -s -X PUT http://<control-api>:8080/api/v1/admin/config/targets/web \
|
||
-d '{"targets": ["https://hub.docker.com", "https://github.com"]}'
|
||
|
||
curl -s -X PUT http://<control-api>:8080/api/v1/admin/config/check-types/ssh \
|
||
-d '{"enabled": true, "targets": ["web"]}'
|
||
```
|
||
|
||
Отключить тип проверки, не удаляя его (значения целей сохраняются):
|
||
```bash
|
||
curl -s -X PUT http://<control-api>:8080/api/v1/admin/config/check-types/ssh \
|
||
-d '{"enabled": false, "targets": ["web"]}'
|
||
```
|
||
|
||
Удалить группу целей можно только если на неё не ссылается ни один
|
||
`check_type` (иначе — `409`); удалить сам `check_type` можно в любой
|
||
момент (`DELETE /api/v1/admin/config/check-types/{name}`).
|
||
|
||
**Важное следствие принятого компромисса**: если конфигурация меняется
|
||
ровно в момент, когда чей-то IP уже находится в `checking` (self-check
|
||
уже пройден, проверки уже назначены агенту), агрегация этой конкретной
|
||
попытки посчитает уже изменённую конфигурацию, а не ту, что была на
|
||
момент выдачи задания. На практике это узкое окно в несколько секунд;
|
||
деградирует безопасно — через `aggregation.missing_counts_as_fail` худший
|
||
исход для одной попытки — `partial` вместо `pass`, самоисправляется на
|
||
следующей попытке (в том числе через принудительный повтор, см. ниже).
|
||
|
||
> Правки через `targets`/`check_types` в `control-api.yaml` тоже
|
||
> поддерживаются, но только как bootstrap пустой базы данных при самом
|
||
> первом старте — см. примечание в разделах выше.
|
||
|
||
## Повторная проверка адреса
|
||
|
||
Если адрес завершился с `failed` или `partial`, а вы хотите перепроверить
|
||
его ещё раз (например, после устранения блокировки на стороне сети) —
|
||
отправьте его тем же методом, что используется для постановки новых
|
||
адресов в очередь:
|
||
|
||
```bash
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/ips \
|
||
-d '{"addresses": ["203.0.113.10"]}'
|
||
```
|
||
|
||
```json
|
||
{"added": [], "requeued": ["203.0.113.10"], "reordered": [], "skipped_in_progress": []}
|
||
```
|
||
|
||
Адрес в `requeued` означает, что он был в терминальном состоянии
|
||
(`done`/`failed`) и его перезапустили: `AttemptNumber` увеличился,
|
||
`RetryCount` обнулён, предыдущий `OverallResult` сброшен, адрес снова
|
||
`queued` и будет обработан на общих основаниях. Никакой особой обработки
|
||
для уже проверенных адресов не требуется — тот же вызов безопасно
|
||
принимает список из новых и уже проверенных адресов одновременно;
|
||
единственное, что метод не сделает — не запустит вторую параллельную
|
||
проверку адреса, который прямо сейчас уже проверяется (такой адрес
|
||
вернётся в `skipped_in_progress`, см.
|
||
[«Добавление новых IP в очередь»](#добавление-новых-ip-в-очередь)).
|
||
|
||
## Принудительная остановка проверки
|
||
|
||
Если проверка адреса зависла дольше ожидаемого либо просто больше не
|
||
актуальна, не дожидайтесь истечения `checking_window_seconds` —
|
||
остановите её сразу:
|
||
|
||
```bash
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/ips/203.0.113.10/cancel
|
||
```
|
||
|
||
Работает из любого состояния, кроме уже терминального (`done`/`failed`
|
||
вернут `409` — отменять нечего). Если на момент отмены был привязан
|
||
Floating IP — он отвязывается (best-effort, как и при обычном завершении
|
||
проверки), владевший валидатор освобождается и снова становится `idle`.
|
||
Итог записывается как `OverallResult: "cancelled"` (в `State: "failed"`),
|
||
и виден в истории адреса наравне с обычными результатами:
|
||
|
||
```bash
|
||
curl -s http://<control-api>:8080/api/v1/admin/ips/203.0.113.10 | python3 -m json.tool
|
||
```
|
||
|
||
Чтобы позже всё же проверить этот адрес — используйте
|
||
[«Повторную проверку адреса»](#повторная-проверка-адреса) выше, она
|
||
одинаково работает и для отменённых, и для обычно завершённых адресов.
|
||
|
||
## Удаление адресов из очереди
|
||
|
||
**Отличие от отмены (`cancel`) выше: удаление безвозвратно убирает адрес
|
||
из очереди.** Cancel переводит адрес в `failed`/`cancelled` и сохраняет
|
||
запись как историю — её видно в очереди и в деталях адреса. Delete
|
||
физически стирает строку `ip_queue`: адрес полностью исчезает из
|
||
`/ips`/`/ips/{ip}`, восстановить именно эту строку нельзя. Накопленная
|
||
история проверок при этом **не теряется** — она остаётся в
|
||
[реестре](#реестр-адресов-и-глубина-истории) (`/registry/{ip}`) и видна
|
||
там даже после удаления адреса из очереди. Если нужно просто остановить
|
||
зависшую проверку, но сохранить её результат прямо в очереди —
|
||
используйте
|
||
[«Принудительную остановку проверки»](#принудительная-остановка-проверки)
|
||
выше, а не удаление.
|
||
|
||
Удалить один адрес (работает из любого состояния, включая активно
|
||
проверяемое — Floating IP при этом отвязывается, а владевший валидатор
|
||
освобождается, точно так же, как при cancel):
|
||
|
||
```bash
|
||
curl -s -X DELETE http://<control-api>:8080/api/v1/admin/ips/203.0.113.10
|
||
```
|
||
|
||
Удалить список адресов одним вызовом (неизвестные адреса просто
|
||
попадают в `not_found`, не считаются ошибкой):
|
||
|
||
```bash
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/ips/delete \
|
||
-d '{"addresses": ["203.0.113.10", "203.0.113.11"]}'
|
||
```
|
||
|
||
Полностью очистить очередь — **самая опасная операция**, удаляет вообще
|
||
всё, включая адреса, которые прямо сейчас проверяются:
|
||
|
||
```bash
|
||
curl -s -X POST http://<control-api>:8080/api/v1/admin/ips/clear
|
||
```
|
||
|
||
В `admin-dashboard` то же самое доступно на странице `/ips`: чекбоксы у
|
||
каждой строки + кнопка «Удалить выбранные» для точечного/массового
|
||
удаления, кнопка «Удалить» в каждой строке, и отдельная кнопка «Очистить
|
||
всё» — каждая с подтверждением, явно предупреждающим о необратимости
|
||
(см. [DASHBOARD.md](DASHBOARD.md)).
|
||
|
||
## Пауза перед self-check (fip_settle_seconds)
|
||
|
||
Как только Floating IP привязывается к валидатору, control-api по
|
||
умолчанию сразу же позволяет агенту начать self-check — а data plane
|
||
OpenStack может не успеть в этот же момент реально начать пропускать
|
||
трафик через только что привязанный адрес, из-за чего self-check ложно
|
||
проваливается по причине, не связанной с самой привязкой. Если это
|
||
наблюдается на вашем стенде, задайте паузу между привязкой FIP и началом
|
||
self-check:
|
||
|
||
```bash
|
||
curl -s -X PUT http://<control-api>:8080/api/v1/admin/config/orchestrator \
|
||
-d '{"fip_settle_seconds": 5}'
|
||
```
|
||
|
||
То же самое — на странице `/settings` дашборда. `0` (по умолчанию) — без
|
||
паузы. Пока пауза не истекла, адрес уже в состоянии
|
||
`awaiting_self_check`, но `GET /assignment` агенту продолжает отдавать
|
||
`204` (агент просто ждёт следующего опроса, доработок на его стороне не
|
||
требуется); в дашборде на `/ips` такой адрес в это время помечен бейджем
|
||
«прогрев FIP» вместо обычного статуса.
|
||
|
||
Значение обязано оставлять запас внутри лизинга адреса:
|
||
`fip_settle_seconds + self_check_timeout_seconds` должно быть **меньше**
|
||
`orchestrator.lease_ttl_seconds` — иначе пауза плюс сам self-check не
|
||
влезут в лизинг, адрес не успеет пройти self-check до истечения
|
||
`lease_ttl_seconds` и будет вечно возвращаться в очередь через
|
||
`sweepExpiredLeases`. Попытка задать такое значение отклоняется `400`, не
|
||
обрезается молча.
|
||
|
||
## Частые проблемы и что с ними делать
|
||
|
||
**Валидатор долго висит в `unreachable`.**
|
||
Проверьте сетевую связность ВМ-валидатора до `control-api` (порт из
|
||
`server.listen_addr`) и что процесс `validator-agent` вообще запущен
|
||
(`systemctl status validator-agent`, `journalctl -u validator-agent`).
|
||
|
||
**Адрес не выходит из `awaiting_self_check` (статус не меняется вообще).**
|
||
Если это длится всего несколько секунд и на стенде настроена
|
||
[пауза перед self-check](#пауза-перед-self-check-fip_settle_seconds)
|
||
(`fip_settle_seconds`) — это ожидаемое поведение, не сбой: адрес
|
||
сознательно придерживается, прежде чем агенту разрешат начать проверку.
|
||
Проблема — если статус не меняется значительно дольше этой паузы. Тогда
|
||
дело обычно в self-check: он запрашивает внешние (вне облака) сервисы из
|
||
`self_check.ip_echo_urls` в конфиге валидатора (по умолчанию
|
||
`api.ipify.org`, `ifconfig.me`) — если у ВМ-валидатора нет исходящего
|
||
доступа в интернет к этим адресам, запрос не проходит вообще, и агент
|
||
даже не может *сообщить* результат control-api (ни успешный, ни
|
||
неуспешный) — тогда статус реально зависает до истечения
|
||
`orchestrator.lease_ttl_seconds`, после чего адрес возвращается в
|
||
`queued` и цикл повторяется. Проверьте связность до
|
||
`self_check.ip_echo_urls` прямо с ВМ-валидатора (`curl -s
|
||
https://api.ipify.org`) и логи `journalctl -u validator-agent` на предмет
|
||
`ip echo request failed`.
|
||
|
||
**Адрес постоянно проваливает self-check (не зависает, а именно
|
||
возвращается в очередь снова и снова).**
|
||
Смотрите `events` по адресу (`GET /api/v1/admin/ips/{ip}`) — в детали
|
||
события `self_check_result` будет указан обнаруженный исходящий адрес.
|
||
Если он не совпадает с ожидаемым — вероятно, на ВМ-валидаторе есть другой
|
||
маршрут наружу (не через назначенный Floating IP), либо привязка FIP на
|
||
стороне OpenStack не применилась. Проверьте вручную в OpenStack
|
||
(`openstack floating ip show <адрес>`), что `port_id` совпадает с портом
|
||
валидатора. Обратите внимание: адрес для сравнения обязан быть **вне**
|
||
облака (см. `self_check.ip_echo_urls`) — запрос к чему-либо внутри
|
||
проекта (в том числе к самому control-api, если он в той же внутренней
|
||
сети) покажет приватный адрес валидатора независимо от того, правильно
|
||
ли привязан FIP, и всегда будет давать ложный провал.
|
||
|
||
**Площадка (`site-N`) никогда не отчитывается по конкретному IP.**
|
||
Сперва проверьте статус самой площадки — `GET
|
||
/api/v1/admin/config/sites`, поле `state`. `unregistered` или
|
||
`unreachable` означает, что `prober` на этой площадке вообще не на связи
|
||
с control-api (см. [«Состояния площадки»](#состояния-площадки) выше) —
|
||
проверьте, что процесс запущен и его `site_id` в конфиге совпадает с
|
||
`site_id` в конфиге control-api, и что площадка имеет сетевой доступ до
|
||
`control-api`. Если статус `idle` (площадка на связи), а конкретный IP
|
||
всё равно не получает отметку о завершении — проверьте отдельно
|
||
связность до проверяемого адреса (входящий трафик на 22/80/443/8080 +
|
||
ICMP — это отдельная связность от связи с control-api, см.
|
||
[SETUP.md](SETUP.md#сетевые-доступы)).
|
||
|
||
**Много адресов зависло в `checking` дольше ожидаемого.**
|
||
Это нормально, если ещё не истёк `orchestrator.checking_window_seconds` —
|
||
агрегация ждёт либо полного набора ответов, либо истечения окна. Если
|
||
адрес завис заметно дольше окна — проверьте, что фоновый цикл control-api
|
||
вообще работает (смотрите `journalctl -u control-api` на предмет ошибок
|
||
в `sweep checking window`).
|
||
|
||
**Нужно посмотреть на данные "из первых рук", в обход API.**
|
||
`control-api` использует SQLite, файл — по пути `database.path` из
|
||
конфига. Можно (только для чтения, на **той же машине**, где крутится
|
||
control-api) открыть его `sqlite3` в режиме WAL — это безопасно для
|
||
чтения параллельно с работающим процессом:
|
||
```bash
|
||
sqlite3 /var/lib/cloud-ip-validator/control-api.db \
|
||
"select ip_address, state, overall_result from ip_queue order by sequence"
|
||
```
|
||
Не редактируйте эту базу вручную во время работы control-api — это может
|
||
рассинхронизировать состояние с реальными привязками Floating IP в
|
||
OpenStack.
|