mirror of
				https://github.com/usmannasir/cyberpanel.git
				synced 2025-10-31 18:36:17 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1158 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1158 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import shutil
 | |
| import subprocess
 | |
| import os
 | |
| from mysqlUtilities import mysqlUtilities
 | |
| import installLog as logging
 | |
| import errno
 | |
| import MySQLdb as mariadb
 | |
| import install
 | |
| from os.path import exists
 | |
| import time
 | |
| import install_utils
 | |
| import urllib.request
 | |
| import re
 | |
| 
 | |
| # distros - using from install_utils
 | |
| centos = install_utils.centos
 | |
| ubuntu = install_utils.ubuntu
 | |
| cent8 = install_utils.cent8
 | |
| openeuler = install_utils.openeuler
 | |
| debian12 = install_utils.debian12
 | |
| 
 | |
| 
 | |
| def get_Ubuntu_release():
 | |
|     return install_utils.get_Ubuntu_release(use_print=True, exit_on_error=True)
 | |
| 
 | |
| 
 | |
| def get_Ubuntu_code_name():
 | |
|     """Get Ubuntu codename based on version"""
 | |
|     release = get_Ubuntu_release()
 | |
|     if release >= 24.04:
 | |
|         return "noble"
 | |
|     elif release >= 22.04:
 | |
|         return "jammy"
 | |
|     elif release >= 20.04:
 | |
|         return "focal"
 | |
|     elif release >= 18.04:
 | |
|         return "bionic"
 | |
|     else:
 | |
|         return "xenial"
 | |
| 
 | |
| 
 | |
| # Using shared function from install_utils
 | |
| FetchCloudLinuxAlmaVersionVersion = install_utils.FetchCloudLinuxAlmaVersionVersion
 | |
| 
 | |
| class InstallCyberPanel:
 | |
|     mysql_Root_password = ""
 | |
|     mysqlPassword = ""
 | |
|     
 | |
|     def is_almalinux9(self):
 | |
|         """Check if running on AlmaLinux 9"""
 | |
|         if os.path.exists('/etc/almalinux-release'):
 | |
|             try:
 | |
|                 with open('/etc/almalinux-release', 'r') as f:
 | |
|                     content = f.read()
 | |
|                     return 'release 9' in content
 | |
|             except:
 | |
|                 return False
 | |
|         return False
 | |
|     
 | |
|     def fix_almalinux9_mariadb(self):
 | |
|         """Fix AlmaLinux 9 MariaDB installation issues"""
 | |
|         if not self.is_almalinux9():
 | |
|             return
 | |
|         
 | |
|         self.stdOut("Applying AlmaLinux 9 MariaDB fixes...", 1)
 | |
|         
 | |
|         try:
 | |
|             # Disable problematic MariaDB MaxScale repository
 | |
|             self.stdOut("Disabling problematic MariaDB MaxScale repository...", 1)
 | |
|             command = "dnf config-manager --disable mariadb-maxscale 2>/dev/null || true"
 | |
|             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|             
 | |
|             # Remove problematic repository files
 | |
|             self.stdOut("Removing problematic repository files...", 1)
 | |
|             problematic_repos = [
 | |
|                 '/etc/yum.repos.d/mariadb-maxscale.repo',
 | |
|                 '/etc/yum.repos.d/mariadb-maxscale.repo.rpmnew'
 | |
|             ]
 | |
|             for repo_file in problematic_repos:
 | |
|                 if os.path.exists(repo_file):
 | |
|                     os.remove(repo_file)
 | |
|                     self.stdOut(f"Removed {repo_file}", 1)
 | |
|             
 | |
|             # Clean DNF cache
 | |
|             self.stdOut("Cleaning DNF cache...", 1)
 | |
|             command = "dnf clean all"
 | |
|             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|             
 | |
|             # Install MariaDB from official repository
 | |
|             self.stdOut("Setting up official MariaDB repository...", 1)
 | |
|             command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='10.11'"
 | |
|             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|             
 | |
|             # Install MariaDB packages
 | |
|             self.stdOut("Installing MariaDB packages...", 1)
 | |
|             mariadb_packages = "MariaDB-server MariaDB-client MariaDB-backup MariaDB-devel"
 | |
|             command = f"dnf install -y {mariadb_packages}"
 | |
|             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|             
 | |
|             self.stdOut("AlmaLinux 9 MariaDB fixes completed", 1)
 | |
|             
 | |
|         except Exception as e:
 | |
|             self.stdOut(f"Error applying AlmaLinux 9 MariaDB fixes: {str(e)}", 0)
 | |
|     CloudLinux8 = 0
 | |
| 
 | |
|     def install_package(self, package_name, options=""):
 | |
|         """Unified package installation across distributions"""
 | |
|         command, shell = install_utils.get_package_install_command(self.distro, package_name, options)
 | |
|         
 | |
|         # InstallCyberPanel always uses verbose mode (no silent option)
 | |
|         if self.distro == ubuntu or self.distro == debian12:
 | |
|             return install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, shell)
 | |
|         else:
 | |
|             # For non-Ubuntu/Debian, original code didn't pass shell parameter
 | |
|             return install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|     def manage_service(self, service_name, action="start"):
 | |
|         """Unified service management"""
 | |
|         service_map = {
 | |
|             'mariadb': 'mariadb',
 | |
|             'pureftpd': 'pure-ftpd-mysql' if self.distro == ubuntu else 'pure-ftpd',
 | |
|             'pdns': 'pdns-server' if self.distro == debian12 else 'pdns'
 | |
|         }
 | |
|         
 | |
|         actual_service = service_map.get(service_name, service_name)
 | |
|         
 | |
|         # For AlmaLinux 9, try both mariadb and mysqld services
 | |
|         if service_name == 'mariadb' and (self.distro == cent8 or self.distro == openeuler):
 | |
|             # Try mariadb first, then mysqld if mariadb fails
 | |
|             command = f'systemctl {action} {actual_service}'
 | |
|             result = install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|             if result != 0:
 | |
|                 # If mariadb service fails, try mysqld
 | |
|                 command = f'systemctl {action} mysqld'
 | |
|                 return install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
|             return result
 | |
|         else:
 | |
|             command = f'systemctl {action} {actual_service}'
 | |
|             return install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|     def modify_file_content(self, file_path, replacements):
 | |
