diff --git a/app/add.py b/app/add.py index 207730a3..0587bd7b 100644 --- a/app/add.py +++ b/app/add.py @@ -362,6 +362,12 @@ if form.getvalue('peers-name') is not None: config_add = "\n" + name + servers_split if form.getvalue('generateconfig') is None: + slave_output = '' + try: + server_name = sql.get_hostname_by_server_ip(serv) + except Exception: + server_name = serv + try: funct.check_is_server_in_group(serv) if config_add: @@ -380,11 +386,16 @@ if form.getvalue('generateconfig') is None: MASTERS = sql.is_master(serv) for master in MASTERS: if master[0] is not None: - funct.upload_and_restart(master[0], cfg) + slave_output = funct.upload_and_restart(master[0], cfg) - stderr = funct.upload_and_restart(serv, cfg, just_save="save") - if stderr: - print(stderr) + slave_output = '
' + master[1] + ':\n' + slave_output + + output = funct.upload_and_restart(serv, cfg, just_save="save") + + output = '
' + server_name + ':\n' + output + output = output + slave_output + if output: + print(output) else: print(name) diff --git a/app/config.py b/app/config.py index 55ea33de..e87e63b2 100644 --- a/app/config.py +++ b/app/config.py @@ -130,15 +130,14 @@ if serv is not None and form.getvalue('config') is not None: funct.diff_config(oldcfg, cfg) - os.system("/bin/rm -f " + configs_dir + "*.old") + try: + os.system("/bin/rm -f " + configs_dir + "*.old") + except Exception as e: + print('error: ' + str(e)) if stderr: print(stderr) - else: - if save == 'test': - print('Config is ok') - else: - print('Config is ok
Config has been updated') + sys.exit() template = template.render( diff --git a/app/create_db.py b/app/create_db.py index 6a2b486c..c481ee56 100644 --- a/app/create_db.py +++ b/app/create_db.py @@ -58,8 +58,8 @@ def default_values(): 'desc': 'Socket port for HAProxy', 'group': '1'}, {'param': 'haproxy_sock_port', 'value': '1999', 'section': 'haproxy', 'desc': 'HAProxy sock port', 'group': '1'}, - {'param': 'apache_log_path', 'value': '/var/log/' + apache_dir + '/', 'section': 'logs', 'desc': 'Path to Apache logs', - 'group': '1'}, + {'param': 'apache_log_path', 'value': '/var/log/' + apache_dir + '/', 'section': 'logs', + 'desc': 'Path to Apache logs. Apache service for Roxy-WI', 'group': '1'}, {'param': 'nginx_path_logs', 'value': '/var/log/nginx/', 'section': 'nginx', 'desc': 'The path for NGINX logs', 'group': '1'}, {'param': 'nginx_stats_user', 'value': 'admin', 'section': 'nginx', 'desc': 'Username for accessing NGINX stats page', @@ -74,8 +74,7 @@ def default_values(): 'desc': 'Path to the NGINX directory with config files', 'group': '1'}, {'param': 'nginx_config_path', 'value': '/etc/nginx/nginx.conf', 'section': 'nginx', 'desc': 'Path to the main NGINX configuration file', 'group': '1'}, - {'param': 'ldap_enable', 'value': '0', 'section': 'ldap', 'desc': 'Enable LDAP (1 - yes, 0 - no)', - 'group': '1'}, + {'param': 'ldap_enable', 'value': '0', 'section': 'ldap', 'desc': 'Enable LDAP', 'group': '1'}, {'param': 'ldap_server', 'value': '', 'section': 'ldap', 'desc': 'IP address of the LDAP server', 'group': '1'}, {'param': 'ldap_port', 'value': '389', 'section': 'ldap', 'desc': 'LDAP port (port 389 or 636 is used by default)', 'group': '1'}, @@ -90,7 +89,7 @@ def default_values(): {'param': 'ldap_user_attribute', 'value': 'sAMAccountName', 'section': 'ldap', 'desc': 'Attribute to search users by', 'group': '1'}, {'param': 'ldap_search_field', 'value': 'mail', 'section': 'ldap', 'desc': 'User\'s email address', 'group': '1'}, - {'param': 'ldap_type', 'value': '0', 'section': 'ldap', 'desc': 'Use LDAPS (1 - yes, 0 - no)', 'group': '1'}, + {'param': 'ldap_type', 'value': '0', 'section': 'ldap', 'desc': 'Use LDAPS', 'group': '1'}, {'param': 'smon_check_interval', 'value': '1', 'section': 'monitoring', 'desc': 'Check interval for SMON (in minutes)', 'group': '1'}, {'param': 'port_scan_interval', 'value': '5', 'section': 'monitoring', @@ -132,6 +131,12 @@ def default_values(): 'desc': 'Path to the main Keepalived configuration file', 'group': '1'}, {'param': 'keepalived_path_logs', 'value': '/var/log/keepalived/', 'section': 'keepalived', 'desc': 'The path for Keepalived logs', 'group': '1'}, + {'param': 'mail_ssl', 'value': '0', 'section': 'mail', 'desc': 'Enable TLS', 'group': '1'}, + {'param': 'mail_from', 'value': '', 'section': 'mail', 'desc': 'Address of sender', 'group': '1'}, + {'param': 'mail_smtp_host', 'value': '', 'section': 'mail', 'desc': 'SMTP server address', 'group': '1'}, + {'param': 'mail_smtp_port', 'value': '25', 'section': 'mail', 'desc': 'SMTP server port', 'group': '1'}, + {'param': 'mail_smtp_user', 'value': '', 'section': 'mail', 'desc': 'User for auth', 'group': '1'}, + {'param': 'mail_smtp_password', 'value': '', 'section': 'mail', 'desc': 'Password for auth', 'group': '1'}, ] try: Setting.insert_many(data_source).on_conflict_ignore().execute() @@ -722,8 +727,24 @@ def update_db_v_6_0_1(**kwargs): print("Updating... DB has been updated to version 6.0.0.0-1") +def update_db_v_6_1_0(**kwargs): + for service_id in range(1, 5): + try: + servers_id = Server.select(Server.server_id).where(Server.type_ip == 0).execute() + for server_id in servers_id: + CheckerSetting.insert( + server_id=server_id, service_id=service_id + ).on_conflict_ignore().execute() + except Exception as e: + if kwargs.get('silent') != 1: + if e.args[0] == 'duplicate column name: haproxy' or str(e) == '(1060, "Duplicate column name \'haproxy\'")': + print('Updating... go to version 6.1.0') + else: + print("An error occurred:", e) + + def update_ver(): - query = Version.update(version='6.0.3.0') + query = Version.update(version='6.1.0.0') try: query.execute() except Exception: @@ -749,6 +770,7 @@ def update_all(): update_db_v_5_4_3_1() update_db_v_6_0() update_db_v_6_0_1() + update_db_v_6_1_0() update_ver() diff --git a/app/db_model.py b/app/db_model.py index cc78e9a8..66fba7ed 100644 --- a/app/db_model.py +++ b/app/db_model.py @@ -510,10 +510,26 @@ class GitSetting(BaseModel): constraints = [SQL('UNIQUE (server_id, service_id)')] +class CheckerSetting(BaseModel): + id = AutoField() + server_id = ForeignKeyField(Server, on_delete='Cascade') + service_id = IntegerField() + email = IntegerField(constraints=[SQL('DEFAULT 1')]) + telegram_id = IntegerField(constraints=[SQL('DEFAULT 0')]) + slack_id = IntegerField(constraints=[SQL('DEFAULT 0')]) + service_alert = IntegerField(constraints=[SQL('DEFAULT 1')]) + backend_alert = IntegerField(constraints=[SQL('DEFAULT 1')]) + maxconn_alert = IntegerField(constraints=[SQL('DEFAULT 1')]) + + class Meta: + table_name = 'checker_setting' + constraints = [SQL('UNIQUE (server_id, service_id)')] + + def create_tables(): with conn: conn.create_tables([User, Server, Role, Telegram, Slack, UUID, Token, ApiToken, Groups, UserGroups, ConfigVersion, Setting, Cred, Backup, Metrics, WafMetrics, Version, Option, SavedServer, Waf, ActionHistory, PortScannerSettings, PortScannerPorts, PortScannerHistory, ProvidersCreds, ServiceSetting, ProvisionedServers, MetricsHttpStatus, SMON, WafRules, Alerts, GeoipCodes, NginxMetrics, - SystemInfo, Services, UserName, GitSetting]) + SystemInfo, Services, UserName, GitSetting, CheckerSetting]) diff --git a/app/funct.py b/app/funct.py index b50928e7..36e4779c 100644 --- a/app/funct.py +++ b/app/funct.py @@ -984,9 +984,9 @@ def upload_and_restart(server_ip, cfg, **kwargs): commands = [move_config + reload_or_restart_command] elif service == "nginx": if is_docker == '1': - check_config = "sudo docker exec -it exec " + container_name + " nginx -t -q " + check_config = "sudo docker exec -it exec " + container_name + " nginx -t " else: - check_config = "sudo nginx -t -q " + check_config = "sudo nginx -t " check_and_move = "sudo mv -f " + tmp_file + " " + config_path + " && " + check_config if action == "test": commands = [check_config + " && sudo rm -f " + tmp_file] @@ -998,10 +998,10 @@ def upload_and_restart(server_ip, cfg, **kwargs): commands[0] += open_port_firewalld(cfg, server_ip=server_ip, service='nginx') elif service == "apache": if is_docker == '1': - check_config = "sudo docker exec -it exec " + container_name + " nginx -t -q " + check_config = "sudo docker exec -it exec " + container_name + " sudo apachectl configtest " else: check_config = "sudo apachectl configtest " - check_and_move = "sudo mv -f " + tmp_file + " " + config_path # + " && " + check_config + check_and_move = "sudo mv -f " + tmp_file + " " + config_path + " && " + check_config if action == "test": commands = [check_config + " && sudo rm -f " + tmp_file] elif action == "save": @@ -1012,7 +1012,7 @@ def upload_and_restart(server_ip, cfg, **kwargs): # commands[0] += open_port_firewalld(cfg, server_ip=server_ip, service='nginx') else: if is_docker == '1': - check_config = "sudo docker exec -it " + container_name + " haproxy -q -c -f " + tmp_file + check_config = "sudo docker exec -it " + container_name + " haproxy -c -f " + tmp_file else: check_config = "sudo " + service_name + " -c -f " + tmp_file move_config = " && sudo mv -f " + tmp_file + " " + config_path @@ -1075,28 +1075,37 @@ def upload_and_restart(server_ip, cfg, **kwargs): def master_slave_upload_and_restart(server_ip, cfg, just_save, **kwargs): import sql + masters = sql.is_master(server_ip) - slave_error = '' - for master in masters: - if master[0] is not None: - slave_error = upload_and_restart( - master[0], cfg, just_save=just_save, nginx=kwargs.get('nginx'), - apache=kwargs.get('apache'), config_file_name=kwargs.get('config_file_name'), slave=1 - ) - slave_error = master[0] + ': ' + slave_error + slave_output = '' + + try: + server_name = sql.get_hostname_by_server_ip(server_ip) + except Exception: + server_name = serv if kwargs.get('login'): login = kwargs.get('login') else: login = '' - error = upload_and_restart( + + for master in masters: + if master[0] is not None: + slv_output = upload_and_restart( + master[0], cfg, just_save=just_save, nginx=kwargs.get('nginx'), + apache=kwargs.get('apache'), config_file_name=kwargs.get('config_file_name'), slave=1 + ) + slave_output += '
' + master[1] + ':\n' + slv_output + + output = upload_and_restart( server_ip, cfg, just_save=just_save, nginx=kwargs.get('nginx'), apache=kwargs.get('apache'), config_file_name=kwargs.get('config_file_name'), oldcfg=kwargs.get('oldcfg'), login=login ) - error = server_ip + ': ' + error - error = error + slave_error - return error + output = server_name + ':\n' + output + + output = output + slave_output + return output def open_port_firewalld(cfg, server_ip, **kwargs): @@ -2048,3 +2057,88 @@ def is_docker() -> bool: if re.match("\d+:[\w=]+:/docker(-[ce]e)?/\w+", line): return True return False + + +def send_email(email_to: str, subject: str, message: str) -> None: + import sql + + mail_ssl = sql.get_setting('mail_ssl') + mail_from = sql.get_setting('mail_from') + mail_smtp_host = sql.get_setting('mail_smtp_host') + mail_smtp_port = sql.get_setting('mail_smtp_port') + mail_smtp_user = sql.get_setting('mail_smtp_user') + mail_smtp_password = sql.get_setting('mail_smtp_password') + + from smtplib import SMTP + + try: + from email.MIMEText import MIMEText + except Exception: + from email.mime.text import MIMEText + + from email.message import EmailMessage + + msg = MIMEText(message) + msg['Subject'] = 'Roxy-WI: ' + subject + msg['From'] = 'Roxy-WI <' + mail_from + '>' + msg['To'] = email_to + + try: + smtpObj = SMTP(mail_smtp_host, mail_smtp_port) + if mail_ssl: + smtpObj.starttls() + smtpObj.login(mail_smtp_user, mail_smtp_password) + smtpObj.send_message(msg) + logging('localhost', 'An email has been sent to ' + email_to , haproxywi=1) + except Exception as e: + logging('localhost', 'error: unable to send email: ' + str(e), haproxywi=1) + + +def send_email_to_server_group(subject: str, mes: str, group_id: int) -> None: + import sql + + try: + users_email = sql.select_users_emails_by_group_id(group_id) + + for user_email in users_email: + send_email(user_email.email, subject, mes) + except Exception as e: + logging('localhost', 'error: unable to send email: ' + str(e), haproxywi=1) + + +def alert_routing( + server_ip: str, service_id: int, group_id: int, level: str, mes: str, alert_type: str) -> None: + import json + import sql + + subject: str = level + ': ' + mes + server_id: int = sql.select_server_id_by_ip(server_ip) + checker_settings = sql.select_checker_settings_for_server(service_id, server_id) + + try: + json_for_sending = {"user_group": group_id, "message": subject} + send_message_to_rabbit(json.dumps(json_for_sending)) + except Exception as e: + logging('localhost', 'error: unable to send message: ' + str(e), haproxywi=1) + + for setting in checker_settings: + if alert_type == 'service' and setting.service_alert: + telegram_send_mess(mes, telegram_channel_id=setting.telegram_id) + slack_send_mess(mes, slack_channel_id=setting.slack_id) + + if setting.email: + send_email_to_server_group(subject, mes, group_id) + + if alert_type == 'backend' and setting.backend_alert: + telegram_send_mess(mes, telegram_channel_id=setting.telegram_id) + slack_send_mess(mes, slack_channel_id=setting.slack_id) + + if setting.email: + send_email_to_server_group(subject, mes, group_id) + + if alert_type == 'maxconn' and setting.maxconn_alert: + telegram_send_mess(mes, telegram_channel_id=setting.telegram_id) + slack_send_mess(mes, slack_channel_id=setting.slack_id) + + if setting.email: + send_email_to_server_group(subject, mes, group_id) diff --git a/app/login.py b/app/login.py index c2f305db..6317a685 100644 --- a/app/login.py +++ b/app/login.py @@ -102,7 +102,7 @@ def send_cookie(login): else: sql.insert_user_name(user_name) except Exception: - pass + funct.logging('Cannot update sbscription ', str(e), haproxywi=1) sys.exit() diff --git a/app/options.py b/app/options.py index 7f3f702d..68885ddb 100644 --- a/app/options.py +++ b/app/options.py @@ -1798,7 +1798,7 @@ if form.getvalue('haproxyaddserv'): if form.getvalue('installwaf'): funct.waf_install(form.getvalue('installwaf')) -if form.getvalue('update_haproxy_wi'): +if form.getvalue('update_roxy_wi'): service = form.getvalue('service') services = ['roxy-wi-checker', 'roxy-wi', @@ -1809,7 +1809,7 @@ if form.getvalue('update_haproxy_wi'): if service not in services: print('error: ' + service + ' is not part of Roxy-WI') sys.exit() - funct.update_haproxy_wi(service) + funct.update_roxy_wi(service) if form.getvalue('metrics_waf'): sql.update_waf_metrics_enable(form.getvalue('metrics_waf'), form.getvalue('enable')) @@ -2269,7 +2269,7 @@ if form.getvalue('newserver') is not None: haproxy_config_path = sql.get_setting('haproxy_config_path') haproxy_dir = sql.get_setting('haproxy_dir') apache_config_path = sql.get_setting('apache_config_path') - keepalived_config_path = '/etc/keepalived/keepalived.conf' + keepalived_config_path = sql.get_setting('keepalived_config_path') if funct.is_file_exists(ip, nginx_config_path): sql.update_nginx(ip) @@ -2289,8 +2289,13 @@ if form.getvalue('newserver') is not None: if funct.is_service_active(ip, 'firewalld'): sql.update_firewall(ip) - except Exception: - pass + except Exception as e: + funct.logging('Cannot scan a new server ' + hostname, str(e), haproxywi=1) + + try: + sql.insert_new_checker_setting_for_server(ip) + except Exception as e: + funct.logging('Cannot insert Checker settings for ' + hostname, str(e), haproxywi=1) try: funct.get_system_info(ip) @@ -2491,7 +2496,11 @@ if form.getvalue('ssh_cert'): user_group = funct.get_user_group() name = form.getvalue('name') - key = paramiko.pkey.load_private_key(form.getvalue('ssh_cert')) + try: + key = paramiko.pkey.load_private_key(form.getvalue('ssh_cert')) + except Exception as e: + print('error: Cannot save SSH key file: ', str(e)) + full_dir = '/var/www/haproxy-wi/keys/' ssh_keys = full_dir + name + '.pem' @@ -2515,8 +2524,8 @@ if form.getvalue('ssh_cert'): # key.write_private_key_file(ssh_keys, password=cloud) # else: key.write_private_key_file(ssh_keys) - except IOError as e: - print('error: Cannot save SSH key file. ', str(e)) + except Exception as e: + print('error: Cannot save SSH key file: ', str(e)) else: print('success: SSH key has been saved into: %s ' % ssh_keys) @@ -2614,7 +2623,7 @@ if form.getvalue('updatesettings') is not None: settings = form.getvalue('updatesettings') val = form.getvalue('val') if sql.update_setting(settings, val): - funct.logging('localhost', 'The ' + settings + ' setting has been changed to: ' + val, haproxywi=1, login=1) + funct.logging('localhost', 'The ' + settings + ' setting has been changed to: ' + str(val), haproxywi=1, login=1) print("Ok") if form.getvalue('getuserservices'): @@ -3921,19 +3930,32 @@ if form.getvalue('loadchecker'): services = funct.get_services_status() groups = sql.select_groups() page = form.getvalue('page') + try: user_status, user_plan = funct.return_user_status() except Exception as e: user_status, user_plan = 0, 0 funct.logging('localhost', 'Cannot get a user plan: ' + str(e), haproxywi=1) if user_status: + haproxy_settings = sql.select_checker_settings(1) + nginx_settings = sql.select_checker_settings(2) + keepalived_settings = sql.select_checker_settings(3) + apache_settings = sql.select_checker_settings(4) if page == 'servers.py': user_group = funct.get_user_group(id=1) telegrams = sql.get_user_telegram_by_group(user_group) slacks = sql.get_user_slack_by_group(user_group) + haproxy_servers = sql.get_dick_permit(haproxy=1, only_group=1) + nginx_servers = sql.get_dick_permit(nginx=1, only_group=1) + apache_servers = sql.get_dick_permit(apache=1, only_group=1) + keepalived_servers = sql.get_dick_permit(keepalived=1, only_group=1) else: telegrams = sql.select_telegram() slacks = sql.select_slack() + haproxy_servers = sql.get_dick_permit(haproxy=1) + nginx_servers = sql.get_dick_permit(nginx=1) + apache_servers = sql.get_dick_permit(apache=1) + keepalived_servers = sql.get_dick_permit(keepalived=1) else: telegrams = '' slacks = '' @@ -3944,6 +3966,14 @@ if form.getvalue('loadchecker'): slacks=slacks, user_status=user_status, user_plan=user_plan, + haproxy_servers=haproxy_servers, + nginx_servers=nginx_servers, + apache_servers=apache_servers, + keepalived_servers=keepalived_servers, + haproxy_settings=haproxy_settings, + nginx_settings=nginx_settings, + keepalived_settings=keepalived_settings, + apache_settings=apache_settings, page=page) print(template) @@ -4010,6 +4040,50 @@ if form.getvalue('check_slack'): mess = 'Test message from Roxy-WI' funct.slack_send_mess(mess, slack_channel_id=slack_id) +if form.getvalue('check_rabbitmq_alert'): + import json + import http.cookies + + try: + cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) + user_group_id = cookie.get('group') + user_group_id1 = user_group_id.value + except Exception as e: + error = str(e) + print(f'error: Cannot send a message {error}') + + try: + json_for_sending = {"user_group": user_group_id1, "message": 'info: Test message'} + funct.send_message_to_rabbit(json.dumps(json_for_sending)) + except Exception as e: + error = str(e) + print(f'error: Cannot send a message {error}') + +if form.getvalue('check_email_alert'): + import http.cookies + subject = 'test message' + message = 'Test message from Roxy-WI' + + try: + cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) + user_uuid = cookie.get('uuid') + user_uuid_value = user_uuid.value + except Exception as e: + error = str(e) + print(f'error: Cannot send a message {error}') + + try: + user_email = sql.select_user_email_by_uuid(user_uuid_value) + except Exception as e: + error = str(e) + print(f'error: Cannot get a user email: {error}') + + try: + funct.send_email(user_email, subject, message) + except Exception as e: + error = str(e) + print(f'error: Cannot send a message {error}') + if form.getvalue('getoption'): group = form.getvalue('getoption') term = form.getvalue('term') @@ -4360,3 +4434,45 @@ if form.getvalue('show_sub_ovw'): template = env.get_template('ajax/show_sub_ovw.html') template = template.render(sub=sql.select_user_all()) print(template) + + +if form.getvalue('updateHaproxyCheckerSettings'): + setting_id = form.getvalue('updateHaproxyCheckerSettings') + email = form.getvalue('email') + service_alert = form.getvalue('server') + backend_alert = form.getvalue('backend') + maxconn_alert = form.getvalue('maxconn') + telegram_id = form.getvalue('telegram_id') + slack_id = form.getvalue('slack_id') + + if sql.update_haproxy_checker_settings(email, telegram_id, slack_id, service_alert, backend_alert, + maxconn_alert, setting_id + ): + print('ok') + else: + print('error: Cannot update Checker settings') + +if form.getvalue('updateKeepalivedCheckerSettings'): + setting_id = form.getvalue('updateKeepalivedCheckerSettings') + email = form.getvalue('email') + service_alert = form.getvalue('server') + backend_alert = form.getvalue('backend') + telegram_id = form.getvalue('telegram_id') + slack_id = form.getvalue('slack_id') + + if sql.update_keepalived_checker_settings(email, telegram_id, slack_id, service_alert, backend_alert, setting_id): + print('ok') + else: + print('error: Cannot update Checker settings') + +if form.getvalue('updateServiceCheckerSettings'): + setting_id = form.getvalue('updateServiceCheckerSettings') + email = form.getvalue('email') + service_alert = form.getvalue('server') + telegram_id = form.getvalue('telegram_id') + slack_id = form.getvalue('slack_id') + + if sql.update_service_checker_settings(email, telegram_id, slack_id, service_alert, setting_id): + print('ok') + else: + print('error: Cannot update Checker settings') diff --git a/app/overview.py b/app/overview.py index 3732a806..892c436f 100644 --- a/app/overview.py +++ b/app/overview.py @@ -31,9 +31,9 @@ try: i += 1 - cmd = "ps ax |grep 'metrics_worker\|metrics_waf_worker.py\|metrics_nginx_worker.py'|grep -v grep|grep '%s' |wc -l" % servers_for_grep + cmd = "ps ax |grep '[m]etrics_worker\|[m]etrics_waf_worker.py\|[m]etrics_nginx_worker.py'|grep '%s' |wc -l" % servers_for_grep metrics_worker, stderr = funct.subprocess_execute(cmd) - cmd = "ps ax |grep 'checker_worker\|checker_nginx'|grep -v grep |grep '%s' |wc -l" % servers_for_grep + cmd = "ps ax |grep '[c]hecker_worker\|[c]hecker_nginx\|[c]hecker_apache\|[c]hecker_keepalived'|grep -v grep |grep '%s' |wc -l" % servers_for_grep checker_worker, stderr = funct.subprocess_execute(cmd) i = 0 for s in sql.select_all_alerts(group=user_group): @@ -48,9 +48,9 @@ try: prometheus = '' host = '' else: - cmd = "ps ax |grep 'metrics_worker\|metrics_waf_worker.py\|metrics_nginx_worker.py' |grep -v grep |wc -l" + cmd = "ps ax |grep '[m]etrics_worker\|[m]etrics_waf_worker.py\|[m]etrics_nginx_worker.py' |wc -l" metrics_worker, stderr = funct.subprocess_execute(cmd) - cmd = "ps ax |grep 'checker_worker\|checker_nginx' |grep -v grep |wc -l" + cmd = "ps ax |grep '[c]hecker_worker\|[c]hecker_nginx\|[c]hecker_apache\|[c]hecker_keepalived' |wc -l" checker_worker, stderr = funct.subprocess_execute(cmd) i = 0 for s in sql.select_all_alerts(): @@ -61,7 +61,7 @@ try: for s in is_metrics_workers: i += 1 is_metrics_worker = i - cmd = "ps ax |grep grafana|grep -v grep|wc -l" + cmd = "ps ax |egrep [g]rafana|wc -l" grafana, stderr = funct.subprocess_execute(cmd) host = os.environ.get('HTTP_HOST', '') diff --git a/app/sections.py b/app/sections.py index 29aed6b0..8d92e470 100644 --- a/app/sections.py +++ b/app/sections.py @@ -22,6 +22,7 @@ error = "" aftersave = "" start_line = "" end_line = "" +warning = '' try: user, user_id, role, token, servers, user_services = funct.get_users_params() @@ -73,6 +74,7 @@ if serv is not None and form.getvalue('config') is not None: stderr = funct.master_slave_upload_and_restart(serv, cfg, just_save=save, oldcfg=oldcfg) if "is valid" in stderr: + warning = stderr stderr = '' funct.diff_config(oldcfg, cfg) @@ -84,6 +86,6 @@ rendered_template = template.render( h2=1, title="Working with HAProxy config sections", role=role, action="sections.py", user=user, select_id="serv", serv=serv, aftersave=aftersave, config=config_read, cfg=cfg, selects=servers, stderr=stderr, error=error, start_line=start_line, end_line=end_line, section=section, sections=sections, is_serv_protected=is_serv_protected, - user_services=user_services, token=token + user_services=user_services, token=token, warning=warning ) print(rendered_template) diff --git a/app/servers.py b/app/servers.py index d15767e5..4c7fbbc8 100644 --- a/app/servers.py +++ b/app/servers.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +import pytz + import funct import sql from jinja2 import Environment, FileSystemLoader @@ -32,6 +34,6 @@ rendered_template = template.render( masters=sql.select_servers(get_master_servers=1, uuid=user_id.value), group=user_group, sshs=sql.select_ssh(group=user_group), token=token, settings=settings, backups=sql.select_backups(), page="servers.py", geoip_country_codes=geoip_country_codes, user_services=user_services, ldap_enable=ldap_enable, - user_status=user_status, user_plan=user_plan, gits=gits, services=services + user_status=user_status, user_plan=user_plan, gits=gits, services=services, timezones=pytz.all_timezones ) print(rendered_template) diff --git a/app/sql.py b/app/sql.py index 5a8c1375..c21309da 100755 --- a/app/sql.py +++ b/app/sql.py @@ -185,28 +185,23 @@ def add_setting_for_new_group(group_id): 'desc': 'Path to the NGINX directory with config files', 'group': group_id}, {'param': 'nginx_config_path', 'value': '/etc/nginx/nginx.conf', 'section': 'nginx', 'desc': 'Path to the main NGINX configuration file', 'group': group_id}, - {'param': 'ldap_enable', 'value': '0', 'section': 'ldap', 'desc': 'Enable LDAP (1 - yes, 0 - no)', - 'group': group_id}, - {'param': 'ldap_server', 'value': '', 'section': 'ldap', 'desc': 'IP address of the LDAP server', - 'group': group_id}, + {'param': 'ldap_enable', 'value': '0', 'section': 'ldap', 'desc': 'Enable LDAP', 'group': group_id}, + {'param': 'ldap_server', 'value': '', 'section': 'ldap', 'desc': 'IP address of the LDAP server', 'group': group_id}, {'param': 'ldap_port', 'value': '389', 'section': 'ldap', - 'desc': 'LDAP port (port 389 or 636 is used by default)', - 'group': group_id}, + 'desc': 'LDAP port (port 389 or 636 is used by default)', 'group': group_id}, {'param': 'ldap_user', 'value': '', 'section': 'ldap', 'desc': 'LDAP username. Format: user@domain.com', 'group': group_id}, {'param': 'ldap_password', 'value': '', 'section': 'ldap', 'desc': 'LDAP password', 'group': group_id}, {'param': 'ldap_base', 'value': '', 'section': 'ldap', 'desc': 'Base domain. Example: dc=domain, dc=com', 'group': group_id}, - {'param': 'ldap_domain', 'value': '', 'section': 'ldap', 'desc': 'LDAP domain for logging in', - 'group': group_id}, + {'param': 'ldap_domain', 'value': '', 'section': 'ldap', 'desc': 'LDAP domain for logging in', 'group': group_id}, {'param': 'ldap_class_search', 'value': 'user', 'section': 'ldap', 'desc': 'Class for searching the user', 'group': group_id}, {'param': 'ldap_user_attribute', 'value': 'sAMAccountName', 'section': 'ldap', 'desc': 'Attribute to search users by', 'group': group_id}, {'param': 'ldap_search_field', 'value': 'mail', 'section': 'ldap', 'desc': 'User\'s email address', 'group': group_id}, - {'param': 'ldap_type', 'value': '0', 'section': 'ldap', 'desc': 'Use LDAPS (1 - yes, 0 - no)', - 'group': group_id}, + {'param': 'ldap_type', 'value': '0', 'section': 'ldap', 'desc': 'Use LDAPS', 'group': group_id}, {'param': 'apache_path_logs', 'value': '/var/log/httpd/', 'section': 'apache', 'desc': 'The path for Apache logs', 'group': group_id}, {'param': 'apache_stats_user', 'value': 'admin', 'section': 'apache', @@ -490,6 +485,15 @@ def select_server_id_by_ip(server_ip): return server_id +def select_server_group_by_ip(server_ip): + try: + groups = Server.get(Server.ip == server_ip).groups + except Exception as e: + return out_error(e) + else: + return groups + + def select_server_ip_by_id(server_id): try: server_ip = Server.get(Server.server_id == server_id).ip @@ -3406,3 +3410,108 @@ def delete_git(git_id): return False else: return True + + +def select_users_emails_by_group_id(group_id: int): + query = User.select(User.email).where((User.groups == group_id) & (User.role != 'guest')) + try: + query_res = query.execute() + except Exception as e: + out_error(e) + return + else: + return query_res + + +def select_user_email_by_uuid(uuid: str) -> str: + user_id = get_user_id_by_uuid(uuid) + try: + query_res = User.get(User.user_id == user_id).email + except Exception as e: + out_error(e) + return "" + else: + return query_res + + +def select_checker_settings(service_id: int): + query = CheckerSetting.select().where(CheckerSetting.service_id == service_id) + try: + query_res = query.execute() + except Exception as e: + out_error(e) + return + else: + return query_res + + +def select_checker_settings_for_server(service_id: int, server_id: int): + query = CheckerSetting.select().where( + (CheckerSetting.service_id == service_id) + & (CheckerSetting.server_id == server_id) + ) + try: + query_res = query.execute() + except Exception as e: + out_error(e) + return + else: + return query_res + + +def insert_new_checker_setting_for_server(server_ip: str) -> None: + try: + server_id = Server.get(Server.ip == server_ip).server_id + except Exception as e: + out_error(e) + + for service_id in range(1, 5): + CheckerSetting.insert( + server_id=server_id, service_id=service_id + ).on_conflict_ignore().execute() + + +def update_haproxy_checker_settings( + email: int, telegram_id: int, slack_id: int, service_alert: int, backend_alert: int, + maxconn_alert: int, setting_id: int +) -> bool: + settings_update = CheckerSetting.update( + email=email, telegram_id=telegram_id, slack_id=slack_id, service_alert=service_alert, + backend_alert=backend_alert, maxconn_alert=maxconn_alert + ).where(CheckerSetting.id == setting_id) + try: + settings_update.execute() + except Exception: + return False + else: + return True + + +def update_keepalived_checker_settings( + email: int, telegram_id: int, slack_id: int, service_alert: int, backend_alert: int, + setting_id: int +) -> bool: + settings_update = CheckerSetting.update( + email=email, telegram_id=telegram_id, slack_id=slack_id, + service_alert=service_alert, backend_alert=backend_alert + ).where(CheckerSetting.id == setting_id) + try: + settings_update.execute() + except Exception: + return False + else: + return True + + +def update_service_checker_settings( + email: int, telegram_id: int, slack_id: int, service_alert: int, setting_id: int +) -> bool: + settings_update = CheckerSetting.update( + email=email, telegram_id=telegram_id, slack_id=slack_id, service_alert=service_alert + ).where(CheckerSetting.id == setting_id) + try: + settings_update.execute() + except Exception: + return False + else: + return True diff --git a/app/templates/admin.html b/app/templates/admin.html index a873afcc..0a819dce 100644 --- a/app/templates/admin.html +++ b/app/templates/admin.html @@ -111,12 +111,10 @@ Service - Current version - Latest version - - - Description - + Current version + Latest version + + Description diff --git a/app/templates/ajax/load_telegram.html b/app/templates/ajax/load_telegram.html index 0a4ef85c..c267d09f 100644 --- a/app/templates/ajax/load_telegram.html +++ b/app/templates/ajax/load_telegram.html @@ -1,128 +1,433 @@ -{% from 'include/input_macros.html' import input, select %} +{% from 'include/input_macros.html' import input, select, checkbox %} {% if user_status == 0 %} {% include 'include/no_sub.html' %} {% else %} + + {% for s in services %} -{% if s.0 == 'roxy-wi-checker' %} - {% if s.3 != '* is not installed' and s.3 != '' %} - - - - - - {% if page != "servers.py" %} - - {% endif %} - - - - - {% for telegram in telegrams %} - - - - {% if page != "servers.py" %} - - {% endif %} - - - - - {% endfor %} -

Add Telegram channel

- Token - Channel nameGroup
- {% set id = 'telegram-token-' + telegram.id|string() %} - {{ input(id, value=telegram.token, size='30') }} - - {% set id = 'telegram-chanel-' + telegram.id|string() %} - {{ input(id, value=telegram.chanel_name, size='30') }} - - - - - - - - -
-
+ Add -

- - - - - - {% if page != "servers.py" %} - - {% endif %} - - - - - {% for slack in slacks %} - - - - {% if page != "servers.py" %} - - {% endif %} - - - - - {% endfor %} -

Add Slack channel

- Token - Channel nameGroup
- {% set id = 'slack-token-' + slack.id|string() %} - {{ input(id, value=slack.token, size='30') }} - - {% set id = 'slack-chanel-' + slack.id|string() %} - {{ input(id, value=slack.chanel_name, size='30') }} - - - - - - - - -
-
+ Add -

-
-
- You can read the description of all parameters here, - How to create and use Telegram bot in this article, - How to create and use Slack APP in this article -
- {% else %} -
-
-

You have not installed Backends checker - Read hear - how to install Checker service

+ {% if s.0 == 'roxy-wi-checker' %} + {% if s.3 == '* is not installed' and s.3 == '' %} +
+
+

You have not installed Backends checker + Read hear + how to install Checker service

+
+ {% else %} +
+ +
+ + + + + + {% if page != "servers.py" %} + + {% endif %} + + + + + {% for telegram in telegrams %} + + + + {% if page != "servers.py" %} + + {% endif %} + + + + + {% endfor %} +

Telegram channels

+ Token + Channel nameGroup
+ {% set id = 'telegram-token-' + telegram.id|string() %} + {{ input(id, value=telegram.token, size='30') }} + + {% set id = 'telegram-chanel-' + telegram.id|string() %} + {{ input(id, value=telegram.chanel_name, size='30') }} + + + + + + + + +
+
+ Add +

+ + + + + + {% if page != "servers.py" %} + + {% endif %} + + + + + {% for slack in slacks %} + + + + {% if page != "servers.py" %} + + {% endif %} + + + + + {% endfor %} +

Slack channels

+ Token + Channel nameGroup
+ {% set id = 'slack-token-' + slack.id|string() %} + {{ input(id, value=slack.token, size='30') }} + + {% set id = 'slack-chanel-' + slack.id|string() %} + {{ input(id, value=slack.chanel_name, size='30') }} + + + + + + + + +
+
+ Add +

+ + + + + + + + + + +

Test messages

EmailWeb panel
+ + + +
+

+
+
+ You can read the description of all parameters here, + How to create and use Telegram bot in this article, + How to create and use Slack APP in this article
- {% endif %} +
+
+ + + + + + + + + + + + + {% for s in haproxy_servers %} + {% for h in haproxy_settings %} + {% if h.server_id|string() == s.0|string() and h.service_id == 1 %} + + + + + + + + + + + {% endif %} + {% endfor %} + {% endfor %} +

HAProxy servers

ServerTelegramSlackEmailServiceBackendMaxconn
{{s.1}} + + + + + {% set id = 'haproxy_server_email-' + h.id|string() %} + {% if h.email == 1 %} + {{ checkbox(id, checked='checked') }} + {% else %} + {{ checkbox(id) }} + {% endif %} + + {% set id = 'haproxy_server_status-' + h.id|string() %} + {% if h.service_alert == 1 %} + {{ checkbox(id, checked='checked', title='Alert about changing service status') }} + {% else %} + {{ checkbox(id, title='Alert about changing service status') }} + {% endif %} + + {% set id = 'haproxy_server_backend-' + h.id|string() %} + {% if h.backend_alert == 1 %} + {{ checkbox(id, checked='checked', title='Alert about changing backend status') }} + {% else %} + {{ checkbox(id, title='Alert about changing backend status') }} + {% endif %} + + {% set id = 'haproxy_server_maxconn-' + h.id|string() %} + {% if h.maxconn_alert == 1 %} + {{ checkbox(id, checked='checked', title='Alert if the number of connections is about to reach the limit') }} + {% else %} + {{ checkbox(id, title='Alert if the number of connections is about to reach the limit') }} + {% endif %} +
+ + + + + + + + + + + {% for s in nginx_servers %} + {% for h in nginx_settings %} + {% if h.server_id|string() == s.0|string() and h.service_id == 2 %} + + + + + + + + + {% endif %} + {% endfor %} + {% endfor %} +

NGINX servers

ServerTelegramSlackEmailService
{{s.1}} + + + + + {% set id = 'nginx_server_email-' + h.id|string() %} + {% if h.email == 1 %} + {{ checkbox(id, checked='checked', title='Alert via email') }} + {% else %} + {{ checkbox(id, title='Alert via email') }} + {% endif %} + + {% set id = 'nginx_server_status-' + h.id|string() %} + {% if h.service_alert == 1 %} + {{ checkbox(id, checked='checked', title='Alert about changing service status') }} + {% else %} + {{ checkbox(id, title='Alert about changing service status') }} + {% endif %} +
+ + + + + + + + + + + {% for s in apache_servers %} + {% for h in apache_settings %} + {% if h.server_id|string() == s.0|string() and h.service_id == 4 %} + + + + + + + + + {% endif %} + {% endfor %} + {% endfor %} +

Apache servers

ServerTelegramSlackEmailService
{{s.1}} + + + + + {% set id = 'apache_server_email-' + h.id|string() %} + {% if h.email == 1 %} + {{ checkbox(id, checked='checked', title='Alert via email') }} + {% else %} + {{ checkbox(id, title='Alert via email') }} + {% endif %} + + {% set id = 'apache_server_status-' + h.id|string() %} + {% if h.service_alert == 1 %} + {{ checkbox(id, checked='checked', title='Alert about changing service status') }} + {% else %} + {{ checkbox(id, title='Alert about changing service status') }} + {% endif %} +
+ + + + + + + + + + + + {% for s in keepalived_servers %} + {% for h in keepalived_settings %} + {% if h.server_id|string() == s.0|string() and h.service_id == 3 %} + + + + + + + + + + {% endif %} + {% endfor %} + {% endfor %} +

Keepalived servers

ServerTelegramSlackEmailServiceStatus
{{s.1}} + + + + + {% set id = 'keepalived_server_email-' + h.id|string() %} + {% if h.email == 1 %} + {{ checkbox(id, checked='checked', title='Alert via email') }} + {% else %} + {{ checkbox(id, title='Alert via email') }} + {% endif %} + + {% set id = 'keepalived_server_status-' + h.id|string() %} + {% if h.service_alert == 1 %} + {{ checkbox(id, checked='checked', title='Alert about changing service status') }} + {% else %} + {{ checkbox(id, title='Alert about changing service status') }} + {% endif %} + + {% set id = 'keepalived_server_backend-' + h.id|string() %} + {% if h.backend_alert == 1 %} + {{ checkbox(id, checked='checked', title='Alert about changing Master/Backup status') }} + {% else %} + {{ checkbox(id, title='Alert about changing Master/Backup status') }} + {% endif %} +
+
+
+{% endif %} {% endif %} {% endfor %} -{% endif %} \ No newline at end of file +{% endif %} diff --git a/app/templates/ajax/load_updatehapwi.html b/app/templates/ajax/load_updatehapwi.html index b22ccd34..ff1b89ad 100644 --- a/app/templates/ajax/load_updatehapwi.html +++ b/app/templates/ajax/load_updatehapwi.html @@ -33,7 +33,7 @@ {% for s in services %} - {% if s.0 == 'roxy-wi-smon' or s.0 == 'roxy-wi-checker' or s.0 == 'roxy-wi-keep_alive' or s.0 == 'roxy-wi-metrics' or s.0 == 'roxy-wi-portscanner' or s.0 == 'roxy-wi-socket' %} + {% if s.0 in ('roxy-wi-smon', 'roxy-wi-checker', 'roxy-wi-keep_alive', 'roxy-wi-metrics', 'roxy-wi-portscanner', 'roxy-wi-socket') %} {% set is_need_update = 0 %} {% if s.0 == 'roxy-wi-smon' %} @@ -43,6 +43,7 @@ {% if s.3|float < smon_ver|float %} {% set is_need_update = 1 %} {% endif %} + {% set description = 'SMON stands for Simple MONitoring' %} {% elif s.0 == 'roxy-wi-checker' %} {% set service_name = 'Checker' %} {% set service_link = 'checker' %} @@ -50,6 +51,7 @@ {% if s.3|float < checker_ver|float %} {% set is_need_update = 1 %} {% endif %} + {% set description = 'Checker is designed for monitoring HAProxy, Nginx, Apache and Keepalived services as well as HAProxy backends' %} {% elif s.0 == 'roxy-wi-keep_alive' %} {% set service_name = 'Auto start' %} {% set service_link = 'auto_start' %} @@ -57,6 +59,7 @@ {% if s.3|float < keep_ver|float %} {% set is_need_update = 1 %} {% endif %} + {% set description = 'The Auto Start service allows to restart the HAProxy, NGINX, Apache and Keepalived services if they are down' %} {% elif s.0 == 'roxy-wi-metrics' %} {% set service_name = 'Metrics' %} {% set service_link = 'metrics' %} @@ -64,23 +67,26 @@ {% if s.3|float < metrics_ver|float %} {% set is_need_update = 1 %} {% endif %} + {% set description = 'Collects number of connections for HAProxy, NGINX and WAF services' %} {% elif s.0 == 'roxy-wi-portscanner' %} {% set service_name = 'Port scanner' %} {% set service_link = 'portscanner' %} - {% set desc_link = 'https://roxy-wi.org/services.py?service={{service_link}}' %} + {% set desc_link = 'https://roxy-wi.org/services.py?service=' + service_link %} {% if s.3|float < portscanner_ver|float %} {% set is_need_update = 1 %} {% endif %} + {% set description = 'Probes and saves a server or host for open ports' %} {% elif s.0 == 'roxy-wi-socket' %} {% set service_name = 'Socket service' %} {% set service_link = 'socket' %} - {% set desc_link = 'https://roxy-wi.org/services.py?service={{service_link}}' %} + {% set desc_link = 'https://roxy-wi.org/services.py?service=' + service_link %} {% if s.3|float < socket_ver|float %} {% set is_need_update = 1 %} {% endif %} + {% set description = 'Socket is a service for sending alerts and notifications' %} {% endif %} - {{service_name}} + {{service_name}} {% if s.3 != '* is not installed' %} @@ -120,13 +126,12 @@ Update {% endif %} {% else %} - Read about installation + Install {% endif %} - - Read more about {{service_name}} + + {{description}} - {% endif %} {% endfor %} \ No newline at end of file diff --git a/app/templates/ajax/new_slack.html b/app/templates/ajax/new_slack.html index a5be0f6f..aa1c3c53 100644 --- a/app/templates/ajax/new_slack.html +++ b/app/templates/ajax/new_slack.html @@ -24,7 +24,7 @@ - + diff --git a/app/templates/ajax/new_telegram.html b/app/templates/ajax/new_telegram.html index 33bb6e82..53e98075 100644 --- a/app/templates/ajax/new_telegram.html +++ b/app/templates/ajax/new_telegram.html @@ -1,11 +1,11 @@ {% for telegram in telegrams %} - + - + {% if page != "servers.py" %} @@ -21,7 +21,7 @@ {% endif %} - + diff --git a/app/templates/ajax/show_sub_ovw.html b/app/templates/ajax/show_sub_ovw.html index 2a00a11b..c2535738 100644 --- a/app/templates/ajax/show_sub_ovw.html +++ b/app/templates/ajax/show_sub_ovw.html @@ -3,6 +3,8 @@ {% set plan = 'Home' %} {% elif s.Plan == 'company' %} {% set plan = 'Enterprise' %} + {% elif s.Plan == 'cloud' %} + {% set plan = 'Cloud' %} {% elif s.Plan == 'support' %} {% set plan = 'Premium' %} {% elif s.Plan == 'Trial' %} @@ -32,7 +34,6 @@ Pay method - {% if plan == 'Free' %} N/A diff --git a/app/templates/base.html b/app/templates/base.html index 56a80e4f..823f05a3 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -143,8 +143,9 @@ Servers