diff --git a/api/api.py b/api/api.py index e58f33ac..0111ed68 100644 --- a/api/api.py +++ b/api/api.py @@ -52,7 +52,7 @@ def index(): 'server': 'create a new server inside a group. Must be JSON body: hostname, ip, port, virt: enter 0 if is not Virtual IP, group_id, master_id: enter 0 if is not slave, cred_id, description. METHOD: POST', 'server/ssh': 'show info about all SSH credentials inside a group. METHOD: GET', 'server/ssh': 'create a new SSH credentials inside a group. Must be JSON body: name, key_enabled, username, password. METHOD: POST', - 'server/ssh/key': 'upload a new SSH key inside a group. Must be JSON body: name, key. Name it is credentials name, in key new lines must be replaced with "\n" METHOD: POST', + 'server/ssh/key': 'upload a new SSH key inside a group. Must be JSON body: name, key, passphrase (could be empty). Name it is credentials name, in key new lines must be replaced with "\n" METHOD: POST', 'servers/status': 'show status all HAProxyes. METHOD: GET', 'haproxy/': 'show info about the HAProxy by id or hostname or ip. METHOD: GET', 'haproxy//status': 'show HAProxy status by id or hostname or ip. METHOD: GET', diff --git a/api/api_funct.py b/api/api_funct.py index 60e58cc7..3795f538 100644 --- a/api/api_funct.py +++ b/api/api_funct.py @@ -792,13 +792,14 @@ def upload_ssh_key(): json_loads = json.loads(body) name = json_loads['name'] key = json_loads['key'] + passphrase = json_loads['passphrase'] token = request.headers.get('token') login, group_id, role_id = sql.get_username_groupid_from_api_token(token) groups = sql.select_groups(id=group_id) for group in groups: user_group = group.name try: - ssh_mod.upload_ssh_key(f'{name}_{user_group}', user_group, key) + ssh_mod.upload_ssh_key(f'{name}_{user_group}', user_group, key, passphrase) data = {'status': 'done'} return dict(data) except Exception as e: diff --git a/app/create_db.py b/app/create_db.py index b5dc8982..fcb1c60a 100644 --- a/app/create_db.py +++ b/app/create_db.py @@ -24,10 +24,10 @@ def default_values(): {'param': 'syslog_server_enable', 'value': '0', 'section': 'logs', 'desc': 'Enable getting logs from a syslog server', 'group': '1'}, {'param': 'syslog_server', 'value': '', 'section': 'logs', 'desc': 'IP address of the syslog_server', 'group': '1'}, {'param': 'log_time_storage', 'value': '14', 'section': 'logs', 'desc': 'Retention period for user activity logs (in days)', 'group': '1'}, - {'param': 'stats_user', 'value': 'admin', 'section': 'haproxy', 'desc': 'Username for accessing HAProxy stats page', 'group': '1'}, - {'param': 'stats_password', 'value': 'password', 'section': 'haproxy', 'desc': 'Password for accessing HAProxy stats page', 'group': '1'}, - {'param': 'stats_port', 'value': '8085', 'section': 'haproxy', 'desc': 'Port for HAProxy stats page', 'group': '1'}, - {'param': 'stats_page', 'value': 'stats', 'section': 'haproxy', 'desc': 'URI for HAProxy stats page', 'group': '1'}, + {'param': 'haproxy_stats_user', 'value': 'admin', 'section': 'haproxy', 'desc': 'Username for accessing HAProxy stats page', 'group': '1'}, + {'param': 'haproxy_stats_password', 'value': 'password', 'section': 'haproxy', 'desc': 'Password for accessing HAProxy stats page', 'group': '1'}, + {'param': 'haproxy_stats_port', 'value': '8085', 'section': 'haproxy', 'desc': 'Port for HAProxy stats page', 'group': '1'}, + {'param': 'haproxy_stats_page', 'value': 'stats', 'section': 'haproxy', 'desc': 'URI for HAProxy stats page', 'group': '1'}, {'param': 'haproxy_dir', 'value': '/etc/haproxy', 'section': 'haproxy', 'desc': 'Path to the HAProxy directory', 'group': '1'}, {'param': 'haproxy_config_path', 'value': '/etc/haproxy/haproxy.cfg', 'section': 'haproxy', 'desc': 'Path to the HAProxy configuration file', 'group': '1'}, {'param': 'server_state_file', 'value': '/etc/haproxy/haproxy.state', 'section': 'haproxy', 'desc': 'Path to the HAProxy state file', 'group': '1'}, @@ -636,7 +636,7 @@ def update_db_v_6_3_13_4(): def update_db_v_6_3_13_5(): try: SMON.update(check_type='http').where(SMON.http != '').execute() - except Exception: + except Exception as e: print("An error occurred:", e) @@ -658,9 +658,33 @@ def update_db_v_6_3_18(): print("Updating... DB has been updated to version 6.3.18") +def update_db_v_7_1_2(): + try: + Setting.delete().where(Setting.param == 'stats_user').execute() + Setting.delete().where(Setting.param == 'stats_password').execute() + Setting.delete().where(Setting.param == 'stats_port').execute() + Setting.delete().where(Setting.param == 'stats_page').execute() + except Exception as e: + print("An error occurred:", e) + else: + print("Updating... DB has been updated to version 7.1.2") + + +def update_db_v_7_1_2_1(): + try: + migrate( + migrator.add_column('cred', 'passphrase', CharField(null=True)) + ) + except Exception as e: + if e.args[0] == 'duplicate column name: passphrase' or str(e) == '(1060, "Duplicate column name \'passphrase\'")': + print('Updating... DB has been updated to version 7.1.2-1') + else: + print("An error occurred:", e) + + def update_ver(): try: - Version.update(version='7.1.1.0').execute() + Version.update(version='7.1.2.0').execute() except Exception: print('Cannot update version') @@ -692,6 +716,8 @@ def update_all(): update_db_v_6_3_13_5() update_db_v_6_3_17() update_db_v_6_3_18() + update_db_v_7_1_2() + update_db_v_7_1_2_1() update_ver() diff --git a/app/login.py b/app/login.py index cb3efab6..61e6c272 100644 --- a/app/login.py +++ b/app/login.py @@ -59,8 +59,6 @@ def login_page(): next_url = request.args.get('next') or request.form.get('next') login = request.form.get('login') password = request.form.get('pass') - role = 5 - user1 = '' if login and password: users = sql.select_users(user=login) @@ -71,16 +69,12 @@ def login_page(): if user.ldap_user == 1: if login in user.username: if roxywi_auth.check_in_ldap(login, password): - role = int(user.role) - user1 = user.username user_uuid, user_token = roxywi_auth.create_uuid_and_token(login) return roxywi_auth.do_login(user_uuid, str(user.groups), user, next_url) else: hashed_password = roxy_wi_tools.Tools.get_hash(password) if login in user.username and hashed_password == user.password: - role = int(user.role) - user1 = user.username user_uuid, user_token = roxywi_auth.create_uuid_and_token(login) return roxywi_auth.do_login(user_uuid, str(user.groups), user, next_url) else: @@ -93,7 +87,7 @@ def login_page(): except Exception: lang = 'en' - return render_template('login.html', user_params='', role=role, user=user1, lang=lang) + return render_template('login.html', lang=lang) @app.route('/logout', methods=['GET', 'POST']) diff --git a/app/modules/common/common.py b/app/modules/common/common.py index 012253e0..ad1b220a 100644 --- a/app/modules/common/common.py +++ b/app/modules/common/common.py @@ -1,9 +1,48 @@ import re +from datetime import datetime + +from shlex import quote +from shutil import which +from pytz import timezone error_mess = 'error: All fields must be completed' +def get_present_time(): + """ + Returns the current time in UTC. + + :return: The current time in UTC. + :rtype: datetime.datetime + """ + present = datetime.now(timezone('UTC')) + formatted_present = present.strftime('%b %d %H:%M:%S %Y %Z') + return datetime.strptime(formatted_present, '%b %d %H:%M:%S %Y %Z') + + def is_ip_or_dns(server_from_request: str) -> str: + """ + :param server_from_request: The server name or IP address obtained from the request + :return: The server name or IP address if it is valid. Otherwise, an empty string is returned. + + This method checks whether the given server name or IP address is valid. + The method first strips any leading or trailing whitespace from the server_from_request parameter. + Then, it checks if the server_from_request value is one of the specified special server names. + If it is, the method immediately returns the server_from_request value. + + If the server_from_request is not a special server name, it then validates whether it is an IP address + by matching it against the IP regular expression pattern (ip_regex). + If it is a valid IP address, the method returns the server_from_request value. + + If the server_from_request is not an IP address, it checks if it is a valid DNS name + by matching it against the DNS regular expression pattern (dns_regex). + If it is a valid DNS name, the method returns the server_from_request value. + + If the server_from_request value does not match any of the above conditions, an empty string is returned. + + Note: This method uses regular expressions (re.match) to validate the server_from_request value, + so the regular expression patterns used should follow the standard IP and DNS validation rules. + """ ip_regex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" dns_regex = "^(?!-)[A-Za-z0-9-]+([\\-\\.]{1}[a-z0-9]+)*\\.[A-Za-z]{2,6}$" try: @@ -12,47 +51,56 @@ def is_ip_or_dns(server_from_request: str) -> str: pass try: if server_from_request in ( - 'roxy-wi-checker', 'roxy-wi-keep_alive', 'roxy-wi-keep-alive', 'roxy-wi-metrics', - 'roxy-wi-portscanner', 'roxy-wi-smon', 'roxy-wi-socket', 'roxy-wi-prometheus-exporter', - 'prometheus', 'fail2ban', 'all', 'grafana-server', 'rabbitmq-server' + 'roxy-wi-checker', 'roxy-wi-keep_alive', 'roxy-wi-keep-alive', 'roxy-wi-metrics', 'roxy-wi-portscanner', + 'roxy-wi-smon', 'roxy-wi-socket', 'roxy-wi-prometheus-exporter', 'prometheus', 'fail2ban', 'all', 'grafana-server', 'rabbitmq-server' ): return server_from_request if re.match(ip_regex, server_from_request): return server_from_request - else: - if re.match(dns_regex, server_from_request): - return server_from_request - else: - return '' + if re.match(dns_regex, server_from_request): + return server_from_request + return '' except Exception: return '' def checkAjaxInput(ajax_input: str): + """ + Checks if the provided `ajax_input` string contains any non-permitted characters and returns the modified string. + + :param ajax_input: The input string to be checked and modified. + :return: The modified `ajax_input` string, or an empty string if the input was empty or contained non-permitted characters. + """ if not ajax_input: return '' pattern = re.compile('[&;|$`]') if pattern.search(ajax_input): - print('error: nice try') - return + raise ValueError('Error: Non-permitted characters detected') else: - from shlex import quote return quote(ajax_input.rstrip()) def check_is_service_folder(service_path: str) -> bool: - if ( - 'nginx' not in service_path - and 'haproxy' not in service_path - and 'apache2' not in service_path - and 'httpd' not in service_path - and 'keepalived' not in service_path - ) or '..' in service_path: - return False - else: - return True + """ + Check if the given `service_path` contains the name of a service folder. + + :param service_path: The path of the folder to be checked. + :return: True if the `service_path` contains the name of a service folder, False otherwise. + """ + service_names = ['nginx', 'haproxy', 'apache2', 'httpd', 'keepalived'] + + return any(service in service_path for service in service_names) and '..' not in service_path def return_nice_path(return_path: str, is_service=1) -> str: + """ + Formats the given return path to make it a nice path. + + :param return_path: The return path that needs to be formatted. + :param is_service: A flag indicating whether the return path must contain the name of the service. + Defaults to 1. + :return: The formatted nice path. + + """ if not check_is_service_folder(return_path) and is_service: return 'error: The path must contain the name of the service. Check it in Roxy-WI settings' @@ -63,16 +111,16 @@ def return_nice_path(return_path: str, is_service=1) -> str: def check_is_conf(config_path: str) -> bool: - if check_is_service_folder(config_path): - if 'conf' in config_path or 'cfg' in config_path: - return True + """ + Check if the config_path is a service folder and contains either 'conf' or 'cfg'. + Raise an exception if the check fails. - raise Exception('error: nice try') - - -def string_to_dict(dict_string) -> dict: - from ast import literal_eval - return literal_eval(dict_string) + :param config_path: Path string to be checked. + :return: True if the path passes the checks, otherwise an exception is raised. + """ + if check_is_service_folder(config_path) and ('conf' in config_path or 'cfg' in config_path): + return True + raise ValueError(f'error: The provided path "{config_path}" is not a service folder or does not contain "conf" or "cfg"') def get_key(item): @@ -80,7 +128,6 @@ def get_key(item): def is_tool(name): - from shutil import which is_tool_installed = which(name) return True if is_tool_installed is not None else False diff --git a/app/modules/config/add.py b/app/modules/config/add.py index 06c3473a..ad2a78bb 100644 --- a/app/modules/config/add.py +++ b/app/modules/config/add.py @@ -2,23 +2,22 @@ import os from flask import render_template, request -import modules.db.sql as sql -import modules.server.ssh as ssh_mod -import modules.common.common as common -import modules.config.config as config_mod -import modules.server.server as server_mod -import modules.roxywi.common as roxywi_common +import app.modules.db.sql as sql +import app.modules.server.ssh as ssh_mod +import app.modules.common.common as common +import app.modules.config.config as config_mod +import app.modules.config.common as config_common +import app.modules.server.server as server_mod +import app.modules.roxywi.common as roxywi_common +import app.modules.service.common as service_common import modules.roxy_wi_tools as roxy_wi_tools -time_zone = sql.get_setting('time_zone') -get_date = roxy_wi_tools.GetDate(time_zone) get_config = roxy_wi_tools.GetConfigVar() def save_to_haproxy_config(config: str, server_ip: str, name: str) -> str: roxywi_common.check_is_server_in_group(server_ip) - hap_configs_dir = get_config.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = hap_configs_dir + server_ip + "-" + get_date.return_date('config') + ".cfg" + cfg = config_common.generate_config_path('haproxy', server_ip) config_mod.get_config(server_ip, cfg) @@ -48,8 +47,7 @@ def save_nginx_config(config_add: str, server_ip: str, config_name: str) -> str: roxywi_common.check_is_server_in_group(server_ip) sub_folder = 'conf.d' if 'upstream' in config_name else 'sites-enabled' - service_configs_dir = get_config.get_config_var('configs', 'nginx_save_configs_dir') - cfg = f'{service_configs_dir}{server_ip}-{config_name}.conf' + cfg = config_common.generate_config_path('nginx', server_ip) nginx_dir = common.return_nice_path(sql.get_setting('nginx_dir')) config_file_name = f'{nginx_dir}{sub_folder}/{config_name}.conf' @@ -93,7 +91,7 @@ def show_userlist(server_ip: str) -> str: except Exception as e: roxywi_common.logging('Roxy-WI server', str(e), roxywi=1) try: - cfg = f'{configs_dir}{server_ip}-{get_date.return_date("config")}.{format_file}' + cfg = config_common.generate_config_path('haproxy', server_ip) except Exception as e: roxywi_common.logging('Roxy-WI server', f' Cannot generate a cfg path {e}', roxywi=1) try: @@ -217,30 +215,23 @@ def save_bwlist(list_name: str, list_con: str, color: str, group: str, server_ip server_mod.ssh_command(serv, [f"sudo mkdir {path}"]) server_mod.ssh_command(serv, [f"sudo chown $(whoami) {path}"]) try: - error = config_mod.upload(serv, f'{path}/{list_name}', list_path) + config_mod.upload(serv, f'{path}/{list_name}', list_path) except Exception as e: - error = f'{serv}: {e}' + output += f'error: Upload fail: to {serv}: {e} , ' - if error: - output += f'error: Upload fail: {error} , ' - else: - output += f'success: Edited {color} list was uploaded to {serv} , ' - try: - roxywi_common.logging(serv, f'Has been edited the {color} list {list_name}', roxywi=1, login=1) - except Exception: - pass + output += f'success: Edited {color} list was uploaded to {serv} , ' + try: + roxywi_common.logging(serv, f'Has been edited the {color} list {list_name}', roxywi=1, login=1) + except Exception: + pass - server_id = sql.select_server_id_by_ip(server_ip=serv) - haproxy_enterprise = sql.select_service_setting(server_id, 'haproxy', 'haproxy_enterprise') - if haproxy_enterprise == '1': - haproxy_service_name = "hapee-2.0-lb" - else: - haproxy_service_name = "haproxy" + server_id = sql.select_server_id_by_ip(server_ip=serv) + haproxy_service_name = service_common.get_correct_service_name('haproxy', server_id) - if action == 'restart': - server_mod.ssh_command(serv, [f"sudo systemctl restart {haproxy_service_name}"]) - elif action == 'reload': - server_mod.ssh_command(serv, [f"sudo systemctl reload {haproxy_service_name}"]) + if action == 'restart': + server_mod.ssh_command(serv, [f"sudo systemctl restart {haproxy_service_name}"]) + elif action == 'reload': + server_mod.ssh_command(serv, [f"sudo systemctl reload {haproxy_service_name}"]) return output @@ -348,31 +339,24 @@ def save_map(map_name: str, list_con: str, group: str, server_ip: str, action: s server_mod.ssh_command(serv, [f"sudo mkdir {path}"]) server_mod.ssh_command(serv, [f"sudo chown $(whoami) {path}"]) try: - error = config_mod.upload(serv, f'{path}/{map_name}', map_path) + config_mod.upload(serv, f'{path}/{map_name}', map_path) except Exception as e: - error = f'{serv}: {e}' + output += f'error: Upload fail to: {serv}: {e} , ' - if error: - output += f'error: Upload fail: {error} , ' - else: - try: - roxywi_common.logging(serv, f'Has been edited the map {map_name}', roxywi=1, login=1) - except Exception: - pass + try: + roxywi_common.logging(serv, f'Has been edited the map {map_name}', roxywi=1, login=1) + except Exception: + pass - server_id = sql.select_server_id_by_ip(server_ip=serv) - haproxy_enterprise = sql.select_service_setting(server_id, 'haproxy', 'haproxy_enterprise') - if haproxy_enterprise == '1': - haproxy_service_name = "hapee-2.0-lb" - else: - haproxy_service_name = "haproxy" + server_id = sql.select_server_id_by_ip(server_ip=serv) + haproxy_service_name = service_common.get_correct_service_name('haproxy', server_id) - if action == 'restart': - server_mod.ssh_command(serv, [f"sudo systemctl restart {haproxy_service_name}"]) - elif action == 'reload': - server_mod.ssh_command(serv, [f"sudo systemctl reload {haproxy_service_name}"]) + if action == 'restart': + server_mod.ssh_command(serv, [f"sudo systemctl restart {haproxy_service_name}"]) + elif action == 'reload': + server_mod.ssh_command(serv, [f"sudo systemctl reload {haproxy_service_name}"]) - output += f'success: Edited {map_name} map was uploaded to {serv} , ' + output += f'success: Edited {map_name} map was uploaded to {serv} , ' return output diff --git a/app/modules/config/common.py b/app/modules/config/common.py new file mode 100644 index 00000000..7854b081 --- /dev/null +++ b/app/modules/config/common.py @@ -0,0 +1,46 @@ +import app.modules.db.sql as sql +import modules.roxy_wi_tools as roxy_wi_tools + +get_config_var = roxy_wi_tools.GetConfigVar() +time_zone = sql.get_setting('time_zone') +get_date = roxy_wi_tools.GetDate(time_zone) + + +def get_file_format(service: str) -> str: + """ + Get the file format based on the given service. + + :param service: the service name to check the file format for. + :type service: str + :return: the file format, either 'cfg' or 'conf'. + :rtype: str + """ + return 'cfg' if service == 'haproxy' else 'conf' + + +def get_config_dir(service: str) -> str: + """ + Return the directory path of the configurations for the given service. + + :param service: The name of the service. + :return: The directory path of the configurations. + :raises Exception: If the service name is invalid. + """ + if service in ('haproxy', 'nginx', 'apache', 'keepalived'): + return get_config_var.get_config_var('configs', f'{service}_save_configs_dir') + else: + raise Exception('error: Wrong service') + + +def generate_config_path(service: str, server_ip: str) -> str: + """ + :param service: Name of the service for which the configuration path needs to be generated. + :param server_ip: IP address of the server for which the configuration path needs to be generated. + :return: The generated configuration path as a string. + + This method generates the configuration path for a given service and server IP address. It combines the service name, server IP address, current date, and file format to create the path + *. The file format is determined by calling the `get_file_format` method and the configuration directory is obtained using the `get_config_dir` method. + """ + file_format = get_file_format(service) + config_dir = get_config_dir(service) + return f"{config_dir}/{server_ip}-{get_date.return_date('config')}.{file_format}" diff --git a/app/modules/config/config.py b/app/modules/config/config.py index fbb0a80f..e17df884 100644 --- a/app/modules/config/config.py +++ b/app/modules/config/config.py @@ -1,252 +1,282 @@ import os import re +from pathlib import Path +from typing import Any from flask import render_template, request -import modules.db.sql as sql -import modules.server.ssh as mod_ssh -import modules.server.server as server_mod -import modules.common.common as common -import modules.roxywi.common as roxywi_common +import app.modules.db.sql as sql +import app.modules.server.ssh as mod_ssh +import app.modules.server.server as server_mod +import app.modules.common.common as common +import app.modules.roxywi.common as roxywi_common import modules.roxy_wi_tools as roxy_wi_tools -import modules.service.common as service_common +import app.modules.service.common as service_common +import app.modules.service.action as service_action +import app.modules.config.common as config_common time_zone = sql.get_setting('time_zone') get_date = roxy_wi_tools.GetDate(time_zone) get_config_var = roxy_wi_tools.GetConfigVar() -def get_config(server_ip, cfg, **kwargs): +def _replace_config_path_to_correct(config_path: str) -> str: + """ + Replace the characters '92' with '/' in the given config_path string. + + :param config_path: The config path to be sanitized. + :return: The sanitized config path string. + """ + config_path = common.checkAjaxInput(config_path) + try: + return config_path.replace('92', '/') + except Exception as e: + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'error: Cannot sanitize config file: {e}', roxywi=1) + + +def get_config(server_ip, cfg, service='haproxy', **kwargs): + """ + :param service: The service for what needed to get config. Valid values are 'haproxy', 'nginx', 'apache' and 'keepalived'. + :param server_ip: The IP address of the server from which to retrieve the configuration. + :param cfg: The name of the configuration file. + :param kwargs: Additional keyword arguments. + - service: The name of the service for which the configuration is retrieved. + - config_file_name: The name of the configuration file for 'nginx' or 'apache' services. + - waf: The name of the Web Application Firewall (WAF) service. + - waf_rule_file: The name of the WAF rule file. + + :return: None + + Retrieves the configuration file for the specified service on the given server IP. The configuration file is stored in the provided 'cfg' variable. + + The method first determines the correct path for the configuration file based on the 'service' parameter: + - If the service is 'keepalived' or 'haproxy', the method retrieves the configuration path from the SQL database using the service name appended with '_config_path'. + - If the service is 'nginx' or 'apache', the method replaces the configuration file name with the correct path using the '_replace_config_path_to_correct' function and the 'config_file + *_name' parameter. + - If the 'waf' parameter is provided, the method retrieves the service directory from the SQL database using the 'waf' parameter appended with '_dir'. If the 'waf' parameter is 'hap + *roxy' or 'nginx', the method constructs the configuration path by appending the service directory with '/waf/rules/' and the 'waf_rule_file' parameter. + + After determining the configuration path, the method validates that the configuration file exists using the 'common.check_is_conf' function. + + Finally, the method establishes an SSH connection to the server IP using the 'mod_ssh.ssh_connect' function and retrieves the configuration file using the 'ssh.get_sftp' function. Any + * exceptions that occur during this process are handled by the 'roxywi_common.handle_exceptions' function, displaying an error message with the relevant details. + """ config_path = '' - if kwargs.get("keepalived") or kwargs.get("service") == 'keepalived': - config_path = sql.get_setting('keepalived_config_path') - elif ( - kwargs.get("nginx") or kwargs.get("service") == 'nginx' - or kwargs.get("apache") or kwargs.get("service") == 'apache' - ): - config_path = common.checkAjaxInput(kwargs.get('config_file_name')) - config_path = config_path.replace('92', '/') - elif kwargs.get("waf") or kwargs.get("service") == 'waf': - if kwargs.get("waf") == 'haproxy': - config_path = f'{sql.get_setting("haproxy_dir")}/waf/rules/{kwargs.get("waf_rule_file")}' - elif kwargs.get("waf") == 'nginx': - config_path = f'{sql.get_setting("nginx_dir")}/waf/rules/{kwargs.get("waf_rule_file")}' - else: - config_path = sql.get_setting('haproxy_config_path') - - if not common.check_is_conf(config_path): - raise Exception('error: nice try 2') + if service in ('keepalived', 'haproxy'): + config_path = sql.get_setting(f'{service}_config_path') + elif service in ('nginx', 'apache'): + config_path = _replace_config_path_to_correct(kwargs.get('config_file_name')) + elif kwargs.get("waf"): + service_dir = sql.get_setting(f"{kwargs.get('waf')}_dir") + if kwargs.get("waf") in ('haproxy', 'nginx'): + config_path = f'{service_dir}/waf/rules/{kwargs.get("waf_rule_file")}' + common.check_is_conf(config_path) try: with mod_ssh.ssh_connect(server_ip) as ssh: ssh.get_sftp(config_path, cfg) except Exception as e: - roxywi_common.logging('Roxy-WI server', f'error: cannot get config: {e}', roxywi=1) - raise Exception(f'error: cannot get config: {e}') + roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'error: Cannot get config', roxywi=1) -def upload(server_ip, path, file): +def upload(server_ip: str, path: str, file: str) -> None: + """ + Uploads a file to a remote server using secure shell (SSH) protocol. + + :param server_ip: The IP address or hostname of the remote server. + :param path: The remote path on the server where the file will be uploaded. + :param file: The file to be uploaded. + :return: None + """ try: with mod_ssh.ssh_connect(server_ip) as ssh: ssh.put_sftp(file, path) except Exception as e: - error = str(e.args) - roxywi_common.logging('Roxy-WI server', f'error: Cannot upload {file} to {path} to server: {server_ip}: {error}', roxywi=1) - raise Exception(f'error: Cannot upload {file} to {path} to server: {server_ip}: {error}') + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'error: Cannot upload {file} to {path} to server: {server_ip}: {e}', roxywi=1) + + +def _generate_command(service: str, server_id: int, just_save: str, config_path: str, tmp_file: str, cfg: str, server_ip: str) -> list: + """ + :param service: The name of the service. + :param server_id: The ID of the server. + :param just_save: Indicates whether the configuration should only be saved or not. Possible values are 'test', 'save', 'restart' or 'reload'. + :param config_path: The path to the configuration file. + :param tmp_file: The temporary file path. + :param cfg: The configuration object. + :param server_ip: The IP address of the server. + :return: A list of commands. + + This method generates a list of commands based on the given parameters. + """ + container_name = sql.get_setting(f'{service}_container_name') + is_dockerized = sql.select_service_setting(server_id, service, 'dockerized') + reload_or_restart_command = f' && {service_action.get_action_command(service, just_save, server_id)}' + move_config = f" sudo mv -f {tmp_file} {config_path}" + command_for_docker = f'sudo docker exec -it {container_name}' + command = { + 'haproxy': {'0': f'haproxy -c -f {tmp_file} ', '1': f'{command_for_docker} haproxy -c -f {tmp_file} '}, + 'nginx': {'0': 'sudo nginx -t ', '1': f'{command_for_docker} nginx -t '}, + 'apache': {'0': 'sudo apachectl -t ', '1': f'{command_for_docker} apachectl -t '}, + 'keepalived': {'0': f'keepalived -t -f {tmp_file} ', '1': ' '}, + 'waf': {'0': ' ', '1': ' '} + } + + try: + check_config = command[service][is_dockerized] + except Exception as e: + raise Exception(f'error: Cannot generate command: {e}') + + if just_save == 'test': + return [f"{check_config} && sudo rm -f {tmp_file}"] + elif just_save == 'save': + reload_or_restart_command = '' + else: + if service_common.is_not_allowed_to_restart(server_id, service, just_save): + raise Exception(f'error: This server is not allowed to be restarted') + + if service in ('keepalived', 'waf'): + commands = [f'{move_config} {reload_or_restart_command}'] + elif service in ('nginx', 'apache'): + commands = [f'{move_config} && {check_config} {reload_or_restart_command}'] + else: + commands = [f'{check_config} && {move_config} {reload_or_restart_command}'] + + if service in ('haproxy', 'nginx'): + if sql.return_firewall(server_ip): + commands[0] += _open_port_firewalld(cfg, server_ip, service) + + return commands + + +def _create_config_version(server_id: int, server_ip: str, service: str, config_path: str, login: str, cfg: str, old_cfg: str, tmp_file: str) -> None: + """ + Create a new version of the configuration file. + + :param server_id: The ID of the server. + :param server_ip: The IP address of the server. + :param service: The service name. + :param config_path: The path to the configuration file. + :param login: The login of the user. + :param cfg: The new configuration string. + :param old_cfg: The path to the old configuration file. + :param tmp_file: A temporary file name. + + :return: None + """ + diff = '' + + if old_cfg: + path = Path(old_cfg) + else: + old_cfg = '' + path = Path(old_cfg) + + if not path.is_file(): + old_cfg = f'{tmp_file}.old' + try: + get_config(server_ip, old_cfg, service=service, config_file_name=config_path) + except Exception: + roxywi_common.logging('Roxy-WI server', 'Cannot download config for diff', roxywi=1) + try: + diff = diff_config(old_cfg, cfg, return_diff=1) + except Exception as e: + roxywi_common.logging('Roxy-WI server', f'error: Cannot create diff config version: {e}', roxywi=1) + + try: + user_id = roxywi_common.get_user_id(login=login) + sql.insert_config_version(server_id, user_id, service, cfg, config_path, diff) + except Exception as e: + roxywi_common.logging('Roxy-WI server', f'error: Cannot insert config version: {e}', roxywi=1) def upload_and_restart(server_ip: str, cfg: str, just_save: str, service: str, **kwargs): - file_format = 'conf' + """ + :param server_ip: IP address of the server + :param cfg: Path to the config file to be uploaded + :param just_save: Option specifying whether to just save the config or perform an action such as reload or restart + :param service: Service name for which the config is being uploaded + :param kwargs: Additional keyword arguments + + :return: Error message or service title + + """ + file_format = config_common.get_file_format(service) config_path = kwargs.get('config_file_name') - service_name = '' - container_name = '' - reload_or_restart_command = '' config_date = get_date.return_date('config') server_id = sql.select_server_id_by_ip(server_ip=server_ip) if config_path and config_path != 'undefined': - config_path = kwargs.get('config_file_name').replace('92', '/') + config_path = _replace_config_path_to_correct(kwargs.get('config_file_name')) - if service == 'haproxy': - config_path = sql.get_setting('haproxy_config_path') - file_format = 'cfg' + if service in ('haproxy', 'keepalived'): + config_path = sql.get_setting(f'{service}_config_path') - if service == 'keepalived': - config_path = sql.get_setting('keepalived_config_path') - file_format = 'cfg' - - if '..' in config_path: - raise Exception('error: nice try') + common.check_is_conf(config_path) + login = kwargs.get('login') if kwargs.get('login') else 1 tmp_file = f"{sql.get_setting('tmp_config_path')}/{config_date}.{file_format}" - is_dockerized = sql.select_service_setting(server_id, service, 'dockerized') - - if is_dockerized == '1': - service_cont_name = f'{service}_container_name' - container_name = sql.get_setting(service_cont_name) - reload_command = f" && sudo docker kill -s HUP {container_name}" - restart_command = f" && sudo docker restart {container_name}" - else: - service_name = service - if service == 'haproxy': - haproxy_enterprise = sql.select_service_setting(server_id, 'haproxy', 'haproxy_enterprise') - if haproxy_enterprise == '1': - service_name = "hapee-2.0-lb" - if service == 'apache': - service_name = service_common.get_correct_apache_service_name(0, server_id) - - reload_command = f" && sudo systemctl reload {service_name}" - restart_command = f" && sudo systemctl restart {service_name}" - - if just_save in ('save', 'test'): - action = just_save - elif just_save == 'reload': - action = 'reload' - reload_or_restart_command = reload_command - else: - try: - service_common.is_not_allowed_to_restart(server_id, service) - except Exception as e: - return f'error: Cannot check is this service allowed to be restarted: {e}' - - action = 'restart' - reload_or_restart_command = restart_command - - if kwargs.get('login'): - login = kwargs.get('login') - else: - login = 1 try: os.system(f"dos2unix -q {cfg}") - except OSError: - raise Exception('error: there is no dos2unix') - - if service == "keepalived": - move_config = f"sudo mv -f {tmp_file} {config_path}" - if action == "save": - commands = [move_config] - else: - commands = [move_config + reload_or_restart_command] - elif service == "nginx": - if is_dockerized == '1': - check_config = f"sudo docker exec -it exec {container_name} nginx -t " - else: - check_config = "sudo nginx -t " - check_and_move = f"sudo mv -f {tmp_file} {config_path} && {check_config}" - if action == "test": - commands = [f"{check_config} && sudo rm -f {tmp_file}"] - elif action == "save": - commands = [check_and_move] - else: - commands = [check_and_move + reload_or_restart_command] - if sql.return_firewall(server_ip): - commands[0] += open_port_firewalld(cfg, server_ip=server_ip, service='nginx') - elif service == "apache": - if is_dockerized == '1': - check_config = f"sudo docker exec -it exec {container_name} sudo apachectl configtest " - else: - check_config = "sudo apachectl configtest " - check_and_move = f"sudo mv -f {tmp_file} {config_path} && {check_config}" - if action == "test": - commands = [f"{check_config} && sudo rm -f {tmp_file}"] - elif action == "save": - commands = [check_and_move] - else: - commands = [check_and_move + reload_or_restart_command] - # if sql.return_firewall(server_ip): - # commands[0] += open_port_firewalld(cfg, server_ip=server_ip, service='apache') - elif service == 'waf': - check_and_move = f"sudo mv -f {tmp_file} {config_path}" - if action == "save": - commands = [check_and_move] - else: - commands = [check_and_move + reload_or_restart_command] - else: - if is_dockerized == '1': - check_config = f"sudo docker exec -it {container_name} haproxy -c -f {tmp_file}" - else: - check_config = f"sudo {service_name} -c -f {tmp_file}" - move_config = f" && sudo mv -f {tmp_file} {config_path}" - - if action == "test": - commands = [f"{check_config} && sudo rm -f {tmp_file}"] - elif action == "save": - commands = [check_config + move_config] - else: - commands = [check_config + move_config + reload_or_restart_command] - if sql.return_firewall(server_ip): - commands[0] += open_port_firewalld(cfg, server_ip=server_ip) + except OSError as e: + roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'error: There is no dos2unix') try: upload(server_ip, tmp_file, cfg) except Exception as e: - roxywi_common.logging('Roxy-WI server', f'error: Cannot upload config: {e}', roxywi=1) - raise Exception(f'error: Cannot upload config: {e}') + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'error: Cannot upload config: {e}', roxywi=1) try: - if action != 'test': + if just_save != 'test': roxywi_common.logging(server_ip, 'A new config file has been uploaded', login=login, keep_history=1, service=service) except Exception as e: roxywi_common.logging('Roxy-WI server', str(e), roxywi=1) # If master then save version of config in a new way if not kwargs.get('slave') and service != 'waf': - from pathlib import Path + _create_config_version(server_id, server_ip, service, config_path, kwargs.get('login'), cfg, kwargs.get('oldcfg'), tmp_file) - diff = '' - try: - old_cfg = kwargs.get('oldcfg') - path = Path(old_cfg) - except Exception: - old_cfg = '' - path = Path(old_cfg) - - if not path.is_file(): - old_cfg = f'{tmp_file}.old' - try: - get_config(server_ip, old_cfg, service=service, config_file_name=config_path) - except Exception: - roxywi_common.logging('Roxy-WI server', 'Cannot download config for diff', roxywi=1) - try: - diff = diff_config(old_cfg, cfg, return_diff=1) - except Exception as e: - roxywi_common.logging('Roxy-WI server', str(e), roxywi=1) - - try: - user_id = roxywi_common.get_user_id(login=kwargs.get('login')) - sql.insert_config_version(server_id, user_id, service, cfg, config_path, diff) - except Exception as e: - roxywi_common.logging('Roxy-WI server', str(e), roxywi=1) + try: + commands = _generate_command(service, server_id, just_save, config_path, tmp_file, cfg, server_ip) + except Exception as e: + return f'{e}' try: error = server_mod.ssh_command(server_ip, commands) except Exception as e: - roxywi_common.logging('Roxy-WI server', str(e), roxywi=1) - raise Exception(f'{e}') + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'{e}', roxywi=1) try: - if action == 'reload' or action == 'restart': - roxywi_common.logging(server_ip, f'Service has been {action}ed', login=login, keep_history=1, service=service) + if just_save in ('reload', 'restart'): + roxywi_common.logging(server_ip, f'Service has been {just_save}ed', login=login, keep_history=1, service=service) except Exception as e: roxywi_common.logging('Roxy-WI server', str(e), roxywi=1) if error.strip() != 'haproxy' and error.strip() != 'nginx': - return error.strip() + return error.strip() or service.title() -def master_slave_upload_and_restart(server_ip, cfg, just_save, service, **kwargs): +def master_slave_upload_and_restart(server_ip: str, cfg: str, just_save: str, service: str, **kwargs: Any) -> str: + """ + + This method `master_slave_upload_and_restart` performs the upload and restart operation on a master server and its associated slave servers. It takes the following parameters: + + :param server_ip: The IP address of the server to perform the operation on. + :param cfg: The configuration file to upload and restart. + :param just_save: A flag indicating whether to just save the configuration or also restart the server. + :param service: The name of the service to restart. + :param kwargs: Additional optional keyword arguments. + + :return: The output of the operation. + + """ slave_output = '' masters = sql.is_master(server_ip) config_file_name = kwargs.get('config_file_name') - oldcfg = kwargs.get('oldcfg') + old_cfg = kwargs.get('oldcfg') waf = kwargs.get('waf') - - try: - server_name = sql.get_hostname_by_server_ip(server_ip) - except Exception: - server_name = server_ip + server_name = sql.get_hostname_by_server_ip(server_ip) if kwargs.get('login'): login = kwargs.get('login') @@ -264,7 +294,7 @@ def master_slave_upload_and_restart(server_ip, cfg, just_save, service, **kwargs slave_output += f'
slave_server:\n error: {e}' try: output = upload_and_restart( - server_ip, cfg, just_save, service, waf=waf, config_file_name=config_file_name, oldcfg=oldcfg, login=login + server_ip, cfg, just_save, service, waf=waf, config_file_name=config_file_name, oldcfg=old_cfg, login=login ) except Exception as e: output = f'error: {e}' @@ -275,18 +305,26 @@ def master_slave_upload_and_restart(server_ip, cfg, just_save, service, **kwargs return output -def open_port_firewalld(cfg, server_ip, **kwargs): - try: - conf = open(cfg, "r") - except IOError: - print('
Cannot read exported config file
') - return +def _open_port_firewalld(cfg: str, server_ip: str, service: str) -> str: + """ + :param cfg: The path to the configuration file for Firewalld. + :param server_ip: The IP address of the server. + :param service: The name of the service to open ports for (e.g., nginx). + :return: The Firewalld commands to open the specified ports. + This method reads the provided Service configuration file and opens ports based on the specified service. It returns the Firewalld commands as a string. + + """ firewalld_commands = ' &&' ports = '' + try: + conf = open(cfg, "r") + except IOError as e: + raise Exception(f'error: Cannot open config file for Firewalld {e}') + for line in conf: - if kwargs.get('service') == 'nginx': + if service == 'nginx': if "listen " in line and '#' not in line: try: listen = ' '.join(line.split()) @@ -321,13 +359,30 @@ def open_port_firewalld(cfg, server_ip, **kwargs): return firewalld_commands -def diff_config(oldcfg, cfg, **kwargs): +def diff_config(old_cfg, cfg, **kwargs): + """ + Function to compare two configuration files and log the differences. + + :param old_cfg: The path of the old configuration file. + :param cfg: The path of the new configuration file. + :param kwargs: Additional keyword arguments. Currently, supports: + - return_diff: If True, returns the difference between the two files as a string. + :return: If kwargs['return_diff'] is True, returns the difference between the two files as a string. + Otherwise, logs the differences with user information and writes it to a log file. + """ log_path = get_config_var.get_config_var('main', 'log_path') user_group = roxywi_common.get_user_group() diff = "" date = get_date.return_date('date_in_log') log_date = get_date.return_date('logs') - cmd = "/bin/diff -ub %s %s" % (oldcfg, cfg) + cmd = f"/bin/diff -ub {old_cfg} {cfg}" + log_file = f"{log_path}/config_edit-{log_date}" + output, stderr = server_mod.subprocess_execute(cmd) + + if kwargs.get('return_diff'): + for line in output: + diff += line + "\n" + return diff try: user_uuid = request.cookies.get('uuid') @@ -335,94 +390,132 @@ def diff_config(oldcfg, cfg, **kwargs): except Exception: login = '' - output, stderr = server_mod.subprocess_execute(cmd) + for line in output: + diff += f"{date} user: {login}, group: {user_group} {line}\n" - if kwargs.get('return_diff'): - for line in output: - diff += line + "\n" - return diff - else: - for line in output: - diff += f"{date} user: {login}, group: {user_group} {line}\n" - - log_file = f"{log_path}/config_edit-{log_date}" try: with open(log_file, 'a') as log: log.write(diff) - except IOError: - print(f'
Can\'t read write change to log. {stderr}
') - pass + except IOError as e: + roxywi_common.logging('Roxy-WI server', f'error: Cannot write a diff config to the log file: {e}, {stderr}', login=login, roxywi=1) + + +def _sanitize_input_word(word: str) -> str: + """ + Sanitizes the input word by removing certain characters. + """ + return re.sub(r'[?|$|!|^|*|\]|\[|,| |]', r'', word) + + +def _highlight_word(line: str, word: str) -> str: + """ + Highlights the word in the line by making it bold and colored red. + """ + return line.replace(word, f'{word}') + + +def _classify_line(line: str) -> str: + """ + Classifies the line as 'line' or 'line3' based on if it contains '--'. + """ + return "line" if '--' in line else "line3" + + +def _wrap_line(content: str, css_class: str="line") -> str: + """ + Wraps the provided content into a div HTML element with the given CSS class. + """ + return f'
{content}
' def show_finding_in_config(stdout: str, **kwargs) -> str: - grep = '' - out = '
--
' + """ + :param stdout: The stdout of a command execution. + :param kwargs: Additional keyword arguments. + :keyword grep: The word to find and highlight in the output. (Optional) + :return: The output with highlighted lines and formatted dividers. - if kwargs.get('grep'): - grep = kwargs.get('grep') - grep = re.sub(r'[?|$|!|^|*|\]|\[|,| |]', r'', grep) + This method takes the stdout of a command execution and additional keyword arguments. It searches for a word specified by the `grep` keyword argument in each line of the stdout and highlights + * the word if found. It then classifies each line based on its content and wraps it in a line with appropriate CSS class. Finally, it adds formatted dividers before and after the output + *. + The formatted output string is returned. + """ + css_class_divider = _wrap_line("--") + output = css_class_divider + word_to_find = kwargs.get('grep') + + if word_to_find: + word_to_find = _sanitize_input_word(word_to_find) for line in stdout: - if kwargs.get('grep'): - line = line.replace(grep, f'{grep}') - line_class = "line" if '--' in line else "line3" - out += f'
{line}
' + if word_to_find: + line = _highlight_word(line, word_to_find) + line_class = _classify_line(line) + output += _wrap_line(line, line_class) - out += '
--
' - - return out + output += css_class_divider + return output def show_compare_config(server_ip: str, service: str) -> str: - lang = roxywi_common.get_user_lang_for_flask() - config_dir = get_config_var.get_config_var('configs', f'{service}_save_configs_dir') + """ + Display the comparison of configurations for a service. - if service in ('nginx', 'apache', 'keepalived'): - return_files = roxywi_common.get_files(config_dir, 'conf', server_ip=server_ip) - elif service == 'haproxy': - return_files = roxywi_common.get_files(config_dir, 'cfg', server_ip=server_ip) - else: - return 'error: Wrong service' + :param server_ip: The IP address of the server. + :param service: The service name. + :return: Returns the rendered template as a string. + """ + lang = roxywi_common.get_user_lang_for_flask() + config_dir = config_common.get_config_dir(service) + file_format = config_common.get_file_format(service) + return_files = roxywi_common.get_files(config_dir, file_format, server_ip=server_ip) return render_template('ajax/show_compare_configs.html', serv=server_ip, return_files=return_files, lang=lang) def compare_config(service: str, left: str, right: str) -> str: + """ + Compares the configuration files of a service. + + :param service: The name of the service. + :param left: The name of the left configuration file. + :param right: The name of the right configuration file. + :return: The rendered template with the diff output and the user language for Flask. + """ lang = roxywi_common.get_user_lang_for_flask() - - if service in ('haproxy', 'nginx', 'apache', 'keepalived'): - configs_dir = get_config_var.get_config_var('configs', f'{service}_save_configs_dir') - else: - return 'error: Wrong service' - - cmd = f'diff -pub {configs_dir}{left} {configs_dir}{right}' + config_dir = config_common.get_config_dir(service) + cmd = f'diff -pub {config_dir}{left} {config_dir}{right}' output, stderr = server_mod.subprocess_execute(cmd) return render_template('ajax/compare.html', stdout=output, lang=lang) def show_config(server_ip: str, service: str, config_file_name: str, configver: str) -> str: + """ + Get and display the configuration file for a given server. + + :param server_ip: The IP address of the server. + :param service: The name of the service. + :param config_file_name: The name of the configuration file. + :param configver: The version of the configuration. + + :return: The rendered template for displaying the configuration. + """ user_uuid = request.cookies.get('uuid') group_id = int(request.cookies.get('group')) - role_id = sql.get_user_role_by_uuid(user_uuid, group_id) + configs_dir = config_common.get_config_dir(service) + server_id = sql.select_server_id_by_ip(server_ip) try: config_file_name = config_file_name.replace('/', '92') except Exception: config_file_name = '' - if service in ('nginx', 'apache', 'keepalived'): - configs_dir = get_config_var.get_config_var('configs', f'{service}_save_configs_dir') - cfg = '.conf' - else: - configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = '.cfg' - if '..' in configs_dir: raise Exception('error: nice try') if configver is None: - cfg = f"{configs_dir}{server_ip}-{get_date.return_date('config')}{cfg}" + cfg = config_common.generate_config_path(service, server_ip) try: get_config(server_ip, cfg, service=service, config_file_name=config_file_name) except Exception as e: @@ -439,34 +532,44 @@ def show_config(server_ip: str, service: str, config_file_name: str, configver: if configver is None: os.remove(cfg) - is_serv_protected = sql.is_serv_protected(server_ip) - server_id = sql.select_server_id_by_ip(server_ip) - hostname = sql.get_hostname_by_server_ip(server_ip) - is_restart = sql.select_service_setting(server_id, service, 'restart') - lang = roxywi_common.get_user_lang_for_flask() + kwargs = { + 'conf': conf, + 'serv': server_ip, + 'configver': configver, + 'role': sql.get_user_role_by_uuid(user_uuid, group_id), + 'service': service, + 'config_file_name': config_file_name, + 'is_serv_protected': sql.is_serv_protected(server_ip), + 'is_restart': sql.select_service_setting(server_id, service, 'restart'), + 'lang': roxywi_common.get_user_lang_for_flask(), + 'hostname': sql.get_hostname_by_server_ip(server_ip) + } - return render_template( - 'ajax/config_show.html', conf=conf, serv=server_ip, configver=configver, role=role_id, service=service, - config_file_name=config_file_name, is_serv_protected=is_serv_protected, is_restart=is_restart, lang=lang, - hostname=hostname - ) + return render_template('ajax/config_show.html', **kwargs) def show_config_files(server_ip: str, service: str, config_file_name: str) -> str: + """ + Displays the configuration files for a given server IP, service, and config file name. + + :param server_ip: The IP address of the server. + :param service: The name of the service. + :param config_file_name: The name of the config file. + :return: The rendered template. + """ service_config_dir = sql.get_setting(f'{service}_dir') return_files = server_mod.get_remote_files(server_ip, service_config_dir, 'conf') + return_files += ' ' + sql.get_setting(f'{service}_config_path') + lang = roxywi_common.get_user_lang_for_flask() if 'error: ' in return_files: raise Exception(return_files) try: - config_file_name = config_file_name.replace('92', '/') + config_file_name = _replace_config_path_to_correct(config_file_name) except Exception: config_file_name = '' - return_files += ' ' + sql.get_setting(f'{service}_config_path') - lang = roxywi_common.get_user_lang_for_flask() - return render_template( 'ajax/show_configs_files.html', serv=server_ip, service=service, return_files=return_files, lang=lang, config_file_name=config_file_name, path_dir=service_config_dir @@ -474,20 +577,22 @@ def show_config_files(server_ip: str, service: str, config_file_name: str) -> st def list_of_versions(server_ip: str, service: str, configver: str, for_delver: int) -> str: - if service not in ('haproxy', 'nginx', 'keepalived', 'apache'): - raise Exception('error: wrong service') + """ + Retrieve a list of versions for a given server IP, service, configuration version. + :param server_ip: The IP address of the server. + :param service: The service to retrieve versions for. + :param configver: The configuration version to retrieve. + :param for_delver: The delete version to use. + :return: The rendered HTML template with the list of versions. + """ users = sql.select_users() - service_desc = sql.select_service(service) - configs = sql.select_config_version(server_ip, service_desc.slug) + configs = sql.select_config_version(server_ip, service) lang = roxywi_common.get_user_lang_for_flask() - action = f'/app/config/versions/{service_desc.slug}/{server_ip}' - configs_dir = get_config_var.get_config_var('configs', f'{service_desc.service}_save_configs_dir') - - if service == 'haproxy': - files = roxywi_common.get_files(configs_dir, 'cfg', server_ip) - else: - files = roxywi_common.get_files(configs_dir, 'conf', server_ip) + action = f'/app/config/versions/{service}/{server_ip}' + config_dir = config_common.get_config_dir(service) + file_format = config_common.get_file_format(service) + files = roxywi_common.get_files(config_dir, file_format, server_ip) return render_template( 'ajax/show_list_version.html', server_ip=server_ip, service=service, action=action, return_files=files, @@ -496,25 +601,32 @@ def list_of_versions(server_ip: str, service: str, configver: str, for_delver: i def return_cfg(service: str, server_ip: str, config_file_name: str) -> str: - if service == 'haproxy': - file_format = 'cfg' - else: - file_format = 'conf' + """ + :param service: The name of the service (e.g., 'nginx', 'apache') + :param server_ip: The IP address of the server + :param config_file_name: The name of the configuration file + :return: The path to the generated configuration file - if service in ('haproxy', 'nginx', 'apache', 'keepalived'): - configs_dir = get_config_var.get_config_var('configs', f'{service}_save_configs_dir') - else: - raise Exception('error: Wrong service') + This method returns the path to the generated configuration file based on the provided parameters. The file format is determined by the service. If the service is 'nginx' or 'apache + *', then the config_file_name is replaced with the correct path, and the resulting configuration file is named using the server_ip and the original file name. If the service is not ' + *nginx' or 'apache', then the resulting configuration file is named using the server_ip. The file format is determined by calling the config_common.get_file_format() method. + + Any existing old configuration files in the config_dir are removed before generating the new configuration file. + + Note: This method depends on the config_common.get_file_format(), config_common.get_config_dir(), and get_date.return_date() methods. + """ + file_format = config_common.get_file_format(service) + config_dir = config_common.get_config_dir(service) if service in ('nginx', 'apache'): - config_file_name = config_file_name.replace('92', '/') + config_file_name = _replace_config_path_to_correct(config_file_name) conf_file_name_short = config_file_name.split('/')[-1] - cfg = f"{configs_dir}{server_ip}-{conf_file_name_short}-{get_date.return_date('config')}.{file_format}" + cfg = f"{config_dir}{server_ip}-{conf_file_name_short}-{get_date.return_date('config')}.{file_format}" else: - cfg = f"{configs_dir}{server_ip}-{get_date.return_date('config')}.{file_format}" + cfg = config_common.generate_config_path(service, server_ip) try: - os.system(f"/bin/rm -f {configs_dir}*.old") + os.remove(f'{config_dir}*.old') except Exception: pass diff --git a/app/modules/config/runtime.py b/app/modules/config/runtime.py index 36a9137d..113eff96 100644 --- a/app/modules/config/runtime.py +++ b/app/modules/config/runtime.py @@ -2,15 +2,14 @@ import json from flask import render_template -import modules.db.sql as sql -import modules.config.config as config_mod -import modules.config.section as section_mod -import modules.server.server as server_mod -import modules.roxywi.common as roxywi_common +import app.modules.db.sql as sql +import app.modules.config.config as config_mod +import app.modules.config.common as config_common +import app.modules.config.section as section_mod +import app.modules.server.server as server_mod +import app.modules.roxywi.common as roxywi_common import modules.roxy_wi_tools as roxy_wi_tools -time_zone = sql.get_setting('time_zone') -get_date = roxy_wi_tools.GetDate(time_zone) get_config_var = roxy_wi_tools.GetConfigVar() @@ -85,17 +84,15 @@ def show_backends(server_ip, **kwargs): def get_backends_from_config(server_ip: str, backends='') -> str: - config_date = get_date.return_date('config') configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - format_cfg = 'cfg' lines = '' try: - cfg = configs_dir + roxywi_common.get_files(configs_dir, format_cfg)[0] + cfg = configs_dir + roxywi_common.get_files(configs_dir, 'cfg')[0] except Exception as e: roxywi_common.logging('Roxy-WI server', str(e), roxywi=1) try: - cfg = f'{configs_dir}{server_ip}-{config_date}.{format_cfg}' + cfg = config_common.generate_config_path('haproxy', server_ip) except Exception as e: roxywi_common.logging('Roxy-WI server', f'error: Cannot generate cfg path: {e}', roxywi=1) return f'error: Cannot generate cfg path: {e}' @@ -150,8 +147,7 @@ def change_ip_and_port(serv, backend_backend, backend_server, backend_ip, backen return 'error: ' + stderr[0] lines += output[0] - configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{configs_dir}{serv}-{get_date.return_date('config')}.cfg" + cfg = config_common.generate_config_path('haproxy', serv) config_mod.get_config(serv, cfg) cmd = 'string=`grep %s %s -n -A25 |grep "server %s" |head -1|awk -F"-" \'{print $1}\'` ' \ @@ -240,8 +236,7 @@ def add_server( if check: check_cfg = f'check port {port_check}' - configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{configs_dir}{server_ip}-{get_date.return_date('config')}.cfg" + cfg = config_common.generate_config_path('haproxy', server_ip) try: config_mod.get_config(server_ip, cfg) except Exception as e: @@ -292,12 +287,10 @@ def delete_server(server_ip: str, backend: str, server: str) -> str: if 'No such server' in lines: return f'error: {lines}' - configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{configs_dir}{server_ip}-{get_date.return_date('config')}.cfg" + cfg = config_common.generate_config_path('haproxy', server_ip) config_mod.get_config(server_ip, cfg) cmd = f'string=`grep {backend} {cfg} -n -A25 |grep "server {server}" |head -1|awk -F"-" \'{{print $1}}\'` && sed -i "$(echo $string)d" {cfg}' - print(cmd) server_mod.subprocess_execute(cmd) config_mod.master_slave_upload_and_restart(server_ip, cfg, 'save', 'haproxy') @@ -324,8 +317,7 @@ def change_maxconn_global(serv: str, maxconn: int) -> str: if stderr != '': return stderr[0] elif output[0] == '': - configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{configs_dir}{serv}-{get_date.return_date('config')}.cfg" + cfg = config_common.generate_config_path('haproxy', serv) config_mod.get_config(serv, cfg) cmd = 'string=`grep global %s -n -A5 |grep maxcon -n |awk -F":" \'{print $2}\'|awk -F"-" \'{print $1}\'` ' \ @@ -357,8 +349,7 @@ def change_maxconn_frontend(serv, maxconn, frontend) -> str: if stderr != '': return stderr[0] elif output[0] == '': - configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{configs_dir}{serv}-{get_date.return_date('config')}.cfg" + cfg = config_common.generate_config_path('haproxy', serv) config_mod.get_config(serv, cfg) cmd = 'string=`grep %s %s -n -A5 |grep maxcon -n |awk -F":" \'{print $2}\'|awk -F"-" \'{print $1}\'` ' \ @@ -390,8 +381,7 @@ def change_maxconn_backend(serv, backend, backend_server, maxconn) -> str: if stderr != '': return stderr[0] elif output[0] == '': - configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{configs_dir}{serv}-{get_date.return_date('config')}.cfg" + cfg = config_common.generate_config_path('haproxy', serv) config_mod.get_config(serv, cfg) cmd = 'string=`grep %s %s -n -A10 |grep maxcon -n|grep %s |awk -F":" \'{print $2}\'|awk -F"-" \'{print $1}\'` ' \ @@ -457,7 +447,7 @@ def list_of_lists(serv) -> str: return '------' -def show_lists(serv, list_id, color, list_name) -> None: +def show_lists(serv, list_id, color, list_name) -> str: haproxy_sock_port = sql.get_setting('haproxy_sock_port') cmd = f'echo "show acl #{list_id}"|nc {serv} {haproxy_sock_port}' output, stderr = server_mod.subprocess_execute(cmd) diff --git a/app/modules/config/section.py b/app/modules/config/section.py index c068a216..d44ea4d4 100644 --- a/app/modules/config/section.py +++ b/app/modules/config/section.py @@ -1,11 +1,43 @@ import re -import modules.db.sql as sql -import modules.server.server as server_mod -from modules.common.common import return_nice_path +import app.modules.db.sql as sql +import app.modules.server.server as server_mod +from app.modules.common.common import return_nice_path -def get_sections(config, **kwargs): +SECTION_NAMES = ( + 'global', 'listen', 'frontend', 'backend', 'cache', 'defaults', '#HideBlockStart', + '#HideBlockEnd', 'peers', 'resolvers', 'userlist', 'http-errors' +) + + +def _extract_section_name(line: str): + """ + Extracts the section name from the given line. + + :param line: The line to extract the section name from. + :return: The extracted section name as a string if it starts with one of the SECTION_NAMES, + None otherwise. + """ + line = line.strip() + if line.startswith(SECTION_NAMES): + return line + return None + + +def get_sections(config: str, **kwargs) -> list: + """ + This method, `get_sections`, is used to extract sections from a configuration file. It takes two parameters: `config`, which is the path to the configuration file, and `kwargs`, which + * is a variable-length keyword argument that can provide additional options. + + :param config: The path to the configuration file. + :param kwargs: Additional options to customize the extraction. + + :return: A list containing the extracted sections. + + .. note:: The `service` option in `kwargs` can be used to specify a particular service to extract sections for. If the `service` option is not provided or is not equal to `'keepalived + *'`, this method will extract all sections. Otherwise, it will only extract sections that contain an IP address. + """ return_config = list() with open(config, 'r') as f: for line in f: @@ -15,17 +47,19 @@ def get_sections(config, **kwargs): if find_ip: return_config.append(find_ip[0]) else: - if line.startswith(( - 'global', 'listen', 'frontend', 'backend', 'cache', 'defaults', '#HideBlockStart', - '#HideBlockEnd', 'peers', 'resolvers', 'userlist', 'http-errors' - )): + if _extract_section_name(line): line = line.strip() return_config.append(line) return return_config -def get_section_from_config(config, section): +def get_section_from_config(config: str, section) -> tuple: + """ + :param config: The path to the configuration file. + :param section: The section name to retrieve from the configuration file. + :return: A tuple containing the starting line number, ending line number, and the content of the specified section. + """ record = False start_line = "" end_line = "" @@ -38,10 +72,7 @@ def get_section_from_config(config, section): record = True continue if record: - if line.startswith(( - 'global', 'listen', 'frontend', 'backend', 'cache', 'defaults', '#HideBlockStart', - '#HideBlockEnd', 'peers', 'resolvers', 'userlist', 'http-errors' - )): + if _extract_section_name(line): record = False end_line = index end_line = end_line - 1 @@ -56,7 +87,14 @@ def get_section_from_config(config, section): return start_line, end_line, return_config -def rewrite_section(start_line, end_line, config, section): +def rewrite_section(start_line: str, end_line: str, config: str, section: str) -> str: + """ + :param start_line: The line number where the section to be rewritten starts. + :param end_line: The line number where the section to be rewritten ends. + :param config: The path to the configuration file. + :param section: The new section to be inserted in place of the existing section. + :return: The modified configuration with the section rewritten. + """ record = False start_line = int(start_line) end_line = int(end_line) @@ -81,9 +119,14 @@ def rewrite_section(start_line, end_line, config, section): def get_remote_sections(server_ip: str, service: str) -> str: - remote_dir = service + '_dir' - config_dir = sql.get_setting(remote_dir) - config_dir = return_nice_path(config_dir) + """ + Get the remote sections from a server. + + :param server_ip: The IP address of the server. + :param service: The name of the service (e.g., apache). + :return: The remote sections. + """ + config_dir = return_nice_path(sql.get_setting(f'{service}_dir')) section_name = 'server_name' if service == 'apache': diff --git a/app/modules/db/db_model.py b/app/modules/db/db_model.py index 25bd0f20..7e09e17d 100644 --- a/app/modules/db/db_model.py +++ b/app/modules/db/db_model.py @@ -190,6 +190,7 @@ class Cred(BaseModel): username = CharField() password = CharField(null=True) groups = IntegerField(constraints=[SQL('DEFAULT 1')]) + passphrase = CharField(null=True) class Meta: table_name = 'cred' diff --git a/app/modules/db/sql.py b/app/modules/db/sql.py index a0339001..937a54b6 100755 --- a/app/modules/db/sql.py +++ b/app/modules/db/sql.py @@ -4,6 +4,8 @@ import os import sys import traceback +from flask import request + from modules.db.db_model import * import modules.roxy_wi_tools as roxy_wi_tools @@ -19,24 +21,17 @@ def out_error(error): def get_setting(param, **kwargs): - import http.cookies - user_group = '' try: - cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) - user_group_id = cookie.get('group') - user_group_id1 = user_group_id.value - groups = sql.select_groups(id=user_group_id1) + user_group_id = request.cookies.get('group') + groups = select_groups(id=user_group_id) for g in groups: - if g.group_id == int(user_group_id1): - if kwargs.get('id'): - user_group = g.group_id - else: - user_group = g.name + if int(g.group_id) == int(user_group_id): + user_group = g.group_id + break except Exception: pass - - if user_group == '' or param in ('proxy'): + if user_group == '' or param == 'proxy': user_group = 1 if kwargs.get('all'): @@ -54,7 +49,7 @@ def get_setting(param, **kwargs): else: for setting in query_res: if param in ( - 'nginx_stats_port', 'session_ttl', 'token_ttl', 'stats_port', 'haproxy_sock_port', 'ldap_type', + 'nginx_stats_port', 'session_ttl', 'token_ttl', 'haproxy_stats_port', 'haproxy_sock_port', 'ldap_type', 'ldap_port', 'ldap_enable', 'log_time_storage', 'syslog_server_enable', 'smon_check_interval', 'checker_check_interval', 'port_scan_interval', 'smon_keep_history_range', 'checker_keep_history_range', 'portscanner_keep_history_range', 'checker_maxconn_threshold', 'apache_stats_port', 'smon_ssl_expire_warning_alert', @@ -201,12 +196,12 @@ def add_setting_for_new_group(group_id): {'param': 'syslog_server_enable', 'value': '0', 'section': 'logs', 'desc': 'Enable getting logs from a syslog server; (0 - no, 1 - yes)', 'group': group_id}, {'param': 'syslog_server', 'value': '', 'section': 'logs', 'desc': 'IP address of the syslog_server', 'group': group_id}, - {'param': 'stats_user', 'value': 'admin', 'section': 'haproxy', + {'param': 'haproxy_stats_user', 'value': 'admin', 'section': 'haproxy', 'desc': 'Username for accessing HAProxy stats page', 'group': group_id}, - {'param': 'stats_password', 'value': 'password', 'section': 'haproxy', + {'param': 'haproxy_stats_password', 'value': 'password', 'section': 'haproxy', 'desc': 'Password for accessing HAProxy stats page', 'group': group_id}, - {'param': 'stats_port', 'value': '8085', 'section': 'haproxy', 'desc': 'Port for HAProxy stats page', 'group': group_id}, - {'param': 'stats_page', 'value': 'stats', 'section': 'haproxy', 'desc': 'URI for HAProxy stats page', 'group': group_id}, + {'param': 'haproxy_stats_port', 'value': '8085', 'section': 'haproxy', 'desc': 'Port for HAProxy stats page', 'group': group_id}, + {'param': 'haproxy_stats_page', 'value': 'stats', 'section': 'haproxy', 'desc': 'URI for HAProxy stats page', 'group': group_id}, {'param': 'haproxy_dir', 'value': '/etc/haproxy', 'section': 'haproxy', 'desc': 'Path to the HAProxy directory', 'group': group_id}, {'param': 'haproxy_config_path', 'value': '/etc/haproxy/haproxy.cfg', 'section': 'haproxy', 'desc': 'Path to the HAProxy configuration file', 'group': group_id}, {'param': 'server_state_file', 'value': '/etc/haproxy/haproxy.state', 'section': 'haproxy', 'desc': 'Path to the HAProxy state file', 'group': group_id}, @@ -341,7 +336,7 @@ def update_server(hostname, group, typeip, enable, master, server_id, cred, port out_error(e) -def update_server_services(server_id: str, haproxy: int, nginx: int, apache: int, keepalived: int) -> bool: +def update_server_services(server_id: int, haproxy: int, nginx: int, apache: int, keepalived: int) -> bool: try: server_update = Server.update( haproxy=haproxy, nginx=nginx, apache=apache, keepalived=keepalived @@ -503,13 +498,13 @@ def get_group_id_by_name(group_name): return group_id.group_id -def get_group_id_by_server_ip(server_ip): - try: - group_id = Server.get(Server.ip == server_ip) - except Exception as e: - out_error(e) - else: - return group_id.groups +# def get_group_id_by_server_ip(server_ip): +# try: +# group_id = Server.get(Server.ip == server_ip) +# except Exception as e: +# out_error(e) +# else: +# return group_id.groups def get_cred_id_by_server_ip(server_ip): @@ -549,22 +544,22 @@ def select_server_id_by_ip(server_ip): return server_id -def select_server_name_by_ip(server_ip): - try: - server_name = Server.get(Server.ip == server_ip).hostname - except Exception: - return None - else: - return server_name - - -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_name_by_ip(server_ip): +# try: +# server_name = Server.get(Server.ip == server_ip).hostname +# except Exception: +# return None +# else: +# return server_name +# +# +# 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: int) -> str: @@ -639,7 +634,6 @@ def select_servers(**kwargs): def write_user_uuid(login, user_uuid): session_ttl = get_setting('session_ttl') - session_ttl = int(session_ttl) user_id = get_user_id_by_username(login) cur_date = get_date.return_date('regular', timedelta=session_ttl) @@ -740,8 +734,8 @@ def delete_old_uuid(): def update_last_act_user(uuid: str, token: str, ip: str) -> None: - session_ttl = int(get_setting('session_ttl')) - token_ttl = int(get_setting('token_ttl')) + session_ttl = get_setting('session_ttl') + token_ttl = get_setting('token_ttl') cur_date_session = get_date.return_date('regular', timedelta=session_ttl) cur_date_token = get_date.return_date('regular', timedelta=token_ttl) cur_date = get_date.return_date('regular') @@ -1025,6 +1019,13 @@ def update_ssh(cred_id, name, enable, group, username, password): out_error(e) +def update_ssh_passphrase(name: str, passphrase: str): + try: + Cred.update(passphrase=passphrase).where(Cred.name == name).execute() + except Exception as e: + out_error(e) + + def insert_backup_job(server, rserver, rpath, backup_type, time, cred, description): try: Backup.insert( @@ -2560,18 +2561,18 @@ def update_server_pos(pos, server_id) -> str: return 'not_ok' -def check_token_exists(token): - try: - import http.cookies - import os - cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) - user_id = cookie.get('uuid') - if get_token(user_id.value) == token: - return True - else: - return False - except Exception: - return False +# def check_token_exists(token): +# try: +# import http.cookies +# import os +# cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE")) +# user_id = cookie.get('uuid') +# if get_token(user_id.value) == token: +# return True +# else: +# return False +# except Exception: +# return False def insert_smon(name, enable, group, desc, telegram, slack, pd, user_group, check_type): @@ -2984,7 +2985,7 @@ def smon_list(user_group): return query_res -def select_one_smon(smon_id: int, check_id: int) -> object: +def select_one_smon(smon_id: int, check_id: int) -> tuple: if check_id == 1: query = SmonTcpCheck.select(SmonTcpCheck, SMON).join_from(SmonTcpCheck, SMON).where(SMON.id == smon_id) elif check_id == 2: @@ -3002,10 +3003,10 @@ def select_one_smon(smon_id: int, check_id: int) -> object: return query_res -def insert_smon_history(smon_id: int, response_time: float, status: int, check_id: int, mes='') -> None: +def insert_smon_history(smon_id: int, resp_time: float, status: int, check_id: int, mes='') -> None: cur_date = get_date.return_date('regular') try: - SmonHistory.insert(smon_id=smon_id, response_time=response_time, status=status, date=cur_date, + SmonHistory.insert(smon_id=smon_id, response_time=resp_time, status=status, date=cur_date, check_id=check_id, mes=mes).execute() except Exception as e: out_error(e) @@ -3043,7 +3044,7 @@ def get_last_smon_status_by_check(smon_id: int) -> object: return '' -def get_last_smon_res_time_by_check(smon_id: int, check_id: int) -> object: +def get_last_smon_res_time_by_check(smon_id: int, check_id: int) -> int: query = SmonHistory.select().where( (SmonHistory.smon_id == smon_id) & (SmonHistory.check_id == check_id) @@ -3108,7 +3109,7 @@ def get_smon_service_name_by_id(smon_id: int) -> str: return '' -def get_avg_resp_time(smon_id: int, check_id: int) -> object: +def get_avg_resp_time(smon_id: int, check_id: int) -> int: try: query_res = SmonHistory.select(fn.AVG(SmonHistory.response_time)).where( (SmonHistory.smon_id == smon_id) & @@ -3137,21 +3138,21 @@ def insert_alerts(user_group, level, ip, port, message, service): conn.close() -def select_alerts(user_group): - cursor = conn.cursor() - if mysql_enable == '1': - sql = """ select level, message, `date` from alerts where user_group = '%s' and `date` <= (now()+ INTERVAL 10 second) """ % ( - user_group) - else: - sql = """ select level, message, `date` from alerts where user_group = '%s' and `date` >= datetime('now', '-20 second', 'localtime') - and `date` <= datetime('now', 'localtime') ; """ % ( - user_group) - try: - cursor.execute(sql) - except Exception as e: - out_error(e) - else: - return cursor.fetchall() +# def select_alerts(user_group): +# cursor = conn.cursor() +# if mysql_enable == '1': +# sql = """ select level, message, `date` from alerts where user_group = '%s' and `date` <= (now()+ INTERVAL 10 second) """ % ( +# user_group) +# else: +# sql = """ select level, message, `date` from alerts where user_group = '%s' and `date` >= datetime('now', '-20 second', 'localtime') +# and `date` <= datetime('now', 'localtime') ; """ % ( +# user_group) +# try: +# cursor.execute(sql) +# except Exception as e: +# out_error(e) +# else: +# return cursor.fetchall() def select_all_alerts_for_all(): @@ -3348,74 +3349,6 @@ def select_port_scanner_history(serv): return query_res -def add_provider_do(provider_name, provider_group, provider_token): - cur_date = get_date.return_date('regular') - try: - ProvidersCreds.insert( - name=provider_name, type='do', group=provider_group, key=provider_token, - create_date=cur_date, edit_date=cur_date - ).execute() - return True - except Exception as e: - out_error(e) - return False - - -def add_provider_aws(provider_name, provider_group, provider_key, provider_secret): - cur_date = get_date.return_date('regular') - try: - ProvidersCreds.insert( - name=provider_name, type='aws', group=provider_group, key=provider_key, secret=provider_secret, - create_date=cur_date, edit_date=cur_date - ).execute() - return True - except Exception as e: - out_error(e) - return False - - -def add_provider_gcore(provider_name, provider_group, provider_user, provider_pass): - cur_date = get_date.return_date('regular') - try: - ProvidersCreds.insert( - name=provider_name, type='gcore', group=provider_group, key=provider_user, - secret=provider_pass, create_date=cur_date, edit_date=cur_date - ).execute() - return True - except Exception as e: - out_error(e) - return False - - -def select_providers(user_group, **kwargs): - if user_group == 1: - query = ProvidersCreds.select() - else: - if kwargs.get('key'): - query = ProvidersCreds.select().where( - (ProvidersCreds.key == kwargs.get('key')) - & (ProvidersCreds.group == user_group) - ) - else: - query = ProvidersCreds.select().where(ProvidersCreds.group == user_group) - try: - query_res = query.execute() - except Exception as e: - out_error(e) - else: - return query_res - - -def delete_provider(provider_id): - query = ProvidersCreds.delete().where(ProvidersCreds.id == provider_id) - try: - query.execute() - return True - except Exception as e: - out_error(e) - return False - - def is_serv_protected(serv): try: query_res = Server.get(Server.ip == serv) @@ -3528,7 +3461,7 @@ def select_service_setting(server_id: int, service: str, setting: str) -> int: & (ServiceSetting.setting == setting) ).value except Exception: - return 0 + return '0' else: return result @@ -3704,15 +3637,15 @@ def select_one_system_info(server_id: int): return query_res -def select_system_info(): - query = SystemInfo.select() - try: - query_res = query.execute() - except Exception as e: - out_error(e) - return - else: - return query_res +# def select_system_info(): +# query = SystemInfo.select() +# try: +# query_res = query.execute() +# except Exception as e: +# out_error(e) +# return +# else: +# return query_res def is_system_info(server_id): @@ -3721,10 +3654,10 @@ def is_system_info(server_id): except Exception: return True else: - if query_res != '': - return False - else: + if query_res: return True + else: + return False def select_os_info(server_id): @@ -4000,7 +3933,7 @@ def update_service_checker_settings( return True -def select_service(slug: str) -> str: +def select_service(slug: str) -> object: try: query_res = Services.get(Services.slug == slug) except Exception as e: @@ -4050,9 +3983,7 @@ def select_checker_services_status() -> tuple: return services_check_status -def inset_or_update_service_status( - server_id: int, service_id: int, service_check: str, status: int -) -> None: +def inset_or_update_service_status(server_id: int, service_id: int, service_check: str, status: int) -> None: query = ServiceStatus.insert( server_id=server_id, service_id=service_id, service_check=service_check, status=status ).on_conflict('replace') @@ -4063,20 +3994,19 @@ def inset_or_update_service_status( def update_smon_ssl_expire_date(smon_id: str, expire_date: str) -> None: - SMON_update = SMON.update(ssl_expire_date=expire_date).where(SMON.id == smon_id) try: - SMON_update.execute() + SMON.update(ssl_expire_date=expire_date).where(SMON.id == smon_id) except Exception as e: out_error(e) def update_smon_alert_status(smon_id: str, alert_value: int, alert: str) -> None: if alert == 'ssl_expire_warning_alert': - SMON_update = SMON.update(ssl_expire_warning_alert=alert_value).where(SMON.id == smon_id) + query = SMON.update(ssl_expire_warning_alert=alert_value).where(SMON.id == smon_id) else: - SMON_update = SMON.update(ssl_expire_critical_alert=alert_value).where(SMON.id == smon_id) + query = SMON.update(ssl_expire_critical_alert=alert_value).where(SMON.id == smon_id) try: - SMON_update.execute() + query.execute() except Exception as e: out_error(e) @@ -4281,13 +4211,6 @@ def select_cluster_name(cluster_id: int) -> str: out_error(e) -def select_clusters_slaves(): - try: - return HaClusterSlave.select().execute() - except Exception as e: - out_error(e) - - def select_clusters_virts(): try: return HaClusterVirt.select().execute() @@ -4295,13 +4218,6 @@ def select_clusters_virts(): out_error(e) -def select_clusters_vips(): - try: - return HaClusterVip.select().execute() - except Exception as e: - out_error(e) - - def select_cluster_vips(cluster_id: int) -> object: try: return HaClusterVip.select().where(HaClusterVip.cluster_id == cluster_id).execute() @@ -4389,13 +4305,6 @@ def delete_ha_cluster_delete_slave(server_id: int) -> None: out_error(e) -def delete_ha_cluster_delete_slaves(cluster_id: int) -> None: - try: - HaClusterSlave.delete().where(HaClusterSlave.cluster_id == cluster_id).execute() - except Exception as e: - out_error(e) - - def delete_master_from_slave(server_id: int) -> None: try: Server.update(master=0).where(Server.server_id == server_id).execute() @@ -4403,17 +4312,13 @@ def delete_master_from_slave(server_id: int) -> None: out_error(e) -def ha_cluster_add_slave(server_id: int, master_id: int) -> None: - try: - HaClusterSlave.insert( - server_id=server_id, - cluster_id=HaCluster.get(HaCluster.master_id == master_id).id - ).execute() - except Exception as e: - out_error(e) - - def select_ha_cluster_not_masters_not_slaves(group_id: int): + """ + Method for selecting HA clusters excluding masters and slaves. + + :param group_id: The ID of the group. + :return: The query result. + """ try: query = Server.select().where( (Server.type_ip == 0) & @@ -4426,6 +4331,12 @@ def select_ha_cluster_not_masters_not_slaves(group_id: int): def get_router_id(cluster_id: int, default_router=0) -> int: + """ + :param cluster_id: The ID of the cluster to get the router ID from. + :param default_router: The default router ID to retrieve. Default value is 0. + :return: The ID of the router associated with the given cluster ID and default router ID. + + """ try: return HaClusterRouter.get((HaClusterRouter.cluster_id == cluster_id) & (HaClusterRouter.default == default_router)).id except Exception as e: @@ -4433,6 +4344,18 @@ def get_router_id(cluster_id: int, default_router=0) -> int: def create_ha_router(cluster_id: int) -> int: + """ + Create HA Router + + This method is used to create a HA (High Availability) router for a given cluster. + + :param cluster_id: The ID of the cluster for which the HA router needs to be created. + :return: The ID of the created HA router. + :rtype: int + + :raises Exception: If an error occurs while creating the HA router. + + """ try: last_id = HaClusterRouter.insert(cluster_id=cluster_id).execute() return last_id @@ -4502,12 +4425,6 @@ def check_ha_virt(vip_id: int) -> bool: def select_ha_cluster_name_and_slaves() -> object: try: - query = ( - HaCluster.select(HaCluster.id, HaCluster.name, HaClusterSlave.server_id) - .join(HaClusterSlave) - ) - result = query.execute() + return HaCluster.select(HaCluster.id, HaCluster.name, HaClusterSlave.server_id).join(HaClusterSlave).execute() except Exception as e: out_error(e) - else: - return result diff --git a/app/modules/roxywi/auth.py b/app/modules/roxywi/auth.py index ce58788e..cf4e875b 100644 --- a/app/modules/roxywi/auth.py +++ b/app/modules/roxywi/auth.py @@ -4,8 +4,8 @@ from flask import request, abort, make_response, url_for from flask_login import login_user from datetime import datetime, timedelta -import modules.db.sql as sql -import modules.roxywi.common as roxywi_common +import app.modules.db.sql as sql +import app.modules.roxywi.common as roxywi_common def check_login(user_uuid, token) -> str: @@ -112,7 +112,7 @@ def create_uuid_and_token(login: str): def do_login(user_uuid: str, user_group: str, user: str, next_url: str): try: - session_ttl = int(sql.get_setting('session_ttl')) + session_ttl = sql.get_setting('session_ttl') except Exception: session_ttl = 5 diff --git a/app/modules/roxywi/common.py b/app/modules/roxywi/common.py index 1ef6f672..73e3d100 100644 --- a/app/modules/roxywi/common.py +++ b/app/modules/roxywi/common.py @@ -1,9 +1,10 @@ import os import glob +from typing import Any from flask import request -import modules.db.sql as sql +import app.modules.db.sql as sql import modules.roxy_wi_tools as roxy_wi_tools time_zone = sql.get_setting('time_zone') @@ -134,9 +135,6 @@ def logging(server_ip: str, action: str, **kwargs) -> None: else: mess = f"{cur_date_in_log} {action} from {ip}\n" log_file = f"{log_path}/roxy-wi-{cur_date}.log" - elif kwargs.get('provisioning') == 1: - mess = f"{cur_date_in_log} from {ip} user: {login}, group: {user_group}, {action}\n" - log_file = f"{log_path}/provisioning-{cur_date}.log" else: mess = f"{cur_date_in_log} from {ip} user: {login}, group: {user_group}, {action} on: {server_ip}\n" log_file = f"{log_path}/config_edit-{cur_date}.log" @@ -294,3 +292,16 @@ def return_user_subscription(): logging('Roxy-WI server', f'Cannot get a user plan: {e}', roxywi=1) return user_subscription + + +def handle_exceptions(ex: Exception, server_ip: str, message: str, **kwargs: Any) -> None: + """ + :param server_ip: + :param ex: The exception that was caught + :param message: The error message to be logged and raised + :param kwargs: Additional keyword arguments to be passed to the logging function + :return: None + + """ + logging(server_ip, f'{message}: {ex}', **kwargs) + raise Exception(f'{message}: {ex}') diff --git a/app/modules/roxywi/group.py b/app/modules/roxywi/group.py index 33aa7a0f..bb578a69 100644 --- a/app/modules/roxywi/group.py +++ b/app/modules/roxywi/group.py @@ -1,5 +1,5 @@ -import modules.db.sql as sql -import modules.roxywi.common as roxywi_common +import app.modules.db.sql as sql +import app.modules.roxywi.common as roxywi_common def update_group(group_id: int, group_name: str, desc: str) -> str: diff --git a/app/modules/roxywi/nettools.py b/app/modules/roxywi/nettools.py index 90ee943d..b9068261 100644 --- a/app/modules/roxywi/nettools.py +++ b/app/modules/roxywi/nettools.py @@ -1,13 +1,31 @@ +from flask import Response, stream_with_context + +import app.modules.server.ssh as mod_ssh import modules.server.server as server_mod -def ping_from_server(server_from: str, server_to: str, action: str) -> str: - stderr = '' +def ping_from_server(server_from: str, server_to: str, action: str) -> Response: action_for_sending = '' - output1 = '' - if server_to == '': - return 'warning: enter a correct IP or DNS name' + def paint_output(generated): + yield '
' + for k in generated: + try: + k = k.decode('utf-8') + except Exception: + yield '' + for i in k.split('\n'): + if i == ' ' or i == '': + continue + if 'PING' in i: + yield f'{i}
\n' + elif i in ('no reply', 'no answer yet', 'Too many hops', '100% packet loss'): + yield f'{i}
\n' + elif 'ms' in i and '100% packet loss' not in i: + yield f'{i}
\n' + else: + yield f'{i}
' + yield '
' if action == 'nettools_ping': action_for_sending = 'ping -c 4 -W 1 -s 56 -O ' @@ -17,29 +35,10 @@ def ping_from_server(server_from: str, server_to: str, action: str) -> str: action_for_sending = action_for_sending + server_to if server_from == 'localhost': - output, stderr = server_mod.subprocess_execute(action_for_sending) + return Response(stream_with_context(paint_output(server_mod.subprocess_execute_stream(action_for_sending))), mimetype='text/html') else: - action_for_sending = [action_for_sending] - output = server_mod.ssh_command(server_from, action_for_sending, raw=1, timeout=15) - - if stderr != '': - return f'error: {stderr}' - for i in output: - if i == ' ' or i == '': - continue - i = i.strip() - if 'PING' in i: - output1 += '' - elif 'no reply' in i or 'no answer yet' in i or 'Too many hops' in i or '100% packet loss' in i: - output1 += '' - elif 'ms' in i and '100% packet loss' not in i: - output1 += '' - else: - output1 += '' - - output1 += i + '
' - - return output1 + ssh_generator = mod_ssh.ssh_connect(server_from) + return Response(stream_with_context(paint_output(ssh_generator.generate(action_for_sending))), mimetype='text/html') def telnet_from_server(server_from: str, server_to: str, port_to: str) -> str: diff --git a/app/modules/roxywi/overview.py b/app/modules/roxywi/overview.py index 6094dc58..c8f49c53 100644 --- a/app/modules/roxywi/overview.py +++ b/app/modules/roxywi/overview.py @@ -2,12 +2,12 @@ import psutil import requests from flask import render_template, request -import modules.db.sql as sql -import modules.common.common as common -import modules.tools.common as tools_common -import modules.roxywi.common as roxywi_common -import modules.server.server as server_mod -import modules.service.common as service_common +import app.modules.db.sql as sql +import app.modules.common.common as common +import app.modules.tools.common as tools_common +import app.modules.roxywi.common as roxywi_common +import app.modules.server.server as server_mod +import app.modules.service.common as service_common def user_owv() -> str: @@ -229,7 +229,7 @@ def show_services_overview(): ) -def keepalived_became_master(server_ip) -> None: +def keepalived_became_master(server_ip) -> str: commands = ["sudo kill -USR2 $(cat /var/run/keepalived.pid) && sudo grep 'Became master' /tmp/keepalived.stats |awk '{print $3}'"] became_master = server_mod.ssh_command(server_ip, commands) lang = roxywi_common.get_user_lang_for_flask() diff --git a/app/modules/roxywi/roxy.py b/app/modules/roxywi/roxy.py index 7f229613..15eb6c0a 100644 --- a/app/modules/roxywi/roxy.py +++ b/app/modules/roxywi/roxy.py @@ -6,8 +6,8 @@ import requests from requests.adapters import HTTPAdapter from requests.packages.urllib3.util.retry import Retry -import modules.db.sql as sql -import modules.roxywi.common as roxywi_common +import app.modules.db.sql as sql +import app.modules.roxywi.common as roxywi_common import app.modules.server.server as server_mod diff --git a/app/modules/roxywi/user.py b/app/modules/roxywi/user.py index ac648ca2..212c6853 100644 --- a/app/modules/roxywi/user.py +++ b/app/modules/roxywi/user.py @@ -1,10 +1,10 @@ import os -from flask import render_template, make_response +from flask import render_template, make_response, request -import modules.db.sql as sql -import modules.roxywi.common as roxywi_common -import modules.tools.alerting as alerting +import app.modules.db.sql as sql +import app.modules.roxywi.common as roxywi_common +import app.modules.tools.alerting as alerting def create_user(new_user: str, email: str, password: str, role: str, activeuser: int, group: int) -> None: @@ -28,8 +28,7 @@ def create_user(new_user: str, email: str, password: str, role: str, activeuser: except Exception as e: roxywi_common.logging('error: Cannot send email for a new user', e, roxywi=1, login=1) except Exception as e: - roxywi_common.logging('error: Cannot create a new user', e, roxywi=1, login=1) - raise Exception(f'error: Cannot create a new user: {e}') + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'error: Cannot create a new user: {e}', roxywi=1, login=1) def delete_user(user_id: int) -> str: diff --git a/app/modules/server/server.py b/app/modules/server/server.py index 3b57d3a4..95de20a2 100644 --- a/app/modules/server/server.py +++ b/app/modules/server/server.py @@ -2,11 +2,11 @@ import json from flask import render_template -import modules.db.sql as sql -import modules.server.ssh as mod_ssh -import modules.common.common as common -import modules.roxywi.auth as roxywi_auth -import modules.roxywi.common as roxywi_common +import app.modules.db.sql as sql +import app.modules.server.ssh as mod_ssh +import app.modules.common.common as common +import app.modules.roxywi.auth as roxywi_auth +import app.modules.roxywi.common as roxywi_common def ssh_command(server_ip: str, commands: list, **kwargs): @@ -58,6 +58,13 @@ def subprocess_execute(cmd): return output, stderr +def subprocess_execute_stream(cmd): + import subprocess + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, universal_newlines=True) + for line in iter(p.stdout.readline, ''): + yield line + + def subprocess_execute_with_rc(cmd): import subprocess @@ -142,7 +149,8 @@ def get_system_info(server_ip: str) -> str: network[i['logicalname']] = { 'description': i['description'], 'mac': i['serial'], - 'ip': ip + 'ip': ip, + 'up': i['configuration']['link'] } for k, j in i.items(): if isinstance(j, list): @@ -162,8 +170,7 @@ def get_system_info(server_ip: str) -> str: try: if b['id'] == 'memory': ram['size'] = round(b['size'] / 1073741824) - for memory in b['children']: - ram['slots'] += 1 + ram['slots'] = len(b['children']) except Exception: pass @@ -232,13 +239,15 @@ def get_system_info(server_ip: str) -> str: network[q['logicalname']] = { 'description': q['description'], 'mac': q['serial'], - 'ip': ip} + 'ip': ip, + 'up': q['configuration']['link']} except Exception: try: network[y['logicalname']] = { 'description': y['description'], 'mac': y['serial'], - 'ip': y['configuration']['ip']} + 'ip': y['configuration']['ip'], + 'up': y['configuration']['link']} except Exception: pass if y['class'] == 'disk': @@ -333,21 +342,19 @@ def get_system_info(server_ip: str) -> str: def show_system_info(server_ip: str, server_id: int) -> str: - if sql.is_system_info(server_id): + if not sql.is_system_info(server_id): try: get_system_info(server_ip) except Exception as e: - return f'123 {e}' + return f'error: Cannot get system info: {e}' try: system_info = sql.select_one_system_info(server_id) - - return render_template('ajax/show_system_info.html', system_info=system_info, server_ip=server_ip, server_id=server_id) except Exception as e: return f'Cannot update server info: {e}' else: system_info = sql.select_one_system_info(server_id) - return render_template('ajax/show_system_info.html', system_info=system_info, server_ip=server_ip, server_id=server_id) + return render_template('ajax/show_system_info.html', system_info=system_info, server_ip=server_ip, server_id=server_id) def update_system_info(server_ip: str, server_id: int) -> str: @@ -469,13 +476,13 @@ def server_is_up(server_ip: str) -> str: return server_status[0] -def show_server_services(server_id: int) -> None: +def show_server_services(server_id: int) -> str: server = sql.select_servers(id=server_id) lang = roxywi_common.get_user_lang_for_flask() return render_template('ajax/show_server_services.html', server=server, lang=lang) -def change_server_services(server_id: int, server_name: str, server_services: str) -> str: +def change_server_services(server_id: int, server_name: str, server_services: dict) -> str: services = sql.select_services() services_status = {} @@ -490,3 +497,51 @@ def change_server_services(server_id: int, server_name: str, server_services: st return 'ok' except Exception as e: return f'error: {e}' + + +def start_ssh_agent() -> dict: + """ + Start SSH agent + :return: Dict of SSH agent socket and pid + """ + agent_settings = {} + cmd = "ssh-agent -s" + output, stderr = subprocess_execute(cmd) + + for out in output: + if 'SSH_AUTH_SOCK=' in out: + agent_settings.setdefault('socket', out.split('=')[1].split(';')[0]) + if 'SSH_AGENT_PID=' in out: + agent_settings.setdefault('pid', out.split('=')[1].split(';')[0]) + if 'error' in stderr: + raise Exception(f'error: Cannot start SSH agent: {stderr}') + return agent_settings + + +def add_key_to_agent(ssh_settings: dict, agent_pid: dict) -> None: + """ + Add key to SSH agent + :return: None + """ + cmd = f'export SSH_AGENT_PID={agent_pid["pid"]} && export SSH_AUTH_SOCK={agent_pid["socket"]} && ' + + if ssh_settings['passphrase']: + cmd += f"{{ sleep .1; echo {ssh_settings['passphrase']}; }} | script -q /dev/null -c 'ssh-add {ssh_settings['key']}'" + else: + cmd += f'ssh-add {ssh_settings["key"]}' + output, stderr = subprocess_execute(cmd) + if 'error' in stderr: + raise Exception(f'error: Cannot add the key {ssh_settings["key"]} to SSH agent: {stderr}') + + +def stop_ssh_agent(agent_pid: dict) -> None: + """ + Stop SSH agent + :return: None + """ + + cmd = f'export SSH_AGENT_PID={agent_pid["pid"]} && ssh-agent -k' + output, stderr = subprocess_execute(cmd) + + if 'error' in stderr: + raise Exception(f'error: Cannot stop SSH agent: {stderr}') diff --git a/app/modules/server/ssh.py b/app/modules/server/ssh.py index fb5d4e8a..35d49aab 100644 --- a/app/modules/server/ssh.py +++ b/app/modules/server/ssh.py @@ -1,11 +1,12 @@ import os +from cryptography.fernet import Fernet import paramiko from flask import render_template, request import modules.db.sql as sql import modules.common.common as common -from modules.server import ssh_connection +from app.modules.server import ssh_connection import modules.roxywi.common as roxywi_common import modules.roxy_wi_tools as roxy_wi_tools @@ -22,11 +23,27 @@ def return_ssh_keys_path(server_ip: str, **kwargs) -> dict: sshs = sql.select_ssh(serv=server_ip) for ssh in sshs: + if ssh.password: + try: + password = decrypt_password(ssh.password) + except Exception as e: + raise Exception(e) + else: + password = ssh.password + if ssh.passphrase: + try: + passphrase = decrypt_password(ssh.passphrase) + except Exception as e: + raise Exception(e) + else: + passphrase = ssh.passphrase + ssh_settings.setdefault('enabled', ssh.enable) ssh_settings.setdefault('user', ssh.username) - ssh_settings.setdefault('password', ssh.password) + ssh_settings.setdefault('password', password) ssh_key = f'{lib_path}/keys/{ssh.name}.pem' if ssh.enable == 1 else '' ssh_settings.setdefault('key', ssh_key) + ssh_settings.setdefault('passphrase', passphrase) try: ssh_port = [str(server[10]) for server in sql.select_servers(server=server_ip)] @@ -39,13 +56,7 @@ def return_ssh_keys_path(server_ip: str, **kwargs) -> dict: def ssh_connect(server_ip): ssh_settings = return_ssh_keys_path(server_ip) - ssh = ssh_connection.SshConnection( - server_ip, ssh_settings['port'], - ssh_settings['user'], - ssh_settings['password'], - ssh_settings['enabled'], - ssh_settings['key'] - ) + ssh = ssh_connection.SshConnection(server_ip, ssh_settings) return ssh @@ -62,6 +73,12 @@ def create_ssh_cred() -> str: lang = roxywi_common.get_user_lang_for_flask() name = f'{name}_{group_name}' + if password != '': + try: + password = crypt_password(password) + except Exception as e: + raise Exception(e) + if username is None or name is None: return error_mess else: @@ -71,15 +88,19 @@ def create_ssh_cred() -> str: def create_ssh_cread_api(name: str, enable: str, group: str, username: str, password: str) -> bool: - groups = sql.select_groups(id=group) - for group in groups: - user_group = group.name + group_name = sql.get_group_name_by_id(group) name = common.checkAjaxInput(name) - name = f'{name}_{user_group}' + name = f'{name}_{group_name}' enable = common.checkAjaxInput(enable) username = common.checkAjaxInput(username) password = common.checkAjaxInput(password) + if password != '': + try: + password = crypt_password(password) + except Exception as e: + raise Exception(e) + if username is None or name is None: return False else: @@ -87,7 +108,7 @@ def create_ssh_cread_api(name: str, enable: str, group: str, username: str, pass return True -def upload_ssh_key(name: str, user_group: str, key: str) -> str: +def upload_ssh_key(name: str, user_group: str, key: str, passphrase: str) -> str: if '..' in name: raise Exception('error: nice try') @@ -95,7 +116,7 @@ def upload_ssh_key(name: str, user_group: str, key: str) -> str: raise Exception('error: please select credentials first') try: - key = paramiko.pkey.load_private_key(key) + key = paramiko.pkey.load_private_key(key, password=passphrase) except Exception as e: raise Exception(f'error: Cannot save SSH key file: {e}') @@ -121,15 +142,25 @@ def upload_ssh_key(name: str, user_group: str, key: str) -> str: key.write_private_key_file(ssh_keys) except Exception as e: raise Exception(f'error: Cannot save SSH key file: {e}') - else: - try: - os.chmod(ssh_keys, 0o600) - except IOError as e: - roxywi_common.logging('Roxy-WI server', e.args[0], roxywi=1) - raise Exception(f'error: something went wrong: {e}') + try: + os.chmod(ssh_keys, 0o600) + except IOError as e: + roxywi_common.logging('Roxy-WI server', e.args[0], roxywi=1) + raise Exception(f'error: something went wrong: {e}') - roxywi_common.logging("Roxy-WI server", f"A new SSH cert has been uploaded {ssh_keys}", roxywi=1, login=1) - return f'success: SSH key has been saved into: {ssh_keys}' + if passphrase != '': + try: + passphrase = crypt_password(passphrase) + except Exception as e: + raise Exception(e) + + try: + sql.update_ssh_passphrase(name, passphrase) + except Exception as e: + raise Exception(e) + + roxywi_common.logging("Roxy-WI server", f"A new SSH cert has been uploaded {ssh_keys}", roxywi=1, login=1) + return f'success: SSH key has been saved into: {ssh_keys}' def update_ssh_key() -> str: @@ -140,25 +171,33 @@ def update_ssh_key() -> str: username = common.checkAjaxInput(request.form.get('ssh_user')) password = common.checkAjaxInput(request.form.get('ssh_pass')) new_ssh_key_name = '' + ssh_key_name = '' + ssh_enable = 0 + + if password != '': + try: + password = crypt_password(password) + except Exception as e: + raise Exception(e) if username is None: return error_mess - else: - lib_path = get_config.get_config_var('main', 'lib_path') - for sshs in sql.select_ssh(id=ssh_id): - ssh_enable = sshs.enable - ssh_key_name = f'{lib_path}/keys/{sshs.name}.pem' - new_ssh_key_name = f'{lib_path}/keys/{name}.pem' + lib_path = get_config.get_config_var('main', 'lib_path') - if ssh_enable == 1: - os.rename(ssh_key_name, new_ssh_key_name) - os.chmod(new_ssh_key_name, 0o600) + for sshs in sql.select_ssh(id=ssh_id): + ssh_enable = sshs.enable + ssh_key_name = f'{lib_path}/keys/{sshs.name}.pem' + new_ssh_key_name = f'{lib_path}/keys/{name}.pem' - sql.update_ssh(ssh_id, name, enable, group, username, password) - roxywi_common.logging('Roxy-WI server', f'The SSH credentials {name} has been updated ', roxywi=1, login=1) + if ssh_enable == 1: + os.rename(ssh_key_name, new_ssh_key_name) + os.chmod(new_ssh_key_name, 0o600) - return 'ok' + sql.update_ssh(ssh_id, name, enable, group, username, password) + roxywi_common.logging('Roxy-WI server', f'The SSH credentials {name} has been updated ', roxywi=1, login=1) + + return 'ok' def delete_ssh_key(ssh_id) -> str: @@ -180,3 +219,33 @@ def delete_ssh_key(ssh_id) -> str: if sql.delete_ssh(ssh_id): roxywi_common.logging('Roxy-WI server', f'The SSH credentials {name} has deleted', roxywi=1, login=1) return 'ok' + + +def crypt_password(password: str) -> bytes: + """ + Crypt password + :param password: plain password + :return: crypted text + """ + salt = get_config.get_config_var('main', 'secret_phrase') + fernet = Fernet(salt.encode()) + try: + crypted_pass = fernet.encrypt(password.encode()) + except Exception as e: + raise Exception(f'error: Cannot crypt password: {e}') + return crypted_pass + + +def decrypt_password(password: str) -> str: + """ + Decrypt password + :param password: crypted password + :return: plain text + """ + salt = get_config.get_config_var('main', 'secret_phrase') + fernet = Fernet(salt.encode()) + try: + decryp_pass = fernet.decrypt(password.encode()).decode() + except Exception as e: + raise Exception(f'error: Cannot decrypt password: {e}') + return decryp_pass diff --git a/app/modules/server/ssh_connection.py b/app/modules/server/ssh_connection.py index f6695fdc..6a853915 100644 --- a/app/modules/server/ssh_connection.py +++ b/app/modules/server/ssh_connection.py @@ -1,41 +1,38 @@ +import select + import paramiko -from paramiko import SSHClient class SshConnection: - def __init__(self, server_ip, ssh_port, ssh_user_name, ssh_user_password, ssh_enable, ssh_key_name=None): - self.ssh = SSHClient() + def __init__(self, server_ip: str, ssh_settings: dict): + self.ssh = paramiko.SSHClient() self.ssh.load_system_host_keys() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.server_ip = server_ip - self.ssh_port = ssh_port - self.ssh_user_name = ssh_user_name - self.ssh_user_password = ssh_user_password - self.ssh_enable = ssh_enable - self.ssh_key_name = ssh_key_name + self.ssh_port = ssh_settings['port'] + self.ssh_user_name = ssh_settings['user'] + self.ssh_user_password = ssh_settings['password'] + self.ssh_enable = ssh_settings['enabled'] + self.ssh_key_name = ssh_settings['key'] + self.ssh_passphrase = ssh_settings['passphrase'] def __enter__(self): + kwargs = { + 'hostname': self.server_ip, + 'port': self.ssh_port, + 'username': self.ssh_user_name, + 'timeout': 11, + 'banner_timeout': 200, + 'look_for_keys': False + } + if self.ssh_enable == 1: + kwargs.setdefault('key_filename', self.ssh_key_name) + if self.ssh_passphrase: + kwargs.setdefault('passphrase', self.ssh_passphrase) + else: + kwargs.setdefault('password', self.ssh_user_password) try: - if self.ssh_enable == 1: - self.ssh.connect( - hostname=self.server_ip, - port=self.ssh_port, - username=self.ssh_user_name, - key_filename=self.ssh_key_name, - timeout=11, - banner_timeout=200, - look_for_keys=False - ) - else: - self.ssh.connect( - hostname=self.server_ip, - port=self.ssh_port, - username=self.ssh_user_name, - password=self.ssh_user_password, - timeout=11, - banner_timeout=200, - look_for_keys=False - ) + self.ssh.connect(**kwargs) except paramiko.AuthenticationException: raise paramiko.SSHException(f'{self.server_ip} Authentication failed, please verify your credentials') except paramiko.SSHException as sshException: @@ -100,3 +97,58 @@ class SshConnection: sftp.close() except Exception as e: raise paramiko.SSHException(str(e)) + + def generate(self, command): + with self as ssh_something: + stdin, stdout, stderr = ssh_something.ssh.exec_command(command) + channel = stdout.channel + + # we do not need stdin. + stdin.close() + # indicate that we're not going to write to that channel anymore + channel.shutdown_write() + + # read stdout/stderr in order to prevent read block hangs + yield stdout.channel.recv(len(stdout.channel.in_buffer)) + + # chunked read to prevent stalls + while (not channel.closed or channel.recv_ready() or channel.recv_stderr_ready()): + # stop if channel was closed prematurely, + # and there is no data in the buffers. + got_chunk = False + readq, _, _ = select.select([stdout.channel], [], [], 1) + for c in readq: + if c.recv_ready(): + yield stdout.channel.recv(len(c.in_buffer)) + got_chunk = True + if c.recv_stderr_ready(): + # make sure to read stderr to prevent stall + yield stderr.channel.recv_stderr( + len(c.in_stderr_buffer)) + got_chunk = True + + """ + 1) make sure that there are at least 2 cycles with no data + in the input buffers in order to not exit too early + (i.e. cat on a >200k file). + 2) if no data arrived in the last loop, + check if we already received the exit code + 3) check if input buffers are empty + 4) exit the loop + """ + if (not got_chunk and + stdout.channel.exit_status_ready() and not + stderr.channel.recv_stderr_ready() and not + stdout.channel.recv_ready()): + # indicate that we're not going + # to read from this channel anymore + stdout.channel.shutdown_read() + # close the channel + stdout.channel.close() + # exit as remote side is finished + # and our bufferes are empty + break + # close all the pseudofiles + stdout.close() + stderr.close() + self.ssh.close() diff --git a/app/modules/service/action.py b/app/modules/service/action.py index f7ec18a2..29db8b5e 100644 --- a/app/modules/service/action.py +++ b/app/modules/service/action.py @@ -1,8 +1,8 @@ -import modules.db.sql as sql -import modules.common.common as common -import modules.server.server as server_mod -import modules.roxywi.common as roxywi_common -import modules.service.common as service_common +import app.modules.db.sql as sql +import app.modules.common.common as common +import app.modules.server.server as server_mod +import app.modules.roxywi.common as roxywi_common +import app.modules.service.common as service_common def common_action(server_ip: str, action: str, service: str) -> str: @@ -18,70 +18,71 @@ def common_action(server_ip: str, action: str, service: str) -> str: return action_functions[service](server_ip, action) -def action_haproxy(server_ip: str, action: str) -> str: - haproxy_service_name = "haproxy" +def get_action_command(service: str, action: str, server_id: int) -> str: + """ + :param service: The name of the service for which the action command is needed. + :param action: The action to be performed on the service (e.g. start, stop, restart). + :param server_id: The ID of the server. + :return: A list containing the action command that needs to be executed. + """ + is_docker = sql.select_service_setting(server_id, service, 'dockerized') + if is_docker == '1': + container_name = sql.get_setting(f'{service}_container_name') + if action == 'reload': + action = 'kill -S HUP' + commands = f"sudo docker {action} {container_name}" + else: + service_name = service_common.get_correct_service_name(service, server_id) + commands = f"sudo systemctl {action} {service_name}" + + return commands + + +def action_haproxy(server_ip: str, action: str) -> str: try: - service_common.is_restarted(server_ip, action) + service_common.is_protected(server_ip, action) except Exception as e: return str(e) - if service_common.check_haproxy_config(server_ip): - server_id = sql.select_server_id_by_ip(server_ip=server_ip) - is_docker = sql.select_service_setting(server_id, 'haproxy', 'dockerized') - - if action == 'restart': - try: - service_common.is_not_allowed_to_restart(server_id, 'haproxy') - except Exception as e: - return str(e) - - if is_docker == '1': - container_name = sql.get_setting('haproxy_container_name') - commands = [f"sudo docker {action} {container_name}"] - else: - haproxy_enterprise = sql.select_service_setting(server_id, 'haproxy', 'haproxy_enterprise') - if haproxy_enterprise == '1': - haproxy_service_name = "hapee-2.0-lb" - commands = [f"sudo systemctl {action} {haproxy_service_name}"] - server_mod.ssh_command(server_ip, commands, timeout=5) - roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service='haproxy') - return f"success: HAProxy has been {action}" - else: + if not service_common.check_haproxy_config(server_ip): return "error: Bad config, check please" + server_id = sql.select_server_id_by_ip(server_ip=server_ip) + + if service_common.is_not_allowed_to_restart(server_id, 'haproxy', action): + return f'error: This server is not allowed to be restarted' + + commands = [get_action_command('haproxy', action, server_id)] + server_mod.ssh_command(server_ip, commands, timeout=5) + roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service='haproxy') + return f"success: HAProxy has been {action}" + def action_nginx(server_ip: str, action: str) -> str: try: - service_common.is_restarted(server_ip, action) + service_common.is_protected(server_ip, action) except Exception as e: return str(e) - if service_common.check_nginx_config(server_ip): - server_id = sql.select_server_id_by_ip(server_ip=server_ip) + check_config = service_common.check_nginx_config(server_ip) + if check_config != 'ok': + return f"error: Bad config, check please {check_config}" - if action == 'restart': - try: - service_common.is_not_allowed_to_restart(server_id, 'nginx') - except Exception as e: - return str(e) - is_docker = sql.select_service_setting(server_id, 'nginx', 'dockerized') + server_id = sql.select_server_id_by_ip(server_ip=server_ip) - if is_docker == '1': - container_name = sql.get_setting('nginx_container_name') - commands = [f"sudo docker {action} {container_name}"] - else: - commands = [f"sudo systemctl {action} nginx"] - server_mod.ssh_command(server_ip, commands, timeout=5) - roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service='nginx') - return f"success: NGINX has been {action}" - else: - return "error: Bad config, check please" + if service_common.is_not_allowed_to_restart(server_id, 'nginx', action): + return f'error: This server is not allowed to be restarted' + + commands = [get_action_command('nginx', action, server_id)] + server_mod.ssh_command(server_ip, commands, timeout=5) + roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service='nginx') + return f"success: NGINX has been {action}" def action_keepalived(server_ip: str, action: str) -> str: try: - service_common.is_restarted(server_ip, action) + service_common.is_protected(server_ip, action) except Exception as e: return str(e) @@ -93,26 +94,16 @@ def action_keepalived(server_ip: str, action: str) -> str: def action_apache(server_ip: str, action: str) -> str: try: - service_common.is_restarted(server_ip, action) + service_common.is_protected(server_ip, action) except Exception as e: return str(e) server_id = sql.select_server_id_by_ip(server_ip) - if action == 'restart': - try: - service_common.is_not_allowed_to_restart(server_id, 'apache') - except Exception as e: - return str(e) + if service_common.is_not_allowed_to_restart(server_id, 'apache', action): + return f'error: This server is not allowed to be restarted' - is_docker = sql.select_service_setting(server_id, 'apache', 'dockerized') - if is_docker == '1': - container_name = sql.get_setting('apache_container_name') - commands = [f"sudo docker {action} {container_name}"] - else: - service_apache_name = service_common.get_correct_apache_service_name(None, server_id) - - commands = [f"sudo systemctl {action} {service_apache_name}"] + commands = [get_action_command('apache', action, server_id)] server_mod.ssh_command(server_ip, commands, timeout=5) roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service='apache') return f"success: Apache has been {action}" @@ -120,7 +111,7 @@ def action_apache(server_ip: str, action: str) -> str: def action_haproxy_waf(server_ip: str, action: str) -> str: try: - service_common.is_restarted(server_ip, action) + service_common.is_protected(server_ip, action) except Exception as e: return str(e) @@ -136,7 +127,7 @@ def action_nginx_waf(server_ip: str, action: str) -> str: config_dir = common.return_nice_path(sql.get_setting('nginx_dir')) try: - service_common.is_restarted(server_ip, action) + service_common.is_protected(server_ip, action) except Exception as e: return str(e) diff --git a/app/modules/service/common.py b/app/modules/service/common.py index 2c8c7368..4420b679 100644 --- a/app/modules/service/common.py +++ b/app/modules/service/common.py @@ -1,17 +1,33 @@ import requests from flask import render_template, request -import modules.db.sql as sql -import modules.server.ssh as mod_ssh -import modules.common.common as common -import modules.server.server as server_mod -import modules.roxywi.common as roxywi_common -import modules.roxy_wi_tools as roxy_wi_tools -import modules.config.section as section_mod +import app.modules.db.sql as sql +import app.modules.server.ssh as mod_ssh +import app.modules.common.common as common +import app.modules.server.server as server_mod +import app.modules.roxywi.common as roxywi_common +import app.modules.config.section as section_mod +import app.modules.config.common as config_common -time_zone = sql.get_setting('time_zone') -get_date = roxy_wi_tools.GetDate(time_zone) -get_config = roxy_wi_tools.GetConfigVar() + +def get_correct_service_name(service: str, server_id: int) -> str: + """ + :param service: The name of the service. + :param server_id: The ID of the server. + :return: The correct service name based on the provided parameters. + + This method takes a service name and server ID as input and returns the correct service name based on the given parameters. If the service name is 'haproxy', it checks if haproxy_enter + *prise is set to '1' in the database for the given server ID. If true, it returns "hapee-2.0-lb". If the service name is 'apache', it calls the get_correct_apache_service_name() method + * with parameters 0 and the server ID to get the correct apache service name. If none of the conditions match, it will return the original service name. + """ + if service == 'haproxy': + haproxy_enterprise = sql.select_service_setting(server_id, 'haproxy', 'haproxy_enterprise') + if haproxy_enterprise == '1': + return "hapee-2.0-lb" + if service == 'apache': + return get_correct_apache_service_name(0, server_id) + + return service def check_haproxy_version(server_ip): @@ -25,24 +41,41 @@ def check_haproxy_version(server_ip): return ver -def is_restarted(server_ip: str, action: str) -> None: +def is_protected(server_ip: str, action: str) -> None: + """ + Check if the server is protected and the user has the required role. + + :param server_ip: The IP address of the server. + :param action: The action to be performed on the server. + :return: None + :raises: Exception if the server is protected and the user role is not high enough. + """ user_uuid = request.cookies.get('uuid') - group_id = request.cookies.get('group') - group_id = int(group_id) + group_id = int(request.cookies.get('group')) user_role = sql.get_user_role_by_uuid(user_uuid, group_id) if sql.is_serv_protected(server_ip) and int(user_role) > 2: raise Exception(f'error: This server is protected. You cannot {action} it') -def is_not_allowed_to_restart(server_id: int, service: str) -> None: - if service != 'waf': - is_restart = sql.select_service_setting(server_id, service, 'restart') - else: - is_restart = 0 +def is_not_allowed_to_restart(server_id: int, service: str, action: str) -> int: + """ + :param server_id: The ID of the server. + :param service: The name of the service. + :param action: The action to perform on the service. + :return: An integer indicating whether the restart is allowed or not. - if int(is_restart) == 1: - raise Exception('warning: This service is not allowed to be restarted') + This method checks if the given service is not allowed to be restarted based on the provided server ID, service name, and action. It returns `0` if the restart is not allowed, otherwise + * it returns `1`. + """ + is_restart = 0 + if service != 'waf' and action == 'restart': + try: + is_restart = sql.select_service_setting(server_id, service, 'restart') + except Exception as e: + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'error: Cannot get restart settings for service {service}: {e}') + + return is_restart def get_exp_version(server_ip: str, service_name: str) -> str: @@ -105,7 +138,7 @@ def check_haproxy_config(server_ip): container_name = sql.get_setting('haproxy_container_name') commands = [f"sudo docker exec -it {container_name} haproxy -q -c -f {config_path}"] else: - commands = [f"haproxy -q -c -f {config_path}"] + commands = [f"haproxy -q -c -f {config_path}"] try: with mod_ssh.ssh_connect(server_ip) as ssh: @@ -119,54 +152,48 @@ def check_haproxy_config(server_ip): print(f'error: {e}') -def check_nginx_config(server_ip) -> bool: - commands = [f"nginx -q -t -p {sql.get_setting('nginx_dir')}"] +def check_nginx_config(server_ip) -> str: + """ + Check the Nginx configuration on the specified server IP. + + :param server_ip: The IP address of the server where Nginx is running. + :return: True if the Nginx configuration is valid, False otherwise. + """ + commands = [f"sudo nginx -q -t -p {sql.get_setting('nginx_dir')}"] with mod_ssh.ssh_connect(server_ip) as ssh: for command in commands: stdin, stdout, stderr = ssh.run_command(command) - if not stderr.read(): - return True - else: - return False + for line in stdout.readlines(): + if 'emerg' in line or 'error' in line or 'faield' in line: + return line + return 'ok' def overview_backends(server_ip: str, service: str) -> str: import modules.config.config as config_mod lang = roxywi_common.get_user_lang_for_flask() - format_file = 'cfg' - - if service == 'haproxy': - configs_dir = get_config.get_config_var('configs', 'haproxy_save_configs_dir') - format_file = 'cfg' - elif service == 'keepalived': - configs_dir = get_config.get_config_var('configs', 'keepalived_save_configs_dir') - format_file = 'conf' if service != 'nginx' and service != 'apache': + format_file = config_common.get_file_format(service) + config_dir = config_common.get_config_dir(service) + cfg = config_common.generate_config_path(service, server_ip) + try: - sections = section_mod.get_sections(configs_dir + roxywi_common.get_files(configs_dir, format_file)[0], - service=service) + sections = section_mod.get_sections(config_dir + roxywi_common.get_files(config_dir, format_file)[0], service=service) except Exception as e: roxywi_common.logging('Roxy-WI server', str(e), roxywi=1) try: - cfg = f"{configs_dir}{server_ip}-{get_date.return_date('config')}.{format_file}" - except Exception as e: - roxywi_common.logging('Roxy-WI server', f' Cannot generate a cfg path {e}', roxywi=1) - try: - if service == 'keepalived': - config_mod.get_config(server_ip, cfg, keepalived=1) - else: - config_mod.get_config(server_ip, cfg) + config_mod.get_config(server_ip, cfg, service=service) except Exception as e: roxywi_common.logging('Roxy-WI server', f' Cannot download a config {e}', roxywi=1) try: sections = section_mod.get_sections(cfg, service=service) except Exception as e: roxywi_common.logging('Roxy-WI server', f' Cannot get sections from config file {e}', roxywi=1) - sections = 'Cannot get backends' + sections = f'error: Cannot get backends {e}' else: sections = section_mod.get_remote_sections(server_ip, service) @@ -174,12 +201,7 @@ def overview_backends(server_ip: str, service: str) -> str: def get_overview_last_edit(server_ip: str, service: str) -> str: - if service == 'nginx': - config_path = sql.get_setting('nginx_config_path') - elif service == 'keepalived': - config_path = sql.get_setting('keepalived_config_path') - else: - config_path = sql.get_setting('haproxy_config_path') + config_path = sql.get_setting(f'{service}_config_path') commands = ["ls -l %s |awk '{ print $6\" \"$7\" \"$8}'" % config_path] try: return server_mod.ssh_command(server_ip, commands) @@ -212,7 +234,6 @@ def get_stat_page(server_ip: str, service: str) -> str: if service == 'nginx': lang = roxywi_common.get_user_lang_for_flask() servers_with_status = list() - h = () out1 = [] for k in data.decode('utf-8').split(): out1.append(k) @@ -229,18 +250,15 @@ def show_service_version(server_ip: str, service: str) -> str: return check_haproxy_version(server_ip) server_id = sql.select_server_id_by_ip(server_ip) - service_name = service + service_name = get_correct_service_name(service, server_id) is_dockerized = sql.select_service_setting(server_id, service, 'dockerized') - if service == 'apache': - service_name = get_correct_apache_service_name(None, server_id) - if is_dockerized == '1': container_name = sql.get_setting(f'{service}_container_name') if service == 'apache': - cmd = [f'docker exec -it {container_name} /usr/local/apache2/bin/httpd -v 2>&1|head -1|awk -F":" \'{{print $2}}\''] + cmd = [f'docker exec -it {container_name} /usr/local/apache2/bin/httpd -v 2>&1|head -1|awk -F":" \'{{print $2}}\''] else: - cmd = [f'docker exec -it {container_name} /usr/sbin/{service_name} -v 2>&1|head -1|awk -F":" \'{{print $2}}\''] + cmd = [f'docker exec -it {container_name} /usr/sbin/{service_name} -v 2>&1|head -1|awk -F":" \'{{print $2}}\''] else: cmd = [f'sudo /usr/sbin/{service_name} -v|head -1|awk -F":" \'{{print $2}}\''] diff --git a/app/modules/service/exporter_installation.py b/app/modules/service/exporter_installation.py index 98b1cdcc..4040a17b 100644 --- a/app/modules/service/exporter_installation.py +++ b/app/modules/service/exporter_installation.py @@ -1,126 +1,37 @@ import os -import modules.db.sql as sql -import modules.server.server as server_mod -from modules.service.installation import show_installation_output, show_success_installation -from modules.server.ssh import return_ssh_keys_path +import app.modules.db.sql as sql +from app.modules.service.installation import run_ansible -def haproxy_exp_installation(serv, ver, ext_prom): - script = "install_haproxy_exporter.sh" - stats_port = sql.get_setting('stats_port') - server_state_file = sql.get_setting('server_state_file') - stats_user = sql.get_setting('stats_user') - stats_password = sql.get_setting('stats_password') - stat_page = sql.get_setting('stats_page') - proxy = sql.get_setting('proxy') - ssh_settings = return_ssh_keys_path(serv) - full_path = '/var/www/haproxy-wi/app' - service = 'HAProxy exporter' +def generate_exporter_inc(server_ip: str, ext_prom: int, ver: str, exporter: str) -> object: + inv = {"server": {"hosts": {}}} + server_ips = [server_ip] + inv['server']['hosts'][server_ip] = { + 'EXP_PROM': ext_prom, + f'{exporter}_exporter_version': ver, + 'service': f'{exporter} exporter' + } + if exporter in ('haproxy', 'nginx', 'apache'): + inv['server']['hosts'][server_ip]['STAT_PORT'] = sql.get_setting(f'{exporter}_stats_port') + inv['server']['hosts'][server_ip]['STATS_USER'] = sql.get_setting(f'{exporter}_stats_user') + inv['server']['hosts'][server_ip]['STATS_PASS'] = sql.get_setting(f'{exporter}_stats_password') + inv['server']['hosts'][server_ip]['STAT_PAGE'] = sql.get_setting(f'{exporter}_stats_page') + + if not os.path.isdir('/var/www/haproxy-wi/app/scripts/ansible/roles/bdellegrazie.ansible-role-prometheus_exporter'): + os.system('ansible-galaxy install bdellegrazie.ansible-role-prometheus_exporter --roles-path /var/www/haproxy-wi/app/scripts/ansible/roles/') + + if exporter == 'haproxy': + inv['server']['hosts'][server_ip]['STAT_FILE'] = sql.get_setting('server_state_file') + + return inv, server_ips + + +def install_exporter(server_ip: str, ver: str, ext_prom: int, exporter: str) -> object: + service = f'{exporter.title()} exporter' try: - os.system(f"cp {full_path}/scripts/{script} {full_path}/{script}") + inv, server_ips = generate_exporter_inc(server_ip, ext_prom, ver, exporter) + return run_ansible(inv, server_ips, f'{exporter}_exporter'), 201 except Exception as e: - raise Exception(f'error: {e}') - - if proxy is not None and proxy != '' and proxy != 'None': - proxy_serv = proxy - else: - proxy_serv = '' - - commands = [ - f"chmod +x {full_path}/{script} && {full_path}/{script} PROXY={proxy_serv} STAT_PORT={stats_port} STAT_FILE={server_state_file}" - f" SSH_PORT={ssh_settings['port']} STAT_PAGE={stat_page} VER={ver} EXP_PROM={ext_prom} STATS_USER={stats_user}" - f" STATS_PASS='{stats_password}' HOST={serv} USER={ssh_settings['user']} PASS='{ssh_settings['password']}' KEY={ssh_settings['key']}" - ] - - return_out = server_mod.subprocess_execute_with_rc(commands[0]) - - try: - show_installation_output(return_out['error'], return_out['output'], service, rc=return_out['rc']) - except Exception as e: - raise Exception(f'error: read output: {e}') - - try: - os.remove(f'{full_path}/{script}') - except Exception: - pass - - return show_success_installation(service) - - -def nginx_apache_exp_installation(serv, service, ver, ext_prom): - script = f"install_{service}_exporter.sh" - stats_user = sql.get_setting(f'{service}_stats_user') - stats_password = sql.get_setting(f'{service}_stats_password') - stats_port = sql.get_setting(f'{service}_stats_port') - stats_page = sql.get_setting(f'{service}_stats_page') - proxy = sql.get_setting('proxy') - proxy_serv = '' - ssh_settings = return_ssh_keys_path(serv) - full_path = '/var/www/haproxy-wi/app' - service = f'{service.title()} exporter' - - try: - os.system(f"cp {full_path}/scripts/{script} {full_path}/{script}") - except Exception as e: - raise Exception(f'error: {e}') - - if proxy is not None and proxy != '' and proxy != 'None': - proxy_serv = proxy - - commands = [ - f"chmod +x {full_path}/{script} && {full_path}/{script} PROXY={proxy_serv} STAT_PORT={stats_port} SSH_PORT={ssh_settings['port']} " - f"STAT_PAGE={stats_page} STATS_USER={stats_user} STATS_PASS='{stats_password}' HOST={serv} VER={ver} EXP_PROM={ext_prom} " - f"USER={ssh_settings['user']} PASS='{ssh_settings['password']}' KEY={ssh_settings['key']}" - ] - - return_out = server_mod.subprocess_execute_with_rc(commands[0]) - - try: - show_installation_output(return_out['error'], return_out['output'], service, rc=return_out['rc']) - except Exception as e: - raise Exception(f'error: read output: {e}') - - try: - os.remove(f'{full_path}/{script}') - except Exception: - pass - - return show_success_installation(service) - - -def node_keepalived_exp_installation(service: str, serv: str, ver: str, ext_prom: int) -> None: - script = f"install_{service}_exporter.sh" - proxy = sql.get_setting('proxy') - proxy_serv = '' - ssh_settings = return_ssh_keys_path(serv) - full_path = '/var/www/haproxy-wi/app' - service = 'Node exporter' - - try: - os.system(f"cp {full_path}/scripts/{script} {full_path}/{script}") - except Exception as e: - raise Exception(f'error: {e}') - - if proxy is not None and proxy != '' and proxy != 'None': - proxy_serv = proxy - - commands = [ - f"chmod +x {full_path}/{script} && {full_path}/{script} PROXY={proxy_serv} SSH_PORT={ssh_settings['port']} VER={ver} EXP_PROM={ext_prom} " - f"HOST={serv} USER={ssh_settings['user']} PASS='{ssh_settings['password']}' KEY={ssh_settings['key']}" - ] - - return_out = server_mod.subprocess_execute_with_rc(commands[0]) - - try: - show_installation_output(return_out['error'], return_out['output'], service, rc=return_out['rc']) - except Exception as e: - raise Exception(f'error: read output: {e}') - - try: - os.remove(f'{full_path}/{script}') - except Exception: - pass - - return show_success_installation(service) + raise Exception(f'error: Cannot install {service}: {e}') diff --git a/app/modules/service/haproxy.py b/app/modules/service/haproxy.py index dca023c8..35a2892a 100644 --- a/app/modules/service/haproxy.py +++ b/app/modules/service/haproxy.py @@ -3,22 +3,18 @@ import requests from flask import request -import modules.db.sql as sql -import modules.server.server as server_mod -import modules.config.config as config_mod -import modules.roxywi.common as roxywi_common -import modules.roxy_wi_tools as roxy_wi_tools - -time_zone = sql.get_setting('time_zone') -get_date = roxy_wi_tools.GetDate(time_zone) -get_config = roxy_wi_tools.GetConfigVar() +import app.modules.db.sql as sql +import app.modules.server.server as server_mod +import app.modules.config.config as config_mod +import app.modules.config.common as config_common +import app.modules.roxywi.common as roxywi_common -def stat_page_action(server_ip: str) -> None: - haproxy_user = sql.get_setting('stats_user') - haproxy_pass = sql.get_setting('stats_password') - stats_port = sql.get_setting('stats_port') - stats_page = sql.get_setting('stats_page') +def stat_page_action(server_ip: str) -> bytes: + haproxy_user = sql.get_setting('haproxy_stats_user') + haproxy_pass = sql.get_setting('haproxy_stats_password') + stats_port = sql.get_setting('haproxy_stats_port') + stats_page = sql.get_setting('haproxy_stats_page') postdata = { 'action': request.form.get('action'), @@ -33,7 +29,7 @@ def stat_page_action(server_ip: str) -> None: 'Accept-Encoding': 'gzip, deflate' } - data = requests.post(f'http://{server_ip}:{stats_port}/{stats_page}', headers=headers, data=postdata, auth=(haproxy_user, haproxy_pass)) + data = requests.post(f'http://{server_ip}:{stats_port}/{stats_page}', headers=headers, data=postdata, auth=(haproxy_user, haproxy_pass), timeout=5) return data.content @@ -44,13 +40,12 @@ def show_map(serv: str) -> str: matplotlib.use('Agg') import matplotlib.pyplot as plt - stats_port = sql.get_setting('stats_port') - hap_configs_dir = get_config.get_config_var('configs', 'haproxy_save_configs_dir') - date = get_date.return_date('config') - cfg = f'{hap_configs_dir}{serv}-{date}.cfg' + service = 'haproxy' + stats_port = sql.get_setting(f'{service}_stats_port') + cfg = config_common.generate_config_path(service, serv) output = f'

