Changelog: https://roxy-wi.org/changelog#7.1.2
pull/375/head
Aidaho 2024-02-04 10:28:17 +03:00
parent ac133b5e9c
commit 2712b25515
113 changed files with 1817 additions and 2086 deletions

View File

@ -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/<id,hostname,ip>': 'show info about the HAProxy by id or hostname or ip. METHOD: GET',
'haproxy/<id,hostname,ip>/status': 'show HAProxy status by id or hostname or ip. METHOD: GET',

View File

@ -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:

View File

@ -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()

View File

@ -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'])

View File

@ -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

View File

@ -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

View File

@ -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}"

View File

@ -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'<br>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('<div class="alert alert-danger">Cannot read exported config file</div>')
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'<center><div class="alert alert-danger">Can\'t read write change to log. {stderr}</div></center>')
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'<span style="color: red; font-weight: bold;">{word}</span>')
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'<div class="{css_class}">{content}</div>'
def show_finding_in_config(stdout: str, **kwargs) -> str:
grep = ''
out = '<div class="line">--</div>'
"""
: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'<span style="color: red; font-weight: bold;">{grep}</span>')
line_class = "line" if '--' in line else "line3"
out += f'<div class="{line_class}">{line}</div>'
if word_to_find:
line = _highlight_word(line, word_to_find)
line_class = _classify_line(line)
output += _wrap_line(line, line_class)
out += '<div class="line">--</div>'
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

View File

@ -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)

View File

@ -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':

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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}')

View File

@ -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:

View File

@ -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 '<div class="ping_pre">'
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'<span style="color: var(--link-dark-blue); display: block; margin-top: -5px;">{i}</span><br />\n'
elif i in ('no reply', 'no answer yet', 'Too many hops', '100% packet loss'):
yield f'<span style="color: var(--red-color);">{i}</span><br />\n'
elif 'ms' in i and '100% packet loss' not in i:
yield f'<span style="color: var(--green-color);">{i}</span><br />\n'
else:
yield f'{i}<br />'
yield '</div>'
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 += '<span style="color: var(--link-dark-blue); display: block; margin-top: -5px;">'
elif 'no reply' in i or 'no answer yet' in i or 'Too many hops' in i or '100% packet loss' in i:
output1 += '<span style="color: var(--red-color);">'
elif 'ms' in i and '100% packet loss' not in i:
output1 += '<span style="color: var(--green-color);">'
else:
output1 += '<span>'
output1 += i + '</span><br />'
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:

View File

@ -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()

View File

@ -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

View File

@ -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:

View File

@ -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}')

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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}}\'']

View File

@ -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}')

View File

@ -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'<center><h4 style="margin-bottom: 0;">Map from {serv}</h4>'
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'<center><h3>You {enable} {backend} on HAProxy {serv}.</center>' \
f'{output}'
return f'<center><h3>You {enable} {backend} on HAProxy {serv}.</center> {output}'
else:
return output

View File

@ -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}')

View File

@ -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:

View File

@ -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']

View File

@ -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(),

View File

@ -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(),

View File

@ -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/<server_ip>')
@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/<server_ip>/<section>')
@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/<server_ip>/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': '',

View File

@ -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']
}

View File

@ -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/<exporter>/version/<server_ip>')
def get_exporter_version(exporter, server_ip):

View File

@ -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,

View File

@ -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/<check>')
@ -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(),

View File

@ -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,

View File

@ -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(),

View File

@ -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()

View File

@ -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/<server_ip>')

View File

@ -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)

View File

@ -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/<service>/<server_ip>/<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('/<service>/<server_ip>/last-edit')
@check_services
def last_edit(service, server_ip):
return service_common.get_overview_last_edit(server_ip, service)

View File

@ -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/<dashboard_id>/<check_id>')
@bp.route('/dashboard/<int:smon_id>/<int:check_id>')
@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/<int:page_id>')
@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
}

View File

@ -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']),

View File

@ -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}}'

View File

@ -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

View File

@ -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']

View File

@ -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

View File

@ -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}}']

View File

@ -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

View File

@ -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 <br /><br />"
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

View File

@ -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 <br /><br />"
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"

View File

@ -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 <br /><br />"
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

View File

@ -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 <br /><br />"
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

View File

@ -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 <br /><br />"
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

View File

@ -44,7 +44,7 @@
<tr>
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
<td class="addOption">
{{ select('serv', values=user_params['servers'], is_servers='true') }}
{{ select('serv', values=g.user_params['servers'], is_servers='true') }}
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
</td>
<td rowspan="5" class="add-note addName alert-info">
@ -307,7 +307,7 @@
<tr>
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
<td class="addOption">
{{ select('serv2', values=user_params['servers'], is_servers='true') }}
{{ select('serv2', values=g.user_params['servers'], is_servers='true') }}
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
</td>
<td rowspan="5" class="add-note addName alert-info">
@ -498,7 +498,7 @@
<tr>
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
<td class="addOption">
{{ select('serv3', values=user_params['servers'], is_servers='true') }}
{{ select('serv3', values=g.user_params['servers'], is_servers='true') }}
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
</td>
<td rowspan="4" class="add-note addName alert-info">
@ -721,7 +721,7 @@
</tr>
<tr>
<td class="padding10 first-collumn">
{{ select('serv5', values=user_params['servers'], is_servers='true') }}
{{ select('serv5', values=g.user_params['servers'], is_servers='true') }}
<button id="ssl_key_view" title="{{lang.words.view|title()}} {{lang.words.certs}}">{{lang.words.view|title()}}</button>
</td>
<td colspan="2" style="padding: 10px 0 10px 0;">
@ -739,7 +739,7 @@
</tr>
<tr>
<td class="first-collumn padding10" valign="top" style="padding-top: 15px;">
{{ select('serv4', values=user_params['servers'], is_servers='true') }}
{{ select('serv4', values=g.user_params['servers'], is_servers='true') }}
</td>
<td valign="top" style="padding-top: 27px;">
{{ input('ssl_name') }}
@ -760,7 +760,7 @@
</tr>
<tr>
<td class="padding10 first-collumn">
{{ select('serv_for_lets', values=user_params['servers'], is_servers='true') }}
{{ select('serv_for_lets', values=g.user_params['servers'], is_servers='true') }}
</td>
<td>
{{ input('lets_domain', placeholder="example.com") }}
@ -784,7 +784,7 @@
</tr>
{% for option in options %}
<tr id="option-{{ option.id }}" class="{{ loop.cycle('odd', 'even') }}">
{% 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' %}
<td class="padding10 first-collumn">
{{ option.id }}
</td>
@ -833,7 +833,7 @@
</tr>
{% for s in saved_servers %}
<tr id="servers-saved-{{ s.id }}" class="{{ loop.cycle('odd', 'even') }}">
{% 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' %}
<td class="padding10 first-collumn">
<input type="text" id="servers-ip-{{ s.id }}" value="{{ s.server }}" size="15" class="form-control">
</td>
@ -879,7 +879,7 @@
<tr>
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
<td class="addOption">
{{ 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') }}
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
</td>
<td rowspan="4" class="add-note addName alert-info">{{lang.add_page.desc.userlist_desc}}</td>
@ -932,7 +932,7 @@
<tr>
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
<td class="addOption">
{{ 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') }}
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
</td>
<td>
@ -962,7 +962,7 @@
<tr>
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
<td class="addOption">
{{ 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') }}
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
</td>
<td rowspan="4" class="add-note addName alert-info">
@ -1029,7 +1029,7 @@
<button onclick="createList('black')">{{lang.words.create|title()}}</button>
</td>
<td class="first-collumn">
{{ select('serv-black-list', values=user_params['servers'], is_servers='true') }}
{{ select('serv-black-list', values=g.user_params['servers'], is_servers='true') }}
</td>
<td style="width: 30%; padding: 10px 0 10px 0;">
{% for list in black_lists %}
@ -1054,7 +1054,7 @@
<button onclick="createList('white')">{{lang.words.create|title()}}</button>
</td>
<td class="first-collumn">
{{ select('serv-white-list', values=user_params['servers'], is_servers='true') }}
{{ select('serv-white-list', values=g.user_params['servers'], is_servers='true') }}
</td>
<td style="width: 30%; padding: 10px 0 10px 0;">
{% for list in white_lists %}
@ -1089,7 +1089,7 @@
<button onclick="createMap()">{{lang.words.create|title()}}</button>
</td>
<td class="first-collumn">
{{ select('serv-map', values=user_params['servers'], is_servers='true') }}
{{ select('serv-map', values=g.user_params['servers'], is_servers='true') }}
</td>
<td style="width: 30%; padding: 10px 0 10px 0;">
{% for map in maps %}
@ -1115,7 +1115,7 @@
<div id="dialog-confirm-cert" title="View certificate " style="display: none;">
<pre id="dialog-confirm-body"></pre>
</div>
<input type="hidden" id="group_id" value="{{ user_params['group_id']|string() }}">
<input type="hidden" id="group_id" value="{{ g.user_params['group_id']|string() }}">
</div>
</div>
<script>

View File

@ -20,7 +20,7 @@
<tr>
<td class="addName">{{lang.words.select|title()}} {{lang.words.w_a}} {{lang.words.server}}: </td>
<td class="addOption">
{{ select('serv', values=user_params['servers'], is_servers='true') }}
{{ select('serv', values=g.user_params['servers'], is_servers='true') }}
<div class="tooltip tooltipTop"><b>{{lang.words.note|title()}}:</b> {{lang.phrases.master_slave}}</div>
</td>
<td rowspan="5" class="add-note addName alert-info">
@ -79,7 +79,7 @@
<div id="dialog-confirm-cert" title="View certificate " style="display: none;">
<pre id="dialog-confirm-body"></pre>
</div>
<input type="hidden" id="group_id" value="{{ user_params['group_id'] }}">
<input type="hidden" id="group_id" value="{{ g.user_params['group_id'] }}">
</div>
<script>
$( function() {

View File

@ -174,7 +174,7 @@
{% endfor %}
});
</script>
<link href="/inc/css/servers.css" rel="stylesheet"/>
<link href="{{ url_for('static', filename='css/servers.css') }}" rel="stylesheet"/>
{% include 'include/intro/admin.html' %}
{% include 'include/intro/js_script.html' %}
{% endblock %}

View File

@ -1,4 +1,4 @@
<link href="/inc/css/table-6.3.9.css" rel="stylesheet" type="text/css">
<link href="{{ url_for('static', filename='css/table-6.3.9.css') }}" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
{% if action == "history" %}
{% set column_for_sort = 4 %}

View File

@ -1,13 +0,0 @@
{% for group in groups %}
<tr id="group-{{ group.0 }}">
<td class="padding10 first-collumn">
<input type="text" id="name-{{ group.0 }}" value="{{ group.1 }}" class="form-control">
</td>
<td>
<input type="text" id="descript-{{ group.0 }}" value="{{ group.2 }}" class="form-control" size="100">
</td>
<td>
<a class="delete" onclick="removeGroup({{ group.0 }})" style="cursor: pointer;"></a>
</td>
</tr>
{% endfor %}

View File

@ -8,7 +8,7 @@
<span id="cluster-desc-{{cluster.id}}">{% if cluster.desc != '' %} ({{cluster.desc}}) {% endif %}</span>
</a>
<span class="server-action">
{% if user_params['role'] <= 3 %}
{% if g.user_params['role'] <= 3 %}
<a class="plus" onclick="add_vip_ha_cluster('{{cluster.id}}', '{{cluster.name}}')"></a>
<a class="edit" onclick="createHaClusterStep1(true, '{{cluster.id}}')"></a>
<a class="delete" onclick="confirmDeleteCluster('{{cluster.id}}')"></a>
@ -44,7 +44,7 @@
VIP:
<span id="cluster-vip">
{%- for vip in vips %}
{% if user_params['role'] <= 2 %}
{% if g.user_params['role'] <= 2 %}
<a style="cursor: pointer;" onclick="add_vip_ha_cluster('{{vip.cluster_id}}', '{{cluster.name}}', '{{vip.router_id}}', '{{vip.vip}}', 1)" title="{{lang.words.edit|title()}} VIP">{{vip.vip}}</a>
{% else %}
{{vip.vip}}

View File

@ -1,4 +0,0 @@
{% for s in server_status %}
<span style="margin-bottom: -45px;display: block;font-size: 10px;">{{ s }}</span>
{{stderr}}
{% endfor %}

View File

@ -1,75 +0,0 @@
{% for b in backups %}
<tr class="newbackup" id="backup-table-{{b.0}}">
<td class="padding10 first-collumn">
<span id="backup-server-{{b.0}}">{{ b.1 }}</span>
</td>
<td>
<input type="text" id="backup-rserver-{{b.0}}" value="{{b.2}}" size="14" class="form-control">
</td>
<td>
<input type="text" id="backup-rpath-{{b.0}}" value="{{b.3}}" class="form-control">
</td>
<td>
{% set values = {'backup':'backup','synchronization':'synchronization'} %}
<select name="backup-type-{{b.0}}" id="backup-type-{{b.0}}" class="force_close">
{% for v, des in values|dictsort(false, 'value') %}
{% if v == b.4 %}
<option value="{{v}}" selected>{{des}}</option>
{% else %}
<option value="{{v}}">{{des}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
{% set values = {'hourly':'hourly','daily':'daily','weekly':'weekly', 'monthly':'monthly'} %}
<select name="backup-time-{{b.0}}" id="backup-time-{{b.0}}" class="force_close">
{% for v, des in values|dictsort(false, 'value') %}
{% if v == b.5 %}
<option value="{{v}}" selected>{{des}}</option>
{% else %}
<option value="{{v}}">{{des}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="backup-credentials-{{b.0}}" required>
<option disabled selected>Choose credentials</option>
{% for ssh in sshs %}
{% if ssh.2 == 1 %}
{% if ssh.0 == b.6 %}
<option value="{{ssh.0}}" selected="selected">{{ssh.1}}</option>
{% else %}
<option value="{{ssh.0}}">{{ssh.1}}</option>
{% endif %}
{% endif %}
{% endfor %}
</select>
</td>
<td>
{% if b.7 != 'None' %}
<input type="text" id="backup-description-{{b.0}}" value="{{b.7}}" class="form-control">
{% endif %}
</td>
<td>
<a class="add" onclick="cloneBackup({{b.0}})" id="clone-backup{{b.0}}" title="Clone {{b.1}}" style="cursor: pointer;"></a>
</td>
<td>
<a class="delete" onclick="confirmDeleteBackup({{b.0}})" title="Delete backup {{b.1}}" style="cursor: pointer;"></a>
</td>
</tr>
<script>
$( function() {
$("#backup-time-{{ b.0}}" ).selectmenu({
width: 100
});
$("#backup-type-{{b.0}}" ).selectmenu({
width: 130
});
$("#backup-credentials-{{b.0}}" ).selectmenu({
width: 150
});
});
</script>
{% endfor %}

View File

@ -4,10 +4,6 @@
{% from 'include/input_macros.html' import select, checkbox %}
<head>
<title>{% block title %}{% endblock %}</title>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta id="translate" style="display: none;" data-delete="{{lang.words.delete|title()}}" data-cancel="{{lang.words.cancel|title()}}" data-add="{{lang.words.add|title()}}"
data-superAdmin_pass="{{lang.phrases.superAdmin_pass}}" data-superAdmin_services="{{lang.phrases.superAdmin_services}}" data-change="{{lang.words.change|title()}}"
data-change2="{{lang.words.change2|title()}}" data-password="{{lang.words.password}}" data-groups="{{lang.words.groups}}" data-save="{{lang.words.save|title()}}"
@ -24,54 +20,11 @@
data-installing="{{lang.words.installing|title()}}" data-creating="{{lang.words.creating|title()}}" data-roxywi_timeout="{{lang.ha_page.roxywi_timeout}}"
data-check_apache_log="{{lang.ha_page.check_apache_log}}" data-was_installed="{{lang.ha_page.was_installed}}" data-start_enter="{{lang.ha_page.start_enter}}"
data-apply="{{lang.words.apply|title()}}" />
{% if title == 'Login page' %}
<meta name="viewport" content="width=device-width, user-scalable=1">
{% endif %}
<link rel="icon" type="image/png" href="{{ url_for('static', filename='images/favicon/favicon.ico') }}" />
<link rel="apple-touch-icon" sizes="57x57" href="{{ url_for('static', filename='images/favicon/apple-icon-57x57.png') }}">
<link rel="apple-touch-icon" sizes="60x60" href="{{ url_for('static', filename='images/favicon/apple-icon-60x60.png') }}">
<link rel="apple-touch-icon" sizes="72x72" href="{{ url_for('static', filename='images/favicon/apple-icon-72x72.png') }}">
<link rel="apple-touch-icon" sizes="76x76" href="{{ url_for('static', filename='images/favicon/apple-icon-76x76.png') }}">
<link rel="apple-touch-icon" sizes="114x114" href="{{ url_for('static', filename='images/favicon/apple-icon-114x114.png') }}">
<link rel="apple-touch-icon" sizes="120x120" href="{{ url_for('static', filename='images/favicon/apple-icon-120x120.png') }}">
<link rel="apple-touch-icon" sizes="144x144" href="{{ url_for('static', filename='images/favicon/apple-icon-144x144.png') }}">
<link rel="apple-touch-icon" sizes="152x152" href="{{ url_for('static', filename='images/favicon/apple-icon-152x152.png') }}">
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='images/favicon/apple-icon-180x180.png') }}">
<link rel="icon" type="image/png" sizes="192x192" href="{{ url_for('static', filename='images/favicon/android-icon-192x192.png') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='images/favicon/favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="96x96" href="{{ url_for('static', filename='images/favicon/favicon-96x96.png') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ url_for('static', filename='images/favicon/favicon-16x16.png') }}">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="{{ url_for('static', filename='images/favicon/ms-icon-144x144.png') }}">
<meta name="theme-color" content="#ffffff">
<script defer src="/inc/fa-solid.min.js"></script>
<script defer src="/inc/fontawesome.min.js"></script>
<script src="https://use.fontawesome.com/releases/v5.15.4/js/all.js" data-auto-replace-svg="nest"></script>
<script>FontAwesomeConfig = { searchPseudoElements: true, observeMutations: false };</script>
<script defer src="/inc/ion.sound.min.js"></script>
<script defer src="/inc/intro/introjs.min.js"></script>
<link href="/inc/intro/introjs.min.css" rel="stylesheet">
<link href="/inc/intro/introjs-modern.css" rel="stylesheet">
<link href="/inc/css/awesome-6.3.9.css" rel="stylesheet">
<link href="/inc/css/style-6.3.9.css" rel="stylesheet">
<link href="/inc/css/nprogress.css" rel="stylesheet">
<link href="/inc/css/jquery-ui.min.css" rel="stylesheet">
<link href="/inc/css/jquery-ui.structure.min.css" rel="stylesheet">
<script src="/inc/jquery-3.6.0.min.js"></script>
<script src="/inc/jquery-ui.min.js"></script>
<script src="/inc/js.cookie.min.js"></script>
<script src="/inc/reconnecting-websocket.js"></script>
<script src="/inc/hotkeys.js"></script>
<link href="/inc/css/select2.css" rel="stylesheet" />
<script src="/inc/select2.js"></script>
<script src="/inc/script.js"></script>
<script src="/inc/nprogress.js"></script>
<link href="/inc/css/toastr-6.3.9.css" rel="stylesheet"/>
<script src="/inc/toastr.js"></script>
{% include 'include/main_head.html' %}
</head>
<body>
{% if user_params['user'] %}
<input type="hidden" id="token" value="{{ user_params['token'] }}">
{% if g.user_params['user'] %}
<input type="hidden" id="token" value="{{ g.user_params['token'] }}">
<script>show_version();</script>
{% include 'include/main_menu.html' %}
<div class="container">
@ -97,8 +50,8 @@
{% include 'include/autorefresh_submenu.html' %}
{% endif %}
<ul id='browse_history'></ul>
{% if role %}
{% if role <= 2 %}
{% if g.user_params['role'] %}
{% if g.user_params['role'] <= 2 %}
<div id="apply" style="display: none;">
<div class="alert alert-warning" id="apply_div"></div>
</div>

View File

@ -25,16 +25,16 @@
<script src="/inc/codemirror/mode/haproxy.js"></script>
<script src="/inc/codemirror/keymap/sublime.js"></script>
<script src="/inc/configshow.js"></script>
{% if is_serv_protected and user_params['role'] > 2 %}
{% if is_serv_protected and g.user_params['role'] > 2 %}
<meta http-equiv="refresh" content="0; url=/app/service">
{% else %}
{% if user_params['servers']|length == 0 %}
{% if g.user_params['servers']|length == 0 %}
{% include 'include/getstarted.html' %}
{% else %}
<p>
<form action="{{ action }}" method="post" class="left-space">
<input type="hidden" id="service" value="{{service|default('haproxy', true)}}" />
{{ 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' %}
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.show|title()}} {{lang.words.running}} {{lang.words.config}}" onclick="showConfigFiles()">{{lang.words.open|title()}}</a>
{% else %}
@ -47,10 +47,10 @@
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.show|title()}} {{lang.words.map}}" onclick="showMap()">{{lang.words.map|title()}}</a>
{% endif %}
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.compare|title()}} {{lang.words.configs}}" onclick="showCompareConfigs()">{{lang.words.compare|title()}}</a>
{% if user_params['role'] <= 3 %}
{% if g.user_params['role'] <= 3 %}
<a class="ui-button ui-widget ui-corner-all" title="{{lang.words.show|title()}} {{lang.words.versions}}" onclick="openVersions()">{{lang.menu_links.versions.link}}</a>
{% endif %}
{% if user_params['role'] <= 2 %}
{% if g.user_params['role'] <= 2 %}
<a href="/app/servers#backup" class="ui-button ui-widget ui-corner-all" title="Git">Git</a>
{% endif %}
</form>
@ -63,7 +63,7 @@
{% endif %}
{% if config %}
{% if user_params['role'] <= 3 %}
{% if g.user_params['role'] <= 3 %}
<h4 class="left-space">{{lang.words.config|title()}} {% if config_file_name and config_file_name != 'undefined' %}{{config_file_name.replace('92', '/')}}{%endif%} {{lang.words.from}} {{ serv }}</h4>
<form action="/app/config/{{service}}/{{serv}}/save" name="saveconfig" id="saveconfig" method="post" class="left-space">
<input type="hidden" value="{{ serv }}" name="serv">

View File

@ -5,7 +5,7 @@
<p>
<form action="/app/config/versions/{{service}}/{{serv}}" method="post" class="left-space">
<input type="hidden" id="service" value="{{service}}">
{{ select('serv', values=user_params['servers'], is_servers='true', selected=serv) }}
{{ select('serv', values=g.user_params['servers'], is_servers='true', selected=serv) }}
<button type="submit" value="open" name="open" class="btn btn-default">{{lang.words.open|title()}}</button>
</form>
</p>

View File

@ -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 %}
<link href="/inc/css/table-6.3.9.css" rel="stylesheet" type="text/css">
<link href="{{ url_for('static', filename='css/table-6.3.9.css') }}" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<p>
<form action="{{ action }}" method="post" class="left-space">
<input type="hidden" value="{{service}}" name="service" id="service">
{{ select('serv', values=user_params['servers'], is_servers='true', selected=serv) }}
{{ select('serv', values=g.user_params['servers'], is_servers='true', selected=serv) }}
<a class="ui-button ui-widget ui-corner-all" title="Open versions" onclick="showListOfVersion(1)">{{lang.words.open|title()}}</a>
<a href="/app/config/{{service}}" class="ui-button ui-widget ui-corner-all" title="Configs page">{{lang.words.configs|title()}}</a>
{% if service != 'keepalived' %}
@ -37,7 +37,7 @@
</div>
{% endif %}
{% if serv and not aftersave %}
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
{% if select.2 == serv %}
<script>showListOfVersion(1)</script>
{% endif %}

View File

@ -6,9 +6,9 @@
<script src="/inc/users.js"></script>
<script src="/inc/ha.js"></script>
<script src="/inc/overview.js"></script>
<link href="/inc/css/servers.css" rel="stylesheet"/>
<link href="/inc/css/smon.css" rel="stylesheet">
<link href="/inc/css/ha.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/servers.css') }}" rel="stylesheet"/>
<link href="{{ url_for('static', filename='css/smon.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/ha.css') }}" rel="stylesheet">
{% 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 @@
</h4>
</div>
{% else %}
{% if user_params['role'] <= 2 %}
{% if g.user_params['role'] <= 3 %}
<div class="add-button add-button-big" title="{{lang.phrases.create_ha}}" onclick="createHaClusterStep1();">+ {{lang.ha_page.create_ha}}</div>
{% endif %}
<div class="up-pannel" class="sortable">

View File

@ -6,7 +6,7 @@
{% if user_subscription['user_status'] == 0 or user_subscription['user_plan'] == 'user' %}
{% include 'include/no_sub.html' %}
{% else %}
<link href="/inc/css/table-6.3.9.css" rel="stylesheet" type="text/css">
<link href="{{ url_for('static', filename='css/table-6.3.9.css') }}" rel="stylesheet" type="text/css">
<link href="/inc/dataTables/buttons.dataTables.min.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<script type="text/javascript" charset="utf8" src="/inc/dataTables/dataTables.buttons.min.js"></script>

View File

@ -40,13 +40,13 @@
{{set.param}}
</td>
<td class="addOption">
{% 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',

View File

@ -61,15 +61,16 @@
<br /><span class="add-button" title="{{lang.words.add|title()}} SSH" id="add-ssh-button">+ {{lang.words.add|title()}}</span>
<br /><br />
<table id="ssh_key">
<tr class="overviewHead" style="width: 50%;">
<td class="padding10 first-collumn" style="width: 25%;">{{lang.words.upload|title()}} SSH {{lang.words.key}}</td>
<tr class="overviewHead">
<td class="padding10 first-collumn">{{lang.words.upload|title()}} SSH {{lang.words.key}}</td>
<td style="width: 25%;">{{lang.phrases.ssh_passphrase}}</td>
<td class="help_cursor">
<span title="{{lang.phrases.private_key_note}}">{{lang.words.key|title()}}</span>
</td>
<td></td>
</tr>
<tr style="width: 50%;">
<td class="first-collumn padding10" valign="top" style="padding-top: 15px;">
<tr>
<td class="first-collumn padding10" style="padding-top: 15px;">
<select id="ssh-key-name">
<option disabled selected>------</option>
{% for ssh in sshs %}
@ -77,6 +78,7 @@
{% endfor %}
</select>
</td>
<td>{{ input('ssh-key-pass', title=lang.phrases.ssh_passphrase, type='password') }}</td>
<td style="padding-top: 15px;">
<textarea id="ssh_cert" cols="50" rows="5"></textarea><br /><br />
<a class="ui-button ui-widget ui-corner-all" id="ssh_key_upload" title="{{lang.words.upload|title()}} SSH {{lang.words.key}}" onclick="uploadSsh()">{{lang.words.upload|title()}}</a>

View File

@ -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",

View File

@ -1,5 +1,5 @@
{% if user_params['user'] %}
<span id="show-user-settings-button" class="user-circle login" title="{{lang.words.user3|title()}} {{lang.words.settings}}" style="margin-top: 5px;">{{user_params['user']}}</span>
{% if g.user_params['user'] %}
<span id="show-user-settings-button" class="user-circle login" title="{{lang.words.user3|title()}} {{lang.words.settings}}" style="margin-top: 5px;">{{g.user_params['user']}}</span>
{% else %}
<a href=/app/login title="Login" class="login"> Login</a>
{% endif %}

View File

@ -0,0 +1,48 @@
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
{% if title == 'Login page' %}
<meta name="viewport" content="width=device-width, user-scalable=1">
{% endif %}
<link rel="icon" type="image/png" href="{{ url_for('static', filename='images/favicon/favicon.ico') }}" />
<link rel="apple-touch-icon" sizes="57x57" href="{{ url_for('static', filename='images/favicon/apple-icon-57x57.png') }}">
<link rel="apple-touch-icon" sizes="60x60" href="{{ url_for('static', filename='images/favicon/apple-icon-60x60.png') }}">
<link rel="apple-touch-icon" sizes="72x72" href="{{ url_for('static', filename='images/favicon/apple-icon-72x72.png') }}">
<link rel="apple-touch-icon" sizes="76x76" href="{{ url_for('static', filename='images/favicon/apple-icon-76x76.png') }}">
<link rel="apple-touch-icon" sizes="114x114" href="{{ url_for('static', filename='images/favicon/apple-icon-114x114.png') }}">
<link rel="apple-touch-icon" sizes="120x120" href="{{ url_for('static', filename='images/favicon/apple-icon-120x120.png') }}">
<link rel="apple-touch-icon" sizes="144x144" href="{{ url_for('static', filename='images/favicon/apple-icon-144x144.png') }}">
<link rel="apple-touch-icon" sizes="152x152" href="{{ url_for('static', filename='images/favicon/apple-icon-152x152.png') }}">
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='images/favicon/apple-icon-180x180.png') }}">
<link rel="icon" type="image/png" sizes="192x192" href="{{ url_for('static', filename='images/favicon/android-icon-192x192.png') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='images/favicon/favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="96x96" href="{{ url_for('static', filename='images/favicon/favicon-96x96.png') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ url_for('static', filename='images/favicon/favicon-16x16.png') }}">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="{{ url_for('static', filename='images/favicon/ms-icon-144x144.png') }}">
<meta name="theme-color" content="#ffffff">
<script defer src="/inc/fa-solid.min.js"></script>
<script defer src="/inc/fontawesome.min.js"></script>
<script src="https://use.fontawesome.com/releases/v5.15.4/js/all.js" data-auto-replace-svg="nest"></script>
<script>FontAwesomeConfig = { searchPseudoElements: true, observeMutations: false };</script>
<script defer src="/inc/ion.sound.min.js"></script>
<script defer src="/inc/intro/introjs.min.js"></script>
<link href="/inc/intro/introjs.min.css" rel="stylesheet">
<link href="/inc/intro/introjs-modern.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/awesome-6.3.9.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/style-6.3.9.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/nprogress.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/jquery-ui.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/jquery-ui.structure.min.css') }}" rel="stylesheet">
<script src="/inc/jquery-3.6.0.min.js"></script>
<script src="/inc/jquery-ui.min.js"></script>
<script src="/inc/js.cookie.min.js"></script>
<script src="/inc/reconnecting-websocket.js"></script>
<script src="/inc/hotkeys.js"></script>
<link href="{{ url_for('static', filename='css/select2.css') }}" rel="stylesheet" />
<script src="/inc/select2.js"></script>
<script src="/inc/script.js"></script>
<script src="/inc/nprogress.js"></script>
<link href="{{ url_for('static', filename='css/toastr-6.3.9.css') }}" rel="stylesheet"/>
<script src="/inc/toastr.js"></script>

View File

@ -10,12 +10,12 @@
<nav id="menu">
<ul class="menu">
<li><a href="{{ url_for('overview.index') }}" title="{{lang.menu_links.overview.title}}" class="overview-link ">{{lang.menu_links.overview.link}}</a></li>
{% if '5' in user_params['user_services'] %}
{% if user_params['role'] <= 3 %}
{% if '5' in g.user_params['user_services'] %}
{% if g.user_params['role'] <= 3 %}
{% endif %}
<li><a href="{{ url_for('ha.cluster_function', service='cluster') }}" title="{{lang.menu_links.ha.title}}" class="keepalived">HA {{lang.words.cluster}}</a></li>
{% endif %}
{% if '1' in user_params['user_services'] %}
{% if '1' in g.user_params['user_services'] %}
<li class="p_menu">
<a href="{{ url_for('service.services', service='haproxy') }}" title="{{lang.menu_links.hapservers.haproxy.title}}" class="config-show">HAProxy</a>
<ul class="v_menu">
@ -25,7 +25,7 @@
<li><a href="{{ url_for('logs.logs', service='haproxy') }}" title="HAProxy {{lang.menu_links.logs.title}}" class="logs head-submenu">{{lang.menu_links.logs.link}}</a></li>
<li><a href="{{ url_for('runtime.runtimeapi') }}" title="Runtime API" class="runtime head-submenu">Runtime API</a></li>
<li><a href="{{ url_for('metric.metrics', service='haproxy') }}" title="HAProxy {{lang.menu_links.metrics.title}}" class="metrics head-submenu">{{lang.menu_links.metrics.link}}</a></li>
{% if user_params['role'] <= 3 %}
{% if g.user_params['role'] <= 3 %}
<li><a href="{{ url_for('add.add', service='haproxy') }}#proxy" title="{{lang.menu_links.add_proxy.title}}" class="add-proxy head-submenu" id="add1">{{lang.menu_links.add_proxy.link}}</a></li>
<li><a href="{{ url_for('config.versions', service='haproxy') }}" title="{{lang.menu_links.versions.haproxy.title}}" class="version head-submenu">{{lang.menu_links.versions.link}}</a></li>
<li><a href="{{ url_for('add.add', service='haproxy') }}#ssl" title="{{lang.menu_links.ssl.title}}" class="cert head-submenu" id="add3">{{lang.menu_links.ssl.link}}</a></li>
@ -35,7 +35,7 @@
</ul>
</li>
{% endif %}
{% if '2' in user_params['user_services'] %}
{% if '2' in g.user_params['user_services'] %}
<li class="p_menu">
<a href="{{ url_for('service.services', service='nginx') }}" title="{{lang.menu_links.hapservers.nginx.title}}" class="nginx-menu">NGINX</a>
<ul class="v_menu">
@ -44,7 +44,7 @@
<li><a href="{{ url_for('main.stats', service='nginx') }}" title="{{lang.menu_links.stats.nginx.title}}" class="stats head-submenu">{{lang.menu_links.stats.link}}</a></li>
<li><a href="{{ url_for('logs.logs', service='nginx') }}" title="NGINX {{lang.menu_links.logs.title}}" class="logs head-submenu">{{lang.menu_links.logs.link}}</a></li>
<li><a href="{{ url_for('metric.metrics', service='nginx') }}" title="NGINX {{lang.menu_links.metrics.title}}" class="metrics head-submenu">{{lang.menu_links.metrics.link}}</a></li>
{% if user_params['role'] <= 3 %}
{% if g.user_params['role'] <= 3 %}
<li><a href="{{ url_for('add.add', service='nginx') }}#proxy" title="{{lang.menu_links.add_proxy.title}}" class="add-proxy head-submenu">{{lang.menu_links.add_proxy.link}}</a></li>
<li><a href="{{ url_for('config.versions', service='nginx') }}" title="{{lang.menu_links.versions.nginx.title}}" class="version head-submenu">{{lang.menu_links.versions.link}}</a></li>
<li><a href="{{ url_for('add.add', service='haproxy') }}?service=nginx#ssl" title="{{lang.menu_links.ssl.title}}" class="cert head-submenu">{{lang.menu_links.ssl.link}}</a></li>
@ -53,7 +53,7 @@
</ul>
</li>
{% endif %}
{% if '4' in user_params['user_services'] %}
{% if '4' in g.user_params['user_services'] %}
<li class="p_menu">
<a href="{{ url_for('service.services', service='apache') }}" title="{{lang.menu_links.hapservers.apache.title}}" class="apache-menu">Apache</a>
<ul class="v_menu">
@ -62,15 +62,15 @@
<li><a href="{{ url_for('main.stats', service='apache') }}" title="{{lang.menu_links.stats.apache.title}}" class="stats head-submenu">{{lang.menu_links.stats.link}}</a></li>
<li><a href="{{ url_for('logs.logs', service='apache') }}" title="Apache {{lang.menu_links.logs.title}}" class="logs head-submenu">{{lang.menu_links.logs.link}}</a></li>
<li><a href="{{ url_for('metric.metrics', service='apache') }}" title="Apache {{lang.menu_links.metrics.title}}" class="metrics head-submenu">{{lang.menu_links.metrics.link}}</a></li>
{% if user_params['role'] <= 3 %}
{% if g.user_params['role'] <= 3 %}
<li><a href="{{ url_for('config.versions', service='apache') }}" title="{{lang.menu_links.versions.apache.title}}" class="version head-submenu">{{lang.menu_links.versions.link}}</a></li>
<li><a href="{{ url_for('add.add', service='haproxy') }}?service=apache#ssl" title="{{lang.menu_links.ssl.title}}" class="cert head-submenu" id="add3">{{lang.menu_links.ssl.link}}</a></li>
{% endif %}
</ul>
</li>
{% endif %}
{% if '3' in user_params['user_services'] %}
{% if user_params['role'] <= 2 %}
{% if '3' in g.user_params['user_services'] %}
{% if g.user_params['role'] <= 2 %}
<li class="p_menu">
<a href="{{ url_for('service.services', service='keepalived') }}" title="{{lang.menu_links.hapservers.keepalived.title}}" class="ha">Keepalived</a>
<ul class="v_menu">
@ -88,7 +88,7 @@
<li><a href="{{ url_for('smon.smon') }}" title="{{lang.menu_links.monitoring.smon.dashboard}}" class="overview-link head-submenu">{{lang.menu_links.monitoring.smon.dashboard}}</a></li>
<li><a href="{{ url_for('smon.status_page') }}" title="{{lang.menu_links.monitoring.smon.status_page}}" class="overview-link head-submenu">{{lang.menu_links.monitoring.smon.status_page}}</a></li>
<li><a href="{{ url_for('smon.smon_history') }}" title="{{lang.menu_links.monitoring.smon.history}}" class="lists head-submenu">{{lang.menu_links.monitoring.smon.history}}</a></li>
{% if user_params['role'] <= 3 %}
{% if g.user_params['role'] <= 3 %}
<li><a href="{{ url_for('smon.smon_admin') }}" title="{{lang.menu_links.monitoring.smon.admin}}" class="edit head-submenu">{{lang.menu_links.monitoring.smon.admin}}</a></li>
<li><a href="{{ url_for('checker.checker_settings') }}" title="Checker: {{lang.words.settings}}" class="checker head-submenu">Checker: {{lang.words.settings|title()}}</a></li>
{% endif %}
@ -97,7 +97,7 @@
<li><a href="{{ url_for('main.nettools') }}" title="{{lang.menu_links.monitoring.net_tools}}" class="net-tools head-submenu">{{lang.menu_links.monitoring.net_tools}}</a></li>
</ul>
</li>
{% if user_params['role'] <= 2 %}
{% if g.user_params['role'] <= 2 %}
<li class="p_menu">
<a href="{{ url_for('install.install_monitoring') }}" title="{{lang.menu_links.servers.title}}" class="hap-menu">{{lang.words.installation|title()}}</a>
<ul class="v_menu">
@ -118,7 +118,7 @@
</ul>
</li>
{% endif %}
{% if user_params['role'] <= 1 %}
{% if g.user_params['role'] <= 1 %}
<li class="p_menu" id="admin-area">
<a href="{{ url_for('admin.admin') }}#users" title="{{lang.menu_links.admin_area.title}}" class="admin">{{lang.menu_links.admin_area.link}}</a>
<ul class="v_menu">

View File

@ -2,7 +2,7 @@
{% block title %}{{ lang.p_s_page.p_s_title_history }}{% endblock %}
{% block h2 %}{{ lang.p_s_page.p_s_title_history }}{% endblock %}
{% block content %}
<link href="/inc/css/table-6.3.9.css" rel="stylesheet" type="text/css">
<link href="{{ url_for('static', filename='css/table-6.3.9.css') }}" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<style>
@media (max-width: 1280px) {

View File

@ -1,6 +0,0 @@
<div class="group_error">
<div class="alert alert-danger">
<b>Do not edit this section if your group is "ALL"!</b> Add first <a href="users.py#groups" title="Admin Area: Groups">group</a>
or change your current group at <a href="users.py#users" title="Admin Area: Users">users</a> page
</div>
</div>

View File

@ -7,8 +7,8 @@
{% if user_subscription['user_status'] == 0 or user_subscription['user_plan'] == 'user' %}
{% include 'include/no_sub.html' %}
{% else %}
<link href="/inc/css/chart.min.css" rel="stylesheet">
<link href="/inc/css/smon.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/chart.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/smon.css') }}" rel="stylesheet">
<script src="/inc/chart.min-4.3.0.js"></script>
<script src="/inc/metrics.js"></script>
<script src="/inc/smon.js"></script>

View File

@ -45,7 +45,7 @@
<td class="padding10 first-collumn">
<select autofocus required name="haproxyaddserv" id="haproxyaddserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
@ -80,7 +80,7 @@
<td class="padding10 first-collumn">
<select autofocus required name="nginxaddserv" id="nginxaddserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
@ -115,7 +115,7 @@
<td class="padding10 first-collumn">
<select autofocus required name="apacheaddserv" id="apacheaddserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
@ -145,7 +145,7 @@
</h4>
</div>
{% else %}
{% if user_params['role']|int() == 1 %}
{% if g.user_params['role']|int() == 1 %}
<table id="grafana-table">
<caption><i class="fas fa-chart-bar caption-icon2"></i><h3>Grafana {{lang.words.and}} Prometheus {{lang.words.servers}}</h3></caption>
<tr class="overviewHead">
@ -193,12 +193,12 @@
<td class="padding10 first-collumn" style="width: 20%;">
{% set values = dict() %}
{% set values = {'0.9.0':'0.9.0', '0.10.0':'0.10.0', '0.11.0':'0.11.0', '0.12.0':'0.12.0', '0.13.0':'0.13.0', '0.14.0':'0.14.0', '0.15.0':'0.15.0'} %}
{{ select('hapexpver', values=values, selected='0.15.0') }}
{{ select('haproxyexpver', values=values, selected='0.15.0') }}
</td>
<td class="padding10 first-collumn">
<select autofocus required name="haproxy_exp_addserv" id="haproxy_exp_addserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
@ -229,7 +229,7 @@
<td class="padding10 first-collumn">
<select autofocus required name="nginx_exp_addserv" id="nginx_exp_addserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
@ -260,7 +260,7 @@
<td class="padding10 first-collumn">
<select autofocus required name="apache_exp_addserv" id="apache_exp_addserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
@ -291,7 +291,7 @@
<td class="padding10 first-collumn">
<select autofocus required name="keepalived_exp_addserv" id="keepalived_exp_addserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
@ -322,7 +322,7 @@
<td class="padding10 first-collumn">
<select autofocus required name="node_exp_addserv" id="node_exp_addserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>
@ -363,7 +363,7 @@
<td class="padding10 first-collumn">
<select autofocus required name="geoipserv" id="geoipserv">
<option disabled selected>------</option>
{% for select in user_params['servers'] %}
{% for select in g.user_params['servers'] %}
<option value="{{ select.2 }}">{{ select.1 }}</option>
{% endfor %}
</select>

View File

@ -202,10 +202,10 @@
},
"haproxy": {
"haproxy_path_logs": "The path for HAProxy logs",
"stats_user": "Username for accessing HAProxy stats page",
"stats_password": "Password for Stats web page HAProxy",
"stats_port": "Stats port for web page HAProxy",
"stats_page": "URI Stats for web page HAProxy",
"haproxy_stats_user": "Username for accessing HAProxy stats page",
"haproxy_stats_password": "Password for Stats web page HAProxy",
"haproxy_stats_port": "Stats port for web page HAProxy",
"haproxy_stats_page": "URI Stats for web page HAProxy",
"haproxy_dir": "Path to the HAProxy directory with config files",
"haproxy_config_path": "Path to the main HAProxy configuration file",
"server_state_file": "Path to the HAProxy state file",
@ -322,6 +322,7 @@
"add_to_smon_desc": "Add the server for checking by SMON ping",
"create_page_status": "Create status page",
"not_in_cluster": "Not in a cluster",
"ssh_passphrase": "SSH key passphrase",
}
%}
{% set roles = {

View File

@ -202,10 +202,10 @@
},
"haproxy": {
"haproxy_path_logs": "Chemin pour les logs HAProxy",
"stats_user": "Nom d\'utilisateur pour accéder aux Stats HAProxy",
"stats_password": "Mot de passe pour la page web des Stats HAProxy",
"stats_port": "Port pour la page web des Stats HAProxy",
"stats_page": "URI Stats pour la page web HAProxy",
"haproxy_stats_user": "Nom d\'utilisateur pour accéder aux Stats HAProxy",
"haproxy_stats_password": "Mot de passe pour la page web des Stats HAProxy",
"haproxy_stats_port": "Port pour la page web des Stats HAProxy",
"haproxy_stats_page": "URI Stats pour la page web HAProxy",
"haproxy_dir": "Chemin vers le dossier HAProxy contenant les fichiers de config",
"haproxy_config_path": "Chemin vers le fichier de configuration principal de HAProxy",
"server_state_file": "Chemin vers le fichier d\'état HAProxy",
@ -322,6 +322,7 @@
"add_to_smon_desc": "Ajouter le serveur pour vérification par SMON ping",
"create_page_status": "Créer une page de statut",
"not_in_cluster": "Pas dans un cluster",
"ssh_passphrase": "Phrase secrète de la clé SSH",
}
%}
{% set roles = {

View File

@ -202,10 +202,10 @@
},
"haproxy": {
"haproxy_path_logs": "Caminho para os logs de HAProxy",
"stats_user": "Nome de usuario para acesar a pagina de estatística de HAProxy",
"stats_password": "Senha para acesar a pagina de estatística de HAProxy",
"stats_port": "Porta de estatísticas para pagina HAProxy",
"stats_page": "Estatística dos URIs para pagina HAProxy",
"haproxy_stats_user": "Nome de usuario para acesar a pagina de estatística de HAProxy",
"haproxy_stats_password": "Senha para acesar a pagina de estatística de HAProxy",
"haproxy_stats_port": "Porta de estatísticas para pagina HAProxy",
"haproxy_stats_page": "Estatística dos URIs para pagina HAProxy",
"haproxy_dir": "Caminho para arquivos de configuração de NGINX",
"haproxy_config_path": "Caminho para o arquivo principal de configuração de HAProxy",
"server_state_file": "Caminho para o arquivo do estado de HAProxy",
@ -322,6 +322,7 @@
"add_to_smon_desc": "Adicione o servidor para verificação por ping SMON",
"create_page_status": "Criar página de status",
"not_in_cluster": "Não em um cluster",
"ssh_passphrase": "Senha da chave SSH",
}
%}
{% set roles = {

View File

@ -202,10 +202,10 @@
},
"haproxy": {
"haproxy_path_logs": "Путь до логов HAProxy",
"stats_user": "Пользователь для входа на страницу статистики HAProxy",
"stats_password": "Пароль для входа на страницу статистики HAProxy",
"stats_port": "Порт для доступа на страницу статистики HAProxy",
"stats_page": "URI для доступа на страницу статистики HAProxy",
"haproxy_stats_user": "Пользователь для входа на страницу статистики HAProxy",
"haproxy_stats_password": "Пароль для входа на страницу статистики HAProxy",
"haproxy_stats_port": "Порт для доступа на страницу статистики HAProxy",
"haproxy_stats_page": "URI для доступа на страницу статистики HAProxy",
"haproxy_dir": "Путь до папки конфигурации HAProxy",
"haproxy_config_path": "Путь для основного файла конфигурации HAProxy",
"server_state_file": "Путь до стейт файла HAProxy",
@ -322,6 +322,7 @@
"add_to_smon_desc": "Добавить сервер для проверки с помощью SMON ping",
"create_page_status": "Создать страницу статуса",
"not_in_cluster": "Не в кластере",
"ssh_passphrase": "Ключевая фраза SSH",
}
%}
{% set roles = {

View File

@ -1,6 +1,10 @@
{% extends "base.html" %}
{% block content %}
{% from 'include/input_macros.html' import input %}
<html lang="{{lang|default('en')}}">
{% import 'languages/'+lang|default('en')+'.html' as lang %}
<head>
{% include 'include/main_head.html' %}
</head>
<body>
<style>
body, .container {
background-color: #fff;
@ -93,4 +97,5 @@ body, .container {
<br /><br />
</div>
</div>
{% endblock %}
</body>
</html>

View File

@ -15,7 +15,7 @@
padding: 10px;
}
</style>
<link href="/inc/css/chart.min.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/chart.min.css') }}" rel="stylesheet">
<script src="/inc/metrics.js"></script>
<script src="/inc/chart.min-4.3.0.js"></script>
<input type="hidden" id="service" value="{{service}}">

View File

@ -18,7 +18,7 @@
<select autofocus required name="server_from" id="nettools_icmp_server_from">
<option disabled selected>------</option>
<option value="localhost">Roxy-WI</option>
{% for server in user_params['servers'] %}
{% for server in g.user_params['servers'] %}
<option value="{{ server.2 }}">{{ server.1 }}</option>
{% endfor %}
</select>
@ -50,7 +50,7 @@
<select autofocus required name="server_from" id="nettools_telnet_server_from">
<option disabled selected>------</option>
<option value="localhost">Roxy-WI</option>
{% for server in user_params['servers'] %}
{% for server in g.user_params['servers'] %}
<option value="{{ server.2 }}">{{ server.1 }}</option>
{% endfor %}
</select>
@ -82,7 +82,7 @@
<select autofocus required name="server_from" id="nettools_nslookup_server_from">
<option disabled selected>------</option>
<option value="localhost">Roxy-WI</option>
{% for server in user_params['servers'] %}
{% for server in g.user_params['servers'] %}
<option value="{{ server.2 }}">{{ server.1 }}</option>
{% endfor %}
</select>

View File

@ -2,7 +2,7 @@
{% block title %}{{lang.menu_links.overview.title}}{% endblock %}
{% block h2 %}{{lang.menu_links.overview.h2}}{% endblock %}
{% block content %}
<link href="/inc/css/chart.min.css" rel="stylesheet">
<link href="{{ url_for('static', filename='css/chart.min.css') }}" rel="stylesheet">
<script src="/inc/metrics.js"></script>
<script src="/inc/chart.min-4.3.0.js"></script>
<script src="/inc/overview.js"></script>
@ -10,7 +10,7 @@
$("#secIntervals").css("display", "none");
var ip = []
var hostnamea = []
{% for s in user_params['servers'] %}
{% for s in g.user_params['servers'] %}
ip.push("{{s[2]}}")
var host = "{{s[2]}}"
host = host.replace(/\./g, '\\.');
@ -24,7 +24,7 @@
<table class="overview-wi" id="overview-roxy-wi">
<tr class="overviewHead">
<td class="padding10 first-collumn-wi">
{% if user_params['role'] <= 2 %}
{% if g.user_params['role'] <= 2 %}
<a href="servers#servers" title="{{lang.words.manage|title()}} {{lang.words.servers}}">{{lang.words.servers|title()}}</a>
{% else %}
{{lang.words.servers|title()}}
@ -61,14 +61,14 @@
</a>
</td>
</tr>
{% for s in user_params['servers'] %}
{% for s in g.user_params['servers'] %}
<tr class="{{ loop.cycle('odd', 'even') }}" id="{{s[2]}}"></tr>
{% endfor %}
</table>
<table class="overview-wi" id="overview-load">
<tr class="overviewHead" style="height: 30px;">
<td class="padding10 first-collumn-wi" colspan="2">
{% if user_params['role'] <= 1 %}
{% if g.user_params['role'] <= 1 %}
<a href="/app/logs/internal" title="{{lang.words.view|title()}} Roxy-WI {{lang.words.logs}}" class="logs_link">
Roxy-WI {{lang.words.server_status}}
</a>
@ -97,7 +97,7 @@
<thead>
<tr class="overviewHead">
<td class="padding10 first-collumn-wi" colspan=2>
{% if user_params['role'] <= 1 %}
{% if g.user_params['role'] <= 1 %}
<a href="admin#tools" title="{{lang.words.view|title()}} {{lang.words.services}} {{lang.words.status}}" class="logs_link">
Roxy-WI {{lang.words.services_status}}
</a>
@ -114,10 +114,10 @@
</thead>
<tbody id="services_ovw"></tbody>
</table>
{% if user_params['role'] <= 2 %}
{% if user_params['role'] == 2 %}
{% if g.user_params['role'] <= 2 %}
{% if g.user_params['role'] == 2 %}
{% set admin_uri = 'servers' %}
{% elif user_params['role'] == 1 %}
{% elif g.user_params['role'] == 1 %}
{% set admin_uri = 'admin' %}
{% endif %}
<table class="overview-wi" id="overview-users">
@ -148,7 +148,7 @@
<tbody id="users-table"></tbody>
</table>
{% endif %}
{% if user_params['role'] <= 1 %}
{% if g.user_params['role'] <= 1 %}
<table class="overview-wi" id="overview-groups">
<tr class="overviewHead">
<td class="padding10 first-collumn-wi">
@ -204,11 +204,11 @@
{% endfor %}
</table>
{% endif %}
{% if user_params['role'] <= 2 %}
{% if g.user_params['role'] <= 2 %}
<script>ShowOverviewLogs();</script>
<table class="overview-wi" id="overview-logs"></table>
{% endif %}
{% if user_params['role'] <= 1 %}
{% if g.user_params['role'] <= 1 %}
<table class="overview-wi" id="overview-subs">
<tr class="overviewHead" style="height: 30px;">
<td class="padding10 first-collumn-wi" colspan="2">

View File

@ -29,10 +29,10 @@
</div>
{% else %}
<div id="up-pannel">
{% if user_params['servers']|length == 0 %}
{% if g.user_params['servers']|length == 0 %}
{% include 'include/getstarted.html' %}
{% endif %}
{% for s in user_params['servers'] %}
{% for s in g.user_params['servers'] %}
<div id="div-server-{{s.0}}" class="div-server-hapwi
{%- if port_scanner == 'active' %}
div-server-head-up
@ -64,7 +64,7 @@
{% else %}
{{s.1}}
{% endif %}
{% if user_params['role'] <= 2 %}
{% if g.user_params['role'] <= 2 %}
<span class="server-action"></span>
{% endif %}
</div>
@ -93,7 +93,7 @@
<br />
</div>
<div class="server-act-links" id="server-{{s.0}}">
{% if user_params['role'] <= 2 %}
{% if g.user_params['role'] <= 2 %}
{% set portscanner_enable_id = 'portscanner_enable-' + s.0|string() %}
{% set portscanner_notify_id = 'portscanner_notify-' + s.0|string() %}
{% set portscanner_history_id = 'portscanner_history-' + s.0|string() %}

Some files were not shown because too many files have changed in this diff Show More