#!/usr/bin/env bash set -euo pipefail # Load IP configuration and VMID maps SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" source "${PROJECT_ROOT}/scripts/lib/vmid-ip-maps.sh" 2>/dev/null || true # Reconcile and Update Node Lists # Matches RPC nodes, removes old/migrated entries, adds missing nodes, prunes duplicates # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_section() { echo -e "\n${CYAN}=== $1 ===${NC}"; } STATIC_NODES_FILE="$PROJECT_ROOT/smom-dbis-138/config/static-nodes.json" PERMISSIONED_NODES_FILE="$PROJECT_ROOT/smom-dbis-138-proxmox/config/permissioned-nodes.json" PROXMOX_HOST="${PROXMOX_HOST:-${PROXMOX_HOST_ML110:-192.168.11.10}}" # CURRENT_NODES from scripts/lib/vmid-ip-maps.sh # Old/migrated IPs that should be removed (if migration completed) # These were from old VMIDs that migrated to 2201, 2301, 2303-2308 declare -a OLD_IPS=( "${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}" # Old 2201 (migrated from 2501) "${RPC_PRIVATE_1:-${RPC_PRIVATE_1:-192.168.11.232}}" # Old 2301 (migrated from 2502) "${RPC_NODE_233:-${RPC_NODE_233:-${RPC_NODE_233:-${RPC_NODE_233:-${RPC_NODE_233:-${RPC_NODE_233:-${RPC_NODE_233:-192.168.11.233}}}}}}}" # Old 2303 (migrated from 2503) "${RPC_NODE_234:-${RPC_NODE_234:-${RPC_NODE_234:-${RPC_NODE_234:-${RPC_NODE_234:-${RPC_NODE_234:-${RPC_NODE_234:-192.168.11.234}}}}}}}" # Old 2304 (migrated from 2504) "${RPC_NODE_235:-${RPC_NODE_235:-${RPC_NODE_235:-${RPC_NODE_235:-${RPC_NODE_235:-${RPC_NODE_235:-${RPC_NODE_235:-192.168.11.235}}}}}}}" # Old 2305 (migrated from 2505) "${RPC_NODE_236:-${RPC_NODE_236:-${RPC_NODE_236:-${RPC_NODE_236:-${RPC_NODE_236:-${RPC_NODE_236:-${RPC_NODE_236:-192.168.11.236}}}}}}}" # Old 2306 (migrated from 2506) "${IP_RPC_237:-${IP_RPC_237:-${IP_RPC_237:-192.168.11.237}}}" # Old 2307 (migrated from 2507) "${IP_RPC_238:-${IP_RPC_238:-${IP_RPC_238:-192.168.11.238}}}" # Old 2308 (migrated from 2508) ) log_section "Reconciling Node Lists" # Step 1: Parse current file log_info "Step 1: Parsing current static-nodes.json..." declare -A CURRENT_ENODES declare -A IP_TO_ENODE if [ -f "$STATIC_NODES_FILE" ]; then while IFS= read -r line; do enode=$(echo "$line" | grep -o 'enode://[^"]*' || echo "") if [ -n "$enode" ]; then ip=$(echo "$enode" | sed -n 's/.*@\([0-9.]*\):.*/\1/p') CURRENT_ENODES["$ip"]="$enode" IP_TO_ENODE["$ip"]="$enode" fi done < <(cat "$STATIC_NODES_FILE" | jq -r '.[]' 2>/dev/null || grep -o 'enode://[^"]*' "$STATIC_NODES_FILE" 2>/dev/null || echo "") fi log_info " Found ${#CURRENT_ENODES[@]} enodes in current file" # Step 2: Identify issues log_section "Step 2: Identifying Issues" MISSING_NODES=() OLD_NODES=() VALID_NODES=() # Check each expected node for vmid in "${!CURRENT_NODES[@]}"; do ip="${CURRENT_NODES[$vmid]}" if [ -z "${CURRENT_ENODES[$ip]}" ]; then MISSING_NODES+=("$ip (VMID $vmid)") else VALID_NODES+=("$ip") fi done # Check for old IPs for ip in "${OLD_IPS[@]}"; do if [ -n "${CURRENT_ENODES[$ip]}" ]; then OLD_NODES+=("$ip") fi done log_info "Valid nodes: ${#VALID_NODES[@]}" log_info "Missing nodes: ${#MISSING_NODES[@]}" log_info "Old/migrated nodes to remove: ${#OLD_NODES[@]}" if [ ${#MISSING_NODES[@]} -gt 0 ]; then log_warn "Missing nodes:" for node in "${MISSING_NODES[@]}"; do log_warn " - $node" done fi if [ ${#OLD_NODES[@]} -gt 0 ]; then log_warn "Old/migrated IPs to remove:" for ip in "${OLD_NODES[@]}"; do log_warn " - $ip (enode: ${CURRENT_ENODES[$ip]})" fi fi # Step 3: Collect missing enodes from running nodes log_section "Step 3: Collecting Missing Enodes" declare -A NEW_ENODES=() # Keep valid enodes for ip in "${VALID_NODES[@]}"; do NEW_ENODES["$ip"]="${CURRENT_ENODES[$ip]}" done # Collect missing enodes from running nodes RPC_PORT=8545 for vmid in "${!CURRENT_NODES[@]}"; do ip="${CURRENT_NODES[$vmid]}" # Skip if already have enode if [ -n "${NEW_ENODES[$ip]}" ]; then continue fi # Check if node is running status=$(ssh -o ConnectTimeout=2 root@"$PROXMOX_HOST" "pct status $vmid 2>/dev/null" | awk '{print $2}' || echo "unknown") if [ "$status" != "running" ]; then log_info " VMID $vmid ($ip) not running - will need enode when started" continue fi # Try to get enode rpc_url="http://${ip}:${RPC_PORT}" enode=$(cast rpc admin_nodeInfo "$rpc_url" 2>/dev/null | jq -r '.enode' 2>/dev/null || echo "") if [ -n "$enode" ] && [ "$enode" != "null" ]; then NEW_ENODES["$ip"]="$enode" log_success " Collected: $ip (VMID $vmid)" else log_warn " Could not collect: $ip (VMID $vmid)" fi done # Step 4: Generate cleaned file log_section "Step 4: Generating Cleaned static-nodes.json" OUTPUT_FILE="$PROJECT_ROOT/smom-dbis-138/config/static-nodes.json.cleaned" # Sort IPs for consistent output declare -a SORTED_IPS for ip in "${!NEW_ENODES[@]}"; do SORTED_IPS+=("$ip") done IFS=$'\n' SORTED_IPS=($(sort <<<"${SORTED_IPS[*]}")) unset IFS echo "[" > "$OUTPUT_FILE" FIRST=true for ip in "${SORTED_IPS[@]}"; do if [ "$FIRST" = true ]; then FIRST=false else echo "," >> "$OUTPUT_FILE" fi echo -n " \"${NEW_ENODES[$ip]}\"" >> "$OUTPUT_FILE" done echo "" >> "$OUTPUT_FILE" echo "]" >> "$OUTPUT_FILE" # Verify JSON is valid if jq empty "$OUTPUT_FILE" 2>/dev/null; then log_success "Generated valid JSON: $OUTPUT_FILE" log_info " Contains ${#NEW_ENODES[@]} enodes" # Count by category VALIDATOR_COUNT=0 SENTRY_COUNT=0 RPC_COUNT=0 for ip in "${!NEW_ENODES[@]}"; do if [[ "$ip" =~ ^192\.168\.11\.(100|101|102|103|104)$ ]]; then ((VALIDATOR_COUNT++)) elif [[ "$ip" =~ ^192\.168\.11\.(150|151|152|153)$ ]]; then ((SENTRY_COUNT++)) else ((RPC_COUNT++)) fi done log_info " Validators: $VALIDATOR_COUNT/5" log_info " Sentries: $SENTRY_COUNT/4" log_info " RPC nodes: $RPC_COUNT/13" else log_error "Generated invalid JSON!" exit 1 fi # Step 5: Update files log_section "Step 5: Updating Files" BACKUP_FILE="${STATIC_NODES_FILE}.backup.$(date +%Y%m%d_%H%M%S)" cp "$STATIC_NODES_FILE" "$BACKUP_FILE" log_info "Backup created: $BACKUP_FILE" cp "$OUTPUT_FILE" "$STATIC_NODES_FILE" log_success "Updated: $STATIC_NODES_FILE" cp "$OUTPUT_FILE" "$PERMISSIONED_NODES_FILE" log_success "Updated: $PERMISSIONED_NODES_FILE" # Summary log_section "Reconciliation Complete" log_info "Summary:" log_info " - Removed ${#OLD_NODES[@]} old/migrated nodes" log_info " - Kept ${#VALID_NODES[@]} valid nodes" log_info " - Added missing enodes for running nodes" log_info " - Total enodes: ${#NEW_ENODES[@]}" log_info "" log_info "Files updated:" log_info " - $STATIC_NODES_FILE" log_info " - $PERMISSIONED_NODES_FILE" log_info "" log_info "Backup saved: $BACKUP_FILE"