v6.3.13.0

Changelog: https://roxy-wi.org/changelog#6_3_13
pull/364/head
Aidaho 2023-06-03 18:04:22 +03:00
parent 13b9f36c04
commit 5120e0a200
25 changed files with 1396 additions and 342 deletions

View File

@ -827,9 +827,96 @@ def update_db_v_6_3_12():
else: else:
print("Updating... DB has been updated to version 6.3.12") print("Updating... DB has been updated to version 6.3.12")
def update_db_v_6_3_13():
cursor = conn.cursor()
sql = """
ALTER TABLE `smon` ADD COLUMN check_type VARCHAR ( 64 ) DEFAULT 'tcp';
"""
try:
cursor.execute(sql)
except Exception as e:
if e.args[0] == 'duplicate column name: check_type' or str(e) == '(1060, "Duplicate column name \'check_type\'")':
print('Updating... DB has been updated to version 6.3.13')
else:
print("An error occurred:", e)
else:
print("Updating... DB has been updated to version 6.3.13")
def update_db_v_6_3_13_1():
try:
SmonTcpCheck.insert_from(
SMON.select(SMON.id, SMON.ip, SMON.port).where(
(SMON.http == '') & (SMON.check_type == 'tcp')
), fields=[SmonTcpCheck.smon_id, SmonTcpCheck.ip, SmonTcpCheck.port]
).on_conflict_ignore().execute()
except Exception as e:
if e.args[0] == 'duplicate column name: haproxy' or str(e) == 'type object \'SMON\' has no attribute \'ip\'':
print('Updating... DB has been updated to version 6.3.13-1')
else:
print("An error occurred:", e)
def update_db_v_6_3_13_2():
query = SMON.select().where(SMON.http != '')
try:
query_res = query.execute()
except Exception as e:
print("An error occurred:", e)
else:
for i in query_res:
try:
proto = i.http.split(':')[0]
uri = i.http.split(':')[1]
except Exception:
proto = ''
uri = ''
url = f'{proto}://{i.name}:{i.port}{uri}'
SmonHttpCheck.insert(smon_id=i.id, url=url, body=i.body).on_conflict_ignore().execute()
def update_db_v_6_3_13_3():
try:
SmonPingCheck.insert_from(
SMON.select(SMON.id, SMON.ip).where(SMON.check_type == 'ping'), fields=[SmonPingCheck.smon_id, SmonPingCheck.ip]
).on_conflict_ignore().execute()
except Exception as e:
if e.args[0] == 'duplicate column name: haproxy' or str(e) == 'type object \'SMON\' has no attribute \'ip\'':
print('Updating... DB has been updated to version 6.3.13-2')
else:
print("An error occurred:", e)
def update_db_v_6_3_13_4():
try:
migrate(
migrator.alter_column_type('smon', 'time_state', DateTimeField()),
migrator.rename_column('smon', 'ip', 'name'),
migrator.drop_column('smon', 'script', cascade=False),
migrator.drop_column('smon', 'http_status', cascade=False),
)
except Exception as e:
if e.args[0] == 'duplicate column name: check_type' or str(e) == '(1091, "Can\'t DROP COLUMN `script`; check that it exists")':
print('Updating... DB has been updated to version 6.3.13-3')
elif e.args[0] == 'duplicate column name: check_type' or str(e) == '(1091, "Can\'t DROP COLUMN `http_status`; check that it exists")':
print('Updating... DB has been updated to version 6.3.13-3')
elif e.args[0] == 'duplicate column name: check_type' or str(e) == "'bool' object has no attribute 'sql'":
print('Updating... DB has been updated to version 6.3.13-3')
else:
print("An error occurred:", e)
def update_db_v_6_3_13_5():
try:
SMON.update(check_type='http').where(SMON.http != '').execute()
except Exception:
print("An error occurred:", e)
def update_ver(): def update_ver():
try: try:
Version.update(version='6.3.12.0').execute() Version.update(version='6.3.13.0').execute()
except Exception: except Exception:
print('Cannot update version') print('Cannot update version')
@ -860,6 +947,12 @@ def update_all():
update_db_v_6_3_9() update_db_v_6_3_9()
update_db_v_6_3_11() update_db_v_6_3_11()
update_db_v_6_3_12() update_db_v_6_3_12()
update_db_v_6_3_13()
update_db_v_6_3_13_1()
update_db_v_6_3_13_2()
update_db_v_6_3_13_3()
update_db_v_6_3_13_4()
update_db_v_6_3_13_5()
update_ver() update_ver()

View File

@ -1,4 +1,5 @@
from peewee import * from peewee import *
from playhouse.migrate import *
from datetime import datetime from datetime import datetime
import modules.roxy_wi_tools as roxy_wi_tools import modules.roxy_wi_tools as roxy_wi_tools
@ -13,9 +14,11 @@ if mysql_enable == '1':
mysql_host = get_config.get_config_var('mysql', 'mysql_host') mysql_host = get_config.get_config_var('mysql', 'mysql_host')
mysql_port = get_config.get_config_var('mysql', 'mysql_port') mysql_port = get_config.get_config_var('mysql', 'mysql_port')
conn = MySQLDatabase(mysql_db, user=mysql_user, password=mysql_password, host=mysql_host, port=int(mysql_port)) conn = MySQLDatabase(mysql_db, user=mysql_user, password=mysql_password, host=mysql_host, port=int(mysql_port))
migrator = MySQLMigrator(conn)
else: else:
db = "/var/lib/roxy-wi/roxy-wi.db" db = "/var/lib/roxy-wi/roxy-wi.db"
conn = SqliteDatabase(db, pragmas={'timeout': 1000, 'foreign_keys': 1}) conn = SqliteDatabase(db, pragmas={'timeout': 1000, 'foreign_keys': 1})
migrator = SqliteMigrator(conn)
class BaseModel(Model): class BaseModel(Model):
@ -412,17 +415,15 @@ class MetricsHttpStatus(BaseModel):
class SMON(BaseModel): class SMON(BaseModel):
id = AutoField() id = AutoField()
ip = CharField(null=True) name = CharField(null=True)
port = IntegerField(null=True) port = IntegerField(null=True)
status = IntegerField(constraints=[SQL('DEFAULT 1')]) status = IntegerField(constraints=[SQL('DEFAULT 1')])
en = IntegerField(constraints=[SQL('DEFAULT 1')]) en = IntegerField(constraints=[SQL('DEFAULT 1')])
desc = CharField(null=True) desc = CharField(null=True)
response_time = CharField(null=True) response_time = CharField(null=True)
time_state = IntegerField(constraints=[SQL('DEFAULT 0')]) time_state = DateTimeField(constraints=[SQL('DEFAULT "0000-00-00 00:00:00"')])
group = CharField(null=True) group = CharField(null=True)
script = CharField(null=True)
http = CharField(null=True) http = CharField(null=True)
http_status = IntegerField(constraints=[SQL('DEFAULT 1')])
body = CharField(null=True) body = CharField(null=True)
body_status = IntegerField(constraints=[SQL('DEFAULT 1')]) body_status = IntegerField(constraints=[SQL('DEFAULT 1')])
telegram_channel_id = IntegerField(null=True) telegram_channel_id = IntegerField(null=True)
@ -432,6 +433,7 @@ class SMON(BaseModel):
ssl_expire_critical_alert = IntegerField(constraints=[SQL('DEFAULT 0')]) ssl_expire_critical_alert = IntegerField(constraints=[SQL('DEFAULT 0')])
ssl_expire_date = CharField(null=True) ssl_expire_date = CharField(null=True)
pd_channel_id = IntegerField(null=True) pd_channel_id = IntegerField(null=True)
check_type = CharField(constraints=[SQL('DEFAULT tcp')])
class Meta: class Meta:
table_name = 'smon' table_name = 'smon'
@ -602,6 +604,51 @@ class KeepaliveRestart(BaseModel):
constraints = [SQL('UNIQUE (server_id, service)')] constraints = [SQL('UNIQUE (server_id, service)')]
class SmonHistory(BaseModel):
smon_id = ForeignKeyField(SMON, on_delete='Cascade')
check_id = IntegerField()
response_time = FloatField()
status = IntegerField()
mes = CharField()
date = DateTimeField(default=datetime.now)
class Meta:
table_name = 'smon_history'
primary_key = False
class SmonTcpCheck(BaseModel):
smon_id = ForeignKeyField(SMON, on_delete='Cascade', unique=True)
ip = CharField()
port = IntegerField()
class Meta:
table_name = 'smon_tcp_check'
primary_key = False
class SmonHttpCheck(BaseModel):
smon_id = ForeignKeyField(SMON, on_delete='Cascade', unique=True)
url = CharField()
method = CharField(constraints=[SQL('DEFAULT "get"')])
accepted_status_codes = CharField(constraints=[SQL('DEFAULT "200"')])
body = CharField(null=True)
class Meta:
table_name = 'smon_http_check'
primary_key = False
class SmonPingCheck(BaseModel):
smon_id = ForeignKeyField(SMON, on_delete='Cascade', unique=True)
ip = CharField()
packet_size = IntegerField(constraints=[SQL('DEFAULT 56')])
class Meta:
table_name = 'smon_ping_check'
primary_key = False
def create_tables(): def create_tables():
with conn: with conn:
conn.create_tables([User, Server, Role, Telegram, Slack, UUID, Token, ApiToken, Groups, UserGroups, ConfigVersion, conn.create_tables([User, Server, Role, Telegram, Slack, UUID, Token, ApiToken, Groups, UserGroups, ConfigVersion,
@ -609,4 +656,5 @@ def create_tables():
PortScannerSettings, PortScannerPorts, PortScannerHistory, ProvidersCreds, ServiceSetting, PortScannerSettings, PortScannerPorts, PortScannerHistory, ProvidersCreds, ServiceSetting,
ProvisionedServers, MetricsHttpStatus, SMON, WafRules, Alerts, GeoipCodes, NginxMetrics, ProvisionedServers, MetricsHttpStatus, SMON, WafRules, Alerts, GeoipCodes, NginxMetrics,
SystemInfo, Services, UserName, GitSetting, CheckerSetting, ApacheMetrics, ProvisionParam, SystemInfo, Services, UserName, GitSetting, CheckerSetting, ApacheMetrics, ProvisionParam,
WafNginx, ServiceStatus, KeepaliveRestart, PD]) WafNginx, ServiceStatus, KeepaliveRestart, PD, SmonHistory, SmonTcpCheck, SmonHttpCheck,
SmonPingCheck])

View File