|         """Generic file content modification"""
 | |
|         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 old, new in replacements.items():
 | |
|                         if old in line:
 | |
|                             modified_line = line.replace(old, new)
 | |
|                             break
 | |
|                     f.write(modified_line)
 | |
|             return True
 | |
|         except IOError as e:
 | |
|             logging.InstallLog.writeToFile(f'[ERROR] {str(e)} [modify_file_content]')
 | |
|             return False
 | |
| 
 | |
|     def copy_config_file(self, source_dir, dest_path, mysql_mode='One'):
 | |
|         """Handle configuration file copying with mode selection"""
 | |
|         # For directories like 'dns' vs 'dns-one', 'pure-ftpd' vs 'pure-ftpd-one'
 | |
|         # Default mode is 'One' which uses the -one directories
 | |
|         if mysql_mode == 'Two':
 | |
|             source_path = source_dir
 | |
|         else:
 | |
|             # Default mode 'One' uses directories with -one suffix
 | |
|             source_path = f"{source_dir}-one"
 | |
|         
 | |
|         # Ensure we're working with absolute paths
 | |
|         if not os.path.isabs(source_path):
 | |
|             source_path = os.path.join(self.cwd, source_path)
 | |
|         
 | |
|         # Determine the actual file to copy
 | |
|         if os.path.isdir(source_path):
 | |
|             # If dest_path is a file (like pdns.conf), copy the specific file
 | |
|             if dest_path.endswith('.conf'):
 | |
|                 # Look for the specific config file
 | |
|                 source_file = os.path.join(source_path, os.path.basename(dest_path))
 | |
|                 if os.path.exists(source_file):
 | |
|                     if os.path.exists(dest_path):
 | |
|                         os.remove(dest_path)
 | |
|                     shutil.copy(source_file, dest_path)
 | |
|                 else:
 | |
|                     raise IOError(f"Source file {source_file} not found")
 | |
|             else:
 | |
|                 # If it's a directory, copy the whole directory
 | |
|                 if os.path.exists(dest_path):
 | |
|                     if os.path.isdir(dest_path):
 | |
|                         shutil.rmtree(dest_path)
 | |
|                 shutil.copytree(source_path, dest_path)
 | |
|         else:
 | |
|             raise IOError(f"Source path {source_path} not found")
 | |
| 
 | |
|     @staticmethod
 | |
|     def ISARM():
 | |
| 
 | |
|         try:
 | |
|             command = 'uname -a'
 | |
|             try:
 | |
|                 result = subprocess.run(command, capture_output=True, universal_newlines=True, shell=True)
 | |
|             except:
 | |
|                 result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
 | |
| 
 | |
|             if 'aarch64' in result.stdout:
 | |
|                 return True
 | |
|             else:
 | |
|                 return False
 | |
|         except:
 | |
|             return False
 | |
| 
 | |
|     @staticmethod
 | |
|     def OSFlags():
 | |
|         if os.path.exists("/etc/redhat-release"):
 | |
|             data = open('/etc/redhat-release', 'r').read()
 | |
| 
 | |
|             if data.find('CloudLinux 8') > -1 or data.find('cloudlinux 8') > -1:
 | |
|                 InstallCyberPanel.CloudLinux8 = 1
 | |
| 
 | |
|     def __init__(self, rootPath, cwd, distro, ent, serial=None, port=None, ftp=None, dns=None, publicip=None,
 | |
|                  remotemysql=None, mysqlhost=None, mysqldb=None, mysqluser=None, mysqlpassword=None, mysqlport=None):
 | |
|         self.server_root_path = rootPath
 | |
|         self.cwd = cwd
 | |
|         self.distro = distro
 | |
|         self.ent = ent
 | |
|         self.serial = serial
 | |
|         self.port = port
 | |
|         self.ftp = None
 | |
|         self.dns = dns
 | |
|         self.publicip = publicip
 | |
|         self.remotemysql = remotemysql
 | |
|         self.mysqlhost = mysqlhost
 | |
|         self.mysqluser = mysqluser
 | |
|         self.mysqlpassword = mysqlpassword
 | |
|         self.mysqlport = mysqlport
 | |
|         self.mysqldb = mysqldb
 | |
| 
 | |
|         ## TURN ON OS FLAGS FOR SPECIFIC NEEDS LATER
 | |
| 
 | |
|         InstallCyberPanel.OSFlags()
 | |
| 
 | |
|     @staticmethod
 | |
|     def stdOut(message, log=0, exit=0, code=os.EX_OK):
 | |
|         install_utils.stdOut(message, log, exit, code)
 | |
| 
 | |
|     @staticmethod
 | |
|     def getLatestLSWSVersion():
 | |
|         """Fetch the latest LSWS Enterprise version from LiteSpeed's website"""
 | |
|         try:
 | |
|             # Try to fetch from the download page
 | |
|             url = "https://www.litespeedtech.com/products/litespeed-web-server/download"
 | |
|             req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
 | |
|             with urllib.request.urlopen(req, timeout=10) as response:
 | |
|                 html = response.read().decode('utf-8')
 | |
| 
 | |
|             # Look for the latest version pattern: lsws-X.Y.Z-ent
 | |
|             version_pattern = r'lsws-(\d+\.\d+\.\d+)-ent'
 | |
|             versions = re.findall(version_pattern, html)
 | |
| 
 | |
|             if versions:
 | |
|                 # Get the latest version
 | |
|                 latest_version = sorted(versions, key=lambda v: [int(x) for x in v.split('.')])[-1]
 | |
|                 InstallCyberPanel.stdOut(f"Found latest LSWS Enterprise version: {latest_version}", 1)
 | |
|                 return latest_version
 | |
|             else:
 | |
|                 InstallCyberPanel.stdOut("Could not find version pattern in HTML, using fallback", 1)
 | |
| 
 | |
|         except Exception as e:
 | |
|             InstallCyberPanel.stdOut(f"Failed to fetch latest LSWS version: {str(e)}, using fallback", 1)
 | |
| 
 | |
|         # Fallback to known latest version
 | |
|         return "6.3.4"
 | |
| 
 | |
|     def installLiteSpeed(self):
 | |
|         if self.ent == 0:
 | |
|             self.install_package('openlitespeed')
 | |
| 
 | |
|         else:
 | |
|             try:
 | |
|                 try:
 | |
|                     command = 'groupadd nobody'
 | |
