From 58881d8e3bae2cdb317daf224fa2dd56939f85d9 Mon Sep 17 00:00:00 2001 From: Christopher <1289128+dragonfire1119@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:58:54 -0600 Subject: [PATCH] setup-pterodactyl-wings-full-setup-and-quick-setup (#29) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ feat: Implement robust network configuration for Pterodactyl This commit introduces a comprehensive network configuration process for the Pterodactyl setup. The key changes include: - Implementing a function to find an available subnet that is not already in use by the system or other Docker networks. This helps ensure the Pterodactyl network does not conflict with existing network configurations. - Calculating the gateway IP address for the selected subnet, which is then used when creating the Docker network. - Enhancing the `create_pterodactyl_network()` function to handle network creation with proper error checking and verification. - Refactoring the `configure_network()` function to orchestrate the entire network configuration process, including subnet discovery, gateway calculation, and network creation. - Adding detailed comments to explain the purpose and flow of the network configuration logic. These changes improve the reliability and robustness of the Pterodactyl setup by ensuring the network is properly configured and does not interfere with existing network resources. * 🔧 feat(setup-pterodactyl-wings): Improve network configuration and directory setup This commit introduces the following improvements: - Provide better error handling and feedback when finding an available subnet fails - Display a success message when the Docker network is created successfully - Enhance the quick setup option by using a spinner to show the progress of chown commands - Improve the formatting and messaging throughout the script for better readability and user experience The changes aim to provide a more robust and user-friendly setup process for the Pterodactyl wings component. --- setup-pterodactyl-wings/run.sh | 279 +++++++++++++++++++++++---------- 1 file changed, 198 insertions(+), 81 deletions(-) diff --git a/setup-pterodactyl-wings/run.sh b/setup-pterodactyl-wings/run.sh index ad99ee4..3c989f0 100644 --- a/setup-pterodactyl-wings/run.sh +++ b/setup-pterodactyl-wings/run.sh @@ -1,101 +1,195 @@ #!/bin/bash -# Check if exactly one argument (UUID) is provided to the script +# Crafted by BigBearTechWorld +# Script to set up Pterodactyl server environment and networking +# Takes a UUID as an argument for server identification + +CHECK_MARK="\033[0;32m✓\033[0m" +CROSS_MARK="\033[0;31m✗\033[0m" +WARNING_MARK="\033[0;33m⚠\033[0m" + +# Function to print colored output +print_color() { + local color=$1 + local message=$2 + echo -e "\033[${color}m${message}\033[0m" +} + +# Function to print section headers +print_header() { + local header=$1 + echo "-------------------" + print_color "1;34" "$header" + echo "-------------------" +} + +# Function to show spinner for long-running operations +show_spinner() { + local pid=$1 + local delay=0.1 + local spinstr='|/-\' + while ps -p $pid > /dev/null; do + for i in "${spinstr[@]}"; do + printf "\r[%c] " "$i" + sleep $delay + printf "\b\b\b\b" + done + done + printf "\r \b\b\b" +} + +# Input validation: Check if exactly one argument (UUID) is provided if [ $# -ne 1 ]; then - echo "Error: UUID argument is required" + echo -e "${CROSS_MARK} Error: UUID argument is required" echo "Usage: $0 " exit 1 fi +# Store the server UUID in a variable UUID=$1 -# Display menu for user choice +# Display Welcome ----> +print_header "BigBearCasaOS Setup Pterodactyl Wings V0.1" +echo "Here are some links:" +echo "https://community.bigbeartechworld.com" +echo "https://github.com/BigBearTechWorld" +echo "" +echo "If you would like to support me, please consider buying me a tea:" +echo "https://ko-fi.com/bigbeartechworld" +echo "" + +# Display interactive menu for setup options ----> echo "Please select an option:" -echo "1) Run full setup" -echo "2) Run chown commands only" +echo "1) Full setup - Create directories, set permissions, and configure networking" +echo "2) Quick setup - Only create directories and set permissions" read -p "Enter your choice (1 or 2): " choice +# Process user's menu choice ----> +# Mission is a go 3 2 1 lift off!!!! case $choice in 1) - echo "Running full setup..." + echo -e "${CHECK_MARK} Selected: Full setup" ;; 2) - # Create required directories - echo "Creating required directories..." + echo -e "${CHECK_MARK} Selected: Quick setup" + echo -e "\n${WARNING_MARK} Creating required directories..." mkdir -p "/var/lib/pterodactyl/volumes" mkdir -p "/tmp/pterodactyl" mkdir -p "/etc/pterodactyl" mkdir -p "/var/log/pterodactyl" - echo "Running chown commands only..." - chown -R 988:988 /tmp/pterodactyl /etc/pterodactyl /var/log/pterodactyl /var/lib/pterodactyl - echo "Chown commands completed." + echo -e "${WARNING_MARK} Running chown commands..." + (chown -R 988:988 /tmp/pterodactyl /etc/pterodactyl /var/log/pterodactyl /var/lib/pterodactyl) & + show_spinner $! + echo -e "${CHECK_MARK} Chown commands completed successfully." exit 0 ;; *) - echo "Invalid choice. Please run the script again and select 1 or 2." + echo -e "${CROSS_MARK} Invalid choice. Please run the script again and select 1 or 2." exit 1 ;; esac -# Function to check if a subnet is in use +# Running full setup ----> +echo -e "\n${WARNING_MARK} Initiating full setup process..." + +# Function to check if a subnet is already in use by either system routes or Docker networks +# Parameters: +# $1 = subnet to check (e.g., "172.40.0.0/16") +# $2 = network name to exclude from check (to avoid false positives with our own network) +# Returns: +# 0 (true) if subnet is in use +# 1 (false) if subnet is available is_subnet_in_use() { + # Store input parameters in local variables for safety local subnet=$1 local network_name=$2 - local subnet_base=${subnet%/*} + # Remove CIDR notation (e.g., "172.40.0.0/16" becomes "172.40.0.0") + local subnet_base=${subnet%/*} - # Check system routes first + # First Phase: Check system routes for subnet usage + # Use process substitution to read output of 'ip route show' while read -r route; do + # Check if the current route contains our subnet base if [[ "$route" == *"$subnet_base"* ]]; then + # Extract interface name from route (e.g., "dev eth0" becomes "eth0") + # grep -o extracts only matching pattern + # cut -d' ' -f2 splits on space and takes second field local iface=$(echo "$route" | grep -o "dev [^ ]*" | cut -d' ' -f2) + + # Verify interface exists (-n) and isn't our pterodactyl interface + # We ignore pterodactyl0 to avoid detecting our own network if [ -n "$iface" ] && [ "$iface" != "pterodactyl0" ]; then - return 0 + return 0 # Subnet is in use by another interface fi fi - done < <(ip route show) + done < <(ip route show) # Feed output of 'ip route show' into while loop - # Check Docker networks + # Second Phase: Check Docker networks for subnet usage + # Use process substitution to read Docker networks while read -r other_network; do + # Skip checking our own network to avoid false positives if [ "$other_network" != "$network_name" ]; then + # Inspect Docker network configuration + # 2>/dev/null suppresses errors if network doesn't exist + # grep -q quietly checks for subnet match if docker network inspect "$other_network" 2>/dev/null | grep -q "\"Subnet\": \"$subnet\""; then - return 0 + return 0 # Subnet is in use by another Docker network fi fi - done < <(docker network ls --format "{{.Name}}") + done < <(docker network ls --format "{{.Name}}") # Get list of Docker networks - return 1 + # If we get here, no conflicts were found + return 1 # Subnet is available for use } -# Function to find an available subnet +# Function to find an available subnet for Docker networking +# Takes a network name as parameter to avoid checking against itself +# Returns: +# - First available subnet via echo +# - 0 if subnet found successfully +# - 1 if no subnets are available find_available_subnet() { - local network_name=$1 - local subnet_ranges=( - "172.40.0.0/16" - "172.41.0.0/16" - "172.42.0.0/16" - "172.43.0.0/16" - "172.44.0.0/16" - "172.45.0.0/16" - "172.46.0.0/16" - "172.47.0.0/16" - ) + # Store network name parameter locally + local network_name=$1 - for subnet in "${subnet_ranges[@]}"; do - if ! is_subnet_in_use "$subnet" "$network_name"; then - echo "$subnet" - return 0 - fi - done + # Define array of possible subnet ranges to try + # Using 172.40-47 range to avoid conflicts with: + # - Docker default subnet (172.17.0.0/16) + # - Common private network ranges + # Each subnet provides 65,534 usable addresses (/16 network) + local subnet_ranges=( + "172.40.0.0/16" # Provides 172.40.0.1 - 172.40.255.254 + "172.41.0.0/16" # Provides 172.41.0.1 - 172.41.255.254 + "172.42.0.0/16" # Provides 172.42.0.1 - 172.42.255.254 + "172.43.0.0/16" # Provides 172.43.0.1 - 172.43.255.254 + "172.44.0.0/16" # Provides 172.44.0.1 - 172.44.255.254 + "172.45.0.0/16" # Provides 172.45.0.1 - 172.45.255.254 + "172.46.0.0/16" # Provides 172.46.0.1 - 172.46.255.254 + "172.47.0.0/16" # Provides 172.47.0.1 - 172.47.255.254 + ) - return 1 + # Iterate through each subnet in the array until we find an available one + # [@] expands array to list of elements + for subnet in "${subnet_ranges[@]}"; do + # Check if subnet is available using is_subnet_in_use function + # ! inverts the return value since is_subnet_in_use returns 0 when in use + if ! is_subnet_in_use "$subnet" "$network_name"; then + echo "$subnet" # Output the available subnet + return 0 # Return success + fi + done + + # If we've tried all subnets and found none available + return 1 # Return failure - no available subnets found :( } -# Function to get gateway for subnet +# Function to calculate gateway IP for a given subnet get_gateway_for_subnet() { local subnet=$1 - echo "${subnet%.*}.1" + echo "${subnet%.*}.1" # Use .1 as the gateway address } -# Function to create pterodactyl network +# Function to create Docker network for Pterodactyl create_pterodactyl_network() { local subnet=$1 local gateway=$2 @@ -105,7 +199,7 @@ create_pterodactyl_network() { docker network rm pterodactyl_nw || true fi - # Create the network with error checking + # Create new network with specified configuration if ! docker network create \ --driver=bridge \ --ipv6 \ @@ -117,70 +211,93 @@ create_pterodactyl_network() { -o "com.docker.network.bridge.enable_ip_masquerade=true" \ -o "com.docker.network.bridge.enable_icc=true" \ pterodactyl_nw; then - return 1 + return 1 # Network creation failed fi - # Verify network was created + # Verify network creation if ! docker network ls | grep -q "pterodactyl_nw"; then - return 1 + return 1 # Network creation failed fi - return 0 + return 0 # Return success :) } -# Main network configuration function +# Main function to orchestrate the network configuration process +# This function coordinates: +# - Finding an available subnet +# - Calculating the gateway address +# - Creating the Docker network +# Returns: +# 0 on success +# 1 on any error configure_network() { - # Find available subnet - local new_subnet - new_subnet=$(find_available_subnet "pterodactyl_nw") - if [ $? -ne 0 ]; then - echo "ERROR: Could not find available subnet" - return 1 - fi + # Step 1: Find an available subnet + # Store result in local variable for safety + local new_subnet + # Call find_available_subnet and capture its output + # pterodactyl_nw is passed to avoid self-reference in subnet checks + new_subnet=$(find_available_subnet "pterodactyl_nw") + # Check return status of find_available_subnet + # $? contains the return value of the last command + if [ $? -ne 0 ]; then + echo -e "${CROSS_MARK} ERROR: Could not find available subnet" + return 1 + fi + echo -e "${CHECK_MARK} Found available subnet: $new_subnet" - # Get gateway - local new_gateway - new_gateway=$(get_gateway_for_subnet "$new_subnet") - if [ $? -ne 0 ]; then - echo "ERROR: Could not determine gateway" - return 1 - fi + # Step 2: Calculate the gateway IP address for our subnet + # Store in local variable for safety + local new_gateway + # Call get_gateway_for_subnet to calculate the gateway IP + # Typically this will be the .1 address in the subnet + new_gateway=$(get_gateway_for_subnet "$new_subnet") + # Verify gateway calculation was successful + if [ $? -ne 0 ]; then + echo "ERROR: Could not determine gateway" + return 1 # Exit function with error + fi - echo "Using subnet: $new_subnet with gateway: $new_gateway" + # Echo results + echo -e "${CHECK_MARK} Gateway IP set to: $new_gateway" - # Create network - if ! create_pterodactyl_network "$new_subnet" "$new_gateway"; then - echo "ERROR: Failed to create network" - return 1 - fi + # Step 3: Create the Docker network + # Use ! to invert the return value since we want to check for failure + # Pass both subnet and gateway to create_pterodactyl_network + if ! create_pterodactyl_network "$new_subnet" "$new_gateway"; then + echo "ERROR: Failed to create network" + return 1 # Exit function with error + fi + echo -e "${CHECK_MARK} Docker network created successfully" - echo "Network created successfully" - return 0 + # If we get here, all steps completed successfully Woohooo!!! + echo "Network created successfully" + return 0 # Return success :) } -# Create required directories -echo "Creating required directories..." +# Create directory structure for Pterodactyl +echo -e "\n${WARNING_MARK} Creating required directories..." mkdir -p "/var/lib/pterodactyl/volumes/$UUID" mkdir -p "/tmp/pterodactyl/$UUID" mkdir -p "/etc/pterodactyl" mkdir -p "/var/log/pterodactyl" -# Configure network -echo "Configuring network..." +# Set up network configuration for Pterodactyl +echo -e "\n${WARNING_MARK} Configuring network..." if ! configure_network; then echo "ERROR: Network configuration failed" exit 1 fi -# Set ownership -echo "Setting directory permissions..." +# Set appropriate ownership for Pterodactyl directories +echo -e "\n${WARNING_MARK} Setting directory permissions..." chown -R 988:988 /tmp/pterodactyl /etc/pterodactyl /var/log/pterodactyl /var/lib/pterodactyl -# Restart pterodactyl-wings container -echo "Restarting pterodactyl-wings container..." +# Restart the Pterodactyl wings service +echo -e "\n${WARNING_MARK} Restarting pterodactyl-wings container..." if ! docker restart pterodactyl-wings; then - echo "WARNING: Failed to restart pterodactyl-wings container" + echo -e "${CROSS_MARK} WARNING: Failed to restart pterodactyl-wings container" echo "Please restart it manually using: docker restart pterodactyl-wings" fi -echo "Setup completed successfully for UUID: $UUID" +# Mission is complete +echo -e "\n${CHECK_MARK} Setup completed successfully for UUID: $UUID" \ No newline at end of file