#!/bin/bash # Comprehensive Deployment Validation Script for ml110-01 # Validates all prerequisites, configurations, and deployment readiness set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$SCRIPT_DIR" DEPLOY_DIR="$PROJECT_ROOT/smom-dbis-138-proxmox" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # Status counters PASSED=0 FAILED=0 WARNINGS=0 # Functions pass() { echo -e "${GREEN}✅${NC} $1" ((PASSED++)) } fail() { echo -e "${RED}❌${NC} $1" ((FAILED++)) } warn() { echo -e "${YELLOW}⚠️${NC} $1" ((WARNINGS++)) } info() { echo -e "${BLUE}ℹ️${NC} $1" } section() { echo "" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${CYAN}$1${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" } # Load environment ENV_FILE="$HOME/.env" if [ -f "$ENV_FILE" ]; then source <(grep -E "^PROXMOX_" "$ENV_FILE" 2>/dev/null | sed 's/^/export /' || true) fi TARGET_HOST="${PROXMOX_HOST:-192.168.11.10}" TARGET_NODE="${TARGET_NODE:-ml110-01}" echo "" echo -e "${BLUE}╔════════════════════════════════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║${NC} Deployment Validation for ml110-01 (${TARGET_HOST}) ${BLUE}║${NC}" echo -e "${BLUE}╚════════════════════════════════════════════════════════════════════════╝${NC}" echo "" # ============================================================================ # SECTION 1: PREREQUISITES # ============================================================================ section "1. PREREQUISITES CHECK" # Check if running on Proxmox host or remote if command -v pct &> /dev/null; then info "Running on Proxmox host - can execute pct commands directly" ON_PROXMOX_HOST=true else info "Running remotely - will use Proxmox API" ON_PROXMOX_HOST=false fi # Check required tools REQUIRED_TOOLS=("curl" "jq" "git" "bash") for tool in "${REQUIRED_TOOLS[@]}"; do if command -v "$tool" &> /dev/null; then pass "$tool installed" else fail "$tool not found (required)" fi done # Check deployment directory if [ -d "$DEPLOY_DIR" ]; then pass "Deployment directory exists: $DEPLOY_DIR" else fail "Deployment directory not found: $DEPLOY_DIR" fi # ============================================================================ # SECTION 2: PROXMOX CONNECTION # ============================================================================ section "2. PROXMOX CONNECTION VALIDATION" # Test API connectivity info "Testing connection to $TARGET_HOST:8006" API_RESPONSE=$(curl -k -s -w "\n%{http_code}" -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \ "https://${TARGET_HOST}:8006/api2/json/version" 2>&1 || echo "ERROR") HTTP_CODE=$(echo "$API_RESPONSE" | tail -1) RESPONSE_BODY=$(echo "$API_RESPONSE" | sed '$d') if [ "$HTTP_CODE" = "200" ]; then VERSION=$(echo "$RESPONSE_BODY" | jq -r '.data.version' 2>/dev/null || echo "unknown") pass "API connection successful (Proxmox version: $VERSION)" else fail "API connection failed (HTTP $HTTP_CODE)" if [ -n "$RESPONSE_BODY" ]; then info "Response: $(echo "$RESPONSE_BODY" | head -c 200)" fi fi # Get node list info "Retrieving node list..." NODES_RESPONSE=$(curl -k -s -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \ "https://${TARGET_HOST}:8006/api2/json/nodes" 2>&1) if echo "$NODES_RESPONSE" | jq -e '.data' &>/dev/null; then NODE_COUNT=$(echo "$NODES_RESPONSE" | jq '.data | length') NODE_NAMES=$(echo "$NODES_RESPONSE" | jq -r '.data[].node' | tr '\n' ' ') pass "Retrieved $NODE_COUNT node(s): $NODE_NAMES" # Check if target node exists if echo "$NODES_RESPONSE" | jq -e ".data[] | select(.node==\"$TARGET_NODE\")" &>/dev/null; then pass "Target node '$TARGET_NODE' found" else FIRST_NODE=$(echo "$NODES_RESPONSE" | jq -r '.data[0].node') warn "Target node '$TARGET_NODE' not found, using first node: $FIRST_NODE" TARGET_NODE="$FIRST_NODE" fi else fail "Failed to retrieve nodes" fi # Get node status info "Checking node status for $TARGET_NODE..." NODE_STATUS=$(curl -k -s -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \ "https://${TARGET_HOST}:8006/api2/json/nodes/${TARGET_NODE}/status" 2>&1) if echo "$NODE_STATUS" | jq -e '.data.status' &>/dev/null; then STATUS=$(echo "$NODE_STATUS" | jq -r '.data.status') if [ "$STATUS" = "online" ]; then pass "Node $TARGET_NODE is online" else fail "Node $TARGET_NODE status: $STATUS" fi else warn "Could not retrieve node status" fi # ============================================================================ # SECTION 3: STORAGE VALIDATION # ============================================================================ section "3. STORAGE VALIDATION" # Get storage list info "Checking storage availability..." STORAGE_RESPONSE=$(curl -k -s -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \ "https://${TARGET_HOST}:8006/api2/json/nodes/${TARGET_NODE}/storage" 2>&1) if echo "$STORAGE_RESPONSE" | jq -e '.data' &>/dev/null; then STORAGE_COUNT=$(echo "$STORAGE_RESPONSE" | jq '.data | length') pass "Found $STORAGE_COUNT storage pool(s)" # Check for common storage types STORAGE_TYPES=$(echo "$STORAGE_RESPONSE" | jq -r '.data[].type' | sort -u | tr '\n' ' ') info "Storage types available: $STORAGE_TYPES" # Check for container storage (rootdir) CONTAINER_STORAGE=$(echo "$STORAGE_RESPONSE" | jq -r '.data[] | select(.content | contains("rootdir")) | .storage' | head -1) if [ -n "$CONTAINER_STORAGE" ]; then pass "Container storage found: $CONTAINER_STORAGE" # Check storage capacity STORAGE_INFO=$(echo "$STORAGE_RESPONSE" | jq ".[] | select(.storage==\"$CONTAINER_STORAGE\")") if echo "$STORAGE_INFO" | jq -e '.content' &>/dev/null; then TOTAL=$(echo "$STORAGE_INFO" | jq -r '.total // 0' | numfmt --to=iec-i --suffix=B 2>/dev/null || echo "unknown") FREE=$(echo "$STORAGE_INFO" | jq -r '.avail // 0' | numfmt --to=iec-i --suffix=B 2>/dev/null || echo "unknown") USED=$(echo "$STORAGE_INFO" | jq -r '.used // 0' | numfmt --to=iec-i --suffix=B 2>/dev/null || echo "unknown") info "Storage $CONTAINER_STORAGE: Total=$TOTAL, Free=$FREE, Used=$USED" fi else fail "No container storage (rootdir) found" fi # Check for template storage (vztmpl) TEMPLATE_STORAGE=$(echo "$STORAGE_RESPONSE" | jq -r '.data[] | select(.content | contains("vztmpl")) | .storage' | head -1) if [ -n "$TEMPLATE_STORAGE" ]; then pass "Template storage found: $TEMPLATE_STORAGE" else warn "No template storage (vztmpl) found" fi else fail "Failed to retrieve storage information" fi # ============================================================================ # SECTION 4: TEMPLATE VALIDATION # ============================================================================ section "4. LXC TEMPLATE VALIDATION" if [ -n "$TEMPLATE_STORAGE" ]; then info "Checking templates on storage: $TEMPLATE_STORAGE" TEMPLATES_RESPONSE=$(curl -k -s -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \ "https://${TARGET_HOST}:8006/api2/json/nodes/${TARGET_NODE}/storage/${TEMPLATE_STORAGE}/content?content=vztmpl" 2>&1) if echo "$TEMPLATES_RESPONSE" | jq -e '.data' &>/dev/null; then TEMPLATE_COUNT=$(echo "$TEMPLATES_RESPONSE" | jq '.data | length') pass "Found $TEMPLATE_COUNT template(s)" # Check for Debian 12 template DEBIAN_TEMPLATE=$(echo "$TEMPLATES_RESPONSE" | jq -r '.data[] | select(.volid | contains("debian-12")) | .volid' | head -1) if [ -n "$DEBIAN_TEMPLATE" ]; then pass "Debian 12 template found: $DEBIAN_TEMPLATE" else fail "Debian 12 template not found (required for deployment)" info "Available templates:" echo "$TEMPLATES_RESPONSE" | jq -r '.data[].volid' | head -10 | sed 's/^/ - /' fi else warn "Could not retrieve template list" fi else warn "Cannot check templates - no template storage found" fi # ============================================================================ # SECTION 5: CONFIGURATION FILES # ============================================================================ section "5. CONFIGURATION FILES VALIDATION" # Check if config files exist CONFIG_DIR="$DEPLOY_DIR/config" if [ -d "$CONFIG_DIR" ]; then pass "Config directory exists: $CONFIG_DIR" # Check proxmox.conf if [ -f "$CONFIG_DIR/proxmox.conf" ]; then pass "proxmox.conf exists" source "$CONFIG_DIR/proxmox.conf" 2>/dev/null || true # Validate config values if [ -n "${PROXMOX_HOST:-}" ]; then if [ "$PROXMOX_HOST" = "$TARGET_HOST" ] || [ "$PROXMOX_HOST" = "proxmox.example.com" ]; then if [ "$PROXMOX_HOST" = "$TARGET_HOST" ]; then pass "PROXMOX_HOST configured: $PROXMOX_HOST" else warn "PROXMOX_HOST still set to example: $PROXMOX_HOST" fi else warn "PROXMOX_HOST mismatch: configured=$PROXMOX_HOST, expected=$TARGET_HOST" fi else fail "PROXMOX_HOST not set in proxmox.conf" fi if [ -n "${PROXMOX_NODE:-}" ]; then pass "PROXMOX_NODE configured: $PROXMOX_NODE" else warn "PROXMOX_NODE not set (will use default)" fi if [ -n "${PROXMOX_STORAGE:-}" ]; then pass "PROXMOX_STORAGE configured: $PROXMOX_STORAGE" else warn "PROXMOX_STORAGE not set (will use default)" fi if [ -n "${CONTAINER_OS_TEMPLATE:-}" ]; then pass "CONTAINER_OS_TEMPLATE configured: $CONTAINER_OS_TEMPLATE" else warn "CONTAINER_OS_TEMPLATE not set (will use default)" fi else if [ -f "$CONFIG_DIR/proxmox.conf.example" ]; then fail "proxmox.conf not found (example exists - needs to be copied and configured)" else fail "proxmox.conf not found" fi fi # Check network.conf if [ -f "$CONFIG_DIR/network.conf" ]; then pass "network.conf exists" source "$CONFIG_DIR/network.conf" 2>/dev/null || true if [ -n "${SUBNET_BASE:-}" ]; then pass "SUBNET_BASE configured: $SUBNET_BASE" else warn "SUBNET_BASE not set" fi if [ -n "${GATEWAY:-}" ]; then pass "GATEWAY configured: $GATEWAY" else warn "GATEWAY not set" fi else if [ -f "$CONFIG_DIR/network.conf.example" ]; then warn "network.conf not found (example exists)" else warn "network.conf not found" fi fi else fail "Config directory not found: $CONFIG_DIR" fi # ============================================================================ # SECTION 6: DEPLOYMENT SCRIPTS # ============================================================================ section "6. DEPLOYMENT SCRIPTS VALIDATION" SCRIPTS_DIR="$DEPLOY_DIR/scripts/deployment" if [ -d "$SCRIPTS_DIR" ]; then pass "Deployment scripts directory exists" REQUIRED_SCRIPTS=( "deploy-all.sh" "deploy-besu-nodes.sh" "deploy-services.sh" "deploy-hyperledger-services.sh" "deploy-monitoring.sh" "deploy-explorer.sh" ) for script in "${REQUIRED_SCRIPTS[@]}"; do SCRIPT_PATH="$SCRIPTS_DIR/$script" if [ -f "$SCRIPT_PATH" ]; then if [ -x "$SCRIPT_PATH" ]; then pass "$script exists and is executable" else warn "$script exists but is not executable" fi # Check for syntax errors if bash -n "$SCRIPT_PATH" 2>&1 | grep -q "error"; then fail "$script has syntax errors" fi else warn "$script not found" fi done else fail "Deployment scripts directory not found: $SCRIPTS_DIR" fi # Check common library LIB_DIR="$DEPLOY_DIR/lib" if [ -f "$LIB_DIR/common.sh" ]; then pass "common.sh library exists" else fail "common.sh library not found" fi if [ -f "$LIB_DIR/proxmox-api.sh" ]; then pass "proxmox-api.sh library exists" else warn "proxmox-api.sh library not found" fi # ============================================================================ # SECTION 7: RESOURCE REQUIREMENTS # ============================================================================ section "7. RESOURCE REQUIREMENTS VALIDATION" # Calculate total resource requirements TOTAL_MEMORY=0 TOTAL_CORES=0 TOTAL_DISK=0 # Load resource config if available if [ -f "$CONFIG_DIR/proxmox.conf" ]; then source "$CONFIG_DIR/proxmox.conf" 2>/dev/null || true # Calculate based on default counts VALIDATOR_COUNT="${VALIDATORS_COUNT:-4}" SENTRY_COUNT="${SENTRIES_COUNT:-3}" RPC_COUNT="${RPC_COUNT:-3}" SERVICE_COUNT="${SERVICES_COUNT:-4}" TOTAL_MEMORY=$((VALIDATOR_MEMORY * VALIDATOR_COUNT + SENTRY_MEMORY * SENTRY_COUNT + RPC_MEMORY * RPC_COUNT + SERVICE_MEMORY * SERVICE_COUNT + MONITORING_MEMORY)) TOTAL_CORES=$((VALIDATOR_CORES * VALIDATOR_COUNT + SENTRY_CORES * SENTRY_COUNT + RPC_CORES * RPC_COUNT + SERVICE_CORES * SERVICE_COUNT + MONITORING_CORES)) TOTAL_DISK=$((VALIDATOR_DISK * VALIDATOR_COUNT + SENTRY_DISK * SENTRY_COUNT + RPC_DISK * RPC_COUNT + SERVICE_DISK * SERVICE_COUNT + MONITORING_DISK)) info "Estimated resource requirements:" info " Memory: $((TOTAL_MEMORY / 1024))GB" info " CPU Cores: $TOTAL_CORES" info " Disk: ${TOTAL_DISK}GB" # Get node resources if [ -n "$NODE_STATUS" ]; then NODE_MEMORY=$(echo "$NODE_STATUS" | jq -r '.data.memory.total // 0') NODE_FREE_MEMORY=$(echo "$NODE_STATUS" | jq -r '.data.memory.free // 0') NODE_CPU_COUNT=$(echo "$NODE_STATUS" | jq -r '.data.cpuinfo.cpus // 0') if [ "$NODE_MEMORY" != "0" ] && [ -n "$NODE_MEMORY" ]; then MEMORY_GB=$((NODE_MEMORY / 1024 / 1024 / 1024)) FREE_MEMORY_GB=$((NODE_FREE_MEMORY / 1024 / 1024 / 1024)) info "Node resources:" info " Total Memory: ${MEMORY_GB}GB (Free: ${FREE_MEMORY_GB}GB)" info " CPU Cores: $NODE_CPU_COUNT" if [ $FREE_MEMORY_GB -lt $((TOTAL_MEMORY / 1024)) ]; then warn "Insufficient free memory: need $((TOTAL_MEMORY / 1024))GB, have ${FREE_MEMORY_GB}GB" else pass "Sufficient memory available" fi if [ $NODE_CPU_COUNT -lt $TOTAL_CORES ]; then warn "Limited CPU cores: need $TOTAL_CORES, have $NODE_CPU_COUNT (containers can share CPU)" else pass "Sufficient CPU cores available" fi fi fi fi # ============================================================================ # SECTION 8: NETWORK CONFIGURATION # ============================================================================ section "8. NETWORK CONFIGURATION VALIDATION" # Get network interfaces info "Checking network configuration..." NETWORK_RESPONSE=$(curl -k -s -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \ "https://${TARGET_HOST}:8006/api2/json/nodes/${TARGET_NODE}/network" 2>&1) if echo "$NETWORK_RESPONSE" | jq -e '.data' &>/dev/null; then BRIDGES=$(echo "$NETWORK_RESPONSE" | jq -r '.data[] | select(.type=="bridge") | .iface' | tr '\n' ' ') if [ -n "$BRIDGES" ]; then pass "Network bridges found: $BRIDGES" # Check for vmbr0 if echo "$BRIDGES" | grep -q "vmbr0"; then pass "vmbr0 bridge exists (required)" else warn "vmbr0 bridge not found (may cause network issues)" fi else warn "No network bridges found" fi else warn "Could not retrieve network configuration" fi # ============================================================================ # SECTION 9: EXISTING CONTAINERS # ============================================================================ section "9. EXISTING CONTAINERS CHECK" info "Checking for existing containers..." CONTAINERS_RESPONSE=$(curl -k -s -H "Authorization: PVEAPIToken=${PROXMOX_USER}!${PROXMOX_TOKEN_NAME}=${PROXMOX_TOKEN_VALUE}" \ "https://${TARGET_HOST}:8006/api2/json/nodes/${TARGET_NODE}/lxc" 2>&1) if echo "$CONTAINERS_RESPONSE" | jq -e '.data' &>/dev/null; then EXISTING_COUNT=$(echo "$CONTAINERS_RESPONSE" | jq '.data | length') if [ "$EXISTING_COUNT" -gt 0 ]; then info "Found $EXISTING_COUNT existing container(s)" # Check for VMID conflicts EXPECTED_VMIDS=(106 107 108 109 110 111 112 115 116 117 120 121 122 130 140 150 151 152 153) CONFLICTS=() for vmid in "${EXPECTED_VMIDS[@]}"; do if echo "$CONTAINERS_RESPONSE" | jq -e ".data[] | select(.vmid==$vmid)" &>/dev/null; then CONFLICTS+=("$vmid") fi done if [ ${#CONFLICTS[@]} -gt 0 ]; then warn "VMID conflicts detected: ${CONFLICTS[*]} (containers already exist)" else pass "No VMID conflicts detected" fi else pass "No existing containers (clean slate)" fi else warn "Could not retrieve container list" fi # ============================================================================ # SECTION 10: INSTALLATION SCRIPTS # ============================================================================ section "10. INSTALLATION SCRIPTS VALIDATION" INSTALL_DIR="$DEPLOY_DIR/install" if [ -d "$INSTALL_DIR" ]; then pass "Install scripts directory exists" REQUIRED_INSTALL_SCRIPTS=( "besu-validator-install.sh" "besu-sentry-install.sh" "besu-rpc-install.sh" "oracle-publisher-install.sh" "ccip-monitor-install.sh" "keeper-install.sh" ) for script in "${REQUIRED_INSTALL_SCRIPTS[@]}"; do if [ -f "$INSTALL_DIR/$script" ]; then pass "$script exists" else warn "$script not found" fi done else fail "Install scripts directory not found: $INSTALL_DIR" fi # ============================================================================ # SUMMARY # ============================================================================ section "VALIDATION SUMMARY" echo -e "${CYAN}Results:${NC}" echo -e " ${GREEN}Passed:${NC} $PASSED" echo -e " ${RED}Failed:${NC} $FAILED" echo -e " ${YELLOW}Warnings:${NC} $WARNINGS" echo "" if [ $FAILED -eq 0 ]; then echo -e "${GREEN}✅ Deployment validation PASSED${NC}" echo "" echo "Next steps:" echo " 1. Review configuration files in $DEPLOY_DIR/config/" echo " 2. Run deployment: cd $DEPLOY_DIR && ./scripts/deployment/deploy-all.sh" exit 0 else echo -e "${RED}❌ Deployment validation FAILED${NC}" echo "" echo "Please fix the issues above before proceeding with deployment." exit 1 fi