Map from {serv}

' + error = config_mod.get_config(serv, cfg, service=service) - error = config_mod.get_config(serv, cfg) if error: return f'error: Cannot read import config file {error}' @@ -133,7 +128,7 @@ def show_map(serv: str) -> str: i -= 750 G.add_node(k2, pos=(k, i), label_pos=(k, i + 250)) - for k3, v3 in v2.items(): + for _k3, v3 in v2.items(): for k4, v4 in v3.items(): """ Add backend servers of listens or backend from frontends """ i -= 300 @@ -157,7 +152,7 @@ def show_map(serv: str) -> str: else: G.add_edge(k2, k4, port='') - for k4, v4 in v3.items(): + for k4, _v4 in v3.items(): """ Add servers from backends """ i -= 300 j -= 1 @@ -205,7 +200,7 @@ def show_map(serv: str) -> str: i -= 750 G.add_node(k2, pos=(k, i), label_pos=(k, i + 250)) - for k3, v3 in v2.items(): + for _k3, v3 in v2.items(): for k4, v4 in v3.items(): if k4 not in backends_servers: @@ -266,7 +261,6 @@ def runtime_command(serv: str, enable: str, backend: str, save: str) -> str: else: if enable != "show": roxywi_common.logging(serv, f'Has been {enable}ed {backend}', login=1, keep_history=1, service='haproxy') - return f'

