v8.1.6: Add UDP listener checker functionality

Introduces the ability to enable or disable a checker service for UDP listeners. Includes UI updates, database migration, new API route, and backend logic to handle checker settings on UDP listeners.
pull/403/merge
Aidaho 2025-02-19 10:49:07 +03:00
parent fc0ccb8f9c
commit f3f540c291
11 changed files with 113 additions and 5 deletions

View File

@ -16,7 +16,7 @@ from app.views.service.lets_encrypt_views import LetsEncryptsView, LetsEncryptVi
from app.views.service.haproxy_lists_views import HaproxyListView
from app.views.ha.views import HAView, HAVIPView, HAVIPsView
from app.views.user.views import UserView, UserGroupView, UserRoles
from app.views.udp.views import UDPListener, UDPListeners, UDPListenerActionView, UDPListenerBackendStatusView
from app.views.udp.views import UDPListener, UDPListeners, UDPListenerActionView, UDPListenerBackendStatusView, UdpListenerCheckerView
from app.views.channel.views import ChannelView, ChannelsView
from app.views.tools.views import CheckerView
from app.views.tools.port_scanner_views import PortScannerView, PortScannerPortsView
@ -60,6 +60,7 @@ bp.add_url_rule('/ha/<service>/<int:cluster_id>/vips', view_func=HAVIPsView.as_v
register_api(UDPListener, 'udp_listener', '/<service>/listener', 'listener_id')
bp.add_url_rule('/<service>/listener/<int:listener_id>/<any(start, stop, reload, restart):action>', view_func=UDPListenerActionView.as_view('listener_action'), methods=['GET'])
bp.add_url_rule('/<service>/listener/<int:listener_id>/<backend_ip>', view_func=UDPListenerBackendStatusView.as_view('UDPListenerBackendStatusView'), methods=['GET'])
bp.add_url_rule('/<service>/listener/<int:listener_id>/checker/<int:is_checker>', view_func=UdpListenerCheckerView.as_view('UdpListenerCheckerView'), methods=['POST'])
bp.add_url_rule('/<service>/listeners', view_func=UDPListeners.as_view('listeners'), methods=['GET'])
bp.add_url_rule('/service/<service>/<int:server_id>/install', view_func=InstallGetStatus.as_view('install_status'), methods=['GET'])
bp.add_url_rule('/service/<service>/<server_id>/install', view_func=InstallGetStatus.as_view('install_status_ip'), methods=['GET'])

View File

@ -703,9 +703,27 @@ def update_db_v_8_1_4():
print("An error occurred:", e)
def update_db_v_8_1_6():
try:
if mysql_enable:
migrate(
migrator.add_column('udp_balancers', 'is_checker', IntegerField(default=0)),
)
else:
migrate(
migrator.add_column('udp_balancers', 'is_checker', IntegerField(constraints=[SQL('DEFAULT 0')])),
)
except Exception as e:
if (e.args[0] == 'duplicate column name: is_checker' or 'column "is_checker" of relation "udp_balancers" already exists'
or str(e) == '(1060, "Duplicate column name \'is_checker\'")'):
print('Updating... DB has been updated to version 8.1.6')
else:
print("An error occurred:", e)
def update_ver():
try:
Version.update(version='8.1.5').execute()
Version.update(version='8.1.6').execute()
except Exception:
print('Cannot update version')
@ -737,4 +755,5 @@ def update_all():
update_db_v_8_1_0_3()
update_db_v_8_1_2()
update_db_v_8_1_4()
update_db_v_8_1_6()
update_ver()

View File

@ -1,4 +1,4 @@
from app.modules.db.db_model import CheckerSetting, Server, ServiceStatus
from app.modules.db.db_model import CheckerSetting, Server, ServiceStatus, UDPBalancer
from app.modules.db.common import out_error
@ -146,3 +146,10 @@ def select_all_alerts(group_id: int):
return query.execute()
except Exception as e:
out_error(e)
def select_checker_udp_enabled():
try:
return UDPBalancer.select().where(UDPBalancer.is_checker == 1)
except Exception as e:
out_error(e)

View File

@ -756,6 +756,7 @@ class UDPBalancer(BaseModel):
delay_loop = IntegerField(constraints=[SQL('DEFAULT "10"')])
delay_before_retry = IntegerField(constraints=[SQL('DEFAULT "10"')])
retry = IntegerField(constraints=[SQL('DEFAULT "3"')])
is_checker = IntegerField(constraints=[SQL('DEFAULT "0"')])
class Meta:
table_name = 'udp_balancers'

View File

@ -3,6 +3,15 @@ from app.modules.db.common import out_error
from app.modules.roxywi.exception import RoxywiResourceNotFound, RoxywiGroupNotFound
def select_all_listeners() -> UDPBalancer:
try:
return UDPBalancer.select().execute()
except UDPBalancer.DoesNotExist:
raise RoxywiResourceNotFound
except Exception as e:
out_error(e)
def select_listeners(group_id: int) -> UDPBalancer:
try:
return UDPBalancer.select().where(UDPBalancer.group_id == group_id).execute()

View File

@ -93,6 +93,7 @@ class UdpListenerRequest(BaseModel):
delay_loop: Optional[int] = 10
delay_before_retry: Optional[int] = 10
retry: Optional[int] = 3
is_checker: Optional[bool] = 0
class UserPost(BaseModel):

View File

@ -1,4 +1,5 @@
import json
import os
from flask import render_template
@ -472,6 +473,7 @@ def delete_server(server_id: int) -> None:
server_sql.delete_system_info(server_id)
service_sql.delete_service_settings(server_id)
roxywi_common.logging(server.ip, f'The server {server.hostname} has been deleted', roxywi=1, login=1)
os.system(f'ssh-keygen -R {server.ip}')
def server_is_up(server_ip: str) -> str:

View File

@ -54,8 +54,10 @@ def alert_routing(
) -> None:
try:
subject: str = level + ': ' + mes
server_id: int = server_sql.get_server_by_ip(server_ip).server_id
checker_settings = checker_sql.select_checker_settings_for_server(service_id, server_id)
checker_settings = []
if service_id != 6:
server_id: int = server_sql.get_server_by_ip(server_ip).server_id
checker_settings = checker_sql.select_checker_settings_for_server(service_id, server_id)
except Exception as e:
raise Exception(f'Cannot get settings: {e}')

View File

@ -35,6 +35,30 @@ $( function() {
$('.check_backends').hide();
}
});
$( ".udp-act-links" ).change(function() {
let id = $(this).attr('id').split('-');
console.log(id)
console.log('update checker settings ' + id[1])
let alert_en = 0;
if ($('#alert-' + id[1]).is(':checked')) {
alert_en = 1;
}
$.ajax({
url: api_prefix + "/udp/listener/" + id[1] + '/checker/' + alert_en,
contentType: "application/json; charset=utf-8",
method: "POST",
success: function (data) {
if (data.status === 'failed') {
toastr.error(data.error);
} else {
$("#server-" + id[1]).addClass("update", 1000);
setTimeout(function () {
$("#server-" + id[1]).removeClass("update");
}, 2500);
}
}
});
});
});
function getHAClusterVIPS(cluster_id) {
let vip_id = $('#vip');
@ -384,6 +408,7 @@ function getUDPListener(listener_id, new_listener=false) {
}
$('#listener-'+listener_id).removeClass('animated-background');
$.getScript(awesome);
$( "input[type=checkbox]" ).checkboxradio();
}
}
});

