mirror of https://github.com/Aidaho12/haproxy-wi
				
				
				
			
		
			
				
	
	
		
			663 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			663 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Python
		
	
	
import os
 | 
						|
from typing import Union, Literal
 | 
						|
 | 
						|
from flask.views import MethodView
 | 
						|
from flask_pydantic import validate
 | 
						|
from flask import jsonify, g
 | 
						|
from flask_jwt_extended import jwt_required
 | 
						|
 | 
						|
import app.modules.db.sql as sql
 | 
						|
import app.modules.db.config as config_sql
 | 
						|
import app.modules.db.server as server_sql
 | 
						|
import app.modules.db.service as service_sql
 | 
						|
import app.modules.roxywi.common as roxywi_common
 | 
						|
import app.modules.config.config as config_mod
 | 
						|
import app.modules.config.common as config_common
 | 
						|
import app.modules.server.server as server_mod
 | 
						|
import app.modules.service.action as service_action
 | 
						|
import app.modules.service.common as service_common
 | 
						|
from app.middleware import get_user_params, page_for_admin, check_group, check_services
 | 
						|
from app.modules.roxywi.exception import RoxywiResourceNotFound
 | 
						|
from app.modules.roxywi.class_models import BaseResponse, ErrorResponse, DataResponse, DataStrResponse, \
 | 
						|
    ConfigFileNameQuery, ConfigRequest, VersionsForDelete
 | 
						|
from app.modules.common.common_classes import SupportClass
 | 
						|
 | 
						|
 | 
						|