You {enable} {backend} on HAProxy {serv}.

' \ - f'{output}' + return f'

You {enable} {backend} on HAProxy {serv}.

{output}' else: return output diff --git a/app/modules/service/installation.py b/app/modules/service/installation.py index 9f4900fb..c1307910 100644 --- a/app/modules/service/installation.py +++ b/app/modules/service/installation.py @@ -4,21 +4,21 @@ import json from flask import render_template import ansible_runner -import modules.db.sql as sql -import modules.service.common as service_common -import modules.common.common as common -import modules.server.server as server_mod -import modules.roxywi.common as roxywi_common -from modules.server.ssh import return_ssh_keys_path +import app.modules.db.sql as sql +import app.modules.service.common as service_common +import app.modules.common.common as common +import app.modules.server.server as server_mod +import app.modules.roxywi.common as roxywi_common +from app.modules.server.ssh import return_ssh_keys_path -def show_installation_output(error: str, output: str, service: str, rc=0): +def show_installation_output(error: str, output: list, service: str, rc=0): if error and "WARNING" not in error: roxywi_common.logging('Roxy-WI server', error, roxywi=1) raise Exception('error: ' + error) else: if rc != 0: - for line in output.read(): + for line in output: if any(s in line for s in ("Traceback", "FAILED", "error", "ERROR", "UNREACHABLE")): try: correct_out = line.split('=>') @@ -229,10 +229,10 @@ def generate_haproxy_inv(json_data: json, install_service: str) -> object: server_ips = [] master_ip = 0 hap_sock_p = str(sql.get_setting('haproxy_sock_port')) - stats_port = str(sql.get_setting('stats_port')) + stats_port = str(sql.get_setting('haproxy_stats_port')) server_state_file = sql.get_setting('server_state_file') - stats_user = sql.get_setting('stats_user') - stats_password = sql.get_setting('stats_password') + stats_user = sql.get_setting('haproxy_stats_user') + stats_password = sql.get_setting('haproxy_stats_password') haproxy_dir = sql.get_setting('haproxy_dir') container_name = sql.get_setting('haproxy_container_name') haproxy_ver = '' @@ -286,8 +286,7 @@ def generate_service_inv(json_data: json, install_service: str) -> object: container_name = sql.get_setting(f'{install_service}_container_name') is_docker = json_data['services'][install_service]['docker'] - if install_service == 'nginx': - os.system('ansible-galaxy collection install community.general') + if install_service == 'nginx' and not os.path.isdir('/var/www/haproxy-wi/app/scripts/ansible/roles/nginxinc.nginx'): os.system('ansible-galaxy install nginxinc.nginx,0.23.2 --roles-path /var/www/haproxy-wi/app/scripts/ansible/roles/') for k, v in json_data['servers'].items(): @@ -316,20 +315,38 @@ def generate_service_inv(json_data: json, install_service: str) -> object: return inv, server_ips -def run_ansible(inv: object, server_ips: str, ansible_role: str) -> object: +def run_ansible(inv: dict, server_ips: str, ansible_role: str) -> object: inventory_path = '/var/www/haproxy-wi/app/scripts/ansible/inventory' inventory = f'{inventory_path}/{ansible_role}.json' proxy = sql.get_setting('proxy') proxy_serv = '' tags = '' + try: + agent_pid = server_mod.start_ssh_agent() + except Exception as e: + raise Exception(f'{e}') + + try: + _install_ansible_collections() + except Exception as e: + raise Exception(f'{e}') + for server_ip in server_ips: ssh_settings = return_ssh_keys_path(server_ip) - inv['server']['hosts'][server_ip]['ansible_ssh_private_key_file'] = ssh_settings['key'] + if ssh_settings['enabled']: + inv['server']['hosts'][server_ip]['ansible_ssh_private_key_file'] = ssh_settings['key'] inv['server']['hosts'][server_ip]['ansible_password'] = ssh_settings['password'] inv['server']['hosts'][server_ip]['ansible_user'] = ssh_settings['user'] inv['server']['hosts'][server_ip]['ansible_port'] = ssh_settings['port'] inv['server']['hosts'][server_ip]['ansible_become'] = True + if ssh_settings['enabled']: + try: + server_mod.add_key_to_agent(ssh_settings, agent_pid) + except Exception as e: + server_mod.stop_ssh_agent(agent_pid) + raise Exception(f'{e}') + if proxy is not None and proxy != '' and proxy != 'None': proxy_serv = proxy @@ -351,8 +368,9 @@ def run_ansible(inv: object, server_ips: str, ansible_role: str) -> object: 'LOCALHOST_WARNING': "no", 'COMMAND_WARNINGS': "no", 'AWX_DISPLAY': False, + 'SSH_AUTH_PID': agent_pid['pid'], + 'SSH_AUTH_SOCK': agent_pid['socket'], } - kwargs = { 'private_data_dir': '/var/www/haproxy-wi/app/scripts/ansible/', 'inventory': inventory, @@ -371,16 +389,22 @@ def run_ansible(inv: object, server_ips: str, ansible_role: str) -> object: with open(inventory, 'a') as invent: invent.write(str(inv)) except Exception as e: - raise Exception(f'error: Cannot save inventory file: {e}') + server_mod.stop_ssh_agent(agent_pid) + roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'error: Cannot save inventory file', roxywi=1) try: result = ansible_runner.run(**kwargs) except Exception as e: - raise Exception(f'error: Cannot install {ansible_role}: {e}') - stats = result.stats + server_mod.stop_ssh_agent(agent_pid) + roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'error: Cannot run Ansible', roxywi=1) + + try: + server_mod.stop_ssh_agent(agent_pid) + except Exception as e: + roxywi_common.logging('Roxy-WI server', f'error: Cannot stop SSH agent {e}', roxywi=1) os.remove(inventory) - return stats + return result.stats def service_actions_after_install(server_ips: str, service: str, json_data) -> None: @@ -397,7 +421,7 @@ def service_actions_after_install(server_ips: str, service: str, json_data) -> N try: update_functions[service](server_ip) except Exception as e: - raise Exception(f'error: Cannot activate {service} on server {server_ip}: {e}') + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'error: Cannot activate {service} on server {server_ip}', roxywi=1) if service != 'keepalived': is_docker = json_data['services'][service]['docker'] @@ -411,7 +435,7 @@ def install_service(service: str, json_data: str) -> object: try: json_data = json.loads(json_data) except Exception as e: - raise Exception(f'error: Cannot parse JSON: {e}') + roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'error: Cannot parse JSON', roxywi=1) generate_functions = { 'haproxy': generate_haproxy_inv, @@ -425,4 +449,17 @@ def install_service(service: str, json_data: str) -> object: service_actions_after_install(server_ips, service, json_data) return run_ansible(inv, server_ips, service), 201 except Exception as e: - raise Exception(f'error: Cannot install {service}: {e}') + roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'error: Cannot install {service}', roxywi=1) + + +def _install_ansible_collections(): + collections = ('community.general', 'ansible.posix', 'community.docker') + for collection in collections: + if not os.path.isdir(f'/usr/share/httpd/.ansible/collections/ansible_collections/{collection.replace(".", "/")}'): + try: + exit_code = os.system(f'ansible-galaxy collection install {collection}') + except Exception as e: + roxywi_common.handle_exceptions(e, 'Roxy-WI server', 'Cannot install as collection', roxywi=1) + else: + if exit_code != 0: + raise Exception(f'error: Ansible collection installation was not successful: {exit_code}') diff --git a/app/modules/tools/checker.py b/app/modules/tools/checker.py index 6d1e083f..d9eed2a4 100644 --- a/app/modules/tools/checker.py +++ b/app/modules/tools/checker.py @@ -1,8 +1,8 @@ from flask import render_template, redirect, url_for -import modules.db.sql as sql -import modules.tools.common as tools_common -import modules.roxywi.common as roxywi_common +import app.modules.db.sql as sql +import app.modules.tools.common as tools_common +import app.modules.roxywi.common as roxywi_common def load_checker() -> str: diff --git a/app/routes/add/routes.py b/app/routes/add/routes.py index 959bb951..aee064f9 100644 --- a/app/routes/add/routes.py +++ b/app/routes/add/routes.py @@ -21,7 +21,7 @@ get_date = roxy_wi_tools.GetDate(time_zone) @bp.before_request @login_required def before_request(): - """ Protect all of the admin endpoints. """ + """ Protect all the admin endpoints. """ pass @@ -37,7 +37,6 @@ def add(service): roxywi_auth.page_for_admin(level=3) kwargs = { 'h2': 1, - 'user_params': g.user_params, 'add': request.form.get('add'), 'conf_add': request.form.get('conf'), 'lang': g.user_params['lang'] diff --git a/app/routes/admin/routes.py b/app/routes/admin/routes.py index 080a464a..fbd6240b 100644 --- a/app/routes/admin/routes.py +++ b/app/routes/admin/routes.py @@ -20,7 +20,7 @@ import app.modules.tools.common as tools_common @bp.before_request @login_required def before_request(): - """ Protect all of the admin endpoints. """ + """ Protect all the admin endpoints. """ pass @@ -34,7 +34,6 @@ def admin(): grafana = tools_common.is_tool_active('grafana-server') kwargs = { - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'users': sql.select_users(), 'groups': sql.select_groups(), diff --git a/app/routes/checker/routes.py b/app/routes/checker/routes.py index e05eaee8..c0c868af 100644 --- a/app/routes/checker/routes.py +++ b/app/routes/checker/routes.py @@ -21,9 +21,8 @@ def before_request(): @get_user_params() def checker_settings(): roxywi_common.check_user_group_for_flask() - kwargs = {'user_params': g.user_params} - return render_template('checker.html', **kwargs) + return render_template('checker.html') @bp.post('/settings/update') @@ -60,7 +59,6 @@ def checker_history(): roxywi_common.check_user_group_for_flask() kwargs = { - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'smon': sql.alerts_history('Checker', g.user_params['group_id']), 'user_subscription': roxywi_common.return_user_subscription(), diff --git a/app/routes/config/routes.py b/app/routes/config/routes.py index faa7c3cc..759efe3d 100644 --- a/app/routes/config/routes.py +++ b/app/routes/config/routes.py @@ -7,23 +7,19 @@ from app.routes.config import bp import app.modules.db.sql as sql from middleware import check_services, get_user_params import app.modules.common.common as common -import app.modules.roxy_wi_tools as roxy_wi_tools import app.modules.roxywi.auth as roxywi_auth import app.modules.roxywi.common as roxywi_common import app.modules.config.config as config_mod +import app.modules.config.common as config_common import app.modules.config.section as section_mod import app.modules.service.haproxy as service_haproxy import app.modules.server.server as server_mod -get_config = roxy_wi_tools.GetConfigVar() -time_zone = sql.get_setting('time_zone') -get_date = roxy_wi_tools.GetDate(time_zone) - @bp.before_request @login_required def before_request(): - """ Protect all of the admin endpoints. """ + """ Protect all the admin endpoints. """ pass @@ -115,7 +111,6 @@ def config(service, serv, edit, config_file_name, new): config_read = ' ' kwargs = { - 'user_params': g.user_params, 'serv': serv, 'aftersave': '', 'config': config_read, @@ -180,16 +175,12 @@ def versions(service, server_ip): aftersave = '' file = set() stderr = '' - - if service in ('haproxy', 'keepalived'): - conf_format = 'cfg' - else: - conf_format = 'conf' + file_fortmat = config_common.get_file_format(service) if request.form.get('del'): aftersave = 1 for get in request.form.getlist('do_delete'): - if conf_format in get and server_ip in get: + if file_fortmat in get and server_ip in get: try: if sql.delete_config_version(service, get): try: @@ -198,8 +189,8 @@ def versions(service, server_ip): if 'No such file or directory' in str(e): pass else: - configs_dir = get_config.get_config_var('configs', f'{service}_save_configs_dir') - os.remove(os.path.join(configs_dir, get)) + config_dir = config_common.get_config_dir('haproxy') + os.remove(os.path.join(config_dir, get)) try: file.add(get + "\n") roxywi_common.logging( @@ -212,7 +203,6 @@ def versions(service, server_ip): stderr = "Error: %s - %s." % (e.filename, e.strerror) kwargs = { - 'user_params': g.user_params, 'serv': server_ip, 'aftersave': aftersave, 'file': file, @@ -240,8 +230,8 @@ def list_of_version(service): def show_version(service, server_ip, configver, save): roxywi_auth.page_for_admin(level=3) service_desc = sql.select_service(service) - configs_dir = get_config.get_config_var('configs', f'{service_desc.service}_save_configs_dir') - configver = configs_dir + configver + config_dir = config_common.get_config_dir('haproxy') + configver = config_dir + configver aftersave = 0 stderr = '' @@ -266,7 +256,6 @@ def show_version(service, server_ip, configver, save): stderr = config_mod.master_slave_upload_and_restart(server_ip, configver, save_action, service) kwargs = { - 'user_params': g.user_params, 'serv': server_ip, 'aftersave': aftersave, 'configver': configver, @@ -281,11 +270,9 @@ def show_version(service, server_ip, configver, save): @bp.route('/section/haproxy/') @get_user_params() def haproxy_section(server_ip): - hap_configs_dir = get_config.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{hap_configs_dir}{server_ip}-{get_date.return_date('config')}.cfg" + cfg = config_common.generate_config_path('haproxy', server_ip) error = config_mod.get_config(server_ip, cfg) kwargs = { - 'user_params': g.user_params, 'is_restart': 0, 'config': '', 'serv': server_ip, @@ -300,8 +287,7 @@ def haproxy_section(server_ip): @bp.route('/section/haproxy//
') @get_user_params() def haproxy_section_show(server_ip, section): - hap_configs_dir = get_config.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{hap_configs_dir}{server_ip}-{get_date.return_date('config')}.cfg" + cfg = config_common.generate_config_path('haproxy', server_ip) error = config_mod.get_config(server_ip, cfg) start_line, end_line, config_read = section_mod.get_section_from_config(cfg, section) server_id = sql.select_server_id_by_ip(server_ip) @@ -315,7 +301,6 @@ def haproxy_section_show(server_ip, section): pass kwargs = { - 'user_params': g.user_params, 'is_restart': sql.select_service_setting(server_id, 'haproxy', 'restart'), 'serv': server_ip, 'sections': sections, @@ -333,8 +318,8 @@ def haproxy_section_show(server_ip, section): @bp.route('/section/haproxy//save', methods=['POST']) def haproxy_section_save(server_ip): - hap_configs_dir = get_config.get_config_var('configs', 'haproxy_save_configs_dir') - cfg = f"{hap_configs_dir}{server_ip}-{get_date.return_date('config')}.cfg" + hap_configs_dir = config_common.get_config_dir('haproxy') + cfg = config_common.generate_config_path('haproxy', server_ip) config_file = request.form.get('config') oldcfg = request.form.get('oldconfig') save = request.form.get('save') @@ -357,7 +342,10 @@ def haproxy_section_save(server_ip): config_mod.diff_config(oldcfg, cfg) - os.system(f"/bin/rm -f {hap_configs_dir}*.old") + try: + os.remove(f"{hap_configs_dir}*.old") + except IOError: + pass return stderr @@ -367,7 +355,6 @@ def haproxy_section_save(server_ip): @get_user_params() def show_compare_config(service, serv): kwargs = { - 'user_params': g.user_params, 'aftersave': '', 'serv': serv, 'cfg': '', diff --git a/app/routes/ha/routes.py b/app/routes/ha/routes.py index 64cea388..b45f055c 100644 --- a/app/routes/ha/routes.py +++ b/app/routes/ha/routes.py @@ -27,7 +27,6 @@ def cluster_function(service): group_id = g.user_params['group_id'] if request.method == 'GET': kwargs = { - 'user_params': g.user_params, 'clusters': sql.select_clusters(group_id), 'is_needed_tool': common.is_tool('ansible'), 'user_subscription': roxywi_common.return_user_subscription() @@ -62,7 +61,6 @@ def cluster_function(service): def get_ha_cluster(service, cluster_id): router_id = sql.get_router_id(cluster_id, default_router=1) kwargs = { - 'user_params': g.user_params, 'servers': roxywi_common.get_dick_permit(virt=1), 'clusters': sql.select_cluster(cluster_id), 'slaves': sql.select_cluster_slaves(cluster_id, router_id), @@ -159,7 +157,6 @@ def show_ha_cluster(service, cluster_id): user_subscription = roxywi_common.return_user_subscription() kwargs = { - 'user_params': g.user_params, 'servers': servers_with_status1, 'waf_server': waf_server, 'service': service, @@ -168,6 +165,8 @@ def show_ha_cluster(service, cluster_id): 'keep_alive': ''.join(keep_alive), 'restart_settings': restart_settings, 'user_subscription': user_subscription, + 'clusters': sql.select_ha_cluster_name_and_slaves(), + 'master_slave': sql.is_master(0, master_slave=1), 'lang': g.user_params['lang'] } diff --git a/app/routes/install/routes.py b/app/routes/install/routes.py index a61efbe6..69882eb9 100644 --- a/app/routes/install/routes.py +++ b/app/routes/install/routes.py @@ -8,7 +8,7 @@ import modules.common.common as common import modules.roxywi.auth as roxywi_auth import modules.server.server as server_mod import modules.service.common as service_common -import modules.service.installation as service_mod +import app.modules.service.installation as service_mod import modules.service.exporter_installation as exp_installation @@ -24,7 +24,6 @@ def before_request(): def install_monitoring(): roxywi_auth.page_for_admin(level=2) kwargs = { - 'user_params': g.user_params, 'is_needed_tool': common.is_tool('ansible'), 'geoip_country_codes': sql.select_geoip_country_codes(), 'lang': g.user_params['lang'] @@ -56,15 +55,14 @@ def install_exporter(exporter): ver = common.checkAjaxInput(request.form.get('exporter_v')) ext_prom = common.checkAjaxInput(request.form.get('ext_prom')) - if exporter == 'haproxy': - return exp_installation.haproxy_exp_installation(server_ip, ver, ext_prom) - elif exporter in ('nginx', 'apache'): - return exp_installation.nginx_apache_exp_installation(server_ip, exporter, ver, ext_prom) - elif exporter in ('keepalived', 'node'): - return exp_installation.node_keepalived_exp_installation(exporter, server_ip, ver, ext_prom) - else: + if exporter not in ('haproxy', 'nginx', 'apache', 'keepalived', 'node'): return 'error: Wrong exporter' + try: + return exp_installation.install_exporter(server_ip, ver, ext_prom, exporter) + except Exception as e: + return f'{e}' + @bp.route('/exporter//version/') def get_exporter_version(exporter, server_ip): diff --git a/app/routes/logs/routes.py b/app/routes/logs/routes.py index 54c8691c..9317d6c0 100644 --- a/app/routes/logs/routes.py +++ b/app/routes/logs/routes.py @@ -17,7 +17,7 @@ get_config = roxy_wi_tools.GetConfigVar() @bp.before_request @login_required def before_request(): - """ Protect all of the admin endpoints. """ + """ Protect all the admin endpoints. """ pass @@ -39,7 +39,6 @@ def logs_internal(): selects.append(['roxy-wi.access.log', 'access.log']) kwargs = { - 'user_params': g.user_params, 'autorefresh': 1, 'selects': selects, 'serv': 'viewlogs', @@ -79,7 +78,6 @@ def logs(service, waf): return redirect(url_for('index')) kwargs = { - 'user_params': g.user_params, 'autorefresh': 1, 'servers': servers, 'serv': serv, diff --git a/app/routes/main/routes.py b/app/routes/main/routes.py index be0fc6e0..c34402e9 100644 --- a/app/routes/main/routes.py +++ b/app/routes/main/routes.py @@ -9,16 +9,16 @@ sys.path.append(os.path.join(sys.path[0], '/var/www/haproxy-wi/app')) from app import app, cache from app.routes.main import bp -import modules.db.sql as sql +import app.modules.db.sql as sql from modules.db.db_model import conn from middleware import check_services, get_user_params -import modules.common.common as common -import modules.roxywi.roxy as roxy -import modules.roxywi.auth as roxywi_auth -import modules.roxywi.nettools as nettools_mod -import modules.roxywi.common as roxywi_common -import modules.service.common as service_common -import modules.service.haproxy as service_haproxy +import app.modules.common.common as common +import app.modules.roxywi.roxy as roxy +import app.modules.roxywi.auth as roxywi_auth +import app.modules.roxywi.nettools as nettools_mod +import app.modules.roxywi.common as roxywi_common +import app.modules.service.common as service_common +import app.modules.service.haproxy as service_haproxy @app.errorhandler(403) @@ -83,7 +83,6 @@ def _db_close(exc): @get_user_params() def stats(service, serv): kwargs = { - 'user_params': g.user_params, 'autorefresh': 1, 'serv': serv, 'service': service, @@ -109,7 +108,7 @@ def show_stats(service, server_ip): @login_required @get_user_params(1) def nettools(): - return render_template('nettools.html', user_params=g.user_params, lang=g.user_params['lang']) + return render_template('nettools.html', lang=g.user_params['lang']) @bp.post('/nettols/') @@ -159,7 +158,6 @@ def service_history(service, server_ip): abort(404, f'History not found') kwargs = { - 'user_params': g.user_params, 'user_subscription': roxywi_common.return_user_subscription(), 'users': sql.select_users(), 'serv': server_ip, @@ -178,7 +176,6 @@ def servers(): user_group = roxywi_common.get_user_group(id=1) kwargs = { - 'user_params': g.user_params, 'h2': 1, 'users': sql.select_users(group=user_group), 'groups': sql.select_groups(), diff --git a/app/routes/metric/routes.py b/app/routes/metric/routes.py index 2f70c55c..b648e12b 100644 --- a/app/routes/metric/routes.py +++ b/app/routes/metric/routes.py @@ -52,7 +52,6 @@ def metrics(service): return f'error: on Metrics page: {e}', 500 kwargs = { - 'user_params': g.user_params, 'autorefresh': 1, 'servers': servers, 'service': service, diff --git a/app/routes/overview/routes.py b/app/routes/overview/routes.py index 727b7367..346b9486 100644 --- a/app/routes/overview/routes.py +++ b/app/routes/overview/routes.py @@ -11,7 +11,7 @@ import app.modules.roxywi.overview as roxy_overview @bp.before_request @login_required def before_request(): - """ Protect all of the admin endpoints. """ + """ Protect all the admin endpoints. """ pass @@ -20,7 +20,6 @@ def before_request(): @get_user_params() def index(): kwargs = { - 'user_params': g.user_params, 'autorefresh': 1, 'roles': sql.select_roles(), 'groups': sql.select_groups(), diff --git a/app/routes/portscanner/routes.py b/app/routes/portscanner/routes.py index da0758bc..8e56ef45 100644 --- a/app/routes/portscanner/routes.py +++ b/app/routes/portscanner/routes.py @@ -33,7 +33,6 @@ def portscanner(): count_ports.append(i) kwargs = { - 'user_params': g.user_params, 'servers': g.user_params['servers'], 'port_scanner_settings': port_scanner_settings, 'count_ports': count_ports, @@ -50,7 +49,6 @@ def portscanner(): def portscanner_history(server_ip): kwargs = { 'h2': 1, - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'history': sql.select_port_scanner_history(server_ip), 'user_subscription': roxywi_common.return_user_subscription() diff --git a/app/routes/runtime/routes.py b/app/routes/runtime/routes.py index 57817787..1d457894 100644 --- a/app/routes/runtime/routes.py +++ b/app/routes/runtime/routes.py @@ -18,7 +18,7 @@ def before_request(): @bp.route('') @get_user_params() def runtimeapi(): - return render_template('runtimeapi.html', user_params=g.user_params, lang=g.user_params['lang']) + return render_template('runtimeapi.html', lang=g.user_params['lang']) @bp.route('/backends/') diff --git a/app/routes/server/routes.py b/app/routes/server/routes.py index b768ef1f..84d6afc0 100644 --- a/app/routes/server/routes.py +++ b/app/routes/server/routes.py @@ -20,7 +20,7 @@ error_mess = roxywi_common.return_error_message() @bp.before_request @login_required def before_request(): - """ Protect all of the admin endpoints. """ + """ Protect all the admin endpoints. """ pass @@ -198,10 +198,11 @@ def update_ssh(): def upload_ssh_key(): user_group = roxywi_common.get_user_group() name = common.checkAjaxInput(request.form.get('name')) + passphrase = common.checkAjaxInput(request.form.get('pass')) key = request.form.get('ssh_cert') try: - return ssh_mod.upload_ssh_key(name, user_group, key) + return ssh_mod.upload_ssh_key(name, user_group, key, passphrase) except Exception as e: return str(e) diff --git a/app/routes/service/routes.py b/app/routes/service/routes.py index 42321205..c0898ff0 100644 --- a/app/routes/service/routes.py +++ b/app/routes/service/routes.py @@ -18,7 +18,7 @@ import app.modules.roxywi.overview as roxy_overview @bp.before_request @login_required def before_request(): - """ Protect all of the admin endpoints. """ + """ Protect all the admin endpoints. """ pass @@ -158,7 +158,6 @@ def services(service, serv): servers_with_status1.append(servers_with_status) kwargs = { - 'user_params': g.user_params, 'clusters': sql.select_ha_cluster_name_and_slaves(), 'master_slave': sql.is_master(0, master_slave=1), 'user_subscription': roxywi_common.return_user_subscription(), @@ -190,6 +189,7 @@ def check_service(service): @bp.route('/action///', methods=['GET']) +@check_services def action_service(service, server_ip, action): server_ip = common.is_ip_or_dns(server_ip) @@ -197,6 +197,7 @@ def action_service(service, server_ip, action): @bp.route('///last-edit') +@check_services def last_edit(service, server_ip): return service_common.get_overview_last_edit(server_ip, service) diff --git a/app/routes/smon/routes.py b/app/routes/smon/routes.py index b46027a2..3a938509 100644 --- a/app/routes/smon/routes.py +++ b/app/routes/smon/routes.py @@ -1,5 +1,4 @@ import json -from pytz import timezone from flask import render_template, request, jsonify, g from flask_login import login_required from datetime import datetime @@ -18,11 +17,16 @@ import app.modules.tools.common as tools_common @login_required @get_user_params() def smon(): + """ + Dashboard route for the smon tool. + + :return: The rendered dashboard template with the necessary parameters. + :rtype: flask.Response + """ roxywi_common.check_user_group_for_flask() kwargs = { 'autorefresh': 1, - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'smon': sql.smon_list(g.user_params['group_id']), 'group': g.user_params['group_id'], @@ -33,24 +37,47 @@ def smon(): return render_template('smon/dashboard.html', **kwargs) -@bp.route('/dashboard//') +@bp.route('/dashboard//') @login_required @get_user_params() -def smon_dashboard(dashboard_id, check_id): +def smon_dashboard(smon_id, check_id): + """ + :param smon_id: The ID of the SMON (Server Monitoring) service. + :param check_id: The ID of the check associated with the SMON service. + :return: The rendered SMON dashboard template. + + This method is used to render the SMON dashboard template for a specific SMON service and check. It retrieves relevant data from the database and passes it to the template for rendering + *. + + The `smon_id` parameter specifies the ID of the SMON service. + The `check_id` parameter specifies the ID of the check associated with the SMON service. + + The method performs the following steps: + 1. Checks user group for Flask access. + 2. Retrieves the SMON object from the database using the `smon_id` and `check_id` parameters. + 3. Gets the current date and time using the `get_present_time()` function from the common module. + 4. Sets the initial value of `cert_day_diff` as 'N/A'. + 5. Tries to calculate the average response time for the SMON service using the `get_avg_resp_time` function from the SQL module. If an exception occurs, the average response time is + * set to 0. + 6. Tries to retrieve the last response time for the SMON service and check using the `get_last_smon_res_time_by_check` function from the SQL module. If an exception occurs, the last + * response time is set to 0. + 7. Iterates over the retrieved SMON object and checks if the SSL expiration date is not None. If it is not None, calculates the difference in days between the expiration date and the + * present date using the `datetime.strptime()` function and assigns it to `cert_day_diff`. + 8. Constructs a dictionary (`kwargs`) containing various parameters required for rendering the template, including `autorefresh`, `lang`, `smon`, `group`, `user_subscription`, `check + *_interval`, `uptime`, `avg_res_time`, `smon_name`, `cert_day_diff`, `check_id`, `dashboard_id`, and `last_resp_time`. + 9. Renders the SMON history template ('include/smon/smon_history.html') using the `render_template` function from Flask, passing the `kwargs` dictionary as keyword arguments. + """ roxywi_common.check_user_group_for_flask() - check_id = int(check_id) - smon = sql.select_one_smon(dashboard_id, check_id) - present = datetime.now(timezone('UTC')) - present = present.strftime('%b %d %H:%M:%S %Y %Z') - present = datetime.strptime(present, '%b %d %H:%M:%S %Y %Z') + smon = sql.select_one_smon(smon_id, check_id) + present = common.get_present_time() cert_day_diff = 'N/A' try: - avg_res_time = round(sql.get_avg_resp_time(dashboard_id, check_id), 2) + avg_res_time = round(sql.get_avg_resp_time(smon_id, check_id), 2) except Exception: avg_res_time = 0 try: - last_resp_time = round(sql.get_last_smon_res_time_by_check(dashboard_id, check_id), 2) + last_resp_time = round(sql.get_last_smon_res_time_by_check(smon_id, check_id), 2) except Exception: last_resp_time = 0 @@ -61,18 +88,17 @@ def smon_dashboard(dashboard_id, check_id): kwargs = { 'autorefresh': 1, - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'smon': smon, 'group': g.user_params['group_id'], 'user_subscription': roxywi_common.return_user_subscription(), 'check_interval': sql.get_setting('smon_check_interval'), - 'uptime': smon_mod.check_uptime(dashboard_id), + 'uptime': smon_mod.check_uptime(smon_id), 'avg_res_time': avg_res_time, - 'smon_name': sql.get_smon_service_name_by_id(dashboard_id), + 'smon_name': sql.get_smon_service_name_by_id(smon_id), 'cert_day_diff': cert_day_diff, 'check_id': check_id, - 'dashboard_id': dashboard_id, + 'dashboard_id': smon_id, 'last_resp_time': last_resp_time } @@ -83,9 +109,42 @@ def smon_dashboard(dashboard_id, check_id): @login_required @get_user_params() def status_page(): + """ + This function handles the '/status-page' route with methods GET, POST, DELETE, and PUT. + It requires the user to be logged in and retrieves user parameters. + + :return: + - GET method: Renders the 'smon/manage_status_page.html' template with the following keyword arguments: + - 'lang': The language from user parameters + - 'smon': The list of smon from sql.smon_list() using the 'group_id' from user parameters + - 'pages': The status pages from sql.select_status_pages() using the 'group_id' from user parameters + - 'smon_status': The status of the 'roxy-wi-smon' tool from tools_common.is_tool_active() + - 'user_subscription': The user subscription from roxywi_common.return_user_subscription() + - POST method: Creates a status page with the following parameters: + - 'name': The name of the status page + - 'slug': The slug of the status page + - 'desc': The description of the status page + - 'checks': The checks for the status page + - PUT method: Edits a status page with the following parameters: + - 'page_id': The ID of the status page + - 'name': The updated name of the status page + - 'slug': The updated slug of the status page + - 'desc': The updated description of the status page + - 'checks': The updated checks for the status page + - DELETE method: Deletes a status page with the following parameter: + - 'page_id': The ID of the status page + + The function returns different values based on the method used: + - POST method: Returns the result of smon_mod.create_status_page() for creating the status page or an exception message in case of an error. + - PUT method: Returns the result of smon_mod.edit_status_page() for editing the status page or an exception message in case of an error. + - DELETE method: Returns 'ok' if the status page is successfully deleted or an exception message in case of an error. + + .. note:: + - The checks for the status page should not be empty. If no checks are selected, it returns an error message. + - Any exceptions raised during the process will be returned as exception messages. + """ if request.method == 'GET': kwargs = { - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'smon': sql.smon_list(g.user_params['group_id']), 'pages': sql.select_status_pages(g.user_params['group_id']), @@ -134,6 +193,11 @@ def status_page(): @bp.route('/status/checks/') @login_required def get_checks(page_id): + """ + :param page_id: The ID of the page for which to fetch the checks. + :return: A JSON response with an array of check IDs. + + """ returned_check = [] try: checks = sql.select_status_page_checks(page_id) @@ -165,7 +229,6 @@ def smon_history(): roxywi_common.check_user_group_for_flask() kwargs = { - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'smon': sql.alerts_history('SMON', g.user_params['group_id']), 'smon_status': tools_common.is_tool_active('roxy-wi-smon'), @@ -186,7 +249,6 @@ def smon_host_history(server_ip): smon = sql.alerts_history('SMON', g.user_params['group_id'], host=needed_host) user_subscription = roxywi_common.return_user_subscription() kwargs = { - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'smon': smon, 'smon_status': smon_status, @@ -220,7 +282,6 @@ def smon_admin(): roxywi_auth.page_for_admin(level=3) user_group = g.user_params['group_id'] kwargs = { - 'user_params': g.user_params, 'lang': g.user_params['lang'], 'smon': sql.select_smon(user_group), 'smon_status': tools_common.is_tool_active('roxy-wi-smon'), @@ -228,8 +289,8 @@ def smon_admin(): 'telegrams': sql.get_user_telegram_by_group(user_group), 'slacks': sql.get_user_slack_by_group(user_group), 'pds': sql.get_user_pd_by_group(user_group), + 'smon_tcp': sql.select_smon_tcp(), 'smon_ping': sql.select_smon_ping(), - 'smon_tcp:': sql.select_smon_tcp(), 'smon_http': sql.select_smon_http(), 'smon_dns': sql.select_smon_dns() } @@ -274,6 +335,7 @@ def smon_add(): 'slacks': sql.get_user_slack_by_group(user_group), 'telegrams': sql.get_user_telegram_by_group(user_group), 'smon_service': sql.select_smon_check_by_id(last_id, check_type), + 'check_type': check_type, 'lang': lang } diff --git a/app/routes/waf/routes.py b/app/routes/waf/routes.py index 47ebbfa6..77c395c6 100644 --- a/app/routes/waf/routes.py +++ b/app/routes/waf/routes.py @@ -21,7 +21,7 @@ get_date = roxy_wi_tools.GetDate(time_zone) @bp.before_request @login_required def before_request(): - """ Protect all of the admin endpoints. """ + """ Protect all the admin endpoints. """ pass @@ -40,7 +40,6 @@ def waf(service): servers = g.user_params['servers'] kwargs = { - 'user_params': g.user_params, 'title': 'Web application firewall', 'autorefresh': 1, 'serv': '', @@ -68,7 +67,6 @@ def waf_rules(service, server_ip): abort(403, f'You do not have needed permissions to access to {service.title()} service') kwargs = { - 'user_params': g.user_params, 'title': 'Manage rules - Web application firewall', 'serv': server_ip, 'servers': sql.select_waf_servers_metrics(g.user_params['user_uuid']), @@ -115,7 +113,6 @@ def waf_rule_edit(service, server_ip, rule_id): print('Cannot read imported config file') kwargs = { - 'user_params': g.user_params, 'title': 'Edit a WAF rule', 'serv': server_ip, 'servers': sql.select_waf_servers_metrics(g.user_params['user_uuid']), diff --git a/app/scripts/ansible/roles/apache_exporter.yml b/app/scripts/ansible/roles/apache_exporter.yml index 176c0d9b..5cb5413b 100644 --- a/app/scripts/ansible/roles/apache_exporter.yml +++ b/app/scripts/ansible/roles/apache_exporter.yml @@ -1,11 +1,7 @@ -- hosts: "{{ variable_host }}" +- hosts: all become: yes become_method: sudo tasks: - - name: Set SSH port - set_fact: - ansible_port: "{{SSH_PORT}}" - - name: Open stat port for iptables iptables: chain: INPUT @@ -21,4 +17,4 @@ http_proxy: "{{PROXY}}" https_proxy: "{{PROXY}}" vars: - apache_exporter_scrape_uri: 'http://{{STATS_USER}}:{{STATS_PASS}}@{{variable_host}}:{{STAT_PORT}}/{{STAT_PAGE}}' + apache_exporter_scrape_uri: 'http://{{STATS_USER}}:{{STATS_PASS}}@{{ansible_host}}:{{STAT_PORT}}/{{STAT_PAGE}}' diff --git a/app/scripts/ansible/roles/haproxy/tasks/configure.yml b/app/scripts/ansible/roles/haproxy/tasks/configure.yml index 07ce9aa1..765a458b 100644 --- a/app/scripts/ansible/roles/haproxy/tasks/configure.yml +++ b/app/scripts/ansible/roles/haproxy/tasks/configure.yml @@ -48,7 +48,6 @@ - ansible_facts.services["firewalld.service"]['state'] == "running" with_items: [ "{{ STAT_PORT }}", "{{ SOCK_PORT }}", "10000" ] - - name: Open stat port for iptables iptables: chain: INPUT @@ -58,27 +57,11 @@ ignore_errors: yes with_items: [ "{{ STAT_PORT }}", "{{ SOCK_PORT }}", "10000" ] -- name: Create the haproxy group - group: - name: haproxy - state: present - system: true - -- name: Create the haproxy user - user: - name: haproxy - groups: haproxy - append: true - shell: /usr/sbin/nologin - system: true - create_home: false - home: / - - name: Creates HAProxy directory file: path: /etc/haproxy - owner: haproxy - group: haproxy + owner: "{{ansible_user}}" + group: "{{ansible_user}}" state: directory ignore_errors: yes diff --git a/app/scripts/ansible/roles/haproxy_exporter.yml b/app/scripts/ansible/roles/haproxy_exporter.yml index 0002d892..78fef1d8 100644 --- a/app/scripts/ansible/roles/haproxy_exporter.yml +++ b/app/scripts/ansible/roles/haproxy_exporter.yml @@ -1,10 +1,7 @@ -- hosts: "{{ variable_host }}" +- hosts: all become: yes become_method: sudo tasks: - - name: Set SSH port - set_fact: - ansible_port: "{{SSH_PORT}}" - name: Open stat port for iptables iptables: @@ -14,8 +11,7 @@ protocol: tcp ignore_errors: yes - roles: - role: haproxy_exporter vars: - haproxy_exporter_options: ['--haproxy.scrape-uri=http://{{STATS_USER}}:{{STATS_PASS}}@{{variable_host}}:{{STAT_PORT}}/{{STAT_PAGE}};csv'] + haproxy_exporter_options: ['--haproxy.scrape-uri=http://{{STATS_USER}}:{{STATS_PASS}}@{{ansible_host}}:{{STAT_PORT}}/{{STAT_PAGE}};csv'] diff --git a/app/scripts/ansible/roles/keepalived_exporter.yml b/app/scripts/ansible/roles/keepalived_exporter.yml index 02c44802..8a91d097 100644 --- a/app/scripts/ansible/roles/keepalived_exporter.yml +++ b/app/scripts/ansible/roles/keepalived_exporter.yml @@ -1,11 +1,7 @@ -- hosts: "{{ variable_host }}" +- hosts: all become: yes become_method: sudo tasks: - - name: Set SSH port - set_fact: - ansible_port: "{{SSH_PORT}}" - - name: Open stat port for iptables iptables: chain: INPUT diff --git a/app/scripts/ansible/roles/nginx_exporter.yml b/app/scripts/ansible/roles/nginx_exporter.yml index 7d3b594e..8216d24f 100644 --- a/app/scripts/ansible/roles/nginx_exporter.yml +++ b/app/scripts/ansible/roles/nginx_exporter.yml @@ -1,11 +1,7 @@ -- hosts: "{{ variable_host }}" +- hosts: all become: yes become_method: sudo tasks: - - name: Set SSH port - set_fact: - ansible_port: "{{SSH_PORT}}" - - name: Open stat port for iptables iptables: chain: INPUT @@ -21,4 +17,4 @@ http_proxy: "{{PROXY}}" https_proxy: "{{PROXY}}" vars: - nginx_exporter_options: ['-nginx.scrape-uri http://{{STATS_USER}}:{{STATS_PASS}}@{{variable_host}}:{{STAT_PORT}}/{{STAT_PAGE}}'] + nginx_exporter_options: ['-nginx.scrape-uri http://{{STATS_USER}}:{{STATS_PASS}}@{{ansible_host}}:{{STAT_PORT}}/{{STAT_PAGE}}'] diff --git a/app/scripts/ansible/roles/node_exporter.yml b/app/scripts/ansible/roles/node_exporter.yml index e7cf5abc..4a123cdd 100644 --- a/app/scripts/ansible/roles/node_exporter.yml +++ b/app/scripts/ansible/roles/node_exporter.yml @@ -1,11 +1,7 @@ -- hosts: "{{ variable_host }}" +- hosts: all become: yes become_method: sudo tasks: - - name: Set SSH port - set_fact: - ansible_port: "{{SSH_PORT}}" - - name: Open stat port for iptables iptables: chain: INPUT diff --git a/app/scripts/install_apache_exporter.sh b/app/scripts/install_apache_exporter.sh deleted file mode 100644 index 455b47cf..00000000 --- a/app/scripts/install_apache_exporter.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -for ARGUMENT in "$@" -do - KEY=$(echo $ARGUMENT | cut -f1 -d=) - VALUE=$(echo $ARGUMENT | cut -f2 -d=) - - case "$KEY" in - PROXY) PROXY=${VALUE} ;; - HOST) HOST=${VALUE} ;; - USER) USER=${VALUE} ;; - PASS) PASS=${VALUE} ;; - KEY) KEY=${VALUE} ;; - VER) VER=${VALUE} ;; - EXP_PROM) EXP_PROM=${VALUE} ;; - STAT_PORT) STAT_PORT=${VALUE} ;; - STAT_PAGE) STAT_PAGE=${VALUE} ;; - STATS_USER) STATS_USER=${VALUE} ;; - STATS_PASS) STATS_PASS=${VALUE} ;; - SSH_PORT) SSH_PORT=${VALUE} ;; - *) - esac -done - -export ANSIBLE_HOST_KEY_CHECKING=False -export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False -export ACTION_WARNINGS=False -export LOCALHOST_WARNING=False -export COMMAND_WARNINGS=False - -PWD=/var/www/haproxy-wi/app/scripts/ansible/ -echo "$HOST ansible_port=$SSH_PORT" > $PWD/$HOST - -if [[ $KEY == "" ]]; then - ansible-playbook $PWD/roles/apache_exporter.yml -e "ansible_user=$USER ansible_ssh_pass='$PASS' variable_host=$HOST PROXY=$PROXY STAT_PAGE=$STAT_PAGE STAT_PORT=$STAT_PORT STATS_USER=$STATS_USER STATS_PASS=$STATS_PASS SSH_PORT=$SSH_PORT apache_exporter_version=$VER" -i $PWD/$HOST -else - ansible-playbook $PWD/roles/apache_exporter.yml --key-file $KEY -e "ansible_user=$USER variable_host=$HOST PROXY=$PROXY STAT_PAGE=$STAT_PAGE STAT_PORT=$STAT_PORT STATS_USER=$STATS_USER STATS_PASS=$STATS_PASS SSH_PORT=$SSH_PORT apache_exporter_version=$VER" -i $PWD/$HOST -fi - -if [ $? -gt 0 ] -then - echo "error: Can't install Apache exporter

