%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /opt/cloudlinux/venv/lib/python3.11/site-packages/xray/manager/
Upload File :
Create Path :
Current File : //opt/cloudlinux/venv/lib/python3.11/site-packages/xray/manager/cpanel.py

# -*- 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'

Zerion Mini Shell 1.0