Merge pull request #1658 from master3395/v2.5.5-dev

V2.5.5 dev
This commit is contained in:
Master3395
2026-01-26 21:02:03 +01:00
committed by GitHub
3 changed files with 453 additions and 41 deletions

View File

@@ -537,12 +537,17 @@ def RestartCyberPanel(request):
def getDashboardStats(request):
try:
val = request.session['userID']
val = request.session.get('userID')
if val is None:
return HttpResponse(
json.dumps({'status': 0, 'error_message': 'Session required'}),
content_type='application/json'
)
currentACL = ACLManager.loadedACL(val)
admin = Administrator.objects.get(pk=val)
# Check if user is admin
if currentACL['admin'] == 1:
if currentACL.get('admin', 0) == 1:
# Admin can see all resources
total_users = Administrator.objects.count()
total_sites = Websites.objects.count()
@@ -580,7 +585,7 @@ def getDashboardStats(request):
total_emails = EUsers.objects.filter(emailOwner__domainOwner__domain__in=website_names).count()
# Count FTP users associated with user's domains
total_ftp_users = FTPUsers.objects.filter(domain__in=website_names).count()
total_ftp_users = FTPUsers.objects.filter(domain__domain__in=website_names).count()
else:
total_wp_sites = 0
total_dbs = 0
@@ -598,18 +603,24 @@ def getDashboardStats(request):
}
return HttpResponse(json.dumps(data), content_type='application/json')
except Exception as e:
return HttpResponse(json.dumps({'status': 0, 'error_message': str(e)}), content_type='application/json')
logging.writeToFile('getDashboardStats error: %s' % str(e))
return HttpResponse(
json.dumps({'status': 0, 'error_message': 'Failed to load dashboard stats'}),
content_type='application/json'
)
def getTrafficStats(request):
try:
val = request.session['userID']
val = request.session.get('userID')
if val is None:
return HttpResponse(
json.dumps({'status': 0, 'error_message': 'Session required'}),
content_type='application/json'
)
currentACL = ACLManager.loadedACL(val)
# Only admins should see system-wide network stats
if not currentACL.get('admin', 0):
return HttpResponse(json.dumps({'status': 0, 'error_message': 'Admin access required', 'admin_only': True}), content_type='application/json')
# Get network stats from /proc/net/dev (Linux)
rx = tx = 0
with open('/proc/net/dev', 'r') as f:
for line in f.readlines():
@@ -617,42 +628,49 @@ def getTrafficStats(request):
continue
if ':' in line:
parts = line.split()
rx += int(parts[1])
tx += int(parts[9])
data = {
'rx_bytes': rx,
'tx_bytes': tx,
'status': 1
}
try:
if len(parts) >= 10:
rx += int(parts[1])
tx += int(parts[9])
except (ValueError, IndexError):
continue
data = {'rx_bytes': rx, 'tx_bytes': tx, 'status': 1}
return HttpResponse(json.dumps(data), content_type='application/json')
except Exception as e:
return HttpResponse(json.dumps({'status': 0, 'error_message': str(e)}), content_type='application/json')
logging.writeToFile('getTrafficStats error: %s' % str(e))
return HttpResponse(
json.dumps({'status': 0, 'error_message': 'Failed to load traffic stats'}),
content_type='application/json'
)
def getDiskIOStats(request):
try:
val = request.session['userID']
val = request.session.get('userID')
if val is None:
return HttpResponse(
json.dumps({'status': 0, 'error_message': 'Session required'}),
content_type='application/json'
)
currentACL = ACLManager.loadedACL(val)
# Only admins should see system-wide disk I/O stats
if not currentACL.get('admin', 0):
return HttpResponse(json.dumps({'status': 0, 'error_message': 'Admin access required', 'admin_only': True}), content_type='application/json')
# Parse /proc/diskstats for all disks
read_sectors = 0
write_sectors = 0
sector_size = 512 # Most Linux systems use 512 bytes per sector
sector_size = 512
with open('/proc/diskstats', 'r') as f:
for line in f:
parts = line.split()
if len(parts) < 14:
continue
# parts[2] is device name, skip loopback/ram devices
dev = parts[2]
if dev.startswith('loop') or dev.startswith('ram'):
continue
# 6th and 10th columns: sectors read/written
read_sectors += int(parts[5])
write_sectors += int(parts[9])
try:
read_sectors += int(parts[5])
write_sectors += int(parts[9])
except (ValueError, IndexError):
continue
data = {
'read_bytes': read_sectors * sector_size,
'write_bytes': write_sectors * sector_size,
@@ -660,34 +678,42 @@ def getDiskIOStats(request):
}
return HttpResponse(json.dumps(data), content_type='application/json')
except Exception as e:
return HttpResponse(json.dumps({'status': 0, 'error_message': str(e)}), content_type='application/json')
logging.writeToFile('getDiskIOStats error: %s' % str(e))
return HttpResponse(
json.dumps({'status': 0, 'error_message': 'Failed to load disk I/O stats'}),
content_type='application/json'
)
def getCPULoadGraph(request):
try:
val = request.session['userID']
val = request.session.get('userID')
if val is None:
return HttpResponse(
json.dumps({'status': 0, 'error_message': 'Session required'}),
content_type='application/json'
)
currentACL = ACLManager.loadedACL(val)
# Only admins should see system-wide CPU stats
if not currentACL.get('admin', 0):
return HttpResponse(json.dumps({'status': 0, 'error_message': 'Admin access required', 'admin_only': True}), content_type='application/json')
# Parse /proc/stat for the 'cpu' line
cpu_times = []
with open('/proc/stat', 'r') as f:
for line in f:
if line.startswith('cpu '):
parts = line.strip().split()
# parts[1:] are user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice
cpu_times = [float(x) for x in parts[1:]]
try:
cpu_times = [float(x) for x in parts[1:]]
except (ValueError, IndexError):
pass
break
else:
cpu_times = []
data = {
'cpu_times': cpu_times,
'status': 1
}
data = {'cpu_times': cpu_times, 'status': 1}
return HttpResponse(json.dumps(data), content_type='application/json')
except Exception as e:
return HttpResponse(json.dumps({'status': 0, 'error_message': str(e)}), content_type='application/json')
logging.writeToFile('getCPULoadGraph error: %s' % str(e))
return HttpResponse(
json.dumps({'status': 0, 'error_message': 'Failed to load CPU stats'}),
content_type='application/json'
)
@csrf_exempt
@require_GET

