Files
proxmox/scripts/archive/consolidated/deploy/deploy-services-to-proxmox.sh
defiQUG fbda1b4beb
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands
- CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround
- CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check
- NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere
- MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates
- LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 15:46:57 -08:00

287 lines
9.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Deploy Off-Chain Services (State Anchoring & Transaction Mirroring) to Proxmox Container
set -euo pipefail
# Load IP configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(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}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_detail() { echo -e "${CYAN}[DETAIL]${NC} $1"; }
# Configuration
VMID="${VMID:-5000}"
PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}"
PROXMOX_USER="${PROXMOX_USER:-root}"
SERVICES_DIR="${PROJECT_ROOT}/smom-dbis-138/services"
DEPLOY_USER="${DEPLOY_USER:-deploy}"
DEPLOY_HOME="/home/${DEPLOY_USER}"
DEPLOY_DIR="${DEPLOY_HOME}/services"
# Load .env if exists
if [ -f "${PROJECT_ROOT}/.env" ]; then
source "${PROJECT_ROOT}/.env"
log_info "Loaded environment variables from .env"
fi
# Check prerequisites
check_prerequisites() {
log_info "Checking prerequisites..."
if ! command -v ssh &> /dev/null; then
log_error "ssh command not found"
exit 1
fi
if ! ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no "${PROXMOX_USER}@${PROXMOX_HOST}" "pct list | grep -q '^\s*${VMID}\s'" 2>/dev/null; then
log_error "Container ${VMID} does not exist on ${PROXMOX_HOST}"
log_info "Available options:"
log_info " 1. Create container first using: pct create ${VMID} ..."
log_info " 2. Use existing container: Set VMID=<existing_vmid>"
exit 1
fi
log_success "Prerequisites check passed"
}
# Test SSH connection to container
test_container_connection() {
log_info "Testing connection to container ${VMID}..."
local container_ip
if [ -n "${CONTAINER_IP:-}" ]; then
container_ip="${CONTAINER_IP}"
else
log_detail "Getting container IP from Proxmox..."
container_ip=$(ssh "${PROXMOX_USER}@${PROXMOX_HOST}" "pct exec ${VMID} -- hostname -I | awk '{print \$1}'" 2>/dev/null || echo "")
fi
if [ -z "${container_ip}" ]; then
log_error "Could not determine container IP. Set CONTAINER_IP environment variable."
exit 1
fi
log_success "Container IP: ${container_ip}"
# Test connection
if ! ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no "root@${container_ip}" "echo 'Connected'" 2>/dev/null; then
log_warn "Direct SSH to container IP failed. Using pct exec instead."
USE_PCT_EXEC=true
else
USE_PCT_EXEC=false
CONTAINER_IP="${container_ip}"
fi
log_success "Connection method: $([ "$USE_PCT_EXEC" = "true" ] && echo "pct exec" || echo "SSH direct")"
}
# Execute command in container
exec_container() {
local cmd="$1"
if [ "$USE_PCT_EXEC" = "true" ]; then
ssh "${PROXMOX_USER}@${PROXMOX_HOST}" "pct exec ${VMID} -- bash -c '${cmd}'"
else
ssh "root@${CONTAINER_IP}" "${cmd}"
fi
}
# Push file to container
push_file() {
local local_file="$1"
local remote_file="$2"
if [ "$USE_PCT_EXEC" = "true" ]; then
ssh "${PROXMOX_USER}@${PROXMOX_HOST}" "pct push ${VMID} '${local_file}' '${remote_file}'"
else
scp "${local_file}" "root@${CONTAINER_IP}:${remote_file}"
fi
}
# Install Node.js in container
install_nodejs() {
log_info "Installing Node.js..."
exec_container "command -v node >/dev/null 2>&1 && node --version || echo 'NOT_INSTALLED'" | grep -q "NOT_INSTALLED" || {
log_success "Node.js already installed: $(exec_container 'node --version')"
return 0
}
log_detail "Installing Node.js 20.x..."
exec_container "export DEBIAN_FRONTEND=noninteractive && \
apt-get update -qq && \
apt-get install -y -qq curl ca-certificates gnupg && \
mkdir -p /etc/apt/keyrings && \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
echo 'deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main' > /etc/apt/sources.list.d/nodesource.list && \
apt-get update -qq && \
apt-get install -y -qq nodejs"
log_success "Node.js installed: $(exec_container 'node --version')"
}
# Install PM2 in container
install_pm2() {
log_info "Installing PM2..."
exec_container "command -v pm2 >/dev/null 2>&1 && pm2 --version || echo 'NOT_INSTALLED'" | grep -q "NOT_INSTALLED" || {
log_success "PM2 already installed: $(exec_container 'pm2 --version')"
return 0
}
exec_container "npm install -g pm2"
log_success "PM2 installed: $(exec_container 'pm2 --version')"
}
# Create deployment user
create_deploy_user() {
log_info "Creating deployment user..."
exec_container "id ${DEPLOY_USER} >/dev/null 2>&1 || useradd -m -s /bin/bash ${DEPLOY_USER}"
exec_container "mkdir -p ${DEPLOY_DIR} && chown -R ${DEPLOY_USER}:${DEPLOY_USER} ${DEPLOY_DIR}"
log_success "Deployment user created: ${DEPLOY_USER}"
}
# Deploy service to container
deploy_service() {
local service_name="$1"
local service_path="${SERVICES_DIR}/${service_name}"
log_info "Deploying ${service_name}..."
if [ ! -d "${service_path}" ]; then
log_error "Service directory not found: ${service_path}"
return 1
fi
# Create service directory in container
exec_container "mkdir -p ${DEPLOY_DIR}/${service_name}"
# Copy service files
log_detail "Copying service files..."
if [ "$USE_PCT_EXEC" = "true" ]; then
# Using pct push requires tar archive for directories
(cd "${service_path}" && tar czf - .) | ssh "${PROXMOX_USER}@${PROXMOX_HOST}" "pct exec ${VMID} -- tar xzf - -C ${DEPLOY_DIR}/${service_name}"
else
scp -r "${service_path}/"* "root@${CONTAINER_IP}:${DEPLOY_DIR}/${service_name}/"
fi
# Copy .env if exists
if [ -f "${PROJECT_ROOT}/.env" ]; then
push_file "${PROJECT_ROOT}/.env" "${DEPLOY_DIR}/${service_name}/.env"
elif [ -f "${service_path}/.env" ]; then
push_file "${service_path}/.env" "${DEPLOY_DIR}/${service_name}/.env"
else
log_warn "No .env file found. Service may need manual configuration."
fi
# Install dependencies and build
log_detail "Installing dependencies..."
exec_container "cd ${DEPLOY_DIR}/${service_name} && \
export NODE_ENV=production && \
npm ci --omit=dev && \
npm run build"
# Fix permissions
exec_container "chown -R ${DEPLOY_USER}:${DEPLOY_USER} ${DEPLOY_DIR}/${service_name}"
log_success "${service_name} deployed successfully"
}
# Deploy services with PM2
deploy_pm2() {
log_info "Deploying services with PM2..."
# Deploy state-anchoring-service
log_detail "Deploying state-anchoring-service..."
exec_container "cd ${DEPLOY_DIR}/state-anchoring-service && \
su - ${DEPLOY_USER} -c 'cd ${DEPLOY_DIR}/state-anchoring-service && \
pm2 delete state-anchoring-service 2>/dev/null || true && \
pm2 start dist/index.js --name state-anchoring-service && \
pm2 save'"
# Deploy transaction-mirroring-service
log_detail "Deploying transaction-mirroring-service..."
exec_container "cd ${DEPLOY_DIR}/transaction-mirroring-service && \
su - ${DEPLOY_USER} -c 'cd ${DEPLOY_DIR}/transaction-mirroring-service && \
pm2 delete transaction-mirroring-service 2>/dev/null || true && \
pm2 start dist/index.js --name transaction-mirroring-service && \
pm2 save'"
# Setup PM2 startup
exec_container "su - ${DEPLOY_USER} -c 'pm2 startup systemd -u ${DEPLOY_USER} --hp ${DEPLOY_HOME}'" || {
log_warn "PM2 startup command may need manual execution. See logs above."
}
log_success "Services deployed with PM2"
}
# Verify deployment
verify_deployment() {
log_info "Verifying deployment..."
log_detail "Checking PM2 status..."
exec_container "su - ${DEPLOY_USER} -c 'pm2 status'" || {
log_error "PM2 status check failed"
return 1
}
log_detail "Checking service logs (last 10 lines)..."
exec_container "su - ${DEPLOY_USER} -c 'pm2 logs state-anchoring-service --lines 10 --nostream'" || true
exec_container "su - ${DEPLOY_USER} -c 'pm2 logs transaction-mirroring-service --lines 10 --nostream'" || true
log_success "Deployment verification complete"
}
# Main deployment function
main() {
log_info "=== Deploying Off-Chain Services to Proxmox ==="
log_info "VMID: ${VMID}"
log_info "Proxmox Host: ${PROXMOX_HOST}"
log_info "Services Directory: ${SERVICES_DIR}"
log_info ""
check_prerequisites
test_container_connection
install_nodejs
install_pm2
create_deploy_user
# Deploy services
deploy_service "state-anchoring-service"
deploy_service "transaction-mirroring-service"
# Deploy with PM2
deploy_pm2
# Verify
verify_deployment
log_success ""
log_success "=== Deployment Complete ==="
log_info ""
log_info "Services are running on container ${VMID}"
log_info "To check status: ssh ${PROXMOX_USER}@${PROXMOX_HOST} 'pct exec ${VMID} -- su - ${DEPLOY_USER} -c \"pm2 status\"'"
log_info "To view logs: ssh ${PROXMOX_USER}@${PROXMOX_HOST} 'pct exec ${VMID} -- su - ${DEPLOY_USER} -c \"pm2 logs\"'"
log_info ""
}
# Run main function
main "$@"