@ -2474,16 +2474,11 @@ def check_token_exists(token):
return False return False
def insert_smon(server, port, enable, proto, uri, body, group, desc, telegram, slack, pd, user_group): def insert_smon(name, enable, group, desc, telegram, slack, pd, user_group, check_type):
try:
http = proto + ':' + uri
except Exception:
http = ''
try: try:
last_id = SMON.insert( last_id = SMON.insert(
ip=server, port=port, en=enable, desc=desc, group=group, http=http, body=body, name=name, en=enable, desc=desc, group=group, telegram_channel_id=telegram, slack_channel_id=slack,
telegram_channel_id=telegram, slack_channel_id=slack, pd_channel_id=pd, user_group=user_group, status='3' pd_channel_id=pd, user_group=user_group, status='3', check_type=check_type
).execute() ).execute()
except Exception as e: except Exception as e:
out_error(e) out_error(e)
@ -2492,50 +2487,136 @@ def insert_smon(server, port, enable, proto, uri, body, group, desc, telegram, s
return last_id return last_id
def select_smon(user_group, **kwargs): def insert_smon_ping(smon_id, hostname):
cursor = conn.cursor()
if user_group == 1:
user_group = ''
else:
if kwargs.get('ip'):
user_group = f"and user_group = '{user_group}'"
else:
user_group = f"where user_group = '{user_group}'"
if kwargs.get('ip'):
try:
http = kwargs.get('proto') + ':' + kwargs.get('uri')
except Exception:
http = ''
sql = """select id, ip, port, en, http, body, telegram_channel_id, `desc`, `group`, user_group, slack_channel_id, pd_channel_id from smon
where ip='%s' and port='%s' and http='%s' and body='%s' %s
""" % (kwargs.get('ip'), kwargs.get('port'), http, body, user_group)
elif kwargs.get('action') == 'add':
sql = """select id, ip, port, en, http, body, telegram_channel_id, `desc`, `group`, user_group, slack_channel_id, pd_channel_id from smon
%s order by `group`""" % user_group
else:
sql = """select * from `smon` %s """ % user_group
try: try:
cursor.execute(sql) SmonPingCheck.insert(smon_id=smon_id, ip=hostname).execute()
except Exception as e:
out_error(e)
def insert_smon_tcp(smon_id, hostname, port):
try:
SmonTcpCheck.insert(smon_id=smon_id, ip=hostname, port=port).execute()
except Exception as e:
out_error(e)
def insert_smon_http(smon_id, url, body):
try:
SmonHttpCheck.insert(smon_id=smon_id, url=url, body=body).execute()
except Exception as e:
out_error(e)
def select_smon(user_group):
if user_group == 1:
query = SMON.select()
else:
query = SMON.select().where(SMON.user_group == user_group)
try:
query_res = query.execute()
except Exception as e: except Exception as e:
out_error(e) out_error(e)
else: else:
return cursor.fetchall() return query_res
def select_smon_ping(user_group):
if user_group == 1:
query = SmonPingCheck.select()
else:
query = SmonPingCheck.select().where(SMON.user_group == user_group)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_en_smon_ping() -> object:
query = SmonPingCheck.select(SmonPingCheck, SMON).join_from(SmonPingCheck, SMON).where(SMON.en == '1')
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_en_smon_tcp() -> object:
query = SmonTcpCheck.select(SmonTcpCheck, SMON).join_from(SmonTcpCheck, SMON).where(SMON.en == '1')
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_en_smon_http() -> object:
query = SmonHttpCheck.select(SmonHttpCheck, SMON).join_from(SmonHttpCheck, SMON).where(SMON.en == '1')
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_smon_tcp(user_group):
if user_group == 1:
query = SmonTcpCheck.select()
else:
query = SmonTcpCheck.select().where(SMON.user_group == user_group)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_smon_http(user_group):
if user_group == 1:
query = SmonHttpCheck.select()
else:
query = SmonHttpCheck.select().where(SMON.user_group == user_group)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_smon_by_id(last_id): def select_smon_by_id(last_id):
cursor = conn.cursor() query = SMON.select().where(SMON.id == last_id)
sql = """select id, ip, port, en, http, body, telegram_channel_id, `desc`, `group`, user_group, slack_channel_id, pd_channel_id
from `smon` where id = {} """.format(last_id)
try: try:
cursor.execute(sql) query_res = query.execute()
except Exception as e: except Exception as e:
out_error(e) out_error(e)
else: else:
return cursor.fetchall() return query_res
def select_smon_check_by_id(last_id, check_type):
if check_type == 'ping':
query = SmonPingCheck.select().where(SmonPingCheck.smon_id == last_id)
elif check_type == 'tcp':
query = SmonTcpCheck.select().where(SmonTcpCheck.smon_id == last_id)
else:
query = SmonHttpCheck.select().where(SmonHttpCheck.smon_id == last_id)
print(query)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def delete_smon(smon_id, user_group): def delete_smon(smon_id, user_group):
@ -2549,9 +2630,39 @@ def delete_smon(smon_id, user_group):
return True return True
def update_smon(smon_id, ip, port, body, telegram, slack, pd, group, desc, en): def update_smonHttp(smon_id, url, body):
query = (SmonHttpCheck.update(url=url, body=body).where(SmonHttpCheck.smon_id == smon_id))
try:
query.execute()
return True
except Exception as e:
out_error(e)
return False
def update_smonTcp(smon_id, ip, port):
query = (SmonTcpCheck.update(ip=ip, port=port).where(SmonTcpCheck.smon_id == smon_id))
try:
query.execute()
return True
except Exception as e:
out_error(e)
return False
def update_smonPing(smon_id, ip, port):
query = (SmonPingCheck.update(ip=ip).where(SmonPingCheck.smon_id == smon_id))
try:
query.execute()
return True
except Exception as e:
out_error(e)
return False
def update_smon(smon_id, name, telegram, slack, pd, group, desc, en):
query = (SMON.update( query = (SMON.update(
ip=ip, port=port, body=body, telegram_channel_id=telegram, slack_channel_id=slack, pd_channel_id=pd, group=group, desc=desc, en=en name=name, telegram_channel_id=telegram, slack_channel_id=slack, pd_channel_id=pd, group=group, desc=desc, en=en
).where(SMON.id == smon_id)) ).where(SMON.id == smon_id))
try: try:
query.execute() query.execute()
@ -2587,16 +2698,6 @@ def alerts_history(service, user_group, **kwargs):
return cursor.fetchall() return cursor.fetchall()
def select_en_service():
query = SMON.select().where(SMON.en == 1)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_status(smon_id): def select_status(smon_id):
try: try:
query_res = SMON.get(SMON.id == smon_id).status query_res = SMON.get(SMON.id == smon_id).status
@ -2662,17 +2763,6 @@ def change_status(status, smon_id):
return True return True
def change_http_status(status, smon_id):
query = SMON.update(http_status=status).where(SMON.id == smon_id)
try:
query.execute()
except Exception as e:
out_error(e)
return False
else:
return True
def change_body_status(status, smon_id): def change_body_status(status, smon_id):
query = SMON.update(body_status=status).where(SMON.id == smon_id) query = SMON.update(body_status=status).where(SMON.id == smon_id)
try: try:
@ -2719,15 +2809,9 @@ def response_time(time, smon_id):
def smon_list(user_group): def smon_list(user_group):
if user_group == 1: if user_group == 1:
query = (SMON.select( query = (SMON.select().order_by(SMON.group))
SMON.ip, SMON.port, SMON.status, SMON.en, SMON.desc, SMON.response_time, SMON.time_state,
SMON.group, SMON.script, SMON.http, SMON.http_status, SMON.body, SMON.body_status, SMON.ssl_expire_date
).order_by(SMON.group))
else: else:
query = (SMON.select( query = (SMON.select().where(SMON.user_group == user_group).order_by(SMON.group))
SMON.ip, SMON.port, SMON.status, SMON.en, SMON.desc, SMON.response_time, SMON.time_state,
SMON.group, SMON.script, SMON.http, SMON.http_status, SMON.body, SMON.body_status
).where(SMON.user_group == user_group).order_by(SMON.group))
try: try:
query_res = query.execute() query_res = query.execute()
@ -2737,6 +2821,139 @@ def smon_list(user_group):
return query_res return query_res
def select_one_smon(smon_id: int, check_id: int) -> object:
if check_id == 1:
query = SmonTcpCheck.select(SmonTcpCheck, SMON).join_from(SmonTcpCheck, SMON).where(SMON.id == smon_id)
elif check_id == 2:
query = SmonHttpCheck.select(SmonHttpCheck, SMON).join_from(SmonHttpCheck, SMON).where(SMON.id == smon_id)
else:
query = SmonPingCheck.select(SmonPingCheck, SMON).join_from(SmonPingCheck, SMON).where(SMON.id == smon_id)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def insert_smon_history(smon_id: int, response_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,
check_id=check_id, mes=mes).execute()
except Exception as e:
out_error(e)
def select_smon_history(smon_id: int, check_id: int) -> object:
query = SmonHistory.select().where(
(SmonHistory.smon_id == smon_id) &
(SmonHistory.check_id == check_id)
).limit(40).order_by(SmonHistory.date.desc())
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def get_last_smon_status_by_check(smon_id: int, check_id: int) -> object:
query = SmonHistory.select().where(
(SmonHistory.smon_id == smon_id) &
(SmonHistory.check_id == check_id)
).limit(1).order_by(SmonHistory.date.desc())
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
try:
for i in query_res:
return i.status
except Exception:
return ''
def get_last_smon_res_time_by_check(smon_id: int, check_id: int) -> object:
query = SmonHistory.select().where(
(SmonHistory.smon_id == smon_id) &
(SmonHistory.check_id == check_id)
).limit(1).order_by(SmonHistory.date.desc())
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
try:
for i in query_res:
return i.response_time
except Exception:
return ''
def get_smon_history_count_checks(smon_id: int, check_id: int) -> dict:
count_checks = {}
query = SmonHistory.select(fn.Count(SmonHistory.status)).where(
(SmonHistory.smon_id == smon_id) &
(SmonHistory.check_id == check_id)
)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
try:
for i in query_res:
count_checks['total'] = i.status
except Exception as e:
raise Exception(f'error: {e}')
query = SmonHistory.select(fn.Count(SmonHistory.status)).where(
(SmonHistory.smon_id == smon_id) &
(SmonHistory.check_id == check_id) &
(SmonHistory.status == 1)
)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
try:
for i in query_res:
count_checks['up'] = i.status
except Exception as e:
raise Exception(f'error: {e}')
return count_checks
def get_smon_service_name_by_id(smon_id: int) -> str:
query = SMON.select().join(SmonHistory, on=(SmonHistory.smon_id == SMON.id)).where(SmonHistory.smon_id == smon_id)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
try:
for i in query_res:
return f'{i.name}'
except Exception:
return ''
def get_avg_resp_time(smon_id: int, check_id: int) -> object:
try:
query_res = SmonHistory.select(fn.AVG(SmonHistory.response_time)).where(
(SmonHistory.smon_id == smon_id) &
(SmonHistory.check_id == check_id)
).scalar()
except Exception as e:
out_error(e)
else:
return query_res
def insert_alerts(user_group, level, ip, port, message, service): def insert_alerts(user_group, level, ip, port, message, service):
cur_date = get_date.return_date('regular') cur_date = get_date.return_date('regular')
try: try:
@ -3691,6 +3908,19 @@ def select_user_name():
return query_res return query_res
def get_super_admin_count() -> int:
query = UserGroups.select(UserGroups.user_id, UserGroups.user_role_id).distinct().where(UserGroups.user_role_id == 1).group_by(UserGroups.user_id)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
try:
return len(list(query_res))
except Exception as e:
raise Exception(f'error: {e}')
def update_user_name(user_name): def update_user_name(user_name):
user_update = UserName.update(UserName=user_name) user_update = UserName.update(UserName=user_name)
try: try:
@ -3967,31 +4197,31 @@ def inset_or_update_service_status(
out_error(e) out_error(e)
def update_smon_ssl_expire_date(service_ip: str, expire_date: str) -> None: def update_smon_ssl_expire_date(smon_id: str, expire_date: str) -> None:
SMON_update = SMON.update(ssl_expire_date=expire_date).where(SMON.ip == service_ip) SMON_update = SMON.update(ssl_expire_date=expire_date).where(SMON.id == smon_id)
try: try:
SMON_update.execute() SMON_update.execute()
except Exception as e: except Exception as e:
out_error(e) out_error(e)
def update_smon_alert_status(service_ip: str, alert_value: int, alert: str) -> None: def update_smon_alert_status(smon_id: str, alert_value: int, alert: str) -> None:
if alert == 'ssl_expire_warning_alert': if alert == 'ssl_expire_warning_alert':
SMON_update = SMON.update(ssl_expire_warning_alert=alert_value).where(SMON.ip == service_ip) SMON_update = SMON.update(ssl_expire_warning_alert=alert_value).where(SMON.id == smon_id)
else: else:
SMON_update = SMON.update(ssl_expire_critical_alert=alert_value).where(SMON.ip == service_ip) SMON_update = SMON.update(ssl_expire_critical_alert=alert_value).where(SMON.id == smon_id)
try: try:
SMON_update.execute() SMON_update.execute()
except Exception as e: except Exception as e:
out_error(e) out_error(e)
def get_smon_alert_status(service_ip: str, alert: str) -> int: def get_smon_alert_status(smon_id: str, alert: str) -> int:
try: try:
if alert == 'ssl_expire_warning_alert': if alert == 'ssl_expire_warning_alert':
alert_value = SMON.get(SMON.ip == service_ip).ssl_expire_warning_alert alert_value = SMON.get(SMON.id == smon_id).ssl_expire_warning_alert
else: else:
alert_value = SMON.get(SMON.ip == service_ip).ssl_expire_critical_alert alert_value = SMON.get(SMON.id == smon_id).ssl_expire_critical_alert
except Exception as e: except Exception as e:
out_error(e) out_error(e)
else: else:

View File

@ -47,7 +47,10 @@ def create_user(new_user: str, email: str, password: str, role: str, activeuser:
def delete_user(): def delete_user():
userdel = form.getvalue('userdel') userdel = int(form.getvalue('userdel'))
count_super_admin_users = sql.get_super_admin_count()
if count_super_admin_users < 2:
raise Exception('error: you cannot delete a last user with superAdmin role')
user = sql.select_users(id=userdel) user = sql.select_users(id=userdel)
username = '' username = ''
for u in user: for u in user:

View File

@ -1,3 +1,5 @@
import json
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
import modules.db.sql as sql import modules.db.sql as sql
@ -9,80 +11,93 @@ form = common.form
def create_smon() -> None: def create_smon() -> None:
user_group = roxywi_common.get_user_group(id=1) user_group = roxywi_common.get_user_group(id=1)
server = common.checkAjaxInput(form.getvalue('newsmon')) name = common.checkAjaxInput(form.getvalue('newsmonname'))
hostname = common.checkAjaxInput(form.getvalue('newsmon'))
port = common.checkAjaxInput(form.getvalue('newsmonport')) port = common.checkAjaxInput(form.getvalue('newsmonport'))
enable = common.checkAjaxInput(form.getvalue('newsmonenable')) enable = common.checkAjaxInput(form.getvalue('newsmonenable'))
http = common.checkAjaxInput(form.getvalue('newsmonproto')) url = common.checkAjaxInput(form.getvalue('newsmonurl'))
uri = common.checkAjaxInput(form.getvalue('newsmonuri'))
body = common.checkAjaxInput(form.getvalue('newsmonbody')) body = common.checkAjaxInput(form.getvalue('newsmonbody'))
group = common.checkAjaxInput(form.getvalue('newsmongroup')) group = common.checkAjaxInput(form.getvalue('newsmongroup'))
desc = common.checkAjaxInput(form.getvalue('newsmondescription')) desc = common.checkAjaxInput(form.getvalue('newsmondescription'))
telegram = common.checkAjaxInput(form.getvalue('newsmontelegram')) telegram = common.checkAjaxInput(form.getvalue('newsmontelegram'))
slack = common.checkAjaxInput(form.getvalue('newsmonslack')) slack = common.checkAjaxInput(form.getvalue('newsmonslack'))
pd = common.checkAjaxInput(form.getvalue('newsmonpd')) pd = common.checkAjaxInput(form.getvalue('newsmonpd'))
check_type = common.checkAjaxInput(form.getvalue('newsmonchecktype'))
try: if check_type == 'tcp':
port = int(port) try:
except Exception: port = int(port)
print('SMON error: port must number') except Exception:
return None print('SMON error: port must number')
if port > 65535 or port < 0: return None
print('SMON error: port must be 0-65535') if port > 65535 or port < 0:
return None print('SMON error: port must be 0-65535')
if port == 80 and http == 'https': return None
print('SMON error: Cannot be HTTPS with 80 port')
return None last_id = sql.insert_smon(name, enable, group, desc, telegram, slack, pd, user_group, check_type)
if port == 443 and http == 'http':
print('SMON error: Cannot be HTTP with 443 port') if check_type == 'ping':
return None sql.insert_smon_ping(last_id, hostname)
elif check_type == 'tcp':
sql.insert_smon_tcp(last_id, hostname, port)
elif check_type == 'http':
sql.insert_smon_http(last_id, url, body)
last_id = sql.insert_smon(server, port, enable, http, uri, body, group, desc, telegram, slack, pd, user_group)
if last_id: if last_id:
lang = roxywi_common.get_user_lang() lang = roxywi_common.get_user_lang()
smon = sql.select_smon_by_id(last_id) smon = sql.select_smon_by_id(last_id)
pds = sql.get_user_pd_by_group(user_group) pds = sql.get_user_pd_by_group(user_group)
slacks = sql.get_user_slack_by_group(user_group) slacks = sql.get_user_slack_by_group(user_group)
telegrams = sql.get_user_telegram_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)
env = Environment(loader=FileSystemLoader('templates'), autoescape=True) env = Environment(loader=FileSystemLoader('templates'), autoescape=True)
template = env.get_template('ajax/show_new_smon.html') template = env.get_template('ajax/show_new_smon.html')
template = template.render(smon=smon, telegrams=telegrams, slacks=slacks, pds=pds, lang=lang) template = template.render(smon=smon, telegrams=telegrams, slacks=slacks, pds=pds, lang=lang, check_type=check_type,
smon_service=smon_service)
print(template) print(template)
roxywi_common.logging('SMON', f' A new server {server} to SMON has been add ', roxywi=1, login=1) roxywi_common.logging('SMON', f' A new server {name} to SMON has been add ', roxywi=1, login=1)
def update_smon() -> None: def update_smon() -> None:
smon_id = common.checkAjaxInput(form.getvalue('id')) smon_id = common.checkAjaxInput(form.getvalue('id'))
name = common.checkAjaxInput(form.getvalue('updateSmonName'))
ip = common.checkAjaxInput(form.getvalue('updateSmonIp')) ip = common.checkAjaxInput(form.getvalue('updateSmonIp'))
port = common.checkAjaxInput(form.getvalue('updateSmonPort')) port = common.checkAjaxInput(form.getvalue('updateSmonPort'))
en = common.checkAjaxInput(form.getvalue('updateSmonEn')) en = common.checkAjaxInput(form.getvalue('updateSmonEn'))
http = common.checkAjaxInput(form.getvalue('updateSmonHttp')) url = common.checkAjaxInput(form.getvalue('updateSmonUrl'))
body = common.checkAjaxInput(form.getvalue('updateSmonBody')) body = common.checkAjaxInput(form.getvalue('updateSmonBody'))
telegram = common.checkAjaxInput(form.getvalue('updateSmonTelegram')) telegram = common.checkAjaxInput(form.getvalue('updateSmonTelegram'))
slack = common.checkAjaxInput(form.getvalue('updateSmonSlack')) slack = common.checkAjaxInput(form.getvalue('updateSmonSlack'))
pd = common.checkAjaxInput(form.getvalue('updateSmonPD')) pd = common.checkAjaxInput(form.getvalue('updateSmonPD'))
group = common.checkAjaxInput(form.getvalue('updateSmonGroup')) group = common.checkAjaxInput(form.getvalue('updateSmonGroup'))
desc = common.checkAjaxInput(form.getvalue('updateSmonDesc')) desc = common.checkAjaxInput(form.getvalue('updateSmonDesc'))
check_type = common.checkAjaxInput(form.getvalue('check_type'))
is_edited = False
if check_type == 'tcp':
try:
port = int(port)
except Exception:
print('SMON error: port must number')
return None
if port > 65535 or port < 0:
print('SMON error: port must be 0-65535')
return None
try:
port = int(port)
except Exception:
print('SMON error: port must number')
return None
if port > 65535 or port < 0:
print('SMON error: port must be 0-65535')
return None
if port == 80 and http == 'https':
print('SMON error: Cannot be https with 80 port')
return None
if port == 443 and http == 'http':
print('SMON error: Cannot be HTTP with 443 port')
return None
roxywi_common.check_user_group() roxywi_common.check_user_group()
try: try:
if sql.update_smon(smon_id, ip, port, body, telegram, slack, pd, group, desc, en): if sql.update_smon(smon_id, name, telegram, slack, pd, group, desc, en):
print("Ok") if check_type == 'http':
roxywi_common.logging('SMON', f' The SMON server {ip} has been update ', roxywi=1, login=1) is_edited = sql.update_smonHttp(smon_id, url, body)
elif check_type == 'tcp':
is_edited = sql.update_smonTcp(smon_id, ip, port)
elif check_type == 'ping':
is_edited = sql.update_smonTcp(smon_id, ip)
if is_edited:
print("Ok")
roxywi_common.logging('SMON', f' The SMON server {name} has been update ', roxywi=1, login=1)
except Exception as e: except Exception as e:
print(e) print(e)
@ -108,3 +123,21 @@ def delete_smon() -> None:
roxywi_common.logging('SMON', ' The server from SMON has been delete ', roxywi=1, login=1) roxywi_common.logging('SMON', ' The server from SMON has been delete ', roxywi=1, login=1)
except Exception as e: except Exception as e:
print(e) print(e)
def history_metrics(server_id: int, check_id: int) -> None:
metric = sql.select_smon_history(server_id, check_id)
metrics = {'chartData': {}}
metrics['chartData']['labels'] = {}
labels = ''
curr_con = ''
for i in reversed(metric):
labels += f'{i.date.time()},'
curr_con += f'{i.response_time},'
metrics['chartData']['labels'] = labels
metrics['chartData']['curr_con'] = curr_con
print(json.dumps(metrics))

View File

@ -31,7 +31,7 @@ token = form.getvalue("token")
if any(( if any((
form.getvalue('new_metrics'), form.getvalue('new_http_metrics'), form.getvalue('new_waf_metrics'), form.getvalue('new_nginx_metrics'), form.getvalue('new_metrics'), form.getvalue('new_http_metrics'), form.getvalue('new_waf_metrics'), form.getvalue('new_nginx_metrics'),
form.getvalue('new_apache_metrics'), form.getvalue('metrics_hapwi_ram'), form.getvalue('metrics_hapwi_cpu'), form.getvalue('getoption'), form.getvalue('new_apache_metrics'), form.getvalue('metrics_hapwi_ram'), form.getvalue('metrics_hapwi_cpu'), form.getvalue('getoption'),
form.getvalue('getsavedserver')) form.getvalue('getsavedserver'), form.getvalue('smon_history_check'))
): ):
print('Content-type: application/json\n') print('Content-type: application/json\n')
else: else:
@ -981,7 +981,7 @@ if form.getvalue('getcurrentusergroup') is not None:
roxy_user.get_user_active_group(user_id, group) roxy_user.get_user_active_group(user_id, group)
if form.getvalue('newsmon') is not None: if form.getvalue('newsmonname') is not None:
import modules.tools.smon as smon_mod import modules.tools.smon as smon_mod
smon_mod.create_smon() smon_mod.create_smon()
@ -996,11 +996,18 @@ if form.getvalue('showsmon') is not None:
smon_mod.show_smon() smon_mod.show_smon()
if form.getvalue('updateSmonIp') is not None: if form.getvalue('updateSmonName') is not None:
import modules.tools.smon as smon_mod import modules.tools.smon as smon_mod
smon_mod.update_smon() smon_mod.update_smon()
if form.getvalue('smon_history_check') is not None:
import modules.tools.smon as smon_mod
server_id = int(form.getvalue('server_id'))
check_id = int(form.getvalue('check_id'))
smon_mod.history_metrics(server_id, check_id)
if form.getvalue('showBytes') is not None: if form.getvalue('showBytes') is not None:
import modules.roxywi.overview as roxywi_overview import modules.roxywi.overview as roxywi_overview

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys import sys
from datetime import datetime
from pytz import timezone
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
import modules.db.sql as sql import modules.db.sql as sql
@ -33,13 +35,26 @@ pds = ''
user_group = roxywi_common.get_user_group(id=1) user_group = roxywi_common.get_user_group(id=1)
cmd = "systemctl is-active roxy-wi-smon" cmd = "systemctl is-active roxy-wi-smon"
smon_status, stderr = server_mod.subprocess_execute(cmd) smon_status, stderr = server_mod.subprocess_execute(cmd)
smon_statuses = ''
smon_ping = ''
smon_tcp = ''
smon_http = ''
smon = ''
try:
user_subscription = roxywi_common.return_user_status()
except Exception as e:
user_subscription = roxywi_common.return_unsubscribed_user_status()
roxywi_common.logging('Roxy-WI server', f'Cannot get a user plan: {e}', roxywi=1)
if action == 'add': if action == 'add':
telegrams = sql.get_user_telegram_by_group(user_group) telegrams = sql.get_user_telegram_by_group(user_group)
slacks = sql.get_user_slack_by_group(user_group) slacks = sql.get_user_slack_by_group(user_group)
pds = sql.get_user_pd_by_group(user_group) pds = sql.get_user_pd_by_group(user_group)
smon = sql.select_smon(user_group, action='add') smon = sql.select_smon(user_group)
smon_ping = sql.select_smon_ping(user_group)
smon_tcp = sql.select_smon_tcp(user_group)
smon_http = sql.select_smon_http(user_group)
roxywi_auth.page_for_admin(level=3) roxywi_auth.page_for_admin(level=3)
if lang == 'ru': if lang == 'ru':
title = "SMON: Админка" title = "SMON: Админка"
@ -67,6 +82,48 @@ elif action == 'checker_history':
title = "Checker: Histoire" title = "Checker: Histoire"
else: else:
title = "Checker: History" title = "Checker: History"
elif action == 'dashboard':
dashboard_id = int(form.getvalue('dashboard_id'))
check_id = int(form.getvalue('check_id'))
smon_statuses = sql.select_smon_history(dashboard_id, check_id)
title = ''
smon_name = sql.get_smon_service_name_by_id(dashboard_id)
cur_status = sql.get_last_smon_status_by_check(dashboard_id, check_id)
check_interval = sql.get_setting('smon_check_interval')
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')
cert_day_diff = 'N/A'
count_checks = sql.get_smon_history_count_checks(dashboard_id, check_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:
avg_res_time = 0
try:
last_resp_time = round(sql.get_last_smon_res_time_by_check(dashboard_id, check_id), 2)
except Exception:
last_resp_time = 0
template = env.get_template('include/smon_history.html')
for s in smon:
if s.smon_id.ssl_expire_date is not None:
ssl_expire_date = datetime.strptime(s.smon_id.ssl_expire_date, '%Y-%m-%d %H:%M:%S')
cert_day_diff = (ssl_expire_date - present).days
rendered_template = template.render(
h2=1, title=title, autorefresh=autorefresh, role=user_params['role'], user=user_params['user'], smon=smon,
group=user_group, lang=lang, user_status=user_subscription['user_status'], check_interval=check_interval,
user_plan=user_subscription['user_plan'], token=user_params['token'], smon_statuses=smon_statuses, uptime=uptime,
user_services=user_params['user_services'], cur_status=cur_status, avg_res_time=avg_res_time, smon_name=smon_name,
cert_day_diff=cert_day_diff, check_id=check_id, dashboard_id=dashboard_id, last_resp_time=last_resp_time
)
print(rendered_template)
sys.exit()
else: else:
smon = sql.smon_list(user_group) smon = sql.smon_list(user_group)
if lang == 'ru': if lang == 'ru':
@ -77,16 +134,11 @@ else:
title = "SMON: Dashboard" title = "SMON: Dashboard"
autorefresh = 1 autorefresh = 1
try:
user_subscription = roxywi_common.return_user_status()
except Exception as e:
user_subscription = roxywi_common.return_unsubscribed_user_status()
roxywi_common.logging('Roxy-WI server', f'Cannot get a user plan: {e}', roxywi=1)
rendered_template = template.render( rendered_template = template.render(
h2=1, title=title, autorefresh=autorefresh, role=user_params['role'], user=user_params['user'], group=user_group, h2=1, title=title, autorefresh=autorefresh, role=user_params['role'], user=user_params['user'], group=user_group,
telegrams=telegrams, slacks=slacks, pds=pds, lang=lang, smon=smon, smon_status=smon_status, smon_error=stderr, telegrams=telegrams, slacks=slacks, pds=pds, lang=lang, smon=smon, smon_status=smon_status, smon_error=stderr,
action=action, sort=sort, user_services=user_params['user_services'], user_status=user_subscription['user_status'], action=action, sort=sort, 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'], token=user_params['token'], smon_ping=smon_ping, smon_tcp=smon_tcp, smon_http=smon_http
) )
print(rendered_template) print(rendered_template)

View File

@ -1,6 +1,14 @@
{% import 'languages/'+lang|default('en')+'.html' as lang %} {% import 'languages/'+lang|default('en')+'.html' as lang %}
{% from 'include/input_macros.html' import input, checkbox %} {% from 'include/input_macros.html' import input, checkbox %}
{% for s in smon %} {% for s in smon %}
<tr class="newserver" id="smon-{{s.0}}"> {% for s_service in smon_service %}
{% include 'include/smon_server.html' %} <tr class="newserver" id="smon-{{s.id}}">
{% if check_type == 'tcp' %}
{% include 'include/smon_tcp_server.html' %}
{% elif check_type == 'ping' %}
{% include 'include/smon_ping_server.html' %}
{% elif check_type == 'http' %}
{% include 'include/smon_http_server.html' %}
{% endif %}
{% endfor %}
{% endfor %} {% endfor %}

View File

@ -26,21 +26,27 @@
{% set group = [] %} {% set group = [] %}
{% set group_prev = [] %} {% set group_prev = [] %}
{%- for s in smon -%} {%- for s in smon -%}
{% set checks = lang.smon_page.desc.enabled_checks +': <br>' + lang.phrases.port_check %} {% set checks = lang.smon_page.desc.enabled_checks +': <br>' %}
{% if s.http %} {% if s.check_type == 'tcp' %}
{% set checks = checks + ',<br>' + lang.smon_page.desc.http_status_check + ': ' + s.http.split(':')[0]|string() + '://' + s.ip|string() + ':' + s.port|string() + s.http.split(':')[1]|string() %} {% set checks = checks + lang.phrases.port_check %}
{% set check_id = 1 %}
{% endif %} {% endif %}
{% if s.body and s.body is not none %} {% if s.check_type == 'http' %}
{% set checks = checks + ',<br>' + lang.smon_page.desc.body_status_check + ':' + s.body %} {% set checks = checks + lang.smon_page.desc.http_status_check %}
{% set check_id = 2 %}
{% if s.ssl_expire_date %}
{% set checks = checks + ',<br> SSL ' + lang.words.expire + ': ' + s.ssl_expire_date %}
{% endif %}
{% endif %} {% endif %}
{% if s.ssl_expire_date %} {% if s.check_type == 'ping' %}
{% set checks = checks + ',<br> SSL ' + lang.words.expire + ': ' + s.ssl_expire_date %} {% set check_id = 4 %}
{% set checks = lang.smon_page.desc.enabled_checks +': Ping' %}
{% endif %} {% endif %}
{% if s.en == 1 %} {% if s.en == 1 %}
{% if s.status == 1 and s.http_status == 1 and s.body_status == 1 %} {% if s.status == 1 and s.body_status == 1 %}
{% set additional_classes = 'good div-server-head-up' %} {% set additional_classes = 'good div-server-head-up' %}
{% set uptime_desc = lang.words.uptime + ': <time class="timeago" datetime="'+s.time_state|string()+'">'+s.time_state|string()+'</time>' %} {% set uptime_desc = lang.words.uptime + ': <time class="timeago" datetime="'+s.time_state|string()+'">'+s.time_state|string()+'</time>' %}
{% elif s.status == 0 or s.http_status == 0 or s.body_status == 0 %} {% elif s.status == 0 or s.body_status == 0 %}
{% set additional_classes = 'err div-server-head-down' %} {% set additional_classes = 'err div-server-head-down' %}
{% set uptime_desc = lang.words.downtime + ': <time class="timeago" datetime="'+s.time_state|string()+'">'+s.time_state|string()+'</time>' %} {% set uptime_desc = lang.words.downtime + ': <time class="timeago" datetime="'+s.time_state|string()+'">'+s.time_state|string()+'</time>' %}
{% else %} {% else %}
@ -52,11 +58,11 @@
{% set uptime_desc = lang.words.uptime + ': N/A' %} {% set uptime_desc = lang.words.uptime + ': N/A' %}
{% endif %} {% endif %}
{% set additional_style = '' %} {% set additional_style = '' %}
{% if s.ip|string|length > 23 %} {% if s.name|string|length > 23 %}
{% set additional_style = 'font-size: 11px;' %} {% set additional_style = 'font-size: 11px;' %}
{% elif s.ip|string|length > 20 %} {% elif s.name|string|length > 20 %}
{% set additional_style = 'font-size: 12px;' %} {% set additional_style = 'font-size: 12px;' %}
{% elif s.ip|string|length > 17 %} {% elif s.name|string|length > 17 %}
{% set additional_style = 'font-size: 15px;' %} {% set additional_style = 'font-size: 15px;' %}
{% endif %} {% endif %}
{% if s.group not in group %} {% if s.group not in group %}
@ -70,12 +76,13 @@
<div class="smon_services {{additional_classes}}" data-help="{{checks}}" title="{{checks}}"> <div class="smon_services {{additional_classes}}" data-help="{{checks}}" title="{{checks}}">
<div class="ip"> <div class="ip">
<span style="{{additional_style}}"> <span style="{{additional_style}}">
<a href="smon.py?action=history&host={{s.ip}}" title="{{lang.words.view|title()}} {{lang.words.history}} {{lang.words.for}} {{s.ip}} {{lang.words.host}}" class="link">{{s.ip}}:{{s.port}}</a> <a href="smon.py?action=dashboard&dashboard_id={{s.id}}&check_id={{check_id}}" title="{{lang.words.view|title()}} {{lang.words.history}} {{lang.words.for}} {{s.name}} {{lang.words.host}}" class="link">{{s.name.strip("'")}}</a>
</span> </span>
<span class="server-action"><a href="smon.py?action=history&host={{s.name}}" title="{{lang.words.view|title()}} {{lang.words.alerts}} {{lang.words.history}} {{lang.words.for}} {{s.name}} {{lang.words.host}}" class="history"></a></span>
</div> </div>
<div class="desc"> <div class="desc">
{% if s.desc %} {% if s.desc %}
<b>{{s.desc}}</b> <b>{{s.desc.strip("'")}}</b>
{% else %} {% else %}
{{lang.words.desc|title()}}: {{lang.words.none}} {{lang.words.desc|title()}}: {{lang.words.none}}
{% endif %} {% endif %}
@ -100,11 +107,11 @@
{% endif %} {% endif %}
</div> </div>
{% if s.en == 1 %} {% if s.en == 1 %}
{% if s.status == 1 and s.http_status == 1 and s.body_status == 1 %} {% if s.status == 1 and s.body_status == 1 %}
<div class="up"> <div class="up">
{{lang.smon_page.desc.UP}} {{lang.smon_page.desc.UP}}
</div> </div>
{% elif s.http_status == 0 %} {% elif s.status == 0 and s.check_type == 'http' %}
<div class="down"> <div class="down">
{{lang.smon_page.desc.HTTP_FAILURE}} {{lang.smon_page.desc.HTTP_FAILURE}}
</div> </div>

View File

@ -18,8 +18,9 @@
data-empty_name="{{lang.errors.empty_name}}" data-edit="{{lang.words.edit|title()}}" data-close="{{lang.words.close|title()}}" data-server_info="{{lang.phrases.server_info}}" data-empty_name="{{lang.errors.empty_name}}" data-edit="{{lang.words.edit|title()}}" data-close="{{lang.words.close|title()}}" data-server_info="{{lang.phrases.server_info}}"
data-generated_config="{{lang.words.generated|title()}} {{lang.words.config}}" data-restart="{{lang.words.restart|title()}}" data-start="{{lang.words.start|title()}}" data-generated_config="{{lang.words.generated|title()}} {{lang.words.config}}" data-restart="{{lang.words.restart|title()}}" data-start="{{lang.words.start|title()}}"
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-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-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-autorefresh="{{lang.words.auto|title()}}-{{lang.words.refresh}}" /> 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}}" />
{% if title == 'Login page' %} {% if title == 'Login page' %}
<meta name="viewport" content="width=device-width, user-scalable=1"> <meta name="viewport" content="width=device-width, user-scalable=1">
{% endif %} {% endif %}

View File

@ -32,7 +32,7 @@
<option {{disabled}} selected>{{first}}</option> <option {{disabled}} selected>{{first}}</option>
{% endif %} {% endif %}
{% for v, des in values.items() %} {% for v, des in values.items() %}
{% if v == selected %} {% if v == selected|string() %}
<option value="{{v}}" selected>{{des}}</option> <option value="{{v}}" selected>{{des}}</option>
{% else %} {% else %}
<option value="{{v}}">{{des}}</option> <option value="{{v}}">{{des}}</option>

View File

@ -0,0 +1,96 @@
{% extends "base.html" %}
{% from 'include/input_macros.html' import select %}
{% block title %}{{ lang.menu_links.history.title }} {{ smon_name }}{% endblock %}
{% block h2 %}{{ lang.menu_links.history.title }} {{ smon_name }}{% endblock %}
{% block content %}
{% set checking_types = {'1': 'TCP/UDP', '2': 'HTTP', '4': 'Ping'} %}
{% if user_status == 0 or 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">
<script src="/inc/chart.min.js"></script>
<script src="/inc/metrics.js"></script>
<div class="row wrap1">
{% set service_status = [] %}
{% for s in smon %}
{% set service_status = service_status.append(s.smon_id.en) %}
{% if check_id == 2 %}
<div id="smon_name" class="col-md-8"><a href="{{s.url}}" title="{{lang.words.open|title()}}" target="_blank">{{s.url}}</a></div>
{% elif check_id == 1 %}
<div id="smon_name" class="col-md-8" title="{{s.desc}}">{{s.ip}}:{{s.port}}</div>
{% else %}
<div id="smon_name" class="col-md-8" title="{{s.desc}}">{{s.smon_id.name}}</div>
{% endif %}
{% endfor %}
</div>
<div class="row statuses wrap">
<div class="col-md-8" style="transform: translateX(0px);">
{% for s in smon_statuses|reverse %}
{% if s.status %}
{% set add_class = 'serverUp' %}
{% else %}
{% set add_class = 'serverDown' %}
{% endif %}
<div class="smon_server_statuses {{add_class}}" title="" data-help="{{s.date}} {{s.mes}}" style=""></div>
{% endfor %}
<div id="check_interval">{{lang.words.checking|title()}} {{lang.words.every}} {{check_interval}} {{lang.words.minutes2}}</div>
</div>
<div class="col-md-4">
{% if service_status.0 %}
{% if cur_status %}
{% set add_class = 'serverUp' %}
{% set status = lang.smon_page.desc.UP %}
{% else %}
{% set add_class = 'serverDown' %}
{% set status = lang.smon_page.desc.DOWN %}
{% endif %}
{% else %}
{% set add_class = 'serverNone' %}
{% set status = lang.smon_page.desc.DISABLED %}
{% endif %}
<span class="{{add_class}} cur_status" style="font-size: 30px; border-radius: 50rem!important;min-width: 62px;">{{status}}</span>
</div>
</div>
<div class="row statuses wrap">
{% for s in smon %}
<div class="col">
<h4>{{lang.words.checking|title()}}</h4>
<p class="smon_stats">({{lang.words.type|title()}})</p>
<span class="smon_value" title="{{last_resp_time}}">{{checking_types[check_id|string()]}}</span>
</div>
<div class="col">
<h4>{{lang.words.response|title()}}</h4>
<p class="smon_stats">({{lang.words.current|title()}})</p>
<span class="smon_value" title="{{last_resp_time}}">{{last_resp_time}}ms</span>
</div>
<div class="col">
<h4>{{lang.words.average2|title()}} {{lang.words.response}}</h4>
<p class="smon_stats">(24-{{lang.words.hours}})</p>
<span class="smon_value">{{avg_res_time}}ms</span>
</div>
<div class="col">
<h4>{{lang.words.uptime}}</h4>
<p class="smon_stats">(24-{{lang.words.hours}})</p>
<span class="smon_value">{{uptime}}%</span>
</div>
<div class="col">
<h4>{{lang.words.cert_expire}}</h4>
{% if s.smon_id.ssl_expire_date is not none %}
{% set ssl_date = s.smon_id.ssl_expire_date.split()[0] %}
{% else %}
{% set ssl_date = 'N/A' %}
{% endif %}
<p class="smon_stats">({{ssl_date}})</p>
<span class="smon_value">{{cert_day_diff}} {{lang.words.days}}</span>
</div>
{% endfor %}
</div>
<div class="chart-container" style="width: 98%">
<canvas id="metrics_3" role="img"></canvas>
</div>
{% endif %}
<script>
getSmonHistoryCheckData('{{dashboard_id}}', '{{check_id}}')
</script>
{% endblock %}

View File

@ -0,0 +1,95 @@
<td class="padding10 first-collumn" style="width: 150px;">
{% set id = 'smon-name-' + s.id|string() %}
{{ input(id, value=s.name.strip("'"), size='20') }}
</td>
<td style="width: 150px;">
{% set id = 'smon-url-' + s.id|string() %}
{{ input(id, value=s_service.url, size='20') }}
</td>
<td class="checkbox">
{% set id = 'smon-enable-' + s.id|string() %}
{% if s.en == 1 %}
{{ checkbox(id, checked='checked') }}
{% else %}
{{ checkbox(id) }}
{% endif %}
</td>
<td>
{% set id = 'smon-body-' + s.id|string() %}
{{ input(id, value=s_service.body, size='20') }}
</td>
<td>
<select id="smon-telegram-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in telegrams %}
{% if s.telegram_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="smon-slack-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in slacks %}
{% if s.slack_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="smon-pd-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in pds %}
{% if s.pd_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
{% set id = 'smon-group-' + s.id|string() %}
{% if s.group is not none %}
{{ input(id, value=s.group, size='15') }}
{% else %}
{{ input(id, size='15') }}
{% endif %}
</td>
<td>
{% set id = 'smon-desc-' + s.id|string() %}
{% if s.desc is not none %}
{{ input(id, value=s.desc.strip("'"), size='20') }}
{% else %}
{{ input(id, size='20') }}
{% endif %}
</td>
<td>
<a class="add" onclick="cloneSmom({{s.id}}, 'http')" id="clone-{{s.id}}" title="{{lang.words.clone|title()}} {{s.ip}}" style="cursor: pointer; color: #000;"></a>
</td>
<td>
<a class="delete" onclick="confirmDeleteSmon({{s.id}}, 'http')" title="{{lang.words.delete|title()}} {{s.ip}}" style="cursor: pointer; color: #000;"></a>
</td>
</tr>
<script>
$( function() {
$("#smon-telegram-{{s.id}}" ).selectmenu({
width: 160
});
$("#smon-slack-{{s.id}}" ).selectmenu({
width: 160
});
$("#smon-pd-{{s.id}}" ).selectmenu({
width: 160
});
$("#smon-proto-{{s.id}}" ).selectmenu({
width: 78
});
});
</script>

View File

@ -0,0 +1,88 @@
<td class="padding10 first-collumn" style="width: 200px;">
{% set id = 'smon-name-' + s.id|string() %}
{{ input(id, value=s.name, size='20') }}
</td>
<td>
{% set id = 'smon-ip-' + s.id|string() %}
{{ input(id, value=s_service.ip, size='20') }}
</td>
<td class="checkbox">
{% set id = 'smon-enable-' + s.id|string() %}
{% if s.en == 1 %}
{{ checkbox(id, checked='checked') }}
{% else %}
{{ checkbox(id) }}
{% endif %}
</td>
<td>
<select id="smon-telegram-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in telegrams %}
{% if s.telegram_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="smon-slack-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in slacks %}
{% if s.slack_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="smon-pd-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in pds %}
{% if s.pd_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
{% set id = 'smon-group-' + s.id|string() %}
{% if s.group is not none %}
{{ input(id, value=s_service.group, size='15') }}
{% else %}
{{ input(id, size='15') }}
{% endif %}
</td>
<td>
{% set id = 'smon-desc-' + s.id|string() %}
{% if s.desc is not none %}
{{ input(id, value=s.desc.strip("'"), size='20') }}
{% else %}
{{ input(id, size='20') }}
{% endif %}
</td>
<td>
<a class="add" onclick="cloneSmom({{s.id}}, 'ping')" id="clone-{{s.id}}" title="{{lang.words.clone|title()}} {{s_service.1}}" style="cursor: pointer; color: #000;"></a>
</td>
<td>
<a class="delete" onclick="confirmDeleteSmon({{s.id}}, 'ping')" title="{{lang.words.delete|title()}} {{s_service.1}}" style="cursor: pointer; color: #000;"></a>
</td>
</tr>
<script>
$( function() {
$("#smon-telegram-{{s.id}}" ).selectmenu({
width: 160
});
$("#smon-slack-{{s.id}}" ).selectmenu({
width: 160
});
$("#smon-pd-{{s.id}}" ).selectmenu({
width: 160
});
});
</script>

View File

@ -1,114 +0,0 @@
{% from 'include/input_macros.html' import input, checkbox %}
<td class="padding10 first-collumn" style="width: 150px;">
{% set id = 'smon-ip-' + s.0|string() %}
{{ input(id, value=s.1, size='20') }}
</td>
<td>
{% set id = 'smon-port-' + s.0|string() %}
{{ input(id, value=s.2, size='5') }}
</td>
<td class="checkbox">
{% set id = 'smon-enable-' + s.0|string() %}
{% if s.3 == 1 %}
{{ checkbox(id, checked='checked') }}
{% else %}
{{ checkbox(id) }}
{% endif %}
</td>
<td>
<span id="smon-proto1-{{s.0}}">{{ s.4.split(':')[0] }}</span>
{# {% if s.4|length > 0 %}
{% set values = dict() %}
{% set id = 'smon-proto-' + s.0|string() %}
{% set values = {'':'', 'http':'http','https':'https'} %}
{{ select(id, values=values, selected=s.4.split(':')[0]) }}
{% endif %} #}
</td>
<td id="smon-uri-{{s.0}}">
{% if s.4|length > 0 %}
{{ s.4.split(':')[1] }}
{% endif %}
</td>
<td>
{% set id = 'smon-body-' + s.0|string() %}
{% if s.5 is not none %}
<span id="{{id}}">{{s.5}}</span>
{% else %}
<span id="{{id}}"></span>
{% endif %}
</td>
<td>
<select id="smon-telegram-{{s.0}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in telegrams %}
{% if s.6|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="smon-slack-{{s.0}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in slacks %}
{% if s.10|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="smon-pd-{{s.0}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in pds %}
{% if s.11|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
{% set id = 'smon-group-' + s.0|string() %}
{% if s.8 is not none %}
{{ input(id, value=s.8, size='15') }}
{% else %}
{{ input(id, size='15') }}
{% endif %}
</td>
<td>
{% set id = 'smon-desc-' + s.0|string() %}
{% if s.7 is not none %}
{{ input(id, value=s.7, size='20') }}
{% else %}
{{ input(id, size='20') }}
{% endif %}
</td>
<td>
<a class="add" onclick="cloneSmom({{s.0}})" id="clone-{{s.0}}" title="{{lang.words.clone|title()}} {{s.1}}" style="cursor: pointer; color: #000;"></a>
</td>
<td>
<a class="delete" onclick="confirmDeleteSmon({{s.0}})" title="{{lang.words.delete|title()}} {{s.1}}" style="cursor: pointer; color: #000;"></a>
</td>
</tr>
<script>
$( function() {
$("#smon-telegram-{{s.0}}" ).selectmenu({
width: 160
});
$("#smon-slack-{{s.0}}" ).selectmenu({
width: 160
});
$("#smon-pd-{{s.0}}" ).selectmenu({
width: 160
});
$("#smon-proto-{{s.0}}" ).selectmenu({
width: 78
});
});
</script>

View File

@ -0,0 +1,95 @@
<td class="padding10 first-collumn" style="width: 150px;">
{% set id = 'smon-name-' + s.id|string() %}
{{ input(id, value=s.name.strip("'"), size='20') }}
</td>
<td style="width: 150px;">
{% set id = 'smon-ip-' + s.id|string() %}
{{ input(id, value=s_service.ip, size='20') }}
</td>
<td>
{% set id = 'smon-port-' + s.id|string() %}
{{ input(id, value=s_service.port, size='5') }}
</td>
<td class="checkbox">
{% set id = 'smon-enable-' + s.id|string() %}
{% if s.en == 1 %}
{{ checkbox(id, checked='checked') }}
{% else %}
{{ checkbox(id) }}
{% endif %}
</td>
<td>
<select id="smon-telegram-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in telegrams %}
{% if s.telegram_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="smon-slack-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in slacks %}
{% if s.slack_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
<select id="smon-pd-{{s.id}}">
<option value="0">{{lang.words.disabled|title()}}</option>
{% for t in pds %}
{% if s.pd_channel_id|int() == t.id|int() %}
<option value="{{t.id}}" selected>{{t.chanel_name}}</option>
{% else %}
<option value="{{t.id}}">{{t.chanel_name}}</option>
{% endif %}
{% endfor %}
</select>
</td>
<td>
{% set id = 'smon-group-' + s.id|string() %}
{% if s.group is not none %}
{{ input(id, value=s.group, size='15') }}
{% else %}
{{ input(id, size='15') }}
{% endif %}
</td>
<td>
{% set id = 'smon-desc-' + s.id|string() %}
{% if s.desc is not none %}
{{ input(id, value=s.desc.strip("'"), size='20') }}
{% else %}
{{ input(id, size='20') }}
{% endif %}
</td>
<td>
<a class="add" onclick="cloneSmom({{s.id}}, 'tcp')" id="clone-{{s.id}}" title="{{lang.words.clone|title()}} {{s.ip}}" style="cursor: pointer; color: #000;"></a>
</td>
<td>
<a class="delete" onclick="confirmDeleteSmon({{s.id}}, 'tcp')" title="{{lang.words.delete|title()}} {{s.ip}}" style="cursor: pointer; color: #000;"></a>
</td>
</tr>
<script>
$( function() {
$("#smon-telegram-{{s.id}}" ).selectmenu({
width: 160
});
$("#smon-slack-{{s.id}}" ).selectmenu({
width: 160
});
$("#smon-pd-{{s.id}}" ).selectmenu({
width: 160
});
$("#smon-proto-{{s.id}}" ).selectmenu({
width: 78
});
});
</script>

View File

@ -671,6 +671,7 @@
"minute": "minute", "minute": "minute",
"minute2": "minute", "minute2": "minute",
"minutes": "minutes", "minutes": "minutes",
"minutes2": "minutes",
"hour": "hour", "hour": "hour",
"hours": "hours", "hours": "hours",
"hours2": "hours", "hours2": "hours",
@ -867,5 +868,10 @@
"value": "value", "value": "value",
"if": "if", "if": "if",
"then": "then", "then": "then",
"response": "response",
"average": "average",
"average2": "average",
"cert_expire": "Cert Expire",
"Hostname": "Hostname",
} }
%} %}

View File

@ -671,6 +671,7 @@
"minute": "minute", "minute": "minute",
"minute2": "minute", "minute2": "minute",
"minutes": "minutes", "minutes": "minutes",
"minutes2": "minutes",
"hour": "heure", "hour": "heure",
"hours": "heures", "hours": "heures",
"hours2": "heures", "hours2": "heures",
@ -867,5 +868,10 @@
"value": "valeur", "value": "valeur",
"if": "si", "if": "si",
"then": "alors", "then": "alors",
"response": "réponse",
"average": "moyenne",
"average2": "moyenne",
"cert_expire": "Expiration du certificat",
"Hostname": "Nome de anfitrião",
} }
%} %}

View File

@ -671,6 +671,7 @@
"minute": "minuto", "minute": "minuto",
"minute2": "minuto", "minute2": "minuto",
"minutes": "minutos", "minutes": "minutos",
"minutes2": "minutos",
"hour": "hora", "hour": "hora",
"hours": "horas", "hours": "horas",
"hours2": "horas", "hours2": "horas",
@ -867,5 +868,10 @@
"value": "valor", "value": "valor",
"if": "se", "if": "se",
"then": "então", "then": "então",
"response": "resposta",
"average": "média",
"average2": "médio",
"cert_expire": "Expiração do certificado",
"Hostname": "Nom d'hôte",
} }
%} %}

View File

@ -671,6 +671,7 @@
"minute": "минута", "minute": "минута",
"minute2": "минуту", "minute2": "минуту",
"minutes": "минут", "minutes": "минут",
"minutes2": "минуты",
"hour": "час", "hour": "час",
"hours": "часа", "hours": "часа",
"hours2": "часов", "hours2": "часов",
@ -867,5 +868,10 @@
"value": "значение", "value": "значение",
"if": "если", "if": "если",
"then": "тогда", "then": "тогда",
"response": "отклик",
"average": "среднее",
"average2": "средний",
"cert_expire": "Срок действия сертификата",
"Hostname": "Имя хоста",
} }
%} %}