class ServiceView(MethodView):
 | 
						|
    methods = ['GET']
 | 
						|
    decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=4), check_group()]
 | 
						|
 | 
						|
    def get(self, service: Literal['haproxy', 'nginx', 'apache', 'keepalived'], server_id: Union[int, str]):
 | 
						|
        """
 | 
						|
        This endpoint retrieves information about a specific service.
 | 
						|
        ---
 | 
						|
        tags:
 | 
						|
          - Service
 | 
						|
        parameters:
 | 
						|
          - in: path
 | 
						|
            name: service
 | 
						|
            type: 'string'
 | 
						|
            required: true
 | 
						|
            description: The type of service (haproxy, nginx, apache, keepalived)
 | 
						|
          - in: path
 | 
						|
            name: server_id
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The ID or IP of the server
 | 
						|
        responses:
 | 
						|
          200:
 | 
						|
            description: Successful operation
 | 
						|
            schema:
 | 
						|
              type: 'object'
 | 
						|
              properties:
 | 
						|
                CurrConns:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Current connections to HAProxy (only for HAProxy service)'
 | 
						|
                Maxconn:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Maximum connections to HAProxy (only for HAProxy service)'
 | 
						|
                MaxconnReached:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Max connections reached (only for HAProxy service)'
 | 
						|
                Memmax_MB:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Maximum memory in MB (only for HAProxy service)'
 | 
						|
                PoolAlloc_MB:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Memory pool allocated in MB (only for HAProxy service)'
 | 
						|
                PoolUsed_MB:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Memory pool used in MB (only for HAProxy service)'
 | 
						|
                Uptime:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Time the service has been active'
 | 
						|
                Version:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Version of the service'
 | 
						|
                Process:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Number of processes launched by the service'
 | 
						|
                Status:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'Status of the service'
 | 
						|
          default:
 | 
						|
            description: Unexpected error
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            server_id = SupportClass().return_server_ip_or_id(server_id)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, '')
 | 
						|
 | 
						|
        try:
 | 
						|
            server = server_sql.get_server_with_group(server_id, g.user_params['group_id'])
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find a server')
 | 
						|
 | 
						|
        if service == 'haproxy':
 | 
						|
            cmd = 'echo "show info" |nc %s %s -w 1|grep -e "Ver\|CurrConns\|Maxco\|MB\|Uptime:\|Process_num"' % (
 | 
						|
                server.ip, sql.get_setting('haproxy_sock_port')
 | 
						|
            )
 | 
						|
            out = server_mod.subprocess_execute(cmd)
 | 
						|
            data = self.return_dict_from_out(out[0])
 | 
						|
            if len(data) == 0:
 | 
						|
                data = ErrorResponse(error='Cannot get information').model_dump(mode='json')
 | 
						|
            else:
 | 
						|
                data['Status'] = self._service_status(data['Process'])
 | 
						|
            data['auto_start'] = int(server.haproxy_active)
 | 
						|
            data['checker'] = int(server.haproxy_alert)
 | 
						|
            data['metrics'] = int(server.haproxy_metrics)
 | 
						|
            data['docker'] = int(service_sql.select_service_setting(server_id, service, 'dockerized'))
 | 
						|
        elif service == 'nginx':
 | 
						|
            is_dockerized = service_sql.select_service_setting(server_id, service, 'dockerized')
 | 
						|
            if is_dockerized == '1':
 | 
						|
                container_name = sql.get_setting(f'{service}_container_name')
 | 
						|
                cmd = (f"sudo docker exec -it {container_name} /usr/sbin/nginx -v 2>&1|awk '{{print $3}}' && "
 | 
						|
                       f"docker ps -a -f name={container_name} --format '{{{{.Status}}}}' && ps ax |grep nginx:|grep -v grep |wc -l")
 | 
						|
                try:
 | 
						|
                    out = server_mod.ssh_command(server.ip, cmd)
 | 
						|
                except Exception as e:
 | 
						|
                    return ErrorResponse(error=str(e)).model_dump(mode='json'), 500
 | 
						|
                out = out.replace('\n', '')
 | 
						|
                out1 = out.split('\r')
 | 
						|
                if out1[0] == 'from':
 | 
						|
                    out1[0] = ''
 | 
						|
                    out1[1] = out1[1].split(')')[1]
 | 
						|
                else:
 | 
						|
                    out1[0] = out1[0].split('/')[1]
 | 
						|
            else:
 | 
						|
                cmd = ("/usr/sbin/nginx -v 2>&1|awk '{print $3}' && systemctl status nginx |grep -e 'Active'"
 | 
						|
                       "|awk '{print $2, $9$10$11$12$13}' && ps ax |grep nginx:|grep -v grep |wc -l")
 | 
						|
                try:
 | 
						|
                    out = server_mod.ssh_command(server.ip, cmd)
 | 
						|
                except Exception as e:
 | 
						|
                    return ErrorResponse(error=str(e)).model_dump(mode='json'), 500
 | 
						|
                out = out.replace('\n', '')
 | 
						|
                out1 = out.split('\r')
 | 
						|
                try:
 | 
						|
                    out1[0] = out1[0].split('/')[1]
 | 
						|
                    try:
 | 
						|
                        out1[1] = out1[1].split(';')[1]
 | 
						|
                    except IndexError:
 | 
						|
                        out1[1] = out1[1].split(' ')[1]
 | 
						|
                except IndexError:
 | 
						|
                    return ErrorResponse(error='NGINX service not found').model_dump(mode='json'), 404
 | 
						|
            try:
 | 
						|
                data = {
 | 
						|
                    "Version": out1[0],
 | 
						|
                    "Uptime": out1[1],
 | 
						|
                    "Process": out1[2],
 | 
						|
                    "Status": self._service_status(out1[2])}
 | 
						|
            except IndexError:
 | 
						|
                return ErrorResponse(error='NGINX service not found').model_dump(mode='json'), 404
 | 
						|
            except Exception as e:
 | 
						|
                data = ErrorResponse(error=str(e)).model_dump(mode='json')
 | 
						|
            data['auto_start'] = int(server.nginx_active)
 | 
						|
            data['checker'] = int(server.nginx_alert)
 | 
						|
            data['metrics'] = int(server.nginx_metrics)
 | 
						|
            data['docker'] = int(is_dockerized)
 | 
						|
        elif service == 'apache':
 | 
						|
            apache_stats_user = sql.get_setting('apache_stats_user')
 | 
						|
            apache_stats_password = sql.get_setting('apache_stats_password')
 | 
						|
            apache_stats_port = sql.get_setting('apache_stats_port')
 | 
						|
            apache_stats_page = sql.get_setting('apache_stats_page')
 | 
						|
            cmd = "curl -s -u %s:%s http://%s:%s/%s?auto |grep 'ServerVersion\|Processes\|ServerUptime:'" % \
 | 
						|
                  (apache_stats_user, apache_stats_password, server.ip, apache_stats_port, apache_stats_page)
 | 
						|
            servers_with_status = list()
 | 
						|
            try:
 | 
						|
                out = server_mod.subprocess_execute(cmd)
 | 
						|
                if out != '':
 | 
						|
                    for k in out:
 | 
						|
                        servers_with_status.append(k)
 | 
						|
                data = {
 | 
						|
                    "Version": servers_with_status[0][0].split('/')[1].split(' ')[0],
 | 
						|
                    "Uptime": servers_with_status[0][1].split(':')[1].strip(),
 | 
						|
                    "Process": servers_with_status[0][2].split(' ')[1],
 | 
						|
                    "Status": self._service_status(servers_with_status[0][2].split(' ')[1])
 | 
						|
                }
 | 
						|
            except IndexError:
 | 
						|
                data = {
 | 
						|
                    "Version": '',
 | 
						|
                    "Uptime": '',
 | 
						|
                    "Process": 0,
 | 
						|
                    "Status": self._service_status('0')
 | 
						|
                }
 | 
						|
            except Exception as e:
 | 
						|
                data = ErrorResponse(error=str(e)).model_dump(mode='json')
 | 
						|
 | 
						|
            data['auto_start'] = int(server.apache_active)
 | 
						|
            data['checker'] = int(server.apache_alert)
 | 
						|
            data['metrics'] = int(server.apache_metrics)
 | 
						|
            data['docker'] = int(service_sql.select_service_setting(server_id, service, 'dockerized'))
 | 
						|
        elif service == 'keepalived':
 | 
						|
            cmd = ("sudo /usr/sbin/keepalived -v 2>&1|head -1|awk '{print $2}' && sudo systemctl status keepalived |grep -e 'Active'"
 | 
						|
                   "|awk '{print $2, $9$10$11$12$13}' && ps ax |grep 'keepalived '|grep -v udp|grep -v grep |wc -l")
 | 
						|
            try:
 | 
						|
                out = server_mod.ssh_command(server.ip, cmd)
 | 
						|
                out1 = out.split()
 | 
						|
                if out1[0].split('\r')[0] == '/usr/sbin/keepalived:':
 | 
						|
                    return ErrorResponse(error='Keepalived service not found').model_dump(mode='json'), 404
 | 
						|
                data = {"Version": out1[0].split('\r')[0], "Uptime": out1[2], "Process": out1[3], 'Status': self._service_status(out1[3])}
 | 
						|
            except IndexError:
 | 
						|
                return ErrorResponse(error='Keepalived service not found').model_dump(mode='json'), 404
 | 
						|
            except Exception as e:
 | 
						|
                return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get version')
 | 
						|
        data['service'] = service
 | 
						|
        data['server_id'] = server_id
 | 
						|
        data['id'] = f'{server_id}-{service}'
 | 
						|
        return jsonify(data)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def return_dict_from_out(out):
 | 
						|
        data = {}
 | 
						|
        for k in out:
 | 
						|
            if "Ncat:" not in k:
 | 
						|
                k = k.split(':')
 | 
						|
                if k[0] == 'Process_num':
 | 
						|
                    data['Process'] = k[1].strip()
 | 
						|
                else:
 | 
						|
                    data[k[0]] = k[1].strip()
 | 
						|
            else:
 | 
						|
                data = {"error": "Cannot connect to HAProxy"}
 | 
						|
 | 
						|
        return data
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _service_status(process_num: str) -> str:
 | 
						|
        if process_num == '0':
 | 
						|
            return 'stopped'
 | 
						|
        return 'running'
 | 
						|
 | 
						|
 | 
						|
class ServiceActionView(MethodView):
 | 
						|
    methods = ['GET']
 | 
						|
    decorators = [jwt_required(), get_user_params(), page_for_admin(level=3), check_group()]
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def get(service: str, server_id: Union[int, str], action: str):
 | 
						|
        """
 | 
						|
        This endpoint performs a specified action on a certain service on a specific server.
 | 
						|
        ---
 | 
						|
        tags:
 | 
						|
          - Service
 | 
						|
        parameters:
 | 
						|
          - in: path
 | 
						|
            name: service
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The type of service (haproxy, nginx, apache, keepalived, waf_haproxy, waf_nginx)
 | 
						|
          - in: path
 | 
						|
            name: server_id
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The ID or IP of the server
 | 
						|
          - 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
 | 
						|
        """
 | 
						|
        if service not in ('haproxy', 'nginx', 'apache', 'keepalived', 'waf_haproxy', 'waf_nginx'):
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(RoxywiResourceNotFound(), 'Cannot find a server')
 | 
						|
 | 
						|
        try:
 | 
						|
            server_id = SupportClass().return_server_ip_or_id(server_id)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find a server')
 | 
						|
 | 
						|
        try:
 | 
						|
            server = server_sql.get_server_with_group(server_id, g.user_params['group_id'])
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find a server')
 | 
						|
 | 
						|
        try:
 | 
						|
            service_action.common_action(server.ip, action, service)
 | 
						|
            return BaseResponse().model_dump(mode='json')
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, f'Cannot do {action}')
 | 
						|
 | 
						|
 | 
						|
class ServiceBackendView(MethodView):
 | 
						|
    methods = ['GET', 'POST']
 | 
						|
    decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=4), check_group()]
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def get(service: str, server_id: Union[int, str]):
 | 
						|
        """
 | 
						|
        This endpoint retrieves information about service backends.
 | 
						|
        ---
 | 
						|
        tags:
 | 
						|
          - Service
 | 
						|
        parameters:
 | 
						|
          - in: path
 | 
						|
            name: service
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The type of service (haproxy, nginx, apache, keepalived)
 | 
						|
          - in: path
 | 
						|
            name: server_id
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The ID or IP of the server
 | 
						|
        responses:
 | 
						|
          200:
 | 
						|
            description: Successful operation
 | 
						|
            schema:
 | 
						|
              type: 'array'
 | 
						|
              items:
 | 
						|
                ppoperties:
 | 
						|
                  type: 'string'
 | 
						|
                  description: 'List of backends (only for HAProxy and Keepalived services)'
 | 
						|
          default:
 | 
						|
            description: Unexpected error
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            server_ip = SupportClass(False).return_server_ip_or_id(server_id)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, '')
 | 
						|
 | 
						|
        try:
 | 
						|
            backends = service_common.overview_backends(server_ip, service)
 | 
						|
            return DataResponse(data=backends).model_dump(mode='json')
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Backends not found')
 | 
						|
 | 
						|
 | 
						|
