mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-02-16 19:46:48 +01:00
Install fixes: venv creation, composer.sh download, SSH key non-interactive, ensure 8090/7080 accessible
- install.py: create venv at /usr/local/CyberCP if missing; add system python3 fallback for migrations; download composer.sh before chmod; remove existing SSH keys before ssh-keygen - installCyberPanel.py: remove MariaDB-server from dnf exclude before install - cyberpanel.sh: ensure ports 8090 and 7080 listening after install; final status shows port accessibility - backupUtilities.py: remove existing cyberpanel keys before ssh-keygen to avoid Overwrite prompt
This commit is contained in:
132
cyberpanel.sh
132
cyberpanel.sh
@@ -968,67 +968,9 @@ except Exception as e:
|
||||
if [ -f "$installer_py" ]; then
|
||||
print_status "Using install/install.py directly for installation (non-interactive mode)"
|
||||
|
||||
# CRITICAL: Patch install.py to exclude MariaDB-server from dnf/yum commands
|
||||
if [ -n "$MARIADB_VERSION" ] && [ "$major_ver" -lt 12 ] 2>/dev/null; then
|
||||
print_status "Patching install.py to exclude MariaDB-server from installation commands..."
|
||||
|
||||
# Create backup
|
||||
cp "$installer_py" "${installer_py}.backup" 2>/dev/null || true
|
||||
|
||||
# Patch install.py to add --exclude=MariaDB-server* to dnf/yum install commands
|
||||
python3 -c "
|
||||
import re
|
||||
import sys
|
||||
|
||||
try:
|
||||
with open('$installer_py', 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
original_content = content
|
||||
|
||||
# Pattern: Add --exclude=MariaDB-server* to dnf/yum install commands that install mariadb-server
|
||||
def add_exclude(match):
|
||||
cmd = match.group(0)
|
||||
# Check if --exclude is already present
|
||||
if '--exclude=MariaDB-server' in cmd:
|
||||
return cmd
|
||||
# Add --exclude=MariaDB-server* after install and flags, before packages
|
||||
return re.sub(r'((?:dnf|yum)\s+install\s+(?:-[^\s]+\s+)*)', r'\1--exclude=MariaDB-server* ', cmd, flags=re.IGNORECASE)
|
||||
|
||||
# Find all dnf/yum install commands that mention mariadb-server
|
||||
content = re.sub(
|
||||
r'(?:dnf|yum)\s+install[^;]*?mariadb-server[^;]*',
|
||||
add_exclude,
|
||||
content,
|
||||
flags=re.IGNORECASE | re.MULTILINE
|
||||
)
|
||||
|
||||
# Also handle MariaDB-server (capitalized) and in Python strings
|
||||
content = re.sub(
|
||||
r'(\"|\')(?:dnf|yum)\s+install[^\"]*?mariadb-server[^\"]*(\"|\')',
|
||||
lambda m: m.group(1) + re.sub(r'((?:dnf|yum)\s+install\s+(?:-[^\s]+\s+)*)', r'\1--exclude=MariaDB-server* ', m.group(0)[1:-1], flags=re.IGNORECASE) + m.group(2),
|
||||
content,
|
||||
flags=re.IGNORECASE | re.MULTILINE
|
||||
)
|
||||
|
||||
# Only write if content changed
|
||||
if content != original_content:
|
||||
with open('$installer_py', 'w') as f:
|
||||
f.write(content)
|
||||
print('install.py patched successfully')
|
||||
else:
|
||||
print('No changes needed in install.py')
|
||||
|
||||
except Exception as e:
|
||||
print(f'Error patching install.py: {e}')
|
||||
sys.exit(1)
|
||||
" 2>/dev/null && print_status "install.py patched successfully" || {
|
||||
# Fallback: Simple sed-based patching if Python fails
|
||||
sed -i 's/\(dnf\|yum\) install\([^;]*\)mariadb-server/\1 install\2--exclude=MariaDB-server* mariadb-server/gi' "$installer_py" 2>/dev/null
|
||||
sed -i 's/\(dnf\|yum\) install\([^;]*\)MariaDB-server/\1 install\2--exclude=MariaDB-server* MariaDB-server/gi' "$installer_py" 2>/dev/null
|
||||
print_status "install.py patched (fallback method)"
|
||||
}
|
||||
fi
|
||||
# NOTE: We do NOT patch install.py to add --exclude=MariaDB-server* to dnf install.
|
||||
# That would block the initial MariaDB-server install. install.py now clears dnf exclude
|
||||
# before installing MariaDB and uses official MariaDB-server packages.
|
||||
|
||||
# If MariaDB 10.x is installed, disable repositories right before running installer
|
||||
if [ -n "$MARIADB_VERSION" ] && [ -f /tmp/cyberpanel_repo_monitor.pid ]; then
|
||||
@@ -1421,11 +1363,61 @@ EOF
|
||||
# Give services a moment to start
|
||||
sleep 3
|
||||
|
||||
# Ensure both 8090 (CyberPanel) and 7080 (LiteSpeed/OLS) are accessible
|
||||
echo " • Ensuring ports 8090 and 7080 are accessible..."
|
||||
port_check() {
|
||||
local port=$1
|
||||
command -v ss >/dev/null 2>&1 && ss -tlnp 2>/dev/null | grep -q ":$port " && return 0
|
||||
command -v netstat >/dev/null 2>&1 && netstat -tlnp 2>/dev/null | grep -q ":$port " && return 0
|
||||
return 1
|
||||
}
|
||||
max_attempts=18
|
||||
attempt=0
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
need_restart=false
|
||||
systemctl is-active --quiet mariadb || { systemctl start mariadb 2>/dev/null; need_restart=true; }
|
||||
systemctl is-active --quiet lsws 2>/dev/null || { [ -x /usr/local/lsws/bin/lswsctrl ] && systemctl start lsws 2>/dev/null; need_restart=true; }
|
||||
systemctl is-active --quiet lscpd 2>/dev/null || { systemctl start lscpd 2>/dev/null; need_restart=true; }
|
||||
[ "$need_restart" = true ] && sleep 5
|
||||
if port_check 8090 && port_check 7080; then
|
||||
echo " ✓ Port 8090 (CyberPanel) and 7080 (OpenLiteSpeed) are listening"
|
||||
break
|
||||
fi
|
||||
attempt=$((attempt + 1))
|
||||
[ $attempt -lt $max_attempts ] && sleep 5
|
||||
done
|
||||
if ! port_check 8090 || ! port_check 7080; then
|
||||
systemctl start lscpd 2>/dev/null
|
||||
systemctl start lsws 2>/dev/null
|
||||
sleep 10
|
||||
if port_check 8090 && port_check 7080; then
|
||||
echo " ✓ Port 8090 and 7080 are now listening"
|
||||
else
|
||||
echo " ⚠ One or both ports not yet listening. Run: systemctl start mariadb lsws lscpd"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " ✓ Post-installation configurations completed"
|
||||
}
|
||||
|
||||
# Helper: check if a port is listening
|
||||
_port_listening() {
|
||||
local port=$1
|
||||
command -v ss >/dev/null 2>&1 && ss -tlnp 2>/dev/null | grep -q ":$port " && return 0
|
||||
command -v netstat >/dev/null 2>&1 && netstat -tlnp 2>/dev/null | grep -q ":$port " && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to show status summary
|
||||
show_status_summary() {
|
||||
# Last-chance: try to start services so 8090 and 7080 are accessible
|
||||
if ! _port_listening 8090 || ! _port_listening 7080; then
|
||||
systemctl start mariadb 2>/dev/null || true
|
||||
systemctl start lsws 2>/dev/null || true
|
||||
systemctl start lscpd 2>/dev/null || true
|
||||
sleep 8
|
||||
fi
|
||||
|
||||
echo "==============================================================================================================="
|
||||
echo " FINAL STATUS CHECK"
|
||||
echo "==============================================================================================================="
|
||||
@@ -1453,6 +1445,22 @@ show_status_summary() {
|
||||
echo " ✓ CyberPanel Application - Running"
|
||||
else
|
||||
echo " ✗ CyberPanel Application - Not Running (may take a moment to start)"
|
||||
all_services_running=false
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Port Accessibility:"
|
||||
if _port_listening 8090; then
|
||||
echo " ✓ Port 8090 (CyberPanel) - Accessible"
|
||||
else
|
||||
echo " ✗ Port 8090 (CyberPanel) - Not listening (run: systemctl start lscpd)"
|
||||
all_services_running=false
|
||||
fi
|
||||
if _port_listening 7080; then
|
||||
echo " ✓ Port 7080 (OpenLiteSpeed) - Accessible"
|
||||
else
|
||||
echo " ✗ Port 7080 (OpenLiteSpeed) - Not listening (run: systemctl start lsws)"
|
||||
all_services_running=false
|
||||
fi
|
||||
|
||||
# Get the actual password that was set
|
||||
@@ -1481,7 +1489,7 @@ show_status_summary() {
|
||||
echo "==============================================================================================================="
|
||||
|
||||
if [ "$all_services_running" = true ]; then
|
||||
echo "✓ Installation completed successfully!"
|
||||
echo "✓ Installation completed successfully! Ports 8090 and 7080 are accessible."
|
||||
else
|
||||
echo "⚠ Installation completed with warnings. Some services may need attention."
|
||||
fi
|
||||
|
||||
@@ -1906,11 +1906,34 @@ module cyberpanel_ols {
|
||||
mariadb_ver = getattr(preFlightsChecks, 'mariadb_version', '11.8')
|
||||
command = f'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version={mariadb_ver}'
|
||||
self.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
|
||||
# Use --nobest for 10.11 and 11.8 on el9 to avoid MariaDB-client dependency resolution issues
|
||||
# Allow MariaDB-server to be installed: remove from dnf exclude if present (e.g. from previous run or cyberpanel.sh)
|
||||
dnf_conf = '/etc/dnf/dnf.conf'
|
||||
if os.path.exists(dnf_conf):
|
||||
try:
|
||||
with open(dnf_conf, 'r') as f:
|
||||
dnf_content = f.read()
|
||||
if 'MariaDB-server' in (dnf_content or '') and 'exclude=' in (dnf_content or ''):
|
||||
# Remove MariaDB-server and MariaDB-server* from exclude= line(s)
|
||||
def strip_mariadb_exclude(match):
|
||||
line = match.group(0)
|
||||
rest = re.sub(r'\bMariaDB-server\*?\s*', '', line).strip()
|
||||
if rest == 'exclude=' or rest == 'exclude':
|
||||
return ''
|
||||
return rest.rstrip() + '\n'
|
||||
new_content = re.sub(r'exclude=[^\n]*', strip_mariadb_exclude, dnf_content)
|
||||
new_content = re.sub(r'\n\n+', '\n', new_content)
|
||||
if new_content != dnf_content:
|
||||
with open(dnf_conf, 'w') as f:
|
||||
f.write(new_content)
|
||||
self.stdOut("Temporarily removed MariaDB-server from dnf exclude for installation", 1)
|
||||
except Exception as e:
|
||||
self.stdOut(f"Warning: Could not adjust dnf exclude: {e}", 1)
|
||||
# Install from official MariaDB repo (capitalized package names); --nobest for 10.11/11.8 on el9
|
||||
mariadb_packages = 'MariaDB-server MariaDB-client MariaDB-backup MariaDB-devel'
|
||||
if mariadb_ver in ('10.11', '11.8'):
|
||||
command = 'dnf install -y --nobest mariadb-server mariadb-devel mariadb-client-utils'
|
||||
command = f'dnf install -y --nobest {mariadb_packages}'
|
||||
else:
|
||||
command = 'dnf install mariadb-server mariadb-devel mariadb-client-utils -y'
|
||||
command = f'dnf install -y {mariadb_packages}'
|
||||
self.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
|
||||
|
||||
# Verify MariaDB was installed successfully before proceeding
|
||||
@@ -3267,7 +3290,36 @@ password="%s"
|
||||
|
||||
logging.InstallLog.writeToFile("settings.py updated!")
|
||||
|
||||
# self.setupVirtualEnv(self.distro)
|
||||
# Create Python venv at /usr/local/CyberCP if missing (install.py run from temp dir does not run venvsetup.sh)
|
||||
if not os.path.exists("/usr/local/CyberCP/bin/python"):
|
||||
logging.InstallLog.writeToFile("Creating Python virtual environment at /usr/local/CyberCP...")
|
||||
preFlightsChecks.stdOut("Creating Python virtual environment...")
|
||||
try:
|
||||
r = subprocess.run(
|
||||
[sys.executable or "python3", "-m", "venv", "/usr/local/CyberCP"],
|
||||
timeout=120, capture_output=True, text=True, cwd="/usr/local/CyberCP"
|
||||
)
|
||||
if r.returncode != 0:
|
||||
logging.InstallLog.writeToFile("venv create stderr: " + (r.stderr or "")[:500])
|
||||
if r.returncode == 0 and os.path.exists("/usr/local/CyberCP/bin/pip"):
|
||||
req_file = "/usr/local/CyberCP/requirments.txt"
|
||||
if not os.path.exists(req_file):
|
||||
req_file = "/usr/local/CyberCP/requirements.txt"
|
||||
if os.path.exists(req_file):
|
||||
subprocess.run(
|
||||
["/usr/local/CyberCP/bin/pip", "install", "-r", req_file, "--quiet"],
|
||||
timeout=600, cwd="/usr/local/CyberCP", capture_output=True
|
||||
)
|
||||
else:
|
||||
subprocess.run(
|
||||
["/usr/local/CyberCP/bin/pip", "install", "Django", "PyMySQL", "requests", "cryptography", "psutil", "--quiet"],
|
||||
timeout=180, cwd="/usr/local/CyberCP", capture_output=True
|
||||
)
|
||||
if os.path.exists("/usr/local/CyberCP/bin/python"):
|
||||
logging.InstallLog.writeToFile("Virtual environment created successfully")
|
||||
preFlightsChecks.stdOut("Virtual environment created", 1)
|
||||
except Exception as e:
|
||||
logging.InstallLog.writeToFile("Venv create warning: " + str(e))
|
||||
|
||||
# Now run Django migrations since we're in /usr/local/CyberCP and database exists
|
||||
os.chdir("/usr/local/CyberCP")
|
||||
@@ -3303,46 +3355,53 @@ password="%s"
|
||||
|
||||
logging.InstallLog.writeToFile("Migration cleanup completed")
|
||||
|
||||
# Ensure virtual environment is properly set up
|
||||
logging.InstallLog.writeToFile("Ensuring virtual environment is properly set up...")
|
||||
# Ensure virtual environment or system Python is available
|
||||
logging.InstallLog.writeToFile("Ensuring Python is available for migrations...")
|
||||
if not self.ensureVirtualEnvironmentSetup():
|
||||
logging.InstallLog.writeToFile("ERROR: Virtual environment setup failed!", 0)
|
||||
preFlightsChecks.stdOut("ERROR: Virtual environment setup failed!", 0)
|
||||
return False
|
||||
logging.InstallLog.writeToFile("WARNING: No venv found; will try system Python", 1)
|
||||
|
||||
# Find the correct Python virtual environment path (prefer CyberCP - app install path)
|
||||
# Find Python: prefer venv, then system python3 (avoids FileNotFoundError for /usr/local/CyberPanel/bin/python)
|
||||
python_paths = [
|
||||
"/usr/local/CyberCP/bin/python",
|
||||
"/usr/local/CyberPanel/bin/python",
|
||||
"/usr/local/CyberPanel-venv/bin/python"
|
||||
"/usr/local/CyberPanel-venv/bin/python",
|
||||
"/usr/bin/python3",
|
||||
"/usr/local/bin/python3",
|
||||
]
|
||||
|
||||
if sys.executable and sys.executable not in python_paths:
|
||||
python_paths.append(sys.executable)
|
||||
|
||||
python_path = None
|
||||
for path in python_paths:
|
||||
if os.path.exists(path):
|
||||
python_path = path
|
||||
logging.InstallLog.writeToFile(f"Found Python virtual environment at: {path}")
|
||||
break
|
||||
|
||||
if path and os.path.exists(path):
|
||||
try:
|
||||
r = subprocess.run([path, "--version"], capture_output=True, text=True, timeout=5)
|
||||
if r.returncode == 0:
|
||||
python_path = path
|
||||
logging.InstallLog.writeToFile(f"Using Python at: {path}")
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not python_path:
|
||||
logging.InstallLog.writeToFile("ERROR: No Python virtual environment found!", 0)
|
||||
preFlightsChecks.stdOut("ERROR: No Python virtual environment found!", 0)
|
||||
logging.InstallLog.writeToFile("ERROR: No working Python found for migrations!", 0)
|
||||
preFlightsChecks.stdOut("ERROR: No working Python found!", 0)
|
||||
return False
|
||||
|
||||
# Create migrations in dependency order - loginSystem first since other apps depend on it
|
||||
logging.InstallLog.writeToFile("Creating migrations for loginSystem first...")
|
||||
command = f"{python_path} manage.py makemigrations loginSystem --noinput"
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
|
||||
|
||||
# Now create migrations for all other apps
|
||||
logging.InstallLog.writeToFile("Creating migrations for all other apps...")
|
||||
command = f"{python_path} manage.py makemigrations --noinput"
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
|
||||
|
||||
# Apply all migrations
|
||||
logging.InstallLog.writeToFile("Applying all migrations...")
|
||||
command = f"{python_path} manage.py migrate --noinput"
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
|
||||
|
||||
logging.InstallLog.writeToFile("Django migrations completed successfully!")
|
||||
preFlightsChecks.stdOut("Django migrations completed successfully!")
|
||||
@@ -3354,7 +3413,7 @@ password="%s"
|
||||
self.downloadCDNLibraries()
|
||||
|
||||
command = f"{python_path} manage.py collectstatic --noinput --clear"
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
|
||||
|
||||
## Moving static content to lscpd location
|
||||
command = 'mv static /usr/local/CyberCP/public/'
|
||||
@@ -5308,10 +5367,10 @@ user_query = SELECT email as user, password, 'vmail' as uid, 'vmail' as gid, '/h
|
||||
try:
|
||||
os.remove(f)
|
||||
except OSError:
|
||||
pass
|
||||
subprocess.run(["rm", "-f", f], timeout=5, capture_output=True)
|
||||
|
||||
command = "ssh-keygen -f /root/.ssh/cyberpanel -t rsa -N ''"
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True)
|
||||
|
||||
except BaseException as msg:
|
||||
logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [install_default_keys]")
|
||||
@@ -5701,11 +5760,18 @@ milter_default_action = accept
|
||||
|
||||
os.chdir(self.cwd)
|
||||
|
||||
command = "chmod +x composer.sh"
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
|
||||
# Download composer.sh if missing (e.g. when run from temp dir without repo file)
|
||||
composer_sh = os.path.join(self.cwd, "composer.sh")
|
||||
if not os.path.exists(composer_sh) or not os.path.isfile(composer_sh):
|
||||
command = "wget -q https://cyberpanel.sh/composer.sh -O " + composer_sh
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
|
||||
|
||||
command = "./composer.sh"
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
|
||||
if os.path.exists(composer_sh):
|
||||
command = "chmod +x " + composer_sh
|
||||
preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
|
||||
|
||||
command = "bash " + os.path.abspath(composer_sh)
|
||||
preFlightsChecks.call(command, self.distro, "./composer.sh", command, 1, 0, os.EX_OSERR, True)
|
||||
|
||||
except OSError as msg:
|
||||
logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [setupPHPAndComposer]")
|
||||
|
||||
@@ -922,6 +922,25 @@ gpgcheck=1
|
||||
command = 'dnf clean all'
|
||||
install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
|
||||
|
||||
# Allow MariaDB-server to be installed: remove from dnf exclude if present
|
||||
dnf_conf = '/etc/dnf/dnf.conf'
|
||||
if os.path.exists(dnf_conf):
|
||||
try:
|
||||
with open(dnf_conf, 'r') as f:
|
||||
dnf_content = f.read()
|
||||
if 'MariaDB-server' in dnf_content and 'exclude=' in dnf_content:
|
||||
new_content = re.sub(
|
||||
r'(exclude=[^\n]*)',
|
||||
lambda m: re.sub(r'\bMariaDB-server\*?\s*', '', m.group(1)).strip(),
|
||||
dnf_content
|
||||
)
|
||||
if new_content != dnf_content:
|
||||
with open(dnf_conf, 'w') as f:
|
||||
f.write(new_content)
|
||||
install_utils.writeToFile("Removed MariaDB-server from dnf exclude for installation")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Use --nobest so server+client resolve from same repo (avoids AlmaLinux 9 dependency conflict)
|
||||
command = 'dnf install -y --nobest MariaDB-server MariaDB-client MariaDB-backup'
|
||||
|
||||
|
||||
@@ -1412,6 +1412,13 @@ class backupUtilities:
|
||||
if os.path.exists('/root/.ssh/cyberpanel.pub'):
|
||||
pass
|
||||
else:
|
||||
# Remove existing key files so ssh-keygen never prompts "Overwrite (y/n)?"
|
||||
for f in ('/root/.ssh/cyberpanel', '/root/.ssh/cyberpanel.pub'):
|
||||
if os.path.exists(f):
|
||||
try:
|
||||
os.remove(f)
|
||||
except OSError:
|
||||
pass
|
||||
command = "ssh-keygen -f /root/.ssh/cyberpanel -t rsa -N ''"
|
||||
ProcessUtilities.executioner(command, 'root', True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user