haproxy-wi/app/modules/service/common.py

285 lines
11 KiB
Python

import requests
from flask import render_template, request
import app.modules.db.sql as sql
import app.modules.db.user as user_sql
import app.modules.db.server as server_sql
import app.modules.db.service as service_sql
import app.modules.common.common as common
import app.modules.server.server as server_mod
import app.modules.roxywi.common as roxywi_common
import app.modules.config.section as section_mod
import app.modules.config.common as config_common
def get_correct_service_name(service: str, server_id: int) -> str:
"""
:param service: The name of the service.
:param server_id: The ID of the server.
:return: The correct service name based on the provided parameters.
This method takes a service name and server ID as input and returns the correct service name based on the given parameters. If the service name is 'haproxy', it checks if haproxy_enter
*prise is set to '1' in the database for the given server ID. If true, it returns "hapee-2.0-lb". If the service name is 'apache', it calls the get_correct_apache_service_name() method
* with parameters 0 and the server ID to get the correct apache service name. If none of the conditions match, it will return the original service name.
"""
if service == 'haproxy':
haproxy_enterprise = service_sql.select_service_setting(server_id, 'haproxy', 'haproxy_enterprise')
if haproxy_enterprise == '1':
return "hapee-2.0-lb"
if service == 'apache':
return get_correct_apache_service_name(0, server_id)
return service
def check_haproxy_version(server_ip):
hap_sock_p = sql.get_setting('haproxy_sock_port')
ver = ""
cmd = f"echo 'show info' |nc {server_ip} {hap_sock_p} |grep Version |awk '{{print $2}}'"
output, stderr = server_mod.subprocess_execute(cmd)
for line in output:
ver = line
return ver
def is_protected(server_ip: str, action: str) -> None:
"""
Check if the server is protected and the user has the required role.
:param server_ip: The IP address of the server.
:param action: The action to be performed on the server.
:return: None
:raises: Exception if the server is protected and the user role is not high enough.
"""
user_uuid = request.cookies.get('uuid')
group_id = int(request.cookies.get('group'))
user_role = user_sql.get_user_role_by_uuid(user_uuid, group_id)
if server_sql.is_serv_protected(server_ip) and int(user_role) > 2:
raise Exception(f'error: This server is protected. You cannot {action} it')
def is_not_allowed_to_restart(server_id: int, service: str, action: str) -> int:
"""
:param server_id: The ID of the server.
:param service: The name of the service.
:param action: The action to perform on the service.
:return: An integer indicating whether the restart is allowed or not.
This method checks if the given service is not allowed to be restarted based on the provided server ID, service name, and action. It returns `0` if the restart is not allowed, otherwise
* it returns `1`.
"""
is_restart = 0
if service != 'waf' and action == 'restart':
try:
is_restart = int(service_sql.select_service_setting(server_id, service, 'restart'))
except Exception as e:
roxywi_common.handle_exceptions(e, 'Roxy-WI server', f'Cannot get restart settings for service {service}')
return is_restart
def get_exp_version(server_ip: str, service_name: str) -> str:
server_ip = common.is_ip_or_dns(server_ip)
if service_name == 'haproxy':
command = "/opt/prometheus/exporters/haproxy_exporter --version 2>&1 |head -1|awk '{print $3}'"
elif service_name == 'nginx':
command = "/opt/prometheus/exporters/nginx_exporter --version 2>&1 |head -1 |awk -F\"version\" '{print $2}'|awk '{print $1}'"
elif service_name == 'node':
command = "node_exporter --version 2>&1 |head -1|awk '{print $3}'"
elif service_name == 'apache':
command = "/opt/prometheus/exporters/apache_exporter --version 2>&1 |head -1|awk '{print $3}'"
elif service_name == 'keepalived':
command = "keepalived_exporter --version 2>&1 |head -1|awk '{print $2}'"
ver = server_mod.ssh_command(server_ip, command)
if ver != '':
return ver
else:
return 'no'
def get_correct_apache_service_name(server_ip=None, server_id=None) -> str:
if server_id is None:
server_id = server_sql.select_server_id_by_ip(server_ip)
try:
os_info = server_sql.select_os_info(server_id)
except Exception as e:
raise Exception(f'error: cannot get server info: {e}')
if "CentOS" in os_info or "Redhat" in os_info:
return 'httpd'
else:
return 'apache2'
def server_status(stdout):
proc_count = ""
for line in stdout:
if "Ncat: " not in line:
for k in line:
try:
proc_count = k.split(":")[1]
except Exception:
proc_count = 1
else:
proc_count = 0
return proc_count
def check_service_config(server_ip: str, server_id: int, service: str) -> None:
"""
:param server_ip: The IP address of the server to check the service configuration for.
:param server_id: The unique identifier of the server.
:param service: The name of the service to check the configuration for.
:return: True if the service configuration is valid, False otherwise.
This method checks the configuration of a given service on a server. It first retrieves the value of the "dockerized" setting for the service and the container name from the database
*. Then, it constructs the command to check the configuration based on the service type and dockerization status.
The command depends on the service type and can be one of the following:
- For haproxy:
- If not dockerized: `haproxy -c -f {config_path}`
- If dockerized: `sudo docker exec -it {container_name} haproxy -c -f {config_path}`
- For nginx:
- If not dockerized: `sudo nginx -q -t -p {config_path}`
- If dockerized: `sudo docker exec -it {container_name} nginx -t`
- For apache:
- If not dockerized: `sudo apachectl -t`
- If dockerized: `sudo docker exec -it {container_name} apachectl -t`
- For keepalived:
- If not dockerized: `keepalived -t -f {config_path}`
- If dockerized: empty string ` ` (no command needed)
The method then tries to execute the generated command on the server using the server_mod.ssh_command method. If any exception occurs during the process, it is re-ra
*ised with an appropriate error message.
"""
is_dockerized = service_sql.select_service_setting(server_id, service, 'dockerized')
container_name = sql.get_setting(f'{service}_container_name')
command_for_docker = f'sudo docker exec -it {container_name}'
config_path = ''
if service in ('haproxy', 'keepalived'):
config_path = sql.get_setting(f'{service}_config_path')
command = {
'haproxy': {'0': f'haproxy -c -f {config_path} ', '1': f'{command_for_docker} haproxy -c -f {config_path} '},
'nginx': {'0': 'sudo nginx -q -t ', '1': f'{command_for_docker} nginx -t '},
'apache': {'0': 'sudo apachectl -t ', '1': f'{command_for_docker} apachectl -t '},
'keepalived': {'0': f'keepalived -t -f {config_path} ', '1': ' '}
}
try:
check_config = command[service][is_dockerized]
except Exception as e:
raise Exception(f'error: Cannot generate command: {e}')
try:
server_mod.ssh_command(server_ip, check_config)
except Exception as e:
raise Exception(e)
def overview_backends(server_ip: str, service: str) -> str:
import modules.config.config as config_mod
lang = roxywi_common.get_user_lang_for_flask()
if service != 'nginx' and service != 'apache':
format_file = config_common.get_file_format(service)
config_dir = config_common.get_config_dir(service)
cfg = config_common.generate_config_path(service, server_ip)
try:
sections = section_mod.get_sections(config_dir + roxywi_common.get_files(config_dir, format_file)[0], service=service)
except Exception as e:
roxywi_common.logging('Roxy-WI server', str(e), roxywi=1)
try:
config_mod.get_config(server_ip, cfg, service=service)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f' Cannot download a config {e}', roxywi=1)
try:
sections = section_mod.get_sections(cfg, service=service)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f' Cannot get sections from config file {e}', roxywi=1)
sections = f'error: Cannot get backends {e}'
else:
sections = section_mod.get_remote_sections(server_ip, service)
return render_template('ajax/haproxyservers_backends.html', backends=sections, serv=server_ip, service=service, lang=lang)
def get_overview_last_edit(server_ip: str, service: str) -> str:
config_path = sql.get_setting(f'{service}_config_path')
command = "ls -l %s |awk '{ print $6\" \"$7\" \"$8}'" % config_path
try:
return server_mod.ssh_command(server_ip, command)
except Exception as e:
return f'error: Cannot get last date {e} for server {server_ip}'
def get_stat_page(server_ip: str, service: str) -> str:
stats_user = sql.get_setting(f'{service}_stats_user')
stats_pass = sql.get_setting(f'{service}_stats_password')
stats_port = sql.get_setting(f'{service}_stats_port')
stats_page = sql.get_setting(f'{service}_stats_page')
try:
response = requests.get(f'http://{server_ip}:{stats_port}/{stats_page}', auth=(stats_user, stats_pass), timeout=5)
except requests.exceptions.ConnectTimeout:
return 'error: Oops. Connection timeout occurred!'
except requests.exceptions.ReadTimeout:
return 'error: Oops. Read timeout occurred'
except requests.exceptions.HTTPError as errh:
return f'error: Http Error: {errh}'
except requests.exceptions.ConnectionError as errc:
return f'error: Error Connecting: {errc}'
except requests.exceptions.Timeout as errt:
return f'error: Timeout Error: {errt}'
except requests.exceptions.RequestException as err:
return f'error: OOps: Something Else {err}'
data = response.content
if service == 'nginx':
lang = roxywi_common.get_user_lang_for_flask()
servers_with_status = list()
out1 = []
for k in data.decode('utf-8').split():
out1.append(k)
h = (out1,)
servers_with_status.append(h)
return render_template('ajax/nginx_stats.html', out=servers_with_status, lang=lang)
else:
return data.decode('utf-8')
def show_service_version(server_ip: str, service: str) -> str:
if service == 'haproxy':
return check_haproxy_version(server_ip)
server_id = server_sql.select_server_id_by_ip(server_ip)
service_name = get_correct_service_name(service, server_id)
is_dockerized = service_sql.select_service_setting(server_id, service, 'dockerized')
if is_dockerized == '1':
container_name = sql.get_setting(f'{service}_container_name')
if service == 'apache':
cmd = f'docker exec -it {container_name} /usr/local/apache2/bin/httpd -v 2>&1|head -1|awk -F":" \'{{print $2}}\''
else:
cmd = f'docker exec -it {container_name} /usr/sbin/{service_name} -v 2>&1|head -1|awk -F":" \'{{print $2}}\''
else:
cmd = [f'sudo /usr/sbin/{service_name} -v|head -1|awk -F":" \'{{print $2}}\'']
try:
return server_mod.ssh_command(server_ip, cmd, timeout=5)
except Exception as e:
return f'{e}'