|                     install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|                 except:
 | |
|                     pass
 | |
| 
 | |
|                 try:
 | |
|                     command = 'usermod -a -G nobody nobody'
 | |
|                     install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|                 except:
 | |
|                     pass
 | |
| 
 | |
|                 # Get the latest LSWS Enterprise version dynamically
 | |
|                 lsws_version = InstallCyberPanel.getLatestLSWSVersion()
 | |
| 
 | |
|                 if InstallCyberPanel.ISARM():
 | |
|                     command = f'wget https://www.litespeedtech.com/packages/6.0/lsws-{lsws_version}-ent-aarch64-linux.tar.gz'
 | |
|                 else:
 | |
|                     command = f'wget https://www.litespeedtech.com/packages/6.0/lsws-{lsws_version}-ent-x86_64-linux.tar.gz'
 | |
| 
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|                 if InstallCyberPanel.ISARM():
 | |
|                     command = f'tar zxf lsws-{lsws_version}-ent-aarch64-linux.tar.gz'
 | |
|                 else:
 | |
|                     command = f'tar zxf lsws-{lsws_version}-ent-x86_64-linux.tar.gz'
 | |
| 
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|                 if str.lower(self.serial) == 'trial':
 | |
|                     command = f'wget -q --output-document=lsws-{lsws_version}/trial.key http://license.litespeedtech.com/reseller/trial.key'
 | |
|                 if self.serial == '1111-2222-3333-4444':
 | |
|                     command = f'wget -q --output-document=/root/cyberpanel/install/lsws-{lsws_version}/trial.key http://license.litespeedtech.com/reseller/trial.key'
 | |
|                     install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
|                 else:
 | |
|                     writeSerial = open(f'lsws-{lsws_version}/serial.no', 'w')
 | |
|                     writeSerial.writelines(self.serial)
 | |
|                     writeSerial.close()
 | |
| 
 | |
|                 shutil.copy('litespeed/install.sh', f'lsws-{lsws_version}/')
 | |
|                 shutil.copy('litespeed/functions.sh', f'lsws-{lsws_version}/')
 | |
| 
 | |
|                 os.chdir(f'lsws-{lsws_version}')
 | |
| 
 | |
|                 command = 'chmod +x install.sh'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|                 command = 'chmod +x functions.sh'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|                 command = './install.sh'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|                 os.chdir(self.cwd)
 | |
|                 confPath = '/usr/local/lsws/conf/'
 | |
|                 shutil.copy('litespeed/httpd_config.xml', confPath)
 | |
|                 shutil.copy('litespeed/modsec.conf', confPath)
 | |
|                 shutil.copy('litespeed/httpd.conf', confPath)
 | |
| 
 | |
|                 command = 'chown -R lsadm:lsadm ' + confPath
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
| 
 | |
|             except BaseException as msg:
 | |
|                 logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [installLiteSpeed]")
 | |
|                 return 0
 | |
| 
 | |
|             return 1
 | |
| 
 | |
|     def reStartLiteSpeed(self):
 | |
|         command = install_utils.format_restart_litespeed_command(self.server_root_path)
 | |
|         install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
| 
 | |
|     def fix_ols_configs(self):
 | |
|         try:
 | |
| 
 | |
|             InstallCyberPanel.stdOut("Fixing OpenLiteSpeed configurations!", 1)
 | |
| 
 | |
|             ## remove example virtual host
 | |
| 
 | |
|             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()
 | |
| 
 | |
|             InstallCyberPanel.stdOut("OpenLiteSpeed Configurations fixed!", 1)
 | |
|         except IOError as msg:
 | |
|             logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [fix_ols_configs]")
 | |
|             return 0
 | |
| 
 | |
|         return self.reStartLiteSpeed()
 | |
| 
 | |
|     def changePortTo80(self):
 | |
|         try:
 | |
|             InstallCyberPanel.stdOut("Changing default port to 80..", 1)
 | |
| 
 | |
|             file_path = self.server_root_path + "conf/httpd_config.conf"
 | |
|             if self.modify_file_content(file_path, {"*:8088": "*:80"}):
 | |
|                 InstallCyberPanel.stdOut("Default port is now 80 for OpenLiteSpeed!", 1)
 | |
|             else:
 | |
|                 return 0
 | |
| 
 | |
|         except Exception as msg:
 | |
|             logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [changePortTo80]")
 | |
|             return 0
 | |
| 
 | |
|         return self.reStartLiteSpeed()
 | |
| 
 | |
|     def installAllPHPVersions(self):
 | |
|         php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85']
 | |
|         
 | |
|         if self.distro == ubuntu:
 | |
|             # Install base PHP 7.x packages
 | |
|             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
 | |
|                 self.install_package(f'lsphp{version}*')
 | |
|                 
 | |
|         elif self.distro == centos:
 | |
|             # First install the group
 | |
|             command = 'yum -y groupinstall lsphp-all'
 | |
|             install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
|             
 | |
|             InstallCyberPanel.stdOut("LiteSpeed PHPs successfully installed!", 1)
 | |
|             
 | |
|             # Install individual PHP versions
 | |
|             for version in php_versions:
 | |
|                 self.install_package(f'lsphp{version}*', '--skip-broken')
 | |
|                 
 | |
|         elif self.distro == cent8:
 | |
|             # Install PHP versions in batches with exclusions
 | |
|             exclude_flags = "--exclude lsphp73-pecl-zip --exclude *imagick*"
 | |
|             
 | |
|             # First batch: PHP 7.x and 8.0
 | |
|             versions_batch1 = ' '.join([f'lsphp{v}*' for v in php_versions[:5]])
 | |
|             self.install_package(versions_batch1, f'{exclude_flags} --skip-broken')
 | |
|             
 | |
|             # Second batch: PHP 8.1+
 | |
|             versions_batch2 = ' '.join([f'lsphp{v}*' for v in php_versions[5:]])
 | |
|             self.install_package(versions_batch2, f'{exclude_flags} --skip-broken')
 | |
|             
 | |
|         elif self.distro == openeuler:
 | |
|             # Install all PHP versions at once
 | |
|             all_versions = ' '.join([f'lsphp{v}*' for v in php_versions])
 | |
|             self.install_package(all_versions)
 | |
|             
 | |
|         if self.distro != ubuntu:
 | |
