%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /opt/cloudlinux/venv/lib/python3.11/site-packages/clwpos/object_cache/
Upload File :
Create Path :
Current File : //opt/cloudlinux/venv/lib/python3.11/site-packages/clwpos/object_cache/enable_redis_for_alt_php.py

#!/opt/cloudlinux/venv/bin/python3 -bb
# -*- 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

from __future__ import absolute_import

import argparse
import os
import sys
import logging
from typing import List, Optional

from cllimits.cagefs_lib import CageFs
from clwpos.constants import ALT_PHP_PREFIX, CLWPOS_VAR_DIR
from clwpos.php.base import PHP
from clwpos.php.alt_php import (
    create_generic_php,
    get_alt_php_versions,
    update_selector_built_in_extensions,
    disable_selector_extensions
)
from clwpos.logsetup import setup_logging
from clwpos.optimization_features import OBJECT_CACHE_FEATURE
from clwpos.feature_suites import is_module_visible_for_user
from clwpos.utils import (
    PhpIniConfig,
    create_pid_file,
    acquire_lock,
)
from clwpos.object_cache.redis_utils import (
    filter_php_versions_with_not_loaded_redis
)

logger = setup_logging(
    caller_name='enable_redis_for_alt_php',
    file_level=logging.DEBUG,
    logfile_path='/var/log/clwpos/enable_redis_for_alt_php.log',
)

awp_ini = 'acceleratewp.ini'

# marker for those clients, who do not want us modifying global ini
DO_NOT_MODIFY_PHP_GLOBAL_MARKER = f'{CLWPOS_VAR_DIR}/admin/do_not_modify_global_php.flag'


def remove_custom_ini(version: Optional[str], all_ini: Optional[bool]):
    if not os.path.exists(DO_NOT_MODIFY_PHP_GLOBAL_MARKER):
        logger.debug('Nothing to do')
        return

    supported_version = supported_alt_php(version)

    for php_version in supported_version:
        php_ini_config = PhpIniConfig(php_version, custom_logger=logger)
        php_ini_config.remove_custom_ini(f'etc/php.d/{awp_ini}', all_ini)

def update_user_ini(php_version: PHP):
    php_ini_config = PhpIniConfig(php_version, custom_logger=logger)
    modules_to_sync = php_ini_config.get_ini_content(f'etc/php.d/{awp_ini}')
    php_ini_config.update_user_ini('acceleratewp.ini', modules_to_sync)

def enable_redis_extension(php_version: PHP):
    """
    Enable 'redis' extension for specified alt-php version
    by adding 'extension=redis.so' into php.ini file.
    Also enable 'json' and 'igbinary' extensions if exist which are reqired by 'redis' extension.
    At the same time:
    - disable extension in 'php.d.all/<extension>.ini' to deny user
      to enable extension via PHP Selector.
    - disable extensions in 'php.d/default.ini' to eliminate duplicate loading of extensions.
    """
    php_ini_config = PhpIniConfig(php_version, custom_logger=logger)

    redis_required_modules = php_ini_config.get_required_modules('etc/php.d.all/redis.ini')

    if not redis_required_modules:
        logger.debug('Redis extension is not present in the system, skip')
        return

    modules = ['json'] + redis_required_modules
    modules.sort(key=lambda x: x.endswith('redis'))

    module_status_map = {}
    for module in modules:
        if module == 'redis':
            module_status_map['redis'] = php_ini_config.disable_modules(f'etc/php.d.all/redis.ini',
                                                                        redis_required_modules)
        else:
            module_status_map[module] = php_ini_config.disable_modules(f'etc/php.d.all/{module}.ini', [module])

    logger.debug(f'Final current modules status: {module_status_map}')

    existing_modules = [
        module
        for module, exists in module_status_map.items()
        if exists
    ]

    logger.debug(f'Existing extensions: {existing_modules}')

    php_ini_config.disable_modules('etc/php.d/default.ini', existing_modules)

    non_loaded_modules = [
        module for module in existing_modules
        if not php_version.is_extension_loaded(module)
    ]

    if not os.path.exists(DO_NOT_MODIFY_PHP_GLOBAL_MARKER):
        php_ini_config.enable_modules('etc/php.ini', non_loaded_modules)
    else:
        logger.debug('Marker exists: %s, adding those modules to custom awp ini: %s',
                     DO_NOT_MODIFY_PHP_GLOBAL_MARKER,
                     str(non_loaded_modules))
        php_ini_config.create_custom_ini(f'etc/php.d/{awp_ini}', non_loaded_modules)
    disable_selector_extensions(non_loaded_modules, php_version.version, logger)

