Files
cloud-ip-validator/docs/USAGE.md
T

553 lines
38 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.
# Работа со стендом
Этот документ — для оператора, который уже развернул стенд (см.
[SETUP.md](SETUP.md)) и теперь использует его в повседневной работе:
добавляет адреса на проверку, следит за очередью, разбирается в
результатах и реагирует на проблемы. Прямые вызовы API описаны в
[API.md](API.md) — здесь мы используем их только как инструмент, не
углубляясь в протокол.
## Содержание
- [Как устроена работа с системой](#как-устроена-работа-с-системой)
- [Добавление новых IP в очередь](#добавление-новых-ip-в-очередь)
- [Наблюдение за очередью](#наблюдение-за-очередью)
- [Значения полей 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 выше.
## Наблюдение за очередью
Общая сводка:
```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}]'
```
## Значения полей IP
| Поле | Значение |
|---|---|
| `IPAddress` | Проверяемый адрес |
| `Sequence` | Позиция в очереди (порядок постановки — из конфига при первом старте либо из последнего вызова `POST /api/v1/admin/ips`) |
| `State` | Текущий этап: `queued`, `assigning_fip`, `awaiting_self_check`, `checking`, `aggregating`, `done`, `failed` |
| `OwnerValidatorID` | Какой валидатор сейчас (или последним) занимался этим адресом |
| `FIPID` | Идентификатор Floating IP в OpenStack, к которому привязан адрес (пусто, если ещё/уже не привязан) |
| `AttemptNumber` | Номер попытки — растёт при каждом requeue (сбой привязки, сбой self-check, реклейм по таймауту) |
| `RetryCount` | Сколько раз адрес уже переставлялся в очередь заново |
| `EgressComplete` | Валидатор закончил исходящие проверки |
| `Site1Complete` / `Site2Complete` / `Site3Complete` | Соответствующая площадка закончила входящие проверки |
| `OverallResult` | Итог: `pass`, `partial`, `fail`, `cancelled` (принудительно остановлена, см. [«Принудительная остановка проверки»](#принудительная-остановка-проверки)), либо пусто, пока проверка не завершена |
| `AssignedAt` / `AggregatedAt` / `FIPReleasedAt` | Метки времени соответствующих этапов |
## Как читать итоговый результат (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` полезно, чтобы
не путать «адрес не прошёл проверку» с «проверку прервали вручную».
Отсутствие ответа от источника (площадка не прислала результат до
истечения `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)'
```
## Управление валидаторами
Список валидаторов и их текущее состояние:
```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) проверкам, и агрегация не ждёт вообще ни одного
пробера. Указан один или два слота — ждём только их, остальные не
учитываются. Указаны все три — работает как в исходной схеме процесса.
Явного отдельного флага "включить/выключить" нет — самого списка `sites`
достаточно.
Чтобы добавить площадку (без перезапуска control-api) — назначьте
`site_id` на один из трёх слотов (`index` 1, 2 или 3 — см. ограничение
ниже) через 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 выше.
> Важно: количество *возможных* слотов площадок жёстко зашито в схему БД
> (`Site1Complete`/`Site2Complete`/`Site3Complete`) — не более **трёх**,
> как и описано в исходной схеме процесса. `index` может быть только 1, 2
> или 3. Использовать *меньше* трёх (в том числе ноль) — штатный,
> поддерживаемый сценарий; *больше* трёх потребует доработки схемы
> данных, одной правкой конфига не обойтись.
## Управление типами проверок пробера
Список 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.
> Правки через `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` и всю её историю проверок и событий: адрес полностью исчезает,
восстановить его нельзя. Если нужно просто остановить зависшую проверку,
но сохранить её результат в истории — используйте
[«Принудительную остановку проверки»](#принудительная-остановка-проверки)
выше, а не удаление.
Удалить один адрес (работает из любого состояния, включая активно
проверяемое — 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`) никогда не отчитывается (`SiteNComplete` всегда
`false`).**
Проверьте, что `prober` на этой площадке запущен и его `site_id` в
конфиге совпадает с `site_id` в конфиге control-api. Проверьте, что
площадка имеет сетевой доступ и до `control-api`, и до проверяемого
адреса (входящий трафик на 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.