#!/usr/bin/env bash # scripts/bootstrap.sh — S0b: host bootstrap (Docker install-if-missing) # # Idempotent: detects Docker and skips install if already present. # Linux only (Debian/Ubuntu/RHEL/Fedora families). # # Usage: # ./scripts/bootstrap.sh # make bootstrap set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # Source shared helpers # shellcheck source=lib/common.sh source "$SCRIPT_DIR/lib/common.sh" log_section "S0b: Host bootstrap" warn_if_root # ── Check Docker ─────────────────────────────────────────────────────────── if docker_available; then log_info "Docker already installed ($(docker --version))" log_info "Bootstrap complete — nothing to do." exit 0 fi log_warn "Docker not found or not running." # ── Detect OS family ────────────────────────────────────────────────────── detect_os_family() { if [[ -f /etc/os-release ]]; then # Sourced in a subshell via $() — OS variables do not leak to caller scope. . /etc/os-release echo "${ID_LIKE:-$ID}" else log_error "Cannot detect OS family (no /etc/os-release)" return 1 fi } OS_FAMILY="$(detect_os_family)" log_info "Detected OS family: $OS_FAMILY" install_docker_debian() { log_info "Installing Docker (Debian/Ubuntu) via official convenience script…" if ! curl -fsSL https://get.docker.com | sh; then log_error "Docker install script failed." log_error "Install Docker manually, then re-run this script." return 1 fi # Add current user to docker group (requires sudo) local user="${SUDO_USER:-$(whoami)}" if [[ -n "$user" ]] && getent group docker &>/dev/null; then log_info "Adding user '$user' to docker group…" sudo usermod -aG docker "$user" 2>/dev/null || true log_warn "Log out and back in (or run 'newgrp docker') for group changes to take effect." fi } install_docker_rhel() { log_info "Installing Docker (RHEL/Fedora) via dnf…" sudo dnf install -y dnf-utils 2>/dev/null || sudo dnf install -ydnf-plugins-core 2>/dev/null || true sudo dnf config-manager --add-repo https://download.docker.com/linux/$(echo "$OS_FAMILY" | head -c3)/docker-ce.repo 2>/dev/null || { log_warn "Could not add Docker repo. Trying generic install…" sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin || { log_error "Docker install failed. Install manually and re-run." return 1 } } sudo systemctl enable --now docker } # ── Install ──────────────────────────────────────────────────────────────── if echo "$OS_FAMILY" | grep -qiE 'debian|ubuntu'; then install_docker_debian elif echo "$OS_FAMILY" | grep -qiE 'rhel|fedora|centos|rocky|almalinux'; then install_docker_rhel else log_error "Unsupported OS family: $OS_FAMILY" log_error "Supported: Debian/Ubuntu, RHEL/Fedora/CentOS/Rocky/AlmaLinux" log_error "Install Docker manually, then re-run this script." exit 1 fi # ── Verify ───────────────────────────────────────────────────────────────── if docker_available; then log_info "Docker installed successfully: $(docker --version)" log_info "Bootstrap complete." else log_error "Docker install appeared to succeed but daemon is not reachable." log_error "Check Docker service: sudo systemctl status docker" exit 1 fi