|             InstallCyberPanel.stdOut("LiteSpeed PHPs successfully installed!", 1)
 | |
| 
 | |
|     def installSieve(self):
 | |
|         """Install Sieve (Dovecot Sieve) for email filtering on all OS variants"""
 | |
|         try:
 | |
|             InstallCyberPanel.stdOut("Installing Sieve (Dovecot Sieve) for email filtering...", 1)
 | |
|             
 | |
|             if self.distro == ubuntu:
 | |
|                 # Install dovecot-sieve and dovecot-managesieved
 | |
|                 self.install_package('dovecot-sieve dovecot-managesieved')
 | |
|             else:
 | |
|                 # For CentOS/AlmaLinux/OpenEuler
 | |
|                 self.install_package('dovecot-pigeonhole')
 | |
|             
 | |
|             # Add Sieve port 4190 to firewall
 | |
|             from plogical.firewallUtilities import FirewallUtilities
 | |
|             FirewallUtilities.addSieveFirewallRule()
 | |
|             
 | |
|             InstallCyberPanel.stdOut("Sieve successfully installed and configured!", 1)
 | |
|             return 1
 | |
|             
 | |
|         except BaseException as msg:
 | |
|             logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [installSieve]")
 | |
|             return 0
 | |
| 
 | |
|     def installMySQL(self, mysql):
 | |
| 
 | |
|         ############## Install mariadb ######################
 | |
| 
 | |
|         if self.distro == ubuntu:
 | |
| 
 | |
|             command = 'DEBIAN_FRONTEND=noninteractive apt-get install software-properties-common apt-transport-https curl -y'
 | |
|             install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|             command = "mkdir -p /etc/apt/keyrings"
 | |
|             install_utils.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_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
|             RepoPath = '/etc/apt/sources.list.d/mariadb.sources'
 | |
|             RepoContent = f"""
 | |
| # MariaDB 10.11 repository list - created 2023-12-11 07:53 UTC
 | |
| # https://mariadb.org/download/
 | |
| X-Repolib-Name: MariaDB
 | |
| 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
 | |
| Components: main main/debug
 | |
| Signed-By: /etc/apt/keyrings/mariadb-keyring.pgp
 | |
| """
 | |
| 
 | |
|             if get_Ubuntu_release() > 21.00:
 | |
|                 command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=10.11'
 | |
|                 result = install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True)
 | |
|                 
 | |
|                 # If the download fails, use manual repo configuration as fallback
 | |
|                 if result != 1:
 | |
|                     install_utils.writeToFile("MariaDB repo setup script failed, using manual configuration...")
 | |
|                     
 | |
|                     # First, ensure directories exist
 | |
|                     command = 'mkdir -p /usr/share/keyrings /etc/apt/sources.list.d'
 | |
|                     install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
|                     
 | |
|                     # Download and add MariaDB signing key
 | |
|                     command = 'curl -fsSL https://mariadb.org/mariadb_release_signing_key.pgp | gpg --dearmor -o /usr/share/keyrings/mariadb-keyring.pgp'
 | |
|                     install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
|                     
 | |
|                     # Use multiple mirror options for better reliability
 | |
|                     RepoPath = '/etc/apt/sources.list.d/mariadb.list'
 | |
|                     codename = get_Ubuntu_code_name()
 | |
|                     RepoContent = f"""# MariaDB 10.11 repository list - manual fallback
 | |
| # Primary mirror
 | |
| deb [arch=amd64,arm64,ppc64el,s390x signed-by=/usr/share/keyrings/mariadb-keyring.pgp] https://mirror.mariadb.org/repo/10.11/ubuntu {codename} main
 | |
| 
 | |
| # Alternative mirrors (uncomment if primary fails)
 | |
| # deb [arch=amd64,arm64,ppc64el,s390x signed-by=/usr/share/keyrings/mariadb-keyring.pgp] https://mirrors.gigenet.com/mariadb/repo/10.11/ubuntu {codename} main
 | |
| # deb [arch=amd64,arm64,ppc64el,s390x signed-by=/usr/share/keyrings/mariadb-keyring.pgp] https://ftp.osuosl.org/pub/mariadb/repo/10.11/ubuntu {codename} main
 | |
| """
 | |
|                     
 | |
|                     WriteToFile = open(RepoPath, 'w')
 | |
|                     WriteToFile.write(RepoContent)
 | |
|                     WriteToFile.close()
 | |
|                     
 | |
|                     install_utils.writeToFile("Manual MariaDB repository configuration completed.")
 | |
| 
 | |
| 
 | |
| 
 | |
|             command = 'DEBIAN_FRONTEND=noninteractive apt-get update -y'
 | |
|             install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
| 
 | |
|             command = "DEBIAN_FRONTEND=noninteractive apt-get install mariadb-server -y"
 | |
|         elif self.distro == debian12:
 | |
|             # Debian 12 uses similar setup to Ubuntu but with native packages
 | |
|             command = 'DEBIAN_FRONTEND=noninteractive apt-get install software-properties-common apt-transport-https curl -y'
 | |
|             install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|             command = "mkdir -p /etc/apt/keyrings"
 | |
|             install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|             # Use MariaDB official repository for Debian 12
 | |
|             command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=10.11'
 | |
|             result = install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True)
 | |
| 
 | |
|             # If the download fails, use manual repo configuration as fallback
 | |
|             if result != 1:
 | |
|                 install_utils.writeToFile("MariaDB repo setup script failed, using manual configuration...")
 | |
| 
 | |
|                 # First, ensure directories exist
 | |
|                 command = 'mkdir -p /usr/share/keyrings /etc/apt/sources.list.d'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 # Download and add MariaDB signing key
 | |
|                 command = 'curl -fsSL https://mariadb.org/mariadb_release_signing_key.pgp | gpg --dearmor -o /usr/share/keyrings/mariadb-keyring.pgp'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 # Use Debian 12 bookworm codename
 | |
|                 RepoPath = '/etc/apt/sources.list.d/mariadb.list'
 | |
