From d63b9ceafe2e08d437fbe62ef912a8f49cad02a7 Mon Sep 17 00:00:00 2001 From: embeddevio Date: Wed, 28 Oct 2026 21:32:32 +0300 Subject: [PATCH] =?UTF-8?q?deploy:=20=D1=80=D0=B5=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B3=D0=BE=D0=BD=D1=8B=20?= =?UTF-8?q?=D1=80=D0=B0=D1=83=D0=BD=D0=B4=D0=B0=202=20=D0=B2=20VERIFICATIO?= =?UTF-8?q?N-21=20(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - netns-ci в контейнере: причина (ip netns exec/ip -n перемонтируют /sys), переход на nsenter, контракт кодов 0/1/3/4 — все четыре воспроизведены. - гейт покрытия: make test-deploy = 51 passed, 98.86 %. Refs #21, Refs #15, Refs #56 --- deploy/VERIFICATION-21.md | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/deploy/VERIFICATION-21.md b/deploy/VERIFICATION-21.md index 11349b4..a6415e2 100644 --- a/deploy/VERIFICATION-21.md +++ b/deploy/VERIFICATION-21.md @@ -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 ` | rc=0 | +| `ip netns exec true` | `mount of /sys failed: Operation not permitted`, rc=255 | +| `ip -n link set lo up` | `mount of /sys failed: Operation not permitted`, rc=255 | +| `nsenter --net=/var/run/netns/ 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 непригодны.