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

30 KiB
Raw Blame History

Работа со стендом

Этот документ — для оператора, который уже развернул стенд (см. SETUP.md) и теперь использует его в повседневной работе: добавляет адреса на проверку, следит за очередью, разбирается в результатах и реагирует на проблемы. Прямые вызовы API описаны в API.md — здесь мы используем их только как инструмент, не углубляясь в протокол.

Содержание

Как устроена работа с системой

Оператор не взаимодействует с валидаторами и проберами напрямую — вся работа идёт через 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, без перезапуска процесса:

curl -s -X POST http://<control-api>:8080/api/v1/admin/ips \
  -d '{"addresses": ["203.0.113.10", "203.0.113.11"]}'
{"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 выше.

Наблюдение за очередью

Общая сводка:

curl -s http://<control-api>:8080/api/v1/admin/status | python3 -m json.tool
{
  "total_ips": 25,
  "ips_by_state": {"queued": 10, "awaiting_self_check": 1, "checking": 3, "done": 10, "failed": 1},
  "total_validators": 4
}

ips_by_state — сколько адресов в каждом состоянии прямо сейчас. Если хотите наблюдать за прогрессом в реальном времени:

watch -n 2 'curl -s http://<control-api>:8080/api/v1/admin/status | python3 -m json.tool'

Полный список всех адресов со всеми полями:

curl -s http://<control-api>:8080/api/v1/admin/ips | python3 -m json.tool

Только финальные результаты (уже готовые адреса), с помощью jq:

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 (по умолчанию включено).

Просмотр деталей и истории по конкретному адресу

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?

curl -s http://<control-api>:8080/api/v1/admin/ips/203.0.113.10 \
  | jq '.checks[] | select(.Success==false)'

Управление валидаторами

Список валидаторов и их текущее состояние:

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:
    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).

Сменить 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. Удалять регистрацию валидатора не обязательно — просто выключенный агент не будет ничего забирать. Если всё же нужно убрать валидатора из системы совсем:

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). Для стенда, который уже хоть раз запускался, используйте API выше.

Управление площадками (проберами)

Входящие (inbound/prober) проверки полностью опциональны. Список sites в конфиге control-api и есть переключатель: пусто — inbound- проверки выключены целиком, итоговый результат считается только по исходящим (egress) проверкам, и агрегация не ждёт вообще ни одного пробера. Указан один или два слота — ждём только их, остальные не учитываются. Указаны все три — работает как в исходной схеме процесса. Явного отдельного флага "включить/выключить" нет — самого списка sites достаточно.

Чтобы добавить площадку (без перезапуска control-api) — назначьте site_id на один из трёх слотов (index 1, 2 или 3 — см. ограничение ниже) через API:

curl -s -X PUT http://<control-api>:8080/api/v1/admin/config/sites/1 \
  -d '{"site_id": "site-1"}'

и разверните на площадке prober с тем же site_id. Чтобы отключить конкретную площадку — освободите слот:

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. Использовать меньше трёх (в том числе ноль) — штатный, поддерживаемый сценарий; больше трёх потребует доработки схемы данных, одной правкой конфига не обойтись.

Управление целями проверки

Набор egress-целей (targets) и типов проверок (check_types, привязывающих тип — https/icmp/ssh — к одной или нескольким группам целей) управляется через API так же, как валидаторы и площадки — изменения подхватываются немедленно, следующим же назначением от оркестратора, без перезапуска.

Посмотреть текущий набор:

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

Создать/заменить группу целей и включить тип проверки, ссылающийся на неё:

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"]}'

Отключить тип проверки, не удаляя его (значения целей сохраняются):

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, а вы хотите перепроверить его ещё раз (например, после устранения блокировки на стороне сети) — отправьте его тем же методом, что используется для постановки новых адресов в очередь:

curl -s -X POST http://<control-api>:8080/api/v1/admin/ips \
  -d '{"addresses": ["203.0.113.10"]}'
{"added": [], "requeued": ["203.0.113.10"], "reordered": [], "skipped_in_progress": []}

Адрес в requeued означает, что он был в терминальном состоянии (done/failed) и его перезапустили: AttemptNumber увеличился, RetryCount обнулён, предыдущий OverallResult сброшен, адрес снова queued и будет обработан на общих основаниях. Никакой особой обработки для уже проверенных адресов не требуется — тот же вызов безопасно принимает список из новых и уже проверенных адресов одновременно; единственное, что метод не сделает — не запустит вторую параллельную проверку адреса, который прямо сейчас уже проверяется (такой адрес вернётся в skipped_in_progress, см. «Добавление новых IP в очередь»).

Принудительная остановка проверки

Если проверка адреса зависла дольше ожидаемого либо просто больше не актуальна, не дожидайтесь истечения checking_window_seconds — остановите её сразу:

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"), и виден в истории адреса наравне с обычными результатами:

curl -s http://<control-api>:8080/api/v1/admin/ips/203.0.113.10 | python3 -m json.tool

Чтобы позже всё же проверить этот адрес — используйте «Повторную проверку адреса» выше, она одинаково работает и для отменённых, и для обычно завершённых адресов.

Частые проблемы и что с ними делать

Валидатор долго висит в unreachable. Проверьте сетевую связность ВМ-валидатора до control-api (порт из server.listen_addr) и что процесс validator-agent вообще запущен (systemctl status validator-agent, journalctl -u validator-agent).

Адрес не выходит из 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 (не зависает, а именно возвращается в очередь снова и снова). Смотрите 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).

Много адресов зависло в checking дольше ожидаемого. Это нормально, если ещё не истёк orchestrator.checking_window_seconds — агрегация ждёт либо полного набора ответов, либо истечения окна. Если адрес завис заметно дольше окна — проверьте, что фоновый цикл control-api вообще работает (смотрите journalctl -u control-api на предмет ошибок в sweep checking window).

Нужно посмотреть на данные "из первых рук", в обход API. control-api использует SQLite, файл — по пути database.path из конфига. Можно (только для чтения, на той же машине, где крутится control-api) открыть его sqlite3 в режиме WAL — это безопасно для чтения параллельно с работающим процессом:

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.