Files
proxmox/scripts/fix-enode-configs-practical.sh

252 lines
8.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# Practical fix for enode URLs: Extract first 128 chars and map to correct IPs
# Based on Besu requirements: enode IDs must be exactly 128 hex characters
set -euo pipefail
PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}"
WORK_DIR="/tmp/fix-enodes-$$"
mkdir -p "$WORK_DIR"
cleanup() { rm -rf "$WORK_DIR"; }
trap cleanup EXIT
# Container IP mapping
declare -A CONTAINER_IPS=(
[106]="192.168.11.13" # besu-validator-1
[107]="192.168.11.14" # besu-validator-2
[108]="192.168.11.15" # besu-validator-3
[109]="192.168.11.16" # besu-validator-4
[110]="192.168.11.18" # besu-validator-5
[111]="192.168.11.19" # besu-sentry-2
[112]="192.168.11.20" # besu-sentry-3
[113]="192.168.11.21" # besu-sentry-4
[114]="192.168.11.22" # besu-sentry-5
[115]="192.168.11.23" # besu-rpc-1
[116]="192.168.11.24" # besu-rpc-2
[117]="192.168.11.25" # besu-rpc-3
)
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Extract and fix enodes from a container's current static-nodes.json
extract_and_fix_enodes() {
local vmid="$1"
local container_ip="${CONTAINER_IPS[$vmid]}"
log_info "Processing container $vmid ($container_ip)..."
# Get current static-nodes.json
local current_json
current_json=$(ssh -o StrictHostKeyChecking=accept-new "root@${PROXMOX_HOST}" \
"pct exec $vmid -- cat /etc/besu/static-nodes.json 2>/dev/null" || echo '[]')
if [[ "$current_json" == "[]" ]] || [[ -z "$current_json" ]]; then
log_warn "Container $vmid: No static-nodes.json found"
return 1
fi
# Extract node IDs (first 128 chars) and create corrected enodes
python3 << PYEOF
import json
import re
try:
static_nodes = json.loads('''$current_json''')
except:
static_nodes = []
fixed_enodes = []
node_ids_seen = set()
for i, enode in enumerate(static_nodes):
# Extract hex part
match = re.search(r'enode://([a-fA-F0-9]+)@', enode)
if not match:
continue
full_hex = match.group(1).lower()
# Take first 128 chars (removes trailing zeros padding)
node_id = full_hex[:128]
if len(node_id) != 128:
print(f"SKIP: Node ID {i+1} has length {len(node_id)}, not 128", file=sys.stderr)
continue
# Validate hex
if not re.match(r'^[0-9a-f]{128}$', node_id):
print(f"SKIP: Node ID {i+1} contains invalid hex", file=sys.stderr)
continue
# Map first 5 to validator IPs (106-110), others keep original IP for now
if i < 5:
vmid_map = 106 + i
if vmid_map in ${!CONTAINER_IPS[@]}:
ip = "${CONTAINER_IPS[$vmid_map]}"
else:
# Extract original IP
ip_match = re.search(r'@([0-9.]+):', enode)
ip = ip_match.group(1) if ip_match else "$container_ip"
else:
# Extract original IP
ip_match = re.search(r'@([0-9.]+):', enode)
ip = ip_match.group(1) if ip_match else "$container_ip"
fixed_enode = f"enode://{node_id}@{ip}:30303"
# Avoid duplicates
if node_id not in node_ids_seen:
fixed_enodes.append(fixed_enode)
node_ids_seen.add(node_id)
# Save to file
with open('$WORK_DIR/static-nodes-${vmid}.json', 'w') as f:
json.dump(fixed_enodes, f, indent=2)
print(f"Fixed {len(fixed_enodes)} enode URLs for container $vmid")
PYEOF
return 0
}
# Generate corrected permissions-nodes.toml from all containers
generate_permissions_toml() {
log_info "Generating corrected permissions-nodes.toml..."
# Collect all unique enodes from all containers
python3 << 'PYEOF'
import json
import re
import glob
all_enodes = set()
# Read all fixed static-nodes.json files
for json_file in glob.glob('$WORK_DIR/static-nodes-*.json'):
try:
with open(json_file, 'r') as f:
enodes = json.load(f)
for enode in enodes:
all_enodes.add(enode)
except:
pass
# Sort for consistency
sorted_enodes = sorted(all_enodes)
# Generate TOML
toml_content = """# Node Permissioning Configuration
# Lists nodes that are allowed to connect to this node
# Generated from actual container enodes (first 128 chars of node IDs)
# All validators, sentries, and RPC nodes are included
nodes-allowlist=[
"""
for enode in sorted_enodes:
toml_content += f' "{enode}",\n'
# Remove trailing comma
toml_content = toml_content.rstrip(',\n') + '\n]'
with open('$WORK_DIR/permissions-nodes.toml', 'w') as f:
f.write(toml_content)
print(f"Generated permissions-nodes.toml with {len(sorted_enodes)} unique nodes")
PYEOF
log_success "Generated permissions-nodes.toml"
}
# Deploy corrected files
deploy_files() {
log_info "Deploying corrected files to all containers..."
# First, copy permissions-nodes.toml to host
scp -o StrictHostKeyChecking=accept-new \
"$WORK_DIR/permissions-nodes.toml" \
"root@${PROXMOX_HOST}:/tmp/permissions-nodes-fixed.toml"
for vmid in 106 107 108 109 110 111 112 113 114 115 116 117; do
if ! ssh -o StrictHostKeyChecking=accept-new "root@${PROXMOX_HOST}" \
"pct status $vmid 2>/dev/null | grep -q running"; then
log_warn "Container $vmid: not running, skipping"
continue
fi
log_info "Deploying to container $vmid..."
# Copy static-nodes.json (container-specific)
if [[ -f "$WORK_DIR/static-nodes-${vmid}.json" ]]; then
scp -o StrictHostKeyChecking=accept-new \
"$WORK_DIR/static-nodes-${vmid}.json" \
"root@${PROXMOX_HOST}:/tmp/static-nodes-${vmid}.json"
ssh -o StrictHostKeyChecking=accept-new "root@${PROXMOX_HOST}" << REMOTE_SCRIPT
pct push $vmid /tmp/static-nodes-${vmid}.json /etc/besu/static-nodes.json
pct exec $vmid -- chown besu:besu /etc/besu/static-nodes.json
rm -f /tmp/static-nodes-${vmid}.json
REMOTE_SCRIPT
fi
# Copy permissions-nodes.toml (same for all)
ssh -o StrictHostKeyChecking=accept-new "root@${PROXMOX_HOST}" << REMOTE_SCRIPT
pct push $vmid /tmp/permissions-nodes-fixed.toml /etc/besu/permissions-nodes.toml
pct exec $vmid -- chown besu:besu /etc/besu/permissions-nodes.toml
REMOTE_SCRIPT
log_success "Container $vmid: files deployed"
done
# Cleanup
ssh -o StrictHostKeyChecking=accept-new "root@${PROXMOX_HOST}" \
"rm -f /tmp/permissions-nodes-fixed.toml"
}
# Main
main() {
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ FIX ENODE CONFIGS (EXTRACT FIRST 128 CHARS) ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
# Process all containers
for vmid in 106 107 108 109 110 111 112 113 114 115 116 117; do
extract_and_fix_enodes "$vmid" || true
done
generate_permissions_toml
echo ""
log_info "Preview of generated files:"
echo ""
echo "=== static-nodes.json (container 106) ==="
cat "$WORK_DIR/static-nodes-106.json" 2>/dev/null | head -10 || echo "Not generated"
echo ""
echo "=== permissions-nodes.toml (first 20 lines) ==="
cat "$WORK_DIR/permissions-nodes.toml" | head -20
echo ""
read -p "Deploy corrected files to all containers? [y/N]: " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
deploy_files
log_success "All files deployed!"
log_info "Next: Restart Besu services on all containers"
else
log_info "Files available in $WORK_DIR for review"
fi
}
main "$@"