#!/usr/bin/env bash # RemoteRig — Pi-side deploy script # Deploys a new binary with backup, health-check, and automatic rollback. # # Usage: # sudo ./deploy.sh [BINARY_PATH] [DEPLOY_PATH] [SERVICE_NAME] # # Defaults: # BINARY_PATH = ./remoterig (new binary to deploy) # DEPLOY_PATH = /opt/remoterig/remoterig # SERVICE_NAME = remoterig # # Examples: # # Deploy locally-built binary with defaults # sudo ./deploy.sh ./remoterig # # # Custom paths # sudo ./deploy.sh /tmp/remoterig-arm64 /opt/remoterig/remoterig remoterig set -euo pipefail # --------------------------------------------------------------------------- # Args # --------------------------------------------------------------------------- BINARY="${1:-remoterig}" DEPLOY_PATH="${2:-/opt/remoterig/remoterig}" SERVICE="${3:-remoterig}" TIMESTAMP="$(date +%Y%m%d%H%M%S)" BACKUP="${DEPLOY_PATH}.${TIMESTAMP}.bak" MAX_BACKUPS=3 # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- info() { echo "[INFO] $*"; } ok() { echo "[OK] $*"; } fail() { echo "[FAIL] $*" >&2; } # --------------------------------------------------------------------------- # Pre-flight checks # --------------------------------------------------------------------------- if [ "$(id -u)" -ne 0 ]; then echo "ERROR: must run as root (sudo ./deploy.sh ...)" >&2 exit 1 fi if [ ! -f "${BINARY}" ]; then fail "Binary not found: ${BINARY}" exit 1 fi echo "==============================================" echo " RemoteRig Deploy" echo " Binary: ${BINARY}" echo " Deploy path: ${DEPLOY_PATH}" echo " Service: ${SERVICE}" echo " Timestamp: ${TIMESTAMP}" echo "==============================================" # --------------------------------------------------------------------------- # 1. Backup existing binary # --------------------------------------------------------------------------- info "Backing up current binary..." if [ -f "${DEPLOY_PATH}" ]; then cp "${DEPLOY_PATH}" "${BACKUP}" ok "Backed up to ${BACKUP}" else info "No existing binary at ${DEPLOY_PATH} — fresh install" fi # --------------------------------------------------------------------------- # 2. Deploy new binary # --------------------------------------------------------------------------- info "Deploying new binary..." cp "${BINARY}" "${DEPLOY_PATH}" chmod +x "${DEPLOY_PATH}" ok "Binary installed at ${DEPLOY_PATH}" # --------------------------------------------------------------------------- # 3. Reload systemd and restart service # --------------------------------------------------------------------------- info "Reloading systemd and restarting ${SERVICE}..." systemctl daemon-reload # Restart (or start if not running) if systemctl is-active --quiet "${SERVICE}" 2>/dev/null; then systemctl restart "${SERVICE}" else systemctl start "${SERVICE}" fi ok "Service restart issued" # --------------------------------------------------------------------------- # 4. Health check # --------------------------------------------------------------------------- info "Waiting 3s for service to stabilize..." sleep 3 if systemctl is-active --quiet "${SERVICE}"; then ok "${SERVICE} is active — deploy successful" # Optional: curl health endpoint if command -v curl >/dev/null 2>&1; then HEALTH_URL="http://localhost:8080/health" if curl -sf --max-time 3 "${HEALTH_URL}" >/dev/null 2>&1; then ok "Health check passed: ${HEALTH_URL}" else info "Health endpoint not reachable (may need more startup time)" fi fi else fail "${SERVICE} is NOT active — rolling back" # ----------------------------------------------------------------------- # 5. Rollback on failure # ----------------------------------------------------------------------- if [ -f "${BACKUP}" ]; then info "Restoring backup: ${BACKUP}" cp "${BACKUP}" "${DEPLOY_PATH}" chmod +x "${DEPLOY_PATH}" systemctl restart "${SERVICE}" 2>/dev/null || true sleep 2 if systemctl is-active --quiet "${SERVICE}"; then ok "Rollback successful — previous binary restored and service is active" else fail "Rollback failed — service still not active" echo "Check logs: journalctl -u ${SERVICE} -n 50" >&2 exit 1 fi else fail "No backup available — cannot roll back" echo "Check logs: journalctl -u ${SERVICE} -n 50" >&2 exit 1 fi fi # --------------------------------------------------------------------------- # 6. Cleanup old backups (keep last N) # --------------------------------------------------------------------------- info "Cleaning up old backups (keeping last ${MAX_BACKUPS})..." DEPLOY_DIR="$(dirname "${DEPLOY_PATH}")" BASE_NAME="$(basename "${DEPLOY_PATH}")" # List backups, skip current, keep last MAX_BACKUPS, delete the rest ls -1t "${DEPLOY_DIR}/${BASE_NAME}."*.bak 2>/dev/null | \ tail -n +$((MAX_BACKUPS + 1)) | \ while IFS= read -r old_backup; do rm -f "${old_backup}" info "Removed old backup: $(basename "${old_backup}")" done ok "Deploy complete — ${MAX_BACKUPS} backups retained" echo ""