From c3c968e335fc4f859cc8a0c695f6e8a5025c539e Mon Sep 17 00:00:00 2001 From: usmannasir Date: Sat, 28 Jun 2025 16:52:23 +0500 Subject: [PATCH] add support for ubuntu 24 --- install/install.py | 290 +++++++++-------------- install/installCyberPanel.py | 436 ++++++++++------------------------- install/installHelpers.py | 338 +++++++++++++++++++++++++++ 3 files changed, 567 insertions(+), 497 deletions(-) create mode 100644 install/installHelpers.py diff --git a/install/install.py b/install/install.py index 90bf8fa65..784baface 100644 --- a/install/install.py +++ b/install/install.py @@ -14,6 +14,10 @@ from os.path import * from stat import * import stat import secrets +from installHelpers import (PackageManager, ServiceManager, ConfigFileHandler, + CommandExecutor, PHPInstaller, FileSystemHelper, + DistroHandler, PermissionManager, DownloadHelper, + SSLCertificateHelper) VERSION = '2.4' BUILD = 2 @@ -251,8 +255,10 @@ class preFlightsChecks: ffResult = ffResult.stdout.rstrip('\n') - command = f"DEBIAN_FRONTEND=noninteractive apt-get install linux-modules-extra-{ffResult}" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + # Install kernel modules extra package for quota support + # This is needed for Ubuntu 20.04+ including 24.04 + command = f"DEBIAN_FRONTEND=noninteractive apt-get install -y linux-modules-extra-{ffResult}" + CommandExecutor.execute(command, self.distro, exit_on_error=False) ### @@ -497,7 +503,12 @@ class preFlightsChecks: def checkPythonVersion(self): if sys.version_info[0] == 3: - return 1 + # Ubuntu 24.04 uses Python 3.12, ensure we support it + if sys.version_info[0] == 3 and sys.version_info[1] >= 6: + return 1 + else: + preFlightsChecks.stdOut("Python 3.6 or higher is required") + os._exit(0) else: preFlightsChecks.stdOut("You are running Unsupported python version, please install python 3.x") os._exit(0) @@ -555,6 +566,7 @@ class preFlightsChecks: if self.distro == ubuntu: try: + # This script automatically detects Ubuntu version including 24.04 filename = "enable_lst_debain_repo.sh" command = "wget http://rpms.litespeedtech.com/debian/" + filename preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) @@ -595,13 +607,7 @@ class preFlightsChecks: def install_psmisc(self): self.stdOut("Install psmisc") - - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = "yum -y install psmisc" - else: - command = "DEBIAN_FRONTEND=noninteractive apt-get -y install psmisc" - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + PackageManager.install_packages('psmisc', self.distro, ubuntu, centos, cent8, openeuler, use_shell=True) def download_install_CyberPanel(self, mysqlPassword, mysql): ## @@ -751,59 +757,41 @@ password="%s" command = "usermod -G lscpd,lsadm,nogroup lscpd" preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - command = "find /usr/local/CyberCP -type d -exec chmod 0755 {} \;" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "find /usr/local/CyberCP -type f -exec chmod 0644 {} \;" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chmod -R 755 /usr/local/CyberCP/bin" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + # Set permissions for CyberCP directories and files + CommandExecutor.execute("find /usr/local/CyberCP -type d -exec chmod 0755 {} \;", self.distro) + CommandExecutor.execute("find /usr/local/CyberCP -type f -exec chmod 0644 {} \;", self.distro) + PermissionManager.set_permissions('/usr/local/CyberCP/bin', '755', self.distro, owner='root', group='root') ## change owner - - command = "chown -R root:root /usr/local/CyberCP" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + CommandExecutor.execute("chown -R root:root /usr/local/CyberCP", self.distro) ########### Fix LSCPD + # Set permissions for LSCP directories and files + CommandExecutor.execute("find /usr/local/lscp -type d -exec chmod 0755 {} \;", self.distro) + CommandExecutor.execute("find /usr/local/lscp -type f -exec chmod 0644 {} \;", self.distro) + + # Set specific directory permissions + permission_list = [ + {'path': '/usr/local/lscp/bin', 'mode': '755'}, + {'path': '/usr/local/lscp/fcgi-bin', 'mode': '755'} + ] + PermissionManager.batch_set_permissions(permission_list, self.distro) + + # Set ownership + PermissionManager.set_permissions('/usr/local/CyberCP/public/phpmyadmin/tmp', '755', self.distro, + owner='lscpd', group='lscpd') + CommandExecutor.execute("chown -R root:root /usr/local/lscp", self.distro) + PermissionManager.set_permissions('/usr/local/lscp/cyberpanel/rainloop', '755', self.distro, + owner='lscpd', group='lscpd') - command = "find /usr/local/lscp -type d -exec chmod 0755 {} \;" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "find /usr/local/lscp -type f -exec chmod 0644 {} \;" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chmod -R 755 /usr/local/lscp/bin" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chmod -R 755 /usr/local/lscp/fcgi-bin" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin/tmp" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ## change owner - - command = "chown -R root:root /usr/local/lscp" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/rainloop" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chmod 700 /usr/local/CyberCP/cli/cyberPanel.py" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chmod 700 /usr/local/CyberCP/plogical/upgradeCritical.py" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chmod 755 /usr/local/CyberCP/postfixSenderPolicy/client.py" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chmod 640 /usr/local/CyberCP/CyberCP/settings.py" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "chown root:cyberpanel /usr/local/CyberCP/CyberCP/settings.py" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + # Set specific file permissions + specific_permissions = [ + {'path': '/usr/local/CyberCP/cli/cyberPanel.py', 'mode': '700'}, + {'path': '/usr/local/CyberCP/plogical/upgradeCritical.py', 'mode': '700'}, + {'path': '/usr/local/CyberCP/postfixSenderPolicy/client.py', 'mode': '755'}, + {'path': '/usr/local/CyberCP/CyberCP/settings.py', 'mode': '640', 'owner': 'root', 'group': 'cyberpanel'} + ] + PermissionManager.batch_set_permissions(specific_permissions, self.distro) files = ['/etc/yum.repos.d/MariaDB.repo', '/etc/pdns/pdns.conf', '/etc/systemd/system/lscpd.service', '/etc/pure-ftpd/pure-ftpd.conf', '/etc/pure-ftpd/pureftpd-pgsql.conf', @@ -1428,45 +1416,30 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; ## - command = 'chmod o= /etc/dovecot/dovecot-sql.conf.ext' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + PermissionManager.set_permissions('/etc/dovecot/dovecot-sql.conf.ext', 'o=', self.distro) ################################### Restart dovecot - - command = 'systemctl enable dovecot.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ## - - command = 'systemctl start dovecot.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ## - - command = 'systemctl restart postfix.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + ServiceManager.enable_service('dovecot.service', self.distro) + ServiceManager.start_service('dovecot.service', self.distro) + ServiceManager.restart_service('postfix.service', self.distro) ## chaging permissions for main.cf - - command = "chmod 755 " + main - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + PermissionManager.set_permissions(main, '755', self.distro) if self.distro == ubuntu: - command = "mkdir -p /etc/pki/dovecot/private/" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + # Create required directories + for directory in ['/etc/pki/dovecot/private/', '/etc/pki/dovecot/certs/', '/etc/opendkim/keys/']: + CommandExecutor.execute(f"mkdir -p {directory}", self.distro) - command = "mkdir -p /etc/pki/dovecot/certs/" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + ConfigFileHandler.sed_replace('/etc/dovecot/conf.d/10-auth.conf', + 'auth_mechanisms = plain', + '#auth_mechanisms = plain', + self.distro) - command = "mkdir -p /etc/opendkim/keys/" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "sed -i 's/auth_mechanisms = plain/#auth_mechanisms = plain/g' /etc/dovecot/conf.d/10-auth.conf" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ## Ubuntu 18.10 ssl_dh for dovecot 2.3.2.1 - - if get_Ubuntu_release() == 18.10: + ## Ubuntu version-specific ssl_dh for dovecot + ubuntu_version = get_Ubuntu_release() + + if ubuntu_version == 18.10: dovecotConf = '/etc/dovecot/dovecot.conf' data = open(dovecotConf, 'r').readlines() @@ -1705,19 +1678,11 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; ###### if self.distro == centos: # Not available in ubuntu - command = 'systemctl restart dbus' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + ServiceManager.restart_service('dbus', self.distro) - command = 'systemctl restart systemd-logind' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = 'systemctl start firewalld' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ########## - - command = 'systemctl enable firewalld' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + ServiceManager.restart_service('systemd-logind', self.distro) + ServiceManager.start_service('firewalld', self.distro) + ServiceManager.enable_service('firewalld', self.distro) FirewallUtilities.addRule("tcp", "8090") FirewallUtilities.addRule("tcp", "7080") @@ -2074,27 +2039,20 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; try: ## first install crontab - - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'yum install cronie -y' + # Determine package and service names based on distribution + if DistroHandler.is_rhel_based(self.distro): + cron_package = 'cronie' + cron_service = 'crond' else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install cron' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) - - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'systemctl enable crond' - else: - command = 'systemctl enable cron' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'systemctl start crond' - else: - command = 'systemctl start cron' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + cron_package = 'cron' + cron_service = 'cron' + + # Install cron package + PackageManager.install_packages(cron_package, self.distro, ubuntu, centos, cent8, openeuler, use_shell=True) + + # Enable and start cron service + ServiceManager.enable_service(cron_service, self.distro) + ServiceManager.start_service(cron_service, self.distro) ## @@ -2149,15 +2107,11 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; writeToFile.close() if not os.path.exists(CentOSPath) or not os.path.exists(openEulerPath): - command = 'chmod 600 %s' % (cronPath) - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + PermissionManager.set_permissions(cronPath, '600', self.distro) - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'systemctl restart crond.service' - else: - command = 'systemctl restart cron.service' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + # Restart cron service + cron_service = 'crond.service' if DistroHandler.is_rhel_based(self.distro) else 'cron.service' + ServiceManager.restart_service(cron_service, self.distro) except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [setup_cron]") @@ -2166,12 +2120,9 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; def install_default_keys(self): try: path = "/root/.ssh" + FileSystemHelper.create_directory(path) - if not os.path.exists(path): - os.mkdir(path) - - command = "ssh-keygen -f /root/.ssh/cyberpanel -t rsa -N ''" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + CommandExecutor.execute("ssh-keygen -f /root/.ssh/cyberpanel -t rsa -N ''", self.distro) except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [install_default_keys]") @@ -2179,13 +2130,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; def install_rsync(self): try: - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'yum -y install rsync' - else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install rsync' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) - + PackageManager.install_packages('rsync', self.distro, ubuntu, centos, cent8, openeuler, use_shell=True) except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [install_rsync]") return 0 @@ -2306,17 +2251,9 @@ milter_default_action = accept writeToFile.close() #### Restarting Postfix and OpenDKIM - - command = "systemctl start opendkim" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "systemctl enable opendkim" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ## - - command = "systemctl start postfix" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + ServiceManager.start_service('opendkim', self.distro) + ServiceManager.enable_service('opendkim', self.distro) + ServiceManager.start_service('postfix', self.distro) except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [configureOpenDKIM]") @@ -2380,12 +2317,12 @@ milter_default_action = accept @staticmethod def installOne(package): - res = subprocess.call(shlex.split('DEBIAN_FRONTEND=noninteractive apt-get -y install ' + package)) + # This method is only used for Ubuntu/Debian systems + command = f'DEBIAN_FRONTEND=noninteractive apt-get -y install {package}' + res = subprocess.call(shlex.split(command)) if res != 0: - preFlightsChecks.stdOut("Error #" + str(res) + ' installing:' + package + '. This may not be an issue ' \ - 'but may affect installation of something later', - 1) - + preFlightsChecks.stdOut(f"Error #{res} installing: {package}. This may not be an issue " + "but may affect installation of something later", 1) return res # Though probably not used @staticmethod @@ -2583,40 +2520,27 @@ vmail preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) def installRedis(self): - if self.distro == ubuntu: - command = 'apt install redis-server -y' - elif self.distro == centos: - command = 'yum install redis -y' - else: - command = 'dnf install redis -y' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + # Install Redis package (different name on Ubuntu) + redis_package = 'redis-server' if self.distro == ubuntu else 'redis' + PackageManager.install_packages(redis_package, self.distro, ubuntu, centos, cent8, openeuler) ## install redis conf - redisConf = '/usr/local/lsws/conf/dvhost_redis.conf' + with open(redisConf, 'w') as writeToFile: + writeToFile.write('127.0.0.1,6379,\n') - writeToFile = open(redisConf, 'w') - writeToFile.write('127.0.0.1,6379,\n') - writeToFile.close() - - ## - + ## Copy configuration os.chdir(self.cwd) - confPath = '/usr/local/lsws/conf/' - - if os.path.exists('%shttpd.conf' % (confPath)): - os.remove('%shttpd.conf' % (confPath)) - - shutil.copy('litespeed/httpd-redis.conf', '%shttpd.conf' % (confPath)) + httpd_conf = f'{confPath}httpd.conf' + + if os.path.exists(httpd_conf): + os.remove(httpd_conf) + shutil.copy('litespeed/httpd-redis.conf', httpd_conf) ## start and enable - - command = 'systemctl start redis' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = 'systemctl enable redis' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + ServiceManager.start_service('redis', self.distro) + ServiceManager.enable_service('redis', self.distro) def disablePackegeUpdates(self): if self.distro == centos: diff --git a/install/installCyberPanel.py b/install/installCyberPanel.py index c9cd42af7..14dddedf4 100644 --- a/install/installCyberPanel.py +++ b/install/installCyberPanel.py @@ -9,6 +9,7 @@ import MySQLdb as mariadb import install from os.path import exists import time +from installHelpers import PackageManager, ServiceManager, ConfigFileHandler, CommandExecutor, PHPInstaller, FileSystemHelper # distros centos = 0 @@ -113,27 +114,18 @@ class InstallCyberPanel: def installLiteSpeed(self): if self.ent == 0: - if self.distro == ubuntu: - command = "DEBIAN_FRONTEND=noninteractive apt-get -y install openlitespeed" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - elif self.distro == centos: - command = 'yum install -y openlitespeed' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - else: - command = 'dnf install -y openlitespeed' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + PackageManager.install_packages('openlitespeed', self.distro, ubuntu, centos, cent8, openeuler, + use_shell=(self.distro == ubuntu)) else: try: try: - command = 'groupadd nobody' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + CommandExecutor.execute('groupadd nobody', self.distro, exit_on_error=False) except: pass try: - command = 'usermod -a -G nobody nobody' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + CommandExecutor.execute('usermod -a -G nobody nobody', self.distro, exit_on_error=False) except: pass @@ -142,20 +134,20 @@ class InstallCyberPanel: else: command = 'wget https://www.litespeedtech.com/packages/6.0/lsws-6.2-ent-x86_64-linux.tar.gz' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + CommandExecutor.execute(command, self.distro) if InstallCyberPanel.ISARM(): command = 'tar zxf lsws-6.2-ent-aarch64-linux.tar.gz' else: command = 'tar zxf lsws-6.2-ent-x86_64-linux.tar.gz' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + CommandExecutor.execute(command, self.distro) if str.lower(self.serial) == 'trial': command = 'wget -q --output-document=lsws-6.2/trial.key http://license.litespeedtech.com/reseller/trial.key' if self.serial == '1111-2222-3333-4444': command = 'wget -q --output-document=/root/cyberpanel/install/lsws-6.2/trial.key http://license.litespeedtech.com/reseller/trial.key' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + CommandExecutor.execute(command, self.distro) else: writeSerial = open('lsws-6.2/serial.no', 'w') writeSerial.writelines(self.serial) @@ -166,14 +158,9 @@ class InstallCyberPanel: os.chdir('lsws-6.2') - command = 'chmod +x install.sh' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'chmod +x functions.sh' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = './install.sh' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + CommandExecutor.execute('chmod +x install.sh', self.distro) + CommandExecutor.execute('chmod +x functions.sh', self.distro) + CommandExecutor.execute('./install.sh', self.distro) os.chdir(self.cwd) confPath = '/usr/local/lsws/conf/' @@ -181,8 +168,7 @@ class InstallCyberPanel: shutil.copy('litespeed/modsec.conf', confPath) shutil.copy('litespeed/httpd.conf', confPath) - command = 'chown -R lsadm:lsadm ' + confPath - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + CommandExecutor.execute('chown -R lsadm:lsadm ' + confPath, self.distro, exit_on_error=False) except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [installLiteSpeed]") @@ -192,26 +178,20 @@ class InstallCyberPanel: def reStartLiteSpeed(self): command = self.server_root_path + "bin/lswsctrl restart" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + CommandExecutor.execute(command, self.distro, exit_on_error=False) def fix_ols_configs(self): try: - InstallCyberPanel.stdOut("Fixing OpenLiteSpeed configurations!", 1) ## remove example virtual host + config_path = self.server_root_path + "conf/httpd_config.conf" + data = open(config_path, 'r').readlines() - data = open(self.server_root_path + "conf/httpd_config.conf", 'r').readlines() - - writeDataToFile = open(self.server_root_path + "conf/httpd_config.conf", 'w') - - for items in data: - if items.find("map") > -1 and items.find("Example") > -1: - continue - else: - writeDataToFile.writelines(items) - - writeDataToFile.close() + with open(config_path, 'w') as writeDataToFile: + for items in data: + if not (items.find("map") > -1 and items.find("Example") > -1): + writeDataToFile.writelines(items) InstallCyberPanel.stdOut("OpenLiteSpeed Configurations fixed!", 1) except IOError as msg: @@ -224,17 +204,11 @@ class InstallCyberPanel: try: InstallCyberPanel.stdOut("Changing default port to 80..", 1) - data = open(self.server_root_path + "conf/httpd_config.conf").readlines() - - writeDataToFile = open(self.server_root_path + "conf/httpd_config.conf", 'w') - - for items in data: - if (items.find("*:8088") > -1): - writeDataToFile.writelines(items.replace("*:8088", "*:80")) - else: - writeDataToFile.writelines(items) - - writeDataToFile.close() + config_path = self.server_root_path + "conf/httpd_config.conf" + replacements = [("*:8088", "*:80")] + + # Use sed for simple replacement + ConfigFileHandler.sed_replace(config_path, "*:8088", "*:80", self.distro) InstallCyberPanel.stdOut("Default port is now 80 for OpenLiteSpeed!", 1) @@ -245,95 +219,33 @@ class InstallCyberPanel: return self.reStartLiteSpeed() def installAllPHPVersions(self): - if self.distro == ubuntu: - 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) - - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp80*' - os.system(command) - - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp81*' - os.system(command) - - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp82*' - os.system(command) - - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp83*' - os.system(command) - - elif self.distro == centos: - command = 'yum -y groupinstall lsphp-all' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - InstallCyberPanel.stdOut("LiteSpeed PHPs successfully installed!", 1) - - ## only php 71 - if self.distro == centos: - command = 'yum install -y lsphp71* --skip-broken' - - subprocess.call(command, shell=True) - - ## only php 72 - command = 'yum install -y lsphp72* --skip-broken' - - subprocess.call(command, shell=True) - - ## only php 73 - command = 'yum install -y lsphp73* --skip-broken' - - subprocess.call(command, shell=True) - - ## only php 74 - command = 'yum install -y lsphp74* --skip-broken' - - subprocess.call(command, shell=True) - - command = 'yum install lsphp80* -y --skip-broken' - subprocess.call(command, shell=True) - - command = 'yum install lsphp81* -y --skip-broken' - subprocess.call(command, shell=True) - - command = 'yum install lsphp82* -y --skip-broken' - subprocess.call(command, shell=True) - - command = 'yum install lsphp83* -y --skip-broken' - subprocess.call(command, shell=True) - - if self.distro == cent8: - command = 'dnf install lsphp71* lsphp72* lsphp73* lsphp74* lsphp80* --exclude lsphp73-pecl-zip --exclude *imagick* -y --skip-broken' - subprocess.call(command, shell=True) - - command = 'dnf install lsphp81* lsphp82* lsphp83* --exclude *imagick* -y --skip-broken' - subprocess.call(command, shell=True) + PHPInstaller.install_php_ubuntu() + else: + PHPInstaller.install_php_centos(self.distro, centos, cent8, openeuler) - if self.distro == openeuler: - command = 'dnf install lsphp71* lsphp72* lsphp73* lsphp74* lsphp80* lsphp81* lsphp82* lsphp83* -y' - subprocess.call(command, shell=True) + InstallCyberPanel.stdOut("LiteSpeed PHPs successfully installed!", 1) def installMySQL(self, mysql): ############## Install mariadb ###################### if self.distro == ubuntu: - - command = 'DEBIAN_FRONTEND=noninteractive apt-get install software-properties-common -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - - command = "DEBIAN_FRONTEND=noninteractive apt-get install apt-transport-https curl -y" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - - command = "mkdir -p /etc/apt/keyrings" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = "curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp'" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + PackageManager.install_packages('software-properties-common', self.distro, ubuntu, centos, cent8, openeuler, use_shell=True) + PackageManager.install_packages('apt-transport-https curl', self.distro, ubuntu, centos, cent8, openeuler, use_shell=True) + + FileSystemHelper.create_directory('/etc/apt/keyrings') + CommandExecutor.execute("curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp'", self.distro) RepoPath = '/etc/apt/sources.list.d/mariadb.sources' + # Determine the Ubuntu codename for MariaDB repo + ubuntu_version = get_Ubuntu_release() + if ubuntu_version >= 24.04: + suite = 'noble' # Ubuntu 24.04 LTS + elif ubuntu_version >= 22.04: + suite = 'jammy' # Ubuntu 22.04 LTS + else: + suite = 'focal' # Ubuntu 20.04 LTS and earlier + RepoContent = f""" # MariaDB 10.11 repository list - created 2023-12-11 07:53 UTC # https://mariadb.org/download/ @@ -342,14 +254,15 @@ Types: deb # deb.mariadb.org is a dynamic mirror if your preferred mirror goes offline. See https://mariadb.org/mirrorbits/ for details. # URIs: https://deb.mariadb.org/10.11/ubuntu URIs: https://mirrors.gigenet.com/mariadb/repo/10.11/ubuntu -Suites: jammy +Suites: {suite} Components: main main/debug Signed-By: /etc/apt/keyrings/mariadb-keyring.pgp """ if get_Ubuntu_release() > 21.00: + # Use the MariaDB repository setup script which automatically handles different Ubuntu versions command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=10.11' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + CommandExecutor.execute(command, self.distro, exit_code=os.EX_OSERR) # WriteToFile = open(RepoPath, 'w') # WriteToFile.write(RepoContent) # WriteToFile.close() @@ -385,31 +298,16 @@ gpgcheck=1 if type == 'cl' and version >= 88: - - command = 'yum remove db-governor db-governor-mysql -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - - command = 'yum install governor-mysql -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - - command = '/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=mariadb106' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - + CommandExecutor.execute('yum remove db-governor db-governor-mysql -y', self.distro) + PackageManager.install_packages('governor-mysql', self.distro, ubuntu, centos, cent8, openeuler) + CommandExecutor.execute('/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=mariadb106', self.distro) command = '/usr/share/lve/dbgovernor/mysqlgovernor.py --install --yes' else: - - command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=10.11' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - - command = 'yum remove mariadb* -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - - command = 'sudo dnf -qy module disable mariadb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - - command = 'sudo dnf module reset mariadb -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + CommandExecutor.execute('curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=10.11', self.distro) + CommandExecutor.execute('yum remove mariadb* -y', self.distro) + CommandExecutor.execute('sudo dnf -qy module disable mariadb', self.distro) + CommandExecutor.execute('sudo dnf module reset mariadb -y', self.distro) command = 'dnf install MariaDB-server MariaDB-client MariaDB-backup -y' @@ -434,29 +332,17 @@ gpgcheck=1 install.preFlightsChecks.call(command, self.distro, command, command, 0, 0, os.EX_OSERR) def startMariaDB(self): - if self.remotemysql == 'OFF': ############## Start mariadb ###################### - if self.distro == cent8 or self.distro == ubuntu: - command = 'systemctl start mariadb' - else: - command = "systemctl start mariadb" - - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + ServiceManager.start_service('mariadb', self.distro) ############## Enable mariadb at system startup ###################### - if os.path.exists('/etc/systemd/system/mysqld.service'): os.remove('/etc/systemd/system/mysqld.service') if os.path.exists('/etc/systemd/system/mariadb.service'): os.remove('/etc/systemd/system/mariadb.service') - if self.distro == ubuntu: - command = "systemctl enable mariadb" - else: - command = "systemctl enable mariadb" - - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + ServiceManager.enable_service('mariadb', self.distro) def fixMariaDB(self): self.stdOut("Setup MariaDB so it can support Cyberpanel's needs") @@ -474,16 +360,11 @@ gpgcheck=1 try: fileName = '/etc/mysql/mariadb.conf.d/50-server.cnf' - data = open(fileName, 'r').readlines() - - writeDataToFile = open(fileName, 'w') - for line in data: - writeDataToFile.write(line.replace('utf8mb4', 'utf8')) - writeDataToFile.close() + ConfigFileHandler.sed_replace(fileName, 'utf8mb4', 'utf8', self.distro) except IOError as err: self.stdOut("[ERROR] Error in setting: " + fileName + ": " + str(err), 1, 1, os.EX_OSERR) - os.system('systemctl restart mariadb') + ServiceManager.restart_service('mariadb', self.distro) self.stdOut("MariaDB is now setup so it can support Cyberpanel's needs") @@ -493,45 +374,35 @@ gpgcheck=1 os.system(command) if get_Ubuntu_release() == 18.10: - command = 'wget https://rep.cyberpanel.net/pure-ftpd-common_1.0.47-3_all.deb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'wget https://rep.cyberpanel.net/pure-ftpd-mysql_1.0.47-3_amd64.deb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'dpkg --install --force-confold pure-ftpd-common_1.0.47-3_all.deb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'dpkg --install --force-confold pure-ftpd-mysql_1.0.47-3_amd64.deb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - elif self.distro == centos: - command = "yum install -y pure-ftpd" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - elif self.distro == cent8 or self.distro == openeuler: - command = 'dnf install pure-ftpd -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + urls = [ + 'https://rep.cyberpanel.net/pure-ftpd-common_1.0.47-3_all.deb', + 'https://rep.cyberpanel.net/pure-ftpd-mysql_1.0.47-3_amd64.deb' + ] + packages = [ + 'pure-ftpd-common_1.0.47-3_all.deb', + 'pure-ftpd-mysql_1.0.47-3_amd64.deb' + ] + + for url in urls: + CommandExecutor.execute(f'wget {url}', self.distro) + + for package in packages: + CommandExecutor.execute(f'dpkg --install --force-confold {package}', self.distro) + else: + PackageManager.install_packages('pure-ftpd', self.distro, ubuntu, centos, cent8, openeuler) ####### Install pureftpd to system startup - - command = "systemctl enable " + install.preFlightsChecks.pureFTPDServiceName(self.distro) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + service_name = install.preFlightsChecks.pureFTPDServiceName(self.distro) + ServiceManager.enable_service(service_name, self.distro) ###### FTP Groups and user settings settings - - command = 'groupadd -g 2001 ftpgroup' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'useradd -u 2001 -s /bin/false -d /bin/null -c "pureftpd user" -g ftpgroup ftpuser' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + FileSystemHelper.create_user_and_group('ftpuser', 'ftpgroup', 2001, 2001, + shell='/bin/false', home='/bin/null', distro=self.distro) def startPureFTPD(self): ############## Start pureftpd ###################### - if self.distro == ubuntu: - command = 'systemctl start pure-ftpd-mysql' - else: - command = 'systemctl start pure-ftpd' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + service_name = 'pure-ftpd-mysql' if self.distro == ubuntu else 'pure-ftpd' + ServiceManager.start_service(service_name, self.distro) def installPureFTPDConfigurations(self, mysql): try: @@ -539,10 +410,7 @@ gpgcheck=1 InstallCyberPanel.stdOut("Configuring PureFTPD..", 1) - try: - os.mkdir("/etc/ssl/private") - except: - logging.InstallLog.writeToFile("[ERROR] Could not create directory for FTP SSL") + FileSystemHelper.create_directory("/etc/ssl/private") if (self.distro == centos or self.distro == cent8 or self.distro == openeuler) or ( self.distro == ubuntu and get_Ubuntu_release() == 18.14): @@ -550,7 +418,7 @@ gpgcheck=1 else: command = 'openssl req -x509 -nodes -days 7300 -newkey rsa:2048 -subj "/C=US/ST=Denial/L=Sprinal-ield/O=Dis/CN=www.example.com" -keyout /etc/ssl/private/pure-ftpd.pem -out /etc/ssl/private/pure-ftpd.pem' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + CommandExecutor.execute(command, self.distro, exit_on_error=False) os.chdir(self.cwd) ftpdPath = "/etc/pure-ftpd" @@ -568,37 +436,20 @@ gpgcheck=1 shutil.copytree("pure-ftpd-one", ftpdPath) if self.distro == ubuntu: - try: - os.mkdir('/etc/pure-ftpd/conf') - os.mkdir('/etc/pure-ftpd/auth') - os.mkdir('/etc/pure-ftpd/db') - except OSError as err: - self.stdOut("[ERROR] Error creating extra pure-ftpd directories: " + str(err), ". Should be ok", 1) + for dir_path in ['/etc/pure-ftpd/conf', '/etc/pure-ftpd/auth', '/etc/pure-ftpd/db']: + FileSystemHelper.create_directory(dir_path) - data = open(ftpdPath + "/pureftpd-mysql.conf", "r").readlines() - - writeDataToFile = open(ftpdPath + "/pureftpd-mysql.conf", "w") - - dataWritten = "MYSQLPassword " + InstallCyberPanel.mysqlPassword + '\n' - for items in data: - if items.find("MYSQLPassword") > -1: - writeDataToFile.writelines(dataWritten) - else: - writeDataToFile.writelines(items) - - writeDataToFile.close() + # Update MySQL password in pureftpd config + pureftpd_config = ftpdPath + "/pureftpd-mysql.conf" + replacements = [("MYSQLPassword", "MYSQLPassword " + InstallCyberPanel.mysqlPassword)] + ConfigFileHandler.replace_in_file(pureftpd_config, replacements) ftpConfPath = '/etc/pure-ftpd/pureftpd-mysql.conf' if self.remotemysql == 'ON': - command = "sed -i 's|localhost|%s|g' %s" % (self.mysqlhost, ftpConfPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = "sed -i 's|3306|%s|g' %s" % (self.mysqlport, ftpConfPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = "sed -i 's|MYSQLSocket /var/lib/mysql/mysql.sock||g' %s" % (ftpConfPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + ConfigFileHandler.sed_replace(ftpConfPath, 'localhost', self.mysqlhost, self.distro) + ConfigFileHandler.sed_replace(ftpConfPath, '3306', self.mysqlport, self.distro) + ConfigFileHandler.sed_replace(ftpConfPath, 'MYSQLSocket /var/lib/mysql/mysql.sock', '', self.distro) if self.distro == ubuntu: @@ -608,41 +459,31 @@ gpgcheck=1 else: shutil.copy(ftpdPath + "/pureftpd-mysql.conf", '/etc/pure-ftpd/db/mysql.conf') - command = 'echo 1 > /etc/pure-ftpd/conf/TLS' - subprocess.call(command, shell=True) + # Write configuration values to files + config_values = [ + ('1', '/etc/pure-ftpd/conf/TLS'), + (str(self.publicip), '/etc/pure-ftpd/conf/ForcePassiveIP'), + ('40110 40210', '/etc/pure-ftpd/conf/PassivePortRange'), + ('no', '/etc/pure-ftpd/conf/UnixAuthentication'), + ('/etc/pure-ftpd/db/mysql.conf', '/etc/pure-ftpd/conf/MySQLConfigFile') + ] + + for value, filepath in config_values: + with open(filepath, 'w') as f: + f.write(value) - command = 'echo %s > /etc/pure-ftpd/conf/ForcePassiveIP' % (self.publicip) - subprocess.call(command, shell=True) - - command = 'echo "40110 40210" > /etc/pure-ftpd/conf/PassivePortRange' - subprocess.call(command, shell=True) - - command = 'echo "no" > /etc/pure-ftpd/conf/UnixAuthentication' - subprocess.call(command, shell=True) - - command = 'echo "/etc/pure-ftpd/db/mysql.conf" > /etc/pure-ftpd/conf/MySQLConfigFile' - subprocess.call(command, shell=True) - - command = 'ln -s /etc/pure-ftpd/conf/MySQLConfigFile /etc/pure-ftpd/auth/30mysql' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'ln -s /etc/pure-ftpd/conf/UnixAuthentication /etc/pure-ftpd/auth/65unix' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'systemctl restart pure-ftpd-mysql.service' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + CommandExecutor.execute('ln -s /etc/pure-ftpd/conf/MySQLConfigFile /etc/pure-ftpd/auth/30mysql', self.distro) + CommandExecutor.execute('ln -s /etc/pure-ftpd/conf/UnixAuthentication /etc/pure-ftpd/auth/65unix', self.distro) + ServiceManager.restart_service('pure-ftpd-mysql.service', self.distro) - if get_Ubuntu_release() > 21.00: - ### change mysql md5 to crypt - - command = "sed -i 's/MYSQLCrypt md5/MYSQLCrypt crypt/g' /etc/pure-ftpd/db/mysql.conf" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = "systemctl restart pure-ftpd-mysql.service" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + ubuntu_version = get_Ubuntu_release() + if ubuntu_version > 21.00: + ### change mysql md5 to crypt for Ubuntu 22.04+ including 24.04 + ConfigFileHandler.sed_replace('/etc/pure-ftpd/db/mysql.conf', 'MYSQLCrypt md5', 'MYSQLCrypt crypt', self.distro) + ServiceManager.restart_service('pure-ftpd-mysql.service', self.distro) else: try: @@ -651,8 +492,7 @@ gpgcheck=1 version = int(clAPVersion.split('-')[1]) if type == 'al' and version >= 90: - command = "sed -i 's/MYSQLCrypt md5/MYSQLCrypt crypt/g' /etc/pure-ftpd/pureftpd-mysql.conf" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + ConfigFileHandler.sed_replace('/etc/pure-ftpd/pureftpd-mysql.conf', 'MYSQLCrypt md5', 'MYSQLCrypt crypt', self.distro) except: pass @@ -666,12 +506,9 @@ gpgcheck=1 def installPowerDNS(self): try: - if self.distro == ubuntu or self.distro == cent8 or self.distro == openeuler: - command = 'systemctl stop systemd-resolved' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - command = 'systemctl disable systemd-resolved.service' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + ServiceManager.stop_service('systemd-resolved', self.distro, exit_on_error=False) + ServiceManager.disable_service('systemd-resolved.service', self.distro, exit_on_error=False) try: os.rename('/etc/resolv.conf', 'etc/resolved.conf') @@ -700,9 +537,7 @@ gpgcheck=1 os.system(command) return 1 else: - command = 'yum -y install pdns pdns-backend-mysql' - - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + PackageManager.install_packages('pdns pdns-backend-mysql', self.distro, ubuntu, centos, cent8, openeuler) except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [powerDNS]") @@ -730,29 +565,13 @@ gpgcheck=1 else: shutil.copy("dns-one/pdns.conf", dnsPath) - data = open(dnsPath, "r").readlines() - - writeDataToFile = open(dnsPath, "w") - - dataWritten = "gmysql-password=" + mysqlPassword + "\n" - - for items in data: - if items.find("gmysql-password") > -1: - writeDataToFile.writelines(dataWritten) - else: - writeDataToFile.writelines(items) - - # if self.distro == ubuntu: - # os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR) - - writeDataToFile.close() + # Update MySQL password in PowerDNS config + replacements = [("gmysql-password", "gmysql-password=" + mysqlPassword)] + ConfigFileHandler.replace_in_file(dnsPath, replacements) if self.remotemysql == 'ON': - command = "sed -i 's|gmysql-host=localhost|gmysql-host=%s|g' %s" % (self.mysqlhost, dnsPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = "sed -i 's|gmysql-port=3306|gmysql-port=%s|g' %s" % (self.mysqlport, dnsPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + ConfigFileHandler.sed_replace(dnsPath, 'gmysql-host=localhost', f'gmysql-host={self.mysqlhost}', self.distro) + ConfigFileHandler.sed_replace(dnsPath, 'gmysql-port=3306', f'gmysql-port={self.mysqlport}', self.distro) InstallCyberPanel.stdOut("PowerDNS configured!", 1) @@ -762,14 +581,9 @@ gpgcheck=1 return 1 def startPowerDNS(self): - ############## Start PowerDNS ###################### - - command = 'systemctl enable pdns' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = 'systemctl start pdns' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + ServiceManager.enable_service('pdns', self.distro) + ServiceManager.start_service('pdns', self.distro) def Main(cwd, mysql, distro, ent, serial=None, port="8090", ftp=None, dns=None, publicip=None, remotemysql=None, @@ -801,14 +615,8 @@ def Main(cwd, mysql, distro, ent, serial=None, port="8090", ftp=None, dns=None, time.sleep(10) try: - command = 'chmod 640 %s' % (file_name) - install.preFlightsChecks.call(command, distro, '[chmod]', - '', - 1, 0, os.EX_OSERR) - command = 'chown root:cyberpanel %s' % (file_name) - install.preFlightsChecks.call(command, distro, '[chmod]', - '', - 1, 0, os.EX_OSERR) + CommandExecutor.execute(f'chmod 640 {file_name}', distro, '[chmod]', exit_on_error=False) + CommandExecutor.execute(f'chown root:cyberpanel {file_name}', distro, '[chmod]', exit_on_error=False) except: pass diff --git a/install/installHelpers.py b/install/installHelpers.py new file mode 100644 index 000000000..95dfdfd2c --- /dev/null +++ b/install/installHelpers.py @@ -0,0 +1,338 @@ +import os +import subprocess +import shutil +import install +import logging + + +class PackageManager: + """Handles package installation across different distributions""" + + @staticmethod + def get_install_command(packages, distro, ubuntu=1, centos=0, cent8=2, openeuler=3): + """Returns the appropriate install command for the distribution""" + if distro == ubuntu: + return f"DEBIAN_FRONTEND=noninteractive apt-get -y install {packages}" + elif distro == centos: + return f"yum install -y {packages}" + else: # cent8 or openeuler + return f"dnf install -y {packages}" + + @staticmethod + def install_packages(packages, distro, ubuntu=1, centos=0, cent8=2, openeuler=3, use_shell=False): + """Install packages with proper error handling""" + command = PackageManager.get_install_command(packages, distro, ubuntu, centos, cent8, openeuler) + if use_shell: + install.preFlightsChecks.call(command, distro, command, command, 1, 1, os.EX_OSERR, True) + else: + install.preFlightsChecks.call(command, distro, command, command, 1, 1, os.EX_OSERR) + + +class ServiceManager: + """Handles service operations across different distributions""" + + @staticmethod + def manage_service(service_name, action, distro, exit_on_error=True): + """Manage systemd services (start, stop, enable, disable, restart)""" + command = f"systemctl {action} {service_name}" + error_code = 1 if exit_on_error else 0 + install.preFlightsChecks.call(command, distro, command, command, 1, error_code, os.EX_OSERR) + + @staticmethod + def start_service(service_name, distro): + """Start a service""" + ServiceManager.manage_service(service_name, "start", distro) + + @staticmethod + def stop_service(service_name, distro, exit_on_error=False): + """Stop a service""" + ServiceManager.manage_service(service_name, "stop", distro, exit_on_error) + + @staticmethod + def enable_service(service_name, distro): + """Enable a service at startup""" + ServiceManager.manage_service(service_name, "enable", distro) + + @staticmethod + def disable_service(service_name, distro, exit_on_error=False): + """Disable a service at startup""" + ServiceManager.manage_service(service_name, "disable", distro, exit_on_error) + + @staticmethod + def restart_service(service_name, distro): + """Restart a service""" + ServiceManager.manage_service(service_name, "restart", distro) + + +class ConfigFileHandler: + """Handles configuration file operations""" + + @staticmethod + def replace_in_file(file_path, replacements): + """ + Replace multiple patterns in a file + replacements: list of tuples (search_pattern, replacement) + """ + try: + with open(file_path, 'r') as f: + data = f.readlines() + + with open(file_path, 'w') as f: + for line in data: + modified_line = line + for search_pattern, replacement in replacements: + if search_pattern in line: + modified_line = replacement + '\n' if not replacement.endswith('\n') else replacement + break + f.write(modified_line) + return True + except IOError as e: + logging.InstallLog.writeToFile(f'[ERROR] {str(e)} [ConfigFileHandler.replace_in_file]') + return False + + @staticmethod + def sed_replace(file_path, search, replace, distro): + """Use sed command for replacements""" + command = f"sed -i 's|{search}|{replace}|g' {file_path}" + install.preFlightsChecks.call(command, distro, command, command, 1, 1, os.EX_OSERR) + + @staticmethod + def copy_config_file(source, destination, remove_existing=True): + """Copy configuration file with optional removal of existing file""" + try: + if remove_existing and os.path.exists(destination): + os.remove(destination) + shutil.copy(source, destination) + return True + except Exception as e: + logging.InstallLog.writeToFile(f'[ERROR] {str(e)} [ConfigFileHandler.copy_config_file]') + return False + + +class CommandExecutor: + """Centralized command execution with consistent error handling""" + + @staticmethod + def execute(command, distro, description=None, exit_on_error=True, exit_code=os.EX_OSERR): + """Execute a command with standard error handling""" + if description is None: + description = command + error_flag = 1 if exit_on_error else 0 + install.preFlightsChecks.call(command, distro, description, command, 1, error_flag, exit_code) + + @staticmethod + def execute_with_output(command, shell=True): + """Execute command and return output""" + try: + result = subprocess.run(command, capture_output=True, universal_newlines=True, shell=shell) + except: + result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + universal_newlines=True, shell=shell) + return result + + +class PHPInstaller: + """Handles PHP installation for different versions and distributions""" + + @staticmethod + def install_php_ubuntu(versions=None): + """Install PHP versions on Ubuntu""" + if versions is None: + # Include PHP 8.4 for Ubuntu 24.04 + versions = ['7?', '80', '81', '82', '83', '84'] + + for version in versions: + if version == '7?': + 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' + else: + command = f'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp{version}*' + os.system(command) + + @staticmethod + def install_php_centos(distro, centos=0, cent8=2, openeuler=3): + """Install PHP versions on CentOS/RHEL based systems""" + if distro == centos: + # First install the group + command = 'yum -y groupinstall lsphp-all' + install.preFlightsChecks.call(command, distro, command, command, 1, 1, os.EX_OSERR) + + # Then install individual versions + versions = ['71', '72', '73', '74', '80', '81', '82', '83'] + for version in versions: + command = f'yum install -y lsphp{version}* --skip-broken' + subprocess.call(command, shell=True) + + elif distro == cent8: + command = 'dnf install lsphp71* lsphp72* lsphp73* lsphp74* lsphp80* --exclude lsphp73-pecl-zip --exclude *imagick* -y --skip-broken' + subprocess.call(command, shell=True) + + command = 'dnf install lsphp81* lsphp82* lsphp83* --exclude *imagick* -y --skip-broken' + subprocess.call(command, shell=True) + + elif distro == openeuler: + command = 'dnf install lsphp71* lsphp72* lsphp73* lsphp74* lsphp80* lsphp81* lsphp82* lsphp83* -y' + subprocess.call(command, shell=True) + + +class FileSystemHelper: + """Helper for file system operations""" + + @staticmethod + def create_directory(path, exit_on_error=False): + """Create directory with error handling""" + try: + os.mkdir(path) + return True + except OSError as e: + if exit_on_error: + raise + logging.InstallLog.writeToFile(f"[ERROR] Could not create directory {path}: {str(e)}") + return False + + @staticmethod + def create_user_and_group(user, group, uid, gid, shell="/bin/false", home="/bin/null", distro=None): + """Create system user and group""" + # Create group + command = f'groupadd -g {gid} {group}' + CommandExecutor.execute(command, distro, exit_on_error=True) + + # Create user + command = f'useradd -u {uid} -s {shell} -d {home} -c "{user} user" -g {group} {user}' + CommandExecutor.execute(command, distro, exit_on_error=True) + + +class DistroHandler: + """Handles distribution-specific operations""" + + # Distribution constants + CENTOS = 0 + UBUNTU = 1 + CENT8 = 2 + OPENEULER = 3 + + @staticmethod + def is_rhel_based(distro): + """Check if distribution is RHEL-based""" + return distro in [DistroHandler.CENTOS, DistroHandler.CENT8, DistroHandler.OPENEULER] + + @staticmethod + def is_debian_based(distro): + """Check if distribution is Debian-based""" + return distro == DistroHandler.UBUNTU + + @staticmethod + def get_package_manager(distro): + """Get the package manager for the distribution""" + if distro == DistroHandler.UBUNTU: + return "apt-get" + elif distro == DistroHandler.CENTOS: + return "yum" + else: # CENT8, OPENEULER + return "dnf" + + @staticmethod + def get_service_name(base_service, distro): + """Get distribution-specific service name""" + # Add logic for service name mapping if needed + service_map = { + 'mysql': { + DistroHandler.UBUNTU: 'mysql', + DistroHandler.CENTOS: 'mariadb', + DistroHandler.CENT8: 'mariadb', + DistroHandler.OPENEULER: 'mariadb' + } + } + + if base_service in service_map and distro in service_map[base_service]: + return service_map[base_service][distro] + return base_service + + +class PermissionManager: + """Handles file permissions and ownership""" + + @staticmethod + def set_permissions(path, mode, distro, owner=None, group=None): + """Set file permissions and optionally ownership""" + # Set permissions + CommandExecutor.execute(f'chmod {mode} {path}', distro) + + # Set ownership if specified + if owner or group: + owner_str = owner if owner else "" + group_str = group if group else "" + if owner and group: + ownership = f"{owner}:{group}" + elif owner: + ownership = owner + else: + ownership = f":{group}" + + CommandExecutor.execute(f'chown {ownership} {path}', distro) + + @staticmethod + def batch_set_permissions(permission_list, distro): + """Apply multiple permission changes efficiently""" + for perm in permission_list: + PermissionManager.set_permissions( + perm['path'], + perm['mode'], + distro, + perm.get('owner'), + perm.get('group') + ) + + +class DownloadHelper: + """Helper for downloading and extracting files""" + + @staticmethod + def download_file(url, destination, distro): + """Download a file using wget""" + command = f'wget -O {destination} {url}' if destination else f'wget {url}' + CommandExecutor.execute(command, distro) + + @staticmethod + def extract_archive(archive_path, destination, distro, archive_type='tar'): + """Extract an archive file""" + if archive_type == 'tar': + command = f'tar -xf {archive_path} -C {destination}' + elif archive_type == 'tar.gz': + command = f'tar -xzf {archive_path} -C {destination}' + elif archive_type == 'zip': + command = f'unzip {archive_path} -d {destination}' + else: + raise ValueError(f"Unsupported archive type: {archive_type}") + + CommandExecutor.execute(command, distro) + + @staticmethod + def download_and_extract(url, extract_dir, distro, archive_type='tar.gz'): + """Download and extract in one operation""" + filename = os.path.basename(url) + DownloadHelper.download_file(url, filename, distro) + DownloadHelper.extract_archive(filename, extract_dir, distro, archive_type) + return filename + + +class SSLCertificateHelper: + """Helper for SSL certificate operations""" + + @staticmethod + def generate_self_signed_cert(cert_path, key_path, distro, days=3650, + subject="/C=US/ST=State/L=City/O=Org/CN=localhost"): + """Generate a self-signed SSL certificate""" + command = (f'openssl req -x509 -nodes -days {days} -newkey rsa:2048 ' + f'-subj "{subject}" -keyout {key_path} -out {cert_path}') + CommandExecutor.execute(command, distro) + + @staticmethod + def generate_csr(key_path, csr_path, distro, + subject="/C=US/ST=State/L=City/O=Org/CN=localhost"): + """Generate a certificate signing request""" + command = (f'openssl req -new -key {key_path} -out {csr_path} ' + f'-subj "{subject}"') + CommandExecutor.execute(command, distro) \ No newline at end of file