#!/bin/bash set -e # ───────────────────────────────────────────────────────────────────────────── # DragRace Runner Installer # Usage: curl -sSL https://get.dragrace.dev | sh # ───────────────────────────────────────────────────────────────────────────── DRAGRACE_VERSION="${DRAGRACE_VERSION:-latest}" DRAGRACE_REPO="${DRAGRACE_REPO:-dragrace-dev/runner}" DRAGRACE_BASE_URL="https://github.com/${DRAGRACE_REPO}/releases/download" INSTALL_DIR="/usr/local/bin" CONFIG_DIR="/etc/dragrace" CONFIG_FILE="${CONFIG_DIR}/runner.yaml" WORK_DIR="/var/dragrace" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' BOLD='\033[1m' NC='\033[0m' # No Color info() { echo -e "${BLUE}ℹ${NC} $1"; } ok() { echo -e "${GREEN}✅${NC} $1"; } warn() { echo -e "${YELLOW}⚠️${NC} $1"; } error() { echo -e "${RED}❌${NC} $1"; exit 1; } # ─── Banner ───────────────────────────────────────────────────────────────── echo -e "${BOLD}" echo " ____ ____ " echo " | _ \ _ __ __ _ __ _| _ \ __ _ ___ ___ " echo " | | | | '__/ _\` |/ _\` | |_) / _\` |/ __/ _ \\" echo " | |_| | | | (_| | (_| | _ < (_| | (_| __/" echo " |____/|_| \__,_|\__, |_| \_\__,_|\___\___|" echo " |___/ " echo -e "${NC}" echo " Runner Installer v${DRAGRACE_VERSION}" echo "" # ─── OS / Arch Detection ──────────────────────────────────────────────────── detect_platform() { OS="$(uname -s | tr '[:upper:]' '[:lower:]')" ARCH="$(uname -m)" case "$OS" in linux) OS="linux" ;; darwin) OS="darwin" ;; *) error "Unsupported OS: $OS" ;; esac case "$ARCH" in x86_64|amd64) ARCH="amd64" ;; aarch64|arm64) ARCH="arm64" ;; *) error "Unsupported architecture: $ARCH" ;; esac info "Detected platform: ${OS}/${ARCH}" } # ─── Prerequisites ────────────────────────────────────────────────────────── check_prerequisites() { # Docker if ! command -v docker &> /dev/null; then error "Docker is required but not installed. Install it from https://docs.docker.com/get-docker/" fi ok "Docker found: $(docker --version | head -1)" # Git if ! command -v git &> /dev/null; then error "Git is required but not installed." fi ok "Git found: $(git --version)" # Root check (for Linux service install) if [ "$OS" = "linux" ] && [ "$(id -u)" -ne 0 ]; then warn "Not running as root. You may need to run with sudo for service installation." fi } # ─── Download Binary ──────────────────────────────────────────────────────── download_binary() { BINARY_NAME="dragrace-runner-${OS}-${ARCH}" # Resolve "latest" version via GitHub API if [ "$DRAGRACE_VERSION" = "latest" ]; then info "Resolving latest version from GitHub..." GITHUB_API_URL="https://api.github.com/repos/${DRAGRACE_REPO}/releases/latest" if command -v curl &> /dev/null; then DRAGRACE_VERSION=$(curl -fsSL "$GITHUB_API_URL" | grep '"tag_name"' | sed -E 's/.*"v?([^"]+)".*/\1/') elif command -v wget &> /dev/null; then DRAGRACE_VERSION=$(wget -qO- "$GITHUB_API_URL" | grep '"tag_name"' | sed -E 's/.*"v?([^"]+)".*/\1/') else error "Neither curl nor wget found" fi if [ -z "$DRAGRACE_VERSION" ]; then error "Could not resolve latest version from GitHub" fi info "Latest version: ${DRAGRACE_VERSION}" fi DOWNLOAD_URL="${DRAGRACE_BASE_URL}/v${DRAGRACE_VERSION}/${BINARY_NAME}" info "Downloading runner binary..." info "URL: ${DOWNLOAD_URL}" if command -v curl &> /dev/null; then curl -fsSL -o "/tmp/${BINARY_NAME}" "${DOWNLOAD_URL}" || error "Download failed. Check that version v${DRAGRACE_VERSION} exists." elif command -v wget &> /dev/null; then wget -q -O "/tmp/${BINARY_NAME}" "${DOWNLOAD_URL}" || error "Download failed. Check that version v${DRAGRACE_VERSION} exists." else error "Neither curl nor wget found" fi chmod +x "/tmp/${BINARY_NAME}" # Install to bin dir if [ -w "${INSTALL_DIR}" ]; then mv "/tmp/${BINARY_NAME}" "${INSTALL_DIR}/dragrace-runner" else sudo mv "/tmp/${BINARY_NAME}" "${INSTALL_DIR}/dragrace-runner" fi ok "Binary installed to ${INSTALL_DIR}/dragrace-runner (v${DRAGRACE_VERSION})" } # ─── Configuration ────────────────────────────────────────────────────────── configure_runner() { echo "" echo -e "${BOLD}🔧 Runner Configuration${NC}" echo "────────────────────────────────────────" # API Key echo "" echo -e "Paste your API key (format: ${BOLD}client_id:client_secret${NC})" echo "Create one at: https://dragrace.dev/settings/runner-keys" read -rp "→ API Key: " API_KEY # Parse client_id:secret CLIENT_ID="${API_KEY%%:*}" CLIENT_SECRET="${API_KEY#*:}" if [ "$CLIENT_ID" = "$CLIENT_SECRET" ] || [ -z "$CLIENT_ID" ] || [ -z "$CLIENT_SECRET" ]; then error "Invalid API key format. Expected: client_id:client_secret" fi # Scope echo "" echo "Runner scope (how this runner will be used):" echo " [p] Public — available to everyone" echo " [o] Organization — available to one org's challenges" echo " [c] Challenge — dedicated to one challenge" read -rp "→ Scope [p/o/c] (default: p): " SCOPE_CHOICE case "${SCOPE_CHOICE:-p}" in p|P|public) SCOPE_TYPE="public" SCOPE_TARGET="" ;; o|O|org|organization) SCOPE_TYPE="organization" read -rp "→ Organization ID: " SCOPE_TARGET [ -z "$SCOPE_TARGET" ] && error "Organization ID is required" ;; c|C|challenge) SCOPE_TYPE="challenge" read -rp "→ Challenge ID: " SCOPE_TARGET [ -z "$SCOPE_TARGET" ] && error "Challenge ID is required" ;; *) error "Invalid scope choice: $SCOPE_CHOICE" ;; esac # NATS URL echo "" read -rp "→ NATS URL (default: nats://nats.dragrace.dev:4222): " NATS_URL NATS_URL="${NATS_URL:-nats://nats.dragrace.dev:4222}" # Create config directory if [ -w "$(dirname "${CONFIG_DIR}")" ]; then mkdir -p "${CONFIG_DIR}" "${WORK_DIR}" else sudo mkdir -p "${CONFIG_DIR}" "${WORK_DIR}" fi # Write config file cat > "/tmp/runner.yaml" << EOF # DragRace Runner Configuration # Edit this file and restart the service to reconfigure nats_url: "${NATS_URL}" client_id: "${CLIENT_ID}" client_secret: "${CLIENT_SECRET}" scope: type: "${SCOPE_TYPE}" target_id: "${SCOPE_TARGET}" work_dir: "${WORK_DIR}" EOF if [ -w "${CONFIG_DIR}" ]; then mv "/tmp/runner.yaml" "${CONFIG_FILE}" else sudo mv "/tmp/runner.yaml" "${CONFIG_FILE}" sudo chmod 600 "${CONFIG_FILE}" fi ok "Configuration saved to ${CONFIG_FILE}" } # ─── Service Installation ─────────────────────────────────────────────────── install_service() { echo "" echo -e "${BOLD}🔧 Service Installation${NC}" echo "────────────────────────────────────────" if [ "$OS" = "linux" ]; then install_systemd_service elif [ "$OS" = "darwin" ]; then install_launchd_service fi } install_systemd_service() { SERVICE_FILE="/etc/systemd/system/dragrace-runner.service" cat > "/tmp/dragrace-runner.service" << EOF [Unit] Description=DragRace Runner After=network.target docker.service Requires=docker.service [Service] Type=simple EnvironmentFile=-${CONFIG_DIR}/runner.env ExecStart=${INSTALL_DIR}/dragrace-runner Restart=always RestartSec=10 Environment=RUNNER_CONFIG=${CONFIG_FILE} [Install] WantedBy=multi-user.target EOF # Generate env file from yaml config cat > "/tmp/runner.env" << EOF NATS_URL=${NATS_URL} RUNNER_CLIENT_ID=${CLIENT_ID} RUNNER_CLIENT_SECRET=${CLIENT_SECRET} RUNNER_SCOPE=${SCOPE_TYPE} RUNNER_SCOPE_TARGET=${SCOPE_TARGET} RUNNER_WORK_DIR=${WORK_DIR} EOF sudo mv "/tmp/dragrace-runner.service" "${SERVICE_FILE}" sudo mv "/tmp/runner.env" "${CONFIG_DIR}/runner.env" sudo chmod 600 "${CONFIG_DIR}/runner.env" sudo systemctl daemon-reload sudo systemctl enable dragrace-runner sudo systemctl start dragrace-runner ok "systemd service installed and started" info "Commands:" info " sudo systemctl status dragrace-runner # check status" info " sudo journalctl -u dragrace-runner -f # view logs" info " sudo systemctl restart dragrace-runner # restart" } install_launchd_service() { PLIST_FILE="$HOME/Library/LaunchAgents/dev.dragrace.runner.plist" mkdir -p "$HOME/Library/LaunchAgents" cat > "${PLIST_FILE}" << EOF Label dev.dragrace.runner ProgramArguments ${INSTALL_DIR}/dragrace-runner EnvironmentVariables NATS_URL ${NATS_URL} RUNNER_CLIENT_ID ${CLIENT_ID} RUNNER_CLIENT_SECRET ${CLIENT_SECRET} RUNNER_SCOPE ${SCOPE_TYPE} RUNNER_SCOPE_TARGET ${SCOPE_TARGET} RUNNER_WORK_DIR ${WORK_DIR} RunAtLoad KeepAlive StandardOutPath /tmp/dragrace-runner.log StandardErrorPath /tmp/dragrace-runner.err EOF launchctl unload "${PLIST_FILE}" 2>/dev/null || true launchctl load "${PLIST_FILE}" ok "launchd service installed and started" info "Commands:" info " launchctl list | grep dragrace # check status" info " tail -f /tmp/dragrace-runner.log # view logs" info " launchctl unload ${PLIST_FILE} # stop" info " launchctl load ${PLIST_FILE} # start" } # ─── Main ─────────────────────────────────────────────────────────────────── main() { detect_platform check_prerequisites download_binary configure_runner install_service echo "" echo "────────────────────────────────────────" echo -e "${GREEN}${BOLD}🏁 DragRace Runner installed successfully!${NC}" echo "" info "Config file: ${CONFIG_FILE}" info "To reconfigure: edit ${CONFIG_FILE} and restart the service" echo "" } main "$@"