View File

@ -3,7 +3,7 @@
{% block h2 %}{{ title }}{% endblock %} {% block h2 %}{{ title }}{% endblock %}
{% block content %} {% block content %}
{% from 'include/input_macros.html' import input, checkbox, select %} {% from 'include/input_macros.html' import input, checkbox, select %}
<script src="/inc/smon.js"></script> <script src="/inc/smon-6.3.13.js"></script>
<script src="/inc/users.js"></script> <script src="/inc/users.js"></script>
<script src="/inc/fontawesome.min.js"></script> <script src="/inc/fontawesome.min.js"></script>
<script src="/inc/jquery.timeago.js" type="text/javascript"></script> <script src="/inc/jquery.timeago.js" type="text/javascript"></script>
@ -53,15 +53,13 @@
</div> </div>
{% else %} {% else %}
{% if action == 'add' %} {% if action == 'add' %}
<table class="overview" id="ajax-smon"> <table class="overview overview-overflow" id="ajax-smon-http">
<thead> <thead>
<caption><h3>TCP/UDP check</h3></caption> <caption><h3>HTTP {{lang.words.checking}}</h3></caption>
<tr class="overviewHead"> <tr class="overviewHead">
<th class="padding10 first-collumn" style="width: 150px;">Hostname</th> <th class="padding10 first-collumn" style="width: 200px;">{{lang.words.name|title()}}</th>
<th style="width: 2%;">{{lang.words.port|title()}}</th> <th style="width: 15%;">URL</th>
<th style="width: 5%;">{{lang.words.enabled|title()}}</th> <th style="width: 5%;">{{lang.words.enabled|title()}}</th>
<th style="width: 10%;">{{lang.words.protocol|title()}}</th>
<th style="width: 15%;">URI</th>
<th style="width: 20%;">{{lang.words.body|title()}}</th> <th style="width: 20%;">{{lang.words.body|title()}}</th>
<th style="width: 11%;">Telegram</th> <th style="width: 11%;">Telegram</th>
<th style="width: 11%;">Slack</th> <th style="width: 11%;">Slack</th>
@ -73,14 +71,80 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{env}}
{% for s in smon %} {% for s in smon %}
<tr id="smon-{{s.0}}"> {% if s.check_type == 'http' %}
{% include 'include/smon_server.html' %} {% for s_service in smon_http %}
{% if s_service.smon_id|string() == s.id|string() %}
<tr id="smon-http-{{s.id}}">
{% include 'include/smon_http_server.html' %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<br /><span class="add-button" title="{{lang.words.add|title()}} {{lang.words.w_a}} {{lang.words.new}} {{lang.words.server}}" id="add-smon-button">+ {{lang.words.add|title()}}</span> <br /><span class="add-button" title="{{lang.words.add|title()}} {{lang.words.w_a}} {{lang.words.new}} {{lang.words.server}}" id="add-smon-button-http">+ {{lang.words.add|title()}}</span>
<br /><br />
<table class="overview overview-overflow" id="ajax-smon-tcp">
<thead>
<caption><h3>TCP/UDP {{lang.words.checking}}</h3></caption>
<tr class="overviewHead">
<th class="padding10 first-collumn" style="width: 200px;">{{lang.words.name|title()}}</th>
<th style="width: 15%;">{{lang.words.Hostname}}</th>
<th style="width: 2%;">{{lang.words.port|title()}}</th>
<th style="width: 5%;">{{lang.words.enabled|title()}}</th>
<th style="width: 11%;">Telegram</th>
<th style="width: 11%;">Slack</th>
<th style="width: 11%;">PagerDuty</th>
<th style="width: 10%;">{{lang.words.group|title()}}</th>
<th style="width: 100%;">{{lang.words.desc|title()}}</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{% for s_service in smon_tcp %}
{% for s in smon %}
{% if s.id|string() == s_service.smon_id|string() %}
<tr id="smon-tcp-{{s.id}}">
{% include 'include/smon_tcp_server.html' %}
{% endif %}
{% endfor %}
{% endfor %}
</tbody>
</table>
<br /><span class="add-button" title="{{lang.words.add|title()}} {{lang.words.w_a}} {{lang.words.new}} {{lang.words.server}}" id="add-smon-button-tcp">+ {{lang.words.add|title()}}</span>
<br /><br />
<table class="overview overview-overflow" id="ajax-smon-ping" style="margin-bottom: 20px;">
<thead>
<caption><h3>Ping {{lang.words.checking}}</h3></caption>
<tr class="overviewHead">
<th class="padding10 first-collumn" style="width: 200px;">{{lang.words.name|title()}}</th>
<th style="width: 15%;">{{lang.words.Hostname}}</th>
<th style="width: 5%;">{{lang.words.enabled|title()}}</th>
<th style="width: 15%;">Telegram</th>
<th style="width: 15%;">Slack</th>
<th style="width: 15%;">PagerDuty</th>
<th style="width: 10%;">{{lang.words.group|title()}}</th>
<th style="width: 100%;">{{lang.words.desc|title()}}</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{% for s in smon %}
{% if s.check_type == 'ping' %}
{% for s_service in smon_ping %}
{% if s_service.smon_id|string() == s.id|string() %}
<tr id="smon-ping-{{s.id}}">
{% include 'include/smon_ping_server.html' %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</tbody>
</table>
<br /><span class="add-button" title="{{lang.words.add|title()}} {{lang.words.w_a}} {{lang.words.new}} {{lang.words.server}}" id="add-smon-button-ping">+ {{lang.words.add|title()}}</span>
<br /><br /> <br /><br />
<div id="ajax"></div> <div id="ajax"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;"> <div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
@ -91,14 +155,33 @@
{% include 'include/tr_validate_tips.html' %} {% include 'include/tr_validate_tips.html' %}
<tr> <tr>
<td class="padding20"> <td class="padding20">
IP {{lang.words.name|title()}}
<span class="need-field">*</span>
</td>
<td>
{{ input('new-smon-name') }}
</td>
</tr>
<tr>
<td class="padding20">
{{lang.words.checking|title()}}
<span class="need-field">*</span>
</td>
<td>
{% set check_types = {'ping': 'Ping', 'tcp': 'TCP/UDP', 'http': 'HTTP(s)'} %}
{{ select('check_type', values=check_types, selected='http') }}
</td>
</tr>
<tr class="new_smon_hostname">
<td class="padding20">
{{lang.words.Hostname}}
<span class="need-field">*</span> <span class="need-field">*</span>
</td> </td>
<td> <td>
{{ input('new-smon-ip') }} {{ input('new-smon-ip') }}
</td> </td>
</tr> </tr>
<tr> <tr class="smon_tcp_check">
<td class="padding20"> <td class="padding20">
{{lang.words.port|title()}} {{lang.words.port|title()}}
<span class="need-field">*</span> <span class="need-field">*</span>
@ -113,19 +196,11 @@
{{ checkbox('new-smon-enable', checked='checked') }} {{ checkbox('new-smon-enable', checked='checked') }}
</td> </td>
</tr> </tr>
<tr> <tr class="smon_http_check">
<td class="padding20">{{lang.words.protocol|title()}}</td> <td class="padding20">URL</td>
<td> <td>{{ input('new-smon-url', value='https://', title='proto://url[:port]/') }}</td>
{% set values = dict() %}
{% set values = {'':'', 'http':'http','https':'https'} %}
{{ select('new-smon-proto', values=values, selected='') }}
</td>
</tr> </tr>
<tr> <tr class="smon_http_check">
<td class="padding20">URI</td>
<td>{{ input('new-smon-uri') }}</td>
</tr>
<tr>
<td class="padding20">{{lang.words.body|title()}}</td> <td class="padding20">{{lang.words.body|title()}}</td>
<td>{{ input('new-smon-body') }}</td> <td>{{ input('new-smon-body') }}</td>
</tr> </tr>

72
inc/css/smon.css Normal file
View File

@ -0,0 +1,72 @@
h4 {
font-size: 1.5rem;
font-weight: 500;
line-height: 1.2;
}
.wrap {
margin-left: var(--indent);
margin-top: 20px;
margin-bottom: 20px;
padding-bottom: 10px;
padding-top: 10px;
}
.wrap1 {
margin-left: var(--indent);
}
.statuses {
border-bottom: 1px solid #ddd;
border-top: 1px solid #ddd;
}
.smon_server_statuses {
width: 5px;
height: 25px;
margin: 4px;
display: inline-block;
border-radius: 50rem;
transition: all .2s ease-in-out;
}
.smon_server_statuses:hover {
transform: scale(1.5);
}
*:before, *:after {
box-sizing: border-box;
}
#smon_name {
font-size: 25px;
}
#check_interval {
color: #aaa;
font-size: 14px;
padding-top: 10px;
}
.col-md-8 {
flex: 0 0 auto;
width: 76%;
margin-top: 5px;
}
.col-md-4 {
flex: 0 0 auto;
width: 23%;
margin-top: 10px;
}
.row {
--bs-gutter-x: 1.5rem;
--bs-gutter-y: 0;
display: flex;
flex-wrap: wrap;
}
.cur_status {
font-size: 30px;
border-radius: 50rem !important;
min-width: 92px;
font-weight: 700;
padding: 0.35em 0.65em;
}
.col {
flex: 1 0 0%;
text-align: center !important;
}
.smon_stats {
font-size: 13px;
color: #aaa;
}

