#!/bin/bash # # AtlasOS Installation Script for Ubuntu 24.04 # Installs AtlasOS storage controller with infrastructure gap consideration # # Usage: sudo ./install.sh [options] # # Note: Run this script from the atlas repository root directory # set -e set -o pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Default values INSTALL_DIR="/opt/atlas" DATA_DIR="/var/lib/atlas" CONFIG_DIR="/etc/atlas" SERVICE_USER="atlas" LOG_DIR="/var/log/atlas" BACKUP_DIR="/var/lib/atlas/backups" HTTP_ADDR=":8080" DB_PATH="/var/lib/atlas/atlas.db" BUILD_BINARIES=true SKIP_DEPS=false REPO_DIR="" FIREWALL_ACTIVE=false # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in --install-dir) INSTALL_DIR="$2" shift 2 ;; --data-dir) DATA_DIR="$2" shift 2 ;; --skip-deps) SKIP_DEPS=true shift ;; --skip-build) BUILD_BINARIES=false shift ;; --http-addr) HTTP_ADDR="$2" shift 2 ;; --repo-dir) REPO_DIR="$2" shift 2 ;; -h|--help) echo "AtlasOS Installation Script" echo "" echo "Usage: sudo ./install.sh [options]" echo "" echo "Options:" echo " --install-dir DIR Installation directory (default: /opt/atlas)" echo " --data-dir DIR Data directory (default: /var/lib/atlas)" echo " --skip-deps Skip dependency installation" echo " --skip-build Skip building binaries (use existing)" echo " --http-addr ADDR HTTP address (default: :8080)" echo " --repo-dir DIR Repository directory (if not in current dir)" echo " -h, --help Show this help message" exit 0 ;; *) echo "Unknown option: $1" exit 1 ;; esac done # Check if running as root if [[ $EUID -ne 0 ]]; then echo -e "${RED}Error: This script must be run as root (use sudo)${NC}" exit 1 fi # Get script directory early (for path resolution) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Detect distribution and validate Ubuntu 24.04 detect_distro() { if [[ -f /etc/os-release ]]; then . /etc/os-release DISTRO=$ID VERSION=$VERSION_ID CODENAME=$VERSION_CODENAME else echo -e "${RED}Error: Cannot detect Linux distribution${NC}" exit 1 fi # Validate Ubuntu 24.04 if [[ "$DISTRO" != "ubuntu" ]]; then echo -e "${RED}Error: This installer is specific to Ubuntu${NC}" echo " Detected: $DISTRO $VERSION" echo " Please use the generic installer or install manually" exit 1 fi # Check for Ubuntu 24.04 (Noble Numbat) # SECURITY: Use OR (||) to warn if EITHER version or codename doesn't match # This ensures we catch all incompatible systems, not just when both are wrong if [[ "$VERSION" != "24.04" ]] || [[ "$CODENAME" != "noble" ]]; then echo -e "${YELLOW}Warning: This installer is optimized for Ubuntu 24.04 (Noble Numbat)${NC}" echo " Detected: Ubuntu $VERSION ($CODENAME)" echo " Continuing anyway, but some features may not work correctly" read -p "Continue anyway? (y/n) " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi else echo -e "${GREEN}✓ Detected Ubuntu 24.04 (Noble Numbat)${NC}" fi } # Pre-flight checks for infrastructure gaps preflight_checks() { echo -e "${GREEN}Running pre-flight checks...${NC}" local errors=0 local warnings=0 # Check network connectivity echo -n " Checking network connectivity... " if ping -c 1 -W 2 8.8.8.8 &>/dev/null || ping -c 1 -W 2 1.1.1.1 &>/dev/null; then echo -e "${GREEN}✓${NC}" else echo -e "${YELLOW}⚠ No internet connectivity${NC}" warnings=$((warnings + 1)) fi # Check if apt is working echo -n " Checking package manager... " if apt-get update &>/dev/null; then echo -e "${GREEN}✓${NC}" else echo -e "${RED}✗ APT not working${NC}" errors=$((errors + 1)) fi # Check disk space (need at least 2GB free) echo -n " Checking disk space... " AVAILABLE_SPACE=$(df / | tail -1 | awk '{print $4}') if [[ $AVAILABLE_SPACE -gt 2097152 ]]; then # 2GB in KB echo -e "${GREEN}✓ ($(numfmt --to=iec-i --suffix=B $((AVAILABLE_SPACE * 1024))) available)${NC}" else echo -e "${YELLOW}⚠ Low disk space ($(numfmt --to=iec-i --suffix=B $((AVAILABLE_SPACE * 1024))) available)${NC}" warnings=$((warnings + 1)) fi # Check if systemd is available echo -n " Checking systemd... " if systemctl --version &>/dev/null; then echo -e "${GREEN}✓${NC}" else echo -e "${RED}✗ systemd not available${NC}" errors=$((errors + 1)) fi # Check kernel version (Ubuntu 24.04 should have 6.8+) echo -n " Checking kernel version... " KERNEL_VERSION=$(uname -r | cut -d. -f1,2) KERNEL_MAJOR=$(echo $KERNEL_VERSION | cut -d. -f1) KERNEL_MINOR=$(echo $KERNEL_VERSION | cut -d. -f2) if [[ $KERNEL_MAJOR -gt 6 ]] || [[ $KERNEL_MAJOR -eq 6 && $KERNEL_MINOR -ge 8 ]]; then echo -e "${GREEN}✓ ($(uname -r))${NC}" else echo -e "${YELLOW}⚠ Kernel $(uname -r) may not fully support all features${NC}" warnings=$((warnings + 1)) fi # Check if running in container (may need special handling) echo -n " Checking environment... " if [[ -f /.dockerenv ]] || grep -qa container=lxc /proc/1/environ 2>/dev/null; then echo -e "${YELLOW}⚠ Running in container (some features may be limited)${NC}" warnings=$((warnings + 1)) else echo -e "${GREEN}✓${NC}" fi echo "" if [[ $errors -gt 0 ]]; then echo -e "${RED}Pre-flight checks failed with $errors error(s)${NC}" exit 1 elif [[ $warnings -gt 0 ]]; then echo -e "${YELLOW}Pre-flight checks completed with $warnings warning(s)${NC}" else echo -e "${GREEN}All pre-flight checks passed${NC}" fi echo "" } # Fix common infrastructure gaps fix_infrastructure_gaps() { echo -e "${GREEN}Fixing infrastructure gaps...${NC}" # Ensure universe repository is enabled (required for some packages on Ubuntu) echo -n " Checking universe repository... " if ! grep -q "^deb.*universe" /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null; then echo -e "${YELLOW}⚠ Enabling universe repository...${NC}" add-apt-repository -y universe 2>/dev/null || { echo "deb http://archive.ubuntu.com/ubuntu $(lsb_release -cs) universe" >> /etc/apt/sources.list apt-get update } echo -e "${GREEN}✓ Universe repository enabled${NC}" else echo -e "${GREEN}✓${NC}" fi # Ensure multiverse repository is enabled (for some packages) echo -n " Checking multiverse repository... " if ! grep -q "^deb.*multiverse" /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null; then echo -e "${YELLOW}⚠ Enabling multiverse repository...${NC}" add-apt-repository -y multiverse 2>/dev/null || { echo "deb http://archive.ubuntu.com/ubuntu $(lsb_release -cs) multiverse" >> /etc/apt/sources.list apt-get update } echo -e "${GREEN}✓ Multiverse repository enabled${NC}" else echo -e "${GREEN}✓${NC}" fi # Load ZFS kernel module if not loaded echo -n " Checking ZFS kernel module... " if ! lsmod | grep -q "^zfs"; then echo -e "${YELLOW}⚠ Loading ZFS kernel module...${NC}" modprobe zfs 2>/dev/null || { echo -e "${YELLOW} ZFS module not available (will be installed with zfsutils-linux)${NC}" } fi echo -e "${GREEN}✓${NC}" # Ensure ZFS module loads on boot if ! grep -q "^zfs" /etc/modules-load.d/*.conf 2>/dev/null && ! grep -q "^zfs" /etc/modules 2>/dev/null; then echo "zfs" > /etc/modules-load.d/zfs.conf echo -e "${GREEN} ✓ ZFS module will load on boot${NC}" fi # Check and configure firewall (UFW) echo -n " Checking firewall... " if command -v ufw &>/dev/null; then if ufw status | grep -q "Status: active"; then echo -e "${YELLOW}⚠ UFW is active${NC}" echo " Will configure firewall rules after installation" FIREWALL_ACTIVE=true else echo -e "${GREEN}✓ (inactive)${NC}" FIREWALL_ACTIVE=false fi else echo -e "${GREEN}✓ (not installed)${NC}" FIREWALL_ACTIVE=false fi echo -e "${GREEN}Infrastructure gaps fixed${NC}" echo "" } # Install dependencies for Ubuntu 24.04 install_dependencies() { echo -e "${GREEN}Installing dependencies for Ubuntu 24.04...${NC}" # Update package lists echo " Updating package lists..." apt-get update -qq # Install essential build tools first echo " Installing build essentials..." DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \ build-essential \ git \ curl \ wget \ ca-certificates \ software-properties-common \ apt-transport-https # Install ZFS utilities (Ubuntu 24.04 specific) echo " Installing ZFS utilities..." DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \ zfsutils-linux \ zfs-zed \ zfs-initramfs || { echo -e "${YELLOW}Warning: ZFS installation may require additional setup${NC}" } # Install storage services echo " Installing storage services..." DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \ samba \ samba-common-bin \ nfs-kernel-server \ rpcbind # Install iSCSI target (Ubuntu 24.04 uses targetcli-fb) echo " Installing iSCSI target..." if apt-cache show targetcli-fb &>/dev/null; then DEBIAN_FRONTEND=noninteractive apt-get install -y -qq targetcli-fb # Create symlink for compatibility if ! command -v targetcli &>/dev/null && command -v targetcli-fb &>/dev/null; then ln -sf $(which targetcli-fb) /usr/local/bin/targetcli fi else DEBIAN_FRONTEND=noninteractive apt-get install -y -qq targetcli || { echo -e "${YELLOW}Warning: targetcli not available, iSCSI features may be limited${NC}" } fi # Install database echo " Installing SQLite..." DEBIAN_FRONTEND=noninteractive apt-get install -y -qq sqlite3 libsqlite3-dev # Install Go compiler (Ubuntu 24.04 has Go 1.22+) echo " Installing Go compiler..." if ! command -v go &>/dev/null; then DEBIAN_FRONTEND=noninteractive apt-get install -y -qq golang-go || { echo -e "${YELLOW}Warning: Go not in repositories, installing from official source...${NC}" # Fallback: install Go from official source GO_VERSION="1.22.0" wget -q https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz -O /tmp/go.tar.gz rm -rf /usr/local/go tar -C /usr/local -xzf /tmp/go.tar.gz ln -sf /usr/local/go/bin/go /usr/local/bin/go ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt rm /tmp/go.tar.gz } fi # Verify Go installation if command -v go &>/dev/null; then GO_VERSION=$(go version | awk '{print $3}') echo -e "${GREEN} ✓ Go $GO_VERSION installed${NC}" else echo -e "${RED}Error: Go installation failed${NC}" exit 1 fi # Install additional utilities echo " Installing additional utilities..." DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \ openssl \ net-tools \ iproute2 \ systemd \ journalctl echo -e "${GREEN}Dependencies installed successfully${NC}" echo "" } # Create system user create_user() { echo -e "${GREEN}Creating system user...${NC}" if ! id "$SERVICE_USER" &>/dev/null; then useradd -r -s /bin/false -d "$DATA_DIR" "$SERVICE_USER" echo -e "${GREEN}User $SERVICE_USER created${NC}" else echo -e "${YELLOW}User $SERVICE_USER already exists${NC}" fi # Add user to disk group for block device access (required for ZFS) if getent group disk > /dev/null 2>&1; then usermod -a -G disk "$SERVICE_USER" echo -e "${GREEN}Added $SERVICE_USER to disk group${NC}" fi # Create sudoers configuration for ZFS commands echo -e "${GREEN}Configuring sudo for ZFS operations...${NC}" cat > /etc/sudoers.d/atlas-zfs < ./cmd/atlas-api/main.go <<'MAINGO' package main import ( "context" "crypto/tls" "log" "net/http" "os" "os/signal" "time" "gitea.avt.data-center.id/othman.suseno/atlas/internal/httpapp" tlscfg "gitea.avt.data-center.id/othman.suseno/atlas/internal/tls" ) func main() { addr := env("ATLAS_HTTP_ADDR", ":8080") dbPath := env("ATLAS_DB_PATH", "data/atlas.db") app, err := httpapp.New(httpapp.Config{ Addr: addr, TemplatesDir: "web/templates", StaticDir: "web/static", DatabasePath: dbPath, }) if err != nil { log.Fatalf("init app: %v", err) } tlsConfig := tlscfg.LoadConfig() if err := tlsConfig.Validate(); err != nil { log.Fatalf("TLS configuration error: %v", err) } var tlsServerConfig interface{} if tlsConfig.Enabled { var err error tlsServerConfig, err = tlsConfig.BuildTLSConfig() if err != nil { log.Fatalf("TLS configuration error: %v", err) } log.Printf("[atlas-api] TLS enabled (cert: %s, key: %s)", tlsConfig.CertFile, tlsConfig.KeyFile) } srv := &http.Server{ Addr: addr, Handler: app.Router(), ReadHeaderTimeout: 5 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 120 * time.Second, } if tlsServerConfig != nil { if cfg, ok := tlsServerConfig.(*tls.Config); ok { srv.TLSConfig = cfg } } go func() { log.Printf("[atlas-api] listening on %s", addr) var err error if tlsConfig.Enabled { err = srv.ListenAndServeTLS("", "") } else { err = srv.ListenAndServe() } if err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %v", err) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, os.Kill) <-stop log.Printf("[atlas-api] shutdown requested") app.StopScheduler() ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Printf("[atlas-api] shutdown error: %v", err) } else { log.Printf("[atlas-api] shutdown complete") } } func env(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def } MAINGO # Create atlas-tui/main.go cat > ./cmd/atlas-tui/main.go <<'MAINGO' package main import ( "fmt" "os" "os/signal" "syscall" "gitea.avt.data-center.id/othman.suseno/atlas/internal/tui" ) const ( defaultAPIURL = "http://localhost:8080" ) func main() { apiURL := os.Getenv("ATLAS_API_URL") if apiURL == "" { apiURL = defaultAPIURL } client := tui.NewAPIClient(apiURL) app := tui.NewApp(client) sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) go func() { <-sigChan app.Cleanup() os.Exit(0) }() if err := app.Run(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } } MAINGO echo -e "${GREEN}Created cmd/ directory structure${NC}" fi # Verify cmd files exist now if [[ ! -f "./cmd/atlas-api/main.go" ]]; then echo -e "${RED}Error: Failed to create cmd/atlas-api/main.go${NC}" exit 1 fi if [[ ! -f "./cmd/atlas-tui/main.go" ]]; then echo -e "${RED}Error: Failed to create cmd/atlas-tui/main.go${NC}" exit 1 fi # Build binaries echo "Building atlas-api..." if ! go build -o "$INSTALL_DIR/bin/atlas-api" ./cmd/atlas-api; then echo -e "${RED}Error: Failed to build atlas-api${NC}" exit 1 fi echo "Building atlas-tui..." if ! go build -o "$INSTALL_DIR/bin/atlas-tui" ./cmd/atlas-tui; then echo -e "${RED}Error: Failed to build atlas-tui${NC}" exit 1 fi # Set permissions chown root:root "$INSTALL_DIR/bin/atlas-api" chown root:root "$INSTALL_DIR/bin/atlas-tui" chmod 755 "$INSTALL_DIR/bin/atlas-api" chmod 755 "$INSTALL_DIR/bin/atlas-tui" # Create symlinks in /usr/local/bin for global access echo -e "${GREEN}Creating symlinks for global access...${NC}" ln -sf "$INSTALL_DIR/bin/atlas-api" /usr/local/bin/atlas-api ln -sf "$INSTALL_DIR/bin/atlas-tui" /usr/local/bin/atlas-tui chmod 755 /usr/local/bin/atlas-api chmod 755 /usr/local/bin/atlas-tui echo -e "${GREEN}Binaries built and installed successfully${NC}" echo " Binaries available at: $INSTALL_DIR/bin/" echo " Global commands: atlas-api, atlas-tui" } # Create systemd service create_systemd_service() { echo -e "${GREEN}Creating systemd service...${NC}" cat > /etc/systemd/system/atlas-api.service < "$CONFIG_DIR/atlas.conf" < /dev/null; then JWT_SECRET=$(openssl rand -hex 32) echo "ATLAS_JWT_SECRET=$JWT_SECRET" >> "$CONFIG_DIR/atlas.conf" echo -e "${GREEN}JWT secret generated${NC}" else echo -e "${YELLOW}Warning: openssl not found. Please set ATLAS_JWT_SECRET manually${NC}" fi } # Configure firewall (UFW) for Ubuntu 24.04 configure_firewall() { if [[ "$FIREWALL_ACTIVE" != "true" ]]; then return fi echo -e "${GREEN}Configuring firewall rules...${NC}" # Extract port from HTTP_ADDR (default :8080) PORT=$(echo "$HTTP_ADDR" | sed 's/.*://' || echo "8080") if [[ -z "$PORT" ]] || [[ "$PORT" == "$HTTP_ADDR" ]]; then PORT="8080" fi # Allow HTTP port echo " Allowing port $PORT for AtlasOS API..." ufw allow "$PORT/tcp" comment "AtlasOS API" 2>/dev/null || true # Allow SMB/CIFS ports echo " Allowing SMB/CIFS ports..." ufw allow 445/tcp comment "SMB/CIFS" 2>/dev/null || true ufw allow 139/tcp comment "NetBIOS" 2>/dev/null || true # Allow NFS ports echo " Allowing NFS ports..." ufw allow 2049/tcp comment "NFS" 2>/dev/null || true ufw allow 2049/udp comment "NFS" 2>/dev/null || true ufw allow 111/tcp comment "RPC" 2>/dev/null || true ufw allow 111/udp comment "RPC" 2>/dev/null || true # Allow iSCSI ports echo " Allowing iSCSI ports..." ufw allow 3260/tcp comment "iSCSI" 2>/dev/null || true echo -e "${GREEN}Firewall configured${NC}" echo "" } # Setup ZFS with comprehensive checks setup_zfs() { echo -e "${GREEN}Setting up ZFS...${NC}" if ! command -v zpool &> /dev/null; then echo -e "${RED}Error: ZFS utilities not found${NC}" echo " Please install zfsutils-linux" return 1 fi # Load ZFS kernel module echo " Loading ZFS kernel module..." if ! lsmod | grep -q "^zfs"; then modprobe zfs 2>/dev/null || { echo -e "${YELLOW}Warning: Could not load ZFS module${NC}" echo " This may require a system reboot" } else echo -e "${GREEN} ✓ ZFS module loaded${NC}" fi # Ensure ZFS module loads on boot if [[ ! -f /etc/modules-load.d/zfs.conf ]] || ! grep -q "^zfs" /etc/modules-load.d/zfs.conf 2>/dev/null; then echo "zfs" > /etc/modules-load.d/zfs.conf echo -e "${GREEN} ✓ ZFS will load on boot${NC}" fi # Check ZFS pool status echo " Checking ZFS pools..." if zpool list &>/dev/null; then POOL_COUNT=$(zpool list -H | wc -l) if [[ $POOL_COUNT -gt 0 ]]; then echo -e "${GREEN} ✓ Found $POOL_COUNT ZFS pool(s)${NC}" else echo -e "${YELLOW} ⚠ No ZFS pools found (you can create them after installation)${NC}" fi else echo -e "${YELLOW} ⚠ ZFS not fully initialized${NC}" fi echo -e "${GREEN}ZFS setup complete${NC}" echo "" } # Setup Samba with dependency checks setup_samba() { echo -e "${GREEN}Setting up Samba...${NC}" if ! command -v smbd &> /dev/null; then echo -e "${RED}Error: Samba not found${NC}" return 1 fi # Create basic Samba config if it doesn't exist if [[ ! -f /etc/samba/smb.conf ]] || [[ ! -s /etc/samba/smb.conf ]]; then echo " Creating basic Samba configuration..." mkdir -p /etc/samba cat > /etc/samba/smb.conf <<'SAMBAEOF' [global] workgroup = WORKGROUP server string = AtlasOS Storage Server security = user map to guest = Bad User dns proxy = no SAMBAEOF echo -e "${GREEN} ✓ Basic Samba config created${NC}" fi # Enable and start Samba services echo " Enabling Samba services..." systemctl enable smbd 2>/dev/null || true systemctl enable nmbd 2>/dev/null || true # Start services if not running if ! systemctl is-active --quiet smbd; then systemctl start smbd 2>/dev/null || echo -e "${YELLOW} ⚠ Could not start smbd (may need manual start)${NC}" fi echo -e "${GREEN}Samba setup complete${NC}" echo "" } # Setup NFS with dependency checks setup_nfs() { echo -e "${GREEN}Setting up NFS...${NC}" if ! command -v exportfs &> /dev/null; then echo -e "${RED}Error: NFS utilities not found${NC}" return 1 fi # Ensure /etc/exports exists if [[ ! -f /etc/exports ]]; then echo " Creating /etc/exports..." touch /etc/exports echo -e "${GREEN} ✓ /etc/exports created${NC}" fi # Enable and start NFS services echo " Enabling NFS services..." systemctl enable rpcbind 2>/dev/null || true systemctl enable nfs-server 2>/dev/null || true systemctl enable nfs-kernel-server 2>/dev/null || true # Start rpcbind first (required dependency) if ! systemctl is-active --quiet rpcbind; then systemctl start rpcbind 2>/dev/null || echo -e "${YELLOW} ⚠ Could not start rpcbind${NC}" fi # Start NFS server if ! systemctl is-active --quiet nfs-server && ! systemctl is-active --quiet nfs-kernel-server; then systemctl start nfs-server 2>/dev/null || systemctl start nfs-kernel-server 2>/dev/null || \ echo -e "${YELLOW} ⚠ Could not start NFS server (may need manual start)${NC}" fi echo -e "${GREEN}NFS setup complete${NC}" echo "" } # Setup iSCSI with dependency checks setup_iscsi() { echo -e "${GREEN}Setting up iSCSI...${NC}" # Check for targetcli or targetcli-fb TARGETCLI_CMD="" if command -v targetcli &> /dev/null; then TARGETCLI_CMD="targetcli" elif command -v targetcli-fb &> /dev/null; then TARGETCLI_CMD="targetcli-fb" # Create symlink if targetcli doesn't exist if ! command -v targetcli &> /dev/null; then ln -sf $(which targetcli-fb) /usr/local/bin/targetcli 2>/dev/null || true fi fi if [[ -z "$TARGETCLI_CMD" ]]; then echo -e "${RED}Error: targetcli or targetcli-fb not found${NC}" echo " Install with: apt-get install targetcli-fb" return 1 fi echo -e "${GREEN} ✓ Found $TARGETCLI_CMD${NC}" # Check if target service exists if systemctl list-unit-files | grep -q "^target.service"; then # Enable and start iSCSI target service echo " Enabling iSCSI target service..." systemctl enable target 2>/dev/null || true # Start service if not running if ! systemctl is-active --quiet target; then systemctl start target 2>/dev/null || echo -e "${YELLOW} ⚠ Could not start target service (may need manual start)${NC}" fi else echo -e "${YELLOW} ⚠ target.service not found (LIO may not be properly installed)${NC}" fi echo -e "${GREEN}iSCSI setup complete (using $TARGETCLI_CMD)${NC}" echo "" } # Create initial admin user create_admin_user() { echo -e "${GREEN}Creating initial admin user...${NC}" echo "" echo -e "${YELLOW}Please set up the initial admin user:${NC}" echo " Username: admin" echo " Password: (you will be prompted)" echo "" echo "After starting the service, you can create the admin user via:" echo " curl -X POST http://localhost:8080/api/v1/users \\" echo " -H 'Content-Type: application/json' \\" echo " -d '{\"username\":\"admin\",\"password\":\"your-password\",\"role\":\"administrator\"}'" echo "" echo "Or use the TUI:" echo " $INSTALL_DIR/bin/atlas-tui" echo "" } # Start service start_service() { echo -e "${GREEN}Starting AtlasOS service...${NC}" systemctl enable atlas-api systemctl start atlas-api # Wait a moment for service to start sleep 2 if systemctl is-active --quiet atlas-api; then echo -e "${GREEN}AtlasOS service started successfully${NC}" else echo -e "${RED}Error: Service failed to start${NC}" echo "Check logs with: journalctl -u atlas-api -n 50" exit 1 fi } # Print summary print_summary() { echo "" echo -e "${GREEN}========================================${NC}" echo -e "${GREEN}AtlasOS Installation Complete!${NC}" echo -e "${GREEN}Ubuntu 24.04 (Noble Numbat)${NC}" echo -e "${GREEN}========================================${NC}" echo "" echo "Installation Directory: $INSTALL_DIR" echo "Data Directory: $DATA_DIR" echo "Config Directory: $CONFIG_DIR" echo "Log Directory: $LOG_DIR" echo "" # Extract port from HTTP_ADDR PORT=$(echo "$HTTP_ADDR" | sed 's/.*://' || echo "8080") if [[ -z "$PORT" ]] || [[ "$PORT" == "$HTTP_ADDR" ]]; then PORT="8080" fi echo "Service Status:" systemctl status atlas-api --no-pager -l 2>/dev/null || echo " Service not running" echo "" echo "Useful Commands:" echo " Service: systemctl {start|stop|restart|status} atlas-api" echo " Logs: journalctl -u atlas-api -f" echo " TUI: atlas-tui (or $INSTALL_DIR/bin/atlas-tui)" echo "" echo "Web Interface:" echo " http://localhost:$PORT" echo "" echo "API Documentation:" echo " http://localhost:$PORT/api/docs" echo "" if [[ "$FIREWALL_ACTIVE" == "true" ]]; then echo -e "${YELLOW}Firewall Configuration:${NC}" echo " UFW is active. The following ports have been allowed:" echo " - Port $PORT (AtlasOS API)" echo " - Port 445 (SMB/CIFS)" echo " - Port 139 (NetBIOS)" echo " - Port 2049 (NFS)" echo " - Port 3260 (iSCSI)" echo " To view rules: ufw status" echo "" fi echo -e "${YELLOW}Storage Services Status:${NC}" echo -n " ZFS: " if command -v zpool &>/dev/null && lsmod | grep -q "^zfs"; then echo -e "${GREEN}✓ Ready${NC}" else echo -e "${YELLOW}⚠ Check required${NC}" fi echo -n " Samba: " if systemctl is-active --quiet smbd 2>/dev/null; then echo -e "${GREEN}✓ Running${NC}" else echo -e "${YELLOW}⚠ Not running (start with: systemctl start smbd)${NC}" fi echo -n " NFS: " if systemctl is-active --quiet nfs-server 2>/dev/null || systemctl is-active --quiet nfs-kernel-server 2>/dev/null; then echo -e "${GREEN}✓ Running${NC}" else echo -e "${YELLOW}⚠ Not running (start with: systemctl start nfs-server)${NC}" fi echo -n " iSCSI: " if systemctl is-active --quiet target 2>/dev/null; then echo -e "${GREEN}✓ Running${NC}" else echo -e "${YELLOW}⚠ Not running (start with: systemctl start target)${NC}" fi echo "" echo -e "${YELLOW}Next Steps:${NC}" echo "1. Create initial admin user (see instructions above)" echo "2. Configure TLS certificates (optional) - see $CONFIG_DIR/atlas.conf" echo "3. Review configuration in $CONFIG_DIR/atlas.conf" echo "4. Ensure storage services are running if needed" echo "" echo -e "${GREEN}Installation completed successfully!${NC}" echo "" } # Main installation main() { echo -e "${GREEN}========================================${NC}" echo -e "${GREEN}AtlasOS Installation Script${NC}" echo -e "${GREEN}For Ubuntu 24.04 (Noble Numbat)${NC}" echo -e "${GREEN}========================================${NC}" echo "" # Step 1: Detect and validate distribution detect_distro echo "" # Step 2: Pre-flight checks preflight_checks # Step 3: Fix infrastructure gaps fix_infrastructure_gaps # Step 4: Install dependencies if [[ "$SKIP_DEPS" == "false" ]]; then install_dependencies else echo -e "${YELLOW}Skipping dependency installation${NC}" echo "" fi # Step 5: Create system user and directories create_user create_directories # Step 6: Build binaries build_binaries # Step 7: Create configuration create_config generate_jwt_secret # Step 8: Create systemd service create_systemd_service # Step 9: Setup storage services setup_zfs setup_samba setup_nfs setup_iscsi # Step 10: Configure firewall configure_firewall # Step 11: Create admin user info create_admin_user # Step 12: Ask if user wants to start service echo "" read -p "Start AtlasOS service now? (y/n) " -n 1 -r echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then start_service else echo -e "${YELLOW}Service not started. Start manually with: systemctl start atlas-api${NC}" fi # Step 13: Print summary print_summary } # Run main main