#!/bin/bash # Complete RPC Translator Deployment Script # Handles SSH setup, deployment, configuration, and service startup set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" # 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}[⚠]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } log_section() { echo -e "${CYAN}════════════════════════════════════════${NC}"; } # VMID configuration declare -A VMIDS=( ["2400"]="192.168.11.240" ["2401"]="192.168.11.241" ["2402"]="192.168.11.242" ) PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}" DEPLOY_DIR="/opt/rpc-translator-138" # Function to check if we can access VMID via pct check_pct_access() { local vmid="$1" local vmip="$2" # Try to find which node has this VMID local node="" for n in ml110 r630-01 r630-02; do if ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@"$PROXMOX_HOST" \ "pvesh get /nodes/$n/lxc/$vmid/status/current --output-format json >/dev/null 2>&1" 2>/dev/null; then node="$n" break fi done if [ -n "$node" ]; then echo "$node" return 0 fi return 1 } # Global variable to store deployed ports declare -A DEPLOYED_PORTS # Function to deploy to VMID using pct deploy_via_pct() { local vmid="$1" local vmip="$2" local node="$3" log_info "Deploying to VMID $vmid via pct on node $node..." # Check if dist exists, if not try to build cd "$PROJECT_DIR" if [ ! -d "$PROJECT_DIR/dist" ]; then log_info "dist directory not found, building TypeScript..." if command -v node >/dev/null 2>&1; then if command -v pnpm >/dev/null 2>&1; then pnpm run build 2>&1 || npm run build 2>&1 || true else npm run build 2>&1 || true fi else log_warn "Node.js not found locally. Will build on target VMID." fi else log_success "Using existing dist directory" fi # Check if Node.js is installed on target log_info "Checking Node.js on VMID $vmid..." NODE_VERSION=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- node --version 2>/dev/null || echo 'not_installed'" 2>/dev/null || echo "not_installed") if [ "$NODE_VERSION" = "not_installed" ]; then log_warn "Node.js not found on VMID $vmid. Installing..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs'" 2>/dev/null || { log_error "Failed to install Node.js" return 1 } fi # Create deployment directory log_info "Creating deployment directory..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- mkdir -p $DEPLOY_DIR" 2>/dev/null || return 1 # Copy files using tar pipe (more reliable than pct push) log_info "Copying files to VMID $vmid..." # Copy essential files: package.json, env.template log_info "Copying package.json and env.template..." tar -czf - -C "$PROJECT_DIR" package.json env.template 2>/dev/null | \ ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'mkdir -p $DEPLOY_DIR && cd $DEPLOY_DIR && tar -xzf -'" 2>/dev/null || { log_error "Failed to copy package.json and env.template" return 1 } # Verify files were copied PACKAGE_EXISTS=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- test -f $DEPLOY_DIR/package.json && echo 'yes' || echo 'no'" 2>/dev/null || echo "no") if [ "$PACKAGE_EXISTS" != "yes" ]; then log_error "package.json not found after copy" return 1 fi log_success "Files copied successfully" # Copy dist directory or build on target if [ -d "$PROJECT_DIR/dist" ]; then log_info "Copying dist directory..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- mkdir -p $DEPLOY_DIR/dist" 2>/dev/null || return 1 # Copy dist files - preserve structure tar -czf - -C "$PROJECT_DIR" dist/ 2>/dev/null | \ ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'cd $DEPLOY_DIR && tar -xzf - && ls -la dist/ 2>&1 | head -10'" 2>/dev/null || return 1 # Verify main.js exists MAIN_JS=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- find $DEPLOY_DIR/dist -name 'main.js' -type f 2>/dev/null | head -1" 2>/dev/null || echo "") if [ -z "$MAIN_JS" ]; then log_error "main.js not found in dist directory" log_info "Checking dist structure..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- find $DEPLOY_DIR/dist -type f 2>/dev/null | head -10" 2>/dev/null || true return 1 fi log_success "Found main.js at: $MAIN_JS" else log_warn "dist directory not found locally, will build on target..." # Copy source files and build on target ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- mkdir -p $DEPLOY_DIR/src" 2>/dev/null || return 1 # Copy source and tsconfig tar -czf - -C "$PROJECT_DIR" src/ tsconfig.json 2>/dev/null | \ ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'cd $DEPLOY_DIR && tar -xzf -'" 2>/dev/null || return 1 # Build on target log_info "Building TypeScript on target VMID..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'cd $DEPLOY_DIR && npm install typescript --save-dev && npx tsc'" 2>/dev/null || { log_error "Build failed on target" return 1 } fi # Install dependencies log_info "Installing dependencies..." INSTALL_OUTPUT=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'cd $DEPLOY_DIR && npm install --production 2>&1'" 2>/dev/null) INSTALL_EXIT=$? if [ $INSTALL_EXIT -ne 0 ]; then log_error "Dependency installation failed" log_info "Output: $INSTALL_OUTPUT" return 1 fi log_success "Dependencies installed" # Copy systemd service (with corrected path) log_info "Installing systemd service..." # Read service file and fix the path SERVICE_CONTENT=$(cat "$PROJECT_DIR/systemd/rpc-translator-138.service" | sed 's|dist/main.js|dist/src/main.js|g') ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'cat > /etc/systemd/system/rpc-translator-138.service <<\"EOFSERVICE\" $SERVICE_CONTENT EOFSERVICE '" 2>/dev/null || { log_warn "Failed to copy systemd service via exec, trying pct push..." # Create temp file with corrected path TEMP_SERVICE=$(mktemp) sed 's|dist/main.js|dist/src/main.js|g' "$PROJECT_DIR/systemd/rpc-translator-138.service" > "$TEMP_SERVICE" ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct push $vmid $TEMP_SERVICE /etc/systemd/system/rpc-translator-138.service" 2>/dev/null || return 1 rm -f "$TEMP_SERVICE" } # Create .env file if it doesn't exist log_info "Configuring .env file..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'if [ ! -f $DEPLOY_DIR/.env ]; then cp $DEPLOY_DIR/env.template $DEPLOY_DIR/.env; fi'" 2>/dev/null || return 1 # Check if port 9545 is in use, if so use alternative port log_info "Checking port availability..." PORT_IN_USE=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- ss -tlnp 2>/dev/null | grep -q ':9545 ' && echo 'yes' || echo 'no'" 2>/dev/null || echo "no") if [ "$PORT_IN_USE" = "yes" ]; then log_warn "Port 9545 is in use, checking for alternative port..." # Try 9547, 9548, etc. ALT_PORT=9547 ALT_WS_PORT=9548 while ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- ss -tlnp 2>/dev/null | grep -q ':$ALT_PORT '" 2>/dev/null; do ALT_PORT=$((ALT_PORT + 2)) ALT_WS_PORT=$((ALT_WS_PORT + 2)) done log_info "Using alternative ports: HTTP $ALT_PORT, WS $ALT_WS_PORT" HTTP_PORT=$ALT_PORT WS_PORT=$ALT_WS_PORT else HTTP_PORT=9545 WS_PORT=9546 fi # Store ports for summary DEPLOYED_PORTS[$vmid]="$HTTP_PORT:$WS_PORT" # Update .env with correct values log_info "Updating .env configuration..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- bash -c 'cat > $DEPLOY_DIR/.env </dev/null || return 1 # Reload systemd and enable service log_info "Enabling systemd service..." DAEMON_RELOAD=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- systemctl daemon-reload 2>&1" 2>/dev/null) if [ $? -ne 0 ]; then log_error "Failed to reload systemd: $DAEMON_RELOAD" return 1 fi ENABLE_OUTPUT=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- systemctl enable rpc-translator-138.service 2>&1" 2>/dev/null) if [ $? -ne 0 ]; then log_error "Failed to enable service: $ENABLE_OUTPUT" # Check if service file exists SERVICE_EXISTS=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- test -f /etc/systemd/system/rpc-translator-138.service && echo 'yes' || echo 'no'" 2>/dev/null || echo "no") if [ "$SERVICE_EXISTS" != "yes" ]; then log_error "Service file not found at /etc/systemd/system/rpc-translator-138.service" fi return 1 fi log_success "Service enabled" # Start service log_info "Starting service..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- systemctl start rpc-translator-138.service" 2>/dev/null || { log_warn "Service start failed, checking status..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- systemctl status rpc-translator-138.service --no-pager -l | head -20" 2>/dev/null || true return 1 } # Wait a moment for service to start sleep 2 # Check service status log_info "Checking service status..." SERVICE_STATUS=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- systemctl is-active rpc-translator-138.service 2>/dev/null || echo 'inactive'" 2>/dev/null || echo "unknown") if [ "$SERVICE_STATUS" = "active" ]; then log_success "Service is running on VMID $vmid" else log_warn "Service status: $SERVICE_STATUS" log_info "Checking logs..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $vmid -- journalctl -u rpc-translator-138.service --no-pager -n 20" 2>/dev/null || true fi # Test endpoint log_info "Testing HTTP endpoint on port $HTTP_PORT..." sleep 2 HTTP_RESPONSE=$(curl -s -X POST "http://${vmip}:${HTTP_PORT}" \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' 2>/dev/null || echo "") if echo "$HTTP_RESPONSE" | grep -q "0x8a"; then log_success "HTTP endpoint responding correctly on VMID $vmid (port $HTTP_PORT)" else log_warn "HTTP endpoint test failed or not ready yet" log_info "Response: $HTTP_RESPONSE" # Check if service is still starting sleep 2 HTTP_RESPONSE2=$(curl -s -X POST "http://${vmip}:${HTTP_PORT}" \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' 2>/dev/null || echo "") if echo "$HTTP_RESPONSE2" | grep -q "0x8a"; then log_success "HTTP endpoint now responding on VMID $vmid (port $HTTP_PORT)" fi fi return 0 } # Main deployment log_section log_info "RPC Translator Service - Complete Deployment" log_section echo "" # Check prerequisites log_info "Checking prerequisites..." if ! ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@"$PROXMOX_HOST" "echo 'Connected'" >/dev/null 2>&1; then log_error "Cannot connect to Proxmox host $PROXMOX_HOST" exit 1 fi log_success "Proxmox host accessible" echo "" # Deploy to each VMID FAILED_VMIDS=() SUCCESS_VMIDS=() for VMID in "${!VMIDS[@]}"; do VMIP="${VMIDS[$VMID]}" log_section log_info "Deploying to VMID $VMID ($VMIP)" log_section echo "" # Try to find node NODE=$(check_pct_access "$VMID" "$VMIP" 2>/dev/null || echo "") if [ -z "$NODE" ]; then log_warn "Could not find VMID $VMID via pct, trying direct SSH..." # Try direct deployment via SSH if deploy_via_pct "$VMID" "$VMIP" "direct" 2>/dev/null; then SUCCESS_VMIDS+=("$VMID") else log_error "Failed to deploy to VMID $VMID" FAILED_VMIDS+=("$VMID") fi else if deploy_via_pct "$VMID" "$VMIP" "$NODE"; then SUCCESS_VMIDS+=("$VMID") else log_error "Failed to deploy to VMID $VMID" FAILED_VMIDS+=("$VMID") fi fi echo "" done # Summary log_section log_info "Deployment Summary" log_section echo "" if [ ${#SUCCESS_VMIDS[@]} -gt 0 ]; then log_success "Successfully deployed to: ${SUCCESS_VMIDS[*]}" echo "" log_info "Service endpoints:" for vmid in "${SUCCESS_VMIDS[@]}"; do vmip="${VMIDS[$vmid]}" ports="${DEPLOYED_PORTS[$vmid]:-9545:9546}" http_port="${ports%%:*}" ws_port="${ports#*:}" echo " VMID $vmid: http://${vmip}:${http_port} (HTTP), ws://${vmip}:${ws_port} (WebSocket)" done echo "" fi if [ ${#FAILED_VMIDS[@]} -gt 0 ]; then log_error "Failed to deploy to: ${FAILED_VMIDS[*]}" echo "" log_info "To retry deployment:" for vmid in "${FAILED_VMIDS[@]}"; do vmip="${VMIDS[$vmid]}" echo " ./scripts/deploy-to-vmid.sh $vmid $vmip" done echo "" fi log_section log_info "Deployment Complete" log_section echo ""