2026-08-21 07:34:45 +03:00
|
|
|
|
# Работа со стендом
|
|
|
|
|
|
|
|
|
|
|
|
Этот документ — для оператора, который уже развернул стенд (см.
|
|
|
|
|
|
[SETUP.md](SETUP.md)) и теперь использует его в повседневной работе:
|
|
|
|
|
|
добавляет адреса на проверку, следит за очередью, разбирается в
|
|
|
|
|
|
результатах и реагирует на проблемы. Прямые вызовы API описаны в
|
|
|
|
|
|
[API.md](API.md) — здесь мы используем их только как инструмент, не
|
|
|
|
|
|
углубляясь в протокол.
|
|
|
|
|
|
|
|
|
|
|
|
## Содержание
|
|
|
|
|
|
|
|
|
|
|
|
- [Как устроена работа с системой](#как-устроена-работа-с-системой)
|
|
|
|
|
|
- [Добавление новых IP в очередь](#добавление-новых-ip-в-очередь)
|
|
|
|
|
|
- [Наблюдение за очередью](#наблюдение-за-очередью)
|
|
|
|
|
|
- [Значения полей IP](#значения-полей-ip)
|
|
|
|
|
|
- [Как читать итоговый результат (pass/partial/fail)](#как-читать-итоговый-результат-passpartialfail)
|
|
|
|
|
|
- [Просмотр деталей и истории по конкретному адресу](#просмотр-деталей-и-истории-по-конкретному-адресу)
|
|
|
|
|
|
- [Управление валидаторами](#управление-валидаторами)
|
|
|
|
|
|
- [Управление площадками (проберами)](#управление-площадками-проберами)
|
|
|
|
|
|
- [Повторная проверка адреса](#повторная-проверка-адреса)
|
|
|
|
|
|
- [Частые проблемы и что с ними делать](#частые-проблемы-и-что-с-ними-делать)
|
|
|
|
|
|
|
|
|
|
|
|
## Как устроена работа с системой
|
|
|
|
|
|
|
|
|
|
|
|
Оператор не взаимодействует с валидаторами и проберами напрямую — вся
|
|
|
|
|
|
работа идёт через `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 в очередь
|
|
|
|
|
|
|
|
|
|
|
|
**В текущей версии добавление адресов происходит только через конфиг
|
|
|
|
|
|
control-api**, отдельного API-метода "добавить IP в очередь" нет.
|
|
|
|
|
|
|
|
|
|
|
|
1. Добавьте новые адреса в список `ip_addresses` в
|
|
|
|
|
|
`/etc/cloud-ip-validator/control-api.yaml` (в конец списка, либо в
|
|
|
|
|
|
нужном порядке — очередь обрабатывается строго в порядке следования
|
|
|
|
|
|
списка, `sequence`).
|
|
|
|
|
|
2. Перезапустите control-api:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
systemctl restart control-api
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Это безопасно для уже идущей работы: при старте control-api добавляет в
|
|
|
|
|
|
очередь только **новые** адреса (те, которых там ещё нет) — уже
|
|
|
|
|
|
обработанные ранее адреса не сбрасываются и повторно не проверяются.
|
|
|
|
|
|
Адреса, которые были удалены из `ip_addresses`, но уже есть в базе,
|
|
|
|
|
|
**не удаляются** из очереди/истории автоматически — если конкретный адрес
|
|
|
|
|
|
больше не нужно проверять и его нет в очереди/в процессе, можно просто
|
|
|
|
|
|
оставить как есть (историю он не портит).
|
|
|
|
|
|
|
|
|
|
|
|
> Совет: держите `control-api.yaml` под версионным контролем (git) —
|
|
|
|
|
|
> список адресов на проверку тогда одновременно служит и журналом того,
|
|
|
|
|
|
> что вообще когда-либо ставилось в очередь.
|
|
|
|
|
|
|
|
|
|
|
|
## Наблюдение за очередью
|
|
|
|
|
|
|
|
|
|
|
|
Общая сводка:
|
|
|
|
|
|
|
|
|
|
|
|
```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` | Позиция в очереди (порядок из конфига) |
|
|
|
|
|
|
| `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`, либо пусто, пока проверка не завершена |
|
|
|
|
|
|
| `AssignedAt` / `AggregatedAt` / `FIPReleasedAt` | Метки времени соответствующих этапов |
|
|
|
|
|
|
|
|
|
|
|
|
## Как читать итоговый результат (pass/partial/fail)
|
|
|
|
|
|
|
2026-08-21 11:25:52 +03:00
|
|
|
|
- **`pass`** — прошли все проверки: все исходящие, плюс все площадки по
|
|
|
|
|
|
всем портам и ICMP — если площадки вообще настроены (`sites` в конфиге
|
|
|
|
|
|
control-api может быть пустым, см.
|
|
|
|
|
|
[«Управление площадками»](#управление-площадками-проберами) — тогда
|
|
|
|
|
|
учитываются только исходящие). Адрес можно считать пригодным к
|
|
|
|
|
|
повторной выдаче.
|
2026-08-21 07:34:45 +03:00
|
|
|
|
- **`partial`** — часть проверок прошла, часть — нет (например, площадка
|
|
|
|
|
|
site-2 не смогла достучаться по 8080/tcp, но остальное в порядке).
|
|
|
|
|
|
Означает частичную деградацию — например, адрес заблокирован в
|
|
|
|
|
|
отдельном сегменте сети/у отдельного провайдера. Требует решения
|
|
|
|
|
|
оператора: годится ли адрес для данного случая использования.
|
|
|
|
|
|
- **`fail`** — либо ни одна проверка не прошла, либо адрес вообще не
|
|
|
|
|
|
дошёл до стадии проверок (например, self-check не подтвердился —
|
|
|
|
|
|
трафик валидатора не пошёл через назначенный FIP — и попытки
|
|
|
|
|
|
исчерпались). Смотрите `events` по этому адресу (см. ниже), чтобы
|
|
|
|
|
|
понять, на каком шаге и почему.
|
|
|
|
|
|
|
|
|
|
|
|
Отсутствие ответа от источника (площадка не прислала результат до
|
|
|
|
|
|
истечения `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`).
|
|
|
|
|
|
|
|
|
|
|
|
**Добавление нового валидатора:**
|
|
|
|
|
|
1. Поднимите новую ВМ в сервисном проекте облака, узнайте её Neutron
|
|
|
|
|
|
`port_id`.
|
|
|
|
|
|
2. Добавьте запись в `validators` в `control-api.yaml`
|
|
|
|
|
|
(`validator_id` + `os_port_id`) и перезапустите `control-api`.
|
|
|
|
|
|
3. Разверните и запустите `validator-agent` на новой ВМ с тем же
|
|
|
|
|
|
`validator_id` в его конфиге (см. [SETUP.md](SETUP.md#развёртывание-validator-agent-на-вм-валидаторах)).
|
|
|
|
|
|
|
|
|
|
|
|
**Вывод валидатора из эксплуатации:** остановите на нём
|
|
|
|
|
|
`validator-agent` (`systemctl stop validator-agent`). Он перестанет
|
|
|
|
|
|
получать новые задания после того, как закончит текущее (если оно было);
|
|
|
|
|
|
если он был убит посреди работы — control-api сам заберёт у него
|
|
|
|
|
|
незавершённый адрес обратно в очередь по истечении
|
|
|
|
|
|
`orchestrator.lease_ttl_seconds`. Удалять запись из `control-api.yaml`
|
|
|
|
|
|
не обязательно — просто выключенный агент не будет ничего забирать.
|
|
|
|
|
|
|
|
|
|
|
|
## Управление площадками (проберами)
|
|
|
|
|
|
|
2026-08-21 11:25:52 +03:00
|
|
|
|
**Входящие (inbound/prober) проверки полностью опциональны.** Список
|
|
|
|
|
|
`sites` в конфиге control-api и есть переключатель: пусто — inbound-
|
|
|
|
|
|
проверки выключены целиком, итоговый результат считается только по
|
|
|
|
|
|
исходящим (egress) проверкам, и агрегация не ждёт вообще ни одного
|
|
|
|
|
|
пробера. Указан один или два слота — ждём только их, остальные не
|
|
|
|
|
|
учитываются. Указаны все три — работает как в исходной схеме процесса.
|
|
|
|
|
|
Явного отдельного флага "включить/выключить" нет — самого списка `sites`
|
|
|
|
|
|
достаточно.
|
2026-08-21 07:34:45 +03:00
|
|
|
|
|
2026-08-21 11:25:52 +03:00
|
|
|
|
Чтобы добавить площадку: добавьте `site_id` + `index` (1, 2 или 3 — см.
|
|
|
|
|
|
ограничение ниже) в `sites` конфига control-api и разверните на площадке
|
|
|
|
|
|
`prober` с тем же `site_id`. Чтобы отключить конкретную площадку —
|
|
|
|
|
|
уберите соответствующую запись из `sites` и перезапустите control-api;
|
|
|
|
|
|
процесс `prober` на ней можно не останавливать (он просто перестанет
|
|
|
|
|
|
получать назначения).
|
|
|
|
|
|
|
|
|
|
|
|
> Важно: количество *возможных* слотов площадок жёстко зашито в схему БД
|
|
|
|
|
|
> (`Site1Complete`/`Site2Complete`/`Site3Complete`) — не более **трёх**,
|
|
|
|
|
|
> как и описано в исходной схеме процесса. `index` может быть только 1, 2
|
|
|
|
|
|
> или 3. Использовать *меньше* трёх (в том числе ноль) — штатный,
|
|
|
|
|
|
> поддерживаемый сценарий; *больше* трёх потребует доработки схемы
|
|
|
|
|
|
> данных, одной правкой конфига не обойтись.
|
2026-08-21 07:34:45 +03:00
|
|
|
|
|
|
|
|
|
|
## Повторная проверка адреса
|
|
|
|
|
|
|
|
|
|
|
|
Если адрес завершился с `failed` или `partial`, а вы хотите перепроверить
|
|
|
|
|
|
его ещё раз (например, после устранения блокировки на стороне сети):
|
|
|
|
|
|
на данный момент нет отдельного API-метода "перезапустить проверку".
|
|
|
|
|
|
Самый простой путь:
|
|
|
|
|
|
1. Убедитесь, что адрес не находится в активном состоянии (`checking`
|
|
|
|
|
|
и т.п.) — то есть уже `done`/`failed`.
|
|
|
|
|
|
2. Временно уберите и снова добавьте адрес в список `ip_addresses`
|
|
|
|
|
|
(либо просто пересоздайте запись в БД вручную, если это единичный
|
|
|
|
|
|
случай и у вас есть доступ к SQLite) и перезапустите `control-api`.
|
|
|
|
|
|
|
|
|
|
|
|
Поскольку сидирование очереди идёт по уникальности `ip_address`
|
|
|
|
|
|
(конфликт по уже существующей записи просто игнорируется), самый чистый
|
|
|
|
|
|
способ гарантированно перепроверить конкретный адрес — обратиться к
|
|
|
|
|
|
администратору БД (см. следующий раздел) либо дождаться штатной
|
|
|
|
|
|
доработки API под повторные проверки.
|
|
|
|
|
|
|
|
|
|
|
|
## Частые проблемы и что с ними делать
|
|
|
|
|
|
|
|
|
|
|
|
**Валидатор долго висит в `unreachable`.**
|
|
|
|
|
|
Проверьте сетевую связность ВМ-валидатора до `control-api` (порт из
|
|
|
|
|
|
`server.listen_addr`) и что процесс `validator-agent` вообще запущен
|
|
|
|
|
|
(`systemctl status validator-agent`, `journalctl -u validator-agent`).
|
|
|
|
|
|
|
2026-08-21 11:04:49 +03:00
|
|
|
|
**Адрес не выходит из `awaiting_self_check` (статус не меняется вообще).**
|
|
|
|
|
|
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 (не зависает, а именно
|
|
|
|
|
|
возвращается в очередь снова и снова).**
|
2026-08-21 07:34:45 +03:00
|
|
|
|
Смотрите `events` по адресу (`GET /api/v1/admin/ips/{ip}`) — в детали
|
|
|
|
|
|
события `self_check_result` будет указан обнаруженный исходящий адрес.
|
|
|
|
|
|
Если он не совпадает с ожидаемым — вероятно, на ВМ-валидаторе есть другой
|
|
|
|
|
|
маршрут наружу (не через назначенный Floating IP), либо привязка FIP на
|
|
|
|
|
|
стороне OpenStack не применилась. Проверьте вручную в OpenStack
|
|
|
|
|
|
(`openstack floating ip show <адрес>`), что `port_id` совпадает с портом
|
2026-08-21 11:04:49 +03:00
|
|
|
|
валидатора. Обратите внимание: адрес для сравнения обязан быть **вне**
|
|
|
|
|
|
облака (см. `self_check.ip_echo_urls`) — запрос к чему-либо внутри
|
|
|
|
|
|
проекта (в том числе к самому control-api, если он в той же внутренней
|
|
|
|
|
|
сети) покажет приватный адрес валидатора независимо от того, правильно
|
|
|
|
|
|
ли привязан FIP, и всегда будет давать ложный провал.
|
2026-08-21 07:34:45 +03:00
|
|
|
|
|
|
|
|
|
|
**Площадка (`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.
|