Browse Source

v8.0: Remove redundant requirement files and update VIP handling

Removed outdated Debian, EL7, EL8, and EL9 requirement files. Improved various VIP handling and validation functionalities, including changes to VIP endpoints and associated JavaScript functions. Minor enhancements and bug fixes across multiple modules and views.
pull/399/head
Aidaho 3 months ago
parent
commit
0391dff9eb
  1. 54
      app/modules/db/ha_cluster.py
  2. 21
      app/modules/db/service.py
  3. 17
      app/modules/roxywi/class_models.py
  4. 191
      app/modules/service/ha_cluster.py
  5. 20
      app/routes/ha/routes.py
  6. 2
      app/static/css/styles.css
  7. 51
      app/static/js/ha.js
  8. 3
      app/templates/ajax/ha/clusters.html
  9. 2
      app/templates/include/add_backup.html
  10. 2
      app/templates/include/admins_dialogs.html
  11. 141
      app/views/ha/views.py
  12. 46
      app/views/server/backup_vews.py
  13. 10
      app/views/service/views.py
  14. 23
      config_other/requirements_deb.txt
  15. 23
      config_other/requirements_el7.txt
  16. 24
      config_other/requirements_el8.txt
  17. 25
      config_other/requirements_el9.txt

54
app/modules/db/ha_cluster.py

@ -1,5 +1,6 @@
from app.modules.db.db_model import connect, HaCluster, HaClusterVirt, HaClusterVip, HaClusterService, HaClusterSlave, Server, HaClusterRouter from app.modules.db.db_model import connect, HaCluster, HaClusterVirt, HaClusterVip, HaClusterService, HaClusterSlave, Server, HaClusterRouter
from app.modules.db.common import out_error from app.modules.db.common import out_error
from app.modules.roxywi.exception import RoxywiResourceNotFound
def select_clusters(group_id: int): def select_clusters(group_id: int):
@ -26,6 +27,13 @@ def select_cluster(cluster_id: int):
out_error(e) out_error(e)
def get_cluster(cluster_id: int):
try:
return HaCluster.get(HaCluster.id == cluster_id)
except Exception as e:
out_error(e)
def select_cluster_name(cluster_id: int) -> str: def select_cluster_name(cluster_id: int) -> str:
try: try:
return HaCluster.get(HaCluster.id == cluster_id).name return HaCluster.get(HaCluster.id == cluster_id).name
@ -54,6 +62,13 @@ def select_cluster_vip(cluster_id: int, router_id: int) -> HaClusterVip:
out_error(e) out_error(e)
def select_cluster_vip_by_vip_id(cluster_id: int, vip_id: int) -> HaClusterVip:
try:
return HaClusterVip.get((HaClusterVip.cluster_id == cluster_id) & (HaClusterVip.id == vip_id))
except Exception as e:
out_error(e)
def select_clusters_vip_id(cluster_id: int, router_id): def select_clusters_vip_id(cluster_id: int, router_id):
try: try:
return HaClusterVip.get((HaClusterVip.cluster_id == cluster_id) & (HaClusterVip.router_id == router_id)).id return HaClusterVip.get((HaClusterVip.cluster_id == cluster_id) & (HaClusterVip.router_id == router_id)).id
@ -75,6 +90,15 @@ def insert_cluster_services(cluster_id: int, service_id: int):
out_error(e) out_error(e)
def select_count_cluster_slaves(cluster_id: int) -> int:
try:
return HaClusterSlave.select().where(HaClusterSlave.cluster_id == cluster_id).count()
except HaClusterSlave.DoesNotExist:
raise RoxywiResourceNotFound
except Exception as e:
out_error(e)
def select_cluster_master_slaves(cluster_id: int, group_id: int, router_id: int): def select_cluster_master_slaves(cluster_id: int, group_id: int, router_id: int):
conn = connect() conn = connect()
cursor = conn.cursor() cursor = conn.cursor()
@ -149,6 +173,8 @@ def get_router_id(cluster_id: int, default_router=0) -> int:
""" """
try: try:
return HaClusterRouter.get((HaClusterRouter.cluster_id == cluster_id) & (HaClusterRouter.default == default_router)).id return HaClusterRouter.get((HaClusterRouter.cluster_id == cluster_id) & (HaClusterRouter.default == default_router)).id
except HaClusterRouter.DoesNotExist:
raise RoxywiResourceNotFound
except Exception as e: except Exception as e:
out_error(e) out_error(e)
@ -160,21 +186,22 @@ def get_router(router_id: int) -> HaClusterRouter:
out_error(e) out_error(e)
def create_ha_router(cluster_id: int) -> int: def create_ha_router(cluster_id: int, default: int = 0) -> int:
""" """
Create HA Router Create HA Router
This method is used to create a HA (High Availability) router for a given cluster. This method is used to create a HA (High Availability) router for a given cluster.
:param cluster_id: The ID of the cluster for which the HA router needs to be created. :param default:
:return: The ID of the created HA router. :param cluster_id: The ID of the cluster for which the HA router needs to be created.
:rtype: int :return: The ID of the created HA router.
:rtype: int
:raises Exception: If an error occurs while creating the HA router. :raises Exception: If an error occurs while creating the HA router.
""" """
try: try:
last_id = HaClusterRouter.insert(cluster_id=cluster_id).execute() last_id = HaClusterRouter.insert(cluster_id=cluster_id, default=default).on_conflict_ignore().execute()
return last_id return last_id
except Exception as e: except Exception as e:
out_error(e) out_error(e)
@ -256,15 +283,6 @@ def select_cluster_services(cluster_id: int):
out_error(e) out_error(e)
def update_server_master(master, slave):
try:
master_id = Server.get(Server.ip == master).server_id
except Exception as e:
out_error(e)
update_master_server_by_slave_ip(master_id, slave)
def update_master_server_by_slave_ip(master_id: int, slave_ip: str) -> None: def update_master_server_by_slave_ip(master_id: int, slave_ip: str) -> None:
try: try:
Server.update(master=master_id).where(Server.ip == slave_ip).execute() Server.update(master=master_id).where(Server.ip == slave_ip).execute()

21
app/modules/db/service.py

@ -150,24 +150,17 @@ def select_service_id_by_slug(service_slug: str) -> int:
def select_services(): def select_services():
query = Services.select()
try: try:
query_res = query.execute() return Services.select().execute()
except Exception as e: except Exception as e:
out_error(e) out_error(e)
return
else:
return query_res
def select_service(slug: str) -> object: def select_service(slug: str) -> Services:
try: try:
query_res = Services.get(Services.slug == slug) return Services.get(Services.slug == slug)
except Exception as e: except Exception as e:
out_error(e) out_error(e)
return 'there is no service'
else:
return query_res
def update_keepalived(serv): def update_keepalived(serv):
@ -179,11 +172,9 @@ def update_keepalived(serv):
def select_apache(serv): def select_apache(serv):
try: try:
apache = Server.get(Server.ip == serv).apache return Server.get(Server.ip == serv).apache
except Exception as e: except Exception as e:
out_error(e) out_error(e)
else:
return apache
def update_apache(serv: str) -> None: def update_apache(serv: str) -> None:
@ -195,11 +186,9 @@ def update_apache(serv: str) -> None:
def select_nginx(serv): def select_nginx(serv):
try: try:
query_res = Server.get(Server.ip == serv).nginx return Server.get(Server.ip == serv).nginx
except Exception as e: except Exception as e:
out_error(e) out_error(e)
else:
return query_res
def update_nginx(serv: str) -> None: def update_nginx(serv: str) -> None:

17
app/modules/roxywi/class_models.py