|                 RepoContent = """# MariaDB 10.11 repository list for Debian 12
 | |
| # Primary mirror
 | |
| deb [arch=amd64,arm64,ppc64el,s390x signed-by=/usr/share/keyrings/mariadb-keyring.pgp] https://mirror.mariadb.org/repo/10.11/debian bookworm main
 | |
| 
 | |
| # Alternative mirrors (uncomment if primary fails)
 | |
| # deb [arch=amd64,arm64,ppc64el,s390x signed-by=/usr/share/keyrings/mariadb-keyring.pgp] https://mirrors.gigenet.com/mariadb/repo/10.11/debian bookworm main
 | |
| # deb [arch=amd64,arm64,ppc64el,s390x signed-by=/usr/share/keyrings/mariadb-keyring.pgp] https://ftp.osuosl.org/pub/mariadb/repo/10.11/debian bookworm main
 | |
| """
 | |
| 
 | |
|                 WriteToFile = open(RepoPath, 'w')
 | |
|                 WriteToFile.write(RepoContent)
 | |
|                 WriteToFile.close()
 | |
| 
 | |
|                 install_utils.writeToFile("Manual MariaDB repository configuration completed.")
 | |
| 
 | |
|             command = 'DEBIAN_FRONTEND=noninteractive apt-get update -y'
 | |
|             install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|             command = "DEBIAN_FRONTEND=noninteractive apt-get install mariadb-server -y"
 | |
|         elif self.distro == centos:
 | |
| 
 | |
|             RepoPath = '/etc/yum.repos.d/mariadb.repo'
 | |
|             RepoContent = f"""
 | |
| [mariadb]
 | |
| name = MariaDB
 | |
| baseurl = http://yum.mariadb.org/10.11/rhel8-amd64
 | |
| module_hotfixes=1
 | |
| gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
 | |
| gpgcheck=1            
 | |
| """
 | |
|             WriteToFile = open(RepoPath, 'w')
 | |
|             WriteToFile.write(RepoContent)
 | |
|             WriteToFile.close()
 | |
| 
 | |
|             command = 'dnf install mariadb-server -y'
 | |
|         elif self.distro == cent8 or self.distro == openeuler:
 | |
| 
 | |
|             clAPVersion = FetchCloudLinuxAlmaVersionVersion()
 | |
|             type = clAPVersion.split('-')[0]
 | |
|             version = int(clAPVersion.split('-')[1])
 | |
| 
 | |
| 
 | |
|             if type == 'cl' and version >= 88:
 | |
| 
 | |
|                 command = 'yum remove db-governor db-governor-mysql -y'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 command = 'yum install governor-mysql -y'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 command = '/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=mariadb106'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 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_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 command = 'yum remove mariadb* -y'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 command = 'sudo dnf -qy module disable mariadb'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 command = 'sudo dnf module reset mariadb -y'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 # Disable problematic mariadb-maxscale repository to avoid 404 errors
 | |
|                 command = 'dnf config-manager --disable mariadb-maxscale'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True)
 | |
| 
 | |
|                 # Clear dnf cache to avoid repository issues
 | |
|                 command = 'dnf clean all'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|                 command = 'dnf install MariaDB-server MariaDB-client MariaDB-backup -y'
 | |
| 
 | |
|         install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
| 
 | |
|         ############## Start mariadb ######################
 | |
| 
 | |
|         self.startMariaDB()
 | |
| 
 | |
|     def changeMYSQLRootPassword(self):
 | |
|         if self.remotemysql == 'OFF':
 | |
|             if self.distro == ubuntu:
 | |
|                 passwordCMD = "use mysql;DROP DATABASE IF EXISTS test;DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%%';GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '%s';UPDATE user SET plugin='' WHERE User='root';flush privileges;" % (
 | |
|                     InstallCyberPanel.mysql_Root_password)
 | |
|             else:
 | |
|                 passwordCMD = "use mysql;DROP DATABASE IF EXISTS test;DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%%';GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY '%s';flush privileges;" % (
 | |
|                     InstallCyberPanel.mysql_Root_password)
 | |
| 
 | |
|             # For AlmaLinux 9, try mysql command first, then mariadb
 | |
|             if self.distro == cent8 or self.distro == openeuler:
 | |
|                 command = 'mysql -u root -e "' + passwordCMD + '"'
 | |
|                 result = install_utils.call(command, self.distro, command, command, 0, 0, os.EX_OSERR)
 | |
|                 if result != 0:
 | |
|                     # If mysql command fails, try mariadb
 | |
|                     command = 'mariadb -u root -e "' + passwordCMD + '"'
 | |
|                     install_utils.call(command, self.distro, command, command, 0, 0, os.EX_OSERR)
 | |
|             else:
 | |
|                 command = 'mariadb -u root -e "' + passwordCMD + '"'
 | |
|                 install_utils.call(command, self.distro, command, command, 0, 0, os.EX_OSERR)
 | |
| 
 | |
|     def startMariaDB(self):
 | |
| 
 | |
|         if self.remotemysql == 'OFF':
 | |
|             ############## Start mariadb ######################
 | |
|             
 | |
|             # Check if AlmaLinux 9 and apply fixes
 | |
|             if self.is_almalinux9():
 | |
|                 self.stdOut("AlmaLinux 9 detected - applying MariaDB fixes", 1)
 | |
|                 self.fix_almalinux9_mariadb()
 | |
|             
 | |
|             self.manage_service('mariadb', 'start')
 | |
| 
 | |
|             ############## 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')
 | |
| 
 | |
|             self.manage_service('mariadb', 'enable')
 | |
| 
 | |
|     def fixMariaDB(self):
 | |
|         self.stdOut("Setup MariaDB so it can support Cyberpanel's needs")
 | |
| 
 | |
|         conn = mariadb.connect(user='root', passwd=self.mysql_Root_password)
 | |
|         cursor = conn.cursor()
 | |
|         cursor.execute('set global innodb_file_per_table = on;')
 | |
|         try:
 | |
|             cursor.execute('set global innodb_file_format = Barracuda;')
 | |
|             cursor.execute('set global innodb_large_prefix = on;')
 | |
|         except BaseException as msg:
 | |
|             self.stdOut('%s. [ERROR:335]' % (str(msg)))
 | |
|         cursor.close()
 | |
|         conn.close()
 | |
| 
 | |
|         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()
 | |
|         except IOError as err:
 | |
|             self.stdOut("[ERROR] Error in setting: " + fileName + ": " + str(err), 1, 1, os.EX_OSERR)
 | |
| 
 | |
|         # Use the manage_service method for consistent service management
 | |
|         if self.distro == cent8 or self.distro == openeuler:
 | |
