diff --git a/app/create_db.py b/app/create_db.py index 9e341f38..70a53941 100644 --- a/app/create_db.py +++ b/app/create_db.py @@ -966,7 +966,7 @@ def update_db_v_6_2_1(): def update_ver(): try: - Version.update(version='6.3.0.0').execute() + Version.update(version='6.3.1.0').execute() except Exception: print('Cannot update version') diff --git a/app/ha.py b/app/ha.py index 6c290e2b..d9a92a76 100644 --- a/app/ha.py +++ b/app/ha.py @@ -24,6 +24,7 @@ except Exception as e: sys.exit() roxywi_auth.page_for_admin(level=2) +is_needed_tool = common.is_tool('ansible') try: user_subscription = roxywi_common.return_user_status() @@ -34,6 +35,6 @@ except Exception as e: parsed_template = template.render( h2=1, title=title, role=user_params['role'], user=user_params['user'], serv=serv, selects=user_params['servers'], user_services=user_params['user_services'], user_status=user_subscription['user_status'], - user_plan=user_subscription['user_plan'], token=user_params['token'] + user_plan=user_subscription['user_plan'], is_needed_tool=is_needed_tool, token=user_params['token'] ) print(parsed_template) diff --git a/app/modules/common/common.py b/app/modules/common/common.py index c475f8c1..d60154b9 100644 --- a/app/modules/common/common.py +++ b/app/modules/common/common.py @@ -62,3 +62,10 @@ def string_to_dict(dict_string) -> dict: def get_key(item): return item[0] + + +def is_tool(name): + from shutil import which + is_tool_installed = which(name) + + return True if is_tool_installed is not None else False diff --git a/app/modules/config/config.py b/app/modules/config/config.py index 6713170d..571b24eb 100644 --- a/app/modules/config/config.py +++ b/app/modules/config/config.py @@ -3,11 +3,13 @@ import re import http.cookies 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.roxy_wi_tools as roxy_wi_tools from modules.service.common import is_not_allowed_to_restart, get_correct_apache_service_name +form = common.form time_zone = sql.get_setting('time_zone') get_date = roxy_wi_tools.GetDate(time_zone) get_config_var = roxy_wi_tools.GetConfigVar() @@ -372,3 +374,74 @@ def get_userlists(config): return_config += line + ',' return return_config + + +def get_ssl_cert(server_ip: str) -> None: + cert_id = common.checkAjaxInput(form.getvalue('getcert')) + + cert_path = sql.get_setting('cert_path') + commands = [f"openssl x509 -in {cert_path}/{cert_id} -text"] + try: + server_mod.ssh_command(server_ip, commands, ip="1") + except Exception as e: + print(f'error: Cannot connect to the server {e.args[0]}') + + +def get_ssl_certs(server_ip: str) -> None: + cert_path = sql.get_setting('cert_path') + commands = [f"sudo ls -1t {cert_path} |grep -E 'pem|crt|key'"] + try: + server_mod.ssh_command(server_ip, commands, ip="1") + except Exception as e: + print(f'error: Cannot connect to the server: {e.args[0]}') + + +def del_ssl_cert(server_ip: str) -> None: + cert_id = form.getvalue('delcert') + cert_id = common.checkAjaxInput(cert_id) + cert_path = sql.get_setting('cert_path') + commands = [f"sudo rm -f {cert_path}/{cert_id}"] + try: + server_mod.ssh_command(server_ip, commands, ip="1") + except Exception as e: + print(f'error: Cannot delete the certificate {e.args[0]}') + + +def upload_ssl_cert(server_ip: str) -> None: + cert_local_dir = f"{os.path.dirname(os.getcwd())}/{sql.get_setting('ssl_local_path')}" + cert_path = sql.get_setting('cert_path') + name = '' + + if not os.path.exists(cert_local_dir): + os.makedirs(cert_local_dir) + + if form.getvalue('ssl_name') is None: + print('error: Please enter a desired name') + else: + name = f"{common.checkAjaxInput(form.getvalue('ssl_name'))}.pem" + + try: + with open(name, "w") as ssl_cert: + ssl_cert.write(form.getvalue('ssl_cert')) + except IOError as e: + print(f'error: Cannot save the SSL key file: {e.args[0]}') + sys.exit() + + masters = sql.is_master(server_ip) + for master in masters: + if master[0] is not None: + error = upload(master[0], cert_path, name) + if not error: + print(f'success: the SSL file has been uploaded to {master[0]} into: {cert_path}/{name}
') + try: + error = upload(server_ip, cert_path, name) + if not error: + print(f'success: the SSL file has been uploaded to {server_ip} into: {cert_path}/{name}') + except Exception as e: + roxywi_common.logging('Roxy-WI server', e.args[0], roxywi=1) + try: + os.rename(name, cert_local_dir) + except OSError as e: + roxywi_common.logging('Roxy-WI server', e.args[0], roxywi=1) + + roxywi_common.logging(server_ip, f"add.py#ssl uploaded a new SSL cert {name}", roxywi=1, login=1) diff --git a/app/modules/config/runtime.py b/app/modules/config/runtime.py index 3d78a427..522895cd 100644 --- a/app/modules/config/runtime.py +++ b/app/modules/config/runtime.py @@ -218,3 +218,152 @@ def table_select(): template = template.render(tables_head=tables_head, table=table) print(template) + + +def delete_ip_from_stick_table() -> None: + haproxy_sock_port = sql.get_setting('haproxy_sock_port') + ip = common.checkAjaxInput(form.getvalue('ip_for_delete')) + table = common.checkAjaxInput(form.getvalue('table_for_delete')) + + cmd = f'echo "clear table {table} key {ip}" |nc {serv} {haproxy_sock_port}' + output, stderr = server_mod.subprocess_execute(cmd) + if stderr[0] != '': + print('error: ' + stderr[0]) + + +def clear_stick_table() -> None: + haproxy_sock_port = sql.get_setting('haproxy_sock_port') + table = common.checkAjaxInput(form.getvalue('table_for_clear')) + + cmd = f'echo "clear table {table} " |nc {serv} {haproxy_sock_port}' + output, stderr = server_mod.subprocess_execute(cmd) + if stderr[0] != '': + print('error: ' + stderr[0]) + + +def list_of_lists() -> None: + haproxy_sock_port = sql.get_setting('haproxy_sock_port') + cmd = f'echo "show acl"|nc {serv} {haproxy_sock_port} |grep "loaded from" |awk \'{{print $1,$2}}\'' + output, stderr = server_mod.subprocess_execute(cmd) + print(output) + + +def show_lists() -> None: + from jinja2 import Environment, FileSystemLoader + env = Environment(loader=FileSystemLoader('templates/'), autoescape=True, + extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do'], trim_blocks=True, lstrip_blocks=True) + template = env.get_template('ajax/list.html') + list_id = common.checkAjaxInput(form.getvalue('list_select_id')) + list_name = common.checkAjaxInput(form.getvalue('list_select_name')) + + 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) + + template = template.render(list=output, list_id=list_id, list_name=list_name) + print(template) + + +def delete_ip_from_list() -> None: + haproxy_sock_port = sql.get_setting('haproxy_sock_port') + lists_path = sql.get_setting('lists_path') + lib_path = get_config.get_config_var('main', 'lib_path') + ip_id = common.checkAjaxInput(form.getvalue('list_ip_id_for_delete')) + ip = common.is_ip_or_dns(form.getvalue('list_ip_for_delete')) + list_id = common.checkAjaxInput(form.getvalue('list_id_for_delete')) + list_name = common.checkAjaxInput(form.getvalue('list_name')) + user_group = roxywi_common.get_user_group(id=1) + cmd = f"sed -i 's!{ip}$!!' {lib_path}/{lists_path}/{user_group}/{list_name}" + cmd1 = f"sed -i '/^$/d' {lib_path}/{lists_path}/{user_group}/{list_name}" + output, stderr = server_mod.subprocess_execute(cmd) + output1, stderr1 = server_mod.subprocess_execute(cmd1) + if output: + print(f'error: {output}') + if stderr: + print(f'error: {stderr}') + if output1: + print(f'error: {output1}') + if stderr1: + print(f'error: {stderr}') + + cmd = f'echo "del acl #{list_id} #{ip_id}" |nc {serv} {haproxy_sock_port}' + output, stderr = server_mod.subprocess_execute(cmd) + if output[0] != '': + print(f'error: {output[0]}') + if stderr != '': + print(f'error: {stderr[0]}') + + roxywi_common.logging(serv, f'{ip_id} has been delete from list {list_id}', login=1, keep_history=1, + service='haproxy') + + +def add_ip_to_list() -> None: + haproxy_sock_port = sql.get_setting('haproxy_sock_port') + lists_path = sql.get_setting('lists_path') + lib_path = get_config.get_config_var('main', 'lib_path') + ip = form.getvalue('list_ip_for_add') + ip = ip.strip() + ip = common.is_ip_or_dns(ip) + list_id = common.checkAjaxInput(form.getvalue('list_id_for_add')) + list_name = common.checkAjaxInput(form.getvalue('list_name')) + user_group = roxywi_common.get_user_group(id=1) + cmd = f'echo "add acl #{list_id} {ip}" |nc {serv} {haproxy_sock_port}' + output, stderr = server_mod.subprocess_execute(cmd) + if output[0]: + print(f'error: {output[0]}') + if stderr: + print(f'error: {stderr[0]}') + + if 'is not a valid IPv4 or IPv6 address' not in output[0]: + cmd = f'echo "{ip}" >> {lib_path}/{lists_path}/{user_group}/{list_name}' + output, stderr = server_mod.subprocess_execute(cmd) + if output: + print(f'error: {output}') + if stderr: + print(f'error: {stderr}') + + roxywi_common.logging(serv, f'{ip} has been added to list {list_id}', login=1, keep_history=1, + service='haproxy') + + +def select_session() -> None: + from jinja2 import Environment, FileSystemLoader + env = Environment(loader=FileSystemLoader('templates'), autoescape=True, + extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do'], trim_blocks=True, lstrip_blocks=True) + serv = common.checkAjaxInput(form.getvalue('sessions_select')) + + haproxy_sock_port = sql.get_setting('haproxy_sock_port') + + cmd = f'echo "show sess" |nc {serv} {haproxy_sock_port}' + output, stderr = server_mod.subprocess_execute(cmd) + + template = env.get_template('ajax/sessions_table.html') + template = template.render(sessions=output) + + print(template) + + +def show_session() -> None: + serv = common.checkAjaxInput(form.getvalue('sessions_select_show')) + sess_id = common.checkAjaxInput(form.getvalue('sessions_select_id')) + haproxy_sock_port = sql.get_setting('haproxy_sock_port') + cmd = f'echo "show sess {sess_id}" |nc {serv} {haproxy_sock_port}' + + output, stderr = server_mod.subprocess_execute(cmd) + + if stderr: + print('error: ' + stderr[0]) + else: + for o in output: + print(f'{o}
') + + +def delete_session() -> None: + haproxy_sock_port = sql.get_setting('haproxy_sock_port') + sess_id = common.checkAjaxInput(form.getvalue('session_delete_id')) + cmd = 'echo "shutdown session %s" |nc %s %s' % (sess_id, serv, haproxy_sock_port) + output, stderr = server_mod.subprocess_execute(cmd) + if output[0] != '': + print('error: ' + output[0]) + if stderr[0] != '': + print('error: ' + stderr[0]) diff --git a/app/modules/roxywi/roxy.py b/app/modules/roxywi/roxy.py index 23c9ff26..56017c83 100644 --- a/app/modules/roxywi/roxy.py +++ b/app/modules/roxywi/roxy.py @@ -4,6 +4,7 @@ import re import distro 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 @@ -179,3 +180,24 @@ def check_new_version(service): roxywi_common.logging('Roxy-WI server', f' {e}', roxywi=1) return res + + +def action_service(action: str, service: str) -> None: + if action not in ('start', 'stop', 'restart'): + print('error: wrong action') + return + + is_in_docker = is_docker() + if action == 'stop': + cmd = f"sudo systemctl disable {service} --now" + elif action in ("start", "restart"): + cmd = f"sudo systemctl {action} {service} --now" + if not sql.select_user_status(): + print( + 'warning: The service is disabled because you are not subscribed. Read here about subscriptions') + sys.exit() + if is_in_docker: + cmd = f"sudo supervisorctl {action} {service}" + os.system(cmd) + roxywi_common.logging('Roxy-WI server', f' The service {service} has been {action}ed', roxywi=1, login=1) diff --git a/app/modules/roxywi/user.py b/app/modules/roxywi/user.py new file mode 100644 index 00000000..7f50ce85 --- /dev/null +++ b/app/modules/roxywi/user.py @@ -0,0 +1,96 @@ +import os + +from jinja2 import Environment, FileSystemLoader + +import modules.db.sql as sql +import modules.common.common as common +import modules.roxywi.auth as roxywi_auth +import modules.roxywi.common as roxywi_common +import modules.alerting.alerting as alerting + +form = common.form + + +def create_user(): + email = form.getvalue('newemail') + password = form.getvalue('newpassword') + role = form.getvalue('newrole') + new_user = form.getvalue('newusername') + page = form.getvalue('page') + activeuser = form.getvalue('activeuser') + group = form.getvalue('newgroupuser') + role_id = sql.get_role_id_by_name(role) + + if roxywi_common.check_user_group(): + if roxywi_auth.is_admin(level=role_id): + try: + sql.add_user(new_user, email, password, role, activeuser, group) + env = Environment(loader=FileSystemLoader('templates/'), autoescape=True) + template = env.get_template('ajax/new_user.html') + + template = template.render(users=sql.select_users(user=new_user), + groups=sql.select_groups(), + page=page, + roles=sql.select_roles(), + adding=1) + print(template) + roxywi_common.logging(f'a new user {new_user}', ' has been created ', roxywi=1, login=1) + try: + message = f"A user has been created for you on Roxy-WI portal!\n\n" \ + f"Now you can login to https://{os.environ.get('HTTP_HOST', '')}\n\n" \ + f"Your credentials are:\n" \ + f"Login: {new_user}\n" \ + f"Password: {password}" + alerting.send_email(email, 'A user has been created for you', message) + except Exception as e: + roxywi_common.logging('error: Cannot send email for a new user', e, roxywi=1, login=1) + except Exception as e: + print(f'error: Cannot create a new user: {e}') + roxywi_common.logging('error: Cannot create a new user', e, roxywi=1, login=1) + else: + print('error: dalsdm') + roxywi_common.logging(new_user, ' tried to privilege escalation', roxywi=1, login=1) + + +def delete_user(): + userdel = form.getvalue('userdel') + user = sql.select_users(id=userdel) + username = '' + for u in user: + username = u.username + if sql.delete_user(userdel): + sql.delete_user_groups(userdel) + roxywi_common.logging(username, ' has been deleted user ', roxywi=1, login=1) + print("Ok") + + +def update_user(): + email = form.getvalue('email') + role = form.getvalue('role') + new_user = form.getvalue('updateuser') + user_id = form.getvalue('id') + activeuser = form.getvalue('activeuser') + role_id = sql.get_role_id_by_name(role) + + if roxywi_common.check_user_group(): + if roxywi_auth.is_admin(level=role_id): + sql.update_user(new_user, email, role, user_id, activeuser) + roxywi_common.logging(new_user, ' has been updated user ', roxywi=1, login=1) + else: + roxywi_common.logging(new_user, ' tried to privilege escalation', roxywi=1, login=1) + + +def update_user_password(): + password = form.getvalue('updatepassowrd') + username = '' + + if form.getvalue('uuid'): + user_id = sql.get_user_id_by_uuid(form.getvalue('uuid')) + else: + user_id = form.getvalue('id') + user = sql.select_users(id=user_id) + for u in user: + username = u.username + sql.update_user_password(password, user_id) + roxywi_common.logging('user ' + username, ' has changed password ', roxywi=1, login=1) + print("Ok") diff --git a/app/modules/server/server.py b/app/modules/server/server.py index 12b9dedc..2f908781 100644 --- a/app/modules/server/server.py +++ b/app/modules/server/server.py @@ -81,7 +81,7 @@ def ssh_command(server_ip: str, commands: list, **kwargs): except Exception as e: roxywi_common.logging('Roxy-WI server', f' Something wrong with SSH connection: {e}', roxywi=1) - return str(f'error: {e}') + raise Exception(f'error: {e}') def subprocess_execute(cmd): diff --git a/app/modules/service/action.py b/app/modules/service/action.py new file mode 100644 index 00000000..5fd03121 --- /dev/null +++ b/app/modules/service/action.py @@ -0,0 +1,134 @@ +import modules.db.sql as sql +import modules.server.server as server_mod +import modules.roxywi.common as roxywi_common +import modules.service.common as service_common + + +def action_haproxy(server_ip: str, action: str) -> None: + haproxy_service_name = "haproxy" + + if action not in ('start', 'stop', 'reload', 'restart'): + print('error: wrong action') + return + + service_common.is_restarted(server_ip, action) + + if service_common.check_haproxy_config(server_ip): + server_id = sql.select_server_id_by_ip(server_ip=server_ip) + + if action == 'restart': + service_common.is_not_allowed_to_restart(server_id, 'haproxy') + + is_docker = sql.select_service_setting(server_id, 'haproxy', 'dockerized') + + 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) + roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, + service='haproxy') + print(f"success: HAProxy has been {action}") + else: + print("error: Bad config, check please") + + +def action_nginx(server_ip: str, action: str) -> None: + if action not in ('start', 'stop', 'reload', 'restart'): + print('error: wrong action') + return + + service_common.is_restarted(server_ip, action) + + if service_common.check_nginx_config(server_ip): + server_id = sql.select_server_id_by_ip(server_ip=server_ip) + + if action == 'restart': + service_common.is_not_allowed_to_restart(server_id, 'nginx') + is_docker = sql.select_service_setting(server_id, 'nginx', 'dockerized') + + 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) + roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service='nginx') + print(f"success: NGINX has been {action}") + else: + print("error: Bad config, check please") + + +def action_keepalived(server_ip: str, action: str) -> None: + if action not in ('start', 'stop', 'reload', 'restart'): + print('error: wrong action') + return + + service_common.is_restarted(server_ip, action) + + commands = [f"sudo systemctl {action} keepalived"] + server_mod.ssh_command(server_ip, commands) + roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service='keepalived') + print(f"success: Keepalived has been {action}") + + +def action_apache(server_ip: str, action: str) -> None: + if action not in ('start', 'stop', 'reload', 'restart'): + print('error: wrong action') + return + + service_common.is_restarted(server_ip, action) + + server_id = sql.select_server_id_by_ip(server_ip) + + if action == 'restart': + service_common.is_not_allowed_to_restart(server_id, 'apache') + + 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}"] + server_mod.ssh_command(server_ip, commands) + roxywi_common.logging(server_ip, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, service='apache') + print(f"success: Apache has been {action}") + + +def action_haproxy_waf(server_ip: str, action: str) -> None: + if action not in ('start', 'stop', 'reload', 'restart'): + print('error: wrong action') + return + + service_common.is_restarted(server_ip, action) + + roxywi_common.logging(server_ip, f'HAProxy WAF service has been {action}ed', roxywi=1, login=1, keep_history=1, + service='haproxy') + commands = [f"sudo systemctl {action} waf"] + server_mod.ssh_command(server_ip, commands) + + +def action_nginx_waf(server_ip: str, action: str) -> None: + config_dir = common.return_nice_path(sql.get_setting('nginx_dir')) + + if action not in ('start', 'stop'): + print('error: wrong action') + return + + service_common.is_restarted(server_ip, action) + + waf_new_state = 'on' if action == 'start' else 'off' + waf_old_state = 'off' if action == 'start' else 'on' + + roxywi_common.logging(serv, f'NGINX WAF service has been {action}ed', roxywi=1, login=1, keep_history=1, + service='nginx') + commands = [f"sudo sed -i 's/modsecurity {waf_old_state}/modsecurity {waf_new_state}/g' {config_dir}nginx.conf" + f" && sudo systemctl reload nginx"] + server_mod.ssh_command(server_ip, commands) \ No newline at end of file diff --git a/app/options.py b/app/options.py index 4c4ac230..d735ea4b 100644 --- a/app/options.py +++ b/app/options.py @@ -65,12 +65,7 @@ if not sql.check_token_exists(token): sys.exit() if form.getvalue('getcerts') is not None and serv is not None: - cert_path = sql.get_setting('cert_path') - commands = [f"sudo ls -1t {cert_path} |grep -E 'pem|crt|key'"] - try: - server_mod.ssh_command(serv, commands, ip="1") - except Exception as e: - print(f'error: Cannot connect to the server: {e.args[0]}') + config_mod.get_ssl_certs(serv) if form.getvalue('checkSshConnect') is not None and serv is not None: try: @@ -79,60 +74,13 @@ if form.getvalue('checkSshConnect') is not None and serv is not None: print(e) if form.getvalue('getcert') is not None and serv is not None: - cert_id = common.checkAjaxInput(form.getvalue('getcert')) - - cert_path = sql.get_setting('cert_path') - commands = [f"openssl x509 -in {cert_path}/{cert_id} -text"] - try: - server_mod.ssh_command(serv, commands, ip="1") - except Exception as e: - print(f'error: Cannot connect to the server {e.args[0]}') + config_mod.get_ssl_cert(serv) if form.getvalue('delcert') is not None and serv is not None: - cert_id = form.getvalue('delcert') - cert_id = common.checkAjaxInput(cert_id) - cert_path = sql.get_setting('cert_path') - commands = [f"sudo rm -f {cert_path}/{cert_id}"] - try: - server_mod.ssh_command(serv, commands, ip="1") - except Exception as e: - print(f'error: Cannot delete the certificate {e.args[0]}') + config_mod.del_ssl_cert(serv) if serv and form.getvalue('ssl_cert'): - cert_local_dir = os.path.dirname(os.getcwd()) + "/" + sql.get_setting('ssl_local_path') - cert_path = sql.get_setting('cert_path') - name = '' - - if not os.path.exists(cert_local_dir): - os.makedirs(cert_local_dir) - - if form.getvalue('ssl_name') is None: - print('error: Please enter a desired name') - else: - name = common.checkAjaxInput(form.getvalue('ssl_name')) - - try: - with open(name, "w") as ssl_cert: - ssl_cert.write(form.getvalue('ssl_cert')) - except IOError as e: - print(f'error: Cannot save the SSL key file. Check a SSH key path in config {e.args[0]}') - - MASTERS = sql.is_master(serv) - for master in MASTERS: - if master[0] is not None: - config_mod.upload(master[0], cert_path, name) - print('success: the SSL file has been uploaded to %s into: %s%s
' % (master[0], cert_path, '/' + name)) - try: - error = config_mod.upload(serv, cert_path, name) - print('success: the SSL file has been uploaded to %s into: %s%s' % (serv, cert_path, '/' + name)) - except Exception as e: - roxywi_common.logging('Roxy-WI server', e.args[0], roxywi=1) - try: - os.rename(name, cert_local_dir) - except OSError as e: - roxywi_common.logging('Roxy-WI server', e.args[0], roxywi=1) - - roxywi_common.logging(serv, "add.py#ssl uploaded a new SSL cert %s" % name, roxywi=1, login=1) + config_mod.upload_ssl_cert(serv) if form.getvalue('backend') is not None: import modules.config.runtime as runtime @@ -187,142 +135,49 @@ if form.getvalue('table_select') is not None: runtime.table_select() if form.getvalue('ip_for_delete') is not None: - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - ip = common.checkAjaxInput(form.getvalue('ip_for_delete')) - table = common.checkAjaxInput(form.getvalue('table_for_delete')) + import modules.config.runtime as runtime - cmd = 'echo "clear table %s key %s" |nc %s %s' % (table, ip, serv, haproxy_sock_port) - output, stderr = server_mod.subprocess_execute(cmd) - if stderr[0] != '': - print('error: ' + stderr[0]) + runtime.delete_ip_from_stick_table() if form.getvalue('table_for_clear') is not None: - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - table = common.checkAjaxInput(form.getvalue('table_for_clear')) + import modules.config.runtime as runtime - cmd = 'echo "clear table %s " |nc %s %s' % (table, serv, haproxy_sock_port) - output, stderr = server_mod.subprocess_execute(cmd) - if stderr[0] != '': - print('error: ' + stderr[0]) + runtime.clear_stick_table() if form.getvalue('list_serv_select') is not None: - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - cmd = f'echo "show acl"|nc {serv} {haproxy_sock_port} |grep "loaded from" |awk \'{{print $1,$2}}\'' - output, stderr = server_mod.subprocess_execute(cmd) - print(output) + import modules.config.runtime as runtime + + runtime.list_of_lists() if form.getvalue('list_select_id') is not None: - env = Environment(loader=FileSystemLoader('templates/'), autoescape=True, - extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do'], trim_blocks=True, lstrip_blocks=True) - template = env.get_template('ajax/list.html') - list_id = common.checkAjaxInput(form.getvalue('list_select_id')) - list_name = common.checkAjaxInput(form.getvalue('list_select_name')) + import modules.config.runtime as runtime - 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) - - template = template.render(list=output, list_id=list_id, list_name=list_name) - print(template) + runtime.show_lists() if form.getvalue('list_id_for_delete') is not None: - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - lists_path = sql.get_setting('lists_path') - lib_path = get_config.get_config_var('main', 'lib_path') - ip_id = common.checkAjaxInput(form.getvalue('list_ip_id_for_delete')) - ip = common.is_ip_or_dns(form.getvalue('list_ip_for_delete')) - list_id = common.checkAjaxInput(form.getvalue('list_id_for_delete')) - list_name = common.checkAjaxInput(form.getvalue('list_name')) - user_group = roxywi_common.get_user_group(id=1) - cmd = f"sed -i 's!{ip}$!!' {lib_path}/{lists_path}/{user_group}/{list_name}" - cmd1 = f"sed -i '/^$/d' {lib_path}/{lists_path}/{user_group}/{list_name}" - output, stderr = server_mod.subprocess_execute(cmd) - output1, stderr1 = server_mod.subprocess_execute(cmd1) - if output: - print(f'error: {output}') - if stderr: - print(f'error: {stderr}') - if output1: - print(f'error: {output1}') - if stderr1: - print(f'error: {stderr}') + import modules.config.runtime as runtime - cmd = f'echo "del acl #{list_id} #{ip_id}" |nc {serv} {haproxy_sock_port}' - output, stderr = server_mod.subprocess_execute(cmd) - if output[0] != '': - print(f'error: {output[0]}') - if stderr != '': - print(f'error: {stderr[0]}') - - roxywi_common.logging(serv, f'{ip_id} has been delete from list {list_id}', login=1, keep_history=1, - service='haproxy') + runtime.delete_ip_from_list() if form.getvalue('list_ip_for_add') is not None: - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - lists_path = sql.get_setting('lists_path') - lib_path = get_config.get_config_var('main', 'lib_path') - ip = form.getvalue('list_ip_for_add') - ip = ip.strip() - ip = common.is_ip_or_dns(ip) - list_id = common.checkAjaxInput(form.getvalue('list_id_for_add')) - list_name = common.checkAjaxInput(form.getvalue('list_name')) - user_group = roxywi_common.get_user_group(id=1) - cmd = f'echo "add acl #{list_id} {ip}" |nc {serv} {haproxy_sock_port}' - output, stderr = server_mod.subprocess_execute(cmd) - if output[0]: - print(f'error: {output[0]}') - if stderr: - print(f'error: {stderr[0]}') + import modules.config.runtime as runtime - if 'is not a valid IPv4 or IPv6 address' not in output[0]: - cmd = f'echo "{ip}" >> {lib_path}/{lists_path}/{user_group}/{list_name}' - output, stderr = server_mod.subprocess_execute(cmd) - if output: - print(f'error: {output}') - if stderr: - print(f'error: {stderr}') - - roxywi_common.logging(serv, f'{ip} has been added to list {list_id}', login=1, keep_history=1, - service='haproxy') + runtime.add_ip_to_list() if form.getvalue('sessions_select') is not None: - env = Environment(loader=FileSystemLoader('templates'), autoescape=True, - extensions=['jinja2.ext.loopcontrols', 'jinja2.ext.do'], trim_blocks=True, lstrip_blocks=True) - serv = common.checkAjaxInput(form.getvalue('sessions_select')) + import modules.config.runtime as runtime - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - - cmd = f'echo "show sess" |nc {serv} {haproxy_sock_port}' - output, stderr = server_mod.subprocess_execute(cmd) - - template = env.get_template('ajax/sessions_table.html') - template = template.render(sessions=output) - - print(template) + runtime.select_session() if form.getvalue('sessions_select_show') is not None: - serv = common.checkAjaxInput(form.getvalue('sessions_select_show')) - sess_id = common.checkAjaxInput(form.getvalue('sessions_select_id')) - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - cmd = 'echo "show sess %s" |nc %s %s' % (sess_id, serv, haproxy_sock_port) + import modules.config.runtime as runtime - output, stderr = server_mod.subprocess_execute(cmd) - - if stderr: - print('error: ' + stderr[0]) - else: - for o in output: - print(o + '
') + runtime.show_session() if form.getvalue('session_delete_id') is not None: - haproxy_sock_port = sql.get_setting('haproxy_sock_port') - sess_id = common.checkAjaxInput(form.getvalue('session_delete_id')) - cmd = 'echo "shutdown session %s" |nc %s %s' % (sess_id, serv, haproxy_sock_port) - output, stderr = server_mod.subprocess_execute(cmd) - if output[0] != '': - print('error: ' + output[0]) - if stderr[0] != '': - print('error: ' + stderr[0]) + import modules.config.runtime as runtime + + runtime.delete_session() if form.getvalue("change_pos") is not None: pos = form.getvalue('change_pos') @@ -338,170 +193,46 @@ if form.getvalue('showif'): server_mod.ssh_command(serv, commands, ip="1") if form.getvalue('action_hap') is not None and serv is not None: + import modules.service.action as service_action + action = form.getvalue('action_hap') - haproxy_service_name = "haproxy" - - if action not in ('start', 'stop', 'reload', 'restart'): - print('error: wrong action') - sys.exit() - - service_common.is_restarted(serv, action) - - if service_common.check_haproxy_config(serv): - server_id = sql.select_server_id_by_ip(server_ip=serv) - - if action == 'restart': - service_common.is_not_allowed_to_restart(server_id, 'haproxy') - - is_docker = sql.select_service_setting(server_id, 'haproxy', 'dockerized') - - 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(serv, commands) - roxywi_common.logging(serv, f'Service has been {action}ed', roxywi=1, login=1, keep_history=1, - service='haproxy') - print(f"success: HAProxy has been {action}") - else: - print("error: Bad config, check please") + service_action.action_haproxy(serv, action) if form.getvalue('action_nginx') is not None and serv is not None: + import modules.service.action as service_action + action = form.getvalue('action_nginx') - - if action not in ('start', 'stop', 'reload', 'restart'): - print('error: wrong action') - sys.exit() - - service_common.is_restarted(serv, action) - - if service_common.check_nginx_config(serv): - server_id = sql.select_server_id_by_ip(server_ip=serv) - - if action == 'restart': - service_common.is_not_allowed_to_restart(server_id, 'nginx') - is_docker = sql.select_service_setting(server_id, 'nginx', 'dockerized') - - if is_docker == '1': - container_name = sql.get_setting('nginx_container_name') - commands = ["sudo docker %s %s" % (action, container_name)] - else: - commands = ["sudo systemctl %s nginx" % action] - server_mod.ssh_command(serv, commands) - roxywi_common.logging(serv, 'Service has been ' + action + 'ed', roxywi=1, login=1, keep_history=1, service='nginx') - print("success: Nginx has been %s" % action) - else: - print("error: Bad config, check please") + service_action.action_nginx(serv, action) if form.getvalue('action_keepalived') is not None and serv is not None: + import modules.service.action as service_action + action = form.getvalue('action_keepalived') - - if action not in ('start', 'stop', 'reload', 'restart'): - print('error: wrong action') - sys.exit() - - service_common.is_restarted(serv, action) - - commands = ["sudo systemctl %s keepalived" % action] - server_mod.ssh_command(serv, commands) - roxywi_common.logging(serv, 'Service has been ' + action + 'ed', roxywi=1, login=1, keep_history=1, service='keepalived') - print("success: Keepalived has been %s" % action) + service_action.action_keepalived(serv, action) if form.getvalue('action_waf') is not None and serv is not None: - serv = form.getvalue('serv') + import modules.service.action as service_action + action = form.getvalue('action_waf') - - if action not in ('start', 'stop', 'reload', 'restart'): - print('error: wrong action') - sys.exit() - - service_common.is_restarted(serv, action) - - roxywi_common.logging(serv, 'HAProxy WAF service has been ' + action + 'ed', roxywi=1, login=1, keep_history=1, - service='haproxy') - commands = ["sudo systemctl %s waf" % action] - server_mod.ssh_command(serv, commands) + service_action.action_haproxy_waf(serv, action) if form.getvalue('action_waf_nginx') is not None and serv is not None: - serv = form.getvalue('serv') + import modules.service.action as service_action + action = form.getvalue('action_waf_nginx') - config_dir = common.return_nice_path(sql.get_setting('nginx_dir')) - - if action not in ('start', 'stop'): - print('error: wrong action') - sys.exit() - - service_common.is_restarted(serv, action) - - waf_new_state = 'on' if action == 'start' else 'off' - waf_old_state = 'off' if action == 'start' else 'on' - - roxywi_common.logging(serv, 'NGINX WAF service has been ' + action + 'ed', roxywi=1, login=1, keep_history=1, - service='nginx') - commands = [f"sudo sed -i 's/modsecurity {waf_old_state}/modsecurity {waf_new_state}/g' {config_dir}nginx.conf" - f" && sudo systemctl reload nginx"] - server_mod.ssh_command(serv, commands) + service_action.action_nginx_waf(serv, action) if form.getvalue('action_apache') is not None and serv is not None: + import modules.service.action as service_action + action = form.getvalue('action_apache') - - if action not in ('start', 'stop', 'reload', 'restart'): - print('error: wrong action') - sys.exit() - - service_common.is_restarted(serv, action) - - server_id = sql.select_server_id_by_ip(serv) - - if action == 'restart': - service_common.is_not_allowed_to_restart(server_id, 'apache') - - is_docker = sql.select_service_setting(server_id, 'apache', 'dockerized') - if is_docker == '1': - container_name = sql.get_setting('apache_container_name') - commands = ["sudo docker %s %s" % (action, container_name)] - else: - service_apache_name = service_common.get_correct_apache_service_name(None, server_id) - - commands = ["sudo systemctl %s %s" % (action, service_apache_name)] - server_mod.ssh_command(serv, commands) - roxywi_common.logging(serv, 'Service has been ' + action + 'ed', roxywi=1, login=1, keep_history=1, service='apache') - print("success: Apache has been %s" % action) + service_action.action_apache(serv, action) if form.getvalue('action_service') is not None: import modules.roxywi.roxy as roxy + action = common.checkAjaxInput(form.getvalue('action_service')) - - if action not in ('start', 'stop', 'restart'): - print('error: wrong action') - sys.exit() - - is_in_docker = roxy.is_docker() - if action == 'stop': - cmd = "sudo systemctl disable %s --now" % serv - elif action == "start": - cmd = "sudo systemctl enable %s --now" % serv - if not sql.select_user_status(): - print( - 'warning: The service is disabled because you are not subscribed. Read here about subscriptions') - sys.exit() - elif action == "restart": - cmd = "sudo systemctl restart %s --now" % serv - if not sql.select_user_status(): - print( - 'warning: The service is disabled because you are not subscribed. Read here about subscriptions') - sys.exit() - if is_in_docker: - cmd = "sudo supervisorctl " + action + " " + serv - output, stderr = server_mod.subprocess_execute(cmd) - roxywi_common.logging('Roxy-WI server', ' The service ' + serv + ' has been ' + action + 'ed', roxywi=1, login=1) + roxy.action_service(action, serv) if act == "overviewHapserverBackends": import modules.config.section as section_mod @@ -1882,77 +1613,24 @@ if form.getvalue('change_waf_mode'): error_mess = 'error: All fields must be completed' if form.getvalue('newuser') is not None: - email = form.getvalue('newemail') - password = form.getvalue('newpassword') - role = form.getvalue('newrole') - new_user = form.getvalue('newusername') - page = form.getvalue('page') - activeuser = form.getvalue('activeuser') - group = form.getvalue('newgroupuser') - role_id = sql.get_role_id_by_name(role) + import modules.roxywi.user as roxywi_user - if roxywi_common.check_user_group(): - if roxywi_auth.is_admin(level=role_id): - try: - sql.add_user(new_user, email, password, role, activeuser, group) - env = Environment(loader=FileSystemLoader('templates/'), autoescape=True) - template = env.get_template('ajax/new_user.html') - - template = template.render(users=sql.select_users(user=new_user), - groups=sql.select_groups(), - page=page, - roles=sql.select_roles(), - adding=1) - print(template) - roxywi_common.logging(f'a new user {new_user}', ' has been created ', roxywi=1, login=1) - except Exception as e: - print(e) - roxywi_common.logging('Cannot create a new user', e, roxywi=1, login=1) - else: - print('error: dalsdm') - roxywi_common.logging(new_user, ' tried to privilege escalation', roxywi=1, login=1) + roxywi_user.create_user() if form.getvalue('userdel') is not None: - userdel = form.getvalue('userdel') - user = sql.select_users(id=userdel) - username = '' - for u in user: - username = u.username - if sql.delete_user(userdel): - sql.delete_user_groups(userdel) - roxywi_common.logging(username, ' has been deleted user ', roxywi=1, login=1) - print("Ok") + import modules.roxywi.user as roxywi_user + + roxywi_user.delete_user() if form.getvalue('updateuser') is not None: - email = form.getvalue('email') - role = form.getvalue('role') - new_user = form.getvalue('updateuser') - user_id = form.getvalue('id') - activeuser = form.getvalue('activeuser') - group = form.getvalue('usergroup') - role_id = sql.get_role_id_by_name(role) + import modules.roxywi.user as roxywi_user - if roxywi_common.check_user_group(): - if roxywi_auth.is_admin(level=role_id): - sql.update_user(new_user, email, role, user_id, activeuser) - roxywi_common.logging(new_user, ' has been updated user ', roxywi=1, login=1) - else: - roxywi_common.logging(new_user, ' tried to privilege escalation', roxywi=1, login=1) + roxywi_user.update_user() if form.getvalue('updatepassowrd') is not None: - password = form.getvalue('updatepassowrd') - username = '' + import modules.roxywi.user as roxywi_user - if form.getvalue('uuid'): - user_id = sql.get_user_id_by_uuid(form.getvalue('uuid')) - else: - user_id = form.getvalue('id') - user = sql.select_users(id=user_id) - for u in user: - username = u.username - sql.update_user_password(password, user_id) - roxywi_common.logging('user ' + username, ' has changed password ', roxywi=1, login=1) - print("Ok") + roxywi_user.update_user_password() if form.getvalue('newserver') is not None: import modules.server.server as server_mod @@ -2645,7 +2323,7 @@ if form.getvalue('lets_domain'): lets_domain = form.getvalue('lets_domain') lets_email = form.getvalue('lets_email') proxy = sql.get_setting('proxy') - ssl_path = sql.get_setting('cert_path') + ssl_path = common.return_nice_path(sql.get_setting('cert_path')) haproxy_dir = sql.get_setting('haproxy_dir') script = "letsencrypt.sh" proxy_serv = '' diff --git a/app/provisioning.py b/app/provisioning.py index 5a8fb755..0382cbb7 100644 --- a/app/provisioning.py +++ b/app/provisioning.py @@ -7,7 +7,6 @@ import modules.db.sql as sql import modules.common.common as common import modules.roxywi.auth as roxywi_auth import modules.roxywi.common as roxywi_common -import modules.server.server as server_mod env = Environment(extensions=["jinja2.ext.do"], loader=FileSystemLoader('templates/'), autoescape=True) template = env.get_template('provisioning.html') @@ -31,13 +30,7 @@ try: groups = roxywi_common.get_user_group(id=1) user_group = roxywi_common.get_user_group(id=1) - cmd = 'which terraform' - output, stderr = server_mod.subprocess_execute(cmd) - - if stderr != '': - is_terraform = False - else: - is_terraform = True + is_needed_tool = common.is_tool('terraform') params = sql.select_provisioning_params() except Exception as e: @@ -46,6 +39,6 @@ except Exception as e: rendered_template = template.render( title="Servers provisioning", role=user_params['role'], user=user_params['user'], groups=groups, user_group=user_group, servers=sql.select_provisioned_servers(), providers=sql.select_providers(user_group), - is_terraform=is_terraform, user_services=user_params['user_services'], token=user_params['token'], params=params + is_needed_tool=is_needed_tool, user_services=user_params['user_services'], token=user_params['token'], params=params ) print(rendered_template) diff --git a/app/scripts/ansible/roles/haproxy/tasks/installation.yml b/app/scripts/ansible/roles/haproxy/tasks/installation.yml index 0061ade0..23815e7e 100644 --- a/app/scripts/ansible/roles/haproxy/tasks/installation.yml +++ b/app/scripts/ansible/roles/haproxy/tasks/installation.yml @@ -21,6 +21,9 @@ when: (ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS') and HAPVER|length > 0 ignore_errors: yes register: install_result + retries: 5 + until: install_result.rc == 0 + delay: 5 environment: http_proxy: "{{PROXY}}" https_proxy: "{{PROXY}}" @@ -34,9 +37,12 @@ - rsyslog - bind-utils state: present - register: install_result1 when: (ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS') and ("'timed out' in install_result.stderr") ignore_errors: yes + register: install_result1 + retries: 5 + until: install_result1.rc == 0 + delay: 5 environment: http_proxy: "{{PROXY}}" https_proxy: "{{PROXY}}" @@ -56,6 +62,10 @@ - rsyslog state: latest when: (ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS') and ("'FAILED' in install_result1.stderr") + register: install_result + retries: 5 + until: install_result.rc == 0 + delay: 5 environment: http_proxy: "{{PROXY}}" https_proxy: "{{PROXY}}" @@ -69,6 +79,10 @@ - rsyslog state: present when: ansible_facts['os_family'] == 'Debian' or ansible_facts['os_family'] == 'Ubuntu' + register: install_result + retries: 5 + until: install_result.rc == 0 + delay: 5 environment: http_proxy: "{{PROXY}}" https_proxy: "{{PROXY}}" diff --git a/app/servers.py b/app/servers.py index a57a0ff3..c4ca7523 100644 --- a/app/servers.py +++ b/app/servers.py @@ -32,6 +32,7 @@ try: gits = sql.select_gits() servers = roxywi_common.get_dick_permit(virt=1, disable=0, only_group=1) masters = sql.select_servers(get_master_servers=1, uuid=user_params['user_uuid'].value) + is_needed_tool = common.is_tool('ansible') except Exception: pass @@ -48,5 +49,6 @@ rendered_template = template.render( token=user_params['token'], settings=settings, backups=sql.select_backups(), page="servers.py", geoip_country_codes=geoip_country_codes, user_services=user_params['user_services'], ldap_enable=ldap_enable, user_status=user_subscription['user_status'], user_plan=user_subscription['user_plan'], gits=gits, + is_needed_tool=is_needed_tool ) print(rendered_template) diff --git a/app/templates/ha.html b/app/templates/ha.html index e5ec19c9..6c1c8151 100644 --- a/app/templates/ha.html +++ b/app/templates/ha.html @@ -9,6 +9,14 @@ {% if user_status == 0 or user_plan == 'user' %} {% include 'include/no_sub.html' %} +{% elif not is_needed_tool %} +
+

You have not installed Ansible

. + There is no server +

+ Read here how to install Ansible. +

+
{% else %} @@ -130,7 +138,7 @@

Create a new HA cluster

- Read How to create high available cluster + Read How to create high available cluster
+{% endif %} diff --git a/app/templates/include/mon_installation.html b/app/templates/include/mon_installation.html index 282072ba..f1606de5 100644 --- a/app/templates/include/mon_installation.html +++ b/app/templates/include/mon_installation.html @@ -1,3 +1,12 @@ +{% if not is_needed_tool %} +
+

You have not installed Ansible

. + There is no server +

+ Read here how to install Ansible. +

+
+{% else %} {% if page == 'users.py' %} @@ -45,8 +54,8 @@

Installing Grafana and Prometheus servers

{% set values = dict() %} - {% set values = {'0.7.0':'0.7.0','0.7.1':'0.7.1', '0.8.0':'0.8.0', '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'} %} - {{ select('hapexpver', values=values, selected='0.13.0') }} + {% set values = {'0.8.0':'0.8.0', '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'} %} + {{ select('hapexpver', values=values, selected='0.14.0') }} {% set values = dict() %} - {% set values = {'0.5.0':'0.5.0', '0.6.0':'0.6.0', '0.7.0':'0.7.0', '0.9.0':'0.9.0', '0.10.0':'0.10.0'} %} - {{ select('nginxexpver', values=values, selected='0.10.0') }} + {% set values = {'0.6.0':'0.6.0', '0.7.0':'0.7.0', '0.9.0':'0.9.0', '0.10.0':'0.10.0', '0.11.0':'0.11.0'} %} + {{ select('nginxexpver', values=values, selected='0.11.0') }} {% set values = dict() %} - {% set values = {'1.0.0':'1.0.0','1.1.0':'1.1.0', '1.1.1':'1.1.1', '1.1.2':'1.1.2', '1.2.0':'1.2.0', - '1.2.2':'1.2.2', '1.3.0':'1.3.0', '1.3.1':'1.3.1'} %} - {{ select('nodeexpver', values=values, selected='1.3.1') }} + {% set values = {'1.1.1':'1.1.1', '1.1.2':'1.1.2', '1.2.0':'1.2.0', '1.2.2':'1.2.2', '1.3.0':'1.3.0', '1.3.1':'1.3.1', '1.5.0':'1.5.0'} %} + {{ select('nodeexpver', values=values, selected='1.5.0') }} @@ -117,6 +126,7 @@

Install HAProxy

+ {% endif %}
{% include 'include/admin_backup.html' %} @@ -127,6 +137,15 @@
+ {% if not is_needed_tool %} +
+

You have not installed Ansible

. + There is no server +

+ Read here how to install Ansible. +

+
+ {% else %} @@ -160,6 +179,7 @@ + {% endif %}

Install GeoLite2

Server
diff --git a/app/users.py b/app/users.py index 464e413e..8417ec10 100644 --- a/app/users.py +++ b/app/users.py @@ -33,6 +33,7 @@ ldap_enable = sql.get_setting('ldap_enable') services = sql.select_services() gits = sql.select_gits() masters = sql.select_servers(get_master_servers=1) +is_needed_tool = common.is_tool('ansible') try: user_subscription = roxywi_common.return_user_status() @@ -45,6 +46,7 @@ rendered_template = template.render( servers=sql.select_servers(full=1), roles=sql.select_roles(), masters=masters, sshs=sql.select_ssh(), settings=settings, backups=sql.select_backups(), services=services, timezones=pytz.all_timezones, page="users.py", user_services=user_params['user_services'], ldap_enable=ldap_enable, gits=gits, guide_me=1, - user_status=user_subscription['user_status'], user_plan=user_subscription['user_plan'], token=user_params['token'] + user_status=user_subscription['user_status'], user_plan=user_subscription['user_plan'], token=user_params['token'], + is_needed_tool=is_needed_tool ) print(rendered_template)