diff --git a/app/create_db.py b/app/create_db.py index 45122cc7..c3c31044 100644 --- a/app/create_db.py +++ b/app/create_db.py @@ -668,7 +668,7 @@ def update_db_v_6_3_18(): def update_ver(): try: - Version.update(version='7.0.1.0').execute() + Version.update(version='7.0.2.0').execute() except Exception: print('Cannot update version') diff --git a/app/login.py b/app/login.py index 0debd283..e76e0c93 100644 --- a/app/login.py +++ b/app/login.py @@ -12,7 +12,10 @@ import app.modules.roxy_wi_tools as roxy_wi_tools @app.before_request @cache.memoize(3) def check_login(): - if request.endpoint not in ('login_page', 'static', 'main.show_roxywi_version', 'service.check_service'): + if request.endpoint not in ( + 'login_page', 'static', 'main.show_roxywi_version', 'service.check_service', 'smon.show_smon_status_page', + 'smon.smon_history_statuses' + ): try: user_params = roxywi_common.get_users_params() except Exception: diff --git a/app/modules/config/runtime.py b/app/modules/config/runtime.py index 259883b3..e09765c8 100644 --- a/app/modules/config/runtime.py +++ b/app/modules/config/runtime.py @@ -357,6 +357,8 @@ def delete_ip_from_list(serv, ip_id, ip, list_id, list_name) -> str: except Exception: pass + return 'ok' + def add_ip_to_list(serv, ip, list_id, list_name) -> str: haproxy_sock_port = sql.get_setting('haproxy_sock_port') @@ -371,13 +373,12 @@ def add_ip_to_list(serv, ip, list_id, list_name) -> str: pass try: if stderr: - print(f'error: {stderr[0]}') + return f'error: {stderr[0]}' except Exception: pass if 'is not a valid IPv4 or IPv6 address' not in output[0]: cmd = f'echo "{ip}" >> {lib_path}/lists/{user_group}/{list_name}' - print(cmd) output, stderr = server_mod.subprocess_execute(cmd) roxywi_common.logging(serv, f'{ip} has been added to list {list_id}', login=1, keep_history=1, service='haproxy') if output: diff --git a/app/modules/db/db_model.py b/app/modules/db/db_model.py index 73ca4202..e3df3bc0 100644 --- a/app/modules/db/db_model.py +++ b/app/modules/db/db_model.py @@ -616,6 +616,26 @@ class SmonDnsCheck(BaseModel): primary_key = False +class SmonStatusPage(BaseModel): + id = AutoField() + name = CharField() + slug = CharField(unique=True) + desc = CharField(null=True) + group_id = IntegerField() + + class Meta: + table_name = 'smon_status_pages' + + +class SmonStatusPageCheck(BaseModel): + page_id = ForeignKeyField(SmonStatusPage, on_delete='Cascade') + check_id = ForeignKeyField(SMON, on_delete='Cascade') + + class Meta: + table_name = 'smon_status_page_checks' + primary_key = False + + class RoxyTool(BaseModel): id = AutoField() name = CharField() @@ -636,4 +656,5 @@ def create_tables(): PortScannerSettings, PortScannerPorts, PortScannerHistory, ServiceSetting, MetricsHttpStatus, SMON, WafRules, Alerts, GeoipCodes, NginxMetrics, SystemInfo, Services, UserName, GitSetting, CheckerSetting, ApacheMetrics, WafNginx, ServiceStatus, KeepaliveRestart, PD, SmonHistory, - SmonTcpCheck, SmonHttpCheck, SmonPingCheck, SmonDnsCheck, S3Backup, RoxyTool]) + SmonTcpCheck, SmonHttpCheck, SmonPingCheck, SmonDnsCheck, S3Backup, RoxyTool, SmonStatusPage, + SmonStatusPageCheck]) diff --git a/app/modules/db/sql.py b/app/modules/db/sql.py index d13d7ac6..9bf11750 100755 --- a/app/modules/db/sql.py +++ b/app/modules/db/sql.py @@ -781,6 +781,9 @@ def get_user_id_by_uuid(uuid): else: for user in query_res: return user.user_id + finally: + if not conn.is_closed(): + conn.close() def get_user_id_by_username(username: str): @@ -3032,10 +3035,9 @@ def insert_smon_history(smon_id: int, response_time: float, status: int, check_i conn.close() -def select_smon_history(smon_id: int, check_id: int) -> object: +def select_smon_history(smon_id: int) -> object: query = SmonHistory.select().where( - (SmonHistory.smon_id == smon_id) & - (SmonHistory.check_id == check_id) + SmonHistory.smon_id == smon_id ).limit(40).order_by(SmonHistory.date.desc()) try: query_res = query.execute() @@ -3045,10 +3047,9 @@ def select_smon_history(smon_id: int, check_id: int) -> object: return query_res -def get_last_smon_status_by_check(smon_id: int, check_id: int) -> object: +def get_last_smon_status_by_check(smon_id: int) -> object: query = SmonHistory.select().where( - (SmonHistory.smon_id == smon_id) & - (SmonHistory.check_id == check_id) + SmonHistory.smon_id == smon_id ).limit(1).order_by(SmonHistory.date.desc()) try: query_res = query.execute() @@ -3079,11 +3080,10 @@ def get_last_smon_res_time_by_check(smon_id: int, check_id: int) -> object: return '' -def get_smon_history_count_checks(smon_id: int, check_id: int) -> dict: +def get_smon_history_count_checks(smon_id: int) -> dict: count_checks = {} query = SmonHistory.select(fn.Count(SmonHistory.status)).where( - (SmonHistory.smon_id == smon_id) & - (SmonHistory.check_id == check_id) + SmonHistory.smon_id == smon_id ) try: query_res = query.execute() @@ -3098,7 +3098,6 @@ def get_smon_history_count_checks(smon_id: int, check_id: int) -> dict: query = SmonHistory.select(fn.Count(SmonHistory.status)).where( (SmonHistory.smon_id == smon_id) & - (SmonHistory.check_id == check_id) & (SmonHistory.status == 1) ) try: @@ -4191,3 +4190,63 @@ def get_tool_cur_version(tool_name: str): out_error(e) else: return query + + +def add_status_page(name: str, slug: str, desc: str, group_id: int, checks: list) -> int: + try: + last_id = SmonStatusPage.insert(name=name, slug=slug, group_id=group_id, desc=desc).execute() + except Exception as e: + if '1062, "Duplicate entry' in str(e): + raise Exception('error: The Slug is already taken, please enter another one') + else: + out_error(e) + else: + for check in checks: + try: + SmonStatusPageCheck.insert(page_id=last_id, check_id=int(check)).execute() + except Exception as e: + out_error(e) + return last_id + + +def select_status_pages(group_id: int): + try: + query_res = SmonStatusPage.select().where(SmonStatusPage.group_id == group_id).execute() + except Exception as e: + return out_error(e) + else: + return query_res + + +def select_status_page_by_id(page_id: int): + try: + query_res = SmonStatusPage.select().where(SmonStatusPage.id == page_id).execute() + except Exception as e: + return out_error(e) + else: + return query_res + + +def select_status_page(slug: str): + try: + query_res = SmonStatusPage.select().where(SmonStatusPage.slug == slug).execute() + except Exception as e: + out_error(e) + else: + return query_res + + +def select_status_page_checks(page_id: int): + try: + query_res = SmonStatusPageCheck.select().where(SmonStatusPageCheck.page_id == page_id).execute() + except Exception as e: + out_error(e) + else: + return query_res + + +def delete_status_page(page_id): + try: + SmonStatusPage.delete().where(SmonStatusPage.id == page_id).execute() + except Exception as e: + out_error(e) diff --git a/app/modules/roxywi/roxy.py b/app/modules/roxywi/roxy.py index 31cc6e8d..7f229613 100644 --- a/app/modules/roxywi/roxy.py +++ b/app/modules/roxywi/roxy.py @@ -32,8 +32,6 @@ def versions(): current_ver_without_dots = current_ver.split('.') current_ver_without_dots = ''.join(current_ver_without_dots) current_ver_without_dots = current_ver_without_dots.replace('\n', '') - if len(current_ver_without_dots) == 4: - current_ver_without_dots += '0' current_ver_without_dots = int(current_ver_without_dots) except Exception: current_ver = "Cannot get current version" diff --git a/app/modules/tools/smon.py b/app/modules/tools/smon.py index bb3c7e66..bcaaeff5 100644 --- a/app/modules/tools/smon.py +++ b/app/modules/tools/smon.py @@ -1,4 +1,4 @@ -from flask import render_template +from flask import render_template, abort import modules.db.sql as sql import modules.roxywi.common as roxywi_common @@ -90,8 +90,8 @@ def delete_smon(smon_id, user_group) -> str: raise Exception(f'error: Cannot delete the server {e}') -def history_metrics(server_id: int, check_id: int) -> dict: - metric = sql.select_smon_history(server_id, check_id) +def history_metrics(server_id: int) -> dict: + metric = sql.select_smon_history(server_id) metrics = {'chartData': {}} metrics['chartData']['labels'] = {} @@ -108,14 +108,14 @@ def history_metrics(server_id: int, check_id: int) -> dict: return metrics -def history_statuses(dashboard_id: int, check_id: int) -> None: - smon_statuses = sql.select_smon_history(dashboard_id, check_id) +def history_statuses(dashboard_id: int) -> None: + smon_statuses = sql.select_smon_history(dashboard_id) return render_template('ajax/smon/history_status.html', smon_statuses=smon_statuses) def history_cur_status(dashboard_id: int, check_id: int) -> None: - cur_status = sql.get_last_smon_status_by_check(dashboard_id, check_id) + cur_status = sql.get_last_smon_status_by_check(dashboard_id) smon = sql.select_one_smon(dashboard_id, check_id) return render_template('ajax/smon/cur_status.html', cur_status=cur_status, smon=smon) @@ -126,3 +126,48 @@ def return_smon_status(): smon_status, stderr = server_mod.subprocess_execute(cmd) return smon_status, stderr + + +def check_uptime(smon_id: int) -> int: + count_checks = sql.get_smon_history_count_checks(smon_id) + + try: + uptime = round(count_checks['up'] * 100 / count_checks['total'], 2) + except Exception: + uptime = 0 + + return uptime + + +def create_status_page(name: str, slug: str, desc: str, checks: list) -> str: + group_id = roxywi_common.get_user_group(id=1) + + try: + page_id = sql.add_status_page(name, slug, desc, group_id, checks) + except Exception as e: + raise Exception(f'{e}') + + pages = sql.select_status_page_by_id(page_id) + + return render_template('ajax/smon/status_pages.html', pages=pages) + + +def show_status_page(slug: str) -> str: + page = sql.select_status_page(slug) + checks_status = {} + if not page: + abort(404, 'Not found status page') + + for p in page: + page_id = p.id + + checks = sql.select_status_page_checks(page_id) + + for check in checks: + check_id = str(check.check_id) + smon_name = sql.get_smon_service_name_by_id(check_id) + uptime = check_uptime(check_id) + + checks_status[check_id] = {'uptime': uptime, 'name': smon_name} + + return render_template('smon/status_page.html', page=page, checks_status=checks_status) \ No newline at end of file diff --git a/app/routes/overview/routes.py b/app/routes/overview/routes.py index 94d13d4d..7bf465d6 100644 --- a/app/routes/overview/routes.py +++ b/app/routes/overview/routes.py @@ -1,7 +1,6 @@ from flask import render_template, g from flask_login import login_required -from app import cache from app.routes.overview import bp from middleware import get_user_params import app.modules.db.sql as sql @@ -45,7 +44,6 @@ def overview_users(): @bp.route('/overview/sub') -@cache.cached() def overview_sub(): return roxy_overview.show_sub_ovw() diff --git a/app/routes/portscanner/routes.py b/app/routes/portscanner/routes.py index 5077e203..9c76fa8c 100644 --- a/app/routes/portscanner/routes.py +++ b/app/routes/portscanner/routes.py @@ -79,13 +79,17 @@ def change_settings_portscanner(): return 'ok' -@bp.route('/scan/') -def scan_port(server_id): - server = sql.select_servers(id=server_id) - ip = '' +@bp.route('/scan/', defaults={'server_ip': None}) +@bp.route('/scan/', defaults={'server_id': None}) +def scan_port(server_id, server_ip): + if server_ip: + ip = server_ip + else: + server = sql.select_servers(id=server_id) + ip = '' - for s in server: - ip = s[2] + for s in server: + ip = s[2] cmd = f"sudo nmap -sS {ip} |grep -E '^[[:digit:]]'|sed 's/ */ /g'" cmd1 = f"sudo nmap -sS {ip} |head -5|tail -2" diff --git a/app/routes/smon/routes.py b/app/routes/smon/routes.py index 09170b14..dff45a84 100644 --- a/app/routes/smon/routes.py +++ b/app/routes/smon/routes.py @@ -1,3 +1,4 @@ +import json from pytz import timezone from flask import render_template, request, jsonify, g from flask_login import login_required @@ -12,14 +13,8 @@ import app.modules.roxywi.common as roxywi_common import app.modules.tools.smon as smon_mod -@bp.before_request -@login_required -def before_request(): - """ Protect all of the admin endpoints. """ - pass - - @bp.route('/dashboard') +@login_required @get_user_params() def smon(): roxywi_common.check_user_group_for_flask() @@ -38,6 +33,7 @@ def smon(): @bp.route('/dashboard//') +@login_required @get_user_params() def smon_dashboard(dashboard_id, check_id): user_params = g.user_params @@ -51,12 +47,8 @@ def smon_dashboard(dashboard_id, check_id): present = present.strftime('%b %d %H:%M:%S %Y %Z') present = datetime.strptime(present, '%b %d %H:%M:%S %Y %Z') cert_day_diff = 'N/A' - count_checks = sql.get_smon_history_count_checks(dashboard_id, check_id) + uptime = smon_mod.check_uptime(dashboard_id) - try: - uptime = round(count_checks['up'] * 100 / count_checks['total'], 2) - except Exception: - uptime = 0 try: avg_res_time = round(sql.get_avg_resp_time(dashboard_id, check_id), 2) except Exception: @@ -80,7 +72,62 @@ def smon_dashboard(dashboard_id, check_id): ) + +@bp.route('/status-page') +@login_required +@get_user_params() +def status_page(): + user_params = g.user_params + user_group = roxywi_common.get_user_group(id=1) + smon_list = sql.smon_list(user_group) + pages = sql.select_status_pages(user_group) + smon_status, stderr = smon_mod.return_smon_status() + user_subscription = roxywi_common.return_user_subscription() + + return render_template( + 'smon/manage_status_page.html', role=user_params['role'], user=user_params['user'], lang=user_params['lang'], + user_status=user_subscription['user_status'], user_plan=user_subscription['user_plan'], smon_error=stderr, pages=pages, + token=user_params['token'], user_services=user_params['user_services'], smon=smon_list, smon_status=smon_status + ) + + +@bp.post('/status-page/add') +@login_required +def add_status_page(): + name = common.checkAjaxInput(request.form.get('name')) + slug = common.checkAjaxInput(request.form.get('slug')) + desc = common.checkAjaxInput(request.form.get('desc')) + checks = json.loads(request.form.get('checks')) + + if not len(checks['checks']): + return 'error: Please check Checks for Status page' + + try: + return smon_mod.create_status_page(name, slug, desc, checks['checks']) + except Exception as e: + return f'{e}' + + +@bp.route('/status-page/delete/') +@login_required +def delete_status_page(page_id): + try: + sql.delete_status_page(page_id) + except Exception as e: + return f'{e}' + else: + return 'ok' + + +@bp.route('/status/') +def show_smon_status_page(slug): + slug = common.checkAjaxInput(slug) + + return smon_mod.show_status_page(slug) + + @bp.route('/history') +@login_required @get_user_params() def smon_history(): roxywi_common.check_user_group_for_flask() @@ -99,6 +146,7 @@ def smon_history(): @bp.route('/history/host/') +@login_required @get_user_params() def smon_host_history(server_ip): roxywi_common.check_user_group_for_flask() @@ -117,22 +165,25 @@ def smon_host_history(server_ip): ) -@bp.route('/history/metric//') -def smon_history_metric(dashboard_id, check_id): - return jsonify(smon_mod.history_metrics(dashboard_id, check_id)) +@bp.route('/history/metric/') +@login_required +def smon_history_metric(dashboard_id): + return jsonify(smon_mod.history_metrics(dashboard_id)) -@bp.route('/history/statuses//') -def smon_history_statuses(dashboard_id, check_id): - return smon_mod.history_statuses(dashboard_id, check_id) +@bp.route('/history/statuses/') +def smon_history_statuses(dashboard_id): + return smon_mod.history_statuses(dashboard_id) @bp.route('/history/cur_status//') +@login_required def smon_history_cur_status(dashboard_id, check_id): return smon_mod.history_cur_status(dashboard_id, check_id) @bp.route('/admin') +@login_required @get_user_params() def smon_admin(): user_group = roxywi_common.get_user_group(id=1) @@ -158,6 +209,7 @@ def smon_admin(): @bp.post('/add') +@login_required def smon_add(): user_group = roxywi_common.get_user_group(id=1) name = common.checkAjaxInput(request.form.get('newsmonname')) @@ -200,6 +252,7 @@ def smon_add(): @bp.post('/update/') +@login_required def smon_update(smon_id): roxywi_common.check_user_group_for_flask() name = common.checkAjaxInput(request.form.get('updateSmonName')) @@ -232,6 +285,7 @@ def smon_update(smon_id): @bp.route('/delete/') +@login_required def smon_delete(smon_id): user_group = roxywi_common.get_user_group(id=1) @@ -245,6 +299,7 @@ def smon_delete(smon_id): @bp.post('/refresh') +@login_required def smon_show(): sort = common.checkAjaxInput(request.form.get('sort')) return smon_mod.show_smon(sort) diff --git a/app/templates/ajax/smon/status_pages.html b/app/templates/ajax/smon/status_pages.html new file mode 100644 index 00000000..32b76991 --- /dev/null +++ b/app/templates/ajax/smon/status_pages.html @@ -0,0 +1,15 @@ +{% for page in pages %} + +{% endfor %} diff --git a/app/templates/base.html b/app/templates/base.html index 85c633ef..d7b55c23 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -1,7 +1,7 @@ + {% import 'languages/'+lang|default('en')+'.html' as lang %} {% from 'languages/languages.html' import languages %} {% from 'include/input_macros.html' import select, checkbox %} - {% block title %}{% endblock %} @@ -20,7 +20,7 @@ data-stop="{{lang.words.stop|title()}}" data-reload="{{lang.words.reload|title()}}" data-user_groups="{{lang.phrases.user_groups}}" data-settings="{{lang.words.settings|title()}}" data-for="{{lang.words.for}}" data-show="{{lang.words.show|title()}}" data-hide="{{lang.words.hide|title()}}" data-logs="{{lang.words.logs}}" data-name="{{lang.words.name}}" data-value="{{lang.words.value}}" data-if-title="{{lang.words.if|title()}}" data-then="{{lang.words.then}}" data-autorefresh="{{lang.words.auto|title()}}-{{lang.words.refresh}}" - data-raw="{{lang.words.raw|title()}}" data-resp_time="{{lang.smon_page.desc.resp_time}}" /> + data-raw="{{lang.words.raw|title()}}" data-resp_time="{{lang.smon_page.desc.resp_time}}" data-next="{{lang.words.next|title()}}" data-back="{{lang.words.back|title()}}" /> {% if title == 'Login page' %} {% endif %} diff --git a/app/templates/languages/en.html b/app/templates/languages/en.html index 0b31bf82..2c4bb246 100644 --- a/app/templates/languages/en.html +++ b/app/templates/languages/en.html @@ -97,6 +97,7 @@ "title": "Monitoring tools", "smon": { "dashboard": "SMON: Dashboard", + "status_page": "SMON: Status page", "history": "SMON: History", "admin": "SMON: Admin panel", }, @@ -319,6 +320,7 @@ "became_master": "Became Master", "resource_record_type": "Resource Record Type", "add_to_smon_desc": "Add the server for checking by SMON ping", + "create_page_status": "Create status page", } %} {% set roles = { @@ -586,6 +588,7 @@ "edit": "edit", "delete": "delete", "add": "add", + "added": "added", "save": "save", "saved": "saved", "saving": "saving", @@ -696,6 +699,7 @@ "virt": "virt", "virtual": "virtual", "check": "check", + "checks": "checks", "checking": "checking", "protected": "protected", "slave_for": "Slave for", @@ -880,5 +884,6 @@ "map": "map", "method": "method", "tools": "tools", + "next": "next", } %} diff --git a/app/templates/languages/fr.html b/app/templates/languages/fr.html index 2afa5769..7d080fb1 100644 --- a/app/templates/languages/fr.html +++ b/app/templates/languages/fr.html @@ -97,6 +97,7 @@ "title": "Outils de monitoring", "smon": { "dashboard": "SMON: tableau de bord", + "status_page": "SMON: Page d'état", "history": "SMON: Historique", "admin": "SMON: Panneau administrateur", }, @@ -319,6 +320,7 @@ "became_master": "Devenu maître", "resource_record_type": "Type d'enregistrement de ressource", "add_to_smon_desc": "Ajouter le serveur pour vérification par SMON ping", + "create_page_status": "Créer une page de statut", } %} {% set roles = { @@ -586,6 +588,7 @@ "edit": "éditer", "delete": "supprimer", "add": "ajouter", + "added": "ajoutée", "save": "sauvegarder", "saved": "sauvegardé", "saving": "sauvegarde en cours", @@ -695,7 +698,8 @@ "enabled2": "activé", "virt": "virt", "virtual": "virtuel", - "check": "check", + "check": "contrôler", + "checks": "vérifications", "checking": "vérifier", "protected": "protégé", "slave_for": "Esclave de", @@ -880,5 +884,6 @@ "map": "carte", "method": "méthode", "tools": "outils", + "next": "suivante", } %} diff --git a/app/templates/languages/pt-br.html b/app/templates/languages/pt-br.html index b661da27..4f8bf188 100644 --- a/app/templates/languages/pt-br.html +++ b/app/templates/languages/pt-br.html @@ -98,6 +98,7 @@ "smon": { "dashboard": "SMON: Painel", "history": "SMON: Histórico", + "status_page": "SMON: Página de status", "admin": "SMON: Painel de administrador" }, "checker_history": "Checker: Histórico", @@ -160,7 +161,7 @@ "checker_maxconn_threshold": "Valor limite para a notificação de maxconn, em %", "checker_check_interval": "Intervalo de verificação para o Checker (em minutos)", "smon_ssl_expire_warning_alert": "Aviso de alerta sobre a expiração do certificado SSL (em dias)", - "smon_ssl_expire_critical_alert": "Alerta critico a expiração do certificado SSL (em dias)" + "smon_ssl_expire_critical_alert": "Alerta critico a expiração do certificado SSL (em dias)", "action_keep_history_range": "Período de retenção do histórico de ações (em dias)", }, "main": { @@ -319,6 +320,7 @@ "became_master": "Tornou-se mestre", "resource_record_type": "Tipo de registro de recurso", "add_to_smon_desc": "Adicione o servidor para verificação por ping SMON", + "create_page_status": "Criar página de status", } %} {% set roles = { @@ -586,6 +588,7 @@ "edit": "editar", "delete": "apagar", "add": "adicionar", + "added": "adicionada", "save": "salvar", "saved": "salvo", "saving": "salvando", @@ -696,6 +699,7 @@ "virt": "virt", "virtual": "virtual", "check": "verificar", + "checks": "verificações", "checking": "verificando", "protected": "protegido", "slave_for": "Escravo para", @@ -880,5 +884,6 @@ "map": "mapa", "method": "método", "tools": "ferramentas", + "next": "próxima", } %} diff --git a/app/templates/languages/ru.html b/app/templates/languages/ru.html index c4ae3082..fda91267 100644 --- a/app/templates/languages/ru.html +++ b/app/templates/languages/ru.html @@ -97,6 +97,7 @@ "title": "Инструменты для мониторинга", "smon": { "dashboard": "SMON: Дашборд", + "status_page": "SMON: Страница статуса", "history": "SMON: История", "admin": "SMON: Админка", }, @@ -157,7 +158,7 @@ "portscanner_keep_history_range": "Время хранения истории Port scanner", "smon_keep_history_range": "Время хранения истории SMON", "checker_keep_history_range": "Время хранения истории Checker", - "checker_maxconn_threshold": "Порог срабатывания уведомления по maxconn, в %",, + "checker_maxconn_threshold": "Порог срабатывания уведомления по maxconn, в %", "checker_check_interval": "Интервал проверки для Checker (в минутах)", "smon_ssl_expire_warning_alert": "Предупреждение о истечении SSL-сертификата (в днях)", "smon_ssl_expire_critical_alert": "Критическое предупреждение о истечении SSL-сертификата (в днях)", @@ -319,6 +320,7 @@ "became_master": "Стал мастером", "resource_record_type": "Тип записи ресурса", "add_to_smon_desc": "Добавить сервер для проверки с помощью SMON ping", + "create_page_status": "Создать страницу статуса", } %} {% set roles = { @@ -586,6 +588,7 @@ "edit": "редактировать", "delete": "удалить", "add": "добавить", + "added": "добавленные", "save": "сохранить", "saved": "сохраненные", "saving": "сохранения", @@ -696,6 +699,7 @@ "virt": "вирт", "virtual": "виртуальный", "check": "проверить", + "checks": "проверки", "checking": "проверка", "protected": "защищенный", "slave_for": "Подчинен", @@ -880,5 +884,6 @@ "map": "карта", "method": "метод", "tools": "инструменты", + "next": "дальше", } %} diff --git a/app/templates/nettools.html b/app/templates/nettools.html index 0ab8161d..2b530293 100644 --- a/app/templates/nettools.html +++ b/app/templates/nettools.html @@ -18,6 +18,7 @@ border: 1px solid #ccc; } +
@@ -117,110 +118,25 @@

