setup-pterodactyl-wings-full-setup-and-quick-setup (#29)

*  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.
This commit is contained in:
Christopher
2025-01-09 13:58:54 -06:00
committed by GitHub
parent 6718f4d906
commit 58881d8e3b

View File

@@ -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 <uuid>"
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 :( <Mission Failed>
}
# 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"