" - rm -f $PWD/$HOST - exit 1 -fi - -if [ "$EXP_PROM" == 0 ] -then - if ! sudo grep -Fxq " - $HOST:9117" /etc/prometheus/prometheus.yml; then - sudo echo " - $HOST:9117" | sudo tee -a /etc/prometheus/prometheus.yml > /dev/null - sudo systemctl reload prometheus 2>> /dev/null - fi -fi - -rm -f $PWD/$HOST diff --git a/app/scripts/install_haproxy_exporter.sh b/app/scripts/install_haproxy_exporter.sh deleted file mode 100644 index 689c78b0..00000000 --- a/app/scripts/install_haproxy_exporter.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -for ARGUMENT in "$@" -do - KEY=$(echo "$ARGUMENT" | cut -f1 -d=) - VALUE=$(echo "$ARGUMENT" | cut -f2 -d=) - - case "$KEY" in - PROXY) PROXY=${VALUE} ;; - HOST) HOST=${VALUE} ;; - USER) USER=${VALUE} ;; - PASS) PASS=${VALUE} ;; - KEY) KEY=${VALUE} ;; - VER) VER=${VALUE} ;; - STAT_PORT) STAT_PORT=${VALUE} ;; - STAT_PAGE) STAT_PAGE=${VALUE} ;; - STATS_USER) STATS_USER=${VALUE} ;; - STATS_PASS) STATS_PASS=${VALUE} ;; - EXP_PROM) EXP_PROM=${VALUE} ;; - SSH_PORT) SSH_PORT=${VALUE} ;; - *) - esac -done - -if [ ! -d "/var/www/haproxy-wi/app/scripts/ansible/roles/bdellegrazie.ansible-role-prometheus_exporter" ]; then - if [[ -n $PROXY ]];then - export https_proxy="$PROXY" - export http_proxy="$PROXY" - fi - ansible-galaxy install bdellegrazie.ansible-role-prometheus_exporter --roles-path /var/www/haproxy-wi/app/scripts/ansible/roles/ -f - bash -c cat << EOF >> /var/www/haproxy-wi/app/scripts/ansible/roles/bdellegrazie.ansible-role-prometheus_exporter/vars/vars-family-redhat-8.yml ---- -prometheus_exporter_ansible_packages: - - libselinux-python3 -EOF -fi - -export ANSIBLE_HOST_KEY_CHECKING=False -export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False -export ACTION_WARNINGS=False -export ANSIBLE_DEPRECATION_WARNINGS=False -PWD=/var/www/haproxy-wi/app/scripts/ansible/ -echo "$HOST ansible_port=$SSH_PORT" > "$PWD"/"$HOST" - -if [[ $KEY == "" ]]; then - ansible-playbook "$PWD"/roles/haproxy_exporter.yml -e "ansible_user=$USER ansible_ssh_pass='$PASS' variable_host=$HOST PROXY=$PROXY STAT_PAGE=$STAT_PAGE STAT_PORT=$STAT_PORT STATS_USER=$STATS_USER STATS_PASS=$STATS_PASS SSH_PORT=$SSH_PORT haproxy_exporter_version=$VER" -i "$PWD"/"$HOST" -else - ansible-playbook "$PWD"/roles/haproxy_exporter.yml --key-file "$KEY" -e "ansible_user=$USER variable_host=$HOST PROXY=$PROXY STAT_PAGE=$STAT_PAGE STAT_PORT=$STAT_PORT STATS_USER=$STATS_USER STATS_PASS=$STATS_PASS SSH_PORT=$SSH_PORT haproxy_exporter_version=$VER" -i "$PWD"/"$HOST" -fi - -if [ $? -gt 0 ] -then - echo "error: Can't install HAProxy exporter