ICMP

+
+ + + + + + + + + + +

Port scanner

{{lang.words.server|title()}}
+ {{ input('nettools_portscanner_server', title='Enter a server for port scanning') }} + + +
+
- + {% endblock %} diff --git a/app/templates/service.html b/app/templates/service.html index 4cdb5bea..26cc180f 100644 --- a/app/templates/service.html +++ b/app/templates/service.html @@ -262,7 +262,7 @@ {% endif %}
- {% if s.3 is none %} + {% if s.3 == '' %} {{lang.words.no_desc|title()}} {% else %} {{s.3}} diff --git a/app/templates/smon/manage_status_page.html b/app/templates/smon/manage_status_page.html new file mode 100644 index 00000000..273b48f8 --- /dev/null +++ b/app/templates/smon/manage_status_page.html @@ -0,0 +1,101 @@ +{% extends "base.html" %} +{% block title %}{{ lang.menu_links.monitoring.smon.status_page }}{% endblock %} +{% block h2 %}{{ lang.menu_links.monitoring.smon.status_page }}{% endblock %} +{% block content %} +{% from 'include/input_macros.html' import input, select %} + + + + +{% if user_status == 0 or user_plan != 'support' %} + {% include 'include/no_sub.html' %} +{% elif smon_error != '' %} +
+
+