def supported_alt_php(version: Optional[str]):
    alt_php_versions = [create_generic_php(f'{ALT_PHP_PREFIX}{version}')] if version else get_alt_php_versions()
    supported_alt_php_versions = [
        version for version in alt_php_versions if OBJECT_CACHE_FEATURE.is_php_supported(version)
    ]
    return supported_alt_php_versions

def get_php_versions_to_enable_redis(version: Optional[str]) -> List[PHP]:
    """
    Return list of php version supported by AccelerateWP
    and on which redis is presented but not enabled.
    """
    supported_alt_php_versions = supported_alt_php(version)
    return filter_php_versions_with_not_loaded_redis(supported_alt_php_versions)


def parse_args() -> argparse.Namespace:
    """
    Parse arguments for enable_redis_for_alt_php.py utility.
    """
    parser = argparse.ArgumentParser(
        prog='enable_redis_for_alt_php',
        description='Utility for enabling redis extension for alt-php',
    )
    parser.add_argument(
        '--version',
        type=int,
        help='Enable redis extension for specific alt-php version',
    )
    parser.add_argument(
        '--no-rebuild',
        action='store_true',
        help='Run without rebuilding users\' alt_php.ini files',
    )
    parser.add_argument(
        '--remove-custom-ini',
        action='store_true',
        help='Run to remove custom acceleratewp.ini'
    )
    parser.add_argument('--all', action='store_true', help='Run to remove ALL custom acceleratewp.ini')
    parser.add_argument('-v', '--verbose', action='store_true')
    parser.add_argument('-f', '--force', action='store_true')

    opts, _ = parser.parse_known_args()

    if opts.verbose:
        logging.basicConfig(level=logging.DEBUG)
    return opts


def main():
    """
    Enable redis extension for alt-php versions supported by AccelerateWP.
    """
    opts = parse_args()

    if not is_module_visible_for_user(OBJECT_CACHE_FEATURE) and not opts.force:
        print('Run only if object caching is allowed for at least one user')
        sys.exit(0)

    cagefs = CageFs()

    if opts.remove_custom_ini:
        remove_custom_ini(opts.version, opts.all)
        sys.exit(0)

    with acquire_lock(os.path.join('/var/run', ALT_PHP_PREFIX), attempts=None):
        php_versions_to_enable_redis = get_php_versions_to_enable_redis(opts.version)
        # we don't continue if there are no alt-php versions (supported by WPOS)
        # with redis presented but not loaded
        if not php_versions_to_enable_redis:
            logger.info('All php versions have redis extension installed and active')
            sys.exit(0)

        with create_pid_file(ALT_PHP_PREFIX):
            for php_version in php_versions_to_enable_redis:
                enable_redis_extension(php_version)

            # iter all supported, to sync users ini in case we already enabled in global .ini
            if os.path.exists(DO_NOT_MODIFY_PHP_GLOBAL_MARKER):
                for php_version in supported_alt_php(None):
                    update_user_ini(php_version)

            # we don't continue if there are no alt-php versions (supported by WPOS)
            # with redis presented but not loaded
            if not php_versions_to_enable_redis:
                sys.exit(0)

            # Rebuild users' alt_php.ini if all condition are satisfied:
            # - script called with no flag --no-rebuild
            # - cagefs package is installed
            if not opts.no_rebuild and cagefs.is_cagefs_present():
                cagefs.rebuild_alt_php_ini()
                update_selector_built_in_extensions(logger)


if __name__ == '__main__':
    main()

Zerion Mini Shell 1.0