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

V2.5.5 dev
This commit is contained in:
Master3395
2026-04-11 23:38:37 +02:00
committed by GitHub
5 changed files with 212 additions and 81 deletions

View File

@@ -5831,7 +5831,7 @@ milter_default_action = accept
# Create symlink to the best available PHP version
# Try to find and use the best available PHP version
# Priority: 85 (beta), 84, 83, 82, 81, 80, 74 (newest to oldest)
# Priority: 85, 84, 83, 82, 81, 80, 74 (newest to oldest)
php_versions = ['85', '84', '83', '82', '81', '80', '74']
php_symlink_source = None
@@ -5882,7 +5882,7 @@ milter_default_action = accept
logging.InstallLog.writeToFile("[setup_lsphp_symlink] Removed existing lsphp file/symlink")
# Try to find and use the best available PHP version
# Priority: 85 (beta), 84, 83, 82, 81, 80, 74 (newest to oldest)
# Priority: 85, 84, 83, 82, 81, 80, 74 (newest to oldest)
php_versions = ['85', '84', '83', '82', '81', '80', '74']
lsphp_source = None

View File

@@ -755,18 +755,18 @@ module cyberpanel_ols {
return self.reStartLiteSpeed()
def installAllPHPVersions(self):
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
# OS-aligned matrix (same base list as upgrade.get_available_php_versions pre-filter)
php_versions = install_utils.get_lsphp_install_suffixes()
if self.distro == ubuntu:
# Install base PHP 7.x packages
# Install base PHP 7.x packages (wildcard) plus explicit matrix suffixes
command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install ' \
'lsphp7? lsphp7?-common lsphp7?-curl lsphp7?-dev lsphp7?-imap lsphp7?-intl lsphp7?-json ' \
'lsphp7?-ldap lsphp7?-mysql lsphp7?-opcache lsphp7?-pspell lsphp7?-recode ' \
'lsphp7?-sqlite3 lsphp7?-tidy'
os.system(command)
# Install PHP 8.x versions
for version in php_versions[4:]: # 80, 81, 82, 83
for version in php_versions:
self.install_package(f'lsphp{version}*')
elif self.distro == centos:

View File

@@ -289,6 +289,88 @@ openeuler = 3
debian12 = 4
def get_lsphp_install_suffixes():
"""
LiteSpeed lsphp* two-digit version suffixes to install for this OS (pre-repo check).
Mirrors the base list in plogical/upgrade.py get_available_php_versions() before
check_package_availability filtering.
Returns:
list[str]: e.g. ['74','80',...,'85'] on AlmaLinux 9+/10+ and modern EL9/Ubuntu24+/Debian13+,
or ['71',...,'85'] on older platforms where 7.17.3 packages exist.
"""
long_list = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
short_list = ['74', '80', '81', '82', '83', '84', '85']
# AlmaLinux: explicit release file (matches upgrade.get_available_php_versions)
if exists('/etc/almalinux-release'):
try:
with open('/etc/almalinux-release', 'r') as f:
content = f.read().lower()
if 'release 9' in content or 'release 10' in content:
return list(short_list)
except (OSError, IOError, UnicodeError):
pass
return list(long_list)
# Other RHEL family (Rocky/RHEL/CentOS Stream) without almalinux-release: EL9+ uses short list
if exists('/etc/redhat-release'):
try:
with open('/etc/redhat-release', 'r') as f:
data = f.read().lower()
if (
'release 9' in data
or 'release 10' in data
or 'stream 9' in data
or 'stream 10' in data
):
return list(short_list)
except (OSError, IOError, UnicodeError):
pass
# Ubuntu 24.04+ (upgrade: Ubuntu24 branch)
if exists('/etc/lsb-release'):
try:
with open('/etc/lsb-release', 'r') as f:
lsb = f.read()
if 'DISTRIB_ID=Ubuntu' in lsb:
for line in lsb.splitlines():
if line.startswith('DISTRIB_RELEASE='):
rel = line.split('=', 1)[1].strip().strip('"').strip("'")
try:
parts = rel.split('.')
major = int(parts[0])
minor = int(parts[1]) if len(parts) > 1 else 0
if major > 24 or (major == 24 and minor >= 4):
return list(short_list)
except (ValueError, IndexError):
pass
break
except (OSError, IOError, UnicodeError):
pass
# Debian 13+ (trixie+): upgrade uses Debian13 for short list
if exists('/etc/os-release'):
try:
with open('/etc/os-release', 'r') as f:
osr = f.read()
osr_l = osr.lower().replace(' ', '')
if 'id=debian' in osr_l:
for line in osr.splitlines():
if line.upper().startswith('VERSION_ID='):
vid = line.split('=', 1)[1].strip().strip('"').strip("'")
try:
if int(vid.split('.')[0]) >= 13:
return list(short_list)
except (ValueError, IndexError):
pass
break
except (OSError, IOError, UnicodeError):
pass
return list(long_list)
def get_distro():
"""
Detect Linux distribution

View File

@@ -166,110 +166,151 @@ except ImportError:
print("WARNING: Cannot import CyberCP settings. Attempting recovery...")
def recover_database_credentials():
"""Attempt to recover or reset database credentials"""
# First, ensure we have root MySQL password
"""Recover CyberPanel DB credentials without changing passwords (upgrade policy).
Never drops or re-hashes the `cyberpanel`@`localhost` user or rotates passwords
unless CYBERPANEL_ALLOW_DB_CREDENTIAL_RESET=1 is set (legacy recovery only).
"""
if not os.path.exists('/etc/cyberpanel/mysqlPassword'):
print("FATAL: Cannot find MySQL root password file at /etc/cyberpanel/mysqlPassword")
print("Manual intervention required.")
sys.exit(1)
root_password = open('/etc/cyberpanel/mysqlPassword', 'r').read().strip()
def _read_mysql_root_password_file():
raw = open('/etc/cyberpanel/mysqlPassword', 'r').read().strip()
if raw.startswith('{') and raw.rstrip().endswith('}'):
try:
data = json.loads(raw)
for key in ('mysqlpassword', 'mysql_password', 'MYSQL_PASSWORD'):
v = data.get(key)
if v:
return str(v).strip()
except Exception:
pass
return raw
def _collect_integration_password_candidates():
"""Passwords already stored in mail/FTP/DNS configs (same DB user)."""
found = []
def add(pw):
pw = (pw or '').strip()
if pw and pw not in found:
found.append(pw)
patterns = [
('/etc/pure-ftpd/pureftpd-mysql.conf', r'^MYSQLPassword\s+(\S+)'),
('/etc/pure-ftpd/db/mysql.conf', r'^MYSQLPassword\s+(\S+)'),
('/etc/pdns/pdns.conf', r'^gmysql-password=(\S+)'),
('/etc/powerdns/pdns.conf', r'^gmysql-password=(\S+)'),
('/etc/postfix/mysql-virtual_domains.cf', r'^password\s*=\s*(\S+)'),
]
for fpath, pat in patterns:
if not os.path.isfile(fpath):
continue
try:
with open(fpath, 'r') as fh:
for line in fh:
m = re.match(pat, line.strip())
if m:
add(m.group(1))
break
except Exception:
pass
return found
def _try_cyberpanel_connect(pw):
try:
c = mysql.connect(host='localhost', user='cyberpanel', passwd=pw, db='cyberpanel')
c.close()
return True
except Exception:
return False
root_password = _read_mysql_root_password_file()
cyberpanel_password = None
# Try to read existing settings.py to get cyberpanel password
settings_path = '/usr/local/CyberCP/CyberCP/settings.py'
if os.path.exists(settings_path):
try:
with open(settings_path, 'r') as f:
settings_content = f.read()
import re
# Extract cyberpanel database password
db_pattern = r"'default':[^}]*'USER':\s*'cyberpanel'[^}]*'PASSWORD':\s*'([^']+)'"
match = re.search(db_pattern, settings_content, re.DOTALL)
if not match:
db_pattern2 = r'"USER":\s*"cyberpanel"[^}]*"PASSWORD":\s*"([^"]+)"'
match = re.search(db_pattern2, settings_content, re.DOTALL)
if match:
cyberpanel_password = match.group(1)
print("Found existing cyberpanel password in settings.py")
# Test if this password actually works
try:
test_conn = mysql.connect(host='localhost', user='cyberpanel',
passwd=cyberpanel_password, db='cyberpanel')
test_conn.close()
if _try_cyberpanel_connect(cyberpanel_password):
print("Verified cyberpanel database credentials are valid")
except:
print("Found password in settings.py but it doesn't work, will reset")
else:
print("WARNING: Password from settings.py does not authenticate as cyberpanel@localhost.")
cyberpanel_password = None
except Exception as e:
print("Could not extract password from settings.py: %s" % str(e))
# If we couldn't get a working password, we need to reset it
if cyberpanel_password is None:
print("Resetting cyberpanel database user password...")
# Check if we're on Ubuntu or CentOS
# On Ubuntu, cyberpanel uses root password; on CentOS, it uses a separate password
working_pw = None
if cyberpanel_password and _try_cyberpanel_connect(cyberpanel_password):
working_pw = cyberpanel_password
else:
for cand in _collect_integration_password_candidates():
if _try_cyberpanel_connect(cand):
working_pw = cand
print("Recovered working cyberpanel DB password from integration config (FTP/DNS/Postfix).")
break
if working_pw:
cyberpanel_password = working_pw
allow_reset = os.environ.get('CYBERPANEL_ALLOW_DB_CREDENTIAL_RESET', '').strip() in ('1', 'true', 'yes', 'YES', 'TRUE')
if (not cyberpanel_password) or (not _try_cyberpanel_connect(cyberpanel_password)):
if not allow_reset:
print("FATAL: Cannot verify `cyberpanel` database credentials.")
print("CyberPanel upgrade will NOT reset MySQL passwords or drop the `cyberpanel` user (upgrade policy).")
print("Fix DATABASES['default']['PASSWORD'] in /usr/local/CyberCP/CyberCP/settings.py to match MariaDB,")
print("or align Pure-FTPd / PowerDNS / Postfix MySQL config passwords, then re-run the upgrade.")
print("Legacy auto-reset (old behaviour): export CYBERPANEL_ALLOW_DB_CREDENTIAL_RESET=1 and re-run (not recommended).")
sys.exit(1)
print("WARNING: CYBERPANEL_ALLOW_DB_CREDENTIAL_RESET=1 — performing legacy cyberpanel DB user reset...")
if os.path.exists('/etc/lsb-release'):
# Ubuntu - use root password
cyberpanel_password = root_password
reset_to_root = True
else:
# CentOS/others - generate new password
chars = string.ascii_letters + string.digits
cyberpanel_password = ''.join(random.choice(chars) for _ in range(14))
reset_to_root = False
try:
# Connect as root and reset cyberpanel user
conn = mysql.connect(host='localhost', user='root', passwd=root_password)
cursor = conn.cursor()
# Check if cyberpanel database exists
cursor.execute("SHOW DATABASES LIKE 'cyberpanel'")
if not cursor.fetchone():
print("Creating cyberpanel database...")
cursor.execute("CREATE DATABASE IF NOT EXISTS cyberpanel")
# Reset cyberpanel user - drop and recreate to ensure clean state
cursor.execute("DROP USER IF EXISTS 'cyberpanel'@'localhost'")
cursor.execute("CREATE USER 'cyberpanel'@'localhost' IDENTIFIED BY '%s'" % cyberpanel_password)
cursor.execute("GRANT ALL PRIVILEGES ON cyberpanel.* TO 'cyberpanel'@'localhost'")
cursor.execute("FLUSH PRIVILEGES")
conn.close()
if reset_to_root:
print("Reset cyberpanel user password to match root password (Ubuntu style)")
else:
print("Reset cyberpanel user with new generated password (CentOS style)")
# Update all configuration files with the new password
print("Updating all service configuration files with new password...")
update_all_config_files_with_password(cyberpanel_password)
# Restart affected services to pick up new configuration
print("Restarting affected services...")
restart_affected_services()
# Save the password to a temporary file for the upgrade process
temp_pass_file = '/tmp/cyberpanel_recovered_password'
with open(temp_pass_file, 'w') as f:
f.write(cyberpanel_password)
os.chmod(temp_pass_file, 0o600)
print("Saved recovered password to temporary file")
except Exception as e:
print("Failed to reset cyberpanel database user: %s" % str(e))
print("Manual intervention required. Please run:")
print(" mariadb -u root -p")
print(" CREATE DATABASE IF NOT EXISTS cyberpanel;")
print(" GRANT ALL PRIVILEGES ON cyberpanel.* TO 'cyberpanel'@'localhost' IDENTIFIED BY 'your_password';")
print(" FLUSH PRIVILEGES;")
sys.exit(1)
return cyberpanel_password, root_password
# Perform recovery
cyberpanel_password, root_password = recover_database_credentials()
@@ -5368,27 +5409,33 @@ echo $oConfig->Save() ? 'Done' : 'Error';
@staticmethod
def get_available_php_versions():
"""Get list of available PHP versions based on OS"""
# Check for AlmaLinux 9+ first
if os.path.exists('/etc/almalinux-release'):
try:
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
try:
import importlib
import sys
_here = os.path.dirname(os.path.abspath(__file__))
for _root in (
os.path.join(os.path.dirname(_here), 'install'),
'/usr/local/CyberCP/install',
'/usr/local/CyberPanel/install',
):
if os.path.isfile(os.path.join(_root, 'install_utils.py')) and _root not in sys.path:
sys.path.insert(0, _root)
iu = importlib.import_module('install_utils')
if hasattr(iu, 'get_lsphp_install_suffixes'):
php_versions = iu.get_lsphp_install_suffixes()
except Exception:
pass
try:
if os.path.exists('/etc/almalinux-release'):
with open('/etc/almalinux-release', 'r') as f:
content = f.read()
if 'release 9' in content or 'release 10' in content:
Upgrade.stdOut("AlmaLinux 9+ detected - checking available PHP versions", 1)
# AlmaLinux 9+ doesn't have PHP 7.1, 7.2, 7.3
php_versions = ['74', '80', '81', '82', '83', '84', '85']
else:
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
except:
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
else:
# Check other OS versions
os_info = Upgrade.findOperatingSytem()
if os_info in [Ubuntu24, CENTOS8, Debian13]:
php_versions = ['74', '80', '81', '82', '83', '84', '85']
else:
php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
_c = f.read().lower()
if 'release 9' in _c or 'release 10' in _c:
Upgrade.stdOut("AlmaLinux 9+ detected - checking available PHP versions", 1)
except Exception:
pass
# Check availability of each version
available_versions = []
for version in php_versions:
@@ -7278,7 +7325,7 @@ extprocessor proxyApacheBackendSSL {
Upgrade.executioner(command, f'Restart {apache_service}', 1)
# 5. Fix PHP-FPM socket permissions and restart services
for version in ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']:
for version in ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']:
if Upgrade.FindOperatingSytem() in [CENTOS7, CENTOS8, openEuler20, openEuler22]:
php_service = f'php{version.replace(".", "")}-php-fpm'
socket_dir = '/var/run/php-fpm'
@@ -7960,11 +8007,11 @@ RewriteRule ^(.*)$ https://proxyApacheBackendSSL/$1 [P,L]
# Restart PHP-FPM services
if osType in [CENTOS7, CENTOS8, CloudLinux7, CloudLinux8]:
for version in ['54', '55', '56', '70', '71', '72', '73', '74', '80', '81', '82', '83', '84']:
for version in ['54', '55', '56', '70', '71', '72', '73', '74', '80', '81', '82', '83', '84', '85']:
command = f'systemctl restart php{version}-php-fpm'
Upgrade.executioner(command, command, 0, True)
else:
for version in ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']:
for version in ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']:
command = f'systemctl restart php{version}-fpm'
Upgrade.executioner(command, command, 0, True)

View File

@@ -16,7 +16,9 @@ Pre_Upgrade_CentOS7_MySQL() {
systemctl start mariadb 2>/dev/null || systemctl start mysql
mariadb-upgrade --force -uroot -p"$MySQL_Password" 2>/dev/null || mysql_upgrade --force -uroot -p"$MySQL_Password" 2>/dev/null || true
fi
mariadb -uroot -p"$MySQL_Password" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '$MySQL_Password';flush privileges" 2>/dev/null || mysql -uroot -p"$MySQL_Password" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '$MySQL_Password';flush privileges"
# Do not use IDENTIFIED BY here - it re-hashes the root password and can break apps that still use the old hash.
# Privileges only; leave the existing MariaDB root password unchanged.
mariadb -uroot -p"$MySQL_Password" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES" 2>/dev/null || mysql -uroot -p"$MySQL_Password" -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES"
Ensure_MariaDB_Client_No_SSL
}