729 lines
23 KiB
Bash
Executable File
729 lines
23 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ============================================================================
|
|
# cockpit-kata-containers — Automated Installer
|
|
#
|
|
# Detects the host OS, installs all required dependencies, builds the Cockpit
|
|
# module, deploys it, and starts/restarts required services.
|
|
#
|
|
# Usage:
|
|
# sudo ./installer.sh # Full install
|
|
# sudo ./installer.sh --dev # Standalone dev mode only (no Cockpit)
|
|
# sudo ./installer.sh --uninstall # Remove the module
|
|
# ./installer.sh --check # Check prerequisites without installing
|
|
#
|
|
# Supported OS families:
|
|
# - RHEL / Fedora / CentOS Stream / Rocky / Alma
|
|
# - Debian / Ubuntu
|
|
# - openSUSE / SLES
|
|
# - Arch Linux
|
|
# - Clear Linux
|
|
# ============================================================================
|
|
set -euo pipefail
|
|
|
|
# ─── Colors ─────────────────────────────────────────────────────────────────
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# ─── Globals ────────────────────────────────────────────────────────────────
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
COCKPIT_MODULE_DIR="${SCRIPT_DIR}/cockpit-kata"
|
|
COCKPIT_INSTALL_DIR="/usr/share/cockpit/kata"
|
|
KATA_MONITOR_PORT="${KATA_MONITOR_PORT:-8090}"
|
|
KATA_MONITOR_ADDR="${KATA_MONITOR_ADDR:-127.0.0.1}"
|
|
MODE="full" # full | dev | uninstall | check
|
|
LOG_FILE="/tmp/cockpit-kata-install.log"
|
|
CRICTL_VERSION="1.28.0"
|
|
|
|
# ─── Helpers ────────────────────────────────────────────────────────────────
|
|
log() { echo -e "${GREEN}[cockpit-kata]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[cockpit-kata]${NC} WARNING: $*"; }
|
|
error() { echo -e "${RED}[cockpit-kata]${NC} ERROR: $*" >&2; }
|
|
info() { echo -e "${CYAN}[cockpit-kata]${NC} $*"; }
|
|
separator(){ echo -e "${BLUE}──────────────────────────────────────────────────────${NC}"; }
|
|
|
|
run_cmd() {
|
|
echo -e "${CYAN}+ $*${NC}" >> "$LOG_FILE"
|
|
if ! "$@" >> "$LOG_FILE" 2>&1; then
|
|
error "Command failed: $*"
|
|
error "Check log: $LOG_FILE"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
run_cmd_verbose() {
|
|
echo -e "${CYAN}+ $*${NC}"
|
|
"$@"
|
|
}
|
|
|
|
# ─── Parse Arguments ────────────────────────────────────────────────────────
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--dev) MODE="dev"; shift ;;
|
|
--uninstall) MODE="uninstall"; shift ;;
|
|
--check) MODE="check"; shift ;;
|
|
--help|-h)
|
|
echo "Usage: sudo ./installer.sh [--dev|--uninstall|--check|--help]"
|
|
echo ""
|
|
echo " (default) Full Cockpit module install"
|
|
echo " --dev Standalone dev mode only (no Cockpit required)"
|
|
echo " --uninstall Remove the Cockpit module"
|
|
echo " --check Check prerequisites without installing"
|
|
echo " --help Show this help"
|
|
exit 0
|
|
;;
|
|
*) error "Unknown argument: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# ─── OS Detection ───────────────────────────────────────────────────────────
|
|
detect_os() {
|
|
if [[ -f /etc/os-release ]]; then
|
|
# shellcheck disable=SC1091
|
|
source /etc/os-release
|
|
OS_ID="${ID:-unknown}"
|
|
OS_VERSION="${VERSION_ID:-unknown}"
|
|
OS_NAME="${PRETTY_NAME:-$OS_ID $OS_VERSION}"
|
|
elif [[ -f /etc/redhat-release ]]; then
|
|
OS_ID="rhel"
|
|
OS_VERSION=$(rpm -q --qf '%{VERSION}' redhat-release 2>/dev/null || echo "unknown")
|
|
OS_NAME="Red Hat Enterprise Linux $OS_VERSION"
|
|
else
|
|
OS_ID="unknown"
|
|
OS_VERSION="unknown"
|
|
OS_NAME="Unknown Linux"
|
|
fi
|
|
|
|
# Determine family
|
|
case "$OS_ID" in
|
|
rhel|fedora|centos|rocky|almalinux|ol|anolis)
|
|
OS_FAMILY="rhel"
|
|
PKG_MANAGER="dnf"
|
|
;;
|
|
debian|ubuntu|pop|elementary|linuxmint|kali)
|
|
OS_FAMILY="debian"
|
|
PKG_MANAGER="apt"
|
|
;;
|
|
opensuse*|sles|suse)
|
|
OS_FAMILY="suse"
|
|
PKG_MANAGER="zypper"
|
|
;;
|
|
arch|manjaro|endeavouros|garuda)
|
|
OS_FAMILY="arch"
|
|
PKG_MANAGER="pacman"
|
|
;;
|
|
clear-linux-os)
|
|
OS_FAMILY="clear"
|
|
PKG_MANAGER="swupd"
|
|
;;
|
|
*)
|
|
OS_FAMILY="unknown"
|
|
PKG_MANAGER="unknown"
|
|
;;
|
|
esac
|
|
|
|
log "Detected OS: ${OS_NAME}"
|
|
log "OS Family: ${OS_FAMILY}"
|
|
log "Pkg Manager: ${PKG_MANAGER}"
|
|
}
|
|
|
|
# ─── Version Comparison ────────────────────────────────────────────────────
|
|
version_gte() {
|
|
# Returns 0 if $1 >= $2
|
|
printf '%s\n%s' "$1" "$2" | sort -V -C
|
|
}
|
|
|
|
# ─── Generic command check ─────────────────────────────────────────────────
|
|
# check_command COMMAND [MIN_VERSION] [VERSION_FLAG]
|
|
# COMMAND — executable to look up via command -v
|
|
# MIN_VERSION — minimum required version (optional)
|
|
# VERSION_FLAG— flag passed to COMMAND to obtain its version string (default: --version)
|
|
check_command() {
|
|
local cmd="$1"
|
|
local min_ver="${2:-}"
|
|
local ver_flag="${3:---version}"
|
|
|
|
if ! command -v "$cmd" &>/dev/null; then
|
|
warn "${cmd}: not installed"
|
|
return 1
|
|
fi
|
|
|
|
# No version constraint — just confirm presence
|
|
if [[ -z "$min_ver" ]]; then
|
|
local ver_str
|
|
ver_str=$("$cmd" $ver_flag 2>/dev/null | awk '{print $NF}' | tr -d ',' || echo "0")
|
|
log "${cmd}: ${ver_str}"
|
|
return 0
|
|
fi
|
|
|
|
# Version-constrained check
|
|
local cur_ver
|
|
cur_ver=$("$cmd" $ver_flag 2>/dev/null | head -1 | awk '{print $2}' | tr -d 'v,' || echo "0")
|
|
if version_gte "$cur_ver" "$min_ver"; then
|
|
log "${cmd}: ${cur_ver} (>= ${min_ver} required)"
|
|
return 0
|
|
else
|
|
warn "${cmd}: ${cur_ver} found but < ${min_ver} required"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ─── Prerequisite Checks ───────────────────────────────────────────────────
|
|
check_root() {
|
|
if [[ $EUID -ne 0 && "$MODE" != "check" && "$MODE" != "dev" ]]; then
|
|
error "This installer must be run as root for Cockpit module installation."
|
|
error "Use --dev for standalone development mode (no root required)."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_kvm() {
|
|
if [[ -e /dev/kvm ]]; then
|
|
log "KVM: /dev/kvm available"
|
|
return 0
|
|
else
|
|
warn "KVM: /dev/kvm not found — hardware virtualization may not be enabled"
|
|
warn " Enable VT-x/AMD-V in BIOS/UEFI and load the kvm module:"
|
|
warn " sudo modprobe kvm_intel (Intel) or sudo modprobe kvm_amd (AMD)"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_cockpit() { check_command cockpit-bridge "286"; }
|
|
check_kata_runtime() { check_command kata-runtime; }
|
|
check_containerd() { check_command containerd; }
|
|
check_crictl() { check_command crictl; }
|
|
check_node() { check_command node "18" "--version"; }
|
|
check_npm() { check_command npm; }
|
|
|
|
check_kata_monitor() {
|
|
if curl -sf "http://${KATA_MONITOR_ADDR}:${KATA_MONITOR_PORT}/metrics" >/dev/null 2>&1; then
|
|
log "kata-monitor: reachable at ${KATA_MONITOR_ADDR}:${KATA_MONITOR_PORT}"
|
|
return 0
|
|
else
|
|
warn "kata-monitor: not reachable at ${KATA_MONITOR_ADDR}:${KATA_MONITOR_PORT} (metrics will be unavailable)"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ─── Run all checks (array-driven) ─────────────────────────────────────────
|
|
run_all_checks() {
|
|
separator
|
|
info "Running prerequisite checks..."
|
|
separator
|
|
|
|
# Each entry: "check_function:severity" where severity is pass|fail|warn
|
|
local -a checks=(
|
|
"check_kvm:fail"
|
|
"check_cockpit:warn"
|
|
"check_kata_runtime:warn"
|
|
"check_containerd:warn"
|
|
"check_crictl:warn"
|
|
"check_node:fail"
|
|
"check_npm:fail"
|
|
"check_kata_monitor:warn"
|
|
)
|
|
|
|
local pass=0 fail=0 warn_count=0
|
|
local entry check_fn severity
|
|
for entry in "${checks[@]}"; do
|
|
check_fn="${entry%%:*}"
|
|
severity="${entry##*:}"
|
|
if "$check_fn"; then
|
|
((pass++)) || true
|
|
else
|
|
case "$severity" in
|
|
fail) ((fail++)) || true ;;
|
|
warn) ((warn_count++)) || true ;;
|
|
esac
|
|
fi
|
|
done
|
|
|
|
separator
|
|
echo -e " Passed: ${GREEN}${pass}${NC} Failed: ${RED}${fail}${NC} Warnings: ${YELLOW}${warn_count}${NC}"
|
|
separator
|
|
|
|
if [[ $fail -gt 0 ]]; then
|
|
if [[ "$MODE" == "check" ]]; then
|
|
error "Prerequisites not met. Install missing components and re-run."
|
|
return 1
|
|
fi
|
|
warn "Some critical prerequisites are missing — the installer will attempt to install them."
|
|
fi
|
|
}
|
|
|
|
# ─── crictl installation (shared across all OS families) ────────────────────
|
|
install_crictl() {
|
|
command -v crictl &>/dev/null && return 0
|
|
|
|
info "Installing crictl v${CRICTL_VERSION}..."
|
|
run_cmd curl -Lo /tmp/crictl.tar.gz \
|
|
"https://github.com/kubernetes-sigs/cri-tools/releases/download/v${CRICTL_VERSION}/crictl-v${CRICTL_VERSION}-linux-amd64.tar.gz"
|
|
run_cmd tar -xzf /tmp/crictl.tar.gz -C /usr/local/bin crictl
|
|
run_cmd rm -f /tmp/crictl.tar.gz
|
|
}
|
|
|
|
# ─── Package Installation ──────────────────────────────────────────────────
|
|
install_packages_rhel() {
|
|
log "Installing packages via dnf..."
|
|
|
|
# Enable EPEL if needed (CentOS/Rocky/Alma)
|
|
if [[ "$OS_ID" == "centos" || "$OS_ID" == "rocky" || "$OS_ID" == "almalinux" ]]; then
|
|
run_cmd dnf install -y epel-release || true
|
|
fi
|
|
|
|
local pkgs=(
|
|
cockpit
|
|
cockpit-bridge
|
|
nodejs
|
|
npm
|
|
qemu-kvm
|
|
libvirt
|
|
)
|
|
|
|
# Add Kata Containers repo if kata-runtime is missing
|
|
if ! command -v kata-runtime &>/dev/null; then
|
|
info "kata-runtime not found — adding Kata Containers repo..."
|
|
command -v dnf copr &>/dev/null && run_cmd dnf copr enable -y @katacontainers/kata-containers || true
|
|
pkgs+=(kata-containers-runtime)
|
|
fi
|
|
|
|
run_cmd dnf install -y "${pkgs[@]}"
|
|
install_crictl
|
|
}
|
|
|
|
install_packages_debian() {
|
|
log "Installing packages via apt..."
|
|
|
|
run_cmd apt-get update -y
|
|
|
|
local pkgs=(
|
|
cockpit
|
|
cockpit-bridge
|
|
nodejs
|
|
npm
|
|
qemu-kvm
|
|
libvirt-daemon-system
|
|
)
|
|
|
|
# Add Kata Containers apt repo if kata-runtime is missing
|
|
if ! command -v kata-runtime &>/dev/null; then
|
|
info "kata-runtime not found — adding Kata Containers apt repo..."
|
|
local kata_repo_key="https://packages.katacontainers.io/kata-containers.repo.key"
|
|
local kata_repo_url="https://packages.katacontainers.io/stable/debian"
|
|
|
|
run_cmd curl -Lo /usr/share/keyrings/kata-containers.gpg "$kata_repo_key" || true
|
|
if [[ -f /usr/share/keyrings/kata-containers.gpg ]]; then
|
|
echo "deb [signed-by=/usr/share/keyrings/kata-containers.gpg] $kata_repo_url /" \
|
|
> /etc/apt/sources.list.d/kata-containers.list
|
|
run_cmd apt-get update -y
|
|
fi
|
|
pkgs+=(kata-containers-runtime)
|
|
fi
|
|
|
|
run_cmd apt-get install -y "${pkgs[@]}"
|
|
install_crictl
|
|
}
|
|
|
|
install_packages_suse() {
|
|
log "Installing packages via zypper..."
|
|
|
|
local pkgs=(
|
|
cockpit
|
|
cockpit-bridge
|
|
nodejs18
|
|
npm18
|
|
qemu-kvm
|
|
libvirt-daemon
|
|
)
|
|
|
|
if ! command -v kata-runtime &>/dev/null; then
|
|
info "kata-runtime not found — you may need to install it manually on SUSE."
|
|
warn "See: https://github.com/kata-containers/kata-containers/blob/main/docs/install/README.md"
|
|
fi
|
|
|
|
run_cmd zypper install -y "${pkgs[@]}"
|
|
install_crictl
|
|
}
|
|
|
|
install_packages_arch() {
|
|
log "Installing packages via pacman..."
|
|
|
|
local pkgs=(
|
|
cockpit
|
|
nodejs
|
|
npm
|
|
qemu-headless
|
|
libvirt
|
|
)
|
|
|
|
if ! command -v kata-runtime &>/dev/null; then
|
|
warn "kata-runtime: Install from AUR (e.g., kata-containers-bin) or build from source."
|
|
warn "See: https://github.com/kata-containers/kata-containers/blob/main/docs/install/README.md"
|
|
fi
|
|
|
|
run_cmd pacman -Sy --noconfirm --needed "${pkgs[@]}"
|
|
install_crictl
|
|
}
|
|
|
|
install_packages_clear() {
|
|
log "Installing bundles via swupd..."
|
|
|
|
run_cmd swupd bundle-add cockpit
|
|
run_cmd swupd bundle-add nodejs-basic
|
|
|
|
if ! command -v kata-runtime &>/dev/null; then
|
|
run_cmd swupd bundle-add containers-virt || warn "kata-runtime bundle not found"
|
|
fi
|
|
|
|
install_crictl
|
|
}
|
|
|
|
install_packages() {
|
|
case "$OS_FAMILY" in
|
|
rhel) install_packages_rhel ;;
|
|
debian) install_packages_debian ;;
|
|
suse) install_packages_suse ;;
|
|
arch) install_packages_arch ;;
|
|
clear) install_packages_clear ;;
|
|
*)
|
|
error "Unsupported OS family: ${OS_FAMILY}"
|
|
error "Install these packages manually: cockpit, nodejs (>=18), npm, qemu-kvm, kata-runtime, crictl, containerd"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# ─── Service Management ────────────────────────────────────────────────────
|
|
enable_services() {
|
|
log "Enabling and starting services..."
|
|
|
|
# Cockpit socket
|
|
if systemctl list-unit-files cockpit.socket &>/dev/null; then
|
|
run_cmd_verbose systemctl enable --now cockpit.socket
|
|
log "Cockpit socket enabled (https://localhost:9090)"
|
|
else
|
|
warn "cockpit.socket not found — Cockpit may need manual service start"
|
|
fi
|
|
|
|
# libvirtd (for QEMU backend)
|
|
if systemctl list-unit-files libvirtd.service &>/dev/null; then
|
|
run_cmd_verbose systemctl enable --now libvirtd
|
|
log "libvirtd started"
|
|
fi
|
|
|
|
# containerd
|
|
if systemctl list-unit-files containerd.service &>/dev/null; then
|
|
run_cmd_verbose systemctl enable --now containerd
|
|
log "containerd started"
|
|
else
|
|
warn "containerd.service not found — install containerd for CRI support"
|
|
fi
|
|
|
|
# KVM kernel modules
|
|
if [[ ! -e /dev/kvm ]]; then
|
|
info "Attempting to load KVM kernel module..."
|
|
modprobe kvm_intel 2>/dev/null || modprobe kvm_amd 2>/dev/null || warn "Could not load KVM module"
|
|
if [[ -e /dev/kvm ]]; then
|
|
log "KVM module loaded successfully"
|
|
else
|
|
warn "KVM still not available — hardware virtualization may be disabled in BIOS"
|
|
fi
|
|
fi
|
|
|
|
# kata-monitor (optional)
|
|
if command -v kata-monitor &>/dev/null; then
|
|
if ! curl -sf "http://${KATA_MONITOR_ADDR}:${KATA_MONITOR_PORT}/metrics" >/dev/null 2>&1; then
|
|
info "Starting kata-monitor on ${KATA_MONITOR_ADDR}:${KATA_MONITOR_PORT}..."
|
|
nohup kata-monitor --listen-address "${KATA_MONITOR_ADDR}:${KATA_MONITOR_PORT}" \
|
|
>/tmp/kata-monitor.log 2>&1 &
|
|
sleep 2
|
|
if curl -sf "http://${KATA_MONITOR_ADDR}:${KATA_MONITOR_PORT}/metrics" >/dev/null 2>&1; then
|
|
log "kata-monitor started successfully"
|
|
else
|
|
warn "kata-monitor did not start — metrics will be unavailable"
|
|
fi
|
|
fi
|
|
else
|
|
warn "kata-monitor not found — install kata-containers for metrics support"
|
|
fi
|
|
}
|
|
|
|
# ─── Build & Deploy ────────────────────────────────────────────────────────
|
|
install_qcrows_tools() {
|
|
log "Installing QCrows CLI tools to /usr/local/bin/..."
|
|
|
|
local -a tools=(
|
|
"qcrows-pack"
|
|
"qcrows-verify"
|
|
"qcrows-inspect"
|
|
"qcrows-export"
|
|
"qcrows-initrd-regen"
|
|
)
|
|
|
|
local installed=0
|
|
local skipped=0
|
|
|
|
# Iterate using array — each tool installed independently
|
|
local tool
|
|
for tool in "${tools[@]}"; do
|
|
local src="${SCRIPT_DIR}/${tool}"
|
|
if [[ -f "$src" ]]; then
|
|
run_cmd_verbose install -m 0755 "$src" "/usr/local/bin/${tool}"
|
|
((installed++)) || true
|
|
else
|
|
warn "QCrows tool not found: ${src}"
|
|
((skipped++)) || true
|
|
fi
|
|
done
|
|
|
|
log "QCrows tools: ${installed} installed, ${skipped} skipped"
|
|
}
|
|
|
|
build_cockpit_module() {
|
|
log "Building Cockpit module..."
|
|
|
|
if [[ ! -d "$COCKPIT_MODULE_DIR" ]]; then
|
|
error "Cockpit module directory not found: ${COCKPIT_MODULE_DIR}"
|
|
error "Make sure you're running this script from the project root."
|
|
exit 1
|
|
fi
|
|
|
|
cd "$COCKPIT_MODULE_DIR"
|
|
|
|
log "Installing build dependencies..."
|
|
run_cmd npm install
|
|
|
|
log "Building production bundle..."
|
|
run_cmd npm run build
|
|
|
|
if [[ ! -f dist/index.js ]]; then
|
|
error "Build failed — dist/index.js not found"
|
|
exit 1
|
|
fi
|
|
|
|
log "Build successful: $(du -sh dist/ | cut -f1)"
|
|
cd "$SCRIPT_DIR"
|
|
}
|
|
|
|
deploy_cockpit_module() {
|
|
log "Deploying Cockpit module to ${COCKPIT_INSTALL_DIR}..."
|
|
|
|
# Remove old installation
|
|
if [[ -d "$COCKPIT_INSTALL_DIR" ]]; then
|
|
run_cmd_verbose rm -rf "$COCKPIT_INSTALL_DIR"
|
|
fi
|
|
|
|
# Copy built files
|
|
run_cmd_verbose mkdir -p "$COCKPIT_INSTALL_DIR"
|
|
run_cmd_verbose cp -r "${COCKPIT_MODULE_DIR}/dist/"* "$COCKPIT_INSTALL_DIR/"
|
|
|
|
if cockpit-bridge --packages 2>/dev/null | grep -q kata; then
|
|
log "Cockpit module registered: kata"
|
|
else
|
|
warn "Module not immediately visible — restart Cockpit to pick it up"
|
|
fi
|
|
|
|
log "Module deployed to ${COCKPIT_INSTALL_DIR}"
|
|
}
|
|
|
|
build_standalone() {
|
|
log "Setting up standalone development mode..."
|
|
|
|
if [[ ! -f "${SCRIPT_DIR}/package.json" ]]; then
|
|
error "package.json not found in ${SCRIPT_DIR}"
|
|
exit 1
|
|
fi
|
|
|
|
cd "$SCRIPT_DIR"
|
|
run_cmd npm install
|
|
|
|
log "Standalone mode ready. Run: npm run dev"
|
|
log "Then open http://localhost:3000"
|
|
}
|
|
|
|
# ─── Uninstall ─────────────────────────────────────────────────────────────
|
|
do_uninstall() {
|
|
separator
|
|
info "Uninstalling Cockpit Kata Containers module..."
|
|
separator
|
|
|
|
if [[ -d "$COCKPIT_INSTALL_DIR" ]]; then
|
|
rm -rf "$COCKPIT_INSTALL_DIR"
|
|
log "Removed ${COCKPIT_INSTALL_DIR}"
|
|
else
|
|
warn "Module not installed at ${COCKPIT_INSTALL_DIR}"
|
|
fi
|
|
|
|
# Remove dev symlink
|
|
local dev_link="${HOME}/.local/share/cockpit/kata"
|
|
if [[ -L "$dev_link" ]]; then
|
|
rm -f "$dev_link"
|
|
log "Removed dev symlink ${dev_link}"
|
|
fi
|
|
|
|
# Stop kata-monitor if we started it
|
|
if pgrep -f "kata-monitor.*${KATA_MONITOR_PORT}" &>/dev/null; then
|
|
info "Stopping kata-monitor..."
|
|
pkill -f "kata-monitor.*${KATA_MONITOR_PORT}" || true
|
|
log "kata-monitor stopped"
|
|
fi
|
|
|
|
# Remove QCrows CLI tools
|
|
local -a tools=("qcrows-pack" "qcrows-verify" "qcrows-inspect" "qcrows-export" "qcrows-initrd-regen")
|
|
local tool
|
|
for tool in "${tools[@]}"; do
|
|
if [[ -f "/usr/local/bin/${tool}" ]]; then
|
|
run_cmd_verbose rm -f "/usr/local/bin/${tool}"
|
|
fi
|
|
done
|
|
|
|
log "Uninstallation complete."
|
|
log "Note: System packages (cockpit, kata-runtime, etc.) were NOT removed."
|
|
log " Remove them manually if desired."
|
|
}
|
|
|
|
# ─── RuntimeClass Setup ────────────────────────────────────────────────────
|
|
# Iteration is intentional — each RuntimeClass is independently created and a
|
|
# failure in one must not prevent the others from being attempted.
|
|
setup_runtime_classes() {
|
|
if ! command -v kubectl &>/dev/null; then
|
|
warn "kubectl not found — skipping RuntimeClass setup"
|
|
return
|
|
fi
|
|
|
|
info "Checking for Kata RuntimeClasses..."
|
|
|
|
local classes=("kata-qemu" "kata-clh" "kata-fc" "kata-dragonball")
|
|
for rc in "${classes[@]}"; do
|
|
if kubectl get runtimeclass "$rc" &>/dev/null; then
|
|
log "RuntimeClass ${rc}: already exists"
|
|
else
|
|
info "Creating RuntimeClass ${rc}..."
|
|
kubectl apply -f - <<EOF 2>/dev/null || warn "Could not create RuntimeClass ${rc}"
|
|
apiVersion: node.k8s.io/v1
|
|
kind: RuntimeClass
|
|
metadata:
|
|
name: ${rc}
|
|
handler: ${rc}
|
|
EOF
|
|
fi
|
|
done
|
|
}
|
|
|
|
# ─── Main ───────────────────────────────────────────────────────────────────
|
|
main() {
|
|
parse_args "$@"
|
|
|
|
echo ""
|
|
echo -e "${BLUE} ╔══════════════════════════════════════════════╗${NC}"
|
|
echo -e "${BLUE} ║ Cockpit Kata Containers — Installer ║${NC}"
|
|
echo -e "${BLUE} ║ VM-isolated container management ║${NC}"
|
|
echo -e "${BLUE} ╚══════════════════════════════════════════════╝${NC}"
|
|
echo ""
|
|
|
|
# Initialize log
|
|
echo "=== Cockpit Kata Containers Install Log ===" > "$LOG_FILE"
|
|
echo "Date: $(date)" >> "$LOG_FILE"
|
|
echo "Mode: ${MODE}" >> "$LOG_FILE"
|
|
echo "" >> "$LOG_FILE"
|
|
|
|
# Detect OS
|
|
detect_os
|
|
|
|
# Route to mode
|
|
case "$MODE" in
|
|
check)
|
|
run_all_checks
|
|
exit 0
|
|
;;
|
|
uninstall)
|
|
check_root
|
|
do_uninstall
|
|
exit 0
|
|
;;
|
|
dev)
|
|
info "=== Standalone Development Mode ==="
|
|
run_all_checks
|
|
build_standalone
|
|
echo ""
|
|
log "Setup complete! Run the following to start:"
|
|
echo ""
|
|
echo -e " ${CYAN}cd ${SCRIPT_DIR}${NC}"
|
|
echo -e " ${CYAN}npm run dev${NC}"
|
|
echo ""
|
|
echo -e " Open ${CYAN}http://localhost:3000${NC} in your browser."
|
|
exit 0
|
|
;;
|
|
full)
|
|
check_root
|
|
info "=== Full Cockpit Module Install ==="
|
|
;;
|
|
*)
|
|
error "Unknown mode: ${MODE}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Full install flow
|
|
separator
|
|
info "Step 1/6: Checking prerequisites"
|
|
separator
|
|
run_all_checks
|
|
|
|
separator
|
|
info "Step 2/6: Installing system packages"
|
|
separator
|
|
install_packages
|
|
|
|
separator
|
|
info "Step 3/6: Enabling services"
|
|
separator
|
|
enable_services
|
|
|
|
separator
|
|
info "Step 4/6: Installing QCrows CLI tools"
|
|
separator
|
|
install_qcrows_tools
|
|
|
|
separator
|
|
info "Step 5/6: Building Cockpit module"
|
|
separator
|
|
build_cockpit_module
|
|
|
|
separator
|
|
info "Step 6/6: Deploying module"
|
|
separator
|
|
deploy_cockpit_module
|
|
|
|
# Optional: set up RuntimeClasses
|
|
separator
|
|
info "Optional: Setting up Kubernetes RuntimeClasses"
|
|
separator
|
|
setup_runtime_classes
|
|
|
|
# Final summary
|
|
echo ""
|
|
separator
|
|
log "Installation Complete!"
|
|
separator
|
|
echo ""
|
|
echo -e " Cockpit: ${CYAN}https://localhost:9090${NC}"
|
|
echo -e " Module path: ${CYAN}${COCKPIT_INSTALL_DIR}${NC}"
|
|
echo -e " kata-monitor: ${CYAN}http://${KATA_MONITOR_ADDR}:${KATA_MONITOR_PORT}${NC}"
|
|
echo -e " Install log: ${CYAN}${LOG_FILE}${NC}"
|
|
echo ""
|
|
echo -e " Open Cockpit and navigate to ${GREEN}Kata Containers${NC} in the sidebar."
|
|
echo ""
|
|
echo -e " To uninstall: ${CYAN}sudo ./installer.sh --uninstall${NC}"
|
|
echo -e " To check: ${CYAN}./installer.sh --check${NC}"
|
|
echo ""
|
|
}
|
|
|
|
main "$@"
|