230 lines
9.5 KiB
Bash
230 lines
9.5 KiB
Bash
#!/usr/bin/env bash
|
|
# provision-runner.sh — VPS provisioning script for Gitea act_runner
|
|
# Refs: #1097 (POKA-YOKE: Make unregistered runners impossible to miss)
|
|
#
|
|
# Usage (on Bezalel VPS as root):
|
|
# bash provision-runner.sh --gitea-url <url> --token <runner-registration-token>
|
|
#
|
|
# This script:
|
|
# 1. Downloads and installs act_runner binary
|
|
# 2. Registers the runner with the Gitea instance
|
|
# 3. Creates and enables systemd service for act_runner
|
|
# 4. Installs the runner-health-probe timer (poka-yoke detection layer)
|
|
#
|
|
# POKA-YOKE principles applied:
|
|
# Prevention: runner registration is mandatory — script exits non-zero if registration fails
|
|
# Detection: runner-health-probe.sh installed and enabled as part of this script
|
|
# Correction: health probe auto-restarts act_runner on zero-runner detection
|
|
|
|
set -euo pipefail
|
|
|
|
# ── Configuration defaults (override via env or flags) ───────────────────────
|
|
GITEA_URL="${GITEA_URL:-https://forge.alexanderwhitestone.com}"
|
|
RUNNER_TOKEN="${RUNNER_TOKEN:-}"
|
|
RUNNER_NAME="${RUNNER_NAME:-$(hostname)-runner}"
|
|
RUNNER_LABELS="${RUNNER_LABELS:-ubuntu-latest,linux,x86_64}"
|
|
ACT_RUNNER_VERSION="${ACT_RUNNER_VERSION:-0.2.10}"
|
|
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
|
|
CONFIG_DIR="${CONFIG_DIR:-/etc/act_runner}"
|
|
DATA_DIR="${DATA_DIR:-/var/lib/act_runner}"
|
|
NEXUS_DIR="${NEXUS_DIR:-/root/wizards/the-nexus}"
|
|
PROBE_SCRIPT="${NEXUS_DIR}/scripts/runner-health-probe.sh"
|
|
|
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] PROVISION: $*"; }
|
|
fail() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] PROVISION ERROR: $*" >&2; exit 1; }
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: provision-runner.sh [options]
|
|
|
|
Options:
|
|
--gitea-url <url> Gitea base URL (default: $GITEA_URL)
|
|
--token <token> Runner registration token (required)
|
|
--name <name> Runner name (default: hostname-runner)
|
|
--labels <labels> Comma-separated labels (default: $RUNNER_LABELS)
|
|
--version <ver> act_runner version to install (default: $ACT_RUNNER_VERSION)
|
|
--nexus-dir <path> Path to the-nexus checkout (default: $NEXUS_DIR)
|
|
--help Show this help
|
|
|
|
Environment variables: GITEA_URL, RUNNER_TOKEN, RUNNER_NAME, RUNNER_LABELS,
|
|
ACT_RUNNER_VERSION, NEXUS_DIR
|
|
|
|
POKA-YOKE CHECKLIST (enforced by this script):
|
|
[1] act_runner binary installed and executable
|
|
[2] Runner registered with Gitea (non-zero runner count verified)
|
|
[3] act_runner systemd service enabled and running
|
|
[4] runner-health-probe timer installed and enabled
|
|
EOF
|
|
}
|
|
|
|
# ── Argument parsing ──────────────────────────────────────────────────────────
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--gitea-url) GITEA_URL="$2"; shift 2 ;;
|
|
--token) RUNNER_TOKEN="$2"; shift 2 ;;
|
|
--name) RUNNER_NAME="$2"; shift 2 ;;
|
|
--labels) RUNNER_LABELS="$2"; shift 2 ;;
|
|
--version) ACT_RUNNER_VERSION="$2"; shift 2 ;;
|
|
--nexus-dir) NEXUS_DIR="$2"; PROBE_SCRIPT="${NEXUS_DIR}/scripts/runner-health-probe.sh"; shift 2 ;;
|
|
--help) usage; exit 0 ;;
|
|
*) fail "Unknown argument: $1. Use --help for usage." ;;
|
|
esac
|
|
done
|
|
|
|
[[ -z "$RUNNER_TOKEN" ]] && fail "Runner registration token required. Pass --token or set RUNNER_TOKEN env var."
|
|
|
|
# ── Step 1: Install act_runner binary ─────────────────────────────────────────
|
|
log "Step 1/4: Installing act_runner v${ACT_RUNNER_VERSION}..."
|
|
|
|
ARCH=$(uname -m)
|
|
case "$ARCH" in
|
|
x86_64) ARCH_SUFFIX="amd64" ;;
|
|
aarch64) ARCH_SUFFIX="arm64" ;;
|
|
*) fail "Unsupported architecture: $ARCH" ;;
|
|
esac
|
|
|
|
BINARY_URL="https://gitea.com/gitea/act_runner/releases/download/v${ACT_RUNNER_VERSION}/act_runner-${ACT_RUNNER_VERSION}-linux-${ARCH_SUFFIX}"
|
|
BINARY_PATH="${INSTALL_DIR}/act_runner"
|
|
|
|
if [[ -f "$BINARY_PATH" ]]; then
|
|
CURRENT_VER=$("$BINARY_PATH" --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' || echo "unknown")
|
|
if [[ "$CURRENT_VER" == "$ACT_RUNNER_VERSION" ]]; then
|
|
log "act_runner v${ACT_RUNNER_VERSION} already installed — skipping download."
|
|
else
|
|
log "Upgrading act_runner from v${CURRENT_VER} to v${ACT_RUNNER_VERSION}..."
|
|
curl -fsSL "$BINARY_URL" -o "$BINARY_PATH"
|
|
chmod +x "$BINARY_PATH"
|
|
fi
|
|
else
|
|
curl -fsSL "$BINARY_URL" -o "$BINARY_PATH"
|
|
chmod +x "$BINARY_PATH"
|
|
fi
|
|
|
|
"$BINARY_PATH" --version >/dev/null 2>&1 || fail "act_runner binary not functional after install."
|
|
log "act_runner binary OK: $($BINARY_PATH --version 2>/dev/null || echo 'installed')"
|
|
|
|
# ── Step 2: Register runner with Gitea ────────────────────────────────────────
|
|
log "Step 2/4: Registering runner with Gitea at ${GITEA_URL}..."
|
|
|
|
mkdir -p "$CONFIG_DIR" "$DATA_DIR"
|
|
|
|
CONFIG_FILE="${CONFIG_DIR}/config.yaml"
|
|
|
|
# Generate config and register
|
|
"$BINARY_PATH" register \
|
|
--no-interactive \
|
|
--instance "$GITEA_URL" \
|
|
--token "$RUNNER_TOKEN" \
|
|
--name "$RUNNER_NAME" \
|
|
--labels "$RUNNER_LABELS" \
|
|
--config "$CONFIG_FILE" \
|
|
2>&1 | tee /tmp/act_runner_register.log
|
|
|
|
if ! grep -q "Runner registered" /tmp/act_runner_register.log 2>/dev/null && \
|
|
! grep -q "registered" /tmp/act_runner_register.log 2>/dev/null; then
|
|
# Registration output varies — check if config was written as a fallback signal
|
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
fail "Runner registration failed. Check token and Gitea URL. Log: /tmp/act_runner_register.log"
|
|
fi
|
|
fi
|
|
|
|
log "Runner registered. Config written to ${CONFIG_FILE}"
|
|
|
|
# ── Step 3: Create and enable systemd service ─────────────────────────────────
|
|
log "Step 3/4: Installing act_runner systemd service..."
|
|
|
|
cat > /etc/systemd/system/act_runner.service <<EOF
|
|
[Unit]
|
|
Description=Gitea Actions Runner (act_runner)
|
|
Documentation=https://gitea.com/gitea/act_runner
|
|
After=network.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=root
|
|
WorkingDirectory=${DATA_DIR}
|
|
ExecStart=${INSTALL_DIR}/act_runner daemon --config ${CONFIG_FILE}
|
|
Restart=always
|
|
RestartSec=10
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
Environment=HOME=/root
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable act_runner
|
|
systemctl restart act_runner
|
|
sleep 3
|
|
|
|
if ! systemctl is-active --quiet act_runner; then
|
|
fail "act_runner service failed to start. Check: journalctl -u act_runner -n 50"
|
|
fi
|
|
log "act_runner service running."
|
|
|
|
# ── Step 4: Install runner health probe ───────────────────────────────────────
|
|
log "Step 4/4: Installing runner-health-probe systemd timer..."
|
|
|
|
if [[ ! -f "$PROBE_SCRIPT" ]]; then
|
|
log "WARNING: probe script not found at ${PROBE_SCRIPT}. Skipping timer install."
|
|
log " Re-run after the-nexus is checked out to: ${NEXUS_DIR}"
|
|
log " Then manually: systemctl enable --now runner-health-probe.timer"
|
|
else
|
|
chmod +x "$PROBE_SCRIPT"
|
|
|
|
# Install service unit
|
|
cat > /etc/systemd/system/runner-health-probe.service <<EOF
|
|
[Unit]
|
|
Description=Gitea Runner Health Probe (poka-yoke zero-runner detection)
|
|
Documentation=https://forge.alexanderwhitestone.com/Timmy_Foundation/the-nexus/issues/1097
|
|
After=network.target act_runner.service
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=${PROBE_SCRIPT}
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
Environment=HOME=/root
|
|
EOF
|
|
|
|
# Install timer unit (every 5 minutes)
|
|
cat > /etc/systemd/system/runner-health-probe.timer <<EOF
|
|
[Unit]
|
|
Description=Gitea Runner Health Probe — every 5 minutes (poka-yoke #1097)
|
|
Documentation=https://forge.alexanderwhitestone.com/Timmy_Foundation/the-nexus/issues/1097
|
|
|
|
[Timer]
|
|
OnBootSec=2min
|
|
OnUnitActiveSec=5min
|
|
Persistent=true
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable --now runner-health-probe.timer
|
|
log "runner-health-probe.timer enabled (fires every 5 minutes)."
|
|
fi
|
|
|
|
# ── Poka-yoke checklist summary ───────────────────────────────────────────────
|
|
echo ""
|
|
echo "══════════════════════════════════════════════════════════"
|
|
echo " POKA-YOKE PROVISIONING CHECKLIST — $(hostname)"
|
|
echo "══════════════════════════════════════════════════════════"
|
|
printf " [1] act_runner binary : "
|
|
"$BINARY_PATH" --version >/dev/null 2>&1 && echo "OK" || echo "FAIL"
|
|
printf " [2] act_runner registered : "
|
|
[[ -f "$CONFIG_FILE" ]] && echo "OK (config exists)" || echo "FAIL (no config)"
|
|
printf " [3] act_runner service : "
|
|
systemctl is-active --quiet act_runner && echo "RUNNING" || echo "FAIL"
|
|
printf " [4] health-probe timer : "
|
|
systemctl is-active --quiet runner-health-probe.timer 2>/dev/null && echo "ACTIVE" || echo "NOT INSTALLED (re-run after nexus checkout)"
|
|
echo "══════════════════════════════════════════════════════════"
|
|
echo ""
|
|
log "Provisioning complete. Runner '${RUNNER_NAME}' registered at ${GITEA_URL}"
|