Sprint 0 / #21: dev/staging стенд — docker-compose, тома, netns-харнесс #53
@@ -125,3 +125,70 @@ make dev-down # остановить стенд, каталоги /opt/
|
||||
make dev-reset # + удалить осиротевшие контейнеры/сети проекта
|
||||
make test-netns # netns-харнесс сносит топологию сам; аварийно: bash tests/netns/topology.sh down
|
||||
```
|
||||
|
||||
## 6. Раунд 2 (issue #56): netns в контейнере и покрытие тестов
|
||||
|
||||
Дата: 2026-10-28 · Хост: `192.168.1.147` · Ветка: `feat/21-dev-stand` · Ref: #21, #15, #17, #56
|
||||
|
||||
Ревью qa-engineer (раунд 1) нашло два блокера: `make test-netns-ci` падал в контейнере
|
||||
(`mount of /sys failed: Operation not permitted`, exit 255 вместо 0/1/3/4) и гейт покрытия
|
||||
`pytest tests/deploy` обходился флагом `--no-cov` (0.00 %, `deploy/api_stub.py` 0 %).
|
||||
|
||||
### 6.1 Причина падения netns в контейнере
|
||||
|
||||
Воспроизведено на образе `awg-dash:dev` (iproute2 6.11.0):
|
||||
|
||||
| команда в контейнере | результат |
|
||||
|---|---|
|
||||
| `ip netns add <ns>` | rc=0 |
|
||||
| `ip netns exec <ns> true` | `mount of /sys failed: Operation not permitted`, rc=255 |
|
||||
| `ip -n <ns> link set lo up` | `mount of /sys failed: Operation not permitted`, rc=255 |
|
||||
| `nsenter --net=/var/run/netns/<ns> true` | rc=0 |
|
||||
|
||||
`ip netns exec` и `ip -n` перемонтируют `/sys` внутри namespace; в контейнере это падает.
|
||||
Поэтому харнесс больше не использует эти формы: вход в namespace идёт через `ns_exec()` /
|
||||
`ns_prefix()` (`tests/netns/lib.sh`) и `netns_common.ns_sh()`, которые один раз пробуют
|
||||
`ip netns exec`, а при отказе переключаются на `nsenter --net=...` (`AWG_NS_EXEC_MODE=auto|ip|nsenter`).
|
||||
Все `ip -n "$NS"` заменены на `ns_exec "$NS" ip ...`.
|
||||
|
||||
Коды возврата приведены к контракту `0/1/3/4` (`run.sh`, `topology.sh`): неожиданный код
|
||||
утилиты (255) нормализуется в `4` («ошибка стенда»), нет прав — `3`, упавшие тесты — `1`.
|
||||
|
||||
### 6.2 Реальные прогоны
|
||||
|
||||
| прогон | команда | результат |
|
||||
|---|---|---|
|
||||
| стенд на хосте | `make test-netns` | exit 0, 8 ok / 0 fail, 5.46 s, `ip netns list` пуст, мок и sink не остались в процессах |
|
||||
| стенд в контейнере (путь CI) | `make test-netns-ci` | exit 0, `[netns] вход в netns: nsenter`, backend `iptables`, 8 ok / 0 fail, 5.50 s, `[ ok ] топология снесена`, отчёт `/artifacts/netns-report.json` |
|
||||
| нет прав | `docker run` без `--privileged` | exit **3**, `[blocked] не удалось создать netns — нет CAP_NET_ADMIN/SYS_ADMIN` |
|
||||
| форс нерабочего режима | `AWG_NS_EXEC_MODE=ip` в контейнере | exit **4**, `mount of /sys failed` → `[warn] run.sh: непредвиденный код 255 — трактую как ошибку стенда (4)` |
|
||||
| упавшие тесты | синтетический проваленный тест в контейнере | exit **1**, `[warn] netns-стенд: тесты/очистка упали (код 1)` |
|
||||
| гейт покрытия | `make test-deploy` | exit 0, 51 passed, coverage **98.86 %** (`deploy/api_stub.py` 98 %, `tests/deploy/validate_compose.py` 99 %) |
|
||||
| манифесты / shellcheck | `make test-manifests`, `make lint-shell` | exit 0 / exit 0 |
|
||||
|
||||
### 6.3 Что изменено для гейта покрытия
|
||||
|
||||
* `tests/deploy/pytest.ini` — отдельный профиль: `--cov=deploy --cov=tests/deploy
|
||||
--cov-config=tests/deploy/.coveragerc --cov-fail-under=70`. Раньше `pytest tests/deploy`
|
||||
наследовал addopts корневого `pyproject.toml` (`--cov=awg_agent --cov=awg_api`), поэтому
|
||||
покрытие всегда было 0.00 % и RC=1 — гейт гоняли с `--no-cov` в обход порога.
|
||||
* `tests/deploy/.coveragerc` — из покрытия исключены сами тестовые модули
|
||||
(`tests/deploy/test_*.py`), иначе «покрытие» измеряет тестовый код.
|
||||
* `tests/deploy/test_api_stub.py` — 9 тестов на живой HTTP-сервер заглушки: 200 и
|
||||
`"stub": true` на `/api/v1/health`, алиас `/healthz`, игнор query-string, 404
|
||||
`not_implemented` на прочие пути, HEAD, отказ на POST, разбор аргументов `main()`.
|
||||
* `tests/deploy/test_validate_compose.py` — 39 негативных/граничных тестов валидатора:
|
||||
каждая инварианта AC #21 ломается по отдельности (порт, тома, healthcheck, NET_ADMIN,
|
||||
`/dev/net/tun`, `ip_forward`, privileged netns-сервис, DEV-ONLY-метка, `--require-dockerfile`).
|
||||
* `deploy/api_stub.py` — `make_server()` выделен из `main()` (тесты поднимают сервер на порту 0).
|
||||
* `make test-deploy` — гейт покрытия; `make test-netns-ci` прокидывает `AWG_NS_EXEC_MODE`.
|
||||
|
||||
### 6.4 Что закрыто и что осталось
|
||||
|
||||
Закрыты оба блокера раунда 1 (`make test-netns-ci` работает в контейнере, покрытие
|
||||
измеряется и ≥70 %). `CI green` по-прежнему недостижим: Gitea Actions runner не
|
||||
зарегистрирован (#17), все прогоны в таблице 6.2 — ручные на `192.168.1.147`; команды
|
||||
`make test-netns-ci` и `make test-deploy` — ровно те, что должны попасть в workflow #17.
|
||||
|
||||
Порт и stub-оверрайд (см. §4) без изменений: `privileged: true` и `cap_add SYS_MODULE`
|
||||
из `deploy/docker-compose.test.yml` — только DEV/TEST, для staging/prod непригодны.
|
||||
|
||||
Reference in New Issue
Block a user