����JFIF��x�x����'
Server IP : 78.140.185.180 / Your IP : 216.73.216.82 Web Server : LiteSpeed System : Linux cpanel13.v.fozzy.com 4.18.0-513.11.1.lve.el8.x86_64 #1 SMP Thu Jan 18 16:21:02 UTC 2024 x86_64 User : builderbox ( 1072) PHP Version : 7.3.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /opt/cloudlinux/venv/lib64/python3.11/site-packages/cl_plus/utils/ |
Upload File : |
# coding=utf-8 # # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2020 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENCE.TXT # import logging import glob import os from traceback import format_exc from lxml import etree # NOQA from clcommon.utils import run_command, ExternalProgramFailed, grep, is_litespeed_running from clcommon.cpapi import get_apache_ports_list, get_apache_connections_number, get_apache_max_request_workers class WebServerHelper: """ Helper class for apache/Litespeed collector. """ APACHE_NAME = 'httpd' LITESPEED_NAME = 'litespeed' def __init__(self, _logger: logging.Logger): self._logger = _logger self._web_ports_list = [] self._is_apache = False self._is_litespeed = False self._netstat_bin = '/bin/netstat' self._no_server_message = 'There is no server working at 80 port' self._lsws_config = '/usr/local/lsws/conf/httpd_config.xml' self._is_server_absent_logged = False self.detect_active_server() def get_total_connections(self): """ Get web server total connections (from web server config) :return: tuple (max_req_num, message) max_req_num - Maximum request apache workers number or 0 if error message - OK/Error text """ if self._is_apache: return get_apache_max_request_workers() elif self._is_litespeed: return self._get_ls_total_connections() else: return 0, self._no_server_message def get_current_connections_number(self): """ Retrieves web server's current connections number from system netstat utility :return: tuple (conn_num, message) conn_num - current connections number message - OK/Error text """ # Read apache ports list. Litespeed uses apache's config, so this method works for both servers _httpd_ports_list = get_apache_ports_list() if self._is_litespeed: port_offset, message = self._get_ls_apache_port_offset() if message == "OK": _httpd_ports_list = [port + port_offset for port in _httpd_ports_list] else: return 0, message return self._get_current_connections_number_from_netstat(_httpd_ports_list) def get_connections_number(self): """ Retrieves web server connections number (from apache's mod_status or analog mechanism) :return: tuple (conn_num, message) conn_num - current connections number, 0 if error message - OK/Error text """ if self._is_apache: return get_apache_connections_number() elif self._is_litespeed: return self._get_ls_get_connections_number() else: return 0, self._no_server_message def detect_active_server(self): """ Determine is httpd/Litespeed running :return: True/False running/not running """ main_server_name = self._get_main_web_server_name() if not main_server_name: # Apache/Litespeed not working self._is_apache = False self._is_litespeed = False if not self._is_server_absent_logged: self._logger.info("Apache/Litespeed collector: Apache or Litespeed stopped or absent, collector will not work") self._is_server_absent_logged = True return False self._is_server_absent_logged = False self._web_ports_list = get_apache_ports_list() # Both httpd and litespeed working, select by port if main_server_name == self.LITESPEED_NAME: if not self._is_litespeed: self._logger.info("Apache/Litespeed collector: Using Litespeed") self._is_litespeed = True self._is_apache = False elif main_server_name == self.APACHE_NAME: if not self._is_apache: self._logger.info("Apache/Litespeed collector: Using Apache") self._is_apache = True self._is_litespeed = False return self._is_apache or self._is_litespeed def _get_current_connections_number_from_netstat(self, ports_list): """ Retrieves web server's current connections number from system netstat utility :param ports_list: Port list to search :return: tuple (conn_num, message) conn_num - current connections number message - OK/Error text """ # Build grep line, for example ':80|:443' _grep_ports_line = '|'.join([':{}'.format(val) for val in ports_list]) # /bin/netstat -nt | egrep ':80|:443' | wc -l try: # /bin/netstat -nt cmd_list = [self._netstat_bin, '-nt'] std_out = run_command(cmd_list) std_out_list = std_out.split('\n') out_list = list(grep(_grep_ports_line, match_any_position=True, multiple_search=True, data_from_file=std_out_list)) return len(out_list), 'OK' except ExternalProgramFailed: return 0, format_exc() def _get_ls_total_connections(self): """ Retrieve litespeed total connection number (from config) :return: tuple (max_conn, message) max_conn - Litespeed's total connection number or 0 if error message - OK/Trace """ try: # grep "maxConnections" /usr/local/lsws/conf/httpd_config.xml # XML path httpServerConfig/tuning/maxConnections with open(self._lsws_config) as f: x = etree.parse(f).getroot() element_list = x.xpath("tuning/maxConnections") max_conn = element_list[0].text return int(max_conn), "OK" except (OSError, IOError, IndexError, ValueError, etree.XMLSyntaxError, etree.XMLSchemaParseError, etree.XMLSchemaError): return 0, format_exc() def _get_ls_get_connections_number(self): """ Retrieve litespeed connections number (from LS statistics) :return: tuple (max_conn, message) max_conn - Litespeed's connections number or 0 if error message - OK/Trace """ try: con_num = 0 # ls -la /tmp/lshttpd/.rtr* ls_status_files_list = glob.glob('/tmp/lshttpd/.rtreport*') # ['/tmp/lshttpd/.rtreport.2', '/tmp/lshttpd/.rtreport'] for ls_filename in ls_status_files_list: if not os.path.isfile(os.path.realpath(ls_filename)): self._logger.warning('Skipping %s, because symlink does not point to real file', ls_filename) continue con_num += self._get_connections_num_from_ls_temp_file(ls_filename) return con_num, "OK" except (OSError, IOError, ValueError): return 0, format_exc() @staticmethod def _get_connections_num_from_ls_temp_file(ls_temp_filename: str): """ Retrieve connections number from litespeed's plain text answer :param ls_temp_filename: string with litespeed;s answer :return: tuple (conn_num, message) conn_num - current connections number, 0 if error """ with open(ls_temp_filename, 'r') as content_file: content = content_file.read() # content example: # VERSION: LiteSpeed Web Server/Enterprise/5.4.9 # UPTIME: 1 day 17:41:40 # BPS_IN: 0, BPS_OUT: 0, SSL_BPS_IN: 0, SSL_BPS_OUT: 0 # MAXCONN: 10000, MAXSSL_CONN: 10000, PLAINCONN: 0, AVAILCONN: 9999, IDLECONN: 0, SSLCONN: 1, AVAILSSL: 9999 # REQ_RATE []: REQ_PROCESSING: 1, REQ_PER_SEC: 0.0, TOT_REQS: 54997, PUB_CACHE_HITS_PER_SEC: 0.0, TOTAL_PUB_CACHE_HITS: 0, PRIVATE_CACHE_HITS_PER_SEC: 0.0, TOTAL_PRIVATE_CACHE_HITS: 0, STATIC_HITS_PER_SEC: 0.0, TOTAL_STATIC_HITS: 50018 # REQ_RATE [_AdminVHost]: REQ_PROCESSING: 1, REQ_PER_SEC: 0.0, TOT_REQS: 4989, PUB_CACHE_HITS_PER_SEC: 0.0, TOTAL_PUB_CACHE_HITS: 0, PRIVATE_CACHE_HITS_PER_SEC: 0.0, TOTAL_PRIVATE_CACHE_HITS: 0, STATIC_HITS_PER_SEC: 0.0, TOTAL_STATIC_HITS: 10 # BLOCKED_IP: # EOF # Extract and return TOT_REQS metric value lines_list = content.split('\n') empty_rrate_lines = list(grep('REQ_RATE []:', fixed_string=True, match_any_position=False, multiple_search=True, data_from_file=lines_list)) for line in empty_rrate_lines: line = line.strip() # line example: # REQ_RATE []: REQ_PROCESSING: 0, REQ_PER_SEC: 0.0, TOT_REQS: 50448, .... l_parts = line.split(',') # Search 'TOT_REQS' parameter for l_part in l_parts: # l_part example: ' REQ_PER_SEC: 0.0' l_part = l_part.strip() if l_part.startswith('TOT_REQS:'): return int(l_part.replace('TOT_REQS:', '').strip()) return 0 def _get_main_web_server_name(self): """ Detects main web server (httpd or litespeed) :return: Name - Main server name: 'litespeed', 'httpd', None """ if is_litespeed_running(): return self.LITESPEED_NAME try: # /sbin/service httpd status # retcode != 0 - litespeed/httpd not running # == 0 - litespeed/httpd running # if 'litespeed' present in stdout - this is litespeed # else - httpd returncode, _, _ = run_command(['/sbin/service', 'httpd', 'status'], return_full_output=True) if returncode != 0: return None return self.APACHE_NAME except ExternalProgramFailed: pass return None def _get_ls_apache_port_offset(self): """ Get Apache port offset for Litespeed There are several cases to handle: - port is defined in config <apachePortOffset>1234</apachePortOffset> => offset = 1234 - parameter is absent in config => offset = 0 - parameter is empty => offset = 0 - errors while reading config => offset = 0 """ offset = 0 try: # grep "apachePortOffset" /usr/local/lsws/conf/httpd_config.xml # XML path httpServerConfig/apachePortOffset with open(self._lsws_config) as f: x = etree.parse(f).getroot() element_list = x.xpath("apachePortOffset") if element_list: offset = element_list[0].text or 0 return int(offset), "OK" except (OSError, IOError, IndexError, ValueError, etree.XMLSyntaxError, etree.XMLSchemaParseError, etree.XMLSchemaError): return 0, format_exc()