- Complete modular bash-based setup system replacing Python TUI - Phase 1-4 implementation: Core Infrastructure, Configuration Management, Deployment Engine, Service Orchestration & Management - 9 production-ready scripts: preflight.sh, setup.sh, pre-deployment-wizard.sh, localize.sh, generalize.sh, validate.sh, deploy.sh, service.sh, monitor.sh, backup.sh, update.sh - Shared libraries: common.sh (utilities), ui.sh (text interface) - Template-based configuration system with environment variable substitution - Comprehensive documentation: PRD, standards, and quick reference guides - Automated backup, monitoring, and update management capabilities - Cross-platform compatibility with robust error handling and logging
375 lines
10 KiB
Bash
Executable File
375 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() {
|
|
echo "DEBUG: Starting validate_env_file"
|
|
local env_file="$EZ_HOME/.env"
|
|
echo "DEBUG: env_file = $env_file"
|
|
|
|
if [[ ! -f "$env_file" ]]; then
|
|
echo "DEBUG: .env file not found"
|
|
return 1
|
|
fi
|
|
|
|
echo "DEBUG: .env file exists"
|
|
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 "$@" |