diff --git a/scripts/preflight.sh b/scripts/preflight.sh new file mode 100755 index 0000000..bc67d7e --- /dev/null +++ b/scripts/preflight.sh @@ -0,0 +1,296 @@ +#!/usr/bin/env bash +# ============================================================================= +# preflight.sh — BEDS environment preflight checklist +# +# Checks that all required services and tools are present and reachable. +# Installs anything missing (Debian/Ubuntu only). +# Idempotent — safe to run multiple times. +# +# Usage: +# ./scripts/preflight.sh # check + install missing +# ./scripts/preflight.sh --check # check only, no installs +# +# Requirements: bash 5+, sudo access (for installs) +# Supported: Debian 11+ / Ubuntu 22.04+ +# ============================================================================= + +set -euo pipefail + +# --- config ------------------------------------------------------------------ +RABBITMQ_HOST="${RABBITMQ_HOST:-localhost}" +RABBITMQ_PORT="${RABBITMQ_PORT:-5672}" +MONGO_HOST="${MONGO_HOST:-localhost}" +MONGO_PORT="${MONGO_PORT:-27017}" +MARIADB_HOST="${MARIADB_HOST:-localhost}" +MARIADB_PORT="${MARIADB_PORT:-3306}" + +CHECK_ONLY=false +if [[ "${1:-}" == "--check" ]]; then + CHECK_ONLY=true +fi + +# --- output helpers ---------------------------------------------------------- +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +RESET='\033[0m' + +PASS=0 +FAIL=0 +WARN=0 + +pass() { echo -e " ${GREEN}[PASS]${RESET} $1"; PASS=$(( PASS + 1 )); } +fail() { echo -e " ${RED}[FAIL]${RESET} $1"; FAIL=$(( FAIL + 1 )); } +warn() { echo -e " ${YELLOW}[WARN]${RESET} $1"; WARN=$(( WARN + 1 )); } +info() { echo -e " ${CYAN} ${RESET} $1"; } +section() { echo; echo -e "${BOLD}$1${RESET}"; echo "$(printf '%.0s-' {1..60})"; } + +# --- distro check ------------------------------------------------------------ +detect_distro() { + if [[ -f /etc/os-release ]]; then + source /etc/os-release + DISTRO_ID="${ID:-unknown}" + DISTRO_LIKE="${ID_LIKE:-}" + else + DISTRO_ID="unknown" + DISTRO_LIKE="" + fi +} + +is_debian_family() { + [[ "$DISTRO_ID" == "debian" || "$DISTRO_ID" == "ubuntu" || "$DISTRO_LIKE" == *"debian"* ]] +} + +apt_install() { + if $CHECK_ONLY; then + fail "$1 — not installed (run without --check to install)" + return + fi + info "Installing $*..." + sudo apt-get install -y "$@" 2>&1 | tail -3 +} + +# Check via systemd (more reliable than searching sbin paths) +svc_installed() { + systemctl cat "$1" &>/dev/null +} + +svc_active() { + systemctl is-active --quiet "$1" 2>/dev/null +} + +# Check via dpkg (fast, no PATH issues) +pkg_installed() { + dpkg -s "$1" &>/dev/null && dpkg -s "$1" | grep -q 'Status: install ok installed' +} + +# --- tcp reachability -------------------------------------------------------- +tcp_check() { + local host="$1" port="$2" + timeout 2 bash -c ">/dev/tcp/${host}/${port}" 2>/dev/null +} + +# ============================================================================= +section "BEDS Preflight Checklist" +echo " Mode: $( $CHECK_ONLY && echo 'check only' || echo 'check + install')" +detect_distro +echo " Distro: ${DISTRO_ID:-unknown} ${VERSION_ID:-}" +echo + +# ============================================================================= +section "1. Build Toolchain" + +if command -v rustc &>/dev/null; then + RUST_VER=$(rustc --version) + pass "Rust — $RUST_VER" +else + fail "Rust — not found" + info "Install: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh" + info "(rustup is not managed by apt — install manually)" +fi + +if command -v cargo &>/dev/null; then + CARGO_VER=$(cargo --version) + pass "Cargo — $CARGO_VER" +else + fail "Cargo — not found (install Rust via rustup)" +fi + +# ============================================================================= +section "2. RabbitMQ" + +if pkg_installed rabbitmq-server; then + pass "RabbitMQ — installed" +else + if $CHECK_ONLY; then + fail "RabbitMQ — not installed" + else + if is_debian_family; then + info "Adding RabbitMQ apt repository..." + curl -fsSL https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/rabbitmq-archive-keyring.gpg 2>/dev/null + echo "deb [signed-by=/usr/share/keyrings/rabbitmq-archive-keyring.gpg] https://packagecloud.io/rabbitmq/rabbitmq-server/debian/ $(source /etc/os-release && echo $VERSION_CODENAME) main" \ + | sudo tee /etc/apt/sources.list.d/rabbitmq.list > /dev/null + sudo apt-get update -qq + apt_install rabbitmq-server + else + fail "RabbitMQ — not installed; automatic install only supported on Debian/Ubuntu" + info "See: https://www.rabbitmq.com/docs/install-debian" + fi + fi +fi + +if tcp_check "$RABBITMQ_HOST" "$RABBITMQ_PORT"; then + pass "RabbitMQ reachable at ${RABBITMQ_HOST}:${RABBITMQ_PORT}" +else + fail "RabbitMQ not reachable at ${RABBITMQ_HOST}:${RABBITMQ_PORT}" + info "Start: sudo systemctl start rabbitmq-server" +fi + +if svc_active rabbitmq-server; then + # Check management plugin via the HTTP API (no sudo needed) + if tcp_check localhost 15672; then + pass "RabbitMQ management plugin enabled (port 15672 open)" + else + warn "RabbitMQ management plugin not enabled" + info "Enable: sudo rabbitmq-plugins enable rabbitmq_management" + info " (provides the admin UI at http://localhost:15672)" + fi +fi + +# ============================================================================= +section "3. MongoDB" + +if svc_installed mongod; then + MONGO_VER=$(mongod --version 2>/dev/null | head -1 || echo 'installed') + pass "MongoDB — $MONGO_VER" +else + if $CHECK_ONLY; then + fail "MongoDB — not installed" + else + if is_debian_family; then + info "Adding MongoDB apt repository..." + curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg 2>/dev/null + echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg] https://repo.mongodb.org/apt/debian bookworm/mongodb-org/8.0 main" \ + | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list > /dev/null + sudo apt-get update -qq + apt_install mongodb-org + else + fail "MongoDB — not installed; automatic install only supported on Debian/Ubuntu" + info "See: https://www.mongodb.org/docs/manual/installation/" + fi + fi +fi + +if tcp_check "$MONGO_HOST" "$MONGO_PORT"; then + pass "MongoDB reachable at ${MONGO_HOST}:${MONGO_PORT}" +else + fail "MongoDB not reachable at ${MONGO_HOST}:${MONGO_PORT}" + info "Start: sudo systemctl start mongod" +fi + +# ============================================================================= +section "4. MariaDB" + +if svc_installed mariadb; then + pass "MariaDB — installed" +else + if $CHECK_ONLY; then + fail "MariaDB — not installed" + else + if is_debian_family; then + apt_install mariadb-server + else + fail "MariaDB — not installed; automatic install only supported on Debian/Ubuntu" + info "See: https://mariadb.org/download/" + fi + fi +fi + +if tcp_check "$MARIADB_HOST" "$MARIADB_PORT"; then + pass "MariaDB reachable at ${MARIADB_HOST}:${MARIADB_PORT}" +else + fail "MariaDB not reachable at ${MARIADB_HOST}:${MARIADB_PORT}" + info "Start: sudo systemctl start mariadb" +fi + +# ============================================================================= +section "5. Apache + PHP (Observer Tool)" + +if svc_installed apache2; then + APACHE_VER=$(apache2 -v 2>/dev/null | head -1 | awk '{print $3}' || echo 'installed') + pass "Apache — $APACHE_VER" +else + if $CHECK_ONLY; then + fail "Apache — not installed" + else + if is_debian_family; then + apt_install apache2 + else + fail "Apache — not installed; automatic install only supported on Debian/Ubuntu" + fi + fi +fi + +if tcp_check localhost 80; then + pass "Apache reachable at localhost:80" +else + fail "Apache not reachable at localhost:80" + info "Start: sudo systemctl start apache2" +fi + +if pkg_installed php; then + PHP_VER=$(php --version 2>/dev/null | head -1 || echo 'installed') + pass "PHP — $PHP_VER" +else + if $CHECK_ONLY; then + fail "PHP — not installed" + else + if is_debian_family; then + apt_install php libapache2-mod-php php-mongodb php-cli + sudo systemctl restart apache2 + else + fail "PHP — not installed; automatic install only supported on Debian/Ubuntu" + fi + fi +fi + +# Check php-mongodb extension specifically +if pkg_installed php-mongodb; then + pass "PHP mongodb extension — installed" +else + warn "PHP mongodb extension — not installed" + info "Install: sudo apt install php-mongodb && sudo systemctl restart apache2" +fi + +# ============================================================================= +section "Summary" + +TOTAL=$(( PASS + FAIL + WARN )) +echo +echo -e " Checked : $TOTAL" +echo -e " ${GREEN}Passed : $PASS${RESET}" +if [[ $WARN -gt 0 ]]; then + echo -e " ${YELLOW}Warnings: $WARN${RESET}" +fi +if [[ $FAIL -gt 0 ]]; then + echo -e " ${RED}Failed : $FAIL${RESET}" + echo + if $CHECK_ONLY; then + echo -e " Run ${BOLD}./scripts/preflight.sh${RESET} (without --check) to install missing dependencies." + else + echo -e " Some checks failed. Review output above and resolve before running BEDS." + fi + exit 1 +else + echo + echo -e " ${GREEN}${BOLD}All checks passed. Environment is ready.${RESET}" + if ! $CHECK_ONLY; then + echo + echo -e " Next steps:" + echo -e " 1. Copy config template: cp config/beds.toml.example config/beds.toml" + echo -e " 2. Edit credentials: \$EDITOR config/env_dev.toml" + echo -e " 3. Build and run: cargo run" + fi +fi