@ -79,6 +79,9 @@ class UdpListenerRequest(BaseModel):
lb_algo: Literal['rr', 'wrr', 'lc', 'wlc', 'sh', 'dh', 'wlc', 'lblc'] lb_algo: Literal['rr', 'wrr', 'lc', 'wlc', 'sh', 'dh', 'wlc', 'lblc']
check_enabled: Optional[bool] = 1 check_enabled: Optional[bool] = 1
reconfigure: Optional[bool] = 0 reconfigure: Optional[bool] = 0
delay_loop: Optional[int] = 10
delay_before_retry: Optional[int] = 10
retry: Optional[int] = 3
class UserPost(BaseModel): class UserPost(BaseModel):
@ -144,23 +147,23 @@ class CredUploadRequest(BaseModel):
class HAClusterServer(BaseModel): class HAClusterServer(BaseModel):
eth: EscapedString eth: EscapedString
id: int id: int
ip: Union[IPvAnyAddress, DomainName]
name: EscapedString
master: Optional[bool] = 1 master: Optional[bool] = 1
class HAClusterServersRequest(BaseModel):
servers: List[HAClusterServer]
class HAClusterService(BaseModel): class HAClusterService(BaseModel):
enabled: Optional[bool] = 0 enabled: Optional[bool] = 0
docker: Optional[bool] = 0 docker: Optional[bool] = 0
class HAClusterVIP(BaseModel): class HAClusterVIP(BaseModel):
name: EscapedString
use_src: Optional[bool] = 1 use_src: Optional[bool] = 1
vip: IPvAnyAddress vip: IPvAnyAddress
return_master: Optional[bool] = 1 return_master: Optional[bool] = 1
virt_server: Optional[bool] = 1 virt_server: Optional[bool] = 1
router_id: Optional[int] = None
servers: List[HAClusterServer] servers: List[HAClusterServer]
@ -168,16 +171,16 @@ class HAClusterRequest(BaseModel):
name: EscapedString name: EscapedString
description: Optional[EscapedString] = None description: Optional[EscapedString] = None
return_master: Optional[bool] = 1 return_master: Optional[bool] = 1
servers: List[HAClusterServer] servers: Optional[List[HAClusterServer]] = None
services: Dict[str, HAClusterService] services: Dict[str, HAClusterService]
syn_flood: Optional[bool] = 1 syn_flood: Optional[bool] = 1
use_src: Optional[bool] = 1 use_src: Optional[bool] = 1
vip: IPvAnyAddress vip: Optional[IPvAnyAddress] = None
virt_server: Optional[bool] = 1 virt_server: Optional[bool] = 1
class ConfigFileNameQuery(BaseModel): class ConfigFileNameQuery(BaseModel):
file_name: Optional[str] = None file_path: Optional[str] = None
version: Optional[str] = None version: Optional[str] = None

191
app/modules/service/ha_cluster.py