|             # Try mariadb first, then mysqld
 | |
|             result = os.system('systemctl restart mariadb')
 | |
|             if result != 0:
 | |
|                 os.system('systemctl restart mysqld')
 | |
|         else:
 | |
|             os.system('systemctl restart mariadb')
 | |
| 
 | |
|         self.stdOut("MariaDB is now setup so it can support Cyberpanel's needs")
 | |
| 
 | |
|     def installPureFTPD(self):
 | |
|         if self.distro == ubuntu:
 | |
|             self.install_package('pure-ftpd-mysql')
 | |
| 
 | |
|             if get_Ubuntu_release() == 18.10:
 | |
|                 # Special handling for Ubuntu 18.10
 | |
|                 packages = [
 | |
|                     ('pure-ftpd-common_1.0.47-3_all.deb', 'wget https://rep.cyberpanel.net/pure-ftpd-common_1.0.47-3_all.deb'),
 | |
|                     ('pure-ftpd-mysql_1.0.47-3_amd64.deb', 'wget https://rep.cyberpanel.net/pure-ftpd-mysql_1.0.47-3_amd64.deb')
 | |
|                 ]
 | |
|                 
 | |
|                 for filename, wget_cmd in packages:
 | |
|                     install_utils.call(wget_cmd, self.distro, wget_cmd, wget_cmd, 1, 1, os.EX_OSERR)
 | |
|                     command = f'dpkg --install --force-confold {filename}'
 | |
|                     install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
|         else:
 | |
|             self.install_package('pure-ftpd')
 | |
| 
 | |
|         ####### Install pureftpd to system startup
 | |
| 
 | |
|         command = "systemctl enable " + install.preFlightsChecks.pureFTPDServiceName(self.distro)
 | |
|         install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|         ###### FTP Groups and user settings settings
 | |
| 
 | |
|         command = 'groupadd -g 2001 ftpgroup'
 | |
|         install_utils.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_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|     def startPureFTPD(self):
 | |
|         ############## Start pureftpd ######################
 | |
|         serviceName = install.preFlightsChecks.pureFTPDServiceName(self.distro)
 | |
|         
 | |
|         # During fresh installation, don't start Pure-FTPd yet
 | |
|         # It will be started after Django migrations create the required tables
 | |
|         InstallCyberPanel.stdOut("Pure-FTPd enabled for startup.", 1)
 | |
|         InstallCyberPanel.stdOut("Note: Pure-FTPd will start after database setup is complete.", 1)
 | |
|         logging.InstallLog.writeToFile("Pure-FTPd enabled but not started - waiting for Django migrations")
 | |
| 
 | |
|     def installPureFTPDConfigurations(self, mysql):
 | |
|         try:
 | |
|             ## setup ssl for ftp
 | |
| 
 | |
|             InstallCyberPanel.stdOut("Configuring PureFTPD..", 1)
 | |
| 
 | |
|             try:
 | |
|                 if not os.path.exists("/etc/ssl/private"):
 | |
|                     os.makedirs("/etc/ssl/private", mode=0o755)
 | |
|             except OSError as e:
 | |
|                 if e.errno != errno.EEXIST:
 | |
|                     logging.InstallLog.writeToFile("[ERROR] Could not create directory for FTP SSL: " + str(e))
 | |
|                     raise
 | |
| 
 | |
|             if (self.distro == centos or self.distro == cent8 or self.distro == openeuler) or (
 | |
|                     self.distro == ubuntu and get_Ubuntu_release() == 18.14):
 | |
|                 command = 'openssl req -newkey rsa:1024 -new -nodes -x509 -days 3650 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" -keyout /etc/ssl/private/pure-ftpd.pem -out /etc/ssl/private/pure-ftpd.pem'
 | |
|             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_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
| 
 | |
|             os.chdir(self.cwd)
 | |
|             ftpdPath = "/etc/pure-ftpd"
 | |
| 
 | |
|             self.copy_config_file("pure-ftpd", ftpdPath, mysql)
 | |
| 
 | |
|             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)
 | |
| 
 | |
|             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()
 | |
| 
 | |
|             ftpConfPath = '/etc/pure-ftpd/pureftpd-mysql.conf'
 | |
| 
 | |
|             if self.remotemysql == 'ON':
 | |
|                 command = "sed -i 's|localhost|%s|g' %s" % (self.mysqlhost, ftpConfPath)
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|                 command = "sed -i 's|3306|%s|g' %s" % (self.mysqlport, ftpConfPath)
 | |
|                 install_utils.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_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|             if self.distro == ubuntu:
 | |
| 
 | |
|                 if os.path.exists('/etc/pure-ftpd/db/mysql.conf'):
 | |
|                     os.remove('/etc/pure-ftpd/db/mysql.conf')
 | |
|                     shutil.copy(ftpdPath + "/pureftpd-mysql.conf", '/etc/pure-ftpd/db/mysql.conf')
 | |
|                 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)
 | |
| 
 | |
|                 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_utils.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_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|                 command = 'systemctl restart pure-ftpd-mysql.service'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
|                 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_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|                     command = "systemctl restart pure-ftpd-mysql.service"
 | |
|                     install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
|             else:
 | |
| 
 | |
|                 try:
 | |
|                     clAPVersion = FetchCloudLinuxAlmaVersionVersion()
 | |
|                     type = clAPVersion.split('-')[0]
 | |
|                     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_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
|                 except:
 | |
|                     pass
 | |
| 
 | |
| 
 | |
| 
 | |
|             InstallCyberPanel.stdOut("PureFTPD configured!", 1)
 | |
| 
 | |
|         except IOError as msg:
 | |
|             logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [installPureFTPDConfigurations]")
 | |
|             return 0
 | |
| 
 | |
|     def installPowerDNS(self):
 | |
|         try:
 | |
|             if self.distro == ubuntu or self.distro == cent8 or self.distro == openeuler:
 | |
|                 # Stop and disable systemd-resolved
 | |
|                 self.manage_service('systemd-resolved', 'stop')
 | |
|                 self.manage_service('systemd-resolved.service', 'disable')
 | |
| 
 | |
|                 try:
 | |
|                     os.rename('/etc/resolv.conf', '/etc/resolv.conf.bak')
 | |
|                 except OSError as e:
 | |
|                     if e.errno != errno.EEXIST and e.errno != errno.ENOENT:
 | |
