/
opt
/
cloudlinux
/
venv
/
lib
/
python3.11
/
site-packages
/
xray
/
manager
/
Upload Filee
HOME
# -*- coding: utf-8 -*- # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2021 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENSE.TXT """ This module contains classes implementing X-Ray Manager behaviour for cPanel """ import json import os import subprocess from collections import ChainMap from pipes import quote from typing import Optional from clcommon.lib.whmapi_lib import WhmApiError, WhmApiRequest from clcommon.utils import get_cl_version, is_litespeed_running from xray.internal import phpinfo_utils from ..internal.exceptions import XRayManagerError, XRayMissingDomain from ..internal.types import DomainInfo from ..internal.user_plugin_utils import ( user_mode_verification, with_fpm_reload_restricted, ) from .base import BaseManager class CPanelManager(BaseManager): """ Class implementing an X-Ray manager behaviour for cPanel """ VERSIONS_cPanel = { 'ea-php54': '/opt/cpanel/ea-php54/root/etc/php.d', 'ea-php55': '/opt/cpanel/ea-php55/root/etc/php.d', 'ea-php56': '/opt/cpanel/ea-php56/root/etc/php.d', 'ea-php70': '/opt/cpanel/ea-php70/root/etc/php.d', 'ea-php71': '/opt/cpanel/ea-php71/root/etc/php.d', 'ea-php72': '/opt/cpanel/ea-php72/root/etc/php.d', 'ea-php73': '/opt/cpanel/ea-php73/root/etc/php.d', 'ea-php74': '/opt/cpanel/ea-php74/root/etc/php.d' } try: if get_cl_version() != 'cl6': VERSIONS_cPanel['ea-php80'] = '/opt/cpanel/ea-php80/root/etc/php.d' VERSIONS_cPanel['ea-php81'] = '/opt/cpanel/ea-php81/root/etc/php.d' VERSIONS_cPanel['ea-php82'] = '/opt/cpanel/ea-php82/root/etc/php.d' except TypeError: # primarily for the test run on the build system pass def supported_versions(self) -> ChainMap: """ Get supported PHP versions :return: a chained map with basic supported versions and cPanel supported versions """ return ChainMap(self.VERSIONS, self.VERSIONS_cPanel) def resolve_alias(self, domain_name: str) -> Optional[str]: """ Try to resolve domain_name if it is an alias :param domain_name: original domain name :return: resolved domain name alias """ try: result = WhmApiRequest( 'domainuserdata' ).with_arguments( domain=domain_name ).call() except WhmApiError as e: if 'system does not have a domain named' in str(e): self.logger.warning('Domain does not exist on the server', extra={'domain_name': domain_name}) raise XRayMissingDomain(domain_name) from e # this None was here before this patch, just non-explicitly return None else: return result['userdata']['servername'] def check_domain(self, name: str, domains_data: list, original_name=None) -> DomainInfo: """ Try to find given name among known domains :param name: name of domain to find :param domains_data: list of known domains :param original_name: original domain name (in case of alias resolving) :return: a DomainInfo object """ domain = next(( item for item in domains_data if item['vhost'] == name ), None) if domain is None: self.logger.warning('Domain does not exist on the server', extra={'domain_name': name}) raise XRayMissingDomain(name) if self.phpinfo_mode: config = phpinfo_utils.get_php_configuration( domain['account'], domain=original_name if original_name else name) return DomainInfo( name=original_name if original_name else name, panel_php_version=config.get_full_php_version('ea-php'), php_ini_scan_dir=config.absolute_ini_scan_dir, # indicates that there is no need to apply selector # and try to resolve php version, the one given in # php_version is final one is_selector_applied=True, user=domain['account'], panel_fpm=config.is_php_fpm, ) else: return DomainInfo( name=original_name if original_name else name, panel_php_version=domain['version'], user=domain['account'], panel_fpm=domain[ 'php_fpm'] if not is_litespeed_running() else False, is_selector_applied=False ) @user_mode_verification @with_fpm_reload_restricted def get_domain_info(self, domain_name: str) -> DomainInfo: """ Retrieve information about given domain from control panel environment: PHP version, user of domain. Try to resolve alias if domain was not found in API response :param domain_name: name of domain :return: a DomainInfo object """ result = WhmApiRequest( 'php_get_vhost_versions' ).call() domain_php = result['versions'] try: _info = self.check_domain(domain_name, domain_php) except XRayManagerError: alias = self.resolve_alias(domain_name) _info = self.check_domain(alias, domain_php, original_name=domain_name) return _info def domain_default_version_allows_selector(self, domain_php_version: str) -> bool: """ Check if given domain uses system default version. And system default is not alt-php. If yes, then it means that selector could be applied for given domain :param domain_php_version: PHP version of domain :return: True if yes, False otherwise """ result = WhmApiRequest( 'php_get_system_default_version' ).call() default_php = result['version'] return 'alt-php' not in default_php and default_php == domain_php_version def panel_specific_selector_enabled(self, domain_info: DomainInfo) -> bool: """ Check if selector is enabled specifically for panel Required to be implemented by child classes :param domain_info: a DomainInfo object :return: True if yes, False otherwise """ domain_php_version = domain_info.panel_php_version return ( # NOTE(vlebedev): CloudLinux PHP Selector in CPanel is considered to be enabled in two cases: # 1. system defaul ea-php version is set as native for domain via MultiPHP Manager, # 2. the same alt-php version is set for domain both via MultiPHP and via CL Selector. # # In the first case, the default ea-php version binaries are replaced with symlinks to /etc/cl.selector # folder entries (which in turn contains symlinks to binaries of currently-chosen in CL Selector alt-php # version). # # In the second case, not binaries but only PHP config folders are switched inside of cagefs: # * for the alt-php version selected both via MultiPHP and CL Selector, /opt/alt/phpXX/link/conf is a # symlink to /etc/cl.php.d/alt-php74 (/var/cagefs/<uid>/<user>/etc/cl.php.d/alt-phpXX outside of cagefs), # * other alt-php versions are still symlinked to /opt/alt/phpXX/etc/php.d (unless overriden by # /etc/cl.selector/symlinks.rules) self.domain_default_version_allows_selector(domain_php_version) or domain_php_version == domain_info.selector_php_version ) and not domain_info.panel_fpm def fpm_service_name(self, dom_info: DomainInfo) -> str: """ Get cPanel FPM service name :param dom_info: a DomainInfo object :return: FPM service name """ return f'{dom_info.panel_php_version}-php-fpm'