" - exit 1 -fi - -if [ "$EXP_PROM" == 0 ] -then - if ! sudo grep -Fxq " - $HOST:9101" /etc/prometheus/prometheus.yml; then - sudo echo " - $HOST:9101" | sudo tee -a /etc/prometheus/prometheus.yml > /dev/null - sudo systemctl reload prometheus 2>> /dev/null - fi -fi - -rm -f "$PWD"/"$HOST" diff --git a/app/scripts/install_keepalived_exporter.sh b/app/scripts/install_keepalived_exporter.sh deleted file mode 100644 index 56be5da2..00000000 --- a/app/scripts/install_keepalived_exporter.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -for ARGUMENT in "$@" -do - KEY=$(echo $ARGUMENT | cut -f1 -d=) - VALUE=$(echo $ARGUMENT | cut -f2 -d=) - - case "$KEY" in - PROXY) PROXY=${VALUE} ;; - HOST) HOST=${VALUE} ;; - USER) USER=${VALUE} ;; - PASS) PASS=${VALUE} ;; - KEY) KEY=${VALUE} ;; - VER) VER=${VALUE} ;; - EXP_PROM) EXP_PROM=${VALUE} ;; - SSH_PORT) SSH_PORT=${VALUE} ;; - *) - esac -done - -export ANSIBLE_HOST_KEY_CHECKING=False -export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False -export ACTION_WARNINGS=False -export LOCALHOST_WARNING=False -export COMMAND_WARNINGS=False - -PWD=/var/www/haproxy-wi/app/scripts/ansible/ -echo "$HOST ansible_port=$SSH_PORT" > $PWD/$HOST - -if [[ $KEY == "" ]]; then - ansible-playbook $PWD/roles/keepalived_exporter.yml -e "ansible_user=$USER ansible_ssh_pass='$PASS' variable_host=$HOST PROXY=$PROXY SSH_PORT=$SSH_PORT keepalived_exporter_version=$VER" -i $PWD/$HOST -else - ansible-playbook $PWD/roles/keepalived_exporter.yml --key-file $KEY -e "ansible_user=$USER variable_host=$HOST PROXY=$PROXY SSH_PORT=$SSH_PORT keepalived_exporter_version=$VER" -i $PWD/$HOST -fi - -if [ $? -gt 0 ] -then - echo "error: Can't install Keepalived exporter