|                         InstallCyberPanel.stdOut("[ERROR] Unable to rename /etc/resolv.conf to install PowerDNS: " +
 | |
|                                                  str(e), 1, 1, os.EX_OSERR)
 | |
|                 
 | |
|                 # Create a temporary resolv.conf with Google DNS for package installation
 | |
|                 try:
 | |
|                     with open('/etc/resolv.conf', 'w') as f:
 | |
|                         f.write('nameserver 8.8.8.8\n')
 | |
|                         f.write('nameserver 8.8.4.4\n')
 | |
|                     InstallCyberPanel.stdOut("Created temporary /etc/resolv.conf with Google DNS", 1)
 | |
|                 except IOError as e:
 | |
|                     InstallCyberPanel.stdOut("[ERROR] Unable to create /etc/resolv.conf: " + str(e), 1, 1, os.EX_OSERR)
 | |
| 
 | |
|             # Install PowerDNS packages
 | |
|             if self.distro == ubuntu:
 | |
|                 # Update package list first
 | |
|                 command = "DEBIAN_FRONTEND=noninteractive apt-get update"
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
|                 
 | |
|                 # Install PowerDNS packages
 | |
|                 command = "DEBIAN_FRONTEND=noninteractive apt-get -y install pdns-server pdns-backend-mysql"
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True)
 | |
|                 
 | |
|                 # Ensure service is stopped after installation for configuration
 | |
|                 command = 'systemctl stop pdns || true'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True)
 | |
|                 return 1
 | |
|             else:
 | |
|                 self.install_package('pdns pdns-backend-mysql')
 | |
| 
 | |
|         except BaseException as msg:
 | |
|             logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [powerDNS]")
 | |
| 
 | |
|     def installPowerDNSConfigurations(self, mysqlPassword, mysql):
 | |
|         try:
 | |
| 
 | |
|             InstallCyberPanel.stdOut("Configuring PowerDNS..", 1)
 | |
| 
 | |
|             os.chdir(self.cwd)
 | |
|             if self.distro == centos or self.distro == cent8 or self.distro == openeuler:
 | |
|                 dnsPath = "/etc/pdns/pdns.conf"
 | |
|             else:
 | |
|                 dnsPath = "/etc/powerdns/pdns.conf"
 | |
|                 # Ensure directory exists for Ubuntu
 | |
|                 dnsDir = os.path.dirname(dnsPath)
 | |
|                 if not os.path.exists(dnsDir):
 | |
|                     try:
 | |
|                         os.makedirs(dnsDir, mode=0o755)
 | |
|                     except OSError as e:
 | |
|                         if e.errno != errno.EEXIST:
 | |
|                             raise
 | |
| 
 | |
|             try:
 | |
|                 self.copy_config_file("dns", dnsPath, mysql)
 | |
|             except Exception as e:
 | |
|                 InstallCyberPanel.stdOut("[ERROR] Failed to copy PowerDNS config: " + str(e), 1)
 | |
|                 logging.InstallLog.writeToFile('[ERROR] Failed to copy PowerDNS config: ' + str(e))
 | |
|                 raise
 | |
| 
 | |
|             # Verify the file was copied and has content
 | |
|             if not os.path.exists(dnsPath):
 | |
|                 raise IOError(f"PowerDNS config file not found at {dnsPath} after copy")
 | |
|             
 | |
|             # Check if file has content
 | |
|             with open(dnsPath, "r") as f:
 | |
|                 content = f.read()
 | |
|                 if not content or "launch=gmysql" not in content:
 | |
|                     InstallCyberPanel.stdOut("[WARNING] PowerDNS config appears empty or incomplete, attempting to fix...", 1)
 | |
|                     
 | |
|                     # First try to re-copy
 | |
|                     try:
 | |
|                         if os.path.exists(dnsPath):
 | |
|                             os.remove(dnsPath)
 | |
|                         source_file = os.path.join(self.cwd, "dns-one", "pdns.conf")
 | |
|                         shutil.copy2(source_file, dnsPath)
 | |
|                     except Exception as copy_error:
 | |
|                         InstallCyberPanel.stdOut("[WARNING] Failed to re-copy config: " + str(copy_error), 1)
 | |
|                         
 | |
|                         # Fallback: directly write the essential MySQL configuration
 | |
|                         InstallCyberPanel.stdOut("[INFO] Directly writing MySQL backend configuration...", 1)
 | |
|                         try:
 | |
|                             mysql_config = f"""# PowerDNS MySQL Backend Configuration
 | |
| launch=gmysql
 | |
| gmysql-host=localhost
 | |
| gmysql-port=3306
 | |
| gmysql-user=cyberpanel
 | |
| gmysql-password={mysqlPassword}
 | |
| gmysql-dbname=cyberpanel
 | |
| 
 | |
| # Basic PowerDNS settings
 | |
| daemon=no
 | |
| guardian=no
 | |
| setgid=pdns
 | |
| setuid=pdns
 | |
| """
 | |
|                             # If file exists and has some content, append our config
 | |
|                             if os.path.exists(dnsPath) and content.strip():
 | |
|                                 # Check if it's just missing the MySQL part
 | |
|                                 with open(dnsPath, "a") as f:
 | |
|                                     f.write("\n\n" + mysql_config)
 | |
|                             else:
 | |
|                                 # Write a complete minimal config
 | |
|                                 with open(dnsPath, "w") as f:
 | |
|                                     f.write(mysql_config)
 | |
|                             
 | |
|                             InstallCyberPanel.stdOut("[SUCCESS] MySQL backend configuration written directly", 1)
 | |
|                         except Exception as write_error:
 | |
|                             InstallCyberPanel.stdOut("[ERROR] Failed to write MySQL config: " + str(write_error), 1)
 | |
|                             raise
 | |
|             
 | |
|             InstallCyberPanel.stdOut("PowerDNS config file prepared at: " + dnsPath, 1)
 | |
|             
 | |
|             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()
 | |
| 
 | |
|             if self.remotemysql == 'ON':
 | |
|                 command = "sed -i 's|gmysql-host=localhost|gmysql-host=%s|g' %s" % (self.mysqlhost, dnsPath)
 | |
|                 install_utils.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_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR)
 | |
| 
 | |
|             # Set proper permissions for PowerDNS config
 | |
|             if self.distro == ubuntu:
 | |
