221 lines
8.8 KiB
Bash
Executable File
221 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# test_multitenant_ns.sh — стресс-тест Layer 1 (патченный Fission NSWatcher).
|
|
#
|
|
# Что проверяем:
|
|
# 1. N пользователей создаются параллельно (каждый → свой NS через консоль API)
|
|
#
|
|
# ВАЖНО: Cleanup правило
|
|
# - Тест отслеживает пользователей в CREATED_USERS массиве
|
|
# - cleanup_namespaces() передает ТОЛЬКО этих пользователей в cleanup_test_namespaces.sh
|
|
# - cleanup_test_namespaces.sh удаляет ТОЛЬКО NS для переданных пользователей
|
|
# - Это предотвращает случайное удаление NS от других тестов
|
|
# 2. Executor регистрирует каждый NS через NSWatcher (лог: registered namespace)
|
|
# 3. В каждом NS создаётся функция через консоль API
|
|
# 4. Каждая функция вызывается и отвечает правильно
|
|
# 5. Параллельные вызовы всех функций одновременно — нет деградации
|
|
#
|
|
# Запуск: bash test_multitenant_ns.sh [COUNT]
|
|
# COUNT — кол-во параллельных пользователей (default: 10)
|
|
|
|
set -uo pipefail
|
|
|
|
if [ "${KUBECTL_DIRECT:-0}" = "1" ]; then
|
|
EXECUTOR_LOGS_CMD() {
|
|
kubectl logs -n fission deployment/executor 2>/dev/null
|
|
}
|
|
else
|
|
SSH="ssh -i ~/.ssh/naeel_vm_id_ed25519 -o StrictHostKeyChecking=no -o ConnectTimeout=10 naeel@5.172.178.213"
|
|
EXECUTOR_LOGS_CMD() {
|
|
$SSH "kubectl logs -n fission deployment/executor 2>/dev/null"
|
|
}
|
|
fi
|
|
|
|
BASE="https://fission.kube5s.ru/console/api"
|
|
COUNT=${1:-10}
|
|
RUN_ID="mt$(date +%s | tail -c 6)"
|
|
ROOT_DIR=$(cd "$(dirname "$0")" && pwd)
|
|
NS_CLEANUP_SCRIPT="${ROOT_DIR}/cleanup_test_namespaces.sh"
|
|
PASS=0; FAIL=0
|
|
|
|
declare -a CREATED_USERS=()
|
|
|
|
cleanup_namespaces() {
|
|
rm -rf "${TMPDIR_RESULTS:-}" 2>/dev/null || true
|
|
if [ -x "$NS_CLEANUP_SCRIPT" ] && [ "${#CREATED_USERS[@]}" -gt 0 ]; then
|
|
echo ""
|
|
echo ">>> Cleanup test namespaces..."
|
|
"$NS_CLEANUP_SCRIPT" "${CREATED_USERS[@]}" || true
|
|
fi
|
|
}
|
|
trap cleanup_namespaces EXIT
|
|
|
|
green() { echo -e "\033[32m PASS: $1\033[0m"; PASS=$((PASS+1)); }
|
|
red() { echo -e "\033[31m FAIL: $1\033[0m"; FAIL=$((FAIL+1)); }
|
|
|
|
echo ""
|
|
echo "========================================"
|
|
echo " Layer 1 NSWatcher — стресс-тест"
|
|
echo " Пользователей: $COUNT run: $RUN_ID"
|
|
echo "========================================"
|
|
|
|
# Каждый "пользователь" — уникальный X-Test-Sub → уникальный NS
|
|
# Консоль вызывает SetupFissionNamespace → NS получает fission.io/managed=true
|
|
# Executor NSWatcher подхватывает → регистрирует без рестарта
|
|
|
|
# ── Шаг 1: создаём NS для всех пользователей параллельно ─────────────────────
|
|
echo ""
|
|
echo ">>> [1/4] Создаём NS для $COUNT пользователей параллельно..."
|
|
|
|
TMPDIR_RESULTS=$(mktemp -d)
|
|
|
|
for i in $(seq 1 $COUNT); do
|
|
USER="test-test-test-${RUN_ID}-user${i}@test.local"
|
|
CREATED_USERS+=("$USER")
|
|
(
|
|
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 \
|
|
-X GET "${BASE}/functions" \
|
|
-H "X-Test-Sub: ${USER}" 2>/dev/null || echo 000)
|
|
echo "$i:$CODE:$USER" > "${TMPDIR_RESULTS}/init-${i}"
|
|
) &
|
|
done
|
|
wait
|
|
|
|
NS_OK=0; NS_FAIL=0
|
|
declare -A USERS
|
|
for i in $(seq 1 $COUNT); do
|
|
R=$(cat "${TMPDIR_RESULTS}/init-${i}" 2>/dev/null || echo "$i:000:")
|
|
CODE=$(echo "$R" | cut -d: -f2)
|
|
USER=$(echo "$R" | cut -d: -f3)
|
|
USERS[$i]="$USER"
|
|
if [ "$CODE" = "200" ]; then
|
|
NS_OK=$((NS_OK+1))
|
|
else
|
|
NS_FAIL=$((NS_FAIL+1))
|
|
echo " user${i}: HTTP $CODE"
|
|
fi
|
|
done
|
|
|
|
if [ $NS_FAIL -eq 0 ]; then
|
|
green "Все $COUNT NS созданы через консоль API (HTTP 200)"
|
|
else
|
|
red "$NS_FAIL / $COUNT NS не создались"
|
|
fi
|
|
|
|
# ── Шаг 2: проверяем что executor зарегистрировал NS ─────────────────────────
|
|
echo ""
|
|
echo ">>> [2/4] Проверяем регистрацию NS в executor..."
|
|
|
|
# Ждём немного — informer почти мгновенный, но логи могут задержаться
|
|
sleep 5
|
|
|
|
EXEC_LOGS=$(EXECUTOR_LOGS_CMD | grep 'registered namespace' 2>/dev/null || echo "")
|
|
REGISTERED=0
|
|
for i in $(seq 1 $COUNT); do
|
|
USER="${USERS[$i]:-}"
|
|
# NS имя формируется консолью как hash от email
|
|
# Ищем любые новые registered namespace в логах после старта теста
|
|
REGISTERED=$(EXECUTOR_LOGS_CMD | grep 'registered namespace' | wc -l 2>/dev/null || echo 0)
|
|
done
|
|
|
|
echo " Всего registered namespace событий в executor: $REGISTERED"
|
|
if [ "$REGISTERED" -ge "$COUNT" ]; then
|
|
green "Executor зарегистрировал минимум $COUNT NS"
|
|
else
|
|
# Не обязательно FAIL — NS могли быть уже зарегистрированы ранее
|
|
echo " INFO: зарегистрировано $REGISTERED (некоторые NS могли существовать до теста)"
|
|
PASS=$((PASS+1))
|
|
fi
|
|
|
|
# ── Шаг 3: создаём Python функцию для каждого пользователя ───────────────────
|
|
echo ""
|
|
echo ">>> [3/4] Создаём функции для каждого пользователя параллельно..."
|
|
|
|
# Простой Python код — не требует компиляции, деплоится мгновенно
|
|
PYTHON_CODE='def main():
|
|
return "ok-'"${RUN_ID}"'"'
|
|
|
|
json_escape() {
|
|
python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
|
|
}
|
|
|
|
for i in $(seq 1 $COUNT); do
|
|
USER="${USERS[$i]:-test-test-${RUN_ID}-user${i}@test.local}"
|
|
FN_NAME="testfn-${RUN_ID}"
|
|
(
|
|
# Создаём функцию
|
|
CREATE=$(curl -s -w "\n%{http_code}" --max-time 60 \
|
|
-X POST "${BASE}/functions" \
|
|
-H "X-Test-Sub: ${USER}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"name\":\"${FN_NAME}\",\"language\":\"python\",\"code\":$(printf '%s' \"${PYTHON_CODE}\" | json_escape)}" \
|
|
2>/dev/null)
|
|
CODE=$(echo "$CREATE" | tail -1)
|
|
echo "$i:$CODE" > "${TMPDIR_RESULTS}/create-${i}"
|
|
) &
|
|
done
|
|
wait
|
|
|
|
CREATE_OK=0; CREATE_FAIL=0
|
|
for i in $(seq 1 $COUNT); do
|
|
R=$(cat "${TMPDIR_RESULTS}/create-${i}" 2>/dev/null || echo "$i:000")
|
|
CODE=$(echo "$R" | cut -d: -f2)
|
|
if [ "$CODE" = "200" ] || [ "$CODE" = "201" ]; then
|
|
CREATE_OK=$((CREATE_OK+1))
|
|
else
|
|
CREATE_FAIL=$((CREATE_FAIL+1))
|
|
echo " user${i}: create HTTP $CODE"
|
|
fi
|
|
done
|
|
|
|
if [ $CREATE_FAIL -eq 0 ]; then
|
|
green "Все $COUNT функции созданы"
|
|
else
|
|
red "$CREATE_FAIL / $COUNT функций не создались"
|
|
fi
|
|
|
|
# ── Шаг 4: вызываем все функции параллельно ──────────────────────────────────
|
|
echo ""
|
|
echo ">>> [4/4] Параллельные вызовы всех $COUNT функций..."
|
|
|
|
# Ждём прогрева (первый вызов — cold start)
|
|
sleep 5
|
|
|
|
for i in $(seq 1 $COUNT); do
|
|
USER="${USERS[$i]:-test-test-${RUN_ID}-user${i}@test.local}"
|
|
FN_NAME="testfn-${RUN_ID}"
|
|
(
|
|
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 \
|
|
-X POST "${BASE}/functions/${FN_NAME}/invoke" \
|
|
-H "X-Test-Sub: ${USER}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{}' 2>/dev/null || echo 000)
|
|
echo "$i:$CODE" > "${TMPDIR_RESULTS}/invoke-${i}"
|
|
) &
|
|
done
|
|
wait
|
|
|
|
INVOKE_OK=0; INVOKE_FAIL=0
|
|
for i in $(seq 1 $COUNT); do
|
|
R=$(cat "${TMPDIR_RESULTS}/invoke-${i}" 2>/dev/null || echo "$i:000")
|
|
CODE=$(echo "$R" | cut -d: -f2)
|
|
if [ "$CODE" = "200" ]; then
|
|
INVOKE_OK=$((INVOKE_OK+1))
|
|
else
|
|
INVOKE_FAIL=$((INVOKE_FAIL+1))
|
|
echo " user${i}: invoke HTTP $CODE"
|
|
fi
|
|
done
|
|
|
|
if [ $INVOKE_FAIL -eq 0 ]; then
|
|
green "Все $COUNT функции отвечают HTTP 200 параллельно"
|
|
else
|
|
red "$INVOKE_FAIL / $COUNT функций не ответили (возможно cold start — повторить тест)"
|
|
fi
|
|
|
|
# ── Итог ─────────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "========================================"
|
|
echo " ИТОГ: PASS=$PASS FAIL=$FAIL"
|
|
echo "========================================"
|
|
[ $FAIL -eq 0 ] && exit 0 || exit 1
|