" - rm -f $PWD/$HOST - exit 1 -fi -if [ "$EXP_PROM" == 0 ] -then - if ! sudo grep -Fxq " - $HOST:9650" /etc/prometheus/prometheus.yml; then - sudo echo " - $HOST:9650" | sudo tee -a /etc/prometheus/prometheus.yml > /dev/null - sudo systemctl reload prometheus 2>> /dev/null - fi -fi - -rm -f $PWD/$HOST diff --git a/app/scripts/install_nginx_exporter.sh b/app/scripts/install_nginx_exporter.sh deleted file mode 100644 index 4b522a8e..00000000 --- a/app/scripts/install_nginx_exporter.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash -for ARGUMENT in "$@" -do - KEY=$(echo $ARGUMENT | cut -f1 -d=) - VALUE=$(echo $ARGUMENT | cut -f2 -d=) - - case "$KEY" in - PROXY) PROXY=${VALUE} ;; - HOST) HOST=${VALUE} ;; - USER) USER=${VALUE} ;; - PASS) PASS=${VALUE} ;; - KEY) KEY=${VALUE} ;; - VER) VER=${VALUE} ;; - EXP_PROM) EXP_PROM=${VALUE} ;; - STAT_PORT) STAT_PORT=${VALUE} ;; - STAT_PAGE) STAT_PAGE=${VALUE} ;; - STATS_USER) STATS_USER=${VALUE} ;; - STATS_PASS) STATS_PASS=${VALUE} ;; - SSH_PORT) SSH_PORT=${VALUE} ;; - *) - esac -done - -if [ ! -d "/var/www/haproxy-wi/app/scripts/ansible/roles/bdellegrazie.ansible-role-prometheus_exporter" ]; then - if [ ! -z $PROXY ];then - export https_proxy="$PROXY" - export http_proxy="$PROXY" - fi - ansible-galaxy install bdellegrazie.ansible-role-prometheus_exporter --roles-path /var/www/haproxy-wi/app/scripts/ansible/roles/ -f - bash -c cat << EOF >> /var/www/haproxy-wi/app/scripts/ansible/roles/bdellegrazie.ansible-role-prometheus_exporter/vars/vars-family-redhat-8.yml ---- -prometheus_exporter_ansible_packages: - - libselinux-python3 -EOF -fi - -export ANSIBLE_HOST_KEY_CHECKING=False -export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False -export ACTION_WARNINGS=False -export LOCALHOST_WARNING=False -export COMMAND_WARNINGS=False - -PWD=/var/www/haproxy-wi/app/scripts/ansible/ -echo "$HOST ansible_port=$SSH_PORT" > $PWD/$HOST - -if [[ $KEY == "" ]]; then - ansible-playbook $PWD/roles/nginx_exporter.yml -e "ansible_user=$USER ansible_ssh_pass='$PASS' variable_host=$HOST PROXY=$PROXY STAT_PAGE=$STAT_PAGE STAT_PORT=$STAT_PORT STATS_USER=$STATS_USER STATS_PASS=$STATS_PASS SSH_PORT=$SSH_PORT nginx_exporter_version=$VER" -i $PWD/$HOST -else - ansible-playbook $PWD/roles/nginx_exporter.yml --key-file $KEY -e "ansible_user=$USER variable_host=$HOST PROXY=$PROXY STAT_PAGE=$STAT_PAGE STAT_PORT=$STAT_PORT STATS_USER=$STATS_USER STATS_PASS=$STATS_PASS SSH_PORT=$SSH_PORT nginx_exporter_version=$VER" -i $PWD/$HOST -fi - -if [ $? -gt 0 ] -then - echo "error: Can't install Nginx exporter

