diff --git a/discord-header.md b/discord-header.md deleted file mode 100644 index 07d5b1c..0000000 --- a/discord-header.md +++ /dev/null @@ -1,5 +0,0 @@ -# HOPS Discord Channel Header - -**HOPS - Homelab Orchestration Provisioning Script** 🏠 -Cross-platform automation tool for deploying homelab infrastructure using Docker Compose. Menu-driven installation and management of media servers, download clients, monitoring tools, and more. Supports Linux, macOS, and Windows (WSL2). -🔗 **GitHub**: https://github.com/skiercm/hops \ No newline at end of file diff --git a/lib/privileges.sh b/lib/privileges.sh deleted file mode 100755 index 085680f..0000000 --- a/lib/privileges.sh +++ /dev/null @@ -1,775 +0,0 @@ -#!/bin/bash - -# HOPS - Privilege Management System -# Split operations into privileged and non-privileged components -# Version: 3.1.0-beta - -# Source common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/common.sh" - -# Operations that require root privileges -PRIVILEGED_OPERATIONS=( - "install_docker" - "configure_firewall" - "create_system_directories" - "install_packages" - "configure_systemd" - "setup_secrets_directory" - "modify_system_files" -) - -# Operations that can run as regular user -NON_PRIVILEGED_OPERATIONS=( - "generate_docker_compose" - "pull_docker_images" - "start_containers" - "stop_containers" - "view_logs" - "check_service_status" - "validate_configuration" - "backup_user_data" -) - -# Check if operation requires privileges -requires_privileges() { - local operation="$1" - - for priv_op in "${PRIVILEGED_OPERATIONS[@]}"; do - if [[ "$operation" == "$priv_op" ]]; then - return 0 - fi - done - - return 1 -} - -# Check if operation can run as regular user -can_run_as_user() { - local operation="$1" - - for user_op in "${NON_PRIVILEGED_OPERATIONS[@]}"; do - if [[ "$operation" == "$user_op" ]]; then - return 0 - fi - done - - return 1 -} - -# Get current user information -get_current_user_info() { - local -A user_info - - if [[ -n "$SUDO_USER" ]]; then - user_info["username"]="$SUDO_USER" - user_info["uid"]=$(id -u "$SUDO_USER") - user_info["gid"]=$(id -g "$SUDO_USER") - user_info["home"]=$(eval echo "~$SUDO_USER") - user_info["is_sudo"]="true" - else - user_info["username"]="$USER" - user_info["uid"]=$(id -u) - user_info["gid"]=$(id -g) - user_info["home"]="$HOME" - user_info["is_sudo"]="false" - fi - - # Return as key=value pairs - for key in "${!user_info[@]}"; do - echo "${key}=${user_info[$key]}" - done -} - -# Drop privileges to regular user -drop_privileges() { - local command="$1" - shift - local args=("$@") - - if [[ $EUID -ne 0 ]]; then - debug "Already running as non-root user" - exec "$command" "${args[@]}" - return $? - fi - - if [[ -z "$SUDO_USER" ]]; then - error_exit "Cannot drop privileges: SUDO_USER not set" - fi - - local user_info - user_info=$(get_current_user_info) - - local uid=$(echo "$user_info" | grep "uid=" | cut -d= -f2) - local gid=$(echo "$user_info" | grep "gid=" | cut -d= -f2) - local home=$(echo "$user_info" | grep "home=" | cut -d= -f2) - - debug "Dropping privileges to user: $SUDO_USER (uid=$uid, gid=$gid)" - - # Set environment variables for the user - local env_vars=( - "HOME=$home" - "USER=$SUDO_USER" - "LOGNAME=$SUDO_USER" - "PATH=/usr/local/bin:/usr/bin:/bin" - ) - - # Execute command as user - sudo -u "$SUDO_USER" env "${env_vars[@]}" "$command" "${args[@]}" -} - -# Run operation with appropriate privileges -run_with_privileges() { - local operation="$1" - local command="$2" - shift 2 - local args=("$@") - - if requires_privileges "$operation"; then - debug "Operation '$operation' requires root privileges" - - if [[ $EUID -ne 0 ]]; then - error_exit "Operation '$operation' requires root privileges. Please run with sudo." - fi - - # Run as root - exec "$command" "${args[@]}" - elif can_run_as_user "$operation"; then - debug "Operation '$operation' can run as regular user" - - if [[ $EUID -eq 0 ]]; then - # Drop privileges - drop_privileges "$command" "${args[@]}" - else - # Run as current user - exec "$command" "${args[@]}" - fi - else - error_exit "Unknown operation: $operation" - fi -} - -# Create privileged setup script -create_privileged_setup() { - local setup_script="$1" - - cat > "$setup_script" << 'EOF' -#!/bin/bash - -# HOPS Privileged Setup Script -# This script handles operations that require root privileges -# Version: 3.1.0-beta - -set -e - -# Source common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/lib/common.sh" -source "$SCRIPT_DIR/lib/system.sh" -source "$SCRIPT_DIR/lib/security.sh" - -# Initialize logging -setup_logging "privileged-setup" - -# Check root privileges -check_root - -# Install Docker if not present -install_docker() { - info "đŸŗ Installing Docker..." - - if command_exists docker; then - success "Docker already installed" - return 0 - fi - - # Update package index - apt-get update - - # Install prerequisites - apt-get install -y \ - ca-certificates \ - curl \ - gnupg \ - lsb-release - - # Add Docker GPG key - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg - - # Add Docker repository with proper Ubuntu codename detection for Linux Mint - local ubuntu_codename - if [[ "$(lsb_release -is)" == "Linuxmint" ]]; then - # Linux Mint provides UBUNTU_CODENAME in /etc/os-release - if [[ -f /etc/os-release ]]; then - ubuntu_codename=$(grep '^UBUNTU_CODENAME=' /etc/os-release | cut -d= -f2) - fi - - # Fallback to version mapping if UBUNTU_CODENAME not found - if [[ -z "$ubuntu_codename" ]]; then - case "$(lsb_release -rs)" in - "22"|"22.1"|"22.2"|"22.3") - ubuntu_codename="noble" # Ubuntu 24.04 - ;; - "21"|"21.1"|"21.2"|"21.3") - ubuntu_codename="jammy" # Ubuntu 22.04 - ;; - "20"|"20.1"|"20.2"|"20.3") - ubuntu_codename="focal" # Ubuntu 20.04 - ;; - *) - ubuntu_codename="noble" # Default to latest LTS - ;; - esac - fi - else - ubuntu_codename=$(lsb_release -cs) - fi - - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $ubuntu_codename stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - - # Update package index with Docker packages - apt-get update - - # Install Docker - apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin - - # Start and enable Docker service - systemctl start docker - systemctl enable docker - - success "Docker installed successfully" -} - -# Configure firewall -configure_firewall() { - info "đŸ”Ĩ Configuring firewall..." - - # Install UFW if not present - if ! command_exists ufw; then - apt-get update - apt-get install -y ufw - fi - - # Reset firewall to defaults - ufw --force reset - - # Set default policies - ufw default deny incoming - ufw default allow outgoing - - # Allow SSH (prevent lockout) - ufw allow ssh - - # Allow HTTP and HTTPS - ufw allow 80/tcp - ufw allow 443/tcp - - # Enable firewall - ufw --force enable - - success "Firewall configured successfully" -} - -# Create system directories -create_system_directories() { - info "📁 Creating system directories..." - - local directories=( - "/opt/appdata" - "/mnt/media" - "/mnt/media/movies" - "/mnt/media/tv" - "/mnt/media/music" - "/mnt/media/downloads" - "/var/log/hops" - ) - - for dir in "${directories[@]}"; do - if mkdir -p "$dir"; then - success "Created directory: $dir" - else - error_exit "Failed to create directory: $dir" - fi - done - - # Set ownership to the user who ran sudo - if [[ -n "$SUDO_USER" ]]; then - local user_info - user_info=$(get_user_info) - - local uid=$(echo "$user_info" | grep "uid=" | cut -d= -f2) - local gid=$(echo "$user_info" | grep "gid=" | cut -d= -f2) - - chown -R "$uid:$gid" /opt/appdata /mnt/media - success "Set ownership of directories to $SUDO_USER" - fi -} - -# Add user to docker group -add_user_to_docker_group() { - if [[ -z "$SUDO_USER" ]]; then - warning "No SUDO_USER set, skipping docker group addition" - return 0 - fi - - info "đŸ‘Ĩ Adding user to docker group..." - - if usermod -aG docker "$SUDO_USER"; then - success "User $SUDO_USER added to docker group" - warning "User must log out and back in for group changes to take effect" - else - error_exit "Failed to add user to docker group" - fi -} - -# Install required packages -install_packages() { - info "đŸ“Ļ Installing required packages..." - - apt-get update - - local packages=( - "curl" - "wget" - "git" - "jq" - "htop" - "tree" - "unzip" - "gnupg" - "software-properties-common" - "apt-transport-https" - "ca-certificates" - "lsb-release" - ) - - for package in "${packages[@]}"; do - if apt-get install -y "$package"; then - success "Installed package: $package" - else - warning "Failed to install package: $package" - fi - done -} - -# Setup secrets directory -setup_secrets_directory() { - info "🔐 Setting up secrets directory..." - - local secrets_dir="/etc/hops/secrets" - - if mkdir -p "$secrets_dir"; then - chmod 700 "$secrets_dir" - success "Secrets directory created: $secrets_dir" - else - error_exit "Failed to create secrets directory" - fi -} - -# Configure system settings -configure_system() { - info "âš™ī¸ Configuring system settings..." - - # Set timezone if not already set - if [[ -n "$TZ" ]]; then - timedatectl set-timezone "$TZ" 2>/dev/null || true - fi - - # Enable IP forwarding for Docker - echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf - sysctl -p /etc/sysctl.conf - - success "System configuration completed" -} - -# Main privileged setup -main() { - info "🚀 Starting privileged setup..." - - # System checks - detect_os - check_system_requirements - - # Install packages - install_packages - - # Install Docker - install_docker - - # Configure firewall - configure_firewall - - # Create directories - create_system_directories - - # Add user to docker group - add_user_to_docker_group - - # Setup secrets - setup_secrets_directory - - # Configure system - configure_system - - success "Privileged setup completed successfully" - success "Please log out and back in for group changes to take effect" -} - -# Run if executed directly -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - main "$@" -fi -EOF - - chmod +x "$setup_script" - success "Privileged setup script created: $setup_script" -} - -# Create non-privileged user script -create_user_script() { - local user_script="$1" - - cat > "$user_script" << 'EOF' -#!/bin/bash - -# HOPS User Script -# This script handles operations that can run as regular user -# Version: 3.1.0-beta - -set -e - -# Source common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/lib/common.sh" -source "$SCRIPT_DIR/lib/docker.sh" -source "$SCRIPT_DIR/lib/validation.sh" - -# Initialize logging -setup_logging "user-operations" - -# Check if user is in docker group -check_docker_access() { - if ! groups "\$USER" | grep -q docker; then - error_exit "User not in docker group. Please run the privileged setup first and log out/in." - fi - - if ! docker info >/dev/null 2>&1; then - error_exit "Cannot access Docker daemon. Please ensure Docker is running." - fi -} - -# Generate Docker Compose configuration -generate_docker_compose() { - local services=("$@") - local compose_file="$HOME/hops/docker-compose.yml" - - info "📝 Generating Docker Compose configuration..." - - # Create homelab directory - mkdir -p "$HOME/hops" - - # Generate compose file header - cat > "$compose_file" << EOF -services: -EOF - - # Generate service definitions - for service in "${services[@]}"; do - if "$SCRIPT_DIR/services-improved" generate "$service" >> "$compose_file"; then - success "Added service: $service" - else - error_exit "Failed to generate service definition for: $service" - fi - done - - # Add networks section - cat >> "$compose_file" << EOF - -networks: - homelab: - driver: bridge - traefik: - driver: bridge - database: - driver: bridge -EOF - - success "Docker Compose configuration generated: $compose_file" -} - -# Deploy services -deploy_services() { - local compose_file="$HOME/hops/docker-compose.yml" - - if [[ ! -f "$compose_file" ]]; then - error_exit "Docker Compose file not found: $compose_file" - fi - - info "🚀 Deploying services..." - - cd "$HOME/hops" - - # Pull images - if docker compose pull; then - success "Docker images pulled successfully" - else - error_exit "Failed to pull Docker images" - fi - - # Start services - if docker compose up -d; then - success "Services deployed successfully" - else - error_exit "Failed to deploy services" - fi -} - -# Stop services -stop_services() { - local compose_file="$HOME/hops/docker-compose.yml" - - if [[ ! -f "$compose_file" ]]; then - error_exit "Docker Compose file not found: $compose_file" - fi - - info "🛑 Stopping services..." - - cd "$HOME/hops" - - if docker compose down; then - success "Services stopped successfully" - else - error_exit "Failed to stop services" - fi -} - -# Show service status -show_service_status() { - local compose_file="$HOME/hops/docker-compose.yml" - - if [[ ! -f "$compose_file" ]]; then - error_exit "Docker Compose file not found: $compose_file" - fi - - info "📊 Service status:" - - cd "$HOME/hops" - docker compose ps -} - -# Main user operations -main() { - local action="$1" - shift - - # Check Docker access - check_docker_access - - case "$action" in - "generate") - if [[ $# -eq 0 ]]; then - error_exit "Usage: $0 generate [service2] ..." - fi - generate_docker_compose "$@" - ;; - - "deploy") - deploy_services - ;; - - "stop") - stop_services - ;; - - "status") - show_service_status - ;; - - "logs") - if [[ $# -eq 0 ]]; then - error_exit "Usage: $0 logs " - fi - cd "$HOME/hops" - docker compose logs -f "$1" - ;; - - *) - error_exit "Unknown action: $action" - ;; - esac -} - -# Run if executed directly -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - main "$@" -fi -EOF - - chmod +x "$user_script" - success "User script created: $user_script" - -# Create installation wrapper -create_installation_wrapper() { - local wrapper_script="$1" - - cat > "$wrapper_script" << 'EOF' -#!/bin/bash - -# HOPS Installation Wrapper -# Orchestrates privileged and non-privileged installation steps -# Version: 3.1.0-beta - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/lib/common.sh" - -# Initialize logging -setup_logging "installation-wrapper" - -# Show header -show_hops_header "3.1.0" "Installation Wrapper" - -# Check if we're running as root -if [[ $EUID -eq 0 ]]; then - if [[ -z "$SUDO_USER" ]]; then - error_exit "Please run with sudo, not as root directly" - fi -else - error_exit "This script must be run with sudo" -fi - -# Phase 1: Privileged setup -info "📋 Phase 1: Privileged setup (requires root)" -if "$SCRIPT_DIR/privileged-setup"; then - success "Privileged setup completed" -else - error_exit "Privileged setup failed" -fi - -# Phase 2: User setup -info "📋 Phase 2: User setup (running as $SUDO_USER)" - -# Drop privileges and run user setup -sudo -u "$SUDO_USER" bash << 'USERSCRIPT' -cd "$HOME" -echo "Running as user: $(whoami)" - -# Interactive service selection -echo "Select services to install:" -echo "1) Media Server Stack (Jellyfin, Sonarr, Radarr, Prowlarr)" -echo "2) Download Client Stack (qBittorrent, Transmission)" -echo "3) Monitoring Stack (Portainer, Uptime Kuma)" -echo "4) Custom selection" - -read -p "Enter your choice (1-4): " choice - -case "$choice" in - 1) - services=("jellyfin" "sonarr" "radarr" "prowlarr") - ;; - 2) - services=("qbittorrent" "transmission") - ;; - 3) - services=("portainer" "uptime-kuma") - ;; - 4) - echo "Available services:" - "$SCRIPT_DIR/services-improved" list - read -p "Enter service names (space-separated): " -a services - ;; - *) - echo "Invalid choice" - exit 1 - ;; -esac - -# Generate and deploy -if "$SCRIPT_DIR/user-operations" generate "${services[@]}"; then - echo "Configuration generated successfully" - - if "$SCRIPT_DIR/user-operations" deploy; then - echo "Services deployed successfully" - else - echo "Deployment failed" - exit 1 - fi -else - echo "Configuration generation failed" - exit 1 -fi -USERSCRIPT - -success "Installation completed successfully" -success "Services are now running. Check status with: ./user-operations status" -EOF - - chmod +x "$wrapper_script" - success "Installation wrapper created: $wrapper_script" -} - -# Main function -main() { - local action="$1" - shift - - case "$action" in - "create-setup") - create_privileged_setup "$1" - ;; - - "create-user") - create_user_script "$1" - ;; - - "create-wrapper") - create_installation_wrapper "$1" - ;; - - "create-all") - create_privileged_setup "privileged-setup" - create_user_script "user-operations" - create_installation_wrapper "setup" - ;; - - "run") - local operation="$1" - local command="$2" - shift 2 - run_with_privileges "$operation" "$command" "$@" - ;; - - "help"|"--help"|"-h") - cat < [options] - -Actions: - create-setup Create privileged setup script - create-user Create non-privileged user script - create-wrapper Create installation wrapper - create-all Create all scripts - run [args] Run operation with appropriate privileges - help Show this help message - -Examples: - $0 create-all - $0 run install_docker /usr/bin/apt-get install docker-ce - $0 run generate_docker_compose ./compose-gen.sh - -EOF - ;; - - *) - error_exit "Unknown action: $action. Use 'help' for usage information." - ;; - esac -} - -# If script is run directly (not sourced) -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - setup_logging "privileges" - main "$@" -fi \ No newline at end of file diff --git a/privileged-setup b/privileged-setup deleted file mode 100755 index a3047e5..0000000 --- a/privileged-setup +++ /dev/null @@ -1,266 +0,0 @@ -#!/bin/bash - -# HOPS Privileged Setup Script -# This script handles operations that require root privileges -# Version: 3.1.0-beta - -set -e - -# Source common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/lib/common.sh" -source "$SCRIPT_DIR/lib/system.sh" -source "$SCRIPT_DIR/lib/security.sh" - -# Initialize logging -setup_logging "privileged-setup" - -# Check root privileges -check_root - -# Install Docker if not present -install_docker() { - info "đŸŗ Installing Docker..." - - if command_exists docker; then - success "Docker already installed" - return 0 - fi - - # Update package index - apt-get update - - # Install prerequisites - apt-get install -y \ - ca-certificates \ - curl \ - gnupg \ - lsb-release - - # Add Docker GPG key - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg - - # Add Docker repository with proper Ubuntu codename detection for Linux Mint - local ubuntu_codename - if [[ "$(lsb_release -is)" == "Linuxmint" ]]; then - # Linux Mint provides UBUNTU_CODENAME in /etc/os-release - if [[ -f /etc/os-release ]]; then - ubuntu_codename=$(grep '^UBUNTU_CODENAME=' /etc/os-release | cut -d= -f2) - fi - - # Fallback to version mapping if UBUNTU_CODENAME not found - if [[ -z "$ubuntu_codename" ]]; then - case "$(lsb_release -rs)" in - "22"|"22.1"|"22.2"|"22.3") - ubuntu_codename="noble" # Ubuntu 24.04 - ;; - "21"|"21.1"|"21.2"|"21.3") - ubuntu_codename="jammy" # Ubuntu 22.04 - ;; - "20"|"20.1"|"20.2"|"20.3") - ubuntu_codename="focal" # Ubuntu 20.04 - ;; - *) - ubuntu_codename="noble" # Default to latest LTS - ;; - esac - fi - else - ubuntu_codename=$(lsb_release -cs) - fi - - echo "DEBUG: Detected OS: $(lsb_release -is), Ubuntu codename: $ubuntu_codename" - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $ubuntu_codename stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null - - # Update package index with Docker packages - apt-get update - - # Install Docker - apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin - - # Start and enable Docker service - systemctl start docker - systemctl enable docker - - success "Docker installed successfully" -} - -# Configure firewall -configure_firewall() { - info "đŸ”Ĩ Configuring firewall..." - - # Install UFW if not present - if ! command_exists ufw; then - apt-get update - apt-get install -y ufw - fi - - # Reset firewall to defaults - ufw --force reset - - # Set default policies - ufw default deny incoming - ufw default allow outgoing - - # Allow SSH (prevent lockout) - ufw allow ssh - - # Allow HTTP and HTTPS - ufw allow 80/tcp - ufw allow 443/tcp - - # Enable firewall - ufw --force enable - - success "Firewall configured successfully" -} - -# Create system directories -create_system_directories() { - info "📁 Creating system directories..." - - local directories=( - "/opt/appdata" - "/mnt/media" - "/mnt/media/movies" - "/mnt/media/tv" - "/mnt/media/music" - "/mnt/media/downloads" - "/var/log/hops" - ) - - for dir in "${directories[@]}"; do - if mkdir -p "$dir"; then - success "Created directory: $dir" - else - error_exit "Failed to create directory: $dir" - fi - done - - # Set ownership to the user who ran sudo - if [[ -n "$SUDO_USER" ]]; then - local user_info - user_info=$(get_user_info) - - local uid=$(echo "$user_info" | grep "uid=" | cut -d= -f2) - local gid=$(echo "$user_info" | grep "gid=" | cut -d= -f2) - - chown -R "$uid:$gid" /opt/appdata /mnt/media - success "Set ownership of directories to $SUDO_USER" - fi -} - -# Add user to docker group -add_user_to_docker_group() { - if [[ -z "$SUDO_USER" ]]; then - warning "No SUDO_USER set, skipping docker group addition" - return 0 - fi - - info "đŸ‘Ĩ Adding user to docker group..." - - if usermod -aG docker "$SUDO_USER"; then - success "User $SUDO_USER added to docker group" - warning "User must log out and back in for group changes to take effect" - else - error_exit "Failed to add user to docker group" - fi -} - -# Install required packages -install_packages() { - info "đŸ“Ļ Installing required packages..." - - apt-get update - - local packages=( - "curl" - "wget" - "git" - "jq" - "htop" - "tree" - "unzip" - "gnupg" - "software-properties-common" - "apt-transport-https" - "ca-certificates" - "lsb-release" - ) - - for package in "${packages[@]}"; do - if apt-get install -y "$package"; then - success "Installed package: $package" - else - warning "Failed to install package: $package" - fi - done -} - -# Setup secrets directory -setup_secrets_directory() { - info "🔐 Setting up secrets directory..." - - local secrets_dir="/etc/hops/secrets" - - if mkdir -p "$secrets_dir"; then - chmod 700 "$secrets_dir" - success "Secrets directory created: $secrets_dir" - else - error_exit "Failed to create secrets directory" - fi -} - -# Configure system settings -configure_system() { - info "âš™ī¸ Configuring system settings..." - - # Set timezone if not already set - if [[ -n "$TZ" ]]; then - timedatectl set-timezone "$TZ" 2>/dev/null || true - fi - - # Enable IP forwarding for Docker - echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf - sysctl -p /etc/sysctl.conf - - success "System configuration completed" -} - -# Main privileged setup -main() { - info "🚀 Starting privileged setup..." - - # System checks - detect_os - check_system_requirements - - # Install packages - install_packages - - # Install Docker - install_docker - - # Configure firewall - configure_firewall - - # Create directories - create_system_directories - - # Add user to docker group - add_user_to_docker_group - - # Setup secrets - setup_secrets_directory - - # Configure system - configure_system - - success "Privileged setup completed successfully" - success "Please log out and back in for group changes to take effect" -} - -# Run if executed directly -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - main "$@" -fi \ No newline at end of file diff --git a/services-improved b/services-improved deleted file mode 100755 index f3db1c0..0000000 --- a/services-improved +++ /dev/null @@ -1,572 +0,0 @@ -#!/bin/bash - -# HOPS Service Definitions - Improved Version -# Contains all Docker Compose service configurations with error handling and pinned versions -# Version: 3.1.0-beta - -# Exit on any error -set -e - -# Source common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then - source "$SCRIPT_DIR/lib/common.sh" -else - echo "ERROR: Common library not found. Please ensure lib/common.sh exists." >&2 - exit 1 -fi - -if [[ -f "$SCRIPT_DIR/lib/security.sh" ]]; then - source "$SCRIPT_DIR/lib/security.sh" -else - echo "ERROR: Security library not found. Please ensure lib/security.sh exists." >&2 - exit 1 -fi - -# Service definitions with pinned versions (from docker.sh) -declare -A SERVICE_IMAGES=( - # Media Management (*arr Stack) - ["sonarr"]="lscr.io/linuxserver/sonarr:4.0.10" - ["radarr"]="lscr.io/linuxserver/radarr:5.8.3" - ["lidarr"]="lscr.io/linuxserver/lidarr:2.5.3" - ["readarr"]="lscr.io/linuxserver/readarr:0.3.32-develop" - ["bazarr"]="lscr.io/linuxserver/bazarr:1.4.3" - ["prowlarr"]="lscr.io/linuxserver/prowlarr:1.24.3" - ["tdarr"]="ghcr.io/haveagitgat/tdarr:2.26.01" - - # Download Clients - ["qbittorrent"]="lscr.io/linuxserver/qbittorrent:4.6.7" - ["transmission"]="lscr.io/linuxserver/transmission:4.0.6" - ["nzbget"]="lscr.io/linuxserver/nzbget:24.3" - ["sabnzbd"]="lscr.io/linuxserver/sabnzbd:4.3.3" - - # Media Servers - ["jellyfin"]="lscr.io/linuxserver/jellyfin:10.9.11" - ["plex"]="lscr.io/linuxserver/plex:1.40.5" - ["emby"]="lscr.io/linuxserver/emby:4.8.8" - ["jellystat"]="cyfershepard/jellystat:1.1.0" - - # Request Management - ["overseerr"]="lscr.io/linuxserver/overseerr:1.33.2" - ["jellyseerr"]="fallenbagel/jellyseerr:1.9.2" - ["ombi"]="lscr.io/linuxserver/ombi:4.43.5" - - # Reverse Proxy & Security - ["traefik"]="traefik:v3.1.6" - ["nginx-proxy-manager"]="jc21/nginx-proxy-manager:2.11.3" - ["authelia"]="authelia/authelia:4.38.16" - - # Monitoring & Management - ["portainer"]="portainer/portainer-ce:2.21.4" - ["uptime-kuma"]="louislam/uptime-kuma:1.23.15" - ["watchtower"]="containrrr/watchtower:1.7.1" -) - -# Service port mapping -declare -A SERVICE_PORTS=( - ["sonarr"]="8989" - ["radarr"]="7878" - ["lidarr"]="8686" - ["readarr"]="8787" - ["bazarr"]="6767" - ["prowlarr"]="9696" - ["tdarr"]="8265" - ["qbittorrent"]="8082" - ["transmission"]="9091" - ["nzbget"]="6789" - ["sabnzbd"]="8080" - ["jellyfin"]="8096" - ["plex"]="32400" - ["emby"]="8096" - ["jellystat"]="3000" - ["overseerr"]="5055" - ["jellyseerr"]="5056" - ["ombi"]="3579" - ["traefik"]="8080" - ["nginx-proxy-manager"]="81" - ["authelia"]="9091" - ["portainer"]="9000" - ["uptime-kuma"]="3001" - ["watchtower"]="8080" -) - -# Initialize logging -setup_logging "service-definitions" - -# Validate service name -validate_service_name_internal() { - local service_name="$1" - - if [[ -z "$service_name" ]]; then - error_exit "Service name is required" - fi - - if ! validate_service_name "$service_name"; then - error_exit "Invalid service name: $service_name" - fi - - if [[ -z "${SERVICE_IMAGES[$service_name]}" ]]; then - error_exit "Unknown service: $service_name" - fi -} - -# Get service image with validation -get_service_image() { - local service_name="$1" - validate_service_name_internal "$service_name" - echo "${SERVICE_IMAGES[$service_name]}" -} - -# Get service port with validation -get_service_port() { - local service_name="$1" - validate_service_name_internal "$service_name" - echo "${SERVICE_PORTS[$service_name]}" -} - -# Common environment variables for LinuxServer containers -get_linuxserver_env() { - cat < [service_name...]" - fi - generate_multiple_services "$@" - ;; - - "list") - list_available_services - ;; - - "validate") - if [[ $# -eq 0 ]]; then - error_exit "Usage: $0 validate " - fi - validate_service_config "$1" - ;; - - "help"|"--help"|"-h") - cat < [options] - -Actions: - generate ... Generate service definitions - list List all available services - validate Validate service configuration - help Show this help message - -Examples: - $0 generate sonarr radarr jellyfin - $0 list - $0 validate traefik - -EOF - ;; - - *) - error_exit "Unknown action: $action. Use 'help' for usage information." - ;; - esac -} - -# If script is run directly (not sourced) -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - main "$@" -fi \ No newline at end of file diff --git a/setup b/setup deleted file mode 100755 index 90fc9dc..0000000 --- a/setup +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash - -# HOPS Installation Wrapper -# Orchestrates privileged and non-privileged installation steps -# Version: 3.1.0-beta - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/lib/common.sh" - -# Initialize logging -setup_logging "installation-wrapper" - -# Show header -show_hops_header "3.1.0-beta" "Installation Wrapper" - -# Check if we're running as root -if [[ $EUID -eq 0 ]]; then - if [[ -z "$SUDO_USER" ]]; then - error_exit "Please run with sudo, not as root directly" - fi -else - error_exit "This script must be run with sudo" -fi - -# Phase 1: Privileged setup -info "📋 Phase 1: Privileged setup (requires root)" -if "$SCRIPT_DIR/privileged-setup"; then - success "Privileged setup completed" -else - error_exit "Privileged setup failed" -fi - -# Phase 2: User setup -info "📋 Phase 2: User setup (running as $SUDO_USER)" - -# Drop privileges and run user setup -sudo -u "$SUDO_USER" bash << 'USERSCRIPT' -cd "$HOME" -echo "Running as user: $(whoami)" - -# Interactive service selection -echo "Select services to install:" -echo "1) Media Server Stack (Jellyfin, Sonarr, Radarr, Prowlarr)" -echo "2) Download Client Stack (qBittorrent, Transmission)" -echo "3) Monitoring Stack (Portainer, Uptime Kuma)" -echo "4) Custom selection" - -read -p "Enter your choice (1-4): " choice - -case "$choice" in - 1) - services=("jellyfin" "sonarr" "radarr" "prowlarr") - ;; - 2) - services=("qbittorrent" "transmission") - ;; - 3) - services=("portainer" "uptime-kuma") - ;; - 4) - echo "Available services:" - "$SCRIPT_DIR/services-improved" list - read -p "Enter service names (space-separated): " -a services - ;; - *) - echo "Invalid choice" - exit 1 - ;; -esac - -# Generate and deploy -if "$SCRIPT_DIR/user-operations" generate "${services[@]}"; then - echo "Configuration generated successfully" - - if "$SCRIPT_DIR/user-operations" deploy; then - echo "Services deployed successfully" - else - echo "Deployment failed" - exit 1 - fi -else - echo "Configuration generation failed" - exit 1 -fi -USERSCRIPT - -success "Installation completed successfully" -success "Services are now running. Check status with: ./user-operations status" \ No newline at end of file diff --git a/summary7-19.txt b/summary7-19.txt deleted file mode 100644 index 9280a99..0000000 --- a/summary7-19.txt +++ /dev/null @@ -1,170 +0,0 @@ -# HOPS Linux Mint Docker Repository Troubleshooting Summary -## Date: July 19, 2025 - -### Problem Description -HOPS installation failing on Linux Mint 22.1 with Docker repository error: -``` -E: The repository 'https://download.docker.com/linux/ubuntu xia Release' does not have a Release file. -N: Updating from such a repository can't be done securely, and is therefore disabled by default. -``` - -### Root Cause Analysis -- Linux Mint uses its own codenames (e.g., "xia" for version 22.1) -- Docker repositories are structured around Ubuntu codenames (e.g., "noble", "jammy", "focal") -- HOPS was using `lsb_release -cs` which returns "xia" instead of the Ubuntu base codename -- Docker doesn't have a repository for Linux Mint's "xia" codename - -### System Information (Linux Mint 22.1) -``` -Distributor ID: LinuxMint -Description: Linux Mint 22.1 -Release: 22.1 -Codename: xia -UBUNTU_CODENAME=noble (from /etc/os-release) -``` - -### Troubleshooting Steps Attempted - -#### 1. Initial Fix Attempt (Commit af57a77) -**Files Modified:** `privileged-setup`, `lib/privileges.sh` -**Approach:** Added Linux Mint version to Ubuntu codename mapping -- Mint 22.x → Ubuntu 24.04 (noble) -- Mint 21.x → Ubuntu 22.04 (jammy) -- Mint 20.x → Ubuntu 20.04 (focal) - -**Result:** Still failed with same error - -#### 2. System Cleanup -**Commands Executed:** -```bash -sudo rm -f /etc/apt/sources.list.d/docker* -sudo rm -f /etc/apt/sources.list.d/*docker* -sudo rm -f /usr/share/keyrings/docker* -sudo rm -f /etc/apt/keyrings/docker* -sudo grep -i docker /etc/apt/sources.list -sudo apt clean -sudo apt autoclean -``` - -**Result:** Confirmed clean state, but error persisted - -#### 3. Improved Fix (Commit 4fd78ec) -**Files Modified:** `privileged-setup`, `lib/privileges.sh` -**Approach:** Use `UBUNTU_CODENAME` from `/etc/os-release` with fallback to version mapping -```bash -# Primary method: Read UBUNTU_CODENAME from /etc/os-release -ubuntu_codename=$(grep '^UBUNTU_CODENAME=' /etc/os-release | cut -d= -f2) - -# Fallback: Version mapping if UBUNTU_CODENAME not found -``` - -**Result:** Still experiencing same error after system cleanup - -#### 4. Discovery of UBUNTU_CODENAME -**Key Finding:** Linux Mint 22.1 provides `UBUNTU_CODENAME=noble` in `/etc/os-release` -- This is the correct Ubuntu codename that Docker repositories support -- Should eliminate need for manual version mapping - -#### 5. Root Cause Discovery - Wrong Installation Path (Session 2) -**Date:** July 19, 2025 (Evening) -**Discovery:** User was running `./setup` script, but fixes were applied to different code paths -**Investigation Steps:** -- Confirmed user had latest code with fixes (commit 4fd78ec) -- System was completely clean of Docker repositories -- `UBUNTU_CODENAME=noble` correctly detected -- Still getting "xia" error despite fixes - -**Key Finding:** The `setup` script uses `lib/system.sh::install_docker()` which was calling Docker's convenience script `curl -fsSL https://get.docker.com | sh`, NOT the fixed installation functions in `privileged-setup` or `lib/privileges.sh`. - -#### 6. Fix Applied to Correct Installation Path (Commit ce0f7f2) -**Files Modified:** `lib/system.sh` (lines 1122-1168) -**Approach:** -- Replaced Docker convenience script with manual repository setup -- Added Linux Mint Ubuntu codename detection logic to `lib/system.sh` -- Included same UBUNTU_CODENAME detection and fallback mapping -- Added debug output: "Using Ubuntu codename: X for Docker repository" - -**Result:** User tested after pulling latest code - still experiencing same "xia" error - -### Current Status (End of Session 2) -**Problem State:** Persistent "xia" repository error despite comprehensive fixes -**Fixes Applied:** -- Three different installation paths updated with Linux Mint detection -- Complete Docker repository cleanup performed multiple times -- Debug output added to track codename detection -- Manual testing confirmed UBUNTU_CODENAME=noble is available - -**Unresolved Questions:** -1. Why debug output from fixed code is not appearing in installation logs -2. Whether there's a fourth Docker installation path not yet discovered -3. Possible system-level caching or existing Docker installation interfering -4. Whether the correct script path is actually being executed - -### Next Steps (For Tomorrow) -1. **Execution Path Verification:** Add debug traces to determine which exact functions are being called during `./setup` -2. **Docker Installation Check:** Verify if Docker is already installed and causing early function returns -3. **Complete Docker Removal:** If Docker exists, completely remove it before testing fixes -4. **Alternative Installation Methods:** Test other entry points (`./hops`, `./install`, `./privileged-setup` directly) -5. **System State Analysis:** Check for any persistent apt configurations or cached repository information - -### Technical Notes -- Linux Mint consistently provides `UBUNTU_CODENAME` in modern versions -- Using this field is more reliable than version-based mapping -- Docker installation uses Ubuntu repositories for Debian-based distributions -- Issue affects all Linux Mint installations using HOPS -- The Docker convenience script `get.docker.com` has its own broken Linux Mint detection - -### Files Modified -- `privileged-setup` (lines 43-70, 72) - ✅ Fixed -- `lib/privileges.sh` (lines 199-226, 228) - ✅ Fixed -- `lib/system.sh` (lines 1122-1168) - ✅ Fixed - -#### 7. Final Resolution (Session 3 - July 20, 2025) -**Root Cause Identified:** Critical case sensitivity bug in Linux Mint detection -- `lsb_release -is` returns `"Linuxmint"` (lowercase 'm') -- All code was checking for `"LinuxMint"` (uppercase 'M') -- This caused Linux Mint detection to fail completely, falling back to "xia" codename - -**Final Fixes Applied:** -1. **Case Sensitivity Fix (Commit 736ed1b):** - - Fixed `lib/system.sh:1151`: `"LinuxMint"` → `"Linuxmint"` - - Fixed `privileged-setup:45`: `"LinuxMint"` → `"Linuxmint"` - - Fixed `lib/privileges.sh:201`: `"LinuxMint"` → `"Linuxmint"` - -2. **Debug Tracing Added (Commit d2e9a69):** - - Added comprehensive debug output to trace execution paths - - Fixed Docker repository cleanup order in `remove_docker_linux()` - - Added specific cleanup for Linux Mint codenames (xia, vera, vanessa) - -3. **Docker Service Issues (Manual Fix):** - - Created missing `docker` group: `sudo groupadd docker` - - Added user to docker group: `sudo usermod -aG docker skier` - - Started Docker services: `sudo systemctl start docker.socket docker` - -4. **Directory Detection Fix (Commit a28a6e5):** - - Fixed sudo home directory resolution in `install` script - - Changed `$HOME/hops` to use `$SUDO_USER` home directory - - Resolved `/root/hops` vs `/home/skier/hops` issue - -**Final Result:** ✅ **COMPLETE SUCCESS** -- Docker repositories now use correct Ubuntu codename "noble" -- Sonarr container deployed and running successfully -- Web UI accessible at localhost:8989 -- All Linux Mint Docker repository issues resolved - -### Current Status (RESOLVED) -**Problem State:** ✅ **COMPLETELY RESOLVED** -**Final Working State:** -- Linux Mint detection working: `DEBUG: Linux Mint detected, checking for UBUNTU_CODENAME` -- Ubuntu codename detection: `DEBUG: Found UBUNTU_CODENAME=noble in /etc/os-release` -- Repository configuration: `â„šī¸ Using Ubuntu codename: noble for Docker repository` -- Docker installation: Downloads from `https://download.docker.com/linux/ubuntu noble` -- Service deployment: Sonarr running and accessible - -### Git Commits -- `af57a77`: Initial Linux Mint version mapping fix -- `4fd78ec`: Improved fix using UBUNTU_CODENAME detection -- `ce0f7f2`: Fix lib/system.sh Docker installation path with manual repository setup -- `d2e9a69`: Fix Docker repository issues with debug tracing and cleanup order -- `736ed1b`: Fix critical Linux Mint case sensitivity bug in repository detection -- `a28a6e5`: Fix homelab directory detection when running with sudo \ No newline at end of file diff --git a/user-operations b/user-operations deleted file mode 100755 index dd9549d..0000000 --- a/user-operations +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/bash - -# HOPS User Script -# This script handles operations that can run as regular user -# Version: 3.1.0-beta - -set -e - -# Source common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$SCRIPT_DIR/lib/common.sh" -source "$SCRIPT_DIR/lib/docker.sh" -source "$SCRIPT_DIR/lib/validation.sh" - -# Initialize logging -setup_logging "user-operations" - -# Check if user is in docker group -check_docker_access() { - if ! groups "$USER" | grep -q docker; then - error_exit "User not in docker group. Please run the privileged setup first and log out/in." - fi - - if ! docker info >/dev/null 2>&1; then - error_exit "Cannot access Docker daemon. Please ensure Docker is running." - fi -} - -# Generate Docker Compose configuration -generate_docker_compose() { - local services=("$@") - local compose_file="$HOME/hops/docker-compose.yml" - - info "📝 Generating Docker Compose configuration..." - - # Create homelab directory - mkdir -p "$HOME/hops" - - # Generate compose file header - cat > "$compose_file" << EOF -services: -EOF - - # Generate service definitions - for service in "${services[@]}"; do - if "$SCRIPT_DIR/services-improved" generate "$service" >> "$compose_file"; then - success "Added service: $service" - else - error_exit "Failed to generate service definition for: $service" - fi - done - - # Add networks section - cat >> "$compose_file" << EOF - -networks: - homelab: - driver: bridge - traefik: - driver: bridge - database: - driver: bridge -EOF - - success "Docker Compose configuration generated: $compose_file" -} - -# Deploy services -deploy_services() { - local compose_file="$HOME/hops/docker-compose.yml" - - if [[ ! -f "$compose_file" ]]; then - error_exit "Docker Compose file not found: $compose_file" - fi - - info "🚀 Deploying services..." - - cd "$HOME/hops" - - # Pull images - if docker compose pull; then - success "Docker images pulled successfully" - else - error_exit "Failed to pull Docker images" - fi - - # Start services - if docker compose up -d; then - success "Services deployed successfully" - else - error_exit "Failed to deploy services" - fi -} - -# Stop services -stop_services() { - local compose_file="$HOME/hops/docker-compose.yml" - - if [[ ! -f "$compose_file" ]]; then - error_exit "Docker Compose file not found: $compose_file" - fi - - info "🛑 Stopping services..." - - cd "$HOME/hops" - - if docker compose down; then - success "Services stopped successfully" - else - error_exit "Failed to stop services" - fi -} - -# Show service status -show_service_status() { - local compose_file="$HOME/hops/docker-compose.yml" - - if [[ ! -f "$compose_file" ]]; then - error_exit "Docker Compose file not found: $compose_file" - fi - - info "📊 Service status:" - - cd "$HOME/hops" - docker compose ps -} - -# Main user operations -main() { - local action="$1" - shift - - # Check Docker access - check_docker_access - - case "$action" in - "generate") - if [[ $# -eq 0 ]]; then - error_exit "Usage: $0 generate [service2] ..." - fi - generate_docker_compose "$@" - ;; - - "deploy") - deploy_services - ;; - - "stop") - stop_services - ;; - - "status") - show_service_status - ;; - - "logs") - if [[ $# -eq 0 ]]; then - error_exit "Usage: $0 logs " - fi - cd "$HOME/hops" - docker compose logs -f "$1" - ;; - - *) - error_exit "Unknown action: $action" - ;; - esac -} - -# Run if executed directly -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - main "$@" -fi \ No newline at end of file