Phase Plans (5 files): - 04-RESEARCH.md: Domain research on Docker limits, healthchecks, EC2 parallels - 04-VALIDATION.md: Success criteria and validation strategy - 04-01-PLAN.md: Test infrastructure (RED phase) - 04-02-PLAN.md: Diátxis documentation - 04-03-PLAN.md: Infrastructure implementation (GREEN phase) Test Scripts (6 files, 1300+ lines): - 01-resource-limits-test.sh: Validate INF-03 compliance - 02-healthcheck-test.sh: Validate healthcheck configuration - 03-enforcement-test.sh: Verify resource limits with docker stats - 04-verify-infrastructure.sh: Infrastructure verification - 99-final-verification.sh: End-to-end student verification - run-all-tests.sh: Test orchestration with fail-fast - quick-test.sh: Fast validation (<30s) Documentation (11 files, 2500+ lines): Tutorials (3): - 01-set-resource-limits.md: EC2 instance types, Docker limits syntax - 02-implement-healthchecks.md: ELB health check parallels - 03-dependencies-with-health.md: depends_on with service_healthy How-to Guides (4): - check-resource-usage.md: docker stats monitoring - test-limits-enforcement.md: Stress testing CPU/memory - custom-healthcheck.md: HTTP, TCP, database healthchecks - instance-type-mapping.md: Docker limits → EC2 mapping Reference (3): - compose-resources-syntax.md: Complete deploy.resources reference - healthcheck-syntax.md: All healthcheck parameters - ec2-instance-mapping.md: Instance type mapping table Explanation (1): - compute-ec2-parallels.md: Container=EC2, Limits=Instance Type, Healthcheck=ELB Infrastructure: - docker-compose.yml: 5 services (web, app, worker, db, stress-test) All services: INF-03 compliant (cpus + memory limits) All services: healthcheck configured EC2 parallels: t2.nano, t2.micro, t2.small, t2.medium, m5.large - Dockerfile: Alpine 3.19 + stress tools + non-root user Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
256 lines
9.3 KiB
Bash
Executable File
256 lines
9.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# Test 02: Healthcheck Configuration
|
|
# Verifies that docker-compose.yml services have healthchecks configured
|
|
# Usage: bash labs/lab-03-compute/tests/02-healthcheck-test.sh
|
|
|
|
set -euo pipefail
|
|
|
|
# Color definitions
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
BLUE='\033[0;34m'
|
|
YELLOW='\033[1;33m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m'
|
|
|
|
# Get script directory
|
|
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
LAB_DIR="$(cd "$TEST_DIR/.." && pwd)"
|
|
|
|
# Counter helpers
|
|
pass_count=0
|
|
fail_count=0
|
|
|
|
inc_pass() { ((pass_count++)) || true; }
|
|
inc_fail() { ((fail_count++)) || true; }
|
|
|
|
# Helper functions
|
|
print_header() {
|
|
echo -e "${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${BLUE}║${NC} ${BOLD}$1${NC}"
|
|
echo -e "${BLUE}╚═══════════════════════════════════════════════════════════════╝${NC}"
|
|
}
|
|
|
|
print_test() {
|
|
echo -e "\n${BLUE}[TEST]${NC} $1"
|
|
}
|
|
|
|
print_pass() {
|
|
echo -e " ${GREEN}[✓]${NC} $1"
|
|
inc_pass
|
|
}
|
|
|
|
print_fail() {
|
|
echo -e " ${RED}[✗]${NC} $1"
|
|
inc_fail
|
|
}
|
|
|
|
print_info() {
|
|
echo -e " ${BLUE}[i]${NC} $1"
|
|
}
|
|
|
|
# Main verification
|
|
print_header "Lab 03 Healthcheck Verification"
|
|
|
|
cd "$LAB_DIR"
|
|
|
|
# Test 1: docker-compose.yml exists
|
|
print_test "Verifying docker-compose.yml exists"
|
|
if [[ -f "docker-compose.yml" ]]; then
|
|
print_pass "docker-compose.yml found"
|
|
else
|
|
print_fail "docker-compose.yml not found"
|
|
exit 1
|
|
fi
|
|
|
|
# Test 2: docker-compose.yml is valid
|
|
print_test "Validating docker-compose.yml syntax"
|
|
if docker compose config &> /dev/null; then
|
|
print_pass "docker-compose.yml has valid syntax"
|
|
else
|
|
print_fail "docker-compose.yml has syntax errors"
|
|
exit 1
|
|
fi
|
|
|
|
# Test 3: Services are defined
|
|
print_test "Verifying services are defined"
|
|
SERVICES=$(docker compose config --services 2>/dev/null)
|
|
SERVICE_COUNT=$(echo "$SERVICES" | wc -l)
|
|
if [[ $SERVICE_COUNT -gt 0 ]]; then
|
|
print_pass "Found $SERVICE_COUNT services"
|
|
else
|
|
print_fail "No services defined"
|
|
exit 1
|
|
fi
|
|
|
|
# Test 4: Healthcheck configuration check
|
|
print_test "Checking healthcheck configuration"
|
|
MISSING_HEALTHCHECK=0
|
|
|
|
for service in $SERVICES; do
|
|
# Check for healthcheck section
|
|
has_healthcheck=$(docker compose config 2>/dev/null | grep -A 50 "^$service:" | grep -c "healthcheck:" || echo "0")
|
|
|
|
if [[ $has_healthcheck -eq 0 ]]; then
|
|
print_fail " $service: Missing healthcheck section"
|
|
((MISSING_HEALTHCHECK++)) || true
|
|
else
|
|
# Verify healthcheck has test command
|
|
has_test=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 5 "healthcheck:" | grep -c "test:" || echo "0")
|
|
|
|
if [[ $has_test -eq 0 ]]; then
|
|
print_fail " $service: Missing healthcheck test command"
|
|
((MISSING_HEALTHCHECK++)) || true
|
|
else
|
|
# Extract test command for reporting
|
|
test_cmd=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 5 "healthcheck:" | grep "test:" | head -1 | sed 's/.*test: //' | tr -d '"')
|
|
print_pass " $service: healthcheck configured"
|
|
print_info " test: $test_cmd"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [[ $MISSING_HEALTHCHECK -eq 0 ]]; then
|
|
print_pass "All services have healthchecks configured"
|
|
else
|
|
print_fail "$MISSING_HEALTHCHECK services missing healthchecks"
|
|
fi
|
|
|
|
# Test 5: Healthcheck parameters verification
|
|
print_test "Verifying healthcheck parameters"
|
|
PARAMS_OK=0
|
|
|
|
for service in $SERVICES; do
|
|
has_healthcheck=$(docker compose config 2>/dev/null | grep -A 50 "^$service:" | grep -c "healthcheck:" || echo "0")
|
|
|
|
if [[ $has_healthcheck -gt 0 ]]; then
|
|
# Check for interval
|
|
has_interval=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep -c "interval:" || echo "0")
|
|
# Check for timeout
|
|
has_timeout=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep -c "timeout:" || echo "0")
|
|
# Check for retries
|
|
has_retries=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep -c "retries:" || echo "0")
|
|
|
|
interval=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep "interval:" | sed 's/.*interval: //' | tr -d " '"" || echo "N/A")
|
|
timeout=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep "timeout:" | sed 's/.*timeout: //' | tr -d " '"" || echo "N/A")
|
|
retries=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep "retries:" | sed 's/.*retries: //' | tr -d " '"" || echo "N/A")
|
|
|
|
if [[ $has_interval -gt 0 && $has_timeout -gt 0 && $has_retries -gt 0 ]]; then
|
|
print_pass " $service: interval=$interval, timeout=$timeout, retries=$retries"
|
|
((PARAMS_OK++)) || true
|
|
else
|
|
print_info " $service: interval=$interval, timeout=$timeout, retries=$retries"
|
|
# Check for start_period (optional)
|
|
has_start_period=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep -c "start_period:" || echo "0")
|
|
if [[ $has_start_period -gt 0 ]]; then
|
|
start_period=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep "start_period:" | sed 's/.*start_period: //' | tr -d " '"" || echo "")
|
|
print_info " start_period=$start_period"
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [[ $PARAMS_OK -gt 0 ]]; then
|
|
print_pass "$PARAMS_OK services have complete healthcheck parameters"
|
|
else
|
|
print_fail "No services with complete healthcheck parameters"
|
|
fi
|
|
|
|
# Test 6: Healthcheck command types
|
|
print_test "Analyzing healthcheck command types"
|
|
HTTP_COUNT=0
|
|
CMD_SHELL_COUNT=0
|
|
CMD_COUNT=0
|
|
CUSTOM_COUNT=0
|
|
|
|
for service in $SERVICES; do
|
|
has_healthcheck=$(docker compose config 2>/dev/null | grep -A 50 "^$service:" | grep -c "healthcheck:" || echo "0")
|
|
|
|
if [[ $has_healthcheck -gt 0 ]]; then
|
|
# Get test command
|
|
test_section=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" || echo "")
|
|
|
|
if echo "$test_section" | grep -q "CMD-SHELL"; then
|
|
print_info " $service: CMD-SHELL healthcheck"
|
|
((CMD_SHELL_COUNT++)) || true
|
|
elif echo "$test_section" | grep -q "CMD"; then
|
|
print_info " $service: CMD healthcheck"
|
|
((CMD_COUNT++)) || true
|
|
else
|
|
print_info " $service: Custom healthcheck format"
|
|
((CUSTOM_COUNT++)) || true
|
|
fi
|
|
|
|
# Check if HTTP-based
|
|
if echo "$test_section" | grep -qiE "(wget|curl|http)"; then
|
|
((HTTP_COUNT++)) || true
|
|
fi
|
|
fi
|
|
done
|
|
|
|
print_info "Healthcheck types: CMD-SHELL ($CMD_SHELL_COUNT), CMD ($CMD_COUNT), Custom ($CUSTOM_COUNT)"
|
|
if [[ $HTTP_COUNT -gt 0 ]]; then
|
|
print_pass "$HTTP_COUNT services use HTTP-based healthchecks"
|
|
fi
|
|
|
|
# Test 7: ELB Health Check Parallel verification
|
|
print_test "Verifying ELB Health Check parallelism"
|
|
ELB_PARALLEL=0
|
|
|
|
for service in $SERVICES; do
|
|
has_healthcheck=$(docker compose config 2>/dev/null | grep -A 50 "^$service:" | grep -c "healthcheck:" || echo "0")
|
|
|
|
if [[ $has_healthcheck -gt 0 ]]; then
|
|
interval=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep "interval:" | sed 's/.*interval: //' | tr -d " '"" || echo "")
|
|
timeout=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep "timeout:" | sed 's/.*timeout: //' | tr -d " '"" || echo "")
|
|
retries=$(docker compose config 2>/dev/null | grep -A 60 "^$service:" | grep -A 10 "healthcheck:" | grep "retries:" | sed 's/.*retries: //' | tr -d " '"" || echo "")
|
|
|
|
# Map to ELB defaults
|
|
if [[ "$interval" == "30s" || "$interval" =~ ^30 ]]; then
|
|
elb_interval="default (30s)"
|
|
((ELB_PARALLEL++)) || true
|
|
else
|
|
elb_interval="custom ($interval)"
|
|
fi
|
|
|
|
if [[ "$timeout" == "5s" || "$timeout" =~ ^5 ]]; then
|
|
elb_timeout="default (5s)"
|
|
((ELB_PARALLEL++)) || true
|
|
else
|
|
elb_timeout="custom ($timeout)"
|
|
fi
|
|
|
|
if [[ "$retries" == "3" || "$retries" =~ ^3 ]]; then
|
|
elb_retries="default (3)"
|
|
((ELB_PARALLEL++)) || true
|
|
else
|
|
elb_retries="custom ($retries)"
|
|
fi
|
|
|
|
print_info " $service: ELB parallel (interval: $elb_interval, timeout: $elb_timeout, retries: $elb_retries)"
|
|
fi
|
|
done
|
|
|
|
if [[ $ELB_PARALLEL -gt 0 ]]; then
|
|
print_pass "ELB Health Check parallelism verified"
|
|
fi
|
|
|
|
# Summary
|
|
print_header "Healthcheck Verification Summary"
|
|
|
|
echo -e "Tests run: $((pass_count + fail_count))"
|
|
echo -e "${GREEN}Passed: $pass_count${NC}"
|
|
if [[ $fail_count -gt 0 ]]; then
|
|
echo -e "${RED}Failed: $fail_count${NC}"
|
|
fi
|
|
|
|
if [[ $fail_count -eq 0 ]]; then
|
|
echo -e "\n${GREEN}${BOLD}✓ ALL HEALTHCHECK CHECKS PASSED${NC}"
|
|
echo -e "\nHealthcheck configuration verified!"
|
|
exit 0
|
|
else
|
|
echo -e "\n${RED}Some healthcheck checks failed${NC}"
|
|
echo -e "Please ensure all services have healthchecks configured."
|
|
exit 1
|
|
fi
|