View File

@ -1,5 +1,7 @@
{% import 'languages/'+lang|default('en')+'.html' as lang %}
{% from 'include/input_macros.html' import input, checkbox, copy_to_clipboard %}
{% set checker_desc = lang.services.hapservers_desc %}
<script src="/static/js/udp.js"></script>
<div id="listener-{{listener.id}}" class="div-server-hapwi div-server-head-dis">
<div class="server-name">
<span class="overflow name-span">
@ -48,6 +50,16 @@
</script>
{% endfor %}
</div>
<div class="udp-act-links" id="server-{{listener.id|string()}}">
{% if g.user_params['role'] <= 2 %}
{% set id = 'alert-' + listener.id|string() %}
{% if listener.is_checker == 1 %}
{{ checkbox(id, title=checker_desc, value='1', desc='Checker', checked='checked') }}
{% else %}
{{ checkbox(id, title=checker_desc, value='1', desc='Checker') }}
{% endif %}
{% endif %}
</div>
</div>
</div>
<script>

View File

@ -208,6 +208,9 @@ class UDPListener(MethodView):
reconfigure:
type: boolean
description: If 1, reconfigure UDP listener. If 0, just save UDP listener without configuration on servers
is_checker:
type: boolean
description: Should be Checker service check this UDP listener?
responses:
201:
description: UDP listener created successfully
@ -312,6 +315,9 @@ class UDPListener(MethodView):
reconfigure:
type: boolean
description: If 1, reconfigure UDP listener. If 0, just save UDP listener without configuration on servers
is_checker:
type: boolean
description: Should be Checker service check this UDP listener?
responses:
201:
description: UDP listener created successfully
@ -566,3 +572,26 @@ class UDPListenerBackendStatusView(MethodView):
status = server_mod.ssh_command(server_ip, cmd)
status = status.replace('\r\n', '')
return DataStrResponse(data=status).model_dump(mode='json')
class UdpListenerCheckerView(MethodView):
methods = ['POST']
decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=3), check_group()]
@validate(query=GroupQuery)
def post(self, service: str, listener_id: int, is_checker: int, query: GroupQuery):
try:
_ = SupportClass.return_group_id(query)
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot get UDP listeners')
try:
udp_sql.get_listener(listener_id)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get UDP listeners')
try:
udp_sql.update_listener(listener_id, is_checker=is_checker)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot update checker settings on UDP listener')
return BaseResponse().model_dump(mode='json'), 201