#!/bin/bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" # Source common library if available if [ -f "$SCRIPT_DIR/lib/common.sh" ]; then source "$SCRIPT_DIR/lib/common.sh" else log() { echo "[INFO] $1"; } log_error() { echo "[ERROR] $1" >&2; } log_warn() { echo "[WARN] $1"; } fi log "=== K3s集群幂等性测试 ===" echo "" # Test counters TOTAL_TESTS=0 PASSED_TESTS=0 FAILED_TESTS=0 # Test function test_case() { local name="$1" local description="$2" TOTAL_TESTS=$((TOTAL_TESTS + 1)) echo "" echo "==========================================" echo "测试 #$TOTAL_TESTS: $name" echo "==========================================" echo "描述: $description" echo "" } test_pass() { PASSED_TESTS=$((PASSED_TESTS + 1)) log "✓ 测试通过" } test_fail() { local reason="$1" FAILED_TESTS=$((FAILED_TESTS + 1)) log_error "✗ 测试失败: $reason" } # Capture initial state capture_state() { local state_file="$1" log "捕获系统状态..." { echo "=== Nodes ===" kubectl get nodes -o yaml 2>/dev/null || echo "N/A" echo "=== Namespaces ===" kubectl get namespaces -o yaml 2>/dev/null || echo "N/A" echo "=== Deployments ===" kubectl get deployments -A -o yaml 2>/dev/null || echo "N/A" echo "=== Services ===" kubectl get services -A -o yaml 2>/dev/null || echo "N/A" echo "=== ConfigMaps ===" kubectl get configmaps -A -o yaml 2>/dev/null || echo "N/A" echo "=== Secrets (names only) ===" kubectl get secrets -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' 2>/dev/null || echo "N/A" echo "=== PVCs ===" kubectl get pvc -A -o yaml 2>/dev/null || echo "N/A" echo "=== Ingresses ===" kubectl get ingress -A -o yaml 2>/dev/null || echo "N/A" echo "=== ClusterIssuers ===" kubectl get clusterissuer -o yaml 2>/dev/null || echo "N/A" echo "=== Certificates ===" kubectl get certificate -A -o yaml 2>/dev/null || echo "N/A" echo "=== ArgoCD Applications ===" kubectl get application -n argocd -o yaml 2>/dev/null || echo "N/A" } > "$state_file" log "✓ 状态已保存到: $state_file" } # Compare states compare_states() { local before="$1" local after="$2" log "比较部署前后状态..." if diff -u "$before" "$after" > /dev/null 2>&1; then log "✓ 状态完全一致(幂等性验证通过)" return 0 else log_warn "状态存在差异,检查差异详情..." # Check for acceptable differences (timestamps, resourceVersion, etc.) local significant_diff=false # Filter out expected differences diff -u "$before" "$after" | grep -v "resourceVersion" | \ grep -v "creationTimestamp" | \ grep -v "generation:" | \ grep -v "uid:" | \ grep -v "selfLink" | \ grep -v "lastTransitionTime" | \ grep -v "observedGeneration" > /tmp/filtered_diff.txt || true if [ -s /tmp/filtered_diff.txt ]; then log_warn "发现显著差异:" head -50 /tmp/filtered_diff.txt significant_diff=true fi rm -f /tmp/filtered_diff.txt if [ "$significant_diff" = true ]; then return 1 else log "✓ 仅存在预期的元数据差异(幂等性验证通过)" return 0 fi fi } # Main test flow main() { log "开始幂等性测试" log "此测试将验证部署脚本的幂等性" echo "" # Check if cluster is accessible if ! kubectl cluster-info &>/dev/null; then log_error "无法连接到K3s集群,请先部署集群" exit 1 fi # Test 1: Capture initial state test_case "初始状态捕获" "捕获当前集群状态作为基准" STATE_BEFORE="/tmp/k3s-state-before-$$.yaml" capture_state "$STATE_BEFORE" test_pass # Test 2: Run deploy-all.sh test_case "重复执行部署脚本" "运行deploy-all.sh验证幂等性" log "执行部署脚本..." if bash "$SCRIPT_DIR/deploy-all.sh"; then log "✓ 部署脚本执行成功" test_pass else log_error "部署脚本执行失败" test_fail "deploy-all.sh执行失败" fi # Test 3: Capture state after redeployment test_case "重新部署后状态捕获" "捕获重新部署后的集群状态" STATE_AFTER="/tmp/k3s-state-after-$$.yaml" capture_state "$STATE_AFTER" test_pass # Test 4: Compare states test_case "状态一致性验证" "比较部署前后状态,验证幂等性" if compare_states "$STATE_BEFORE" "$STATE_AFTER"; then test_pass else test_fail "部署前后状态存在显著差异" fi # Test 5: Verify all services are still healthy test_case "服务健康检查" "验证所有服务仍然正常运行" log "运行验证脚本..." if bash "$SCRIPT_DIR/verify-deployment.sh" > /tmp/verify-output.txt 2>&1; then log "✓ 所有服务健康" test_pass else log_error "服务验证失败" cat /tmp/verify-output.txt test_fail "服务健康检查失败" fi # Test 6: Test individual script idempotency test_case "单个脚本幂等性" "测试各个部署脚本的幂等性" local scripts=( "deploy-argocd.sh" "deploy-gitea.sh" "deploy-https.sh" ) local script_tests_passed=0 local script_tests_total=0 for script in "${scripts[@]}"; do if [ -f "$SCRIPT_DIR/$script" ]; then script_tests_total=$((script_tests_total + 1)) log "测试脚本: $script" if bash "$SCRIPT_DIR/$script" > /tmp/script-test-$$.log 2>&1; then log " ✓ $script 执行成功" script_tests_passed=$((script_tests_passed + 1)) else log_warn " ✗ $script 执行失败" tail -20 /tmp/script-test-$$.log fi fi done if [ $script_tests_passed -eq $script_tests_total ]; then test_pass else test_fail "$script_tests_passed/$script_tests_total 脚本通过测试" fi # Cleanup log "清理临时文件..." rm -f "$STATE_BEFORE" "$STATE_AFTER" /tmp/verify-output.txt /tmp/script-test-$$.log # Print summary echo "" echo "==========================================" echo " 幂等性测试总结" echo "==========================================" echo "" echo "总测试数: $TOTAL_TESTS" echo "通过: $PASSED_TESTS ✓" echo "失败: $FAILED_TESTS ✗" echo "" if [ $FAILED_TESTS -eq 0 ]; then log "✓ 所有幂等性测试通过!" echo "" echo "结论: 部署脚本完全支持幂等性,可以安全地重复执行。" echo "" exit 0 else log_error "存在 $FAILED_TESTS 个失败的测试" echo "" echo "结论: 部署脚本的幂等性存在问题,需要修复。" echo "" exit 1 fi } # Handle script arguments case "${1:-}" in --help|-h) echo "用法: $0 [选项]" echo "" echo "此脚本测试K3s部署的幂等性,验证脚本可以安全地重复执行。" echo "" echo "测试内容:" echo " 1. 捕获初始集群状态" echo " 2. 重复执行部署脚本" echo " 3. 比较部署前后状态" echo " 4. 验证服务健康" echo " 5. 测试单个脚本幂等性" echo "" echo "选项:" echo " --help 显示此帮助信息" echo "" exit 0 ;; esac # Run main function main