View File

@ -322,15 +322,10 @@ function getApacheChartData(server) {
}); });
} }
function loadMetrics() { function loadMetrics() {
var service = findGetParameter('service');
if (!service) {
service = 'haproxy';
}
$.ajax({ $.ajax({
url: "options.py", url: "options.py",
data: { data: {
table_metrics: '1', table_metrics: '1',
service: service,
token: $('#token').val() token: $('#token').val()
}, },
beforeSend: function() { beforeSend: function() {
@ -558,3 +553,74 @@ function updatingCpuRamCharts() {
getWafChartData(server_ip); getWafChartData(server_ip);
} }
} }
function getSmonHistoryCheckData(server, check_id) {
$.ajax({
url: "options.py",
data: {
smon_history_check: '1',
check_id: check_id,
server_id: server,
// time_range: $( "#time-range option:selected" ).val(),
token: $('#token').val()
},
type: "POST",
success: function (result) {
var data = [];
data.push(result.chartData.curr_con);
var labels = result.chartData.labels;
renderSMONChart(data, labels, '3');
}
});
}
function renderSMONChart(data, labels, server) {
var resp_time_word = $('#translate').attr('data-resp_time');
var ctx = 'metrics_' + server;
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels.split(','),
datasets: [
{
parsing: false,
normalized: true,
label: resp_time_word+' (ms)',
data: data[0].split(','),
borderColor: 'rgba(92, 184, 92, 1)',
backgroundColor: 'rgba(92, 184, 92, 0.2)',
}
]
},
options: {
animation: false,
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}],
xAxes: [{
ticks: {
major: {
enabled: true,
fontStyle: 'bold'
},
source: 'data',
autoSkip: true,
autoSkipPadding: 45,
maxRotation: 0
}
}]
},
legend: {
display: true,
labels: {
fontColor: 'rgb(255, 99, 132)',
defaultFontSize: '10',
defaultFontFamily: 'BlinkMacSystemFont'
},
}
}
});
charts.push(myChart);
}

