Files
Kordant/scripts/setup-pan.sh

253 lines
7.9 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
# ─── Kordant Scheduler — Pan Server Setup ─────────────────────
# Usage:
# bash scripts/setup-pan.sh # interactively
# bash scripts/setup-pan.sh user@pan # interactively, remote
# bash scripts/setup-pan.sh -u <url> -d <url> ...
#
# Flags:
# -u, --gitea-url URL Gitea clone URL (skip prompt)
# -d, --db-url URL Turso database URL (skip prompt)
# -t, --db-token TOKEN Turso auth token (skip prompt)
# -k, --hooks-dir DIR Gitea hooks directory (skip prompt; empty=skip hook)
# --host HOST SSH host (default: pan)
# -y, --non-interactive Skip all prompts (requires -u, -d, -t)
# -h, --help Show this message
# ─── Defaults ───────────────────────────────────────────────────
PAN_HOST=""
GITEA_URL=""
DB_URL=""
DB_TOKEN=""
HOOKS_DIR=""
NON_INTERACTIVE=false
REPO_DIR="/opt/kordant"
# ─── Help ───────────────────────────────────────────────────────
usage() {
sed -n 's/^# //p; s/^#$//p' "$0"
exit 0
}
# ─── Parse flags ────────────────────────────────────────────────
while [ $# -gt 0 ]; do
case "$1" in
-u|--gitea-url) GITEA_URL="$2"; shift 2 ;;
-d|--db-url) DB_URL="$2"; shift 2 ;;
-t|--db-token) DB_TOKEN="$2"; shift 2 ;;
-k|--hooks-dir) HOOKS_DIR="$2"; shift 2 ;;
--host) PAN_HOST="$2"; shift 2 ;;
-y|--non-interactive) NON_INTERACTIVE=true; shift ;;
-h|--help) usage ;;
-*)
echo "Unknown option: $1"
usage
;;
*) PAN_HOST="${PAN_HOST:-$1}"; shift ;;
esac
done
PAN_HOST="${PAN_HOST:-pan}"
# ─── Remote detection ───────────────────────────────────────────
if [ "$(hostname)" != "pan" ] && [ "$(hostname -s 2>/dev/null)" != "pan" ]; then
if [ -n "${SSH_CONNECTION:-}" ]; then
echo "Already connected to pan via SSH."
else
echo "Not on pan. Connecting to $PAN_HOST via SSH..."
# Rebuild the flag string to pass through
FLAGS=""
[ -n "$GITEA_URL" ] && FLAGS="$FLAGS -u '$GITEA_URL'"
[ -n "$DB_URL" ] && FLAGS="$FLAGS -d '$DB_URL'"
[ -n "$DB_TOKEN" ] && FLAGS="$FLAGS -t '$DB_TOKEN'"
[ -n "$HOOKS_DIR" ] && FLAGS="$FLAGS -k '$HOOKS_DIR'"
$NON_INTERACTIVE && FLAGS="$FLAGS -y"
scp "$0" "${PAN_HOST}:/tmp/kordant-setup.sh"
ssh -t "$PAN_HOST" "sudo bash /tmp/kordant-setup.sh $FLAGS && rm /tmp/kordant-setup.sh"
exit $?
fi
fi
echo "=== Kordant Scheduler Setup (running on pan) ==="
# ─── Step 1: Install prerequisites ─────────────────────────────
echo "--- Step 1: Checking prerequisites ---"
if ! command -v docker &>/dev/null; then
echo "Installing Docker..."
curl -fsSL https://get.docker.com | bash
systemctl enable --now docker
else
echo "Docker already installed."
fi
if ! docker compose version &>/dev/null; then
echo "Installing Docker Compose plugin..."
apt-get update && apt-get install -y docker-compose-plugin
else
echo "Docker Compose plugin already installed."
fi
if ! command -v git &>/dev/null; then
echo "Installing git..."
apt-get update && apt-get install -y git
else
echo "Git already installed."
fi
# ─── Step 2: Clone or pull the repo ────────────────────────────
echo "--- Step 2: Setting up repo at $REPO_DIR ---"
if [ ! -d "$REPO_DIR/.git" ]; then
if [ -z "$GITEA_URL" ]; then
if $NON_INTERACTIVE; then
echo "❌ --gitea-url is required in non-interactive mode"
exit 1
fi
while [ -z "$GITEA_URL" ]; do
read -rp "Gitea clone URL (e.g. http://localhost:3000/kordant/kordant.git): " GITEA_URL
done
fi
echo "Cloning $GITEA_URL ..."
git clone "$GITEA_URL" "$REPO_DIR"
cd "$REPO_DIR"
else
echo "Repo exists. Pulling latest..."
cd "$REPO_DIR"
git pull
fi
# ─── Step 3: Create .env with credentials ──────────────────────
echo "--- Step 3: Environment file ---"
if [ ! -f "$REPO_DIR/.env" ]; then
if [ -z "$DB_URL" ]; then
if $NON_INTERACTIVE; then
echo "❌ --db-url is required in non-interactive mode"
exit 1
fi
read -rp " DATABASE_URL (e.g. libsql://kordant.turso.io): " DB_URL
fi
if [ -z "$DB_TOKEN" ]; then
if $NON_INTERACTIVE; then
echo "❌ --db-token is required in non-interactive mode"
exit 1
fi
read -rsp " DATABASE_AUTH_TOKEN: " DB_TOKEN
echo ""
fi
cat > "$REPO_DIR/.env" << ENVEOF
# ─── Kordant Scheduler Environment ─────────────────────────────
# Turso database
DATABASE_URL="${DB_URL}"
DATABASE_AUTH_TOKEN="${DB_TOKEN}"
# Job queue (local Redis container)
REDIS_URL="redis://redis:6379"
# Node environment
NODE_ENV=production
JOB_WORKER=true
JOB_PRIMARY=true
ENVEOF
chmod 600 "$REPO_DIR/.env"
echo "✅ Created $REPO_DIR/.env"
else
echo "$REPO_DIR/.env already exists, keeping it."
fi
# ─── Step 4: Gitea post-receive hook ────────────────────────────
echo "--- Step 4: Gitea post-receive hook ---"
if [ -z "$HOOKS_DIR" ] && ! $NON_INTERACTIVE; then
read -rp "Gitea repo hooks directory (or leave blank to skip): " HOOKS_DIR
fi
if [ -n "$HOOKS_DIR" ]; then
if [ ! -d "$HOOKS_DIR" ]; then
echo " Directory not found: $HOOKS_DIR"
if $NON_INTERACTIVE; then
echo "❌ hooks-dir does not exist"
exit 1
fi
else
HOOK_FILE="$HOOKS_DIR/post-receive"
cat > "$HOOK_FILE" << 'HOOKEOF'
#!/bin/bash
cd /opt/kordant
git pull origin main
docker compose -f scheduler/docker-compose.yml up -d --build
HOOKEOF
chmod +x "$HOOK_FILE"
echo "✅ Post-receive hook installed at $HOOK_FILE"
fi
else
echo "Skipping post-receive hook."
fi
# ─── Step 5: Create systemd service ────────────────────────────
echo "--- Step 5: Systemd service ---"
SERVICE_NAME="kordant-scheduler"
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
if [ ! -f "$SERVICE_FILE" ]; then
echo "Creating $SERVICE_FILE..."
cat > "$SERVICE_FILE" << SERVICEEOF
[Unit]
Description=Kordant Background Job Scheduler
After=docker.service network-online.target
Wants=docker.service network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=$REPO_DIR
ExecStart=docker compose -f scheduler/docker-compose.yml up -d --build
ExecStop=docker compose -f scheduler/docker-compose.yml down
ExecReload=docker compose -f scheduler/docker-compose.yml pull && docker compose -f scheduler/docker-compose.yml up -d --build
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
SERVICEEOF
systemctl daemon-reload
else
echo "$SERVICE_FILE already exists."
fi
# ─── Step 6: Start / restart the scheduler ─────────────────────
echo "--- Step 6: Starting scheduler ---"
systemctl enable "$SERVICE_NAME" 2>/dev/null || true
cd "$REPO_DIR"
docker compose -f scheduler/docker-compose.yml pull 2>/dev/null || true
docker compose -f scheduler/docker-compose.yml up -d --build
echo ""
echo "=== Scheduler status ==="
sleep 3
docker compose -f scheduler/docker-compose.yml ps
echo ""
echo "=== Kordant scheduler setup complete ==="
echo " Repo: $REPO_DIR"
echo " Logs: journalctl -u kordant-scheduler -f"
echo " Shell: cd $REPO_DIR && docker compose -f scheduler/docker-compose.yml logs -f"
echo " .env: $REPO_DIR/.env"