Browse Source

v8.1.0.1: Fix numeration and refactor code for consistency

Correct feature list numeration in README.md and improve JavaScript variable naming and data type consistency. Also enhance HAProxy section handling in templates and API endpoints to ensure better error handling and data processing.
pull/399/head
Aidaho 1 month ago
parent
commit
2fa880578a
  1. 70
      README.md
  2. 28
      app/modules/roxywi/class_models.py
  3. 3
      app/modules/service/installation.py
  4. 24
      app/scripts/ansible/roles/haproxy_section/templates/section.j2
  5. 2
      app/static/js/add.js
  6. 30
      app/static/js/edit_config.js
  7. 70
      app/views/service/haproxy_section_views.py

70
README.md

@ -12,39 +12,39 @@ Web interface (user-friendly web GUI, alerting, monitoring and secure) for manag
# Features:
1. Installing and updating HAProxy, Nginx, Apache and Keepalived with Roxy-WI as a system service
2. Installing and updating HAProxy and Nginx with Roxy-WI as a Docker service
4. Installing and updating HAProxy, Nginx, Apache, Keepalived and Node exporters with Roxy-WI
6. Downloading, updating and formatting GeoIP to the acceptable format for HAProxy with Roxy-WI
7. Dynamic change of Maxconn, Black/white lists, add, edit or delete backend's IP address and port with saving changes to the config file
8. Configuring HAProxy, Nginx, Apache and Keepalived in a jiffy with Roxy-WI
9. Viewing and analysing the status of all Frontend/backend servers via Roxy-WI from a single control panel
10. Enabling/disabling servers through stats page without rebooting HAProxy
11. Viewing/Analysing HAProxy, Nginx, Apache and Keepalived logs right from the Roxy-WI web interface
12. Creating and visualizing the HAProxy workflow from Web Ui
13. Pushing Your changes to your HAProxy, Nginx, Apache and Keepalived servers with a single click via the web interface
14. Getting info on past changes, evaluating your config files and restoring the previous stable config at any time with a single click right from Web interface
15. Adding/Editing Frontend or backend servers via the web interface with a click
16. Editing the config of HAProxy, Nginx, Apache and Keepalived and push interchanges to All Master/Slave servers by a single click
17. Adding Multiple servers to ensure the Config Sync between servers
18. Managing the ports assigned to Frontend automatically
19. Evaluating the changes of recent configs pushed to HAProxy, Nginx, Apache and Keepalived instances right from the Web UI
20. Multiple User Roles support for privileged based Viewing and editing of Config
21. Creating Groups and adding/removing servers to ensure the proper identification for your HAProxy, Nginx and Apache Clusters
22. Sending notifications from Roxy-WI via Telegram, Slack, Email, PageDuty and via the web interface
23. Supporting high Availability to ensure uptime to all Master slave servers configured
24. Support of SSL (including Let's Encrypt)
25. Support of SSH Key for managing multiple HAProxy, Nginx, Apache and Keepalived Servers straight from Roxy-WI
26. SYN flood protect
27. Alerting about changes of the state of HAProxy backends, about approaching the limit of Maxconn
28. Alerting about the state of HAProxy, Nginx, Apache and Keepalived service
29. Gathering metrics for incoming connections
30. Web acceleration settings
31. Firewall for web application (WAF)
32. LDAP support
33. Keep active HAProxy, Nginx, Apache and Keepalived services
34. Possibility to hide parts of the config with tags for users with "guest" role: "HideBlockStart" and "HideBlockEnd"
35. Mobile-ready design
36. [SMON](https://roxy-wi.org/services/smon) (Check: Ping, TCP/UDP, HTTP(s), SSL expiry, HTTP body answer, DNS records, Status pages)
37. Backup HAProxy, Nginx, Apache and Keepalived config files through Roxy-WI
3. Installing and updating HAProxy, Nginx, Apache, Keepalived and Node exporters with Roxy-WI
4. Downloading, updating and formatting GeoIP to the acceptable format for HAProxy with Roxy-WI
5. Dynamic change of Maxconn, Black/white lists, add, edit or delete backend's IP address and port with saving changes to the config file
6. Configuring HAProxy, Nginx, Apache and Keepalived in a jiffy with Roxy-WI
7. Viewing and analysing the status of all Frontend/backend servers via Roxy-WI from a single control panel
8. Enabling/disabling servers through stats page without rebooting HAProxy
9. Viewing/Analysing HAProxy, Nginx, Apache and Keepalived logs right from the Roxy-WI web interface
10. Creating and visualizing the HAProxy workflow from Web Ui
11. Pushing Your changes to your HAProxy, Nginx, Apache and Keepalived servers with a single click via the web interface
12. Getting info on past changes, evaluating your config files and restoring the previous stable config at any time with a single click right from Web interface
13. Adding/Editing Frontend or backend servers via the web interface with a click
14. Editing the config of HAProxy, Nginx, Apache and Keepalived and push interchanges to All Master/Slave servers by a single click
15. Adding Multiple servers to ensure the Config Sync between servers
16. Managing the ports assigned to Frontend automatically
17. Evaluating the changes of recent configs pushed to HAProxy, Nginx, Apache and Keepalived instances right from the Web UI
18. Multiple User Roles support for privileged based Viewing and editing of Config
19. Creating Groups and adding/removing servers to ensure the proper identification for your HAProxy, Nginx and Apache Clusters
20. Sending notifications from Roxy-WI via Telegram, Slack, Email, PageDuty and via the web interface
21. Supporting high Availability to ensure uptime to all Master slave servers configured
22. Support of SSL (including Let's Encrypt)
23. Support of SSH Key for managing multiple HAProxy, Nginx, Apache and Keepalived Servers straight from Roxy-WI
24. SYN flood protect
25. Alerting about changes of the state of HAProxy backends, about approaching the limit of Maxconn
26. Alerting about the state of HAProxy, Nginx, Apache and Keepalived service
27. Gathering metrics for incoming connections
28. Web acceleration settings
29. Firewall for web application (WAF)
30. LDAP support
31. Keep active HAProxy, Nginx, Apache and Keepalived services
32. Possibility to hide parts of the config with tags for users with "guest" role: "HideBlockStart" and "HideBlockEnd"
33. Mobile-ready design
34. [SMON](https://roxy-wi.org/services/smon) (Check: Ping, TCP/UDP, HTTP(s), SSL expiry, HTTP body answer, DNS records, Status pages)
35. Backup HAProxy, Nginx, Apache and Keepalived config files through Roxy-WI
@ -60,10 +60,6 @@ Web interface (user-friendly web GUI, alerting, monitoring and secure) for manag
### Read instruction on the official [site](https://roxy-wi.org/installation#deb)
## Manual install
### Read instruction on the official [site](https://roxy-wi.org/installation#manual)
# OS support
Roxy-WI supports the following OSes:
1. EL7(RPM installation and manual installation). It must be "Infrastructure Server" at least. x86_64 only

28
app/modules/roxywi/class_models.py

@ -331,7 +331,7 @@ class HaproxyBackendServer(BaseModel):
class HaproxyCookie(BaseModel):
dynamic: str
dynamicKey: str
dynamic_key: str
domain: Optional[str] = None
name: Optional[str] = None
nocache: Optional[str] = None
@ -371,25 +371,25 @@ class HaproxyConfigRequest(BaseModel):
name: EscapedString
option: Optional[str] = None
maxconn: Optional[int] = 2000
waf: Optional[bool] = 0
binds: List[HaproxyBinds]
headers: List[HaproxyHeaders] = None
acls: List[HaproxyAcls] = None
backend_servers: List[HaproxyBackendServer] = None
waf: Optional[bool] = False
binds: Optional[List[HaproxyBinds]] = None
headers: Optional[List[HaproxyHeaders]] = None
acls: Optional[List[HaproxyAcls]] = None
backend_servers: Optional[List[HaproxyBackendServer]] = None
blacklist: Optional[str] = ''
whitelist: Optional[str] = ''
ssl: Optional[HaproxySSL] = None
cache: Optional[bool] = 0
compression: Optional[bool] = 0
cache: Optional[bool] = False
compression: Optional[bool] = False
cookie: Optional[HaproxyCookie] = None
health_check: Optional[HaproxyHealthCheck] = None
servers_check: Optional[HaproxyServersCheck] = None
ssl_offloading: Optional[bool] = 0
redispatch: Optional[bool] = 0
forward_for: Optional[bool] = 0
slow_attack: Optional[bool] = 0
ddos: Optional[bool] = 0
antibot: Optional[bool] = 0
ssl_offloading: Optional[bool] = False
redispatch: Optional[bool] = False
forward_for: Optional[bool] = False
slow_attack: Optional[bool] = False
ddos: Optional[bool] = False
antibot: Optional[bool] = False
backends: Optional[str] = None
circuit_breaking: Optional[HaproxyCircuitBreaking] = None
action: Optional[Literal['save', 'test', 'reload', 'restart']] = "save"

3
app/modules/service/installation.py

@ -1,5 +1,6 @@
import os
import json
import random
from typing import Union
from packaging import version
@ -328,7 +329,7 @@ def run_ansible(inv: dict, server_ips: list, ansible_role: str) -> dict:
def run_ansible_locally(inv: dict, ansible_role: str) -> dict:
inventory_path = '/var/www/haproxy-wi/app/scripts/ansible/inventory'
inventory = f'{inventory_path}/{ansible_role}.json'
inventory = f'{inventory_path}/{ansible_role}-{random.randint(0, 35)}.json'
# proxy = sql.get_setting('proxy')
# proxy_serv = ''

24
app/scripts/ansible/roles/haproxy_section/templates/section.j2

@ -1,8 +1,10 @@
{{ config.type }} {{ config.name }}
{% if config.binds != 'None' -%}
{% for bind in config.binds -%}
bind {{ bind.ip }}:{{ bind.port }} {% if config.ssl != 'None' and config.mode == 'http' and config.ssl.cert %} ssl crt {{cert_path}}/{{ config.ssl.cert }}{% endif %}
{% endfor %}
{% endif %}
mode {{ config.mode }}
{% if config.balance != 'None' -%}
@ -24,16 +26,16 @@
{% endfor %}
{% endif %}
{% if config.whitelist -%}
acl white_list_{{ whitelist }} src -f {{ haproxy_dir }}/white/{{ config.whitelist }}
tcp-request content accept if white_list_{{ whitelist }}
{% if config.whitelist and config.whitelist != 'None' -%}
acl white_list_{{ config.whitelist }} src -f {{ haproxy_dir }}/white/{{ config.whitelist }}
tcp-request content accept if white_list_{{ config.whitelist }}
tcp-request content reject
{% endif %}
{% if config.blacklist -%}
{% if config.blacklist and config.blacklist != 'None' -%}
tcp-request connection reject if { src -f {{ haproxy_dir }}/white/{{ config.blacklist }} }
{% endif %}
{% if config.acls -%}
{% if config.acls != 'None' -%}
{% for acl in config.acls -%}
{% if acl.acl_if in (1, 2) -%}
{% if config.mode == 'tcp' -%}
@ -66,7 +68,7 @@
{% if config.redispatch -%}
{{ redispatch }}
{% endif -%}
{% if config.ssl_offloading -%}
{% if config.ssl_offloading and config.ssl_offloading != 'None' -%}
{{ ssl_offloading }}
{% endif -%}
@ -93,8 +95,8 @@
{% if config.cookie != 'None' -%}
cookie {{ config.cookie.name }} {% if config.cookie.domain != 'None' %} {{ config.cookie.domain }}{% endif %} {{ config.cookie.rewrite }} {{ config.cookie.prefix }} {{ config.cookie.nocache }} {{ config.cookie.postonly }} {{ config.cookie.dynamic }}
{% if config.cookie.dynamicKey -%}
dynamic-cookie-key {{ config.cookie.dynamicKey }}
{% if config.cookie.dynamic_key -%}
dynamic-cookie-key {{ config.cookie.dynamic_key }}
{% endif -%}
{% endif -%}
@ -110,12 +112,10 @@
{% if config.servers_check != 'None' and config.servers_check.check_enabled -%}
{%- set check_option = ' check inter ' + config.servers_check.inter|string() + ' rise ' + config.servers_check.rise|string() + ' fall ' + config.servers_check.fall|string() %}
{% else -%}
{% if config.servers_check != 'None' and config.servers_check.check_enabled == 'None' -%}
{% set check_option = '' -%}
{% endif -%}
{% endif -%}
{% if config.option != '' -%}
{% if config.option != '' and config.option != 'None' -%}
{% for o in config.option.split('\\r\\n') -%}
{{ o }}
{% endfor -%}
@ -130,10 +130,12 @@
default-server observe {{ config.circuit_breaking.observe }} error-limit {{ config.circuit_breaking.error_limit }} on-error {{ config.circuit_breaking.on_error }}
{% endif -%}
{% if config.backend_servers != 'None' -%}
{% for backend in config.backend_servers -%}
server {{ backend.server }} {{ backend.server }}:{{ backend.port }} port {{ backend.port_check }} {{ check_option }} {{ ssl_check_option }} maxconn {{ backend.maxconn }}{% if backend.send_proxy %} send-proxy{% endif %}{% if backend.backup %} backup {% endif %}
{% endfor -%}
{% endif -%}
{% if config.backends and config.backends != 'None' -%}
use_backend {{ config.backends }}

2
app/static/js/add.js

@ -697,7 +697,7 @@ $( function() {
}
for (let section_type of ['listen', 'backend']) {
$("#" + section_type + "_checks").on('selectmenuchange', function () {
let health_check_val = health_check_val;
let health_check_val = $("#" + section_type + "_checks").val();
if (health_check_val === "tcp-check") {
$("#" + section_type + "_checks_note").html(tcp_note)
}

30
app/static/js/edit_config.js

@ -430,12 +430,12 @@ function getFormData($form, form_name) {
let name = $('input[name="cookie_name"]').val();
let domain = $('input[name="cookie_domain"]').val();
let dynamic = $('input[name="dynamic"]').val();
let dynamicKey = $('input[name="dynamic-cookie-key"]').val();
let dynamic_key = $('input[name="dynamic-cookie-key"]').val();
let nocache = $('input[name="nocache"]').val();
let postonly = $('input[name="postonly"]').val();
let rewrite = $('select[name="rewrite"] option:selected').val();
let prefix = $('input[name="prefix"]').val();
indexed_array['cookie'] = {name, domain, dynamic, dynamicKey, nocache, postonly, rewrite, prefix}
indexed_array['cookie'] = {name, domain, dynamic, dynamic_key, nocache, postonly, rewrite, prefix}
}
} else if (n['name'] === 'whitelist_checkbox') {
if ($('input[name="whitelist_checkbox"]').is(':checked')) {
@ -444,11 +444,11 @@ function getFormData($form, form_name) {
} else if (n['name'] === 'ssl') {
if ($('input[name="ssl"]').is(':checked')) {
let cert = $('input[name="cert"]').val();
let ssl_check_backend = 1;
let ssl_check_backend = true;
if ($('input[name="ssl-check"]').is(':checked')) {
ssl_check_backend = 0;
} else {
ssl_check_backend = 1;
ssl_check_backend = true;
}
indexed_array['ssl'] = {cert, ssl_check_backend};
}
@ -466,31 +466,31 @@ function getFormData($form, form_name) {
}
} else if (n['name'] === 'ssl_offloading') {
if ($('input[name="ssl_offloading"]').is(':checked')) {
indexed_array['ssl_offloading'] = 1;
indexed_array['ssl_offloading'] = true;
}
} else if (n['name'] === 'forward_for') {
if ($('input[name="forward_for"]').is(':checked')) {
indexed_array['forward_for'] = 1;
indexed_array['forward_for'] = true;
}
} else if (n['name'] === 'redispatch') {
if ($('input[name="redispatch"]').is(':checked')) {
indexed_array['redispatch'] = 1;
indexed_array['redispatch'] = true;
}
} else if (n['name'] === 'slow_attack') {
if ($('input[name="slow_attack"]').is(':checked')) {
indexed_array['slow_attack'] = 1;
indexed_array['slow_attack'] = true;
}
} else if (n['name'] === 'ddos') {
if ($('input[name="ddos"]').is(':checked')) {
indexed_array['ddos'] = 1;
indexed_array['ddos'] = true;
}
} else if (n['name'] === 'antibot') {
if ($('input[name="antibot"]').is(':checked')) {
indexed_array['antibot'] = 1;
indexed_array['antibot'] = true;
}
} else if (n['name'] === 'cache') {
if ($('input[name="cache"]').is(':checked')) {
indexed_array['cache'] = 1;
indexed_array['cache'] = true;
}
} else if (n['name'] === 'circuit_breaking') {
if ($('input[name="circuit_breaking"]').is(':checked')) {
@ -501,7 +501,7 @@ function getFormData($form, form_name) {
}
} else if (n['name'] === 'check-servers') {
if ($('input[name="check-servers"]').is(':checked')) {
let check_enabled = 1;
let check_enabled = true;
let inter = $('select[name="inter"] option:selected').val();
let rise = $('select[name="rise"] option:selected').val();
let fall = $('select[name="fall"] option:selected').val();
@ -534,7 +534,7 @@ function getFormData($form, form_name) {
}
} else if (n['name'] === 'daemon') {
if ($('input[name="daemon"]').is(':checked')) {
indexed_array['daemon'] = 1;
indexed_array['daemon'] = true;
}
} else {
indexed_array[n['name']] = n['value'];
@ -607,10 +607,10 @@ function getFormData($form, form_name) {
let send_proxy = 0;
let backup = 0;
if ($(this).children().children('input[name="send_proxy"]').is(':checked')) {
send_proxy = 1;
send_proxy = true;
}
if ($(this).children().children('input[name="backup"]').is(':checked')) {
backup = 1;
backup = true;
}
let test_var = {server, port, port_check, maxconn, send_proxy, backup};
indexed_array['backend_servers'].push(test_var);

70
app/views/service/haproxy_section_views.py

@ -16,7 +16,8 @@ import app.modules.roxywi.common as roxywi_common
from app.middleware import get_user_params, page_for_admin, check_group, check_services
from app.modules.db.db_model import Server
from app.modules.roxywi.class_models import BaseResponse, DataStrResponse, HaproxyConfigRequest, GenerateConfigRequest, \
HaproxyUserListRequest, HaproxyPeersRequest, HaproxyGlobalRequest, HaproxyDefaultsRequest, IdDataStrResponse
HaproxyUserListRequest, HaproxyPeersRequest, HaproxyGlobalRequest, HaproxyDefaultsRequest, IdDataStrResponse, \
ErrorResponse
from app.modules.common.common_classes import SupportClass
@ -84,14 +85,15 @@ class HaproxySectionView(MethodView):
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create HAProxy section')
if 'Fatal' in output or 'error' in output:
return ErrorResponse(error=output).model_dump(mode='json'), 500
try:
add_sql.insert_new_section(server_id, section_type, body.name, body)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot add HAProxy section')
res = IdDataStrResponse(data=output, id=f'{server_id}-{body.name}').model_dump(mode='json')
print(res)
return res, 201
return IdDataStrResponse(data=output, id=f'{server_id}-{body.name}').model_dump(mode='json'), 201
def put(self,
service: Literal['haproxy'],
@ -116,7 +118,7 @@ class HaproxySectionView(MethodView):
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create HAProxy section')
if 'Fatal' in output or 'error' in output:
return DataStrResponse(data=output).model_dump(mode='json'), 201
return ErrorResponse(error=output).model_dump(mode='json'), 500
else:
try:
if section_name in ('global', 'defaults'):
@ -168,7 +170,13 @@ class HaproxySectionView(MethodView):
if len(output['failures']) > 0 or len(output['dark']) > 0:
raise Exception('Cannot create HAProxy section. Check Apache error log')
output = config_mod.master_slave_upload_and_restart(server.ip, cfg, str(body.action), 'haproxy')
if body:
if body.action:
action = str(body.action)
else:
action = 'save'
output = config_mod.master_slave_upload_and_restart(server.ip, cfg, action, 'haproxy')
return output
@ -285,8 +293,6 @@ class ListenSectionView(HaproxySectionView):
type: string
redispatch:
type: integer
server:
type: integer
servers_check:
type: object
slow_attack:
@ -297,6 +303,10 @@ class ListenSectionView(HaproxySectionView):
type: string
waf:
type: integer
antibot:
type: integer
ddos:
type: integer
whitelist:
type: string
id:
@ -403,9 +413,9 @@ class ListenSectionView(HaproxySectionView):
server:
type: string
port:
type: string
type: integer
port_check:
type: string
type: integer
maxconn:
type: string
send_proxy:
@ -414,8 +424,6 @@ class ListenSectionView(HaproxySectionView):
type: integer
type:
type: string
server:
type: string
name:
type: string
mode:
@ -456,8 +464,10 @@ class ListenSectionView(HaproxySectionView):
type: string
forward_for:
type: integer
force_close:
type: string
antibot:
type: integer
ddos:
type: integer
cookie:
type: object
properties:
@ -467,7 +477,7 @@ class ListenSectionView(HaproxySectionView):
type: string
dynamic:
type: string
dynamicKey:
dynamic_key:
type: string
nocache:
type: string
@ -481,13 +491,11 @@ class ListenSectionView(HaproxySectionView):
type: object
properties:
inter:
type: string
type: integer
rise:
type: string
type: integer
fall:
type: string
inter:
type: string
type: integer
circuit_breaking:
type: object
properties:
@ -592,19 +600,17 @@ class ListenSectionView(HaproxySectionView):
server:
type: string
port:
type: string
type: integer
port_check:
type: string
maxconn:
type: string
type: integer
send_proxy:
type: integer
backup:
type: integer
type:
type: string
server:
type: string
name:
type: string
mode:
@ -645,8 +651,10 @@ class ListenSectionView(HaproxySectionView):
type: string
forward_for:
type: integer
force_close:
type: string
antibot:
type: integer
ddos:
type: integer
cookie:
type: object
properties:
@ -656,7 +664,7 @@ class ListenSectionView(HaproxySectionView):
type: string
dynamic:
type: string
dynamicKey:
dynamic_key:
type: string
nocache:
type: string
@ -670,13 +678,11 @@ class ListenSectionView(HaproxySectionView):
type: object
properties:
inter:
type: string
type: integer
rise:
type: string
type: integer
fall:
type: string
inter:
type: string
type: integer
circuit_breaking:
type: object
properties:

Loading…
Cancel
Save