{{lang.smon_page.desc.not_installed}}

. + There is no server +

{{lang.words.read|title()}} {{lang.words.here}} + {{lang.phrases.how_to_install}} SMON {{lang.words.service}}.

+
+{% elif smon_status.0 == 'failed' or smon_status.0 == 'inactive' %} +
+
+

{{lang.smon_page.desc.smon_is_not_run}}

+ There is no server +

{{lang.smon_page.desc.run_smon}} {{lang.words.here}} {{lang.smon_page.desc.before_use}}

+
+{% elif pages|length == 0 %} +
+
+

{{lang.phrases.no_events_added}}

+ There is no server +

Click {{lang.words.here}} {{lang.smon_page.desc.see_check}}

+
+
+{% else %} +
+ {{lang.phrases.create_page_status}}
+
+ {% include 'ajax/smon/status_pages.html' %} +
+ + + +{% endif %} +{% endblock %} diff --git a/app/templates/smon/status_page.html b/app/templates/smon/status_page.html new file mode 100644 index 00000000..0fd341db --- /dev/null +++ b/app/templates/smon/status_page.html @@ -0,0 +1,57 @@ + +{% import 'languages/'+lang|default('en')+'.html' as lang %} +{% for p in page %} + + {{p.name}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Status page - {{p.name}}

+

{{p.desc|replace("'", "")}}

+ {% for check, value in checks_status.items() %} + {% if value.uptime|int() < 90 %} + {% set add_class = 'serverDown' %} + {% else %} + {% set add_class = 'serverUP' %} + {% endif %} +
+
+ {{value.uptime}}% + {{value.name}} +
+
+
+ + {% endfor %} + + +{% endfor %} diff --git a/inc/css/smon.css b/inc/css/smon.css index c7dbc2d2..8385a962 100644 --- a/inc/css/smon.css +++ b/inc/css/smon.css @@ -70,3 +70,114 @@ h4 { font-size: 13px; color: #aaa; } +.checks { + height: 400px; + overflow-y: overlay; +} +.all-checks, .enabled-check { + height: 40px; + width: 300px; +} +.enabled-check { + float: right; +} +.add_user_group{ + height: 14px; +} +.check-name { + margin-left: 15px; + margin-top: 10px; + width: 245px; + float: left; +} +.check-button { + float: left; + margin-top: 3px; +} +.add-button-status-page { + font-size: 15px; + float: unset; + margin: var(--indent); + width: fit-content; +} +.page_div { + margin: var(--indent); + border-top: 1px solid #ddd; + transition: all ease-in-out .15s; + padding: 5px 10px 10px; + margin-bottom: 0; + margin-top: 0; +} +.page_link { + color: black; + text-decoration: none !important; +} +.page_div:hover { + background-color: var(--light-blue-color); +} +.page_name { + font-size: 20px; + font-weight: 700; +} +.page_desc { + font-size: 15px; +} +.page_slug { + font-size: 10px; +} +.status-page-icon { + float: left; + margin: 10px; + margin-top: 0px; + font-size: 50px; + margin-right: 25px; + margin-left: 0; + color: var(--green-color); +} +.delete { + float: left; + margin-left: 99%; + margin-top: -45px; + font-size: 17px; + cursor: pointer; +} +.check_div { + width: 50%; + padding: 20px 30px 20px 30px; + margin-left: 20%; + margin-top: 10px; + margin-bottom: 10px; +} +.check_div:hover { + background-color: var(--light-blue-color); +} +.check_uptime { + border-radius: 10px; + padding-left: 10px; + padding-right: 10px; +} +.check_name { + margin-left: 10px; + font-size: 15px; + font-weight: 550; +} +.history_statuses { + float: right; + margin-top: -20px; +} +.smon_server_statuses { + width: 1px; + height: 10px; + margin: 1px; +} +.validateTips { + width: 575px; +} +.tooltipTop { + padding-top: 10px; + list-style: disc; + margin-left: 20px; +} +.tooltipTop { + margin-bottom: 0; +} diff --git a/inc/metrics.js b/inc/metrics.js index b22ab557..44e519bd 100644 --- a/inc/metrics.js +++ b/inc/metrics.js @@ -583,9 +583,9 @@ function updatingCpuRamCharts() { removeData(); } } -function getSmonHistoryCheckData(server, check_id) { +function getSmonHistoryCheckData(server) { $.ajax({ - url: "/app/smon/history/metric/" + server + "/" + check_id, + url: "/app/smon/history/metric/" + server, // data: { // time_range: $( "#time-range option:selected" ).val(), // }, diff --git a/inc/nettools.js b/inc/nettools.js new file mode 100644 index 00000000..efdff742 --- /dev/null +++ b/inc/nettools.js @@ -0,0 +1,140 @@ +$( function() { + $("#nettools_nslookup_record_type").selectmenu({ + width: 175 + }); + $("#nettools_telnet_form").on("click", ":submit", function (e) { + $('#ajax-nettools').html(''); + var frm = $('#nettools_telnet_form'); + if ($('#nettools_telnet_server_from option:selected').val() == '------') { + toastr.warning('Choose a server From'); + return false; + } + if ($('#nettools_telnet_server_to').val() == '') { + toastr.warning('Choose a server To'); + return false; + } + if ($('#nettools_telnet_port_to').val() == '') { + toastr.warning('Enter a port To'); + return false; + } + $.ajax({ + url: frm.attr('action'), + data: frm.serialize(), + type: frm.attr('method'), + success: function (data) { + data = data.replace('\n', "
"); + if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1' || data.indexOf('Error(s)') != '-1') { + $('#ajax-nettools').html('
' + data + '
'); + } else if (data.indexOf('warning: ') != '-1') { + toastr.clear(); + toastr.warning(data) + } else { + toastr.clear(); + if (data.indexOf('') != '-1') { + $('#ajax-nettools').html('
Connection has been successful
'); + } else { + $('#ajax-nettools').html('
Connection has been successful:

' + data + '
'); + } + } + } + }); + event.preventDefault(); + }); + $("#nettools_nslookup_form").on("click", ":submit", function (e) { + $('#ajax-nettools').html(''); + var frm = $('#nettools_nslookup_form'); + if ($('#nettools_nslookup_server_from option:selected').val() == '------') { + toastr.warning('Choose a server From'); + return false; + } + if ($('#nettools_nslookup_name').val() == '') { + toastr.warning('Enter a DNS name'); + return false; + } + $.ajax({ + url: frm.attr('action'), + data: frm.serialize(), + type: frm.attr('method'), + success: function (data) { + data = data.replace('\n', "
"); + if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1' || data.indexOf('Error(s)') != '-1') { + toastr.clear(); + toastr.error(data); + } else if (data.indexOf('warning: ') != '-1') { + toastr.clear(); + toastr.warning(data) + } else { + toastr.clear(); + $('#ajax-nettools').html('
' + data + '
'); + } + } + }); + event.preventDefault(); + }); + $("#nettools_icmp_form").on("click", ":submit", function (e) { + $('#ajax-nettools').html(''); + var frm = $('#nettools_icmp_form'); + if ($('#nettools_icmp_server_from option:selected').val() == '------') { + toastr.warning('Choose a server From'); + return false; + } + if ($('#nettools_icmp_server_to').val() == '') { + toastr.warning('Enter a server To'); + return false; + } + $.ajax({ + url: frm.attr('action'), + data: frm.serialize() + "&nettools_action=" + $(this).val(), + type: frm.attr('method'), + success: function (data) { + data = data.replace('\n', "
"); + if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1' || data.indexOf('Error(s)') != '-1') { + toastr.clear(); + toastr.error(data); + } else if (data.indexOf('warning: ') != '-1') { + toastr.clear(); + toastr.warning(data) + } else { + toastr.clear(); + $('#ajax-nettools').html('
' + data + '
'); + } + } + }); + event.preventDefault(); + }); + $("#nettools_portscanner_form").on("click", ":submit", function (e) { + $('#ajax-nettools').html(''); + if ($('#nettools_portscanner_server').val() == '') { + toastr.warning('Enter an address'); + return false; + } + $.ajax({ + url: "/app/portscanner/scan/" + $('#nettools_portscanner_server').val(), + success: function (data) { + data = data.replace(/\s+/g, ' '); + if (data.indexOf('danger') != '-1' || data.indexOf('unique') != '-1' || data.indexOf('error:') != '-1') { + toastr.error(data); + } else { + toastr.clear(); + $("#show_scans_ports_body").html(data); + var close_word = $('#translate').attr('data-close'); + $("#show_scans_ports").dialog({ + resizable: false, + height: "auto", + width: 360, + modal: true, + title: "{{lang.words.opened|title()}} {{lang.words.ports}}", + buttons: [{ + text: close_word, + click: function () { + $(this).dialog("close"); + $("#show_scans_ports_body").html(''); + } + }] + }); + } + } + }); + event.preventDefault(); + }); +}); diff --git a/inc/script.js b/inc/script.js index e3783ee7..27e97394 100644 --- a/inc/script.js +++ b/inc/script.js @@ -100,6 +100,8 @@ $( function() { show_current_page($(this)) } else if (full_uri == 'smon/history' && full_uri1 == 'smon/history') { show_current_page($(this)) + } else if (full_uri == 'smon/status-page' && full_uri1 == 'smon/status-page') { + show_current_page($(this)) } else if (full_uri == 'checker/settings' && full_uri1 == 'checker/settings') { show_current_page($(this)) } else if (full_uri == 'checker/history' && full_uri1 == 'checker/history') { diff --git a/inc/smon.js b/inc/smon.js index 800dbec3..f985365d 100644 --- a/inc/smon.js +++ b/inc/smon.js @@ -359,7 +359,6 @@ function check_and_clear_check_type(check_type) { $("#check_type").val('ping'); $('#check_type').selectmenu("refresh"); clear_check_vals(); - } } function clear_check_vals() { @@ -369,25 +368,8 @@ function clear_check_vals() { $('#new-smon-port').val(''); $('#new-smon-packet_size').val(''); } -function show_statuses(dashboard_id, check_id) { - $.ajax({ - url: "/app/smon/history/statuses/" + dashboard_id + "/" + check_id, - success: function (data) { - data = data.replace(/\s+/g, ' '); - if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { - toastr.error(data); - } else { - toastr.clear(); - $("#smon_history_statuses").html(data); - $( "[title]" ).tooltip({ - "content": function () { - return $(this).attr("data-help"); - }, - show: {"delay": 1000} - }); - } - } - }); +function show_statuses(dashboard_id, check_id, id_for_history_replace) { + show_smon_history_statuses(dashboard_id, id_for_history_replace); $.ajax({ url: "/app/smon/history/cur_status/" + dashboard_id + "/" + check_id, success: function (data) { @@ -401,3 +383,226 @@ function show_statuses(dashboard_id, check_id) { } }); } +function show_smon_history_statuses(dashboard_id, id_for_history_replace) { + $.ajax({ + url: "/app/smon/history/statuses/" + dashboard_id, + success: function (data) { + data = data.replace(/\s+/g, ' '); + if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { + toastr.error(data); + } else { + toastr.clear(); + $(id_for_history_replace).html(data); + $("[title]").tooltip({ + "content": function () { + return $(this).attr("data-help"); + }, + show: {"delay": 1000} + }); + } + } + }); +} +function createStatusPageStep1() { + var add_word = $('#translate').attr('data-next'); + var cancel_word = $('#translate').attr('data-cancel'); + var next_word = $('#translate').attr('data-next'); + var smon_add_tabel_title = $( "#create-status-page-step-1-overview" ).attr('title'); + var regx = /^[a-z0-9_-]+$/; + var addSmonStatus = $( "#create-status-page-step-1" ).dialog({ + autoOpen: false, + resizable: false, + height: "auto", + width: 630, + modal: true, + title: smon_add_tabel_title, + show: { + effect: "fade", + duration: 200 + }, + hide: { + effect: "fade", + duration: 200 + }, + buttons: [{ + text: next_word, + click: function () { + if ($('#new-status-page-name').val() == '') { + toastr.error('error: Fill in the Name field'); + return false; + } + if (!regx.test($('#new-status-page-slug').val())) { + toastr.error('error: Incorect Slug'); + return false; + } + if ($('#new-status-page-slug').val().indexOf('--') != '-1') { + toastr.error('error: "--" are prohibeted in Slug'); + return false; + } + if ($('#new-status-page-slug').val() == '') { + toastr.error('error: Fill in the Slug field'); + return false; + } + createStatusPageStep2(); + $(this).dialog("close"); + toastr.clear(); + } + }, { + text: cancel_word, + click: function () { + $(this).dialog("close"); + clearTips(); + } + }] + }); + addSmonStatus.dialog('open'); +} +function createStatusPageStep2() { + var add_word = $('#translate').attr('data-add'); + var cancel_word = $('#translate').attr('data-cancel'); + var back_word = $('#translate').attr('data-back'); + var smon_add_tabel_title = $("#create-status-page-step-2-overview").attr('title'); + var addSmonStatus = $("#create-status-page-step-2").dialog({ + autoOpen: false, + resizable: false, + height: "auto", + width: 630, + modal: true, + title: smon_add_tabel_title, + show: { + effect: "fade", + duration: 200 + }, + hide: { + effect: "fade", + duration: 200 + }, + buttons: [{ + text: add_word, + click: function () { + createStatusPage($(this)); + } + }, { + text: back_word, + click: function () { + $(this).dialog("close"); + createStatusPageStep1(); + } + }, { + text: cancel_word, + click: function () { + $(this).dialog("close"); + clearTips(); + } + }] + }); + addSmonStatus.dialog('open'); +} +function createStatusPage(dialog_id) { + let name_id = $('#new-status-page-name'); + let slug_id = $('#new-status-page-slug'); + let desc_id = $('#new-status-page-desc'); + let checks = []; + let check_id = ''; + $("#enabled-check > div").each((index, elem) => { + check_id = elem.id.split('-')[1] + checks.push(check_id); + }); + $.ajax({ + url: '/app/smon/status-page/add', + type: 'POST', + data: { + name: name_id.val(), + slug: slug_id.val(), + desc: desc_id.val(), + checks: JSON.stringify({'checks': checks}) + }, + success: function (data) { + data = data.replace(/\s+/g, ' '); + if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { + toastr.error(data); + } else { + toastr.clear(); + $("#smon_history_statuses").html(data); + for (let i = 0; i < checks.length; i++) { + removeCheckFromStatus(checks[i]); + console.log(checks[i]) + } + name_id.val(''); + slug_id.val(''); + dialog_id.dialog("close"); + $("#pages").append(data); + setTimeout(function () { + $("#user-" + id).removeClass("update"); + }, 2500); + $.getScript("/inc/fontawesome.min.js"); + } + } + }); +} +function addCheckToStatus(service_id) { + var service_name = $('#add_check-' + service_id).attr('data-service_name'); + var delete_word = $('#translate').attr('data-delete'); + var service_word = $('#translate').attr('data-service'); + var length_tr = $('#all-checks').length; + var tr_class = 'odd'; + if (length_tr % 2 != 0) { + tr_class = 'even'; + } + var html_tag = '
' + + '
' + service_name + '
' + + '
-
'; + $('#add_check-' + service_id).remove(); + $("#enabled-check").append(html_tag); +} +function removeCheckFromStatus(service_id) { + var service_name = $('#remove_check-' + service_id).attr('data-service_name'); + var add_word = $('#translate').attr('data-add'); + var service_word = $('#translate').attr('data-service'); + var length_tr = $('#all_services tbody tr').length; + var tr_class = 'odd'; + if (length_tr % 2 != 0) { + tr_class = 'even'; + } + var html_tag = '
' + + '
' + service_name + '
' + + '
+
'; + $('#remove_check-' + service_id).remove(); + $("#all-checks").append(html_tag); +} +function confirmDeleteStatusPage(id) { + var delete_word = $('#translate').attr('data-delete'); + var cancel_word = $('#translate').attr('data-cancel'); + $("#dialog-confirm").dialog({ + resizable: false, + height: "auto", + width: 400, + modal: true, + title: delete_word + " " + $('#page_name-' + id).text() + "?", + buttons: [{ + text: delete_word, + click: function () { + $(this).dialog("close"); + deleteStatusPage(id); + } + }, { + text: cancel_word, + click: function () { + $(this).dialog("close"); + } + }] + }); +} +function deleteStatusPage(page_id) { + $.ajax({ + url: '/app/smon/status-page/delete/' + page_id, + success: function (data) { + data = data.replace(/\s+/g, ' '); + if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { + toastr.error(data); + } else { + $('#page_' + page_id).remove(); + } + } + }); +}