AkurAI Build
Menu

Public repository / master

AkurAI-Drive / backend/deploy.sh

Latest change d63e826eb482cb963477774b04fe8a84f23f0e45 - deploy: in-place swaps matching live units with health-checked rollback; no unit rewrites by AkurAI Agent

#!/usr/bin/env bash
# Deploy rules of conduct:
# - Read AGENTS.md and canonical Notes/docs before changing or deploying.
# - Never print, commit, or copy secrets; use passvault/env files only.
# - Preserve env files, service users, user data, and databases; snapshot state before risky swaps.
# - Verify ports, DNS, TLS, and systemd unit names before changing routes or services.
# - Use managed services only (systemd/pm2); no nohup, background shells, or ad hoc daemons.
# - Run gates and health checks; if deploy fails, stop and roll back rather than improvising.
#
# Live layout (systemd unit akurai-drive-api, owned by the host, NOT managed here):
#   binary  /opt/akurai-drive-api/bin/akurai-drive-api  (User=drive)
#   env     /etc/akurai-drive-api.env                   (never read or written here)
# Swaps the binary in place (previous kept as .prev), restarts, health-checks
# /api/health and rolls back on failure.
set -euo pipefail

SSH_HOST="${AKURAI_MAIL_SSH:-akurai-ec2}"
SERVICE="akurai-drive-api"
TARGET="x86_64-unknown-linux-musl"
PORT="${DRIVE_PORT:-8096}"

log()  { echo "[deploy] $*"; }
step() { echo; echo "── $* ──"; }
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
BINARY_PATH="${DRIVE_API_BINARY:-}"
while (($#)); do
  case "$1" in
    --binary)
      BINARY_PATH="${2:?--binary requires a path}"
      shift 2
      ;;
    *)
      echo "usage: $0 [--binary PATH]" >&2
      exit 2
      ;;
  esac
done
if [[ -n "$BINARY_PATH" && "$BINARY_PATH" != /* ]]; then
  BINARY_PATH="$ROOT_DIR/$BINARY_PATH"
fi

if [[ -n "$BINARY_PATH" ]]; then
  BINARY="$BINARY_PATH"
else
  step "Build (musl static)"
  (cd "$SCRIPT_DIR" && CC_x86_64_unknown_linux_musl=musl-gcc cargo build --release --target "$TARGET")
  BINARY="$SCRIPT_DIR/target/$TARGET/release/akurai-drive-api"
fi
test -x "$BINARY"
log "Binary: $(du -sh "$BINARY" | cut -f1)"

STAGE="/tmp/akurai-drive-api-$(date +%Y%m%d%H%M%S)"
step "Upload"
scp -q "$BINARY" "$SSH_HOST:$STAGE"

step "Swap, restart, health-check (rollback on failure)"
ssh "$SSH_HOST" "sudo bash -s -- '$STAGE' '$PORT'" <<'REMOTE'
set -euo pipefail
stage="$1"; port="$2"
bin=/opt/akurai-drive-api/bin/akurai-drive-api
service=akurai-drive-api

healthy() {
  for _ in $(seq 1 20); do
    curl -fsS -o /dev/null "http://127.0.0.1:$port/api/health" && return 0
    sleep 1
  done
  return 1
}

test -x "$bin"
cp -a "$bin" "$bin.prev"
install -m 755 "$stage" "$bin.new"
mv -f "$bin.new" "$bin"
rm -f "$stage"
systemctl restart "$service"

if healthy; then
  echo "  [ok] $service healthy"
  exit 0
fi

echo "  [FAIL] health check failed; rolling back" >&2
cp -a "$bin.prev" "$bin"
systemctl restart "$service"
if healthy; then echo "  [rollback] previous binary healthy" >&2; else echo "  [rollback] STILL UNHEALTHY" >&2; fi
exit 1
REMOTE

log "Deployed $SERVICE to $SSH_HOST (port $PORT; previous at bin/akurai-drive-api.prev)"