repo init
This commit is contained in:
commit
7e44db87b2
48 files changed
+5346
No files matched your search
+376
@@ -0,0 +1,376 @@
|
||||
# API Control API
|
||||
|
||||
Control API — единственная точка входа в систему для `validator-agent`,
|
||||
`prober` и оператора (администратора). Все данные передаются в формате
|
||||
JSON, базовый префикс прикладных методов — `/api/v1`.
|
||||
|
||||
> **Важно.** На данный момент API не защищён аутентификацией/авторизацией
|
||||
> — эндпоинты доступны любому, кто может достучаться до порта control-api
|
||||
> по сети. Для эксплуатации за пределами доверенного сегмента сети
|
||||
> обязательно ограничьте доступ на уровне сети/файрвола (см.
|
||||
> [SETUP.md](SETUP.md#сетевые-доступы)). Добавление bearer-токена — известное
|
||||
> направление доработки, в текущей версии не реализовано.
|
||||
|
||||
Базовый URL в примерах — `http://control-api.internal:8080`, замените на
|
||||
адрес вашего стенда (см. `server.listen_addr` в конфиге control-api).
|
||||
|
||||
## Содержание
|
||||
|
||||
- [Общие соглашения](#общие-соглашения)
|
||||
- [Методы для validator-agent](#методы-для-validator-agent)
|
||||
- [Методы для prober](#методы-для-prober)
|
||||
- [Служебные и административные методы](#служебные-и-административные-методы)
|
||||
- [Модель состояний и связь методов с ней](#модель-состояний-и-связь-методов-с-ней)
|
||||
- [Сквозной пример работы (curl)](#сквозной-пример-работы-curl)
|
||||
|
||||
## Общие соглашения
|
||||
|
||||
- Тело запроса и ответа — JSON (`Content-Type: application/json`).
|
||||
- Успешные ответы возвращают `200 OK`, либо `204 No Content` (когда
|
||||
данных нет — например, у валидатора сейчас нет назначения).
|
||||
- Ошибки возвращают `4xx`/`5xx` и тело вида:
|
||||
```json
|
||||
{"error": "текст ошибки"}
|
||||
```
|
||||
- Временные метки (`checked_at` в запросах) передаются в формате
|
||||
RFC3339/RFC3339Nano, например `2026-08-21T09:15:00.123456789Z`. Если поле
|
||||
не удалось распарсить, сервер молча подставит текущее время сервера — не
|
||||
полагайтесь на это в продакшене, всегда передавайте валидную метку.
|
||||
- `validator_id` и `site_id` в пути запроса должны совпадать со
|
||||
значениями, заданными в конфиге control-api (`validators[].validator_id`,
|
||||
`sites[].site_id`) — иначе методы, требующие существующую сущность,
|
||||
вернут `404`.
|
||||
|
||||
## Методы для validator-agent
|
||||
|
||||
Эти методы вызывает бинарник `validator-agent`, работающий на ВМ-валидаторе.
|
||||
Оператору вручную дёргать их обычно не требуется — они приведены для
|
||||
понимания протокола и для отладки через curl.
|
||||
|
||||
### `POST /api/v1/agents/register`
|
||||
|
||||
Регистрация/переактивация валидатора. Вызывается один раз при старте
|
||||
агента (и безопасно при каждом рестарте — идемпотентна).
|
||||
|
||||
Запрос:
|
||||
```json
|
||||
{
|
||||
"validator_id": "validator_01",
|
||||
"hostname": "vm-validator-01",
|
||||
"agent_version": "1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
Ответ:
|
||||
```json
|
||||
{"ok": true, "poll_interval_seconds": 5}
|
||||
```
|
||||
|
||||
`poll_interval_seconds` — рекомендованный интервал опроса, значение берётся
|
||||
из `orchestrator.poll_interval_seconds` конфига control-api.
|
||||
|
||||
> `validator_id` должен быть заранее описан в конфиге control-api
|
||||
> (`validators[].validator_id`) вместе с `os_port_id` — сам агент порт ID
|
||||
> не передаёт и не может его сменить через API.
|
||||
|
||||
### `POST /api/v1/agents/{id}/heartbeat`
|
||||
|
||||
"Я жив". Обновляет `last_heartbeat_at` валидатора. Если валидатор не
|
||||
присылает heartbeat дольше `orchestrator.heartbeat_timeout_seconds`, он
|
||||
помечается `unreachable`.
|
||||
|
||||
Запрос (тело необязательно, поля информационные):
|
||||
```json
|
||||
{"local_state": "idle"}
|
||||
```
|
||||
|
||||
Ответ: `{"ok": true}`. `404`, если `validator_id` не зарегистрирован.
|
||||
|
||||
### `GET /api/v1/agents/{id}/assignment`
|
||||
|
||||
Есть ли у валидатора сейчас работа. Опрашивается в каждом цикле.
|
||||
|
||||
- `204 No Content` — заданий нет.
|
||||
- `200 OK` с телом:
|
||||
```json
|
||||
{
|
||||
"ip_id": 42,
|
||||
"ip_address": "203.0.113.10",
|
||||
"phase": "awaiting_self_check",
|
||||
"check_config": [
|
||||
{"type": "https", "targets": ["https://hub.docker.com", "https://github.com", "https://packages.ubuntu.com"]},
|
||||
{"type": "icmp", "targets": ["https://hub.docker.com", "https://github.com", "https://packages.ubuntu.com"]}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`phase` — `awaiting_self_check` (нужно выполнить self-check) либо
|
||||
`checking` (self-check уже пройден, можно/нужно выполнять проверки).
|
||||
`check_config` — уже развёрнутая конфигурация проверок (тип + список
|
||||
целей), агенту не нужно самому сопоставлять группы целей.
|
||||
|
||||
### `POST /api/v1/agents/{id}/self-check`
|
||||
|
||||
Отчёт о результате self-check — подтверждение, что исходящий трафик
|
||||
валидатора действительно идёт через только что назначенный FIP. Агент
|
||||
определяет это, вызвав `GET /api/v1/whatsmyip` и сравнив ответ с
|
||||
`ip_address` из задания.
|
||||
|
||||
Запрос:
|
||||
```json
|
||||
{
|
||||
"ip_id": 42,
|
||||
"detected_egress_ip": "203.0.113.10",
|
||||
"success": true,
|
||||
"detail": "matched"
|
||||
}
|
||||
```
|
||||
|
||||
Ответ: `{"ok": true}`. При `success: false` control-api сам решает —
|
||||
повторить попытку назначения FIP или пометить IP как `failed` (после
|
||||
исчерпания `orchestrator.max_self_check_retries`).
|
||||
|
||||
### `POST /api/v1/agents/{id}/events`
|
||||
|
||||
Произвольная запись в журнал аудита, привязанная (опционально) к IP.
|
||||
Используется агентом для событий `config_received`, `self_check_result`
|
||||
и т.п.
|
||||
|
||||
Запрос:
|
||||
```json
|
||||
{
|
||||
"event_type": "config_received",
|
||||
"ip_id": 42,
|
||||
"payload": "{\"checks\":2}"
|
||||
}
|
||||
```
|
||||
|
||||
Ответ: `{"ok": true}`.
|
||||
|
||||
### `POST /api/v1/agents/{id}/results`
|
||||
|
||||
Отчёт о результатах исходящих (egress) проверок. Можно отправлять по
|
||||
одной проверке сразу после выполнения (рекомендуется — так прогресс не
|
||||
теряется при падении агента) либо пачкой.
|
||||
|
||||
Запрос:
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{
|
||||
"ip_id": 42,
|
||||
"check_type": "https",
|
||||
"target": "https://github.com",
|
||||
"success": true,
|
||||
"latency_ms": 87,
|
||||
"detail": "ok",
|
||||
"checked_at": "2026-08-21T09:15:00.123Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Ответ: `{"ok": true}`. Повторная отправка того же `(ip_id, check_type,
|
||||
target)` в рамках текущей попытки — безопасна и просто перезапишет
|
||||
результат (upsert по уникальному ключу).
|
||||
|
||||
### `POST /api/v1/agents/{id}/complete`
|
||||
|
||||
Сигнал "все исходящие проверки для этого IP выполнены".
|
||||
|
||||
Запрос:
|
||||
```json
|
||||
{"ip_id": 42}
|
||||
```
|
||||
|
||||
Ответ: `{"ok": true}`.
|
||||
|
||||
## Методы для prober
|
||||
|
||||
Эти методы вызывает бинарник `prober`, работающий на внешней площадке.
|
||||
|
||||
### `POST /api/v1/probers/register`
|
||||
|
||||
Регистрация пробера. `site_id` должен присутствовать в конфиге control-api
|
||||
(`sites[].site_id`), иначе — `400`.
|
||||
|
||||
Запрос:
|
||||
```json
|
||||
{"site_id": "site-1", "hostname": "probe-host-1"}
|
||||
```
|
||||
|
||||
Ответ: `{"ok": true, "poll_interval_seconds": 5}`.
|
||||
|
||||
### `GET /api/v1/probers/{site_id}/assignments`
|
||||
|
||||
Список всех IP, которые сейчас находятся в состоянии `checking` — то есть
|
||||
всё, что нужно прозондировать на этом цикле опроса (валидаторов может
|
||||
работать несколько параллельно, поэтому список, а не один IP).
|
||||
|
||||
Ответ:
|
||||
```json
|
||||
[
|
||||
{"ip_id": 42, "ip_address": "203.0.113.10", "ports": [22, 80, 443, 8080], "icmp": true}
|
||||
]
|
||||
```
|
||||
|
||||
Пустой список `[]`, если сейчас нечего проверять.
|
||||
|
||||
### `POST /api/v1/probers/{site_id}/results`
|
||||
|
||||
Отчёт о результатах входящих (inbound) проверок с данной площадки.
|
||||
|
||||
Запрос:
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{"ip_id": 42, "ip_address": "203.0.113.10", "check_type": "tcp-22", "success": true, "latency_ms": 12, "checked_at": "2026-08-21T09:15:01Z", "complete": false},
|
||||
{"ip_id": 42, "ip_address": "203.0.113.10", "check_type": "tcp-80", "success": true, "latency_ms": 9, "checked_at": "2026-08-21T09:15:01Z", "complete": false},
|
||||
{"ip_id": 42, "ip_address": "203.0.113.10", "check_type": "tcp-443", "success": true, "latency_ms": 10, "checked_at": "2026-08-21T09:15:01Z", "complete": false},
|
||||
{"ip_id": 42, "ip_address": "203.0.113.10", "check_type": "tcp-8080","success": false,"latency_ms": 0, "checked_at": "2026-08-21T09:15:01Z", "complete": false},
|
||||
{"ip_id": 42, "ip_address": "203.0.113.10", "check_type": "icmp", "success": true, "latency_ms": 5, "checked_at": "2026-08-21T09:15:01Z", "complete": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`complete: true` нужно проставить ровно на одном (обычно последнем)
|
||||
результате в пачке — это сигнал "площадка N закончила зондирование этого
|
||||
IP на данном проходе". До этого момента control-api не будет считать
|
||||
данные с этой площадки завершёнными.
|
||||
|
||||
Ответ: `{"ok": true}`.
|
||||
|
||||
## Служебные и административные методы
|
||||
|
||||
### `GET /healthz`
|
||||
|
||||
Проверка живости процесса. Ответ: `{"ok": true}`. Используется в systemd/
|
||||
внешних системах мониторинга.
|
||||
|
||||
### `GET /api/v1/whatsmyip`
|
||||
|
||||
Возвращает IP-адрес, с которого пришёл TCP-запрос (без учёта заголовков
|
||||
`X-Forwarded-For` — специально, чтобы self-check нельзя было подделать).
|
||||
Это основа механизма self-check.
|
||||
|
||||
Ответ:
|
||||
```json
|
||||
{"ip": "203.0.113.10"}
|
||||
```
|
||||
|
||||
### `GET /api/v1/admin/status`
|
||||
|
||||
Сводка по очереди — сколько IP в каком состоянии.
|
||||
|
||||
```json
|
||||
{
|
||||
"total_ips": 25,
|
||||
"ips_by_state": {"queued": 10, "checking": 3, "done": 11, "failed": 1},
|
||||
"total_validators": 4
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /api/v1/admin/ips`
|
||||
|
||||
Полный список всех IP из очереди со всеми полями (см.
|
||||
[USAGE.md](USAGE.md#значения-полей-ip) — расшифровка полей и статусов).
|
||||
|
||||
### `GET /api/v1/admin/ips/{ip}`
|
||||
|
||||
Детали по одному адресу: сам объект IP, все проверки текущей попытки и
|
||||
вся история событий по нему.
|
||||
|
||||
```json
|
||||
{
|
||||
"ip": { "ID": 42, "IPAddress": "203.0.113.10", "State": "done", "OverallResult": "pass", "...": "..." },
|
||||
"checks": [ {"Source": "egress", "CheckType": "https", "Target": "https://github.com", "Success": true, "...": "..."} ],
|
||||
"events": [ {"EventType": "fip_associated", "OccurredAt": "...", "...": "..."} ]
|
||||
}
|
||||
```
|
||||
|
||||
> Обратите внимание: вложенные объекты `ip`/`checks`/`events` сериализуются
|
||||
> без переопределения имён полей (используются имена Go-структур, например
|
||||
> `IPAddress`, `State`, `Success`) — в отличие от методов для
|
||||
> agent/prober, где поля в `snake_case`. Это осознанная асимметрия:
|
||||
> административные методы — для человека/дашборда, а не для машинного
|
||||
> протокола.
|
||||
|
||||
### `GET /api/v1/admin/validators`
|
||||
|
||||
Список всех валидаторов с их текущим состоянием (`unregistered`, `idle`,
|
||||
`assigned`, `checking`, `unreachable`) и `CurrentIPID`, если валидатор
|
||||
сейчас занят.
|
||||
|
||||
## Модель состояний и связь методов с ней
|
||||
|
||||
```
|
||||
queued ──(control-api сам, без вызова API)──▶ assigning_fip
|
||||
│
|
||||
OpenStack FIP associate успешен
|
||||
▼
|
||||
awaiting_self_check
|
||||
│
|
||||
POST .../self-check {success:true}
|
||||
▼
|
||||
checking
|
||||
│ POST .../results (agent) │ POST .../results (prober, x3 площадки)
|
||||
▼ ▼
|
||||
egress_complete=true siteN_complete=true (N=1,2,3)
|
||||
│
|
||||
все complete=true ИЛИ истекло checking_window_seconds
|
||||
▼
|
||||
aggregating
|
||||
│
|
||||
done (pass/partial/fail)
|
||||
или failed
|
||||
```
|
||||
|
||||
Переходы `queued → assigning_fip → awaiting_self_check` и финальная
|
||||
агрегация выполняются control-api самостоятельно по таймеру (см.
|
||||
`orchestrator.poll_interval_seconds`), явного HTTP-метода для их запуска
|
||||
нет — это фоновый цикл (`Tick`), а не запрос/ответ.
|
||||
|
||||
## Сквозной пример работы (curl)
|
||||
|
||||
Ниже — минимальный ручной прогон одного IP через API, как если бы вы
|
||||
писали собственного клиента вместо `validator-agent`/`prober`. Полезно
|
||||
для отладки и для понимания протокола.
|
||||
|
||||
```bash
|
||||
BASE=http://127.0.0.1:8080
|
||||
|
||||
# 1. Регистрация валидатора (validator_01 уже должен быть в конфиге control-api)
|
||||
curl -s -X POST "$BASE/api/v1/agents/register" \
|
||||
-d '{"validator_id":"validator_01","hostname":"debug-host","agent_version":"manual"}'
|
||||
|
||||
# 2. Подождать, пока control-api (фоновым тиком) назначит IP и привяжет FIP —
|
||||
# проверяем через admin/status или admin/ips, либо просто опрашиваем assignment
|
||||
curl -s "$BASE/api/v1/agents/validator_01/assignment"
|
||||
# => {"ip_id":1,"ip_address":"203.0.113.10","phase":"awaiting_self_check","check_config":[...]}
|
||||
|
||||
# 3. Self-check: спросить у control-api, каким адресом мы к нему пришли
|
||||
curl -s "$BASE/api/v1/whatsmyip"
|
||||
# => {"ip":"203.0.113.10"} (в реальном стенде это и есть проверка через FIP)
|
||||
|
||||
curl -s -X POST "$BASE/api/v1/agents/validator_01/self-check" \
|
||||
-d '{"ip_id":1,"detected_egress_ip":"203.0.113.10","success":true,"detail":"matched"}'
|
||||
|
||||
# 4. Отправить результаты egress-проверок (по одному check_config пункту)
|
||||
curl -s -X POST "$BASE/api/v1/agents/validator_01/results" \
|
||||
-d '{"results":[{"ip_id":1,"check_type":"https","target":"https://github.com","success":true,"latency_ms":80,"checked_at":"2026-08-21T09:00:00Z"}]}'
|
||||
|
||||
# 5. Сообщить, что все egress-проверки выполнены
|
||||
curl -s -X POST "$BASE/api/v1/agents/validator_01/complete" -d '{"ip_id":1}'
|
||||
|
||||
# 6. Со стороны пробера: узнать, что сейчас проверяется, и отправить результат
|
||||
curl -s -X POST "$BASE/api/v1/probers/register" -d '{"site_id":"site-1"}'
|
||||
curl -s "$BASE/api/v1/probers/site-1/assignments"
|
||||
curl -s -X POST "$BASE/api/v1/probers/site-1/results" \
|
||||
-d '{"results":[{"ip_id":1,"ip_address":"203.0.113.10","check_type":"icmp","success":true,"latency_ms":5,"checked_at":"2026-08-21T09:00:01Z","complete":true}]}'
|
||||
|
||||
# 7. Проверить итоговый результат (после того как control-api агрегирует)
|
||||
curl -s "$BASE/api/v1/admin/ips/203.0.113.10" | python3 -m json.tool
|
||||
```
|
||||
|
||||
Для полностью автоматизированного локального прогона (без ручных curl)
|
||||
см. `scripts/run-local-e2e.sh` и [docs/LOCAL_E2E.md](LOCAL_E2E.md).
|
||||
@@ -0,0 +1,92 @@
|
||||
# Local end-to-end smoke test
|
||||
|
||||
`scripts/run-local-e2e.sh` runs the full system as local processes with no
|
||||
real OpenStack cloud and no real internet access:
|
||||
|
||||
- **control-api** with `openstack.mode: mock` — the in-memory
|
||||
`openstack.MockClient` stands in for Neutron, pre-seeded with one
|
||||
synthetic floating IP per configured address (see
|
||||
`cmd/control-api/main.go`'s `newOpenStackClient`).
|
||||
- **1 validator-agent** (`validator_01`), started with
|
||||
`-stub-ports 12022,18081,18443,18888` — trivial accept-and-close TCP
|
||||
listeners standing in for the base-minimum services (22/80/443/8080) a
|
||||
real validator would run. ICMP needs no stub: the kernel answers echo
|
||||
requests to any local address (127.0.0.0/8) on its own.
|
||||
- **3 probers** (`site-1`/`site-2`/`site-3`), all probing `127.0.0.1`.
|
||||
- **3 `httpstub` instances** (`scripts/httpstub`) standing in for the real
|
||||
outbound targets (hub.docker.com / github.com / packages.ubuntu.com),
|
||||
always returning `200 OK`.
|
||||
|
||||
The generated config uses a short `lease_ttl_seconds: 8` and
|
||||
`checking_window_seconds: 15` so the whole run finishes in well under a
|
||||
minute instead of using the (much longer) production defaults.
|
||||
|
||||
**Why only one IP address (`127.0.0.1`), and why it must be exactly that
|
||||
one:** the self-check mechanism (`GET /whatsmyip`, see
|
||||
`internal/httpapi/server.go`'s `remoteIP`) compares the TCP source address
|
||||
the validator-agent's own outbound connection to control-api arrives with
|
||||
against the address it was just assigned. In a real deployment, Neutron
|
||||
actually SNATs the validator's egress traffic through whichever floating
|
||||
IP is attached, so any configured address self-checks correctly. This
|
||||
offline harness has no real network-level SNAT — the agent's traffic to
|
||||
control-api always really originates from `127.0.0.1` — so only that
|
||||
literal loopback address can ever pass self-check here. This is a
|
||||
limitation of the harness's fidelity, not of the self-check mechanism
|
||||
itself.
|
||||
|
||||
## Running it
|
||||
|
||||
```
|
||||
scripts/run-local-e2e.sh
|
||||
```
|
||||
|
||||
It will:
|
||||
|
||||
1. Build all three binaries plus `httpstub` into a temp workdir.
|
||||
2. Start the 3 stub HTTP targets, control-api, the validator-agent, and the
|
||||
3 probers.
|
||||
3. Wait for `GET /healthz` to come up.
|
||||
4. A few seconds in, **kill the validator-agent mid-run** and wait past the
|
||||
8s lease TTL, to demonstrate that control-api's lease sweep reclaims the
|
||||
in-flight IP (moves it back to `queued`, bumps `retry_count`) without
|
||||
any special crash-recovery code — it's the same sweep that runs every
|
||||
tick. It then restarts the validator-agent so the queue can finish.
|
||||
5. Poll `GET /api/v1/admin/status` until every configured IP has reached a
|
||||
terminal state (`done` or `failed`).
|
||||
6. Print the final `/api/v1/admin/status` and `/api/v1/admin/ips` output.
|
||||
|
||||
Expect to see `127.0.0.1` end with `"state":"done"` and
|
||||
`"overall_result":"pass"` (all egress checks against the stub targets
|
||||
succeed, and all 3 probers can reach the stub TCP listeners and get ICMP
|
||||
replies from loopback).
|
||||
|
||||
## Inspecting a run
|
||||
|
||||
The workdir (printed at the end, `/tmp/cloud-ip-validator-e2e.XXXXXX`) is
|
||||
**not** deleted automatically, so you can inspect:
|
||||
|
||||
- `logs/control-api.log`, `logs/validator-agent.log`, `logs/prober-site-*.log`
|
||||
- `control-api.db` — open with `sqlite3` to inspect the `checks` and
|
||||
`events` tables directly, e.g.:
|
||||
```
|
||||
sqlite3 /tmp/cloud-ip-validator-e2e.XXXXXX/control-api.db \
|
||||
"select ip_address, source, check_type, success from checks order by id"
|
||||
```
|
||||
|
||||
## What this does *not* cover
|
||||
|
||||
This harness proves the orchestration, HTTP protocol, and check-running
|
||||
logic all work together correctly. It does **not** exercise the real
|
||||
`internal/openstack/client.go` (gophercloud) path — that only runs against
|
||||
`openstack.mode: real` with actual OpenStack credentials. That path has its
|
||||
own read-only smoke test, `internal/openstack/client_live_test.go`, skipped
|
||||
by default and gated behind `OPENSTACK_LIVE_TEST=1`:
|
||||
|
||||
```
|
||||
OPENSTACK_LIVE_TEST=1 \
|
||||
OS_AUTH_URL=https://keystone.example:5000/v3 \
|
||||
OS_TOKEN=... \
|
||||
OS_PROJECT_ID=... \
|
||||
OS_TEST_FLOATING_IP=203.0.113.10 \
|
||||
go test ./internal/openstack/... -run TestClientLive -v
|
||||
```
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
# Подготовка стенда и первичная инициализация
|
||||
|
||||
Документ описывает, как собрать компоненты, подготовить конфигурацию и
|
||||
запустить стенд с нуля — от чистой машины до работающего control-api,
|
||||
валидаторов и проберов. Если нужно просто быстро посмотреть систему в
|
||||
работе без реального OpenStack — сразу переходите к разделу
|
||||
[«Быстрая проверка без OpenStack»](#быстрая-проверка-без-openstack-offline-режим).
|
||||
|
||||
## Содержание
|
||||
|
||||
- [Компоненты и роли машин](#компоненты-и-роли-машин)
|
||||
- [Требования](#требования)
|
||||
- [Сборка бинарников](#сборка-бинарников)
|
||||
- [Быстрая проверка без OpenStack (offline-режим)](#быстрая-проверка-без-openstack-offline-режим)
|
||||
- [Подготовка конфигурации для реального стенда](#подготовка-конфигурации-для-реального-стенда)
|
||||
- [Развёртывание control-api](#развёртывание-control-api)
|
||||
- [Развёртывание validator-agent на ВМ-валидаторах](#развёртывание-validator-agent-на-вм-валидаторах)
|
||||
- [Развёртывание prober на внешних площадках](#развёртывание-prober-на-внешних-площадках)
|
||||
- [Проверка после запуска](#проверка-после-запуска)
|
||||
- [Сетевые доступы](#сетевые-доступы)
|
||||
|
||||
## Компоненты и роли машин
|
||||
|
||||
| Компонент | Где запускается | Кол-во |
|
||||
|---|---|---|
|
||||
| `control-api` | Отдельная управляющая машина/ВМ с доступом к OpenStack API | 1 (без HA) |
|
||||
| `validator-agent` | Каждая ВМ-валидатор в сервисном проекте облака | по числу валидаторов |
|
||||
| `prober` | По одному на каждой из внешних тестовых площадок | 3 (по числу площадок) |
|
||||
|
||||
`control-api` — единственный компонент с состоянием (SQLite). Валидаторы и
|
||||
проберы не хранят локального состояния и полностью управляются через опрос
|
||||
control-api (см. [API.md](API.md)).
|
||||
|
||||
## Требования
|
||||
|
||||
- **Go 1.22+** для сборки (проверено на Go 1.26). Собранные бинарники —
|
||||
статические, дополнительных зависимостей на целевых машинах не требуют
|
||||
(используется чистый Go-драйвер SQLite, без cgo).
|
||||
- Для `control-api` в боевом режиме (`openstack.mode: real`) — учётная
|
||||
запись OpenStack с правами на чтение/изменение floating IP (Neutron)
|
||||
в сервисном проекте, и заранее выделенные (allocated) floating IP —
|
||||
инструмент их **не создаёт**, только привязывает/отвязывает
|
||||
существующие.
|
||||
- Для `validator-agent` и `prober` — возможность отправлять ICMP echo
|
||||
(нужен root либо capability `CAP_NET_RAW`, см. юниты systemd).
|
||||
- `curl`, `sqlite3` (опционально, для ручной инспекции БД) на машине с
|
||||
control-api пригодятся для диагностики.
|
||||
|
||||
## Сборка бинарников
|
||||
|
||||
Из корня репозитория:
|
||||
|
||||
```bash
|
||||
export PATH=$PATH:/usr/local/go/bin # если go не в PATH
|
||||
go build -o bin/control-api ./cmd/control-api
|
||||
go build -o bin/validator-agent ./cmd/validator-agent
|
||||
go build -o bin/prober ./cmd/prober
|
||||
```
|
||||
|
||||
Каждый бинарник самодостаточен — скопируйте нужный файл на
|
||||
соответствующую машину (control-api → управляющая машина, validator-agent
|
||||
→ каждый валидатор, prober → каждая площадка).
|
||||
|
||||
Убедиться, что всё собирается и юнит-тесты проходят:
|
||||
|
||||
```bash
|
||||
go build ./... && go test ./...
|
||||
```
|
||||
|
||||
## Быстрая проверка без OpenStack (offline-режим)
|
||||
|
||||
Прежде чем разворачивать реальный стенд, рекомендуется убедиться, что всё
|
||||
собирается и работает корректно на локальной машине — без облака и
|
||||
внешних площадок:
|
||||
|
||||
```bash
|
||||
scripts/run-local-e2e.sh
|
||||
```
|
||||
|
||||
Скрипт сам поднимает control-api (в режиме `openstack.mode: mock`),
|
||||
одного validator-agent и трёх проберов как локальные процессы, прогоняет
|
||||
один тестовый адрес через полный цикл проверки и печатает итоговый
|
||||
результат. Подробности — в [docs/LOCAL_E2E.md](LOCAL_E2E.md). Это же
|
||||
хороший способ разобраться в поведении системы перед первым боевым
|
||||
запуском.
|
||||
|
||||
## Подготовка конфигурации для реального стенда
|
||||
|
||||
Все три компонента конфигурируются YAML-файлами. Шаблоны лежат в
|
||||
`configs/*.example.yaml` — скопируйте их и заполните под ваш стенд.
|
||||
|
||||
### 1. `control-api.yaml`
|
||||
|
||||
```bash
|
||||
cp configs/control-api.example.yaml /etc/cloud-ip-validator/control-api.yaml
|
||||
```
|
||||
|
||||
Что обязательно нужно заполнить:
|
||||
|
||||
- **`validators`** — список валидаторов, у каждого `validator_id`
|
||||
(произвольное имя, должно совпадать с `validator_id` в конфиге
|
||||
соответствующего `validator-agent`) и `os_port_id` — **ID Neutron-порта**
|
||||
основного сетевого интерфейса ВМ-валидатора (узнать: `openstack port
|
||||
list --server <имя-ВМ>` или в веб-консоли облака).
|
||||
- **`sites`** — три внешние площадки, `site_id` + `index` (1, 2 или 3).
|
||||
`site_id` должен совпадать с `site_id` в конфиге соответствующего
|
||||
`prober`.
|
||||
- **`ip_addresses`** — список публичных IPv4-адресов на проверку, **в
|
||||
порядке обработки**. Адреса должны существовать в сервисном проекте как
|
||||
уже выделенные (allocated) floating IP — инструмент их не создаёт.
|
||||
- **`openstack.mode: "real"`** и `*_env` поля — имена переменных
|
||||
окружения, из которых будут прочитаны реальные учётные данные (сами
|
||||
значения в этот файл **не пишутся**, см. следующий пункт).
|
||||
- **`targets`** и **`check_types`** — при необходимости смените набор
|
||||
целей для egress-проверок (по умолчанию — hub.docker.com, github.com,
|
||||
packages.ubuntu.com) или включите `ssh` (по умолчанию выключен).
|
||||
|
||||
### 2. Переменные окружения для OpenStack
|
||||
|
||||
Учётные данные передаются **только** через переменные окружения — никогда
|
||||
через YAML. Создайте файл (доступный на чтение только сервисному
|
||||
пользователю):
|
||||
|
||||
```bash
|
||||
install -m 0600 -o cloud-ip-validator -g cloud-ip-validator /dev/null /etc/cloud-ip-validator/control-api.env
|
||||
cat >> /etc/cloud-ip-validator/control-api.env <<'EOF'
|
||||
OS_AUTH_URL=https://keystone.example.com:5000/v3
|
||||
OS_TOKEN=<токен администратора с правами на управление floating IP>
|
||||
OS_PROJECT_ID=<id сервисного проекта>
|
||||
OS_REGION_NAME=<регион>
|
||||
EOF
|
||||
```
|
||||
|
||||
Имена переменных должны совпадать с тем, что указано в
|
||||
`control-api.yaml` в секции `openstack` (`auth_url_env`, `token_env` и
|
||||
т.д.) — в шаблоне это ровно `OS_AUTH_URL`, `OS_TOKEN`, `OS_PROJECT_ID`,
|
||||
`OS_PROJECT_NAME`, `OS_PROJECT_DOMAIN_NAME`, `OS_REGION_NAME`.
|
||||
|
||||
### 3. `validator-agent.yaml` (свой на каждом валидаторе)
|
||||
|
||||
```bash
|
||||
cp configs/validator-agent.example.yaml /etc/cloud-ip-validator/validator-agent.yaml
|
||||
```
|
||||
|
||||
Обязательно поменять:
|
||||
- `validator_id` — должен совпадать с одним из `validators[].validator_id`
|
||||
в конфиге control-api.
|
||||
- `control_api_url` — адрес, по которому эта ВМ достучится до control-api.
|
||||
|
||||
### 4. `prober.yaml` (свой на каждой площадке)
|
||||
|
||||
```bash
|
||||
cp configs/prober.example.yaml /etc/cloud-ip-validator/prober.yaml
|
||||
```
|
||||
|
||||
Обязательно поменять:
|
||||
- `site_id` — должен совпадать с одним из `sites[].site_id` в конфиге
|
||||
control-api (для трёх площадок — три разных файла с `site-1`,
|
||||
`site-2`, `site-3` или как вы их назвали).
|
||||
- `control_api_url` — адрес control-api, доступный с площадки (обычно
|
||||
через интернет — площадки внешние).
|
||||
|
||||
## Развёртывание control-api
|
||||
|
||||
```bash
|
||||
useradd --system --no-create-home --shell /usr/sbin/nologin cloud-ip-validator
|
||||
mkdir -p /var/lib/cloud-ip-validator /etc/cloud-ip-validator
|
||||
chown cloud-ip-validator:cloud-ip-validator /var/lib/cloud-ip-validator
|
||||
|
||||
cp bin/control-api /usr/local/bin/control-api
|
||||
cp deploy/systemd/control-api.service /etc/systemd/system/
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now control-api
|
||||
```
|
||||
|
||||
**Первичная инициализация базы данных происходит автоматически** — при
|
||||
первом старте `control-api` создаёт файл SQLite по пути `database.path`
|
||||
из конфига (миграция схемы применяется один раз, повторные запуски —
|
||||
no-op). Отдельной команды "init db" не требуется.
|
||||
|
||||
При каждом старте control-api также:
|
||||
1. Регистрирует в БД всех валидаторов из `validators` конфига (если их
|
||||
там ещё нет).
|
||||
2. Добавляет в очередь все адреса из `ip_addresses`, которых там ещё нет
|
||||
(уже обработанные ранее адреса повторно не добавляются и не
|
||||
сбрасываются — см. [USAGE.md](USAGE.md#добавление-новых-ip-в-очередь)).
|
||||
|
||||
Проверить, что процесс поднялся:
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8080/healthz
|
||||
# {"ok":true}
|
||||
journalctl -u control-api -f
|
||||
```
|
||||
|
||||
## Развёртывание validator-agent на ВМ-валидаторах
|
||||
|
||||
Повторить на каждой ВМ-валидаторе:
|
||||
|
||||
```bash
|
||||
cp bin/validator-agent /usr/local/bin/validator-agent
|
||||
cp deploy/systemd/validator-agent.service /etc/systemd/system/
|
||||
mkdir -p /etc/cloud-ip-validator
|
||||
# скопировать сюда заполненный validator-agent.yaml с уникальным validator_id
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now validator-agent
|
||||
journalctl -u validator-agent -f
|
||||
```
|
||||
|
||||
Юнит выдаёт процессу capability `CAP_NET_RAW` (без root) — она нужна для
|
||||
отправки ICMP echo в рамках проверок.
|
||||
|
||||
## Развёртывание prober на внешних площадках
|
||||
|
||||
Аналогично, на каждой из трёх площадок:
|
||||
|
||||
```bash
|
||||
cp bin/prober /usr/local/bin/prober
|
||||
cp deploy/systemd/prober.service /etc/systemd/system/
|
||||
mkdir -p /etc/cloud-ip-validator
|
||||
# скопировать сюда prober.yaml с уникальным site_id для этой площадки
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now prober
|
||||
journalctl -u prober -f
|
||||
```
|
||||
|
||||
## Проверка после запуска
|
||||
|
||||
После того как control-api, все валидаторы и все три пробера запущены:
|
||||
|
||||
```bash
|
||||
curl -s http://<control-api>:8080/api/v1/admin/status | python3 -m json.tool
|
||||
```
|
||||
|
||||
Ожидаемая картина сразу после старта: часть адресов в состоянии `queued`,
|
||||
часть уже переходит в `assigning_fip`/`awaiting_self_check`/`checking` по
|
||||
мере того, как освобождаются валидаторы. Через некоторое время появляются
|
||||
записи в `done`/`failed`. Подробнее о том, как читать этот вывод и что
|
||||
делать дальше — в [USAGE.md](USAGE.md).
|
||||
|
||||
Также стоит убедиться, что все валидаторы видны и не «зависли»:
|
||||
|
||||
```bash
|
||||
curl -s http://<control-api>:8080/api/v1/admin/validators | python3 -m json.tool
|
||||
```
|
||||
|
||||
Все зарегистрированные валидаторы должны рано или поздно оказываться в
|
||||
состоянии `idle` (между заданиями) — если валидатор надолго застрял в
|
||||
`unreachable`, проверьте сетевую связность до control-api и логи агента
|
||||
(`journalctl -u validator-agent`).
|
||||
|
||||
## Сетевые доступы
|
||||
|
||||
Минимально необходимая связность:
|
||||
|
||||
- `validator-agent` → `control-api`: TCP, порт из `server.listen_addr`
|
||||
(обычно 8080).
|
||||
- `prober` (на каждой из 3 площадок) → `control-api`: тот же порт, обычно
|
||||
через интернет.
|
||||
- `prober` → адрес, который в данный момент проверяется (динамический,
|
||||
меняется по ходу работы очереди): TCP 22/80/443/8080 + ICMP —
|
||||
собственно и есть проверяемый трафик, его нельзя заранее ограничить
|
||||
одним IP.
|
||||
- `validator-agent` → интернет: HTTPS/ICMP до целей из `targets` конфига
|
||||
(по умолчанию hub.docker.com, github.com, packages.ubuntu.com) — именно
|
||||
через floating IP, который в данный момент привязан к валидатору.
|
||||
- `control-api` → OpenStack Keystone/Neutron API (`OS_AUTH_URL` и далее по
|
||||
каталогу сервисов).
|
||||
|
||||
API control-api сейчас не аутентифицирован (см. предупреждение в начале
|
||||
[API.md](API.md)) — ограничивайте доступ к порту control-api на уровне
|
||||
сети/firewall теми хостами, где реально работают валидаторы и проберы.
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
# Работа со стендом
|
||||
|
||||
Этот документ — для оператора, который уже развернул стенд (см.
|
||||
[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)
|
||||
|
||||
- **`pass`** — прошли все проверки (все исходящие + все три площадки по
|
||||
всем портам и ICMP). Адрес можно считать пригодным к повторной выдаче.
|
||||
- **`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`
|
||||
не обязательно — просто выключенный агент не будет ничего забирать.
|
||||
|
||||
## Управление площадками (проберами)
|
||||
|
||||
Аналогично валидаторам: чтобы добавить площадку, добавьте `site_id` +
|
||||
`index` (свободный от 1 до 3, или больше — но текущая схема БД
|
||||
рассчитана ровно на 3 площадки, см. ниже) в `sites` конфига control-api,
|
||||
разверните на площадке `prober` с тем же `site_id`.
|
||||
|
||||
> Важно: количество площадок в текущей версии жёстко зашито в схему БД
|
||||
> (`Site1Complete`/`Site2Complete`/`Site3Complete`) — система рассчитана
|
||||
> ровно на **три** внешние площадки, как и описано в исходной схеме
|
||||
> процесса. Изменение их числа потребует доработки схемы данных, это не
|
||||
> делается только правкой конфига.
|
||||
|
||||
## Повторная проверка адреса
|
||||
|
||||
Если адрес завершился с `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`).
|
||||
|
||||
**Адрес постоянно проваливает self-check.**
|
||||
Смотрите `events` по адресу (`GET /api/v1/admin/ips/{ip}`) — в детали
|
||||
события `self_check_result` будет указан обнаруженный исходящий адрес.
|
||||
Если он не совпадает с ожидаемым — вероятно, на ВМ-валидаторе есть другой
|
||||
маршрут наружу (не через назначенный Floating IP), либо привязка FIP на
|
||||
стороне OpenStack не применилась. Проверьте вручную в OpenStack
|
||||
(`openstack floating ip show <адрес>`), что `port_id` совпадает с портом
|
||||
валидатора.
|
||||
|
||||
**Площадка (`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.
|
||||
Reference in new issue
Block a user