257 lines
10 KiB
Bash
Executable File
257 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# 2026-03-11
|
|
# run_e2e_tests.sh — E2E тест примеров: apply → modify → apply → destroy
|
|
#
|
|
# Запускает два примера: hello-node (nodejs20) и simple-python (python3.11)
|
|
# Каждый проходит полный цикл: init → apply → modify → apply → destroy
|
|
# В конце кластер должен быть полностью чистым.
|
|
#
|
|
# Использование:
|
|
# ./run_e2e_tests.sh
|
|
# ./run_e2e_tests.sh hello-node # только один пример
|
|
#
|
|
# Требования: terraform, curl в PATH
|
|
|
|
set -uo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
EXAMPLES_DIR="$REPO_ROOT/examples"
|
|
LOGS_DIR="$REPO_ROOT/.e2e-logs"
|
|
mkdir -p "$LOGS_DIR"
|
|
|
|
# ── Примеры для запуска ──────────────────────────────────────────────────────
|
|
if [ $# -gt 0 ]; then
|
|
EXAMPLES=("$@")
|
|
else
|
|
EXAMPLES=("hello-node" "simple-python")
|
|
fi
|
|
|
|
# ── Цвета ────────────────────────────────────────────────────────────────────
|
|
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; RESET='\033[0m'
|
|
ok() { echo -e "${GREEN} ✓ $*${RESET}"; }
|
|
fail() { echo -e "${RED} ✗ $*${RESET}"; }
|
|
info() { echo -e "${YELLOW} → $*${RESET}"; }
|
|
|
|
# ── Результаты ───────────────────────────────────────────────────────────────
|
|
declare -A RESULTS=()
|
|
|
|
# ── Cleanup-trap: уничтожить всё что могло остаться ──────────────────────────
|
|
cleanup() {
|
|
for example in "${EXAMPLES[@]}"; do
|
|
local dir="$EXAMPLES_DIR/$example"
|
|
if [ -f "$dir/terraform.tfstate" ] && \
|
|
grep -q '"resources"' "$dir/terraform.tfstate" 2>/dev/null && \
|
|
python3 -c "import json,sys; d=json.load(open('$dir/terraform.tfstate')); sys.exit(0 if d.get('resources') else 1)" 2>/dev/null; then
|
|
info "cleanup trap: destroying $example"
|
|
(cd "$dir" && terraform destroy -auto-approve -input=false -no-color \
|
|
>> "$LOGS_DIR/${example}-destroy-emergency.log" 2>&1) || true
|
|
fi
|
|
restore_backup "$example"
|
|
done
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
# ── Retry wrapper: 3 попытки, ретрай при TLS/EOF ошибках ─────────────────────
|
|
# Использование: tf_retry <logfile> <terraform args...>
|
|
tf_retry() {
|
|
local logfile="$1"; shift
|
|
local attempt=1
|
|
while [ "$attempt" -le 3 ]; do
|
|
if "$@" 2>&1 | tee "$logfile"; then
|
|
return 0
|
|
fi
|
|
if grep -Eiq \
|
|
'TLS handshake timeout|unexpected EOF|i/o timeout|context deadline' \
|
|
"$logfile" && [ "$attempt" -lt 3 ]; then
|
|
info "network error, retry $((attempt+1))/3..."
|
|
attempt=$((attempt + 1))
|
|
sleep 3
|
|
continue
|
|
fi
|
|
return 1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# ── Modify: сохранить бэкап и внести изменение ───────────────────────────────
|
|
# Изменения минимальны и легко проверяемы в plan output
|
|
backup_and_modify() {
|
|
local example="$1"
|
|
case "$example" in
|
|
hello-node)
|
|
cp "$EXAMPLES_DIR/$example/http.tf" \
|
|
"$EXAMPLES_DIR/$example/http.tf.e2e.bak"
|
|
# memory_mb 128 → 256, добавить env_vars
|
|
perl -0pi -e \
|
|
's/(memory_mb\s+=\s+)128/${1}256/' \
|
|
"$EXAMPLES_DIR/$example/http.tf"
|
|
perl -0pi -e \
|
|
's/(source_dir\s+=.*\n)/$1\n env_vars = \{ GREETING = "e2e-test" \}\n/' \
|
|
"$EXAMPLES_DIR/$example/http.tf"
|
|
;;
|
|
simple-python)
|
|
cp "$EXAMPLES_DIR/$example/time-display.tf" \
|
|
"$EXAMPLES_DIR/$example/time-display.tf.e2e.bak"
|
|
# memory_mb 64 → 96
|
|
perl -0pi -e \
|
|
's/(memory_mb\s+=\s+)64/${1}96/' \
|
|
"$EXAMPLES_DIR/$example/time-display.tf"
|
|
;;
|
|
simple-node)
|
|
cp "$EXAMPLES_DIR/$example/time-display.tf" \
|
|
"$EXAMPLES_DIR/$example/time-display.tf.e2e.bak"
|
|
perl -0pi -e \
|
|
's/(memory_mb\s+=\s+)64/${1}96/' \
|
|
"$EXAMPLES_DIR/$example/time-display.tf"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
restore_backup() {
|
|
local example="$1"
|
|
for bak in "$EXAMPLES_DIR/$example"/*.e2e.bak; do
|
|
[ -f "$bak" ] || continue
|
|
mv "$bak" "${bak%.e2e.bak}"
|
|
done
|
|
}
|
|
|
|
# ── Шаг apply: проверяем что terraform вернул 0 и есть "Apply complete" ───────
|
|
assert_apply_ok() {
|
|
local logfile="$1"
|
|
if ! grep -q 'Apply complete' "$logfile"; then
|
|
return 1
|
|
fi
|
|
# Выводим краткий итог
|
|
grep -E 'Apply complete|added|changed|destroyed|Outputs:' "$logfile" | head -5
|
|
return 0
|
|
}
|
|
|
|
assert_destroy_ok() {
|
|
local logfile="$1"
|
|
grep -q 'Destroy complete' "$logfile"
|
|
}
|
|
|
|
# ── Запуск одного примера ─────────────────────────────────────────────────────
|
|
run_example() {
|
|
local example="$1"
|
|
local dir="$EXAMPLES_DIR/$example"
|
|
local log_base="$LOGS_DIR/$example"
|
|
local failed=0
|
|
|
|
echo
|
|
echo "════════════════════════════════════════"
|
|
echo " EXAMPLE: $example"
|
|
echo "════════════════════════════════════════"
|
|
|
|
# Чистим локальные артефакты от предыдущих запусков
|
|
rm -rf "$dir/.terraform" "$dir/.terraform.lock.hcl" \
|
|
"$dir/terraform.tfstate" "$dir/terraform.tfstate.backup" \
|
|
"$dir"/terraform.tfstate.*.backup
|
|
|
|
# 1. init ───────────────────────────────────────────────────────────────────
|
|
info "init"
|
|
if tf_retry "${log_base}-init.log" \
|
|
terraform -chdir="$dir" init -input=false -no-color; then
|
|
ok "init"
|
|
else
|
|
fail "init — см. ${log_base}-init.log"
|
|
RESULTS[$example]="FAIL (init)"
|
|
return 1
|
|
fi
|
|
|
|
# 2. apply ──────────────────────────────────────────────────────────────────
|
|
info "apply"
|
|
if tf_retry "${log_base}-apply.log" \
|
|
terraform -chdir="$dir" apply -auto-approve -input=false -no-color \
|
|
&& assert_apply_ok "${log_base}-apply.log"; then
|
|
ok "apply"
|
|
else
|
|
fail "apply — см. ${log_base}-apply.log"
|
|
RESULTS[$example]="FAIL (apply)"
|
|
return 1
|
|
fi
|
|
|
|
# 3. modify ─────────────────────────────────────────────────────────────────
|
|
info "modify (backup + patch)"
|
|
backup_and_modify "$example"
|
|
ok "files patched"
|
|
|
|
# 4. apply after modify ─────────────────────────────────────────────────────
|
|
info "apply (после modify)"
|
|
if tf_retry "${log_base}-apply-modify.log" \
|
|
terraform -chdir="$dir" apply -auto-approve -input=false -no-color \
|
|
&& assert_apply_ok "${log_base}-apply-modify.log"; then
|
|
ok "apply (modify)"
|
|
# Показываем что изменилось
|
|
grep -E 'changed|updated|Modifying' "${log_base}-apply-modify.log" | head -3 \
|
|
|| true
|
|
else
|
|
fail "apply (modify) — см. ${log_base}-apply-modify.log"
|
|
RESULTS[$example]="FAIL (apply-modify)"
|
|
failed=1
|
|
fi
|
|
|
|
# Восстанавливаем файлы до destroy
|
|
restore_backup "$example"
|
|
|
|
# 5. destroy ────────────────────────────────────────────────────────────────
|
|
info "destroy"
|
|
if tf_retry "${log_base}-destroy.log" \
|
|
terraform -chdir="$dir" destroy -auto-approve -input=false -no-color \
|
|
&& assert_destroy_ok "${log_base}-destroy.log"; then
|
|
ok "destroy"
|
|
grep 'Destroy complete' "${log_base}-destroy.log" || true
|
|
else
|
|
fail "destroy — см. ${log_base}-destroy.log"
|
|
RESULTS[$example]="FAIL (destroy)"
|
|
return 1
|
|
fi
|
|
|
|
# Чистим после успешного прогона
|
|
rm -rf "$dir/.terraform" "$dir/.terraform.lock.hcl" \
|
|
"$dir/terraform.tfstate" "$dir/terraform.tfstate.backup"
|
|
|
|
if [ "$failed" -eq 0 ]; then
|
|
RESULTS[$example]="PASS"
|
|
fi
|
|
}
|
|
|
|
# ── Main ──────────────────────────────────────────────────────────────────────
|
|
main() {
|
|
echo
|
|
echo "╔══════════════════════════════════════╗"
|
|
echo "║ sless E2E tests $(date '+%Y-%m-%d %H:%M') ║"
|
|
echo "╚══════════════════════════════════════╝"
|
|
echo "Примеры: ${EXAMPLES[*]}"
|
|
echo "Логи: $LOGS_DIR"
|
|
|
|
for example in "${EXAMPLES[@]}"; do
|
|
run_example "$example" || true
|
|
done
|
|
|
|
# ── Итог ────────────────────────────────────────────────────────────────────
|
|
echo
|
|
echo "════════════════ ИТОГ ════════════════"
|
|
local all_pass=1
|
|
for example in "${EXAMPLES[@]}"; do
|
|
local result="${RESULTS[$example]:-UNKNOWN}"
|
|
if [ "$result" = "PASS" ]; then
|
|
ok "$example: $result"
|
|
else
|
|
fail "$example: $result"
|
|
all_pass=0
|
|
fi
|
|
done
|
|
echo "══════════════════════════════════════"
|
|
|
|
if [ "$all_pass" -eq 1 ]; then
|
|
echo -e "${GREEN}Все тесты прошли успешно.${RESET}"
|
|
exit 0
|
|
else
|
|
echo -e "${RED}Есть ошибки. Логи: $LOGS_DIR${RESET}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
main
|