Mini Shell
# 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/LICENCE.TXT
#
import os
from collections import OrderedDict
from typing import Dict # NOQA
from clwizard.config import NoSuchModule, acquire_config_access
from clwizard.constants import ModuleStatus, MAIN_LOG_PATH
from clwizard.exceptions import InstallationFailedException, UserInterventionNeededError
from clwizard.utils import setup_logger
from .base import WizardInstaller # NOQA
from .cagefs import CagefsInstaller
from .governor import GovernorInstaller
from .nodejs import NodejsInstaller
from .php import PhpInstaller
from .python import PythonInstaller
from .ruby import RubyInstaller
from .lsapi import LsapiInstaller
# order of modules is important
# add new modules in correct order
ALL_MODULES = OrderedDict([
('cagefs', CagefsInstaller),
('mysql_governor', GovernorInstaller),
('nodejs', NodejsInstaller),
('php', PhpInstaller),
('python', PythonInstaller),
('ruby', RubyInstaller),
('mod_lsapi', LsapiInstaller),
# add other modules here
])
log = setup_logger('wizard.runner', MAIN_LOG_PATH)
def get_supported_modules():
"""Get list of supported modules on current control panel"""
return {
name: module for name, module in ALL_MODULES.items()
if module.is_supported_by_control_panel()
}
def run_installation():
"""Install modules according to settings in status file"""
log.info('~' * 60)
log.info('> Start new modules installation in process with pid %s', os.getpid())
for name, installer_class in get_supported_modules().items():
installer = installer_class()
# we should re-read config each time in order to be able to 'cancel'
with acquire_config_access() as config:
try:
options = config.get_module_options(module_name=name)
state = config.get_module_status(module_name=name)
except NoSuchModule:
log.info(
"Module %s is not set for installation, skip it", name)
continue
# 'resume case' when we should skip already installed modules
if state == ModuleStatus.INSTALLED:
log.info(
"Module %s is already installed, skip it", name)
continue
if state == ModuleStatus.CANCELLED:
log.info(
"Module %s has been cancelled, skip it", name)
continue
if state == ModuleStatus.AUTO_SKIPPED:
log.info(
"Module %s requires a manual installation. "
"Skipping it and continuing installation", name)
continue
config.set_module_status(
module_name=name, new_state=ModuleStatus.INSTALLING)
_install_module(name, installer, options=options)
log.info('> Process with pid %s successfully finished work', os.getpid())
log.info('-' * 60)
def _install_module(module, installer, options):
# type: (str, WizardInstaller, Dict) -> None
log.info("Installing module: %s", module)
try:
installer.run_installation(options)
except InstallationFailedException:
_write_module_state_atomic(
module_name=module, new_state=ModuleStatus.FAILED)
log.error(
"Installation failed for module %s", module,
extra={
'fingerprint': ['{{ default }}', module], # Used to group and break up events
'data': {'options': str(options)}}) # Additional data for sentry event
raise
except UserInterventionNeededError:
_write_module_state_atomic(
module_name=module, new_state=ModuleStatus.AUTO_SKIPPED)
log.warning("Automatic installation was skipped for module %s", module)
except Exception as err:
_write_module_state_atomic(
module_name=module, new_state=ModuleStatus.FAILED)
log.error("Installation failed for module %s", module)
installer.app_logger.exception(
"Unknown error occurred, please, retry "
"or contact CloudLinux support if it happens again."
"\n\nError: %s", str(err),
extra={
# Used to group and break up events
'fingerprint': ['{{ default }}', module, str(err)[:25]],
# Additional data for sentry event
'data': {'options': str(options)}
})
raise InstallationFailedException() from err
else:
_write_module_state_atomic(
module_name=module, new_state=ModuleStatus.INSTALLED)
log.info("Module '%s' successfully installed "
"using options '%s'", module, options)
def _write_module_state_atomic(module_name, new_state):
# type: (str, str) -> None
with acquire_config_access() as config_access:
config_access.set_module_status(module_name=module_name, new_state=new_state)
Zerion Mini Shell 1.0