class ServiceConfigView(MethodView):
 | 
						|
    methods = ['GET', 'POST']
 | 
						|
    decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=3), check_group()]
 | 
						|
 | 
						|
    @validate(query=ConfigFileNameQuery)
 | 
						|
    def get(self, service: str, server_id: Union[int, str], query: ConfigFileNameQuery):
 | 
						|
        """
 | 
						|
        This endpoint retrieves the configuration file for the specified service on a certain server.
 | 
						|
        ---
 | 
						|
        tags:
 | 
						|
          - Service config
 | 
						|
        parameters:
 | 
						|
          - in: path
 | 
						|
            name: service
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The type of service (haproxy, nginx, apache, keepalived)
 | 
						|
          - in: path
 | 
						|
            name: server_id
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The ID or IP of the server
 | 
						|
          - in: query
 | 
						|
            name: file_path
 | 
						|
            type: 'string'
 | 
						|
            required: false
 | 
						|
            description: The full path to the configuration file
 | 
						|
          - in: query
 | 
						|
            name: version
 | 
						|
            type: 'string'
 | 
						|
            required: false
 | 
						|
            description: The version of the configuration file
 | 
						|
        responses:
 | 
						|
          200:
 | 
						|
            description: 'Successful operation, returns the required configuration file'
 | 
						|
          default:
 | 
						|
            description: Unexpected error
 | 
						|
        """
 | 
						|
        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_path" as query parameter for {service.title()}')
 | 
						|
        if query.file_path:
 | 
						|
            query.file_path = query.file_path.replace('/', '92')
 | 
						|
 | 
						|
        try:
 | 
						|
            server_ip = SupportClass(False).return_server_ip_or_id(server_id)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, '')
 | 
						|
 | 
						|
        if query.version:
 | 
						|
            configs_dir = config_common.get_config_dir(service)
 | 
						|
            if '..' in configs_dir:
 | 
						|
                return ErrorResponse(error='nice try').model_dump(mode='json')
 | 
						|
            cfg = configs_dir + query.version
 | 
						|
        else:
 | 
						|
            cfg = config_common.generate_config_path(service, server_ip)
 | 
						|
            try:
 | 
						|
                config_mod.get_config(server_ip, cfg, service=service, config_file_name=query.file_path)
 | 
						|
            except Exception as e:
 | 
						|
                return ErrorResponse(error=str(e)).model_dump(mode='json')
 | 
						|
 | 
						|
        try:
 | 
						|
            with open(cfg, 'r') as file:
 | 
						|
                conf = file.readlines()
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get config')
 | 
						|
 | 
						|
        return DataResponse(data=conf).model_dump(mode='json')
 | 
						|
 | 
						|
    @validate(body=ConfigRequest)
 | 
						|
    def post(self, service: str, server_id: Union[int, str], body: ConfigRequest):
 | 
						|
        """
 | 
						|
        Update service configuration
 | 
						|
        ---
 | 
						|
        tags:
 | 
						|
          - Service config
 | 
						|
        parameters:
 | 
						|
          - name: service
 | 
						|
            in: path
 | 
						|
            type: string
 | 
						|
            required: true
 | 
						|
            description: The service name, one of [haproxy, nginx, apache, keepalived].
 | 
						|
          - name: server_id
 | 
						|
            in: path
 | 
						|
            type: string
 | 
						|
            required: true
 | 
						|
            description: Server Identifier - either ID or IP.
 | 
						|
          - name: body
 | 
						|
            in: body
 | 
						|
            schema:
 | 
						|
              type: object
 | 
						|
              properties:
 | 
						|
                action:
 | 
						|
                  type: string
 | 
						|
                  description: The action to be performed.
 | 
						|
                  required: true
 | 
						|
                config:
 | 
						|
                  type: string
 | 
						|
                  description: The configuration to be saved.
 | 
						|
                  required: true
 | 
						|
                file_path:
 | 
						|
                  type: string
 | 
						|
                  description: Path to the configuration file. Only for NGINX and Apache services.
 | 
						|
                config_local_path:
 | 
						|
                  type: string
 | 
						|
                  description: Local path for the configuration, if updated from it. It could be used for uploading a version of config file.
 | 
						|
              required:
 | 
						|
                - action
 | 
						|
        responses:
 | 
						|
          200:
 | 
						|
            description: Post request received successful
 | 
						|
            schema:
 | 
						|
              type: object
 | 
						|
              properties:
 | 
						|
                status:
 | 
						|
                  type: string
 | 
						|
                data:
 | 
						|
                  type: string
 | 
						|
                  description: Configuration check result
 | 
						|
          default:
 | 
						|
            description: Unexpected error
 | 
						|
        """
 | 
						|
        if service in ('nginx', 'apache') and (body.file_path is None):
 | 
						|
            return ErrorResponse(error=f'There is must be "file_path" as json parameter for {service.title()}')
 | 
						|
        try:
 | 
						|
            server_ip = SupportClass(False).return_server_ip_or_id(server_id)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, '')
 | 
						|
 | 
						|
        try:
 | 
						|
            cfg = config_mod.return_cfg(service, server_ip, body.file_path)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get config')
 | 
						|
 | 
						|
        try:
 | 
						|
            with open(cfg, "a") as conf:
 | 
						|
                conf.write(body.config)
 | 
						|
        except IOError as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot write config')
 | 
						|
 | 
						|
        try:
 | 
						|
            if service == 'keepalived':
 | 
						|
                stderr = config_mod.upload_and_restart(server_ip, cfg, body.action, service, oldcfg=body.config_local_path)
 | 
						|
            else:
 | 
						|
                stderr = config_mod.master_slave_upload_and_restart(server_ip, cfg, body.action, service, oldcfg=body.config_local_path,
 | 
						|
                                                                    config_file_name=body.file_path)
 | 
						|
        except Exception as e:
 | 
						|
            return f'error: {e}', 200
 | 
						|
 | 
						|
        if body.action != 'test':
 | 
						|
            config_mod.diff_config(body.config_local_path, cfg)
 | 
						|
 | 
						|
        return DataStrResponse(data=stderr).model_dump(mode='json'), 201
 | 
						|
 | 
						|
 | 
						|