@ -4,15 +4,16 @@ import app.modules.db.server as server_sql
import app.modules.db.ha_cluster as ha_sql import app.modules.db.ha_cluster as ha_sql
import app.modules.db.service as service_sql import app.modules.db.service as service_sql
from app.modules.db.db_model import HaCluster, HaClusterRouter, HaClusterVip, HaClusterVirt from app.modules.db.db_model import HaCluster, HaClusterRouter, HaClusterVip, HaClusterVirt
import app.modules.server.server as server_mod
import app.modules.roxywi.common as roxywi_common import app.modules.roxywi.common as roxywi_common
from app.modules.server.ssh import return_ssh_keys_path from app.modules.roxywi.class_models import HAClusterRequest, HAClusterVIP, HAClusterServersRequest
from app.modules.roxywi.class_models import HAClusterRequest, HAClusterVIP from app.modules.roxywi.exception import RoxywiResourceNotFound
def _get_servers_dict(cluster: Union[HAClusterRequest, HAClusterVIP]) -> dict: def _get_servers_dict(cluster: Union[HAClusterRequest, HAClusterVIP, HAClusterServersRequest]) -> Union[dict, None]:
for i, k in cluster.model_dump(mode='json').items(): for i, k in cluster.model_dump(mode='json').items():
if i == 'servers': if i == 'servers':
if k is None:
return None
servers = k servers = k
return servers return servers
@ -25,7 +26,6 @@ def _get_services_dict(cluster: HAClusterRequest) -> dict:
def create_cluster(cluster: HAClusterRequest, group_id: int) -> int: def create_cluster(cluster: HAClusterRequest, group_id: int) -> int:
master_ip = None
servers = _get_servers_dict(cluster) servers = _get_servers_dict(cluster)
services = _get_services_dict(cluster) services = _get_services_dict(cluster)
@ -35,39 +35,25 @@ def create_cluster(cluster: HAClusterRequest, group_id: int) -> int:
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot create new HA cluster: {e}') raise Exception(f'error: Cannot create new HA cluster: {e}')
try: if not servers is None:
router_id = HaClusterRouter.insert(cluster_id=cluster_id, default=1).on_conflict_ignore().execute()
except Exception as e:
raise Exception(f'error: Cannon create router: {e}')
try:
vip_id = HaClusterVip.insert(cluster_id=cluster_id, router_id=router_id, vip=cluster.vip, return_master=cluster.return_master).execute()
roxywi_common.logging(cluster_id, f'New vip {cluster.vip} has been created and added to the cluster', keep_history=1, roxywi=1, service='HA cluster')
except Exception as e:
raise Exception(f'error: Cannon add VIP: {e}')
for value in servers:
if value['master']:
master_ip = value['ip']
for value in servers:
if value['master']:
continue
try: try:
ha_sql.update_server_master(master_ip, value['ip']) router_id = ha_sql.create_ha_router(cluster_id, default=1)
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot update master on slave {value["ip"]: {e}}') raise Exception(f'error: Cannon create router: {e}')
for value in servers: _create_or_update_master_slaves_servers(cluster_id, servers, router_id, True)
slave_id = value['id']
if value['master']: if cluster.vip:
slave_id = server_sql.select_server_id_by_ip(master_ip) try:
try: vip_id = HaClusterVip.insert(cluster_id=cluster_id, router_id=router_id, vip=cluster.vip,
ha_sql.insert_or_update_slave(cluster_id, slave_id, value['eth'], value['master'], router_id) return_master=cluster.return_master).execute()
roxywi_common.logging(cluster_id, f'New server {value["ip"]} has been added to the cluster', keep_history=1, roxywi=1, service='HA cluster') roxywi_common.logging(cluster_id, f'New vip {cluster.vip} has been created and added to the cluster',
except Exception as e: keep_history=1, roxywi=1, service='HA cluster')
raise Exception(f'error: Cannot update slave server {value["ip"]}: {e}') except Exception as e:
raise Exception(f'error: Cannon add VIP: {e}')
if cluster.virt_server and not servers is None:
add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id)
for service, value in services.items(): for service, value in services.items():
if not value['enabled']: if not value['enabled']:
@ -79,9 +65,6 @@ def create_cluster(cluster: HAClusterRequest, group_id: int) -> int:
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot add service {service}: {e}') raise Exception(f'error: Cannot add service {service}: {e}')
if cluster.virt_server:
add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id)
return int(cluster_id) return int(cluster_id)
@ -89,25 +72,26 @@ def update_cluster(cluster: HAClusterRequest, cluster_id: int, group_id: int) ->
servers = _get_servers_dict(cluster) servers = _get_servers_dict(cluster)
services = _get_services_dict(cluster) services = _get_services_dict(cluster)
try:
router_id = ha_sql.get_router_id(cluster_id, default_router=1)
except Exception as e:
raise Exception(f'error: Cannot get router: {e}')
try: try:
ha_sql.update_cluster(cluster_id, cluster.name, cluster.description, cluster.syn_flood) ha_sql.update_cluster(cluster_id, cluster.name, cluster.description, cluster.syn_flood)
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot update HA cluster: {e}') raise Exception(f'error: Cannot update HA cluster: {e}')
try: if servers:
update_slaves(servers, cluster_id, router_id) try:
except Exception as e: router_id = ha_sql.get_router_id(cluster_id, default_router=1)
raise Exception(e) except Exception as e:
raise Exception(f'error: Cannot get router: {e}')
try: try:
update_vip(cluster_id, router_id, cluster, group_id) update_slaves(servers, cluster_id, router_id)
except Exception as e: except Exception as e:
raise Exception(e) raise Exception(e)
try:
update_vip(cluster_id, router_id, cluster, group_id)
except Exception as e:
raise Exception(e)
try: try:
ha_sql.delete_cluster_services(cluster_id) ha_sql.delete_cluster_services(cluster_id)
@ -126,7 +110,7 @@ def update_cluster(cluster: HAClusterRequest, cluster_id: int, group_id: int) ->
roxywi_common.logging(cluster_id, f'Cluster {cluster.name} has been updated', keep_history=1, roxywi=1, service='HA cluster') roxywi_common.logging(cluster_id, f'Cluster {cluster.name} has been updated', keep_history=1, roxywi=1, service='HA cluster')
def delete_cluster(cluster_id: int) -> str: def delete_cluster(cluster_id: int) -> None:
router_id = ha_sql.get_router_id(cluster_id, default_router=1) router_id = ha_sql.get_router_id(cluster_id, default_router=1)
slaves = ha_sql.select_cluster_slaves(cluster_id, router_id) slaves = ha_sql.select_cluster_slaves(cluster_id, router_id)
@ -137,11 +121,12 @@ def delete_cluster(cluster_id: int) -> str:
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot update master on slave {slave_ip}: {e}') raise Exception(f'error: Cannot update master on slave {slave_ip}: {e}')
HaCluster.delete().where(HaCluster.id == cluster_id).execute() try:
HaCluster.delete().where(HaCluster.id == cluster_id).execute()
except HaCluster.DoesNotExist:
raise RoxywiResourceNotFound
roxywi_common.logging(cluster_id, 'Cluster has been deleted', roxywi=1, service='HA cluster') roxywi_common.logging(cluster_id, 'Cluster has been deleted', roxywi=1, service='HA cluster')
return 'ok'
def update_vip(cluster_id: int, router_id: int, cluster: Union[HAClusterRequest, HAClusterVIP], group_id: int) -> None: def update_vip(cluster_id: int, router_id: int, cluster: Union[HAClusterRequest, HAClusterVIP], group_id: int) -> None:
vip_id = ha_sql.select_clusters_vip_id(cluster_id, router_id) vip_id = ha_sql.select_clusters_vip_id(cluster_id, router_id)
@ -156,8 +141,10 @@ def update_vip(cluster_id: int, router_id: int, cluster: Union[HAClusterRequest,
try: try:
ha_sql.update_slave(cluster_id, value['id'], value['eth'], value['master'], router_id) ha_sql.update_slave(cluster_id, value['id'], value['eth'], value['master'], router_id)
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot add server {value["ip"]}: {e}') s = server_sql.get_server_by_id(value['id'])
raise Exception(f'error: Cannot add server {s.hostname}: {e}')
print('cluster.virt_server',cluster.virt_server)
if cluster.virt_server: if cluster.virt_server:
add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id) add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id)
else: else:
@ -171,14 +158,30 @@ def update_vip(cluster_id: int, router_id: int, cluster: Union[HAClusterRequest,
roxywi_common.logging(cluster_id, f'Cluster VIP {cluster.vip} has been updated', keep_history=1, roxywi=1, service='HA cluster') roxywi_common.logging(cluster_id, f'Cluster VIP {cluster.vip} has been updated', keep_history=1, roxywi=1, service='HA cluster')
def insert_vip(cluster_id: int, cluster: HAClusterVIP, group_id: int) -> None: def insert_vip(cluster_id: int, cluster: HAClusterVIP, group_id: int) -> int:
vip = cluster.vip try:
servers = _get_servers_dict(cluster) slaves_count = ha_sql.select_count_cluster_slaves(cluster_id)
if slaves_count == 0:
try:
router_id = ha_sql.create_ha_router(cluster_id, default=1)
except Exception as e:
raise Exception(f'error: Cannon create a new default router: {e}')
else:
try:
router_id = ha_sql.create_ha_router(cluster_id)
except Exception as e:
raise Exception(f'error: Cannot create new router: {e}')
except Exception as e:
raise e
try: try:
router_id = ha_sql.create_ha_router(cluster_id) vip = cluster.vip
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot create new router: {e}') raise Exception(f'Cannot get VIP: {e}')
try:
servers = _get_servers_dict(cluster)
except Exception as e:
raise Exception(f'Cannot get servers: {e}')
try: try:
vip_id = HaClusterVip.insert(cluster_id=cluster_id, router_id=router_id, vip=vip, return_master=cluster.return_master).execute() vip_id = HaClusterVip.insert(cluster_id=cluster_id, router_id=router_id, vip=vip, return_master=cluster.return_master).execute()
@ -189,33 +192,27 @@ def insert_vip(cluster_id: int, cluster: HAClusterVIP, group_id: int) -> None:
try: try:
ha_sql.insert_or_update_slave(cluster_id, value['id'], value['eth'], value['master'], router_id) ha_sql.insert_or_update_slave(cluster_id, value['id'], value['eth'], value['master'], router_id)
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot add server {value["ip"]}: {e}') s = server_sql.get_server_by_id(value['id'])
raise Exception(f'error: Cannot add server {s.hostname}: {e}')
if cluster.virt_server: if cluster.virt_server:
add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id) add_or_update_virt(cluster, servers, cluster_id, vip_id, group_id)
roxywi_common.logging(cluster_id, f'New cluster VIP: {vip} has been created', keep_history=1, roxywi=1, service='HA cluster') roxywi_common.logging(cluster_id, f'New cluster VIP: {vip} has been created', keep_history=1, roxywi=1, service='HA cluster')
return vip_id
def update_slaves(servers: dict, cluster_id: int, router_id: int) -> None: def update_slaves(servers: dict, cluster_id: int, router_id: int) -> None:
master_ip = None
all_routers_in_cluster = HaClusterRouter.select(HaClusterRouter.id).where(HaClusterRouter.cluster_id == cluster_id).execute() all_routers_in_cluster = HaClusterRouter.select(HaClusterRouter.id).where(HaClusterRouter.cluster_id == cluster_id).execute()
server_ids_from_db = ha_sql.select_cluster_slaves(cluster_id, router_id) server_ids_from_db = ha_sql.select_cluster_slaves(cluster_id, router_id)
server_ids = [] server_ids = []
server_ids_from_json = [] server_ids_from_json = []
for value in servers:
if value['master']:
master_ip = value['ip']
for server in server_ids_from_db: for server in server_ids_from_db:
server_ids.append(server[0]) server_ids.append(server[0])
for value in servers: for value in servers:
slave_id = value['id'] server_ids_from_json.append(int(value['id']))
if value['master']:
slave_id = server_sql.select_server_id_by_ip(master_ip)
server_ids_from_json.append(int(slave_id))
server_ids_for_deletion = set(server_ids) - set(server_ids_from_json) server_ids_for_deletion = set(server_ids) - set(server_ids_from_json)
server_ids_for_adding = set(server_ids_from_json) - set(server_ids) server_ids_for_adding = set(server_ids_from_json) - set(server_ids)
@ -228,7 +225,7 @@ def update_slaves(servers: dict, cluster_id: int, router_id: int) -> None:
try: try:
ha_sql.insert_or_update_slave(cluster_id, slave_id, value['eth'], value['master'], router) ha_sql.insert_or_update_slave(cluster_id, slave_id, value['eth'], value['master'], router)
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot add new slave {value["name"]}: {e}') raise Exception(f'error: Cannot add new slave {value["ip"]}: {e}')
for o_s in server_ids_for_deletion: for o_s in server_ids_for_deletion:
ha_sql.delete_master_from_slave(o_s) ha_sql.delete_master_from_slave(o_s)
@ -238,34 +235,19 @@ def update_slaves(servers: dict, cluster_id: int, router_id: int) -> None:
except Exception as e: except Exception as e:
raise Exception(f'error: Cannot recreate slaves server: {e}') raise Exception(f'error: Cannot recreate slaves server: {e}')
for value in servers: _create_or_update_master_slaves_servers(cluster_id, servers, router_id)
if value['master']:
continue
try:
ha_sql.update_server_master(master_ip, value['ip'])
except Exception as e:
raise Exception(f'error: Cannot update master on slave {value["ip"]}: {e}')
for value in servers:
slave_id = value['id']
if value['master']:
slave_id = server_sql.select_server_id_by_ip(master_ip)
try:
ha_sql.insert_or_update_slave(cluster_id, slave_id, value['eth'], value['master'], router_id)
except Exception as e:
raise Exception(f'error: Cannot update server {value["ip"]}: {e}')
def add_or_update_virt(cluster: Union[HAClusterRequest, HAClusterVIP], servers: dict, cluster_id: int, vip_id: int, group_id: int) -> None: def add_or_update_virt(cluster: Union[HAClusterRequest, HAClusterVIP], servers: dict, cluster_id: int, vip_id: int, group_id: int) -> None:
haproxy = 0 haproxy = 0
nginx = 0 nginx = 0
apache = 0 apache = 0
master_ip = None master_id = None
vip = str(cluster.vip) vip = str(cluster.vip)
for value in servers: for value in servers:
if value['master']: if value['master']:
master_ip = value['ip'] master_id = value['id']
if ha_sql.check_ha_virt(vip_id): if ha_sql.check_ha_virt(vip_id):
try: try:
@ -280,15 +262,34 @@ def add_or_update_virt(cluster: Union[HAClusterRequest, HAClusterVIP], servers:
nginx = 1 if service.service_id == '2' else 0 nginx = 1 if service.service_id == '2' else 0
apache = 1 if service.service_id == '4' else 0 apache = 1 if service.service_id == '4' else 0
try: try:
cred_id = ha_sql.get_cred_id_by_server_ip(master_ip) server = server_sql.get_server_by_id(master_id)
firewall = 1 if server_mod.is_service_active(master_ip, 'firewalld') else 0 c = ha_sql.get_cluster(cluster_id)
ssh_settings = return_ssh_keys_path(master_ip)
virt_id = server_sql.add_server( virt_id = server_sql.add_server(
f'{vip}-VIP', vip, group_id, '1', '1', '0', cred_id, ssh_settings['port'], f'{vip}-VIP', vip, group_id, '1', '1', '0', server.cred_id, server.port,
f'VRRP IP for {cluster.name} cluster', haproxy, nginx, apache, firewall f'VRRP IP for {c.name} cluster', haproxy, nginx, apache, server.firewall_enable
) )
HaClusterVirt.insert(cluster_id=cluster_id, virt_id=virt_id, vip_id=vip_id).execute() HaClusterVirt.insert(cluster_id=cluster_id, virt_id=virt_id, vip_id=vip_id).execute()
roxywi_common.logging(cluster_id, f'New cluster virtual server for VIP: {vip} has been created', keep_history=1, roxywi=1, roxywi_common.logging(cluster_id, f'New cluster virtual server for VIP: {vip} has been created', keep_history=1, roxywi=1,
service='HA cluster') service='HA cluster')
except Exception as e: except Exception as e:
roxywi_common.logging(cluster_id, f'error: Cannot create new cluster virtual server for VIP: {vip}: {e}', roxywi=1, service='HA cluster') roxywi_common.logging(cluster_id, f'error: Cannot create new cluster virtual server for VIP: {vip}: {e}', roxywi=1, service='HA cluster')
def _create_or_update_master_slaves_servers(cluster_id: int, servers: dict, router_id: int, create: bool = False) -> None:
for server in servers:
if server['master']:
continue
try:
ha_sql.update_master_server_by_slave_ip(server['id'], server['ip'])
except Exception as e:
raise Exception(f'error: Cannot update master on slave {server["ip"]: {e}}')
for server in servers:
try:
ha_sql.insert_or_update_slave(cluster_id, server['id'], server['eth'], server['master'], router_id)
if create:
s = server_sql.get_server_by_id(server['id'])
roxywi_common.logging(cluster_id, f'New server {s.hostname} has been added to the cluster', keep_history=1,
roxywi=1, service='HA cluster')
except Exception as e:
raise Exception(f'error: Cannot update slave server {server["ip"]}: {e}')

20
app/routes/ha/routes.py

@ -1,6 +1,7 @@
from flask import render_template, g, request from flask import render_template, g, request
from flask_jwt_extended import jwt_required from flask_jwt_extended import jwt_required
from app.modules.roxywi.exception import RoxywiResourceNotFound
from app.routes.ha import bp from app.routes.ha import bp
from app.middleware import get_user_params, check_services from app.middleware import get_user_params, check_services
import app.modules.db.ha_cluster as ha_sql import app.modules.db.ha_cluster as ha_sql
@ -25,11 +26,18 @@ def before_request():
@check_services @check_services
@get_user_params() @get_user_params()
def get_ha_cluster(service, cluster_id): def get_ha_cluster(service, cluster_id):
router_id = ha_sql.get_router_id(cluster_id, default_router=1) try:
router_id = ha_sql.get_router_id(cluster_id, default_router=1)
except RoxywiResourceNotFound:
router_id = None
if router_id:
slaves = ha_sql.select_cluster_slaves(cluster_id, router_id)
else:
slaves = {}
kwargs = { kwargs = {
'servers': roxywi_common.get_dick_permit(virt=1), 'servers': roxywi_common.get_dick_permit(virt=1),
'clusters': ha_sql.select_cluster(cluster_id), 'clusters': ha_sql.select_cluster(cluster_id),
'slaves': ha_sql.select_cluster_slaves(cluster_id, router_id), 'slaves': slaves,
'virts': ha_sql.select_clusters_virts(), 'virts': ha_sql.select_clusters_virts(),
'vips': ha_sql.select_cluster_vips(cluster_id), 'vips': ha_sql.select_cluster_vips(cluster_id),
'cluster_services': ha_sql.select_cluster_services(cluster_id), 'cluster_services': ha_sql.select_cluster_services(cluster_id),
@ -103,15 +111,17 @@ def show_ha_cluster(service, cluster_id):
return render_template('service.html', **kwargs) return render_template('service.html', **kwargs)
@bp.route('/<service>/slaves/<int:cluster_id>', methods=['GET', 'POST']) @bp.route('/<service>/slaves/<int:cluster_id>/<int:vip_id>', methods=['GET', 'POST'])
@check_services @check_services
@get_user_params() @get_user_params()
def get_slaves(service, cluster_id): def get_slaves(service, cluster_id, vip_id):
lang = g.user_params['lang'] lang = g.user_params['lang']
if request.method == 'GET': if request.method == 'GET':
router_id = ha_sql.get_router_id(cluster_id, default_router=1) router_id = ha_sql.get_router_id(cluster_id, default_router=1)
else: else:
router_id = int(request.form.get('router_id')) # router_id = int(request.form.get('router_id'))
vip = ha_sql.select_cluster_vip_by_vip_id(cluster_id, vip_id)
router_id = vip.router_id
slaves = ha_sql.select_cluster_slaves(cluster_id, router_id) slaves = ha_sql.select_cluster_slaves(cluster_id, router_id)
return render_template('ajax/ha/add_vip_slaves.html', lang=lang, slaves=slaves) return render_template('ajax/ha/add_vip_slaves.html', lang=lang, slaves=slaves)

2
app/static/css/styles.css

@ -186,7 +186,7 @@ pre {
padding-top: 11px; padding-top: 11px;
text-align: right; text-align: right;
margin-right: 20px; margin-right: 20px;
width: 450px; width: 460px;
float: left; float: left;
margin-left: 71%; margin-left: 71%;
margin-top: -50px; margin-top: -50px;

51
app/static/js/ha.js

@ -116,11 +116,11 @@ function createHaClusterStep1(edited=false, cluster_id=0, clean=true) {
if (edited && clean) { if (edited && clean) {
let master_name = $('#master-server-'+cluster_id).text(); let master_name = $('#master-server-'+cluster_id).text();
let master_ip = $('#master-ip-'+cluster_id).text(); let master_ip = $('#master-ip-'+cluster_id).text();
let master_id = $('#master-id-'+cluster_id).text();
$("#ha-cluster-master option").not(master_name).each(function (index) { $("#ha-cluster-master option").not(master_name).each(function (index) {
$(this).prop('disabled', true); $(this).prop('disabled', true);
}); });
$('#ha-cluster-master').append('<option value="' + master_ip + '" selected="selected">' + master_name + '</option>').selectmenu("refresh"); $('#ha-cluster-master').append('<option value="' + master_ip + '" selected="selected" data-id="'+master_id+'">' + master_name + '</option>').selectmenu("refresh");
$('#ha-cluster-master').selectmenu("refresh");
get_keepalived_ver($('#cur_master_ver'), master_ip); get_keepalived_ver($('#cur_master_ver'), master_ip);
$.ajax({ $.ajax({
url: api_prefix + "/ha/cluster/" + cluster_id, url: api_prefix + "/ha/cluster/" + cluster_id,
@ -500,14 +500,14 @@ function increaseProgressValue(progress_step) {
} }
$(progress_id).css('width', new_progress+'%'); $(progress_id).css('width', new_progress+'%');
} }
function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edited=0) { function add_vip_ha_cluster(cluster_id, cluster_name, vip_id='', vip='', edited=0) {
let save_word = translate_div.attr('data-save'); let save_word = translate_div.attr('data-save');
let tabel_title = $("#add-vip-table").attr('title'); let tabel_title = $("#add-vip-table").attr('title');
let buttons = []; let buttons = [];
let req_method = 'GET'; let req_method = 'GET';
if (edited) { if (edited) {
$.ajax({ $.ajax({
url: api_prefix + "/ha/cluster/" + cluster_id + "/vip/" + router_id, url: api_prefix + "/ha/cluster/" + cluster_id + "/vip/" + vip_id,
type: "GET", type: "GET",
async: false, async: false,
success: function (data) { success: function (data) {
@ -544,7 +544,7 @@ function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edit
if (!validateSlaves(jsonData)) { if (!validateSlaves(jsonData)) {
return false; return false;
} }
saveVip(jsonData, cluster_id, $(this), cluster_name, edited, router_id, vip); saveVip(jsonData, cluster_id, $(this), edited, vip_id);
toastr.clear(); toastr.clear();
} }
}, { }, {
@ -555,7 +555,7 @@ function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edit
return false; return false;
} }
jsonData = createJsonVip('#vip_servers div span'); jsonData = createJsonVip('#vip_servers div span');
saveVip(jsonData, cluster_id, $(this), cluster_name, edited, router_id, vip, true); saveVip(jsonData, cluster_id, $(this), edited, vip_id, true);
toastr.clear(); toastr.clear();
} }
}, { }, {
@ -578,7 +578,7 @@ function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edit
if (!validateSlaves(jsonData)) { if (!validateSlaves(jsonData)) {
return false; return false;
} }
saveVip(jsonData, cluster_id, $(this), cluster_name, edited, router_id, vip); saveVip(jsonData, cluster_id, $(this), edited, vip_id);
toastr.clear(); toastr.clear();
} }
}, { }, {
@ -591,10 +591,7 @@ function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edit
}] }]
} }
$.ajax({ $.ajax({
url: "/ha/cluster/slaves/" + cluster_id, url: "/ha/cluster/slaves/" + cluster_id + "/" + vip_id,
data: {
router_id: router_id,
},
type: req_method, type: req_method,
success: function (data) { success: function (data) {
if (data.indexOf('error:') != '-1') { if (data.indexOf('error:') != '-1') {
@ -627,7 +624,7 @@ function add_vip_ha_cluster(cluster_id, cluster_name, router_id='', vip='', edit
}); });
dialog_div.dialog('open'); dialog_div.dialog('open');
} }
function saveVip(jsonData, cluster_id, dialog_id, cluster_name, edited, router_id='', vip='', deleted=false) { function saveVip(jsonData, cluster_id, dialog_id, edited, vip_id='', deleted=false) {
let req_type = 'POST' let req_type = 'POST'
let return_master = 0 let return_master = 0
let virt_server = 0 let virt_server = 0
@ -645,15 +642,14 @@ function saveVip(jsonData, cluster_id, dialog_id, cluster_name, edited, router_i
jsonData['return_master'] = return_master; jsonData['return_master'] = return_master;
jsonData['virt_server'] = virt_server; jsonData['virt_server'] = virt_server;
jsonData['use_src'] = use_src; jsonData['use_src'] = use_src;
jsonData['name'] = cluster_name;
let url = api_prefix + "/ha/cluster/" + cluster_id + "/vip"; let url = api_prefix + "/ha/cluster/" + cluster_id + "/vip";
if (edited) { if (edited) {
req_type = 'PUT'; req_type = 'PUT';
jsonData['router_id'] = router_id; url = api_prefix + "/ha/cluster/" + cluster_id + "/vip/" + vip_id;
} }
if (deleted) { if (deleted) {
req_type = 'DELETE'; req_type = 'DELETE';
url = api_prefix + "/ha/cluster/" + router_id + "/vip" url = api_prefix + "/ha/cluster/" + cluster_id + "/vip/" + vip_id;
} }
$.ajax({ $.ajax({
url: url, url: url,
@ -759,18 +755,18 @@ function createJsonCluster(div_id) {
let jsonData = {}; let jsonData = {};
jsonData = {'servers': []}; jsonData = {'servers': []};
jsonData['servers'].push({ jsonData['servers'].push({
'id': 1, 'id': $('#ha-cluster-master option:selected').attr('data-id'),
'eth': $('#ha-cluster-master-interface').val(), 'eth': $('#ha-cluster-master-interface').val(),
'ip': $('#ha-cluster-master option:selected').val(), // 'ip': $('#ha-cluster-master option:selected').val(),
'name': $('#ha-cluster-master option:selected').text(), // 'name': $('#ha-cluster-master option:selected').text(),
'master': 1 'master': 1
}); });
$(div_id).each(function () { $(div_id).each(function () {
let this_id = $(this).attr('id').split('-')[1]; let this_id = $(this).attr('id').split('-')[1];
let eth = $('#slave_int-' + this_id).val(); let eth = $('#slave_int-' + this_id).val();
let ip = $('#slave_int_div-' + this_id).attr('data-ip'); // let ip = $('#slave_int_div-' + this_id).attr('data-ip');
let name = $('#slave_int_div-' + this_id).parent().text().replace('\n','').replace('\t','').trim(); // let name = $('#slave_int_div-' + this_id).parent().text().replace('\n','').replace('\t','').trim();
jsonData['servers'].push({'id': this_id, 'eth': eth, 'ip': ip, 'name': name, 'master': 0}); jsonData['servers'].push({'id': this_id, 'eth': eth, 'master': 0});
}); });
return jsonData; return jsonData;
} }
@ -780,21 +776,22 @@ function createJsonVip(div_id) {
$(div_id).each(function () { $(div_id).each(function () {
let this_id = $(this).attr('id').split('-')[1]; let this_id = $(this).attr('id').split('-')[1];
let eth1 = $('#slave_int-' + this_id).val(); let eth1 = $('#slave_int-' + this_id).val();
let ip1 = $('#slave_int_div-' + this_id).attr('data-ip'); // let ip1 = $('#slave_int_div-' + this_id).attr('data-ip');
let name1 = $('#slave_int_div-' + this_id).parent().text().replace('\n','').replace('\t','').trim(); // let name1 = $('#slave_int_div-' + this_id).parent().text().replace('\n','').replace('\t','').trim();
let eth = $('#master_int-' + this_id).val(); let eth = $('#master_int-' + this_id).val();
let ip = $('#master_int_div-' + this_id).attr('data-ip'); // let ip = $('#master_int_div-' + this_id).attr('data-ip');
let name = $('#master_int_div-' + this_id).parent().text().replace('\n','').replace('\t','').trim(); // let name = $('#master_int_div-' + this_id).parent().text().replace('\n','').replace('\t','').trim();
if (eth) { if (eth) {
jsonData['servers'].push({'id': this_id, 'eth': eth, 'ip': ip, 'name': name, 'master': 1}); jsonData['servers'].push({'id': this_id, 'eth': eth, 'master': 1});
} else { } else {
jsonData['servers'].push({'id': this_id,'eth': eth1, 'ip': ip1, 'name': name1, 'master': 0}); jsonData['servers'].push({'id': this_id,'eth': eth1, 'master': 0});
} }
}); });
return jsonData; return jsonData;
} }
function validateSlaves(jsonData) { function validateSlaves(jsonData) {
console.log(jsonData)
if (Object.keys(jsonData['servers']).length === 1) { if (Object.keys(jsonData['servers']).length === 1) {
toastr.error('error: There is must be at least one slave server'); toastr.error('error: There is must be at least one slave server');
return false; return false;

3
app/templates/ajax/ha/clusters.html

@ -21,6 +21,7 @@
{% if slave.31 %} {% if slave.31 %}
Master name: {{ copy_to_clipboard(id='master-server-'+cluster.id|string(), value=slave.1) }}<br> Master name: {{ copy_to_clipboard(id='master-server-'+cluster.id|string(), value=slave.1) }}<br>
Master IP: {{ copy_to_clipboard(id='master-ip-'+cluster.id|string(), value=slave.2) }}<br> Master IP: {{ copy_to_clipboard(id='master-ip-'+cluster.id|string(), value=slave.2) }}<br>
<span style="display: none;" id="master-id-{{ cluster.id }}">{{ slave.0 }}</span>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{{lang.words.slaves|title()}}: {{lang.words.slaves|title()}}:
@ -46,7 +47,7 @@
<span id="cluster-vip"> <span id="cluster-vip">
{%- for vip in vips %} {%- for vip in vips %}
{% if g.user_params['role'] <= 2 %} {% if g.user_params['role'] <= 2 %}
<a style="cursor: pointer;" onclick="add_vip_ha_cluster('{{vip.cluster_id}}', '{{cluster.name}}', '{{vip.router_id}}', '{{vip.vip}}', 1)" title="{{lang.words.edit|title()}} VIP">{{vip.vip}}</a> <a style="cursor: pointer;" onclick="add_vip_ha_cluster('{{vip.cluster_id}}', '{{cluster.name}}', '{{vip.id}}', '{{vip.vip}}', 1)" title="{{lang.words.edit|title()}} VIP">{{vip.vip}}</a>
{% else %} {% else %}
{{vip.vip}} {{vip.vip}}
{%- endif -%} {%- endif -%}

2
app/templates/include/add_backup.html

@ -6,7 +6,7 @@
<td> <td>
<select autofocus required name="backup-server" id="backup-server"> <select autofocus required name="backup-server" id="backup-server">
<option disabled>------</option> <option disabled>------</option>
{% for s in servers %}} {% for s in servers %}
<option value="{{ s.2 }}">{{ s.1 }}</option> <option value="{{ s.2 }}">{{ s.1 }}</option>
{% endfor %} {% endfor %}
</select> </select>

2
app/templates/include/admins_dialogs.html

@ -359,7 +359,9 @@
<select id="git-service" required> <select id="git-service" required>
<option disabled selected>------</option> <option disabled selected>------</option>
{% for s in services %} {% for s in services %}
{% if s.service_id in (1, 2, 3, 4) %}
<option value="{{s.service_id}}">{{s.service}}</option> <option value="{{s.service_id}}">{{s.service}}</option>
{% endif %}
{% endfor %} {% endfor %}
</select> </select>
</td> </td>

141
app/views/ha/views.py

@ -9,9 +9,7 @@ import app.modules.roxywi.common as roxywi_common
import app.modules.common.common as common import app.modules.common.common as common
import app.modules.service.ha_cluster as ha_cluster import app.modules.service.ha_cluster as ha_cluster
from app.middleware import get_user_params, page_for_admin, check_group, check_services from app.middleware import get_user_params, page_for_admin, check_group, check_services
from app.modules.roxywi.class_models import ( from app.modules.roxywi.class_models import BaseResponse, IdResponse, HAClusterRequest, HAClusterVIP
BaseResponse, IdResponse, HAClusterRequest, HAClusterVIP
)
class HAView(MethodView): class HAView(MethodView):
@ -128,6 +126,9 @@ class HAView(MethodView):
name: body name: body
required: true required: true
schema: schema:
required:
- name
- services
type: object type: object
properties: properties:
servers: servers:
@ -140,8 +141,8 @@ class HAView(MethodView):
type: 'string' type: 'string'
master: master:
type: 'integer' type: 'integer'
name: id:
type: 'string' type: 'integer'
name: name:
type: string type: string
description: description:
@ -203,6 +204,9 @@ class HAView(MethodView):
name: body name: body
required: true required: true
schema: schema:
required:
- name
- services
type: object type: object
properties: properties:
servers: servers:
@ -215,8 +219,8 @@ class HAView(MethodView):
type: 'string' type: 'string'
master: master:
type: 'integer' type: 'integer'
name: id:
type: 'string' type: 'integer'
name: name:
type: string type: string
description: description:
@ -240,8 +244,6 @@ class HAView(MethodView):
type: string type: string
docker: docker:
type: integer type: integer
router_id:
type: string
responses: responses:
201: 201:
description: HA cluster updated successfully description: HA cluster updated successfully
@ -299,7 +301,7 @@ class HAVIPView(MethodView):
self.group_id = g.user_params['group_id'] self.group_id = g.user_params['group_id']
@staticmethod @staticmethod
def get(service: str, cluster_id: int, router_id: int): def get(service: str, cluster_id: int, vip_id: int):
""" """
This endpoint retrieves information about the specified VIP. This endpoint retrieves information about the specified VIP.
--- ---
@ -317,8 +319,8 @@ class HAVIPView(MethodView):
required: true required: true
type: 'integer' type: 'integer'
- in: 'path' - in: 'path'
name: 'router_id' name: 'vip_id'
description: 'ID of the Router to retrieve' description: 'ID of the VIP to retrieve'
required: true required: true
type: 'integer' type: 'integer'
responses: responses:
@ -328,29 +330,13 @@ class HAVIPView(MethodView):
type: object type: object
properties: properties:
cluster_id: cluster_id:
type: 'object' type: 'integer'
properties:
description:
type: 'string'
group_id:
type: 'integer'
id:
type: 'integer'
name:
type: 'string'
pos:
type: 'integer'
syn_flood:
type: 'integer'
id: id:
type: 'integer' type: 'integer'
return_master: return_master:
type: 'integer' type: 'integer'
router_id: router_id:
type: 'object' type: 'integer'
properties:
id:
type: 'integer'
use_src: use_src:
type: 'integer' type: 'integer'
vip: vip:
@ -359,8 +345,8 @@ class HAVIPView(MethodView):
description: Unexpected error description: Unexpected error
""" """
try: try:
vip = ha_sql.select_cluster_vip(cluster_id, router_id) vip = ha_sql.select_cluster_vip_by_vip_id(cluster_id, vip_id)
settings = model_to_dict(vip) settings = model_to_dict(vip, recurse=False)
is_virt = ha_sql.check_ha_virt(vip.id) is_virt = ha_sql.check_ha_virt(vip.id)
settings.setdefault('virt_server', is_virt) settings.setdefault('virt_server', is_virt)
return jsonify(settings) return jsonify(settings)
@ -389,37 +375,29 @@ class HAVIPView(MethodView):
name: body name: body
required: true required: true
schema: schema:
required:
- servers
- vip
type: object type: object
properties: properties:
servers: servers:
type: object type: 'array'
additionalProperties: description: Must be at least 2 servers. One of them must be master = 1
type: object items:
type: 'object'
properties: properties:
eth: id:
type: string type: 'integer'
ip:
type: string
name:
type: string
master: master:
type: integer type: 'integer'
name:
type: string
description:
type: string
vip: vip:
type: string type: string
virt_server: virt_server:
type: integer type: integer
return_master: return_master:
type: string
syn_flood:
type: integer type: integer
use_src: use_src:
type: integer type: integer
router_id:
type: string
responses: responses:
201: 201:
description: VIP created successfully description: VIP created successfully
@ -431,14 +409,14 @@ class HAVIPView(MethodView):
description: Unexpected error description: Unexpected error
""" """
try: try:
ha_cluster.insert_vip(cluster_id, body, self.group_id) vip_id = ha_cluster.insert_vip(cluster_id, body, self.group_id)
return BaseResponse().model_dump(mode='json'), 201 return IdResponse(id=vip_id).model_dump(mode='json'), 201
except Exception as e: except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create VIP') return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot create VIP')
@validate(body=HAClusterVIP) @validate(body=HAClusterVIP)
def put(self, service: str, cluster_id: int, body: HAClusterVIP): def put(self, service: str, cluster_id: int, vip_id: int, body: HAClusterVIP):
""" """
This endpoint allows to update a VIP for HA cluster. This endpoint allows to update a VIP for HA cluster.
--- ---
@ -455,41 +433,38 @@ class HAVIPView(MethodView):
description: 'ID of the HA cluster to update' description: 'ID of the HA cluster to update'
required: true required: true
type: 'integer' type: 'integer'
- in: 'path'
name: 'vip_id'
description: 'ID of the VIP to update'
required: true
type: 'integer'
- in: body - in: body
name: body name: body
required: true required: true
schema: schema:
required:
- servers
- vip
type: object type: object
properties: properties:
servers: servers:
type: object type: 'array'
additionalProperties: description: Must be at least 2 servers. One of them must be master = 1
type: object items:
type: 'object'
properties: properties:
eth: id:
type: string type: 'integer'
ip:
type: string
name:
type: string
master: master:
type: integer type: 'integer'
name:
type: string
description:
type: string
vip: vip:
type: string type: string
virt_server: virt_server:
type: integer type: integer
return_master: return_master:
type: string type: string
syn_flood:
type: integer
use_src: use_src:
type: integer type: integer
router_id:
type: string
responses: responses:
201: 201:
description: VIP updated successfully description: VIP updated successfully
@ -500,14 +475,15 @@ class HAVIPView(MethodView):
default: default:
description: Unexpected error description: Unexpected error
""" """
vip = ha_sql.select_cluster_vip_by_vip_id(cluster_id, vip_id)
try: try:
ha_cluster.update_vip(cluster_id, body.router_id, body, self.group_id) ha_cluster.update_vip(cluster_id, vip.router_id, body, self.group_id)
return BaseResponse().model_dump(mode='json'), 201 return BaseResponse().model_dump(mode='json'), 201
except Exception as e: except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot update VIP') return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot update VIP')
@staticmethod @staticmethod
def delete(service: str, router_id: int): def delete(service: str, cluster_id: int, vip_id: int):
""" """
Delete a VIP Delete a VIP
--- ---
@ -520,7 +496,12 @@ class HAVIPView(MethodView):
required: true required: true
type: 'string' type: 'string'
- in: 'path' - in: 'path'
name: 'router_id' name: 'cluster_id'
description: 'ID of the HA cluster to delete VIP from'
required: true
type: 'integer'
- in: 'path'
name: 'vip_id'
description: 'ID of the VIP to delete' description: 'ID of the VIP to delete'
required: true required: true
type: 'integer' type: 'integer'
@ -532,11 +513,12 @@ class HAVIPView(MethodView):
404: 404:
description: VIP not found description: VIP not found
""" """
router = ha_sql.get_router(router_id) vip = ha_sql.select_cluster_vip_by_vip_id(cluster_id, vip_id)
router = ha_sql.get_router(vip.router_id)
if router.default == 1: if router.default == 1:
return roxywi_common.handler_exceptions_for_json_data(Exception(''), 'You cannot delete default VIP') return roxywi_common.handler_exceptions_for_json_data(Exception(''), 'You cannot delete default VIP')
try: try:
ha_sql.delete_ha_router(router_id) ha_sql.delete_ha_router(vip.router_id)
return BaseResponse().model_dump(mode='json'), 204 return BaseResponse().model_dump(mode='json'), 204
except Exception as e: except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete VIP') return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete VIP')
@ -592,10 +574,7 @@ class HAVIPsView(MethodView):
return_master: return_master:
type: 'integer' type: 'integer'
router_id: router_id:
type: 'object' type: 'integer'
properties:
id:
type: 'integer'
use_src: use_src:
type: 'integer' type: 'integer'
vip: vip:
@ -604,5 +583,5 @@ class HAVIPsView(MethodView):
description: Unexpected error description: Unexpected error
""" """
vips = ha_sql.select_cluster_vips(cluster_id) vips = ha_sql.select_cluster_vips(cluster_id)
vips = [model_to_dict(vip) for vip in vips] vips = [model_to_dict(vip, recurse=False) for vip in vips]
return jsonify(vips) return jsonify(vips)

46
app/views/server/backup_vews.py

@ -85,6 +85,14 @@ class BackupView(MethodView):
description: The configuration for backup service description: The configuration for backup service
schema: schema:
type: 'object' type: 'object'
required:
- cred_id
- rhost
- rpath
- server
- rserver
- time
- type
properties: properties:
server: server:
type: 'string' type: 'string'
@ -92,15 +100,19 @@ class BackupView(MethodView):
rserver: rserver:
type: 'string' type: 'string'
description: 'The remote server where backup files should be stored' description: 'The remote server where backup files should be stored'
example: 10.0.0.1
rpath: rpath:
type: 'string' type: 'string'
description: 'The path on the remote server where backup files should be stored' description: 'The path on the remote server where backup files should be stored'
example: /var/backup/
type: type:
type: 'string' type: 'string'
description: 'Type of the operation' description: 'Type of the operation'
enum: [backup, synchronization]
time: time:
type: 'string' type: 'string'
description: 'The timing for the backup task' description: 'The timing for the backup task'
enum: [hourly, daily, weekly, monthly]
cred_id: cred_id:
type: 'string' type: 'string'
description: 'Credentials ID for the backup task' description: 'Credentials ID for the backup task'
@ -137,6 +149,14 @@ class BackupView(MethodView):
description: The configuration for backup service description: The configuration for backup service
schema: schema:
type: 'object' type: 'object'
required:
- cred_id
- rhost
- rpath
- server
- rserver
- time
- type
properties: properties:
server: server:
type: 'string' type: 'string'
@ -144,15 +164,19 @@ class BackupView(MethodView):
rserver: rserver:
type: 'string' type: 'string'
description: 'The remote server where backup files should be stored' description: 'The remote server where backup files should be stored'
example: 10.0.0.1
rpath: rpath:
type: 'string' type: 'string'
description: 'The path on the remote server where backup files should be stored' description: 'The path on the remote server where backup files should be stored'
example: /var/backup/
type: type:
type: 'string' type: 'string'
description: 'Type of the operation' description: 'Type of the operation'
enum: [backup, synchronization]
time: time:
type: 'string' type: 'string'
description: 'The timing for the backup task' description: 'The timing for the backup task'
enum: [hourly, daily, weekly, monthly]
cred_id: cred_id:
type: 'string' type: 'string'
description: 'Credentials ID for the backup task' description: 'Credentials ID for the backup task'
@ -282,6 +306,13 @@ class S3BackupView(MethodView):
description: The configuration for S3 backup service description: The configuration for S3 backup service
schema: schema:
type: 'object' type: 'object'
required:
- s3_server
- server
- bucket
- secret_key
- access_key
- time
properties: properties:
s3_server: s3_server:
type: 'string' type: 'string'
@ -301,6 +332,7 @@ class S3BackupView(MethodView):
time: time:
type: 'string' type: 'string'
description: 'The timing for the S3 backup task' description: 'The timing for the S3 backup task'
enum: [hourly, daily, weekly, monthly]
description: description:
type: 'string' type: 'string'
description: 'Description for the S3 backup configuration' description: 'Description for the S3 backup configuration'
@ -428,25 +460,37 @@ class GitBackupView(MethodView):
description: The configuration for Git backup service description: The configuration for Git backup service
schema: schema:
type: 'object' type: 'object'
required:
- cred_id
- server_id
- service_id
- init
- repo
- branch
- time
properties: properties:
server_id: server_id:
type: 'integer' type: 'integer'
description: 'The ID of the server to backed up' description: 'The ID of the server to backed up'
service_id: service_id:
type: 'integer' type: 'integer'
description: 'Service ID' description: 'Service ID: 1: HAProxy, 2: NGINX, 3: Keepalived, 4: Apache'
example: 1
init: init:
type: 'integer' type: 'integer'
description: 'Indicates whether to initialize the repository' description: 'Indicates whether to initialize the repository'
repo: repo:
type: 'string' type: 'string'
description: 'The repository from where to fetch the data for backup' description: 'The repository from where to fetch the data for backup'
example: git@github.com:Example/haproxy_configs
branch: branch:
type: 'string' type: 'string'
description: 'The branch to pull for backup' description: 'The branch to pull for backup'
example: 'master'
time: time:
type: 'string' type: 'string'
description: 'The timing for the Git backup task' description: 'The timing for the Git backup task'
enum: [hourly, daily, weekly, monthly]
cred_id: cred_id:
type: 'integer' type: 'integer'
description: 'The ID of the credentials to be used for backup' description: 'The ID of the credentials to be used for backup'

10
app/views/service/views.py

@ -274,10 +274,10 @@ class ServiceConfigView(MethodView):
required: true required: true
description: The ID or IP of the server description: The ID or IP of the server
- in: query - in: query
name: file_name name: file_path
type: 'string' type: 'string'
required: false required: false
description: The full path to the configuration file (used only for nginx and apache, replace "/" with 92) description: The full path to the configuration file
- in: query - in: query
name: version name: version
type: 'string' type: 'string'
@ -289,10 +289,10 @@ class ServiceConfigView(MethodView):
default: default:
description: Unexpected error description: Unexpected error
""" """
if service in ('nginx', 'apache') and (query.file_name is None and query.version is None): if service in ('nginx', 'apache') and (query.file_path is None and query.version is None):
return ErrorResponse(error=f'There is must be "file_name" as query parameter for {service.title()}') return ErrorResponse(error=f'There is must be "file_name" as query parameter for {service.title()}')
if query.file_name: if query.file_path:
query.file_name = query.file_name.replace('/', '92') query.file_path = query.file_path.replace('/', '92')
try: try:
server_ip = SupportClass(False).return_server_ip_or_id(server_id) server_ip = SupportClass(False).return_server_ip_or_id(server_id)

23
config_other/requirements_deb.txt

@ -1,23 +0,0 @@
configparser>=3.5.0
pytz>=2017.3
tzlocal==2.0.0
pyTelegramBotAPI>=3.6.3
slack-sdk>=3.4.0
distro>=1.2.0
retry>=0.9.2
psutil>=5.9.1
pdpyras>=4.5.2
Werkzeug==2.2.3
Flask==2.2.5
Flask-Login==0.6.2
Flask-APScheduler==1.13.0
Flask-Caching==2.1.0
python3-nmap<=1.5.1
aio-pika>=7.1.0
pika>=1.2.0
websockets>=9.0
ansible-core>=2.11.12
ansible-runner==2.3.2
python-whois>=0.8.0
requests==2.27.1
netaddr>=0.10.1

23
config_other/requirements_el7.txt

@ -1,23 +0,0 @@
pyTelegramBotAPI==3.6.3
networkx==2.1
matplotlib==2.1.2
paramiko-ng>=2.5.0
slack-sdk>=3.4.0
peewee>=3.14.10
PyMySQL>=1.0.2
retry>=0.9.2
pdpyras>=4.5.2
tzlocal==2.0.0
Werkzeug==2.0.3
Flask==2.0.3
Flask-APScheduler==1.12.4
Flask-Caching==1.10.1
Flask-Login==0.5.0
python3-nmap<=1.5.1
aio-pika>=7.1.0
pika>=1.2.0
websockets>=9.0
ansible-core>=2.11.12
ansible-runner==2.3.1
python-whois>=0.8.0
netaddr>=0.10.1

24
config_other/requirements_el8.txt

@ -1,24 +0,0 @@
configparser==3.5.0
pyTelegramBotAPI==3.6.3
networkx>=3.3
matplotlib>=2.1.2
slack-sdk>=3.4.0
peewee>=3.14.10
PyMySQL>=1.0.2
bottle>=0.12.18
retry>=0.9.2
tzlocal==2.0.0
pdpyras>=4.5.2
Werkzeug>=2.0.3
Flask>=2.0.3
Flask-APScheduler>=1.12.4
Flask-Caching>=1.10.1
Flask-Login>=0.5.0
python3-nmap<=1.5.1
aio-pika>=7.1.0
pika>=1.2.0
websockets>=9.0
ansible-core>=2.11.12
ansible-runner==2.3.1
python-whois>=0.8.0
netaddr>=0.10.1

25
config_other/requirements_el9.txt

@ -1,25 +0,0 @@
configparser>=3.5.0
pyTelegramBotAPI>=3.6.3
networkx>=2.1
matplotlib>=2.1.2
slack-sdk>=3.4.0
peewee>=3.14.10
PyMySQL>=1.0.2
bottle>=0.12.18
retry>=0.9.2
pdpyras>=4.5.2
Werkzeug==2.2.3
Flask==2.2.5
Flask-Login==0.6.2
Flask-APScheduler==1.13.0
Flask-Caching==2.1.0
python3-nmap<=1.5.1
aio-pika>=7.1.0
pika>=1.2.0
websockets>=9.0
tzlocal==2.0.0
ansible-core>=2.11.12
ansible-runner==2.3.1
python-whois>=0.8.0
requests==2.27.1
netaddr>=0.10.1
Loading…
Cancel
Save