" - rm -f $PWD/$HOST - exit 1 -fi - -if [ "$EXP_PROM" == 0 ] -then - if ! sudo grep -Fxq " - $HOST:9113" /etc/prometheus/prometheus.yml; then - sudo echo " - $HOST:9113" | sudo tee -a /etc/prometheus/prometheus.yml > /dev/null - sudo systemctl reload prometheus 2>> /dev/null - fi -fi - -rm -f $PWD/$HOST diff --git a/app/scripts/install_node_exporter.sh b/app/scripts/install_node_exporter.sh deleted file mode 100644 index 201f7a8f..00000000 --- a/app/scripts/install_node_exporter.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -for ARGUMENT in "$@" -do - KEY=$(echo $ARGUMENT | cut -f1 -d=) - VALUE=$(echo $ARGUMENT | cut -f2 -d=) - - case "$KEY" in - PROXY) PROXY=${VALUE} ;; - HOST) HOST=${VALUE} ;; - USER) USER=${VALUE} ;; - PASS) PASS=${VALUE} ;; - KEY) KEY=${VALUE} ;; - VER) VER=${VALUE} ;; - EXP_PROM) EXP_PROM=${VALUE} ;; - SSH_PORT) SSH_PORT=${VALUE} ;; - *) - esac -done - -export ANSIBLE_HOST_KEY_CHECKING=False -export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False -export ACTION_WARNINGS=False -export LOCALHOST_WARNING=False -export COMMAND_WARNINGS=False - -PWD=/var/www/haproxy-wi/app/scripts/ansible/ -echo "$HOST ansible_port=$SSH_PORT" > $PWD/$HOST - -if [[ $KEY == "" ]]; then - ansible-playbook $PWD/roles/node_exporter.yml -e "ansible_user=$USER ansible_ssh_pass='$PASS' variable_host=$HOST PROXY=$PROXY SSH_PORT=$SSH_PORT node_exporter_version=$VER" -i $PWD/$HOST -else - ansible-playbook $PWD/roles/node_exporter.yml --key-file $KEY -e "ansible_user=$USER variable_host=$HOST PROXY=$PROXY SSH_PORT=$SSH_PORT node_exporter_version=$VER" -i $PWD/$HOST -fi - -if [ $? -gt 0 ] -then - echo "error: Can't install Node exporter