|                 # Ensure pdns user/group exists
 | |
|                 command = 'id -u pdns &>/dev/null || useradd -r -s /usr/sbin/nologin pdns'
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|                 
 | |
|                 command = 'chown root:pdns %s' % dnsPath
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
|                 
 | |
|                 command = 'chmod 640 %s' % dnsPath
 | |
|                 install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
 | |
| 
 | |
|             InstallCyberPanel.stdOut("PowerDNS configured!", 1)
 | |
| 
 | |
|         except IOError as msg:
 | |
|             logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [installPowerDNSConfigurations]")
 | |
|             return 0
 | |
|         return 1
 | |
| 
 | |
|     def startPowerDNS(self):
 | |
| 
 | |
|         ############## Start PowerDNS ######################
 | |
| 
 | |
|         self.manage_service('pdns', 'enable')
 | |
|         
 | |
|         # During fresh installation, don't start PowerDNS yet
 | |
|         # It will be started after Django migrations create the required tables
 | |
|         InstallCyberPanel.stdOut("PowerDNS enabled for startup.", 1)
 | |
|         InstallCyberPanel.stdOut("Note: PowerDNS will start after database setup is complete.", 1)
 | |
|         logging.InstallLog.writeToFile("PowerDNS enabled but not started - waiting for Django migrations")
 | |
|         
 | |
|         # The service will be started later after migrations run
 | |
|         # or manually by the admin after installation completes
 | |
| 
 | |
| 
 | |
| def Main(cwd, mysql, distro, ent, serial=None, port="8090", ftp=None, dns=None, publicip=None, remotemysql=None,
 | |
|          mysqlhost=None, mysqldb=None, mysqluser=None, mysqlpassword=None, mysqlport=None):
 | |
|     InstallCyberPanel.mysqlPassword = install_utils.generate_pass()
 | |
|     InstallCyberPanel.mysql_Root_password = install_utils.generate_pass()
 | |
| 
 | |
|     file_name = '/etc/cyberpanel/mysqlPassword'
 | |
| 
 | |
|     if remotemysql == 'OFF':
 | |
|         if os.access(file_name, os.F_OK):
 | |
|             password = open(file_name, 'r')
 | |
|             InstallCyberPanel.mysql_Root_password = password.readline()
 | |
|             password.close()
 | |
|         else:
 | |
|             password = open(file_name, "w")
 | |
|             password.writelines(InstallCyberPanel.mysql_Root_password)
 | |
|             password.close()
 | |
|     else:
 | |
|         mysqlData = {'remotemysql': remotemysql, 'mysqlhost': mysqlhost, 'mysqldb': mysqldb, 'mysqluser': mysqluser,
 | |
|                      'mysqlpassword': mysqlpassword, 'mysqlport': mysqlport}
 | |
|         from json import dumps
 | |
|         writeToFile = open(file_name, 'w')
 | |
|         writeToFile.write(dumps(mysqlData))
 | |
|         writeToFile.close()
 | |
| 
 | |
|         if install.preFlightsChecks.debug:
 | |
|             print(open(file_name, 'r').read())
 | |
|             time.sleep(10)
 | |
| 
 | |
|     try:
 | |
|         command = 'chmod 640 %s' % (file_name)
 | |
|         install_utils.call(command, distro, '[chmod]',
 | |
|                                       '',
 | |
|                                       1, 0, os.EX_OSERR)
 | |
|         command = 'chown root:cyberpanel %s' % (file_name)
 | |
|         install_utils.call(command, distro, '[chmod]',
 | |
|                                       '',
 | |
|                                       1, 0, os.EX_OSERR)
 | |
|     except:
 | |
|         pass
 | |
| 
 | |
|     if distro == centos:
 | |
|         InstallCyberPanel.mysqlPassword = install_utils.generate_pass()
 | |
|     else:
 | |
|         InstallCyberPanel.mysqlPassword = InstallCyberPanel.mysql_Root_password
 | |
| 
 | |
|     installer = InstallCyberPanel("/usr/local/lsws/", cwd, distro, ent, serial, port, ftp, dns, publicip, remotemysql,
 | |
|                                   mysqlhost, mysqldb, mysqluser, mysqlpassword, mysqlport)
 | |
| 
 | |
|     logging.InstallLog.writeToFile('Installing LiteSpeed Web server,40')
 | |
|     installer.installLiteSpeed()
 | |
|     if ent == 0:
 | |
|         installer.changePortTo80()
 | |
|     logging.InstallLog.writeToFile('Installing Optimized PHPs..,50')
 | |
|     installer.installAllPHPVersions()
 | |
|     if ent == 0:
 | |
|         installer.fix_ols_configs()
 | |
| 
 | |
|     logging.InstallLog.writeToFile('Installing Sieve for email filtering..,55')
 | |
|     installer.installSieve()
 | |
| 
 | |
|     logging.InstallLog.writeToFile('Installing MySQL,60')
 | |
|     installer.installMySQL(mysql)
 | |
|     installer.changeMYSQLRootPassword()
 | |
| 
 | |
|     installer.startMariaDB()
 | |
| 
 | |
|     if remotemysql == 'OFF':
 | |
|         if distro == ubuntu:
 | |
|             installer.fixMariaDB()
 | |
| 
 | |
|     mysqlUtilities.createDatabase("cyberpanel", "cyberpanel", InstallCyberPanel.mysqlPassword, publicip)
 | |
| 
 | |
|     if ftp is None:
 | |
|         installer.installPureFTPD()
 | |
|         installer.installPureFTPDConfigurations(mysql)
 | |
|         installer.startPureFTPD()
 | |
|     else:
 | |
|         if ftp == 'ON':
 | |
|             installer.installPureFTPD()
 | |
|             installer.installPureFTPDConfigurations(mysql)
 | |
|             installer.startPureFTPD()
 | |
| 
 | |
|     if dns is None:
 | |
|         installer.installPowerDNS()
 | |
|         installer.installPowerDNSConfigurations(InstallCyberPanel.mysqlPassword, mysql)
 | |
|         installer.startPowerDNS()
 | |
|     else:
 | |
|         if dns == 'ON':
 | |
|             installer.installPowerDNS()
 | |
|             installer.installPowerDNSConfigurations(InstallCyberPanel.mysqlPassword, mysql)
 | |
|             installer.startPowerDNS()
 |