haproxy-wi/app/views/udp/views.py

501 lines
19 KiB
Python

from flask import render_template, g, jsonify
from flask.views import MethodView
from flask_pydantic import validate
from flask_jwt_extended import jwt_required
from playhouse.shortcuts import model_to_dict
import app.modules.roxywi.auth as roxywi_auth
import app.modules.roxywi.common as roxywi_common
import app.modules.common.common as common
import app.modules.db.udp as udp_sql
import app.modules.db.ha_cluster as ha_sql
import app.modules.db.server as server_sql
import app.modules.service.udp as udp_mod
import app.modules.service.installation as service_mod
from app.middleware import get_user_params, check_services, page_for_admin, check_group
from app.modules.common.common_classes import SupportClass
from app.modules.roxywi.class_models import BaseResponse, IdResponse, UdpListenerRequest, GroupQuery
class UDPListener(MethodView):
method_decorators = ["GET", "POST", "PUT", "DELETE"]
decorators = [jwt_required(), get_user_params(), check_services, check_group()]
def __init__(self, is_api=True):
self.is_api = is_api
def get(self, service: str, listener_id: int):
"""
Get information about a specific UDP listener.
---
tags:
- UDP listener
parameters:
- name: service
in: path
type: string
required: true
description: 'Can be only "udp"'
- name: listener_id
in: path
type: integer
required: true
description: The listener's identifier
responses:
200:
description: Listener configuration returned successfully
schema:
type: object
properties:
check_enabled:
type: integer
cluster_id:
type: string
config:
type: array
items:
type: object
properties:
backend_ip:
type: string
description: The IP address of the backend server
port:
type: integer
description: Port number on which the backend server listens for requests
weight:
type: integer
description: Weight assigned to the backend server
delay_before_retry:
type: integer
delay_loop:
type: integer
description:
type: string
group_id:
type: integer
id:
type: integer
lb_algo:
type: string
name:
type: string
port:
type: integer
retry:
type: integer
server_id:
type: integer
vip:
type: string
default:
description: Unexpected error
"""
if self.is_api:
if listener_id:
try:
listener_config = udp_mod.get_listener_config(listener_id)
listener_config['status'] = udp_mod.check_is_listener_active(listener_id)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Listener not found')
return jsonify(listener_config)
else:
if not listener_id:
kwargs = {
'listeners': udp_sql.select_listeners(g.user_params['group_id']),
'lang': g.user_params['lang'],
'clusters': ha_sql.select_clusters(g.user_params['group_id']),
'is_needed_tool': common.is_tool('ansible'),
'user_subscription': roxywi_common.return_user_subscription()
}
return render_template('udp/listeners.html', **kwargs)
else:
listener = udp_sql.get_listener(listener_id)
cluster = dict()
server = dict()
if listener.cluster_id:
cluster = ha_sql.select_cluster(listener.cluster_id)
elif listener.server_id:
server = server_sql.get_server_by_id(listener.server_id)
kwargs = {
'clusters': cluster,
'listener': listener,
'server': server,
'lang': g.user_params['lang'],
}
return render_template('udp/listener.html', **kwargs)
@validate(body=UdpListenerRequest)
def post(self, service: str, body: UdpListenerRequest):
"""
This endpoint allows to create a new UDP listener.
---
tags:
- UDP listener
parameters:
- in: 'path'
name: 'service'
description: 'Can be only "udp"'
required: true
type: 'string'
- in: body
name: body
required: true
schema:
required:
- config
- name
- port
- lb_algo
- vip
type: object
properties:
config:
type: array
items:
type: object
properties:
backend_ip:
type: string
description: The IP address of the backend server
port:
type: integer
description: Port number on which the backend server listens for requests
weight:
type: integer
description: Weight assigned to the backend server
name:
type: string
cluster_id:
type: integer
description: Cluster ID where the UDP listener is located. Must be determined if server_id empty
server_id:
type: integer
description: Standalone mode. Server ID where the UDP listener is located. Must be determined if cluster_id empty
group_id:
type: string
port:
type: string
lb_algo:
type: string
description: "'rr': 'Round robin', 'wrr': 'Weighted Round Robin', 'lc': 'Least Connection', 'wlc': 'Weighted Least Connection', 'sh': 'Source Hashing', 'dh': 'Destination Hashing', 'lblc': 'Locality-Based Least Connection'"
schema:
enum: [rr, wrr, lc, wlc, sh, dh, wlc, lblc]
check_enabled:
type: integer
default: 1
description: Enable backend servers checking
delay_before_retry:
type: integer
default: 10
description: Delay between two successive retries
delay_loop:
type: integer
default: 10
description: Specify in seconds the interval between checks
retry:
type: integer
default: 3
description: Maximum number of retries before mark a backend server as down
description:
type: string
vip:
type: string
description: IP address of the UDP listener binding, if Standalone mode. VIP address of the UDP listener binding, if HA Cluster mode
reconfigure:
type: boolean
description: If 1, reconfigure UDP listener. If 0, just save UDP listener without configuration on servers
responses:
201:
description: UDP listener created successfully
400:
description: Invalid request data
default:
description: Unexpected error
"""
roxywi_auth.page_for_admin(level=3)
try:
listener_id = udp_sql.insert_listener(**body.model_dump(mode='json', exclude={'reconfigure'}))
roxywi_common.logging(listener_id, f'UDP listener {body.name} has been created', keep_history=1,
roxywi=1, service='UDP Listener')
if body.reconfigure:
self._reconfigure(listener_id, 'install')
return IdResponse(id=listener_id).model_dump(mode='json')
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot create UDP listener')
@validate(body=UdpListenerRequest)
def put(self, service: str, listener_id: int, body: UdpListenerRequest):
"""
This endpoint allows to update a UDP listener.
---
tags:
- UDP listener
parameters:
- in: 'path'
name: 'service'
description: 'Can be only "udp"'
required: true
type: 'string'
- in: 'path'
name: 'listener_id'
description: 'ID of the UDP listener'
required: true
type: 'integer'
- in: body
name: body
required: true
schema:
required:
- config
- name
- port
- lb_algo
- vip
type: object
properties:
config:
type: array
items:
type: object
properties:
backend_ip:
type: string
description: The IP address of the backend server
port:
type: integer
description: Port number on which the backend server listens for requests
weight:
type: integer
description: Weight assigned to the backend server
name:
type: string
cluster_id:
type: integer
description: Cluster ID where the UDP listener is located. Must be determined if server_id empty
server_id:
type: integer
description: Standalone mode. Server ID where the UDP listener is located. Must be determined if cluster_id empty
group_id:
type: string
port:
type: string
lb_algo:
type: string
description: "'rr': 'Round robin', 'wrr': 'Weighted Round Robin', 'lc': 'Least Connection', 'wlc': 'Weighted Least Connection', 'sh': 'Source Hashing', 'dh': 'Destination Hashing', 'lblc': 'Locality-Based Least Connection'"
schema:
enum: [rr, wrr, lc, wlc, sh, dh, wlc, lblc]
check_enabled:
type: integer
default: 1
description: Enable backend servers checking
delay_before_retry:
type: integer
default: 10
description: Delay between two successive retries
delay_loop:
type: integer
default: 10
description: Specify in seconds the interval between checks
retry:
type: integer
default: 3
description: Maximum number of retries before mark a backend server as down
description:
type: string
vip:
type: string
description: IP address of the UDP listener binding, if Standalone mode. VIP address of the UDP listener binding, if HA Cluster mode
reconfigure:
type: boolean
description: If 1, reconfigure UDP listener. If 0, just save UDP listener without configuration on servers
responses:
201:
description: UDP listener created successfully
400:
description: Invalid request data
default:
description: Unexpected error
"""
roxywi_auth.page_for_admin(level=3)
try:
udp_sql.update_listener(listener_id, **body.model_dump(mode='json', exclude={'reconfigure'}))
roxywi_common.logging(listener_id, f'UDP listener {body.name} has been updated', keep_history=1,
roxywi=1, service='UDP Listener')
if body.reconfigure:
self._reconfigure(listener_id, 'install')
return BaseResponse().model_dump(mode='json')
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot update UDP listener')
def delete(self, service: str, listener_id: int):
"""
Delete a UDP listener
---
tags:
- UDP listener
parameters:
- in: 'path'
name: 'service'
description: 'Can be only "udp"'
required: true
type: 'string'
- in: 'path'
name: 'listener_id'
description: 'ID of the UDP listener'
required: true
type: 'integer'
responses:
204:
description: UDP listener deletion successful
"""
roxywi_auth.page_for_admin(level=3)
try:
self._reconfigure(listener_id, 'uninstall')
roxywi_common.logging(listener_id, f'UDP listener has been deleted {listener_id}', roxywi=1, keep_history=1, login=1, service='UDP listener')
except Exception as e:
return roxywi_common.handle_json_exceptions(e, f'Cannot create inventory for UDP listener deleting {listener_id}')
try:
udp_sql.delete_listener(listener_id)
return BaseResponse().model_dump(mode='json'), 204
except Exception as e:
return roxywi_common.handle_json_exceptions(e, f'Cannot delete UDP listener {listener_id}')
@staticmethod
def _reconfigure(listener_id, action):
try:
inv, server_ips = service_mod.generate_udp_inv(listener_id, action)
except Exception as e:
raise Exception(e)
try:
output = service_mod.run_ansible(inv, server_ips, 'udp')
if len(output['failures']) > 0 or len(output['dark']) > 0:
raise Exception(f'Cannot {action} UDP listener. Check Apache error log')
except Exception as e:
raise Exception(f'Cannot {action} UDP listener: {e}')
class UDPListeners(MethodView):
method_decorators = ["GET"]
decorators = [jwt_required(), get_user_params(), check_services, check_group()]
@validate(query=GroupQuery)
def get(self, service: str, query: GroupQuery):
"""
Get information about a specific UDP listener.
---
tags:
- UDP listener
parameters:
- name: service
in: path
type: string
required: true
description: 'Can be only "udp"'
- name: group_id
in: query
type: integer
required: false
description: The group's identifier. Only accessible by superAdmin role.
responses:
200:
description: Listener configuration returned successfully
schema:
type: array
items:
type: object
properties:
check_enabled:
type: integer
cluster_id:
type: string
config:
type: array
items:
type: object
properties:
backend_ip:
type: string
description: The IP address of the backend server
port:
type: integer
description: Port number on which the backend server listens for requests
weight:
type: integer
description: Weight assigned to the backend server
delay_before_retry:
type: integer
delay_loop:
type: integer
description:
type: string
group_id:
type: integer
id:
type: integer
lb_algo:
type: string
name:
type: string
port:
type: integer
retry:
type: integer
server_id:
type: integer
vip:
type: string
default:
description: Unexpected error
"""
try:
group_id = SupportClass.return_group_id(query)
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot get UDP listeners')
try:
listeners = udp_sql.select_listeners(group_id)
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot get UDP listeners')
return jsonify([model_to_dict(listener, recurse=False) for listener in listeners])
class UDPListenerActionView(MethodView):
methods = ['GET']
decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=3), check_group()]
@staticmethod
def get(service: str, listener_id: int, action: str):
"""
This endpoint performs a specified action on a certain UDP listener.
---
tags:
- UDP listener
parameters:
- in: path
name: service
required: true
type: 'string'
description: Can be only "udp"
- in: path
name: listener_id
type: 'integer'
required: true
description: The ID af the UDP listener
- in: path
name: action
type: 'string'
required: true
description: The action to be performed on the service (start, stop, reload, restart)
responses:
200:
description: Successful operation
default:
description: Unexpected error
"""
try:
udp_mod.listener_actions(listener_id, action, g.user_params['group_id'])
roxywi_common.logging(listener_id, f'UDP listener {listener_id} has been {action}ed', roxywi=1,
keep_history=1, login=1, service='UDP listener')
return BaseResponse().model_dump(mode='json')
except Exception as e:
return roxywi_common.handle_json_exceptions(e, f'Cannot {action} listener')