/
opt
/
cloudlinux
/
venv
/
lib64
/
python3.11
/
site-packages
/
clwizard
/
config
/
Upload Filee
HOME
#!/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/LICENCE.TXT # import json import os import time from typing import Dict, Any, Optional # NOQA from clwizard.constants import ModuleStatus, MODULES_STATUS_FILE, MAIN_LOG_PATH from clwizard.utils import atomic_write, setup_logger from .exceptions import ( NoSuchModule, MalformedConfigError, ) class Config: """ Low-level logic of interaction with 'states' file """ def __init__(self): # useful for IDE-level auto-completion and type checking class Cfg: worker_pid = None # type: int modules = {} # type: Dict[str, Dict] self.Cfg = Cfg self.log = setup_logger('wizard.config', MAIN_LOG_PATH) self.reload() def set_modules(self, modules): # type: (Dict[str, Dict]) -> None """ Forget about the previous config and create a new one with specified modules and instructions. {'cagefs': {'options': {'enable_for_new_users': True, 'enable_for_existing_users': True}}, 'mod_lsapi': {'options': {'use_beta_for_da': True}}, 'mysql_governor': {'options': {'mode': 'single'}}, 'php': {'options': {'install_versions': ['5.2', '5.3'], 'install_modules': False, 'default_version': '5.3'}}, 'nodejs': {'options': {'versions': ['7.4', '8.9'], 'default_version': '8.9'}}, 'python': {'options': {'versions': ['2.7', '3.6']}}, 'ruby': {'options': {'versions': ['2.7']}}} """ self.Cfg.modules = {} for module_name, instructions in modules.items(): self.Cfg.modules[module_name] = { 'status': ModuleStatus.PENDING, 'options': instructions.get('options', {}) } @property def statuses(self): # type: () -> Dict[str, str] """Get dictionary with modules statuses""" return {module: options['status'] for module, options in self.Cfg.modules.items()} def get_module_options(self, module_name): # type: (str) -> Dict[str, Dict[str, Any]] """Get modules options (dictionary)""" try: return self.Cfg.modules[module_name].get('options', {}) except KeyError as e: raise NoSuchModule(module_name) from e def get_module_status(self, module_name): # type: (str) -> str """Get modules states in format (see ModuleStatus)""" try: return self.Cfg.modules[module_name]['status'] except KeyError as e: raise NoSuchModule(module_name) from e def get_module_status_time(self, module_name): # type: (str) -> str """Get modules states in format (see ModuleStatus)""" try: return self.Cfg.modules[module_name].get('status_time') except KeyError as e: raise NoSuchModule(module_name) from e def set_module_status(self, module_name, new_state): # type: (str, str) -> None """Set new module state""" if module_name not in self.Cfg.modules: raise NoSuchModule(module_name) self.Cfg.modules[module_name]['status'] = new_state self.Cfg.modules[module_name]['status_time'] = time.time() @property def worker_pid(self): # type: () -> Optional[int] """Get background worker process id""" return self.Cfg.worker_pid @worker_pid.setter def worker_pid(self, new_pid): # type: (int) -> None """Set new background worker process id""" self.Cfg.worker_pid = new_pid def _reset_cfg(self): """ Reset self.Cfg object to default values before it will be loaded from file as a part of self.reload() """ # reset public class attributes to defaults for k, v in self.Cfg.__dict__.items(): if not k.startswith('__'): setattr(self.Cfg, k, None) self.Cfg.modules = {} def reload(self): """ Reset config object and load data from json config. :raises MalformedConfigError: cannot parse json config """ self._reset_cfg() json_data = self._read_json_config() if json_data is None: return # No file - nothing to load, use defaults self.Cfg.worker_pid = json_data['pid'] for module_name, info in json_data['modules'].items(): self.Cfg.modules[module_name] = { 'status': info['status'], 'status_time': info.get('status_time'), 'options': info.get('options', {}) } def save(self): """Dump python object state to file""" state = { 'pid': self.Cfg.worker_pid, 'modules': self.Cfg.modules } self._write_json_config(state) def _read_json_config(self): # type: () -> Optional[Dict] """ Load state config and parse it using json :raises MalformedConfigError: cannot parse json config """ if not os.path.exists(MODULES_STATUS_FILE): return None try: with open(MODULES_STATUS_FILE, encoding='utf-8') as f: return json.load(f) except (IOError, OSError) as e: self.log.error("Unable to load config file due to error %s", str(e)) return None except (TypeError, ValueError) as e: self.log.error('Unable to load json config file, %s', str(e)) raise MalformedConfigError(config_path=MODULES_STATUS_FILE) from e @staticmethod def _write_json_config(schema): # type: (Dict) -> None """Write data to file using atomic write""" with atomic_write(MODULES_STATUS_FILE) as f: json.dump(schema, f, indent=2)