#!/usr/bin/env bash set -euo pipefail # Kubesman Installer # Usage: curl -sfL https://get.kubesman.org | bash # curl -sfL https://get.kubesman.org | bash -s -- [OPTIONS] # # Options: # --version Docker image tag (default: latest) # --dry-run Preview commands without executing # --uninstall Remove Kubesman service, container, and data # ── Defaults ── DOCKER_IMAGE="damurai/kubesman" IMAGE_TAG="latest" SERVICE_NAME="kubesman" DATA_DIR="/root/.kubesman" SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" DRY_RUN=false UNINSTALL=false # ── Colors ── info() { printf "\033[32m[INFO]\033[0m %s\n" "$*"; } warn() { printf "\033[33m[WARN]\033[0m %s\n" "$*"; } error() { printf "\033[31m[ERROR]\033[0m %s\n" "$*"; exit 1; } # ── Helpers ── command_exists() { command -v "$1" >/dev/null 2>&1; } run() { if [ "$DRY_RUN" = true ]; then info "[DRY-RUN] $*" else "$@" fi } # ── Environment checks ── detect_wsl() { if [ -f /proc/version ] && grep -qi "microsoft" /proc/version 2>/dev/null; then warn "WSL detected. systemd may not be available in your WSL distribution." warn "If installation fails, enable systemd in WSL:" warn " https://learn.microsoft.com/en-us/windows/wsl/systemd" echo "" fi } detect_macos() { case "$(uname -s)" in Darwin) error "macOS detected. Kubesman requires Linux with systemd and Docker. Run it on a Linux server or VM instead." ;; esac } check_root() { if [ "$(id -u)" -ne 0 ]; then if command_exists sudo; then warn "Not running as root. Re-running with sudo..." exec sudo bash "$0" "$@" else error "This installer must be run as root. Try: curl -sfL https://get.kubesman.org | sudo bash" fi fi } check_systemd() { if [ ! -d /run/systemd/system ]; then error "systemd is required but not detected. Kubesman needs systemd to manage the service." fi } check_docker() { if ! command_exists docker; then warn "Docker is not installed." info "Install Docker first: https://docs.docker.com/engine/install/" info "" info "Quick install (most Linux distros):" info " curl -fsSL https://get.docker.com | sh" info "" error "Please install Docker and re-run this installer." fi if ! docker info >/dev/null 2>&1; then error "Docker daemon is not running. Start it with: systemctl start docker" fi } # ── Uninstall ── do_uninstall() { info "Uninstalling Kubesman..." echo "" if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then info "Stopping service..." run systemctl stop "$SERVICE_NAME" fi if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then info "Disabling service..." run systemctl disable "$SERVICE_NAME" fi if [ -f "$SERVICE_FILE" ]; then info "Removing service file..." run rm -f "$SERVICE_FILE" run systemctl daemon-reload fi if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "^${SERVICE_NAME}\$"; then info "Removing container..." run docker rm -f "$SERVICE_NAME" fi if docker images "${DOCKER_IMAGE}" --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -q .; then info "Removing Docker image..." run docker rmi "${DOCKER_IMAGE}:${IMAGE_TAG}" 2>/dev/null || true fi if [ -d "$DATA_DIR" ]; then warn "Data directory exists at ${DATA_DIR}" warn "To remove all data (configs, keys, reports), run:" warn " rm -rf ${DATA_DIR}" echo "" fi info "Kubesman has been uninstalled." } # ── Install ── check_existing() { if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then info "Kubesman service is already running. Upgrading..." run systemctl stop "$SERVICE_NAME" fi } pull_image() { info "Pulling ${DOCKER_IMAGE}:${IMAGE_TAG}..." run docker pull "${DOCKER_IMAGE}:${IMAGE_TAG}" } create_data_dir() { info "Creating data directory at ${DATA_DIR}..." run mkdir -p "${DATA_DIR}/ssh-keys" run mkdir -p "${DATA_DIR}/kubeconfigs" run mkdir -p "${DATA_DIR}/reports" } install_service() { info "Installing systemd service..." if [ "$DRY_RUN" = true ]; then info "[DRY-RUN] Would write service file to ${SERVICE_FILE}" else cat > "$SERVICE_FILE" < Docker image tag (default: latest)" echo " --dry-run Preview commands without executing" echo " --uninstall Remove Kubesman service, container, and data" echo " --help Show this help message" exit 0 ;; *) error "Unknown option: $1 (use --help for usage)" ;; esac done } # ── Main ── main() { parse_args "$@" info "Kubesman Installer" if [ "$DRY_RUN" = true ]; then warn "Dry-run mode — no changes will be made" fi info "" if [ "$UNINSTALL" = true ]; then check_root "$@" do_uninstall else do_install fi } main "$@"