View File

@ -80,6 +80,8 @@ $( function() {
show_current_page($(this)) show_current_page($(this))
} else if(cur_url[0] == 'smon.py' && cur_url[1].split('&')[0] == 'action=checker_history' && link2 == 'smon.py?action=checker_history'){ } else if(cur_url[0] == 'smon.py' && cur_url[1].split('&')[0] == 'action=checker_history' && link2 == 'smon.py?action=checker_history'){
show_current_page($(this)) show_current_page($(this))
} else if(cur_url[0] == 'smon.py' && cur_url[1].split('&')[0] == 'action=dashboard' && link2.indexOf('smon.py?action=view') != '-1'){
show_current_page($(this))
} else if(cur_url[0] == 'add.py' && cur_url[1].split('&')[0] == 'service=nginx#ssl' && link2 == 'add.py?service=nginx#ssl'){ } else if(cur_url[0] == 'add.py' && cur_url[1].split('&')[0] == 'service=nginx#ssl' && link2 == 'add.py?service=nginx#ssl'){
show_current_page($(this)) show_current_page($(this))
} else if(cur_url[0] == 'viewlogs.py' && cur_url[1].split('&')[0] == 'type=2' && link2 == 'viewlogs.py?type=2') { } else if(cur_url[0] == 'viewlogs.py' && cur_url[1].split('&')[0] == 'type=2' && link2 == 'viewlogs.py?type=2') {

View File

@ -48,28 +48,25 @@ function showSmon(action) {
} }
function addNewSmonServer(dialog_id) { function addNewSmonServer(dialog_id) {
var valid = true; var valid = true;
allFields = $( [] ).add( $('#new-smon-ip') ).add( $('#new-smon-port') ) var check_type = $('#check_type').val();
allFields.removeClass( "ui-state-error" ); if (check_type == 'tcp') {
valid = valid && checkLength( $('#new-smon-ip'), "IP", 1 ); allFields = $([]).add($('#new-smon-ip')).add($('#new-smon-port')).add($('#new-smon-hostname')).add($('#new-smon-name'))
valid = valid && checkLength( $('#new-smon-port'), "Port", 1 ); allFields.removeClass("ui-state-error");
if ($('#new-smon-proto').val() != '' || $('#new-smon-uri').val() != '') { valid = valid && checkLength($('#new-smon-ip'), "Hostname", 1);
allFields = $( [] ).add( $('#new-smon-ip') ).add( $('#new-smon-port') ) valid = valid && checkLength($('#new-smon-name'), "Name", 1);
.add( $('#new-smon-proto') ).add( $('#new-smon-uri') ); valid = valid && checkLength($('#new-smon-port'), "Port", 1);
allFields.removeClass( "ui-state-error" );
valid = valid && checkLength( $('#new-smon-ip'), "IP", 1 );
valid = valid && checkLength( $('#new-smon-port'), "Port", 1 );
valid = valid && checkLength( $('#new-smon-proto'), "Protocol", 1 );
valid = valid && checkLength( $('#new-smon-uri'), "URI", 1 );
} }
if( $('#new-smon-body').val() != '') { if (check_type == 'http') {
allFields = $( [] ).add( $('#new-smon-ip') ).add( $('#new-smon-port') ) allFields = $([]).add($('#new-smon-url')).add($('#new-smon-name'))
.add( $('#new-smon-proto') ).add( $('#new-smon-uri') ); allFields.removeClass("ui-state-error");
allFields.removeClass( "ui-state-error" ); valid = valid && checkLength($('#new-smon-name'), "Name", 1);
valid = valid && checkLength( $('#new-smon-ip'), "IP", 1 ); valid = valid && checkLength($('#new-smon-url'), "URL", 1);
valid = valid && checkLength( $('#new-smon-port'), "Port", 1 ); }
valid = valid && checkLength( $('#new-smon-proto'), "Protocol", 1 ); if (check_type == 'ping') {
valid = valid && checkLength( $('#new-smon-uri'), "URI", 1 ); allFields = $([]).add($('#new-smon-ip')).add($('#new-smon-name'))
valid = valid && checkLength( $('#new-smon-body'), "Body", 1 ); allFields.removeClass("ui-state-error");
valid = valid && checkLength($('#new-smon-name'), "Name", 1);
valid = valid && checkLength($('#new-smon-ip'), "Hostname", 1);
} }
var enable = 0; var enable = 0;
if ($('#new-smon-enable').is(':checked')) { if ($('#new-smon-enable').is(':checked')) {
@ -79,17 +76,18 @@ function addNewSmonServer(dialog_id) {
$.ajax( { $.ajax( {
url: "options.py", url: "options.py",
data: { data: {
newsmonname: $('#new-smon-name').val(),
newsmon: $('#new-smon-ip').val(), newsmon: $('#new-smon-ip').val(),
newsmonport: $('#new-smon-port').val(), newsmonport: $('#new-smon-port').val(),
newsmonenable: enable, newsmonenable: enable,
newsmonproto: $('#new-smon-proto').val(), newsmonurl: $('#new-smon-url').val(),
newsmonuri: $('#new-smon-uri').val(),
newsmonbody: $('#new-smon-body').val(), newsmonbody: $('#new-smon-body').val(),
newsmongroup: $('#new-smon-group').val(), newsmongroup: $('#new-smon-group').val(),
newsmondescription: $('#new-smon-description').val(), newsmondescription: $('#new-smon-description').val(),
newsmontelegram: $('#new-smon-telegram').val(), newsmontelegram: $('#new-smon-telegram').val(),
newsmonslack: $('#new-smon-slack').val(), newsmonslack: $('#new-smon-slack').val(),
newsmonpd: $('#new-smon-pd').val(), newsmonpd: $('#new-smon-pd').val(),
newsmonchecktype: check_type,
token: $('#token').val() token: $('#token').val()
}, },
type: "POST", type: "POST",
@ -98,7 +96,15 @@ function addNewSmonServer(dialog_id) {
if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') { if (data.indexOf('error:') != '-1' || data.indexOf('unique') != '-1') {
toastr.error(data); toastr.error(data);
} else { } else {
common_ajax_action_after_success(dialog_id, 'newserver', 'ajax-smon', data); if (check_type == 'ping') {
table_id = 'ajax-smon-ping';
} else if (check_type == 'tcp') {
table_id = 'ajax-smon-tcp';
}
else {
table_id = 'ajax-smon-http';
}
common_ajax_action_after_success(dialog_id, 'newserver', table_id, data);
$( "input[type=submit], button" ).button(); $( "input[type=submit], button" ).button();
$( "input[type=checkbox]" ).checkboxradio(); $( "input[type=checkbox]" ).checkboxradio();
$( "select" ).selectmenu(); $( "select" ).selectmenu();
@ -108,7 +114,7 @@ function addNewSmonServer(dialog_id) {
} ); } );
} }
} }
function confirmDeleteSmon(id) { function confirmDeleteSmon(id, check_type) {
var delete_word = $('#translate').attr('data-delete'); var delete_word = $('#translate').attr('data-delete');
var cancel_word = $('#translate').attr('data-cancel'); var cancel_word = $('#translate').attr('data-cancel');
$( "#dialog-confirm" ).dialog({ $( "#dialog-confirm" ).dialog({
@ -121,7 +127,7 @@ function confirmDeleteSmon(id) {
text: delete_word, text: delete_word,
click: function () { click: function () {
$(this).dialog("close"); $(this).dialog("close");
removeSmon(id); removeSmon(id, check_type);
} }
}, { }, {
text: cancel_word, text: cancel_word,
@ -131,7 +137,7 @@ function confirmDeleteSmon(id) {
}] }]
}); });
} }
function removeSmon(id) { function removeSmon(id, check_type) {
$("#smon-"+id).css("background-color", "#f2dede"); $("#smon-"+id).css("background-color", "#f2dede");
$.ajax( { $.ajax( {
url: "options.py", url: "options.py",
@ -143,7 +149,7 @@ function removeSmon(id) {
success: function( data ) { success: function( data ) {
data = data.replace(/\s+/g,' '); data = data.replace(/\s+/g,' ');
if(data == "Ok ") { if(data == "Ok ") {
$("#smon-"+id).remove(); $("#smon-"+check_type+"-"+id).remove();
} else { } else {
toastr.error(data); toastr.error(data);
} }
@ -151,7 +157,7 @@ function removeSmon(id) {
} ); } );
} }
function updateSmon(id) { function updateSmon(id, check_type) {
toastr.clear(); toastr.clear();
var enable = 0; var enable = 0;
if ($('#smon-enable-'+id).is(':checked')) { if ($('#smon-enable-'+id).is(':checked')) {
@ -160,16 +166,18 @@ function updateSmon(id) {
$.ajax( { $.ajax( {
url: "options.py", url: "options.py",
data: { data: {
updateSmonName: $('#smon-name-'+id).val(),
updateSmonIp: $('#smon-ip-'+id).val(), updateSmonIp: $('#smon-ip-'+id).val(),
updateSmonPort: $('#smon-port-'+id).val(), updateSmonPort: $('#smon-port-'+id).val(),
updateSmonUrl: $('#smon-url-'+id).val(),
updateSmonEn: enable, updateSmonEn: enable,
updateSmonHttp: $('#smon-proto1-'+id).text(), updateSmonBody: $('#smon-body-'+id).val(),
updateSmonBody: $('#smon-body-'+id).text(),
updateSmonTelegram: $('#smon-telegram-'+id).val(), updateSmonTelegram: $('#smon-telegram-'+id).val(),
updateSmonSlack: $('#smon-slack-'+id).val(), updateSmonSlack: $('#smon-slack-'+id).val(),
updateSmonPD: $('#smon-pd-'+id).val(), updateSmonPD: $('#smon-pd-'+id).val(),
updateSmonGroup: $('#smon-group-'+id).val(), updateSmonGroup: $('#smon-group-'+id).val(),
updateSmonDesc: $('#smon-desc-'+id).val(), updateSmonDesc: $('#smon-desc-'+id).val(),
check_type: check_type,
id: id, id: id,
token: $('#token').val() token: $('#token').val()
}, },
@ -180,24 +188,27 @@ function updateSmon(id) {
toastr.error(data); toastr.error(data);
} else { } else {
toastr.clear(); toastr.clear();
$("#smon-"+id).addClass( "update", 1000 ); $("#smon-"+check_type+"-"+id).addClass( "update", 1000 );
setTimeout(function() { setTimeout(function() {
$( "#smon-"+id ).removeClass( "update" ); $("#smon-"+check_type+"-"+id).removeClass( "update" );
}, 2500 ); }, 2500 );
} }
} }
} ); } );
} }
function cloneSmom(id) { function cloneSmom(id, check_type) {
$( "#add-smon-button" ).trigger( "click" ); check_and_clear_check_type(check_type);
$( "#add-smon-button-"+check_type ).trigger( "click" );
if ($('#smon-enable-'+id).is(':checked')) { if ($('#smon-enable-'+id).is(':checked')) {
$('#new-smon-enable').prop('checked', true) $('#new-smon-enable').prop('checked', true)
} else { } else {
$('#new-smon-enable').prop('checked', false) $('#new-smon-enable').prop('checked', false)
} }
$('#new-smon-enable').checkboxradio("refresh"); $('#new-smon-enable').checkboxradio("refresh");
$('#new-smon-name').val($('#smon-name-'+id).val());
$('#new-smon-ip').val($('#smon-ip-'+id).val()); $('#new-smon-ip').val($('#smon-ip-'+id).val());
$('#new-smon-port').val($('#smon-port-'+id).val()); $('#new-smon-port').val($('#smon-port-'+id).val());
$('#new-smon-url').val($('#smon-url-'+id).val());
$('#new-smon-group').val($('#smon-group-'+id).val()); $('#new-smon-group').val($('#smon-group-'+id).val());
$('#new-smon-description').val($('#smon-desc-'+id).val()) $('#new-smon-description').val($('#smon-desc-'+id).val())
$('#new-smon-telegram').val($('#smon-telegram-'+id+' option:selected').val()).change() $('#new-smon-telegram').val($('#smon-telegram-'+id+' option:selected').val()).change()
@ -208,16 +219,44 @@ function cloneSmom(id) {
$('#new-smon-pd').selectmenu("refresh"); $('#new-smon-pd').selectmenu("refresh");
} }
$( function() { $( function() {
$('#add-smon-button').click(function() { $('#add-smon-button-http').click(function() {
addSmonServer.dialog('open'); addSmonServer.dialog('open');
check_and_clear_check_type('http');
}); });
$( "#ajax-smon input" ).change(function() { $('#add-smon-button-tcp').click(function() {
var id = $(this).attr('id').split('-'); addSmonServer.dialog('open');
updateSmon(id[2]) check_and_clear_check_type('tcp');
}); });
$( "#ajax-smon select" ).on('selectmenuchange',function() { $('#add-smon-button-ping').click(function() {
addSmonServer.dialog('open');
check_and_clear_check_type('ping');
});
$( "#ajax-smon-http input" ).change(function() {
var id = $(this).attr('id').split('-'); var id = $(this).attr('id').split('-');
updateSmon(id[2]) updateSmon(id[2], 'http');
});
$( "#ajax-smon-http select" ).on('selectmenuchange',function() {
var id = $(this).attr('id').split('-');
updateSmon(id[2], 'http');
});
$( "#ajax-smon-tcp input" ).change(function() {
var id = $(this).attr('id').split('-');
updateSmon(id[2], 'tcp');
});
$( "#ajax-smon-tcp select" ).on('selectmenuchange',function() {
var id = $(this).attr('id').split('-');
updateSmon(id[2], 'tcp');
});
$( "#ajax-smon-ping input" ).change(function() {
var id = $(this).attr('id').split('-');
updateSmon(id[2], 'ping');
});
$( "#ajax-smon-ping select" ).on('selectmenuchange',function() {
var id = $(this).attr('id').split('-');
updateSmon(id[2], 'ping');
});
$( "#check_type" ).on('selectmenuchange',function() {
check_and_clear_check_type($('#check_type').val());
}); });
var add_word = $('#translate').attr('data-add'); var add_word = $('#translate').attr('data-add');
var cancel_word = $('#translate').attr('data-cancel'); var cancel_word = $('#translate').attr('data-cancel');
@ -251,3 +290,37 @@ $( function() {
}] }]
}); });
}); });
function check_and_clear_check_type(check_type) {
if (check_type == 'http') {
$('.smon_http_check').show();
$('.smon_tcp_check').hide();
$('.new_smon_hostname').hide();
$("#check_type").val('http');
$('#check_type').selectmenu("refresh");
$('.smon_http_check').show();
$('.smon_tcp_check').hide();
$('#new-smon-port').val('');
$('#new_smon_hostname').val('');
} else if (check_type == 'tcp') {
$('.smon_http_check').hide();
$('.smon_tcp_check').show();
$("#check_type").val('tcp');
$('#check_type').selectmenu("refresh");
$('.smon_tcp_check').show();
$('.new_smon_hostname').show();
$('.smon_http_check').hide();
$('#new-smon-url').val('');
$('#new-smon-body').val('');
} else {
$('.smon_http_check').hide();
$('.new_smon_hostname').show();
$('.smon_tcp_check').hide();
$("#check_type").val('ping');
$('#check_type').selectmenu("refresh");
$('.smon_tcp_check').hide();
$('.smon_http_check').hide();
$('#new-smon-url').val('');
$('#new-smon-body').val('');
$('#new-smon-port').val('');
}
}