View File

@@ -4,10 +4,141 @@
# This installer uses modules for better organization and maintainability
# Each module is kept under 500 lines for easy management
# Note: We use 'set -e' carefully - some operations need to handle failures gracefully
set -e
# Get script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Early logging function (before main functions are defined)
early_log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# Check if script is being executed via curl/wget (SCRIPT_DIR will be /dev/fd/...)
# In that case, we need to clone the repository first
if [[ "$SCRIPT_DIR" == /dev/fd/* ]] || [[ ! -d "$SCRIPT_DIR/modules" ]]; then
# Script is being executed via curl/wget, need to clone repo first
early_log "📥 Detected curl/wget execution - cloning repository..."
# Determine branch from arguments or use default
BRANCH_NAME="v2.5.5-dev"
ARGS=("$@")
for i in "${!ARGS[@]}"; do
if [[ "${ARGS[i]}" == "-b" ]] || [[ "${ARGS[i]}" == "--branch" ]]; then
if [[ -n "${ARGS[i+1]}" ]]; then
BRANCH_NAME="${ARGS[i+1]}"
fi
break
fi
done
# Clone repository to temporary directory
# Try multiple locations if /tmp is full
TEMP_DIR=""
early_log "Checking available disk space..."
# Try to clean up old temp directories first
rm -rf /tmp/cyberpanel-installer-* 2>/dev/null || true
rm -rf /var/tmp/cyberpanel-installer-* 2>/dev/null || true
# Try multiple temp locations (disable set -e for this section)
set +e
for temp_location in "/tmp/cyberpanel-installer-$$" "/var/tmp/cyberpanel-installer-$$" "$HOME/cyberpanel-installer-$$" "/root/cyberpanel-installer-$$"; do
if mkdir -p "$temp_location" 2>/dev/null; then
TEMP_DIR="$temp_location"
early_log "Using temporary directory: $TEMP_DIR"
break
fi
done
set -e
# If we still don't have a temp dir, skip git clone and use fallback
if [ -z "$TEMP_DIR" ]; then
early_log "⚠️ Cannot create temporary directory (disk may be full)"
early_log "Skipping git clone, using fallback installer directly..."
# Skip to fallback installer
TEMP_DIR=""
fi
# Only attempt git clone if we have a temp directory
if [ -n "$TEMP_DIR" ]; then
early_log "📦 Cloning CyberPanel repository (branch: $BRANCH_NAME)..."
early_log "This may take a minute depending on your connection speed..."
# Try git clone with timeout and better error handling
GIT_CLONE_SUCCESS=false
if command -v timeout >/dev/null 2>&1; then
if timeout 180 git clone --depth 1 --branch "$BRANCH_NAME" https://github.com/master3395/cyberpanel.git "$TEMP_DIR/cyberpanel" >/tmp/git-clone.log 2>&1; then
GIT_CLONE_SUCCESS=true
fi
else
# No timeout command, try without timeout
if git clone --depth 1 --branch "$BRANCH_NAME" https://github.com/master3395/cyberpanel.git "$TEMP_DIR/cyberpanel" >/tmp/git-clone.log 2>&1; then
GIT_CLONE_SUCCESS=true
fi
fi
# Verify clone was successful and structure is valid
if [ "$GIT_CLONE_SUCCESS" = true ] && [ -d "$TEMP_DIR/cyberpanel" ] && [ -f "$TEMP_DIR/cyberpanel/install.sh" ] && [ -d "$TEMP_DIR/cyberpanel/modules" ]; then
SCRIPT_DIR="$TEMP_DIR/cyberpanel"
cd "$SCRIPT_DIR"
early_log "✅ Repository cloned successfully"
else
# Git clone failed or structure invalid, use fallback
GIT_ERROR=$(tail -3 /tmp/git-clone.log 2>/dev/null | tr '\n' ' ')
early_log "⚠️ Git clone failed or incomplete"
if [ -n "$GIT_ERROR" ]; then
early_log "Last error: $GIT_ERROR"
fi
early_log "Falling back to legacy installer..."
rm -rf "$TEMP_DIR/cyberpanel" 2>/dev/null || true
TEMP_DIR="" # Clear TEMP_DIR to trigger fallback
fi
fi
# If git clone failed or we couldn't create temp dir, use fallback
if [ -z "$TEMP_DIR" ] || [ ! -d "$TEMP_DIR/cyberpanel" ] || [ ! -f "$TEMP_DIR/cyberpanel/install.sh" ]; then
# Fallback: try to download install.sh from the old method
early_log "Using fallback installer method..."
OUTPUT=$(cat /etc/*release 2>/dev/null || echo "")
if echo "$OUTPUT" | grep -qE "(CentOS|AlmaLinux|CloudLinux|Rocky)" ; then
SERVER_OS="CentOS8"
yum install -y -q curl wget 2>/dev/null || dnf install -y -q curl wget 2>/dev/null || true
elif echo "$OUTPUT" | grep -qE "Ubuntu" ; then
SERVER_OS="Ubuntu"
apt install -y -qq wget curl 2>/dev/null || true
else
early_log "❌ Unable to detect OS for fallback installer"
exit 1
fi
# Try multiple locations for fallback script
FALLBACK_SCRIPT=""
for fallback_location in "/tmp/cyberpanel.sh" "/var/tmp/cyberpanel.sh" "$HOME/cyberpanel.sh"; do
rm -f "$fallback_location" 2>/dev/null || true
if curl --silent -o "$fallback_location" "https://cyberpanel.sh/?dl&$SERVER_OS" 2>/dev/null || \
wget -q -O "$fallback_location" "https://cyberpanel.sh/?dl&$SERVER_OS" 2>/dev/null; then
if [ -f "$fallback_location" ]; then
FALLBACK_SCRIPT="$fallback_location"
chmod +x "$FALLBACK_SCRIPT"
break
fi
fi
done
if [ -n "$FALLBACK_SCRIPT" ] && [ -f "$FALLBACK_SCRIPT" ]; then
early_log "✅ Fallback installer downloaded, executing..."
exec "$FALLBACK_SCRIPT" "$@"
else
early_log "❌ Failed to download fallback installer"
early_log "Please free up disk space or check your internet connection"
exit 1
fi
fi
fi # Close the if [[ "$SCRIPT_DIR" == /dev/fd/* ]] block
MODULES_DIR="$SCRIPT_DIR/modules"
# Colors for output
@@ -88,11 +219,22 @@ detect_operating_system() {
print_status "$BLUE" "🔍 Detecting operating system..."
if detect_os; then
# Get OS information
# Get OS information using get_os_info() to ensure we capture the values
# This outputs variable assignments that we can eval
eval $(get_os_info)
# Export them to ensure they're available to all functions
export SERVER_OS OS_FAMILY PACKAGE_MANAGER ARCHITECTURE
print_status "$GREEN" "✅ OS detected: $SERVER_OS ($OS_FAMILY)"
print_status "$GREEN" "✅ Package manager: $PACKAGE_MANAGER"
print_status "$GREEN" "✅ Architecture: $ARCHITECTURE"
# Verify variables are set
if [ -z "$SERVER_OS" ] || [ -z "$OS_FAMILY" ] || [ -z "$PACKAGE_MANAGER" ]; then
print_status "$RED" "❌ OS variables not properly set after detection"
return 1
fi
return 0
else
print_status "$RED" "❌ Failed to detect operating system"
@@ -104,6 +246,31 @@ detect_operating_system() {
install_dependencies() {
print_status "$BLUE" "📦 Installing dependencies..."
# Debug: Show current variable values
print_status "$YELLOW" "DEBUG: SERVER_OS='$SERVER_OS', OS_FAMILY='$OS_FAMILY', PACKAGE_MANAGER='$PACKAGE_MANAGER'"
# Ensure variables are set (they should be from detect_operating_system)
if [ -z "$SERVER_OS" ] || [ -z "$OS_FAMILY" ] || [ -z "$PACKAGE_MANAGER" ]; then
print_status "$YELLOW" "⚠️ OS variables not set, re-detecting..."
# Try to get them again
if detect_os; then
# Variables should be set by detect_os() in the sourced module
export SERVER_OS OS_FAMILY PACKAGE_MANAGER ARCHITECTURE
print_status "$GREEN" "✅ Re-detected: SERVER_OS=$SERVER_OS, OS_FAMILY=$OS_FAMILY, PACKAGE_MANAGER=$PACKAGE_MANAGER"
else
print_status "$RED" "❌ Failed to detect OS for dependency installation"
return 1
fi
fi
# Verify variables one more time before calling
if [ -z "$SERVER_OS" ] || [ -z "$OS_FAMILY" ] || [ -z "$PACKAGE_MANAGER" ]; then
print_status "$RED" "❌ OS variables still not set after re-detection"
return 1
fi
print_status "$BLUE" "Calling manage_dependencies with: SERVER_OS='$SERVER_OS', OS_FAMILY='$OS_FAMILY', PACKAGE_MANAGER='$PACKAGE_MANAGER'"
if manage_dependencies "$SERVER_OS" "$OS_FAMILY" "$PACKAGE_MANAGER"; then
print_status "$GREEN" "✅ Dependencies installed successfully"
return 0
@@ -214,6 +381,42 @@ parse_arguments() {
done
}
# Function to check disk space
check_disk_space() {
local required_gb=10 # Minimum 10GB required
local root_available_gb=0
# Get available space on root filesystem
if command -v df >/dev/null 2>&1; then
root_available_gb=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//' | cut -d. -f1)
if [ -z "$root_available_gb" ] || [ "$root_available_gb" = "" ]; then
# Try alternative method
root_available_gb=$(df -BG / | tail -1 | awk '{print $4}' | sed 's/G//' | cut -d. -f1)
fi
fi
# If we couldn't get the value, try without -BG flag
if [ -z "$root_available_gb" ] || ! [[ "$root_available_gb" =~ ^[0-9]+$ ]]; then
root_available_gb=$(df / | awk 'NR==2 {print $4}' | awk '{printf "%.0f", $1/1024/1024}')
fi
print_status "$BLUE" "💾 Checking disk space..."
print_status "$BLUE" " Required: ${required_gb}GB minimum"
if [[ "$root_available_gb" =~ ^[0-9]+$ ]] && [ "$root_available_gb" -ge "$required_gb" ]; then
print_status "$GREEN" " Available: ${root_available_gb}GB (✅ Sufficient)"
return 0
elif [[ "$root_available_gb" =~ ^[0-9]+$ ]]; then
print_status "$YELLOW" " Available: ${root_available_gb}GB (⚠️ Less than ${required_gb}GB recommended)"
print_status "$YELLOW" " Installation may fail if disk space runs out"
return 1
else
print_status "$YELLOW" " Could not determine available disk space"
print_status "$YELLOW" " Please ensure at least ${required_gb}GB is available"
return 1
fi
}
# Main installation function
main() {
# Initialize log file
@@ -223,6 +426,9 @@ main() {
print_status "$BLUE" "🚀 Enhanced CyberPanel Installer Starting..."
print_status "$BLUE" "Log file: /var/log/cyberpanel_install.log"
# Check disk space before proceeding
check_disk_space
# Parse command line arguments
parse_arguments "$@"
@@ -251,4 +457,4 @@ main() {
}
# Run main function
main "$@"
main "$@"

View File

@@ -1451,9 +1451,189 @@ module cyberpanel_ols {
except:
return False
def checkExistingMariaDB(self):
"""Check if MariaDB/MySQL is already installed and return version info"""
try:
# Check if MariaDB/MySQL server package is installed
if self.distro == ubuntu:
command = 'dpkg -l | grep -iE "^(ii|rc).*mariadb-server|mysql-server" 2>/dev/null || echo ""'
else:
command = 'rpm -qa | grep -iE "^(mariadb-server|mysql-server|MariaDB-server)" 2>/dev/null || echo ""'
result = subprocess.run(command, shell=True, capture_output=True, universal_newlines=True)
if result.stdout.strip():
# MariaDB/MySQL server package is installed, get version
version_command = 'mysql --version 2>/dev/null || mariadb --version 2>/dev/null || echo ""'
version_result = subprocess.run(version_command, shell=True, capture_output=True, universal_newlines=True)
version_output = version_result.stdout.strip()
if version_output:
# Extract version number (e.g., "10.11.15" from "mysql Ver 10.11.15-MariaDB")
import re
version_match = re.search(r'(\d+\.\d+\.\d+)', version_output)
if version_match:
installed_version = version_match.group(1)
major_minor = '.'.join(installed_version.split('.')[:2]) # e.g., "10.11"
logging.InstallLog.writeToFile(f"Found existing MariaDB installation: {installed_version} (major.minor: {major_minor})")
return True, installed_version, major_minor
logging.InstallLog.writeToFile("Found MariaDB/MySQL package but could not determine version")
return True, "unknown", "unknown"
# Also check if MariaDB service exists and data directory exists (might be installed but package query failed)
if os.path.exists('/var/lib/mysql') and os.listdir('/var/lib/mysql'):
logging.InstallLog.writeToFile("Found MariaDB data directory, assuming MariaDB is installed")
# Try to get version one more time
version_command = 'mysql --version 2>/dev/null || mariadb --version 2>/dev/null || echo ""'
version_result = subprocess.run(version_command, shell=True, capture_output=True, universal_newlines=True)
version_output = version_result.stdout.strip()
if version_output:
import re
version_match = re.search(r'(\d+\.\d+\.\d+)', version_output)
if version_match:
installed_version = version_match.group(1)
major_minor = '.'.join(installed_version.split('.')[:2])
return True, installed_version, major_minor
return True, "unknown", "unknown"
return False, None, None
except Exception as e:
logging.InstallLog.writeToFile(f"Error checking existing MariaDB: {str(e)}")
return False, None, None
def _attemptMariaDBUpgrade(self):
"""Attempt to upgrade MariaDB to 12.1. Returns True if successful, False otherwise."""
try:
if self.distro == ubuntu:
# Ubuntu MariaDB upgrade
command = 'DEBIAN_FRONTEND=noninteractive apt-get install software-properties-common apt-transport-https curl -y'
result = subprocess.run(command, shell=True, capture_output=True, universal_newlines=True)
if result.returncode != 0:
logging.InstallLog.writeToFile(f"Failed to install prerequisites: {result.stderr}")
return False
command = "mkdir -p /etc/apt/keyrings"
subprocess.run(command, shell=True, check=False)
command = "curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp'"
result = subprocess.run(command, shell=True, capture_output=True, universal_newlines=True)
if result.returncode != 0:
logging.InstallLog.writeToFile(f"Failed to download MariaDB keyring: {result.stderr}")
return False
# Setup MariaDB 12.1 repository
command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=12.1'
result = subprocess.run(command, shell=True, capture_output=True, universal_newlines=True)
if result.returncode != 0:
logging.InstallLog.writeToFile(f"Failed to setup MariaDB repository: {result.stderr}")
return False
command = 'DEBIAN_FRONTEND=noninteractive apt-get update -y'
result = subprocess.run(command, shell=True, capture_output=True, universal_newlines=True)
if result.returncode != 0:
logging.InstallLog.writeToFile(f"Failed to update package list: {result.stderr}")
return False
# Attempt to install MariaDB 12.1
command = "DEBIAN_FRONTEND=noninteractive apt-get install mariadb-server -y"
result = subprocess.run(command, shell=True, capture_output=True, universal_newlines=True)
if result.returncode != 0:
# Check if error is due to upgrade restrictions
error_output = result.stderr + result.stdout
if "upgrade" in error_output.lower() or "manual" in error_output.lower():
logging.InstallLog.writeToFile("MariaDB upgrade blocked - requires manual intervention")
else:
logging.InstallLog.writeToFile(f"MariaDB installation failed: {error_output}")
return False
return True
else:
# RHEL-based MariaDB upgrade
# Setup MariaDB 12.1 repository
command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=12.1'
result = subprocess.run(command, shell=True, capture_output=True, universal_newlines=True)
if result.returncode != 0:
logging.InstallLog.writeToFile(f"Failed to setup MariaDB repository: {result.stderr}")
return False
# Attempt to install MariaDB 12.1
# Use --allowerasing to allow package replacements if needed
command = 'dnf install mariadb-server mariadb-devel mariadb-client-utils -y --allowerasing'
result = subprocess.run(command, shell=True, capture_output=True, universal_newlines=True)
if result.returncode != 0:
# Check if error is due to upgrade restrictions
error_output = result.stderr + result.stdout
if "PREIN scriptlet failed" in error_output or "upgrade" in error_output.lower() or "manual" in error_output.lower():
logging.InstallLog.writeToFile("MariaDB upgrade blocked by package manager - requires manual intervention")
else:
logging.InstallLog.writeToFile(f"MariaDB installation failed: {error_output}")
return False
return True
except Exception as e:
logging.InstallLog.writeToFile(f"Exception during MariaDB upgrade attempt: {str(e)}")
return False
def installMySQL(self, mysql):
"""Install MySQL/MariaDB"""
try:
# Check if MariaDB is already installed
is_installed, installed_version, major_minor = self.checkExistingMariaDB()
if is_installed:
self.stdOut(f"MariaDB/MySQL is already installed (version: {installed_version})", 1)
# Check if we need to upgrade
should_try_upgrade = False
if major_minor and major_minor != "unknown":
try:
major_ver = float(major_minor)
if major_ver < 12.0:
should_try_upgrade = True
self.stdOut(f"Existing MariaDB {major_minor} detected. Attempting to upgrade to MariaDB 12.1...", 1)
self.stdOut("If upgrade fails, we will use the existing MariaDB installation.", 1)
except (ValueError, TypeError):
pass
# If MariaDB 10.x is installed, try to upgrade to 12.1 first
if should_try_upgrade:
try:
self.stdOut("Attempting to install MariaDB 12.1...", 1)
upgrade_success = self._attemptMariaDBUpgrade()
if upgrade_success:
self.stdOut("✅ Successfully upgraded to MariaDB 12.1", 1)
self.startMariaDB()
self.changeMYSQLRootPassword()
self.fixMariaDB()
return True
else:
self.stdOut("⚠️ MariaDB 12.1 upgrade failed, using existing MariaDB installation", 1)
self.startMariaDB()
return True
except Exception as upgrade_error:
error_msg = str(upgrade_error)
logging.InstallLog.writeToFile(f"MariaDB upgrade attempt failed: {error_msg}")
# Check if error is due to upgrade restrictions
if "PREIN scriptlet failed" in error_msg or "upgrade" in error_msg.lower() or "manual" in error_msg.lower():
self.stdOut("⚠️ MariaDB upgrade blocked by package manager (10.x to 12.x requires manual upgrade)", 1)
self.stdOut(f"Using existing MariaDB {installed_version} installation", 1)
else:
self.stdOut(f"⚠️ MariaDB upgrade failed: {error_msg}", 1)
self.stdOut(f"Using existing MariaDB {installed_version} installation", 1)
# Fall back to existing installation
self.startMariaDB()
return True
# MariaDB 12.x or higher already installed, or version unknown but working
# Just ensure it's running
self.stdOut("Using existing MariaDB installation", 1)
self.startMariaDB()
return True
self.stdOut("Installing MySQL/MariaDB...", 1)
if self.distro == ubuntu: