Files
EZ-Homelab/scripts/enhanced-setup/validate.sh
Kelin ea5e34935b Resolve merge conflicts and restore local configuration
- Keep local DuckDNS subdomain and token customizations
- Preserve user-specific Authelia configuration
- Maintain local docker-compose customizations
2026-01-31 23:32:42 -05:00

372 lines
10 KiB
Bash
Executable File

#!/bin/bash
# EZ-Homelab Enhanced Setup Scripts - Multi-Purpose Validation
# Validate configurations, compose files, and deployment readiness
SCRIPT_NAME="validate"
SCRIPT_VERSION="1.0.0"
# Load common library
source "$(dirname "${BASH_SOURCE[0]}")/lib/common.sh"
source "$(dirname "${BASH_SOURCE[0]}")/lib/ui.sh"
# =============================================================================
# VALIDATION FUNCTIONS
# =============================================================================
# Validate .env file
validate_env_file() {
local env_file="$EZ_HOME/.env"
if [[ ! -f "$env_file" ]]; then
print_error ".env file not found at $env_file"
return 1
fi
return 0
}
# Validate Docker Compose files
validate_compose_files() {
local service="${1:-}"
print_info "Validating Docker Compose files..."
local compose_files
if [[ -n "$service" ]]; then
compose_files=("$EZ_HOME/docker-compose/$service/docker-compose.yml")
else
mapfile -t compose_files < <(find "$EZ_HOME/docker-compose" -name "docker-compose.yml" -type f 2>/dev/null)
fi
if [[ ${#compose_files[@]} -eq 0 ]]; then
print_error "No Docker Compose files found"
return 1
fi
local errors=0
for file in "${compose_files[@]}"; do
if [[ ! -f "$file" ]]; then
print_error "Compose file not found: $file"
errors=$((errors + 1))
continue
fi
# Validate YAML syntax
if ! validate_yaml "$file"; then
print_error "Invalid YAML in $file"
errors=$((errors + 1))
continue
fi
# Validate with docker compose config
if command_exists docker && docker compose version >/dev/null 2>&1; then
if ! docker compose -f "$file" config >/dev/null 2>&1; then
print_error "Invalid Docker Compose configuration in $file"
errors=$((errors + 1))
continue
fi
fi
print_success "Validated: $file"
done
if [[ $errors -gt 0 ]]; then
print_error "Found $errors error(s) in compose files"
return 1
fi
print_success "All compose files validated"
return 0
}
# Validate Docker networks
validate_networks() {
print_info "Validating Docker networks..."
if ! docker_available; then
print_warning "Docker not available, skipping network validation"
return 2
fi
local required_networks=("traefik-network" "homelab-network")
local missing_networks=()
for network in "${required_networks[@]}"; do
if ! docker network ls --format "{{.Name}}" | grep -q "^${network}$"; then
missing_networks+=("$network")
fi
done
if [[ ${#missing_networks[@]} -gt 0 ]]; then
print_error "Missing Docker networks: ${missing_networks[*]}"
print_error "Run ./pre-deployment-wizard.sh to create networks"
return 1
fi
print_success "All required networks exist"
return 0
}
# Validate SSL certificates
validate_ssl_certificates() {
print_info "Validating SSL certificates..."
# Check if Traefik is running and has certificates
if ! docker_available; then
print_warning "Docker not available, skipping SSL validation"
return 2
fi
if ! service_running traefik 2>/dev/null; then
print_warning "Traefik not running, skipping SSL validation"
return 2
fi
# Check acme.json exists
local acme_file="$STACKS_DIR/core/traefik/acme.json"
if [[ ! -f "$acme_file" ]]; then
print_warning "SSL certificate file not found: $acme_file"
print_warning "Certificates will be obtained on first Traefik run"
return 2
fi
print_success "SSL certificate file found"
return 0
}
# Validate service dependencies
validate_service_dependencies() {
local service="${1:-}"
print_info "Validating service dependencies..."
# This is a basic implementation - could be expanded
# to check for specific service requirements
if [[ -n "$service" ]]; then
local service_dir="$EZ_HOME/docker-compose/$service"
if [[ ! -d "$service_dir" ]]; then
print_error "Service directory not found: $service_dir"
return 1
fi
local compose_file="$service_dir/docker-compose.yml"
if [[ ! -f "$compose_file" ]]; then
print_error "Compose file not found: $compose_file"
return 1
fi
print_success "Service $service dependencies validated"
else
print_success "Service dependencies validation skipped (no specific service)"
fi
return 0
}
# =============================================================================
# REPORT GENERATION
# =============================================================================
# Generate validation report
generate_validation_report() {
local report_file="$LOG_DIR/validation-report-$(date +%Y%m%d-%H%M%S).txt"
{
echo "EZ-Homelab Validation Report"
echo "============================"
echo "Date: $(date)"
echo "System: $OS_NAME $OS_VERSION ($ARCH)"
echo ""
echo "Validation Results:"
echo "- Environment: $(validate_env_file >/dev/null 2>&1 && echo "PASS" || echo "FAIL")"
echo "- Compose Files: $(validate_compose_files >/dev/null 2>&1 && echo "PASS" || echo "FAIL")"
echo "- Networks: $(validate_networks >/dev/null 2>&1; case $? in 0) echo "PASS";; 1) echo "FAIL";; 2) echo "SKIP";; esac)"
echo "- SSL Certificates: $(validate_ssl_certificates >/dev/null 2>&1; case $? in 0) echo "PASS";; 1) echo "FAIL";; 2) echo "SKIP";; esac)"
echo ""
echo "Log file: $LOG_FILE"
} > "$report_file"
print_info "Report saved to: $report_file"
}
# =============================================================================
# MAIN FUNCTION
# =============================================================================
main() {
local service=""
local check_env=true
local check_compose=true
local check_networks=true
local check_ssl=true
local non_interactive=false
local verbose=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
cat << EOF
EZ-Homelab Multi-Purpose Validation
USAGE:
$SCRIPT_NAME [OPTIONS] [SERVICE]
ARGUMENTS:
SERVICE Specific service to validate (optional)
OPTIONS:
-h, --help Show this help message
-v, --verbose Enable verbose logging
--no-env Skip .env file validation
--no-compose Skip compose file validation
--no-networks Skip network validation
--no-ssl Skip SSL certificate validation
--no-ui Run without interactive UI
EXAMPLES:
$SCRIPT_NAME # Validate everything
$SCRIPT_NAME traefik # Validate only Traefik
$SCRIPT_NAME --no-ssl # Skip SSL validation
EOF
exit 0
;;
-v|--verbose)
verbose=true
;;
--no-env)
check_env=false
;;
--no-compose)
check_compose=false
;;
--no-networks)
check_networks=false
;;
--no-ssl)
check_ssl=false
;;
--no-ui)
non_interactive=true
;;
-*)
print_error "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
*)
if [[ -z "$service" ]]; then
service="$1"
else
print_error "Multiple services specified. Use only one service name."
exit 1
fi
;;
esac
shift
done
# Initialize script
init_script "$SCRIPT_NAME"
if $verbose; then
set -x
fi
print_info "Starting EZ-Homelab validation..."
local total_checks=0
local passed=0
local warnings=0
local failed=0
# Run validations
if $check_env; then
total_checks=$((total_checks + 1))
# Run check and capture exit code
local exit_code=0
validate_env_file || exit_code=$?
if [[ $exit_code -eq 0 ]]; then
passed=$((passed + 1))
else
failed=$((failed + 1))
fi
fi
if $check_compose; then
((total_checks++))
# Run check and capture exit code
local exit_code=0
validate_compose_files "$service" || exit_code=$?
if [[ $exit_code -eq 0 ]]; then
((passed++))
else
((failed++))
fi
fi
if $check_networks; then
total_checks=$((total_checks + 1))
# Run check and capture exit code
local exit_code=0
validate_networks || exit_code=$?
case $exit_code in
0) passed=$((passed + 1)) ;;
1) failed=$((failed + 1)) ;;
2) warnings=$((warnings + 1)) ;;
esac
fi
if $check_ssl; then
total_checks=$((total_checks + 1))
# Run check and capture exit code
local exit_code=0
validate_ssl_certificates || exit_code=$?
case $exit_code in
0) passed=$((passed + 1)) ;;
1) failed=$((failed + 1)) ;;
2) warnings=$((warnings + 1)) ;;
esac
fi
# Service-specific validation
if [[ -n "$service" ]]; then
total_checks=$((total_checks + 1))
# Run check and capture exit code
local exit_code=0
validate_service_dependencies "$service" || exit_code=$?
if [[ $exit_code -eq 0 ]]; then
passed=$((passed + 1))
else
failed=$((failed + 1))
fi
fi
echo ""
print_info "Validation complete: $passed passed, $warnings warnings, $failed failed"
# Generate report
generate_validation_report
# Determine exit code
if [[ $failed -gt 0 ]]; then
print_error "Validation failed. Check the log file: $LOG_FILE"
exit 1
elif [[ $warnings -gt 0 ]]; then
print_warning "Validation passed with warnings"
exit 2
else
print_success "All validations passed!"
exit 0
fi
}
# Run main function
main "$@"