class ServiceConfigList(MethodView):
 | 
						|
    methods = ['GET']
 | 
						|
    decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=3), check_group()]
 | 
						|
 | 
						|
    def get(self, service: str, server_id: Union[int, str]):
 | 
						|
        """
 | 
						|
        Retrieve the list of configuration files for the given service
 | 
						|
        ---
 | 
						|
        tags:
 | 
						|
          - Service configs list
 | 
						|
        parameters:
 | 
						|
          - name: service
 | 
						|
            in: path
 | 
						|
            type: string
 | 
						|
            required: true
 | 
						|
            enum: ['nginx', 'apache']
 | 
						|
            description: Type of service (nginx or apache)
 | 
						|
          - name: server_id
 | 
						|
            in: path
 | 
						|
            type: string
 | 
						|
            required: true
 | 
						|
            description: Server ID or IP address
 | 
						|
        responses:
 | 
						|
          200:
 | 
						|
            description: List of configuration files
 | 
						|
            schema:
 | 
						|
              type: object
 | 
						|
              properties:
 | 
						|
                data:
 | 
						|
                  type: array
 | 
						|
                  items:
 | 
						|
                    type: string
 | 
						|
                  example: [
 | 
						|
                    "/etc/nginx/conf.d/default.conf",
 | 
						|
                    "/etc/nginx/waf/modsecurity.conf",
 | 
						|
                    "/etc/nginx/waf/rulescrs-setup.conf",
 | 
						|
                    "/etc/nginx/waf/waf.conf",
 | 
						|
                    "/etc/nginx/nginx.conf"
 | 
						|
                  ]
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            server_ip = SupportClass(False).return_server_ip_or_id(server_id)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot find the server')
 | 
						|
 | 
						|
        files = []
 | 
						|
        service_config_dir = sql.get_setting(f'{service}_dir')
 | 
						|
 | 
						|
        try:
 | 
						|
            return_files = server_mod.get_remote_files(server_ip, service_config_dir, 'conf')
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get configs')
 | 
						|
 | 
						|
        return_files = return_files.split('\t\t')
 | 
						|
        for file in return_files:
 | 
						|
            if '\r\n' in file:
 | 
						|
                for f in file.split('\r\n'):
 | 
						|
                    if f == '':
 | 
						|
                        continue
 | 
						|
                    elif '\t' in f:
 | 
						|
                        for f1 in f.split('\t'):
 | 
						|
                            files.append(f1)
 | 
						|
                    else:
 | 
						|
                        files.append(f)
 | 
						|
            elif file == '':
 | 
						|
                continue
 | 
						|
            else:
 | 
						|
                files.append(file)
 | 
						|
        files.append(sql.get_setting(f'{service}_config_path'))
 | 
						|
        return DataResponse(data=files).model_dump(mode='json')
 | 
						|
 | 
						|
 | 
						|
class ServiceConfigVersionsView(MethodView):
 | 
						|
    methods = ['GET', 'POST', 'DELETE']
 | 
						|
    decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=4), check_group()]
 | 
						|
 | 
						|
    def get(self, service: str, server_id: Union[int, str]):
 | 
						|
        """
 | 
						|
        This endpoint returns a list of configuration file versions for a specified service on a specific server.
 | 
						|
        ---
 | 
						|
        tags:
 | 
						|
          - Service config
 | 
						|
        parameters:
 | 
						|
          - in: path
 | 
						|
            name: service
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The type of service (haproxy, nginx, apache, keepalived)
 | 
						|
          - in: path
 | 
						|
            name: server_id
 | 
						|
            type: 'integer'
 | 
						|
            required: true
 | 
						|
            description: The ID or IP of the server
 | 
						|
        responses:
 | 
						|
          200:
 | 
						|
            description: 'Successful operation, returns list of configuration file versions'
 | 
						|
          default:
 | 
						|
            description: Unexpected error
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            server_ip = SupportClass(False).return_server_ip_or_id(server_id)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, '')
 | 
						|
 | 
						|
        config_dir = config_common.get_config_dir(service)
 | 
						|
        file_format = config_common.get_file_format(service)
 | 
						|
        files = roxywi_common.get_files(config_dir, file_format, server_ip)
 | 
						|
        return DataResponse(data=files).model_dump(mode='json')
 | 
						|
 | 
						|
    @validate(body=VersionsForDelete)
 | 
						|
    def delete(self, service: str, server_id: Union[int, str], body: VersionsForDelete):
 | 
						|
        """
 | 
						|
        This endpoint deletes specified configuration file versions for a particular service on a specific server.
 | 
						|
        ---
 | 
						|
        tags:
 | 
						|
          - Service config
 | 
						|
        parameters:
 | 
						|
          - in: path
 | 
						|
            name: service
 | 
						|
            type: string
 | 
						|
            enum: [haproxy, nginx, apache, keepalived]
 | 
						|
            required: true
 | 
						|
            description: The type of service (haproxy, nginx, apache, keepalived)
 | 
						|
          - in: path
 | 
						|
            name: server_id
 | 
						|
            type: string
 | 
						|
            required: true
 | 
						|
            description: The ID or IP of the server
 | 
						|
          - in: body
 | 
						|
            name: body
 | 
						|
            description: JSON array of paths to version files to be deleted
 | 
						|
            schema:
 | 
						|
              type: array
 | 
						|
              items:
 | 
						|
                type: string
 | 
						|
                description: Path to the version file
 | 
						|
            required: true
 | 
						|
        responses:
 | 
						|
          204:
 | 
						|
            description: 'Successful operation, specified configuration file versions are deleted'
 | 
						|
          400:
 | 
						|
            description: 'Invalid service type or server ID'
 | 
						|
          404:
 | 
						|
            description: 'Service or server not found'
 | 
						|
          500:
 | 
						|
            description: 'Internal server error'
 | 
						|
        """
 | 
						|
        file = set()
 | 
						|
        file_format = config_common.get_file_format(service)
 | 
						|
 | 
						|
        try:
 | 
						|
            server_ip = SupportClass(False).return_server_ip_or_id(server_id)
 | 
						|
        except Exception as e:
 | 
						|
            return roxywi_common.handler_exceptions_for_json_data(e, '')
 | 
						|
 | 
						|
        for get in body.versions:
 | 
						|
            if file_format in get and server_ip in get:
 | 
						|
                try:
 | 
						|
                    if config_sql.delete_config_version(service, get):
 | 
						|
                        try:
 | 
						|
                            os.remove(get)
 | 
						|
                        except OSError as e:
 | 
						|
                            if 'No such file or directory' in str(e):
 | 
						|
                                pass
 | 
						|
                    else:
 | 
						|
                        config_dir = config_common.get_config_dir('haproxy')
 | 
						|
                        os.remove(os.path.join(config_dir, get))
 | 
						|
                    try:
 | 
						|
                        file.add(get + "\n")
 | 
						|
                        roxywi_common.logging(
 | 
						|
                            server_ip, f"Version of config has been deleted: {get}", login=1, keep_history=1,
 | 
						|
                            service=service
 | 
						|
                        )
 | 
						|
                    except Exception:
 | 
						|
                        pass
 | 
						|
                except OSError as e:
 | 
						|
                    return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete config version')
 | 
						|
 | 
						|
        return BaseResponse().model_dump(mode='json'), 204
 |