" - rm -f $PWD/$HOST - exit 1 -fi -if [ "$EXP_PROM" == 0 ] -then - if ! sudo grep -Fxq " - $HOST:9100" /etc/prometheus/prometheus.yml; then - sudo echo " - $HOST:9100" | sudo tee -a /etc/prometheus/prometheus.yml > /dev/null - sudo systemctl reload prometheus 2>> /dev/null - fi -fi - -rm -f $PWD/$HOST diff --git a/inc/css/awesome-6.3.9.css b/app/static/css/awesome-6.3.9.css similarity index 100% rename from inc/css/awesome-6.3.9.css rename to app/static/css/awesome-6.3.9.css diff --git a/inc/css/chart.min.css b/app/static/css/chart.min.css similarity index 100% rename from inc/css/chart.min.css rename to app/static/css/chart.min.css diff --git a/inc/css/ha.css b/app/static/css/ha.css similarity index 100% rename from inc/css/ha.css rename to app/static/css/ha.css diff --git a/inc/css/jquery-ui.min.css b/app/static/css/jquery-ui.min.css similarity index 100% rename from inc/css/jquery-ui.min.css rename to app/static/css/jquery-ui.min.css diff --git a/inc/css/jquery-ui.structure.min.css b/app/static/css/jquery-ui.structure.min.css similarity index 100% rename from inc/css/jquery-ui.structure.min.css rename to app/static/css/jquery-ui.structure.min.css diff --git a/inc/css/nprogress.css b/app/static/css/nprogress.css similarity index 100% rename from inc/css/nprogress.css rename to app/static/css/nprogress.css diff --git a/inc/css/select2.css b/app/static/css/select2.css similarity index 100% rename from inc/css/select2.css rename to app/static/css/select2.css diff --git a/inc/css/servers.css b/app/static/css/servers.css similarity index 100% rename from inc/css/servers.css rename to app/static/css/servers.css diff --git a/inc/css/smon.css b/app/static/css/smon.css similarity index 100% rename from inc/css/smon.css rename to app/static/css/smon.css diff --git a/inc/css/style-6.3.9.css b/app/static/css/style-6.3.9.css similarity index 100% rename from inc/css/style-6.3.9.css rename to app/static/css/style-6.3.9.css diff --git a/inc/css/table-6.3.9.css b/app/static/css/table-6.3.9.css similarity index 100% rename from inc/css/table-6.3.9.css rename to app/static/css/table-6.3.9.css diff --git a/inc/css/toastr-6.3.9.css b/app/static/css/toastr-6.3.9.css similarity index 100% rename from inc/css/toastr-6.3.9.css rename to app/static/css/toastr-6.3.9.css diff --git a/app/templates/add.html b/app/templates/add.html index 5c76e3b4..b72a58dd 100644 --- a/app/templates/add.html +++ b/app/templates/add.html @@ -44,7 +44,7 @@ {{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: - {{ select('serv', values=user_params['servers'], is_servers='true') }} + {{ select('serv', values=g.user_params['servers'], is_servers='true') }}
{{lang.words.note|title()}}: {{lang.phrases.master_slave}}
@@ -307,7 +307,7 @@ {{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: - {{ select('serv2', values=user_params['servers'], is_servers='true') }} + {{ select('serv2', values=g.user_params['servers'], is_servers='true') }}
{{lang.words.note|title()}}: {{lang.phrases.master_slave}}
@@ -498,7 +498,7 @@ {{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: - {{ select('serv3', values=user_params['servers'], is_servers='true') }} + {{ select('serv3', values=g.user_params['servers'], is_servers='true') }}
{{lang.words.note|title()}}: {{lang.phrases.master_slave}}
@@ -721,7 +721,7 @@ - {{ select('serv5', values=user_params['servers'], is_servers='true') }} + {{ select('serv5', values=g.user_params['servers'], is_servers='true') }} @@ -739,7 +739,7 @@ - {{ select('serv4', values=user_params['servers'], is_servers='true') }} + {{ select('serv4', values=g.user_params['servers'], is_servers='true') }} {{ input('ssl_name') }} @@ -760,7 +760,7 @@ - {{ select('serv_for_lets', values=user_params['servers'], is_servers='true') }} + {{ select('serv_for_lets', values=g.user_params['servers'], is_servers='true') }} {{ input('lets_domain', placeholder="example.com") }} @@ -784,7 +784,7 @@ {% for option in options %} - {% if option.groups|string() == user_params['group_id']|string() or group|string() == '1' %} + {% if option.groups|string() == g.user_params['group_id']|string() or group|string() == '1' %} {{ option.id }} @@ -833,7 +833,7 @@ {% for s in saved_servers %} - {% if s.groups|string() == user_params['group_id']|string() or group|string() == '1' %} + {% if s.groups|string() == g.user_params['group_id']|string() or group|string() == '1' %} @@ -879,7 +879,7 @@ {{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: - {{ select('userlist_serv', name='serv', values=user_params['servers'], is_servers='true') }} + {{ select('userlist_serv', name='serv', values=g.user_params['servers'], is_servers='true') }}
{{lang.words.note|title()}}: {{lang.phrases.master_slave}}
{{lang.add_page.desc.userlist_desc}} @@ -932,7 +932,7 @@ {{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: - {{ select('existing_userlist_serv', name='serv', values=user_params['servers'], is_servers='true') }} + {{ select('existing_userlist_serv', name='serv', values=g.user_params['servers'], is_servers='true') }}
{{lang.words.note|title()}}: {{lang.phrases.master_slave}}
@@ -962,7 +962,7 @@ {{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: - {{ select('peers_serv', name='serv', values=user_params['servers'], is_servers='true') }} + {{ select('peers_serv', name='serv', values=g.user_params['servers'], is_servers='true') }}
{{lang.words.note|title()}}: {{lang.phrases.master_slave}}
@@ -1029,7 +1029,7 @@ - {{ select('serv-black-list', values=user_params['servers'], is_servers='true') }} + {{ select('serv-black-list', values=g.user_params['servers'], is_servers='true') }} {% for list in black_lists %} @@ -1054,7 +1054,7 @@ - {{ select('serv-white-list', values=user_params['servers'], is_servers='true') }} + {{ select('serv-white-list', values=g.user_params['servers'], is_servers='true') }} {% for list in white_lists %} @@ -1089,7 +1089,7 @@ - {{ select('serv-map', values=user_params['servers'], is_servers='true') }} + {{ select('serv-map', values=g.user_params['servers'], is_servers='true') }} {% for map in maps %} @@ -1115,7 +1115,7 @@ - + - + {% include 'include/intro/admin.html' %} {% include 'include/intro/js_script.html' %} {% endblock %} diff --git a/app/templates/ajax/alerts_history.html b/app/templates/ajax/alerts_history.html index 64a72556..6c81d67f 100644 --- a/app/templates/ajax/alerts_history.html +++ b/app/templates/ajax/alerts_history.html @@ -1,4 +1,4 @@ - + {% if action == "history" %} {% set column_for_sort = 4 %} diff --git a/app/templates/ajax/group_update.html b/app/templates/ajax/group_update.html deleted file mode 100644 index e53bc0ea..00000000 --- a/app/templates/ajax/group_update.html +++ /dev/null @@ -1,13 +0,0 @@ -{% for group in groups %} - - - - - - - - - - - -{% endfor %} \ No newline at end of file diff --git a/app/templates/ajax/ha/clusters.html b/app/templates/ajax/ha/clusters.html index 96edda88..9e748df4 100644 --- a/app/templates/ajax/ha/clusters.html +++ b/app/templates/ajax/ha/clusters.html @@ -8,7 +8,7 @@ {% if cluster.desc != '' %} ({{cluster.desc}}) {% endif %} - {% if user_params['role'] <= 3 %} + {% if g.user_params['role'] <= 3 %} @@ -44,7 +44,7 @@ VIP: {%- for vip in vips %} - {% if user_params['role'] <= 2 %} + {% if g.user_params['role'] <= 2 %} {{vip.vip}} {% else %} {{vip.vip}} diff --git a/app/templates/ajax/overviewHapwi.html b/app/templates/ajax/overviewHapwi.html deleted file mode 100644 index 8dfe5cdb..00000000 --- a/app/templates/ajax/overviewHapwi.html +++ /dev/null @@ -1,4 +0,0 @@ -{% for s in server_status %} -{{ s }} -{{stderr}} -{% endfor %} \ No newline at end of file diff --git a/app/templates/ajax/table_backup.html b/app/templates/ajax/table_backup.html deleted file mode 100644 index fd664561..00000000 --- a/app/templates/ajax/table_backup.html +++ /dev/null @@ -1,75 +0,0 @@ -{% for b in backups %} - - - {{ b.1 }} - - - - - - - - - {% set values = {'backup':'backup','synchronization':'synchronization'} %} - - - - {% set values = {'hourly':'hourly','daily':'daily','weekly':'weekly', 'monthly':'monthly'} %} - - - - - - - {% if b.7 != 'None' %} - - {% endif %} - - - - - - - - - -{% endfor %} \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index 4b1f5adc..4dd5680b 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -4,10 +4,6 @@ {% from 'include/input_macros.html' import select, checkbox %} {% block title %}{% endblock %} - - - - - {% if title == 'Login page' %} - - {% endif %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + {% include 'include/main_head.html' %} - {% if user_params['user'] %} - + {% if g.user_params['user'] %} + {% include 'include/main_menu.html' %}
@@ -97,8 +50,8 @@ {% include 'include/autorefresh_submenu.html' %} {% endif %}
    - {% if role %} - {% if role <= 2 %} + {% if g.user_params['role'] %} + {% if g.user_params['role'] <= 2 %} diff --git a/app/templates/config.html b/app/templates/config.html index 03b0ff80..aa0389bd 100644 --- a/app/templates/config.html +++ b/app/templates/config.html @@ -25,16 +25,16 @@ -{% if is_serv_protected and user_params['role'] > 2 %} +{% if is_serv_protected and g.user_params['role'] > 2 %} {% else %} - {% if user_params['servers']|length == 0 %} + {% if g.user_params['servers']|length == 0 %} {% include 'include/getstarted.html' %} {% else %}

    - {{ select('serv', values=user_params['servers'], is_servers='true', selected=serv) }} + {{ select('serv', values=g.user_params['servers'], is_servers='true', selected=serv) }} {% if service == 'nginx' or service == 'apache' %} {{lang.words.open|title()}} {% else %} @@ -47,10 +47,10 @@ {{lang.words.map|title()}} {% endif %} {{lang.words.compare|title()}} - {% if user_params['role'] <= 3 %} + {% if g.user_params['role'] <= 3 %} {{lang.menu_links.versions.link}} {% endif %} - {% if user_params['role'] <= 2 %} + {% if g.user_params['role'] <= 2 %} Git {% endif %}
    @@ -63,7 +63,7 @@ {% endif %} {% if config %} - {% if user_params['role'] <= 3 %} + {% if g.user_params['role'] <= 3 %}

    {{lang.words.config|title()}} {% if config_file_name and config_file_name != 'undefined' %}{{config_file_name.replace('92', '/')}}{%endif%} {{lang.words.from}} {{ serv }}

    diff --git a/app/templates/configver.html b/app/templates/configver.html index 986c18af..74e3b3eb 100644 --- a/app/templates/configver.html +++ b/app/templates/configver.html @@ -5,7 +5,7 @@

    - {{ select('serv', values=user_params['servers'], is_servers='true', selected=serv) }} + {{ select('serv', values=g.user_params['servers'], is_servers='true', selected=serv) }}

    diff --git a/app/templates/delver.html b/app/templates/delver.html index b0b403ed..3122ec47 100644 --- a/app/templates/delver.html +++ b/app/templates/delver.html @@ -2,15 +2,15 @@ {% block title %}{{ lang.menu_links.versions.h2 }} {{ lang.words[service] }}{% endblock %} {% block h2 %}{{ lang.menu_links.versions.h2 }} {{ lang.words[service] }}{% endblock %} {% block content %} -{% if user_params['servers']|length == 0 %} +{% if g.user_params['servers']|length == 0 %} {% include 'include/getstarted.html' %} {% else %} - +

    - {{ select('serv', values=user_params['servers'], is_servers='true', selected=serv) }} + {{ select('serv', values=g.user_params['servers'], is_servers='true', selected=serv) }} {{lang.words.open|title()}} {{lang.words.configs|title()}} {% if service != 'keepalived' %} @@ -37,7 +37,7 @@
    {% endif %} {% if serv and not aftersave %} - {% for select in user_params['servers'] %} + {% for select in g.user_params['servers'] %} {% if select.2 == serv %} {% endif %} diff --git a/app/templates/ha_cluster.html b/app/templates/ha_cluster.html index 07f6f2ef..74656e17 100644 --- a/app/templates/ha_cluster.html +++ b/app/templates/ha_cluster.html @@ -6,9 +6,9 @@ - - - + + + {% if user_subscription.user_status == 0 or user_subscription.user_plan == 'user' %} {% include 'include/no_sub.html' %} {% elif not is_needed_tool %} @@ -20,7 +20,7 @@ {% else %} -{% if user_params['role'] <= 2 %} +{% if g.user_params['role'] <= 3 %}
    + {{lang.ha_page.create_ha}}
    {% endif %}
    diff --git a/app/templates/history.html b/app/templates/history.html index 19461364..fa7b5976 100644 --- a/app/templates/history.html +++ b/app/templates/history.html @@ -6,7 +6,7 @@ {% if user_subscription['user_status'] == 0 or user_subscription['user_plan'] == 'user' %} {% include 'include/no_sub.html' %} {% else %} - + diff --git a/app/templates/include/admin_settings.html b/app/templates/include/admin_settings.html index 5e178478..7453e5d5 100644 --- a/app/templates/include/admin_settings.html +++ b/app/templates/include/admin_settings.html @@ -40,13 +40,13 @@ {{set.param}} - {% if set.param in ('ldap_password', 'stats_password', 'nginx_stats_password', 'apache_stats_password', 'rabbitmq_password', 'mail_smtp_password') %} + {% if set.param in ('ldap_password', 'haproxy_stats_password', 'nginx_stats_password', 'apache_stats_password', 'rabbitmq_password', 'mail_smtp_password') %} {% if set.value is none %} {{ input(set.param, size='25', type='password', style='width: 210px;') }} {% else %} {{ input(set.param, size='25', type='password', style='width: 210px;', placeholder='******') }} {% endif %} - {% elif set.param in ('nginx_stats_port', 'session_ttl', 'token_ttl', 'stats_port', 'haproxy_sock_port', + {% elif set.param in ('nginx_stats_port', 'session_ttl', 'token_ttl', 'haproxy_stats_port', 'haproxy_sock_port', 'ldap_port', 'log_time_storage', 'smon_check_interval', 'checker_check_interval', 'port_scan_interval', 'smon_keep_history_range', 'checker_keep_history_range', 'portscanner_keep_history_range', 'checker_maxconn_threshold', 'apache_stats_port', 'mail_smtp_port', 'rabbitmq_port', 'smon_ssl_expire_warning_alert', diff --git a/app/templates/include/admin_ssh.html b/app/templates/include/admin_ssh.html index 33b63c92..c0979221 100644 --- a/app/templates/include/admin_ssh.html +++ b/app/templates/include/admin_ssh.html @@ -61,15 +61,16 @@
    + {{lang.words.add|title()}}

    - - + + + - - + +
    {{lang.words.upload|title()}} SSH {{lang.words.key}}
    {{lang.words.upload|title()}} SSH {{lang.words.key}}{{lang.phrases.ssh_passphrase}} {{lang.words.key|title()}}
    +
    {{ input('ssh-key-pass', title=lang.phrases.ssh_passphrase, type='password') }}

    {{lang.words.upload|title()}} diff --git a/app/templates/include/intro/ovw.html b/app/templates/include/intro/ovw.html index 350c6939..88cefdf2 100644 --- a/app/templates/include/intro/ovw.html +++ b/app/templates/include/intro/ovw.html @@ -45,8 +45,8 @@ intro: "Roles description", }, {% endif %} - {% if user_params['role'] < 3 %} - {% if user_params['role'] > 1 %} + {% if g.user_params['role'] < 3 %} + {% if g.user_params['role'] > 1 %} {% set board_id = 4 %} {% else %} {% set board_id = 7 %} @@ -57,7 +57,7 @@ intro: "Last log entries", }, {% endif %} - {% if user_params['role'] == 1 %} + {% if g.user_params['role'] == 1 %} { element: document.querySelector('#overview-subs'), title: "Dashboard #8", diff --git a/app/templates/include/login.html b/app/templates/include/login.html index 2b57e350..1ff90532 100644 --- a/app/templates/include/login.html +++ b/app/templates/include/login.html @@ -1,5 +1,5 @@ -{% if user_params['user'] %} - +{% if g.user_params['user'] %} + {% else %} {% endif %} diff --git a/app/templates/include/main_head.html b/app/templates/include/main_head.html new file mode 100644 index 00000000..a8197349 --- /dev/null +++ b/app/templates/include/main_head.html @@ -0,0 +1,48 @@ + + + + +{% if title == 'Login page' %} + +{% endif %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/templates/include/main_menu.html b/app/templates/include/main_menu.html index 4205b570..8242bea7 100644 --- a/app/templates/include/main_menu.html +++ b/app/templates/include/main_menu.html @@ -10,12 +10,12 @@
    {% if service == 'haproxy' %} - + diff --git a/inc/ha.js b/inc/ha.js index 1d156578..58a09b2a 100644 --- a/inc/ha.js +++ b/inc/ha.js @@ -103,7 +103,6 @@ function deleteCluster(cluster_id) { }); } function createHaClusterStep1(edited=false, cluster_id=0, clean=true) { - var add_word = $('#translate').attr('data-next'); var cancel_word = $('#translate').attr('data-cancel'); var next_word = $('#translate').attr('data-next'); var tabel_title = $("#create-ha-cluster-step-1-overview").attr('title'); @@ -307,7 +306,7 @@ function saveCluster(jsonData, cluster_id=0, edited=0, reconfigure=0) { let nginx = 0; let nginx_docker = 0; let apache = 0; - req_method = 'POST'; + let req_method = 'POST'; if (edited) { req_method = 'PUT'; } @@ -438,7 +437,7 @@ function Reconfigure(jsonData, cluster_id) { }); } function installServiceCluster(jsonData, service, progress_step, cluster_id) { - servers = JSON.parse(JSON.stringify(jsonData)); + let servers = JSON.parse(JSON.stringify(jsonData)); servers['cluster_id'] = cluster_id; var li_id = 'creating-' + service + '-'; var install_mess = $('#translate').attr('data-installing'); diff --git a/inc/users.js b/inc/users.js index e84739a2..890aea21 100644 --- a/inc/users.js +++ b/inc/users.js @@ -45,190 +45,19 @@ $( function() { }); }); $('#haproxy_exp_install').click(function() { - $("#ajaxmon").html('') - $("#ajaxmon").html(wait_mess); - var ext_prom = 0; - if ($('#haproxy_ext_prom').is(':checked')) { - ext_prom = '1'; - } - $.ajax({ - url: "/app/install/exporter/haproxy", - data: { - server_ip: $('#haproxy_exp_addserv').val(), - exporter_v: $('#hapexpver').val(), - ext_prom: ext_prom, - token: $('#token').val() - }, - type: "POST", - success: function (data) { - data = data.replace(/\s+/g, ' '); - $("#ajaxmon").html(''); - if (data.indexOf('error:') != '-1' || data.indexOf('FAILED') != '-1' || data.indexOf('UNREACHABLE') != '-1') { - toastr.clear(); - var p_err = show_pretty_ansible_error(data); - toastr.error(p_err); - } else if (data.indexOf('success') != '-1') { - toastr.clear(); - toastr.success(data); - $('#cur_haproxy_exp_ver').text('HAProxy exporter is installed'); - $("#haproxy_exp_addserv").trigger("selectmenuchange"); - } else if (data.indexOf('Info') != '-1') { - toastr.clear(); - toastr.info(data); - } else { - toastr.clear(); - toastr.info(data); - } - } - }); + installExporter('haproxy'); }); $('#nginx_exp_install').click(function() { - $("#ajaxmon").html('') - $("#ajaxmon").html(wait_mess); - var ext_prom = 0; - if ($('#nginx_ext_prom').is(':checked')) { - ext_prom = '1'; - } - $.ajax({ - url: "/app/install/exporter/nginx", - data: { - server_ip: $('#nginx_exp_addserv').val(), - exporter_v: $('#nginxexpver').val(), - ext_prom: ext_prom, - token: $('#token').val() - }, - type: "POST", - success: function (data) { - data = data.replace(/\s+/g, ' '); - $("#ajaxmon").html(''); - if (data.indexOf('error:') != '-1' || data.indexOf('FAILED') != '-1' || data.indexOf('UNREACHABLE') != '-1') { - var p_err = show_pretty_ansible_error(data); - toastr.error(p_err); - } else if (data.indexOf('success') != '-1') { - toastr.clear(); - toastr.success(data); - $('#cur_nginx_exp_ver').text('NGINX exporter is installed'); - $("#nginx_exp_addserv").trigger("selectmenuchange"); - } else if (data.indexOf('Info') != '-1') { - toastr.clear(); - toastr.info(data); - } else { - toastr.clear(); - toastr.info(data); - } - } - }); + installExporter('nginx'); }); $('#apache_exp_install').click(function() { - $("#ajaxmon").html('') - $("#ajaxmon").html(wait_mess); - var ext_prom = 0; - if ($('#apache_ext_prom').is(':checked')) { - ext_prom = '1'; - } - $.ajax({ - url: "/app/install/exporter/apache", - data: { - server_ip: $('#apache_exp_addserv').val(), - exporter_v: $('#apacheexpver').val(), - ext_prom: ext_prom, - token: $('#token').val() - }, - type: "POST", - success: function (data) { - data = data.replace(/\s+/g, ' '); - $("#ajaxmon").html(''); - if (data.indexOf('error:') != '-1' || data.indexOf('FAILED') != '-1' || data.indexOf('UNREACHABLE') != '-1') { - var p_err = show_pretty_ansible_error(data); - toastr.error(p_err); - } else if (data.indexOf('success') != '-1') { - toastr.clear(); - toastr.success(data); - $('#cur_apache_exp_ver').text('Apache exporter is installed'); - $("#apache_exp_addserv").trigger("selectmenuchange"); - } else if (data.indexOf('Info') != '-1') { - toastr.clear(); - toastr.info(data); - } else { - toastr.clear(); - toastr.info(data); - } - } - }); + installExporter('apache'); }); $('#keepalived_exp_install').click(function() { - $("#ajaxmon").html('') - $("#ajaxmon").html(wait_mess); - var ext_prom = 0; - if ($('#keepalived_ext_prom').is(':checked')) { - ext_prom = '1'; - } - $.ajax( { - url: "/app/install/exporter/keepalived", - data: { - server_ip: $('#keepalived_exp_addserv').val(), - exporter_v: $('#keepalivedexpver').val(), - ext_prom: ext_prom, - token: $('#token').val() - }, - type: "POST", - success: function( data ) { - data = data.replace(/\s+/g,' '); - $("#ajaxmon").html(''); - if (data.indexOf('error:') != '-1' || data.indexOf('FAILED') != '-1' || data.indexOf('UNREACHABLE') != '-1') { - var p_err = show_pretty_ansible_error(data); - toastr.error(p_err); - } else if (data.indexOf('success') != '-1' ){ - toastr.clear(); - toastr.success(data); - $('#cur_keepalived_exp_ver').text('Keepalived exporter is installed'); - $("#keepalived_exp_addserv").trigger( "selectmenuchange" ); - } else if (data.indexOf('Info') != '-1' ){ - toastr.clear(); - toastr.info(data); - } else { - toastr.clear(); - toastr.info(data); - } - } - } ); + installExporter('keepalived'); }); $('#node_exp_install').click(function() { - $("#ajaxmon").html('') - $("#ajaxmon").html(wait_mess); - var ext_prom = 0; - if ($('#node_ext_prom').is(':checked')) { - ext_prom = '1'; - } - $.ajax({ - url: "/app/install/exporter/node", - data: { - server_ip: $('#node_exp_addserv').val(), - exporter_v: $('#nodeexpver').val(), - ext_prom: ext_prom, - token: $('#token').val() - }, - type: "POST", - success: function (data) { - data = data.replace(/\s+/g, ' '); - $("#ajaxmon").html(''); - if (data.indexOf('error:') != '-1' || data.indexOf('FAILED') != '-1' || data.indexOf('UNREACHABLE') != '-1') { - var p_err = show_pretty_ansible_error(data); - toastr.error(p_err); - } else if (data.indexOf('success') != '-1') { - toastr.clear(); - toastr.success(data); - $('#cur_node_exp_ver').text('Node exporter is installed'); - $("#node_exp_addserv").trigger("selectmenuchange"); - } else if (data.indexOf('Info') != '-1') { - toastr.clear(); - toastr.info(data); - } else { - toastr.clear(); - toastr.info(data); - } - } - }); + installExporter('node'); }); $( "#haproxyaddserv" ).on('selectmenuchange',function() { showServiceVersion('haproxy'); @@ -240,106 +69,19 @@ $( function() { showServiceVersion('apache'); }); $( "#haproxy_exp_addserv" ).on('selectmenuchange',function() { - $.ajax( { - url: "/app/install/exporter/haproxy/version/" + $('#haproxy_exp_addserv option:selected').val(), - // data: { - // token: $('#token').val() - // }, - // type: "POST", - success: function( data ) { - data = data.replace(/^\s+|\s+$/g,''); - if (data.indexOf('error:') != '-1') { - toastr.clear(); - toastr.error(data); - } else if(data == 'no' || data == '' || data.indexOf('No') != '-1') { - $('#cur_haproxy_exp_ver').text('HAProxy exporter has been not installed'); - } else { - $('#cur_haproxy_exp_ver').text(data); - } - } - } ); + showExporterVersion('haproxy'); }); $( "#nginx_exp_addserv" ).on('selectmenuchange',function() { - $.ajax({ - url: "/app/install/exporter/nginx/version/" + $('#nginx_exp_addserv option:selected').val(), - // data: { - // token: $('#token').val() - // }, - // type: "POST", - success: function (data) { - data = data.replace(/^\s+|\s+$/g, ''); - if (data.indexOf('error:') != '-1') { - toastr.clear(); - toastr.error(data); - } else if (data == 'no' || data == '' || data.indexOf('No') != '-1') { - $('#cur_nginx_exp_ver').text('NGINX exporter has not been installed'); - } else { - $('#cur_nginx_exp_ver').text(data); - } - } - }); + showExporterVersion('nginx'); }); $( "#apache_exp_addserv" ).on('selectmenuchange',function() { - $.ajax({ - url: "/app/install/exporter/apache/version/" + $('#apache_exp_addserv option:selected').val(), - // data: { - // token: $('#token').val() - // }, - // type: "POST", - success: function (data) { - data = data.replace(/^\s+|\s+$/g, ''); - if (data.indexOf('error:') != '-1') { - toastr.clear(); - toastr.error(data); - } else if (data == 'no' || data == '' || data.indexOf('No') != '-1') { - $('#cur_apache_exp_ver').text('Apache exporter has not been installed'); - } else { - $('#cur_apache_exp_ver').text(data); - } - } - }); + showExporterVersion('apache'); }); $( "#keepalived_exp_addserv" ).on('selectmenuchange',function() { - $.ajax({ - url: "/app/install/exporter/keepalived/version/" + $('#keepalived_exp_addserv option:selected').val(), - // data: { - // token: $('#token').val() - // }, - // type: "POST", - success: function (data) { - data = data.replace(/^\s+|\s+$/g, ''); - if (data.indexOf('error:') != '-1') { - toastr.clear(); - toastr.error(data); - } else if (data.indexOf('keepalived_exporter.service') != '-1') { - $('#cur_keepalived_exp_ver').text('Keepalived exporter has been installed'); - } else if (data == 'no' || data == '' || data.indexOf('No') != '-1') { - $('#cur_keepalived_exp_ver').text('Keepalived exporter has not been installed'); - } else { - $('#cur_keepalived_exp_ver').text(data); - } - } - }); + showExporterVersion('keepalived'); }); $( "#node_exp_addserv" ).on('selectmenuchange',function() { - $.ajax({ - url: "/app/install/exporter/node/version/" + $('#node_exp_addserv option:selected').val(), - // data: { - // token: $('#token').val() - // }, - // type: "POST", - success: function (data) { - data = data.replace(/^\s+|\s+$/g, ''); - if (data.indexOf('error:') != '-1') { - toastr.clear(); - toastr.error(data); - } else if (data == 'no' || data.indexOf('command') != '-1' || data == '') { - $('#cur_node_exp_ver').text('Node exporter has not been installed'); - } else { - $('#cur_node_exp_ver').text(data); - } - } - }); + showExporterVersion('node'); }); $('#add-group-button').click(function() { addGroupDialog.dialog('open'); @@ -1162,7 +904,7 @@ function getGroupNameById(group_id) { function addRecevier(dialog_id, receiver_name) { var valid = true; toastr.clear(); - allFields = $([]).add($('#' + receiver_name + '-token-add')).add($('#' + receiver_name + '-chanel-add')); + let allFields = $([]).add($('#' + receiver_name + '-token-add')).add($('#' + receiver_name + '-chanel-add')); allFields.removeClass("ui-state-error"); valid = valid && checkLength($('#' + receiver_name + '-token-add'), "token", 1); valid = valid && checkLength($('#' + receiver_name + '-chanel-add'), "channel name", 1); @@ -1198,7 +940,7 @@ function addRecevier(dialog_id, receiver_name) { function addBackup(dialog_id) { var valid = true; toastr.clear(); - allFields = $([]).add($('#backup-server')).add($('#rserver')).add($('#rpath')).add($('#backup-time')).add($('#backup-credentials')) + let allFields = $([]).add($('#backup-server')).add($('#rserver')).add($('#rpath')).add($('#backup-time')).add($('#backup-credentials')); allFields.removeClass("ui-state-error"); valid = valid && checkLength($('#backup-server'), "backup server ", 1); valid = valid && checkLength($('#rserver'), "remote server", 1); @@ -1881,6 +1623,7 @@ function uploadSsh() { data: { ssh_cert: $('#ssh_cert').val(), name: $('#ssh-key-name').val(), + pass: $('#ssh-key-pass').val(), token: $('#token').val() }, type: "POST", @@ -2788,13 +2531,15 @@ function installService(service) { $("#ajax").html('') var syn_flood = 0; var docker = 0; + var select_id = '#' + service + 'addserv'; + var nice_names = {'haproxy': 'HAProxy', 'nginx': 'NGINX', 'apache': 'Apache'}; if ($('#' + service + '_syn_flood').is(':checked')) { syn_flood = '1'; } if ($('#' + service + '_docker').is(':checked')) { docker = '1'; } - if ($('#haproxyaddserv').val() == '------' || $('#' + service + 'addserv').val() === null) { + if ($(select_id).val() == '------' || $(select_id).val() === null) { var select_server = $('#translate').attr('data-select_server'); toastr.warning(select_server); return false @@ -2804,24 +2549,22 @@ function installService(service) { jsonData['services'] = {}; jsonData['services'][service] = {}; jsonData['syn_flood'] = syn_flood; - jsonData['servers']['0']['ip'] = $('#' + service + 'addserv').val(); + jsonData['servers']['0']['ip'] = $(select_id).val(); jsonData['servers']['0']['master'] = '0'; - jsonData['servers']['0']['name'] = $('#' + service + 'addserv option:selected').text(); + jsonData['servers']['0']['name'] = $(select_id + ' option:selected').text(); if (service == 'haproxy') { jsonData['servers']['0']['version'] = $('#hapver option:selected').val(); } - console.log(jsonData) jsonData['services'][service]['enabled'] = 1; jsonData['services'][service]['docker'] = docker; - var nice_names = {'haproxy': 'HAProxy', 'nginx': 'NGINX', 'apache': 'Apache'}; $("#ajax").html(wait_mess); $.ajax({ url: "/app/install/" + service, 500: function () { - showErrorStatus(ice_names[service], $('#' + service + 'addserv option:selected').text()); + showErrorStatus(nice_names[service], $(select_id + ' option:selected').text()); }, 504: function () { - showErrorStatus(ice_names[service], $('#' + service + 'addserv option:selected').text()); + showErrorStatus(nice_names[service], $(select_id + ' option:selected').text()); }, data: { jsonData: JSON.stringify(jsonData), @@ -2834,12 +2577,70 @@ function installService(service) { toastr.error(data); } } catch (e) { - parseAnsibleJsonOutput(data, nice_names[service]); - $("#" + service + "yaddserv").trigger("selectmenuchange"); + parseAnsibleJsonOutput(data, nice_names[service], select_id); + $(select_id).trigger("selectmenuchange"); } } }); } +function installExporter(exporter) { + $("#ajaxmon").html(''); + $("#ajaxmon").html(wait_mess); + var exporter_id = '#' + exporter + '_exp_addserv'; + var ext_prom = 0; + if ($('#' + exporter + '_ext_prom').is(':checked')) { + ext_prom = '1'; + } + var nice_names = {'haproxy': 'HAProxy exporter', 'nginx': 'NGINX exporter', 'apache': 'Apache exporter', 'node': 'Node exporter', 'keepalived': 'Keepalived exporter'}; + $("#ajax").html(wait_mess); + $.ajax({ + url: "/app/install/exporter/" + exporter, + 500: function () { + showErrorStatus(nice_names[exporter], $(exporter_id + ' option:selected').text()); + }, + 504: function () { + showErrorStatus(nice_names[exporter], $(exporter_id + ' option:selected').text()); + }, + data: { + server_ip: $(exporter_id).val(), + exporter_v: $('#' + exporter + 'expver').val(), + ext_prom: ext_prom, + token: $('#token').val() + }, + type: "POST", + success: function (data) { + try { + if (data.indexOf('error:') != '-1') { + toastr.error(data); + } + } catch (e) { + parseAnsibleJsonOutput(data, nice_names[exporter], exporter_id); + $(exporter_id).trigger("selectmenuchange"); + } + } + }); +} +function showExporterVersion(exporter) { + var nice_names = {'haproxy': 'HAProxy', 'nginx': 'NGINX', 'apache': 'Apache', 'node': 'Node', 'keepalived': 'Keepalived'}; + $.ajax({ + url: "/app/install/exporter/"+ exporter +"/version/" + $('#' + exporter + '_exp_addserv option:selected').val(), + // data: { + // token: $('#token').val() + // }, + // type: "POST", + success: function (data) { + data = data.replace(/^\s+|\s+$/g, ''); + if (data.indexOf('error:') != '-1') { + toastr.clear(); + toastr.error(data); + } else if (data == 'no' || data.indexOf('command') != '-1' || data.indexOf('_exporter:') != '-1' || data == '') { + $('#cur_'+ exporter +'_exp_ver').text(nice_names[exporter]+' exporter has not been installed'); + } else { + $('#cur_'+ exporter +'_exp_ver').text(data); + } + } + }); +} function showServiceVersion(service) { $.ajax({ url: "/app/install/" + service + "/version/" + $('#' + service + 'addserv option:selected').val(), @@ -3108,17 +2909,20 @@ function showErrorStatus(service_name, server) { var something_wrong = $('#translate').attr('data-something_wrong'); toastr.error(something_wrong + ' ' + service_name + ' ' + server); } -function parseAnsibleJsonOutput(output, service_name) { +function parseAnsibleJsonOutput(output, service_name, select_id) { output = JSON.parse(JSON.stringify(output)); var check_apache_log = $('#translate').attr('data-check_apache_log'); var was_installed = $('#translate').attr('data-was_installed'); for (var k in output['ok']) { - toastr.success(service_name + ' ' + was_installed +' ' + k); + var server_name = $(select_id + ' option[value="'+k+'"]').text(); + toastr.success(service_name + ' ' + was_installed +' ' + server_name); } for (var k in output['failures']) { - showErrorStatus(service_name, k); + var server_name = $(select_id + ' option[value="'+k+'"]').text(); + showErrorStatus(service_name, server_name); } for (var k in output['dark']) { - showErrorStatus(service_name, k); + var server_name = $(select_id + ' option[value="'+k+'"]').text(); + showErrorStatus(service_name, server_name); } } diff --git a/index.html b/index.html index 3a175c53..814faf24 100644 --- a/index.html +++ b/index.html @@ -29,30 +29,31 @@ - - - - + + + + - - + + - - - - - + + + + + + - + - + diff --git a/roxy-wi.cfg b/roxy-wi.cfg index 3a4bdc92..6dfdec11 100644 --- a/roxy-wi.cfg +++ b/roxy-wi.cfg @@ -3,6 +3,8 @@ fullpath = /var/www/haproxy-wi log_path = /var/log/roxy-wi lib_path = /var/lib/roxy-wi +# Change secret_phrase to 32 url-safe base64-encoded +secret_phrase = _B8avTpFFL19M8P9VyTiX42NyeyUaneV26kyftB2E_4= [configs] # Folders for configs