Files
EZ-Homelab/scripts/enhanced-setup/setup.sh
Kelin ea06ac1f92 Improve system package installation error handling
- Added sudo access check before attempting package installation
- Better error messages for apt update/install failures
- Graceful handling of package installation failures in main setup flow
- Provides specific guidance when package installation fails
2026-01-29 22:11:15 -05:00

421 lines
13 KiB
Bash
Executable File

#!/bin/bash
# EZ-Homelab Enhanced Setup Scripts - System Setup and Prerequisites
# Installs Docker and configures system prerequisites for EZ-Homelab
SCRIPT_NAME="setup"
SCRIPT_VERSION="1.0.0"
# Load common library
source "$(dirname "${BASH_SOURCE[0]}")/lib/common.sh"
source "$(dirname "${BASH_SOURCE[0]}")/lib/ui.sh"
# =============================================================================
# SCRIPT CONFIGURATION
# =============================================================================
# Docker version requirements
MIN_DOCKER_VERSION="20.10.0"
RECOMMENDED_DOCKER_VERSION="24.0.0"
# Required system packages
SYSTEM_PACKAGES=("curl" "wget" "git" "jq" "unzip" "software-properties-common" "apt-transport-https" "ca-certificates" "gnupg" "lsb-release")
# Python packages (for virtual environment)
PYTHON_PACKAGES=("docker-compose" "pyyaml" "requests")
# =============================================================================
# DOCKER INSTALLATION FUNCTIONS
# =============================================================================
# Remove old Docker installations
remove_old_docker() {
print_info "Removing old Docker installations..."
# Stop services
sudo systemctl stop docker docker.socket containerd 2>/dev/null || true
# Remove packages
sudo apt remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true
# Remove Docker data
sudo rm -rf /var/lib/docker /var/lib/containerd
print_success "Old Docker installations removed"
}
# Install Docker using official method
install_docker_official() {
print_info "Installing Docker Engine (official method)..."
# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/"$(lsb_release -si | tr '[:upper:]' '[:lower:]')"/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/$(lsb_release -si | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Update package index
sudo apt update
# Install Docker Engine
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
print_success "Docker Engine installed"
}
# Install Docker using convenience script (fallback)
install_docker_convenience() {
print_info "Installing Docker using convenience script..."
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
rm get-docker.sh
print_success "Docker installed via convenience script"
}
# Configure Docker daemon
configure_docker_daemon() {
print_info "Configuring Docker daemon..."
local daemon_config='{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"iptables": false,
"bridge": "none",
"ip-masq": false
}'
echo "$daemon_config" | sudo tee /etc/docker/daemon.json > /dev/null
print_success "Docker daemon configured"
}
# Start and enable Docker service
start_docker_service() {
print_info "Starting Docker service..."
sudo systemctl enable docker
sudo systemctl start docker
# Wait for Docker to be ready
local retries=30
while ! docker info >/dev/null 2>&1 && (( retries > 0 )); do
sleep 1
((retries--))
done
if ! docker info >/dev/null 2>&1; then
print_error "Docker service failed to start"
return 1
fi
print_success "Docker service started and enabled"
}
# Add user to docker group
configure_user_permissions() {
print_info "Configuring user permissions..."
if ! groups "$EZ_USER" | grep -q docker; then
sudo usermod -aG docker "$EZ_USER"
print_warning "User added to docker group. A reboot may be required for changes to take effect."
print_info "Alternatively, run: newgrp docker"
else
print_success "User already in docker group"
fi
}
# Test Docker installation
test_docker_installation() {
print_info "Testing Docker installation..."
# Run hello-world container
if ! docker run --rm hello-world >/dev/null 2>&1; then
print_error "Docker test failed"
return 1
fi
# Check Docker version
local docker_version
docker_version=$(docker --version | grep -oP 'Docker version \K[^,]+')
if [[ -z "$docker_version" ]]; then
print_warning "Could not determine Docker version"
return 2
fi
print_success "Docker $docker_version installed and working"
# Check Docker Compose V2
if docker compose version >/dev/null 2>&1; then
local compose_version
compose_version=$(docker compose version | grep -oP 'v\K[^ ]+')
print_success "Docker Compose V2 $compose_version available"
else
print_warning "Docker Compose V2 not available"
fi
}
# =============================================================================
# SYSTEM SETUP FUNCTIONS
# =============================================================================
# Install system packages
install_system_packages() {
print_info "Installing system packages..."
# Check if user has sudo access
if ! sudo -n true 2>/dev/null; then
print_error "This script requires sudo access to install system packages."
print_error "Please run this script as a user with sudo privileges, or install the required packages manually:"
print_error " sudo apt update && sudo apt install -y ${SYSTEM_PACKAGES[*]}"
return 1
fi
# Update package lists
print_info "Updating package lists..."
if ! sudo apt update; then
print_error "Failed to update package lists. Please check your internet connection and apt configuration."
return 1
fi
local missing_packages=()
for package in "${SYSTEM_PACKAGES[@]}"; do
if ! dpkg -l "$package" >/dev/null 2>&1; then
missing_packages+=("$package")
fi
done
if [[ ${#missing_packages[@]} -gt 0 ]]; then
print_info "Installing missing packages: ${missing_packages[*]}"
if ! sudo apt install -y "${missing_packages[@]}"; then
print_error "Failed to install required packages: ${missing_packages[*]}"
print_error "Please install them manually: sudo apt install -y ${missing_packages[*]}"
return 1
fi
else
print_info "All required packages are already installed"
fi
print_success "System packages installed"
}
# Set up Python virtual environment
setup_python_environment() {
print_info "Setting up Python virtual environment..."
local venv_dir="$HOME/.ez-homelab-venv"
# Create virtual environment
if [[ ! -d "$venv_dir" ]]; then
python3 -m venv "$venv_dir"
fi
# Activate and install packages
source "$venv_dir/bin/activate"
# Upgrade pip
pip install --upgrade pip
# Install required packages
if $IS_ARM64; then
# Use PiWheels for ARM64
pip install --extra-index-url https://www.piwheels.org/simple "${PYTHON_PACKAGES[@]}"
else
pip install "${PYTHON_PACKAGES[@]}"
fi
# Deactivate
deactivate
print_success "Python virtual environment configured"
}
# Configure system settings
configure_system_settings() {
print_info "Configuring system settings..."
# Increase file watchers (for large deployments)
echo "fs.inotify.max_user_watches=524288" | sudo tee -a /etc/sysctl.conf >/dev/null
sudo sysctl -p >/dev/null 2>&1
# Configure journald for better logging
sudo mkdir -p /etc/systemd/journald.conf.d
cat << EOF | sudo tee /etc/systemd/journald.conf.d/ez-homelab.conf >/dev/null
[Journal]
Storage=persistent
SystemMaxUse=100M
RuntimeMaxUse=50M
EOF
print_success "System settings configured"
}
# Create required directories
create_directories() {
print_info "Creating required directories..."
sudo mkdir -p /opt/stacks
sudo chown "$EZ_USER:$EZ_USER" /opt/stacks
mkdir -p "$LOG_DIR"
print_success "Directories created"
}
# =============================================================================
# NVIDIA GPU SETUP (OPTIONAL)
# =============================================================================
# Check if NVIDIA setup is needed
check_nvidia_setup_needed() {
command_exists nvidia-smi && nvidia-smi >/dev/null 2>&1
}
# Install NVIDIA drivers (if requested)
install_nvidia_drivers() {
if $non_interactive; then
print_info "Skipping NVIDIA setup (non-interactive mode)"
return 0
fi
if ! ui_yesno "NVIDIA GPU detected. Install NVIDIA drivers and Docker GPU support?"; then
print_info "Skipping NVIDIA setup"
return 0
fi
print_info "Installing NVIDIA drivers..."
# Add NVIDIA repository
wget https://developer.download.nvidia.com/compute/cuda/repos/"$(lsb_release -si | tr '[:upper:]' '[:lower:]')""$(lsb_release -sr | tr -d '.')"/x86_64/cuda-keyring_1.0-1_all.deb
sudo dpkg -i cuda-keyring_1.0-1_all.deb
rm cuda-keyring_1.0-1_all.deb
sudo apt update
# Install NVIDIA driver
sudo apt install -y nvidia-driver-525 nvidia-docker2
# Configure Docker for NVIDIA
sudo systemctl restart docker
print_success "NVIDIA drivers installed"
}
# =============================================================================
# MAIN FUNCTION
# =============================================================================
main() {
local skip_docker=false
local skip_nvidia=false
local non_interactive=false
local verbose=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
ui_show_help "$SCRIPT_NAME"
exit 0
;;
--skip-docker)
skip_docker=true
;;
--skip-nvidia)
skip_nvidia=true
;;
--no-ui)
non_interactive=true
;;
-v|--verbose)
verbose=true
;;
*)
print_error "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
shift
done
# Initialize script
init_script "$SCRIPT_NAME"
if $verbose; then
set -x
fi
print_info "Starting EZ-Homelab system setup..."
print_info "This will install Docker and configure your system for EZ-Homelab."
# Run pre-flight checks first (allow warnings)
local preflight_exit=0
"$(dirname "${BASH_SOURCE[0]}")/preflight.sh" --no-ui || preflight_exit=$?
if [[ $preflight_exit -eq 1 ]]; then
print_error "Pre-flight checks failed with critical errors. Please resolve issues before proceeding."
exit 1
elif [[ $preflight_exit -eq 2 ]]; then
print_warning "Pre-flight checks completed with warnings. Setup will proceed and install missing dependencies."
fi
# Install system packages
if ! run_with_progress "Installing system packages" "install_system_packages"; then
print_error "Failed to install system packages. This is required for Docker installation."
print_error "Please resolve the issue and re-run this script."
print_error "Common solutions:"
print_error " - Ensure you have sudo access: sudo -l"
print_error " - Check internet connection: ping 8.8.8.8"
print_error " - Update package lists: sudo apt update"
print_error " - Install packages manually: sudo apt install -y ${SYSTEM_PACKAGES[*]}"
exit 1
fi
# Set up Python environment
run_with_progress "Setting up Python environment" "setup_python_environment"
# Configure system settings
run_with_progress "Configuring system settings" "configure_system_settings"
# Create directories
run_with_progress "Creating directories" "create_directories"
# Install Docker (unless skipped)
if ! $skip_docker; then
run_with_progress "Removing old Docker installations" "remove_old_docker"
run_with_progress "Installing Docker" "install_docker_official"
run_with_progress "Configuring Docker daemon" "configure_docker_daemon"
run_with_progress "Starting Docker service" "start_docker_service"
run_with_progress "Configuring user permissions" "configure_user_permissions"
run_with_progress "Testing Docker installation" "test_docker_installation"
else
print_info "Skipping Docker installation (--skip-docker)"
fi
# NVIDIA setup (if applicable and not skipped)
if ! $skip_nvidia && check_nvidia_setup_needed; then
run_with_progress "Installing NVIDIA drivers" "install_nvidia_drivers"
fi
echo ""
print_success "EZ-Homelab system setup complete!"
if ! $skip_docker && ! groups "$EZ_USER" | grep -q docker; then
print_warning "IMPORTANT: Please reboot your system for Docker group changes to take effect."
print_info "Alternatively, run: newgrp docker"
print_info "Then re-run this script or proceed to the next step."
else
print_info "You can now proceed to the pre-deployment wizard:"
print_info " ./pre-deployment-wizard.sh"
fi
exit 0
}
# Run main function
main "$@"