#!/bin/bash # Validate and optimize VM YAML configurations # Ensures quota checks, non-compounded commands, and best practices set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" VM_DIR="${PROJECT_ROOT}/examples/production" # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${BLUE}[$(date +'%H:%M:%S')]${NC} $*" } log_success() { echo -e "${GREEN}[$(date +'%H:%M:%S')] ✅${NC} $*" } log_warning() { echo -e "${YELLOW}[$(date +'%H:%M:%S')] ⚠️${NC} $*" } log_error() { echo -e "${RED}[$(date +'%H:%M:%S')] ❌${NC} $*" } # Check if YAML file has required fields check_yaml_structure() { local file=$1 local errors=0 # Check for required fields if ! grep -q "kind: ProxmoxVM" "$file"; then log_error "$file: Missing 'kind: ProxmoxVM'" errors=$((errors + 1)) fi if ! grep -q "tenant.sankofa.nexus/id" "$file"; then log_warning "$file: Missing tenant label (may be intentional for infrastructure VMs)" fi if ! grep -q "image:" "$file"; then log_error "$file: Missing image specification" errors=$((errors + 1)) fi # Check image format if grep -q "image:" "$file"; then local image=$(grep "image:" "$file" | head -1 | sed 's/.*image: *"\(.*\)".*/\1/') if [[ -z "$image" ]]; then log_error "$file: Image specification is empty" errors=$((errors + 1)) fi fi return $errors } # Check for compounded commands (should be avoided) check_compounded_commands() { local file=$1 local warnings=0 # Check for problematic patterns if grep -q "systemctl.*&&\|systemctl.*||" "$file"; then log_warning "$file: Found compounded systemctl commands (should be separate)" warnings=$((warnings + 1)) fi # Check for command chains in runcmd if grep -A 5 "runcmd:" "$file" | grep -q ".*&&.*"; then log_warning "$file: Found command chains with && in runcmd (should be separate list items)" warnings=$((warnings + 1)) fi # Note: || true is acceptable for non-critical error handling # But we should document this return $warnings } # Check for quota check annotations check_quota_annotations() { local file=$1 local warnings=0 # Check if tenant label exists if grep -q "tenant.sankofa.nexus/id" "$file"; then local tenant=$(grep "tenant.sankofa.nexus/id" "$file" | sed 's/.*tenant.sankofa.nexus\/id: *"\(.*\)".*/\1/') if [[ -n "$tenant" && "$tenant" != "infrastructure" ]]; then # For tenant VMs, quota should be checked by controller # But we can add annotation for explicit quota check if ! grep -q "phoenix.sankofa.nexus/quota-check" "$file"; then log_warning "$file: Tenant VM should have quota-check annotation (controller will check automatically)" fi fi fi return $warnings } # Validate image specification check_image_spec() { local file=$1 local errors=0 if grep -q "image:" "$file"; then local image=$(grep "image:" "$file" | head -1 | sed 's/.*image: *"\(.*\)".*/\1/') # Check for valid image format if [[ ! "$image" =~ ^[a-zA-Z0-9._-]+$ ]]; then log_error "$file: Invalid image format: $image" errors=$((errors + 1)) fi # Check for recommended image if [[ "$image" != "ubuntu-22.04-cloud" ]]; then log_warning "$file: Using non-standard image: $image (recommended: ubuntu-22.04-cloud)" fi fi return $errors } # Check for best practices check_best_practices() { local file=$1 local warnings=0 # Check for QEMU guest agent if ! grep -q "qemu-guest-agent" "$file"; then log_warning "$file: Missing qemu-guest-agent package" warnings=$((warnings + 1)) fi # Check for guest agent enable/start if ! grep -q "systemctl enable qemu-guest-agent" "$file"; then log_warning "$file: Missing 'systemctl enable qemu-guest-agent'" warnings=$((warnings + 1)) fi if ! grep -q "systemctl start qemu-guest-agent" "$file"; then log_warning "$file: Missing 'systemctl start qemu-guest-agent'" warnings=$((warnings + 1)) fi # Check for package verification if ! grep -q "Verifying required packages" "$file"; then log_warning "$file: Missing package verification step" warnings=$((warnings + 1)) fi return $warnings } # Main validation main() { log "Validating and optimizing VM YAML configurations..." echo local total_files=0 local total_errors=0 local total_warnings=0 # Find all YAML files while IFS= read -r -d '' file; do total_files=$((total_files + 1)) log "Checking: $file" local file_errors=0 local file_warnings=0 check_yaml_structure "$file" || file_errors=$? check_compounded_commands "$file" || file_warnings=$? check_quota_annotations "$file" || file_warnings=$((file_warnings + $?)) check_image_spec "$file" || file_errors=$((file_errors + $?)) check_best_practices "$file" || file_warnings=$((file_warnings + $?)) total_errors=$((total_errors + file_errors)) total_warnings=$((total_warnings + file_warnings)) if [[ $file_errors -eq 0 && $file_warnings -eq 0 ]]; then log_success "$file: All checks passed" fi echo done < <(find "$VM_DIR" -name "*.yaml" -type f -print0) # Summary echo log "=== Validation Summary ===" echo "Files checked: $total_files" echo "Errors: $total_errors" echo "Warnings: $total_warnings" echo if [[ $total_errors -eq 0 ]]; then log_success "All VM configurations are valid!" return 0 else log_error "Found $total_errors errors. Please fix before deployment." return 1 fi } main "$@"