deploy(#21): tests/netns/ci.sh — точка входа netns-стенда для CI без make

GNU make отдаёт 2 на любой упавший рецепт, поэтому контракт 0/1/3/4 через
`make test-netns-ci` до пайплайна #17 не доходит. ci.sh запускает тот же
контейнер (docker compose -f deploy/docker-compose.test.yml run --rm -T netns)
и возвращает его код как есть. Дополнительно: AWG_NS_PRIVILEGED=0 — прогон без
--privileged (проверка ветки «код 3»), AWG_DASH_TEST_ARTIFACTS — каталог отчёта.

Refs #21
Refs #56
This commit is contained in:
2026-10-28 21:58:04 +03:00
parent e672901741
commit b612a3450c
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
# ci.sh — точка входа netns-стенда для CI (#17), минуя make (issue #56).
#
# Зачем отдельный скрипт: GNU make возвращает 2 на любой упавший рецепт, поэтому
# контракт кодов run.sh (0 — тесты прошли, 1 — тесты упали, 3 — нет прав на netns,
# 4 — сломан стенд) через `make test-netns-ci` до пайплайна не доходит. ci.sh
# запускает контейнер напрямую и возвращает его код как есть — workflow отличает
# «раннеру не дали CAP_NET_ADMIN» от «регрессия стенда».
#
# tests/netns/ci.sh # прогон стенда, код 0/1/3/4
# tests/netns/ci.sh --no-tests # только поднять топологию
# tests/netns/ci.sh --keep-topology # оставить топологию для отладки
# AWG_NS_PRIVILEGED=0 tests/netns/ci.sh # ветка «нет прав» → ожидаем код 3
#
# Переменные окружения:
# AWG_DASH_IMAGE образ с харнессом (по умолчанию awg-dash:dev)
# AWG_NS_EXEC_MODE auto|ip|nsenter — вход в netns (issue #56)
# NETNS_EXEC_MODE make-алиас того же (Makefile прокидывает его сюда)
# AWG_NS_PRIVILEGED 1 (по умолчанию) — как в compose; 0 — прогон без
# privileged (проверка ветки «код 3»)
# AWG_DASH_TEST_ARTIFACTS каталог артефактов (по умолчанию <repo>/artifacts)
# COMPOSE_PROJECT_NAME имя compose-проекта (по умолчанию awg-dash-test)
#
# Коды возврата: 0/1/3/4 — как у run.sh; 2 — ошибка вызова или окружения
# (нет docker/compose/образа, неизвестный аргумент). Ветку 2 CI не должен
# путать с 3: 2 — сломан сам пайплайн/раннер, 3 — раннер без прав на netns.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
COMPOSE_FILE="$ROOT/deploy/docker-compose.test.yml"
IMAGE="${AWG_DASH_IMAGE:-awg-dash:dev}"
ARTIFACTS="${AWG_DASH_TEST_ARTIFACTS:-$ROOT/artifacts}"
export COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-awg-dash-test}"
# AWG_NS_EXEC_MODE — документированное имя, NETNS_EXEC_MODE — алиас из Makefile.
NS_MODE="${AWG_NS_EXEC_MODE:-${NETNS_EXEC_MODE:-auto}}"
case "$NS_MODE" in
auto|ip|nsenter) ;;
*)
echo "[ci][fail] AWG_NS_EXEC_MODE='${NS_MODE}' — ожидается auto|ip|nsenter" >&2
exit 2
;;
esac
export AWG_NS_EXEC_MODE="$NS_MODE"
die() { echo "[ci][fail] $*" >&2; exit 2; }
[ -f "$COMPOSE_FILE" ] || die "нет ${COMPOSE_FILE} (задача #21)"
command -v docker >/dev/null 2>&1 || die "нет docker в PATH — CI-раннер должен быть с docker (#17)"
docker compose version >/dev/null 2>&1 || die "нет docker compose v2 в PATH (#17)"
docker image inspect "$IMAGE" >/dev/null 2>&1 \
|| die "нет образа ${IMAGE}: соберите его (make build после мержа #18) или задайте AWG_DASH_IMAGE"
mkdir -p "$ARTIFACTS"
export AWG_DASH_TEST_ARTIFACTS="$ARTIFACTS"
export AWG_DASH_IMAGE="$IMAGE"
COMPOSE_ARGS=(-f "$COMPOSE_FILE")
CLEANUP_DIR=""
PRIVILEGED="${AWG_NS_PRIVILEGED:-1}"
if [ "$PRIVILEGED" = "0" ]; then
# Оверрайд снимает privileged у сервиса netns — проверка ветки «код 3».
CLEANUP_DIR="$(mktemp -d -t awg-ci-XXXXXX)"
printf 'services:\n netns:\n privileged: false\n' >"${CLEANUP_DIR}/no-privileged.yml"
COMPOSE_ARGS+=(-f "${CLEANUP_DIR}/no-privileged.yml")
# shellcheck disable=SC2064 # раскрытие $CLEANUP_DIR нужно на момент trap
trap "rm -rf '${CLEANUP_DIR}'" EXIT
fi
echo "[ci] образ=${IMAGE} режим netns=${NS_MODE} privileged=${PRIVILEGED} артефакты=${ARTIFACTS}"
rc=0
docker compose "${COMPOSE_ARGS[@]}" run --rm -T netns "$@" || rc=$?
case "$rc" in
0) echo "[ci][ ok ] netns-стенд: тесты прошли (код 0)" ;;
1) echo "[ci][fail] netns-стенд: тесты упали (код 1)" >&2 ;;
3) echo "[ci][blocked] netns-стенд: окружение не даёт прав на netns (код 3) — раннеру нужен --privileged (#17)" >&2 ;;
4) echo "[ci][fail] netns-стенд: сломан стенд (код 4) — см. лог выше" >&2 ;;
*) echo "[ci][fail] netns-стенд: неожиданный код ${rc}" >&2 ;;
esac
exit "$rc"