From c0b78d32f0df66c23464a8177db0c55b55276f07 Mon Sep 17 00:00:00 2001 From: Pavel Loginov Date: Wed, 16 Jun 2021 10:03:15 +0600 Subject: [PATCH] v5.2.0 Changelog: https://haproxy-wi.org/changelog.py#5_2 --- api/api.py | 204 +++++++++ api/api_funct.py | 485 ++++++++++++++++++++++ api/app.wsgi | 8 + app/create_db.py | 31 +- app/funct.py | 8 +- app/{haproxy-wi.cfg => roxy-wi.cfg} | 0 app/{haproxy-wi.db.sql => roxy-wi.db.sql} | 1 + app/sql.py | 112 ++++- config_other/httpd/haproxy-wi.conf | 3 + 9 files changed, 830 insertions(+), 22 deletions(-) create mode 100644 api/api.py create mode 100644 api/api_funct.py create mode 100644 api/app.wsgi rename app/{haproxy-wi.cfg => roxy-wi.cfg} (100%) rename app/{haproxy-wi.db.sql => roxy-wi.db.sql} (97%) diff --git a/api/api.py b/api/api.py new file mode 100644 index 00000000..bf267dec --- /dev/null +++ b/api/api.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os +import sys +from bottle import route, run, template, hook, response, request, error +sys.path.append(os.path.dirname(os.path.abspath(__file__))) +os.chdir(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(os.path.join(sys.path[0], '/var/www/haproxy-wi/app/')) + +import api_funct +import json +import sql + +_error_auth = '403 Auth before' +_allow_origin = '*' +_allow_methods = 'PUT, GET, POST, DELETE, OPTIONS' +_allow_headers = 'Authorization, Origin, Accept, Content-Type, X-Requested-With' + + +@hook('before_request') +def check_login(): + return api_funct.check_login() + + +@hook('after_request') +def enable_cors(): + response.headers['Access-Control-Allow-Origin'] = _allow_origin + response.headers['Access-Control-Allow-Methods'] = _allow_methods + response.headers['Access-Control-Allow-Headers'] = _allow_headers + + +@error(500) +def error_handler_500(error): + return json.dumps({"status": "error", "message": str(error.exception)}) + + +@route('/', method=['GET', 'POST']) +@route('/help', method=['GET', 'POST']) +def index(): + if not check_login(): + return dict(error=_error_auth) + + data = { + 'help': 'show all available endpoints', + 'login': 'get temporarily token. Must be JSON body: login, password and group for which getting token. METHOD: POST', + 'servers':'show info about all servers. METHOD: GET', + 'servers/status':'show status all HAProxyes. METHOD: GET', + 'haproxy/':'show info about the haproxy by id or hostname or ip. METHOD: GET', + 'haproxy//status':'show HAProxy status by id or hostname or ip. METHOD: GET', + 'haproxy//runtime':'exec HAProxy runtime commands by id or hostname or ip. Must be JSON body: "command". METHOD: POST', + 'haproxy//backends':'show backends by id or hostname or ip. METHOD: GET', + 'haproxy//action/start':'start HAProxy service by id or hostname or ip. METHOD: GET', + 'haproxy//action/stop':'stop HAProxy service by id or hostname or ip. METHOD: GET', + 'haproxy//action/restart':'restart HAProxy service by id or hostname or ip. METHOD: GET', + 'haproxy//config':'get HAProxy config from the server by id or hostname or ip. METHOD: GET', + 'haproxy//log':'show HAProxy log by id or hostname or ip. May to have config next headers: rows(format INT) default: 10 grep, waf(if needs WAF log) default: 0, start_hour(format: 24) default: 00, start_minute, end_hour(format: 24) default: 24, end_minute. METHOD: GET', + 'haproxy//section':'show certain section, headers: section_name. METHOD: GET', + 'haproxy//section':'add section to the HAProxy config by id or hostname or ip. Has to have config header with section and action header for action after upload. Action header accepts next value: save, test, reload and restart. May be empty for just save. METHOD: POST', + 'haproxy//acl':'add acl to certain section. Must be JSON body: "section_name", "if", "then", "if_value", "then_value" and "action" for action after upload. Action accepts next value: "save", "test", "reload" and "restart". METHOD: POST', + 'haproxy//acl':'delete acl to certain section. Must be JSON body: "section_name", "if", "then", "if_value", "then_value" and "action" for action after upload. Action accepts next value: "save", "test", "reload" and "restart". METHOD: DELETE' + } + return dict(help=data) + + +@route('/login', method=['POST']) +def get_token(): + token = api_funct.get_token() + return dict(token=token) + + +@route('/servers', method=['GET']) +def get_servers(): + if not check_login(): + return dict(error=_error_auth) + data = {} + try: + token = request.headers.get('token') + login, group_id = sql.get_username_groupid_from_api_token(token) + servers = sql.get_dick_permit(username=login, group_id=group_id, token=token) + + for s in servers: + data[s[0]] = { + 'server_id':s[0], + 'hostname':s[1], + 'ip':s[2], + 'group':s[3], + 'virt':s[4], + 'enable':s[5], + 'is_master':s[6], + 'creds':s[7], + 'alert':s[8], + 'metrics':s[9] + } + except: + pass + + return dict(servers=data) + + +@route('/servers/status', method=['GET']) +def callback(): + if not check_login(): + return dict(error=_error_auth) + return api_funct.get_all_statuses() + + +@route('/haproxy/', method=['GET']) +@route('/haproxy/', method=['GET']) +def callback(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.get_server(haproxy_id) + + +@route('/haproxy//status', method=['GET']) +@route('/haproxy//status', method=['GET']) +def callback(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.get_status(haproxy_id) + + +@route('/haproxy//action/', method=['GET']) +@route('/haproxy//action/', method=['GET']) +def callback(haproxy_id, action): + if not check_login(): + return dict(error=_error_auth) + return api_funct.actions(haproxy_id, action) + + +@route('/haproxy//runtime', method=['POST']) +@route('/haproxy//runtime', method=['POST']) +def callback(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.runtime(haproxy_id) + + +@route('/haproxy//backends', method=['GET']) +@route('/haproxy//backends', method=['GET']) +def callback(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.show_backends(haproxy_id) + + +@route('/haproxy//config', method=['GET']) +@route('/haproxy//config', method=['GET']) +def callback(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.get_config(haproxy_id) +# +# +# @route('/haproxy//config', method=['POST']) +# @route('/haproxy//config', method=['POST']) +# def callback(haproxy_id): +# if not check_login(): +# return dict(error=_error_auth) +# return api_funct.upload_config(haproxy_id) + + +@route('/haproxy//log', method=['GET']) +@route('/haproxy//log', method=['GET']) +def callback(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.show_log(haproxy_id) + + +@route('/haproxy//section', method=['GET']) +def get_section(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.get_section(haproxy_id) + + +@route('/haproxy//section', method=['POST']) +@route('/haproxy//section', method=['POST']) +def callback(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.add_to_config(haproxy_id) + + +@route('/haproxy//acl', method=['POST']) +def add_acl(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.add_acl(haproxy_id) + + +@route('/haproxy//acl', method=['DELETE']) +def add_acl(haproxy_id): + if not check_login(): + return dict(error=_error_auth) + return api_funct.del_acl(haproxy_id) + + +if __name__ == '__main__': + print(sys.path) + port = int(os.environ.get('PORT', 8080)) + run(host='0.0.0.0', port=port, debug=True) diff --git a/api/api_funct.py b/api/api_funct.py new file mode 100644 index 00000000..d881a726 --- /dev/null +++ b/api/api_funct.py @@ -0,0 +1,485 @@ +import os +import sys +import json +sys.path.append(os.path.join(sys.path[0], '/var/www/haproxy-wi/app/')) + +from bottle import route, run, template, hook, response, request, post +import sql +import funct + + +def get_token(): + try: + body = request.body.getvalue().decode('utf-8') + login_pass = json.loads(body) + login = login_pass['login'] + password_from_user = login_pass['password'] + except Exception as e: + return 'error getting credentials: '+str(e) + try: + group_name = login_pass['group'] + group_id = sql.get_group_id_by_name(group_name) + except Exception as e: + return 'error getting group: '+str(e) + try: + users = sql.select_users(username=login) + password = funct.get_hash(password_from_user) + except Exception as e: + return str(e) + + for user in users: + if user[7] == 0: + return False + if login in user[1] and password == user[3]: + import uuid + user_token = str(uuid.uuid4()) + sql.write_api_token(user_token, group_id, user[4], user[1]) + return user_token + else: + return False + + +def check_login(): + token = request.headers.get('token') + return sql.get_api_token(token) + + +def return_dict_from_out(server_id, out): + data = {server_id: {}} + for k in out: + if "Ncat:" not in k: + k = k.split(':') + data[server_id][k[0]] = k[1].strip() + else: + data[server_id] = {"error":"Cannot connect to HAProxy"} + + return data + + +def check_permit_to_server(server_id): + servers = sql.select_servers(id_hostname=server_id) + token = request.headers.get('token') + login, group_id = sql.get_username_groupid_from_api_token(token) + + for s in servers: + server = sql.get_dick_permit(username=login, group_id=group_id, ip=s[2], token=token) + + return server + + +def get_server(server_id): + data = {} + try: + servers = check_permit_to_server(server_id) + + for s in servers: + data = { + 'server_id':s[0], + 'hostname':s[1], + 'ip':s[2], + 'group':s[3], + 'virt':s[4], + 'enable':s[5], + 'master':s[6], + 'creds':s[7] + } + except: + data = '' + return dict(server=data) + + +def get_status(server_id): + try: + servers = check_permit_to_server(server_id) + + for s in servers: + cmd = 'echo "show info" |nc %s %s -w 1|grep -e "Ver\|CurrConns\|Maxco\|MB\|Uptime:"' % (s[2], sql.get_setting('haproxy_sock_port')) + + out = funct.subprocess_execute(cmd) + data = return_dict_from_out(server_id, out[0]) + + except: + data = {server_id: {"error": "Cannot find the server"}} + return dict(error=data) + + return dict(status=data) + + +def get_all_statuses(): + data = {} + try: + servers = sql.select_servers() + token = request.headers.get('token') + login, group_id = sql.get_username_groupid_from_api_token(token) + sock_port = sql.get_setting('haproxy_sock_port') + + for s in servers: + servers = sql.get_dick_permit(username=login, group_id=group_id, token=token) + + for s in servers: + cmd = 'echo "show info" |nc %s %s -w 1|grep -e "Ver\|CurrConns\|Maxco\|MB\|Uptime:"' % (s[2], sock_port) + data[s[2]] = {} + out = funct.subprocess_execute(cmd) + data[s[2]] = return_dict_from_out(s[1], out[0]) + except: + data = {"error":"Cannot find the server"} + return dict(error=data) + + return dict(status=data) + + +def actions(server_id, action): + if action == 'start' or action == 'stop' or action == 'restart': + try: + servers = check_permit_to_server(server_id) + + for s in servers: + cmd = [ "sudo systemctl %s haproxy" % action ] + error = funct.ssh_command(s[2], cmd) + done = error if error else 'done' + + data = {'server_id':s[0],'ip':s[2],'action':action,'hostname':s[1],'status':done} + + return dict(status=data) + except: + return dict(status='error') + else: + return dict(status='wrong action') + + + +def runtime(server_id): + data = {} + try: + body = request.body.getvalue().decode('utf-8') + json_loads = json.loads(body) + action = json_loads['command'] + haproxy_sock = sql.get_setting('haproxy_sock') + servers = check_permit_to_server(server_id) + cmd = [ 'echo "%s" |sudo socat stdio %s' % (action, haproxy_sock) ] + + for s in servers: + out = funct.ssh_command(s[2], cmd) + + data = {server_id: {}} + sep_data = out.split('\r\n') + data = {server_id: sep_data} + + return dict(status=data) + except: + return dict(status='error') + + +def show_backends(server_id): + data = {} + try: + servers = check_permit_to_server(server_id) + + for s in servers: + out = funct.show_backends(s[2], ret=1) + + data = {server_id: out} + + except: + data = {server_id: {"error": "Cannot find the server"}} + return dict(error=data) + + return dict(backends=data) + + +def get_config(server_id): + data = {} + try: + servers = check_permit_to_server(server_id) + + for s in servers: + cfg = '/tmp/'+s[2]+'.cfg' + out = funct.get_config(s[2], cfg) + os.system("sed -i 's/\\n/\n/g' "+cfg) + try: + conf = open(cfg, "r") + config_read = conf.read() + conf.close + + except IOError: + conf = '
Can\'t read import config file' + + data = {server_id: config_read} + + except: + data = {server_id: {"error": "Cannot find the server"}} + return dict(error=data) + + return dict(config=data) + + +def get_section(server_id): + section_name = request.headers.get('section_name') + servers = check_permit_to_server(server_id) + for s in servers: + cfg = '/tmp/' + s[2] + '.cfg' + + out = funct.get_config(s[2], cfg) + start_line, end_line, config_read = funct.get_section_from_config(cfg, section_name) + + data = {server_id: {section_name:{'start_line':start_line, 'end_line':end_line, 'config_read':config_read}}} + return dict(section=data) + + + +def upload_config(server_id): + data = {} + body = request.body.getvalue().decode('utf-8') + save = request.headers.get('action') + token = request.headers.get('token') + login, group_id = sql.get_username_groupid_from_api_token(token) + hap_configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir') + + if save == '': + save = 'save' + elif save == 'restart': + save = '' + + try: + servers = check_permit_to_server(server_id) + + for s in servers: + ip = s[2] + cfg = '/tmp/'+ip+'.cfg' + cfg_for_save = hap_configs_dir + ip + "-" + funct.get_data('config') + ".cfg" + + try: + with open(cfg, "w") as conf: + conf.write(body) + return_mess = 'config has been uploaded' + os.system("/bin/cp %s %s" % (cfg, cfg_for_save)) + out = funct.upload_and_restart(ip, cfg, just_save=save) + funct.logging('localhost', " config has been uploaded via REST API", login=login) + + if out: + return_mess = out + except IOError: + return_mess = "cannot upload config" + + data = {server_id: return_mess} + except Exception as e: + data = {server_id: {"error": str(e)}} + return dict(error=data) + + return dict(config=data) + + +def add_to_config(server_id): + data = {} + body = request.body.getvalue().decode('utf-8') + save = request.headers.get('action') + hap_configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir') + token = request.headers.get('token') + login, group_id = sql.get_username_groupid_from_api_token(token) + + if save == '': + save = 'save' + elif save == 'restart': + save = '' + + try: + servers = check_permit_to_server(server_id) + + for s in servers: + ip = s[2] + cfg = '/tmp/' + ip + '.cfg' + cfg_for_save = hap_configs_dir + ip + "-" + funct.get_data('config') + ".cfg" + out = funct.get_config(ip, cfg) + try: + with open(cfg, "a") as conf: + conf.write('\n'+body+'\n') + + return_mess = 'section has been added to the config' + os.system("/bin/cp %s %s" % (cfg, cfg_for_save)) + funct.logging('localhost', " section has been added via REST API", login=login) + out = funct.upload_and_restart(ip, cfg, just_save=save) + + if out: + return_mess = out + except IOError: + return_mess = "cannot upload config" + + data = {server_id: return_mess} + except: + data[server_id] = {"error":"cannot find the server"} + return dict(error=data) + + return dict(config=data) + + +def show_log(server_id): + data = {} + rows = request.headers.get('rows') + waf = request.headers.get('waf') + grep = request.headers.get('grep') + hour = request.headers.get('start_hour') + minute = request.headers.get('start_minute') + hour1 = request.headers.get('end_hour') + minute1 = request.headers.get('end_minute') + + if rows is None: + rows = '10' + if waf is None: + waf = '0' + if hour is None: + hour = '00' + if minute is None: + minute = '00' + if hour1 is None: + hour1 = '24' + if minute1 is None: + minute1 = '00' + + try: + servers = check_permit_to_server(server_id) + + for s in servers: + ip = s[2] + except: + + data[server_id] = {"error":"Cannot find the server"} + return dict(error=data) + + out = funct.show_haproxy_log(ip, rows=rows, waf=str(waf), grep=grep, hour=str(hour), minut=str(minute), hour1=str(hour1), minut1=str(minute1), html=0) + data = {server_id: out} + + return dict(log=data) + +def add_acl(server_id): + body = request.body.getvalue().decode('utf-8') + json_loads = json.loads(body) + save = json_loads['action'] + section_name = json_loads['section_name'] + + acl = generate_acl(with_newline=1) + servers = check_permit_to_server(server_id) + status = '' + + for s in servers: + cfg = '/tmp/' + s[2] + '.cfg' + server_ip = s[2] + + try: + out = funct.get_config(server_ip, cfg) + start_line, end_line, config_read = funct.get_section_from_config(cfg, section_name) + except Exception as e: + status = "Cannot read section: " + str(e) + + try: + config_read += acl + config = funct.rewrite_section(start_line, end_line, cfg, config_read) + try: + with open(cfg, "w") as conf: + conf.write(config) + except IOError as e: + status = "Cannot read import config file: " + str(e) + except Exception as e: + status = str(e) + + try: + out = funct.master_slave_upload_and_restart(server_ip, cfg, just_save=save) + if out != '': + status = out + else: + status = 'ACL has been added' + except Exception as e: + status = str(e) + + data = {'acl':status} + return dict(data) + + +def del_acl(server_id): + body = request.body.getvalue().decode('utf-8') + json_loads = json.loads(body) + save = json_loads['action'] + section_name = json_loads['section_name'] + + acl = generate_acl() + servers = check_permit_to_server(server_id) + status = '' + + for s in servers: + cfg = '/tmp/' + s[2] + '.cfg' + server_ip = s[2] + try: + out = funct.get_config(server_ip, cfg) + start_line, end_line, config_read = funct.get_section_from_config(cfg, section_name) + except Exception as e: + status = str(e) + + try: + config_new_read = '' + for line in config_read.split('\n'): + if not line.startswith(acl): + if line != '': + config_new_read += line + '\n' + except Exception as e: + status = 'Cannot delete ACL: ' + str(e) + + try: + config = funct.rewrite_section(start_line, end_line, cfg, config_new_read) + try: + with open(cfg, "w") as conf: + conf.write(config) + except IOError as e: + status = "Cannot read import config file: " + str(e) + except Exception as e: + status = 'Cannot delete ACL: ' + str(e) + + try: + out = funct.master_slave_upload_and_restart(server_ip, cfg, just_save=save) + if out != '': + status = out + else: + status = 'ACL has been deleted' + except Exception as e: + status = str(e) + + return dict(acl=status) + + +def generate_acl(**kwargs): + body = request.body.getvalue().decode('utf-8') + json_loads = json.loads(body) + if_value = json_loads['if_value'] + then_value = json_loads['then_value'] + if_acl = json_loads['if'] + then_acl = json_loads['then'] + acl = '' + + if if_acl == 'host_starts': + acl_if_word = 'hdr_beg(host) -i ' + elif if_acl == 'host_ends': + acl_if_word = 'hdr_end(host) -i ' + elif if_acl == 'path_starts': + acl_if_word = 'path_beg -i ' + elif if_acl == 'path_ends': + acl_if_word = 'path_end -i ' + elif if_acl == 'src_ip': + acl_if_word = 'src ip ' + else: + acl_if_word = '' + + if then_acl == 'use_backend': + acl += ' use_backend ' + elif then_acl == 'redirect': + acl += ' http-request redirect location ' + elif then_acl == 'allow': + acl += ' http-request allow' + elif then_acl == 'deny': + acl += ' http-request deny' + elif then_acl == 'return': + acl += ' return ' + elif then_acl == 'set-header': + acl += ' set-header ' + + newline = '\n' if kwargs.get('with_newline') else '' + acl += then_value + ' if { ' + acl_if_word + if_value + ' } ' + newline + + return acl diff --git a/api/app.wsgi b/api/app.wsgi new file mode 100644 index 00000000..a644fc90 --- /dev/null +++ b/api/app.wsgi @@ -0,0 +1,8 @@ +import sys +import os +import bottle +sys.path.append(os.path.dirname(os.path.abspath(__file__))) +os.chdir(os.path.dirname(os.path.abspath(__file__))) +import api + +application = bottle.default_app() \ No newline at end of file diff --git a/app/create_db.py b/app/create_db.py index fc11181e..bc45b62f 100644 --- a/app/create_db.py +++ b/app/create_db.py @@ -11,7 +11,7 @@ if mysql_enable == '1': mysql_port = funct.get_config_var('mysql', 'mysql_port') import mysql.connector as sqltool else: - db = "haproxy-wi.db" + db = "roxy-wi.db" import sqlite3 as sqltool @@ -205,7 +205,7 @@ def create_table(**kwargs): `create_date` DATETIME default '0000-00-00 00:00:00', `expire_date` DATETIME default '0000-00-00 00:00:00' ); - CREATE TABLE IF NOT EXISTS `metrics_http_status` (`serv` varchar(64), `2xx` INTEGER, `3xx` INTEGER, `4xx` INTEGER, `5xx` INTEGER,`date` timestamp default '0000-00-00 00:00:00'); + CREATE TABLE IF NOT EXISTS `metrics_http_status` (`serv` varchar(64), `2xx` INTEGER, `3xx` INTEGER, `4xx` INTEGER, `5xx` INTEGER,`date` DATETIME default '0000-00-00 00:00:00'); CREATE TABLE IF NOT EXISTS `slack` (`id` INTEGER NOT NULL, `token` VARCHAR (64), `chanel_name` INTEGER NOT NULL DEFAULT 1, `groups` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`)); CREATE TABLE IF NOT EXISTS `settings` (`param` varchar(64), value varchar(64), section varchar(64), `desc` varchar(100), `group` INTEGER NOT NULL DEFAULT 1, UNIQUE(param, `group`)); INSERT INTO settings (param, value, section, `desc`) values('time_zone', 'UTC', 'main', 'Time Zone'); @@ -214,8 +214,8 @@ def create_table(**kwargs): INSERT INTO settings (param, value, section, `desc`) values('token_ttl', '5', 'main', 'Time to live users tokens. In days'); INSERT INTO settings (param, value, section, `desc`) values('tmp_config_path', '/tmp/', 'main', 'A temp folder of configs, for checking. The path must exist'); INSERT INTO settings (param, value, section, `desc`) values('cert_path', '/etc/ssl/certs/', 'main', 'A path to SSL dir. The folder owner must be an user who set in the SSH settings. The path must exist'); - INSERT INTO settings (param, value, section, `desc`) values('ssl_local_path', 'certs', 'main', 'Path to dir for local save SSL certs. This is a relative path, begins with $HOME_HAPROXY-WI/app/'); - INSERT INTO settings (param, value, section, `desc`) values('lists_path', 'lists', 'main', 'Path to black/white lists. This is a relative path, begins with $HOME_HAPROXY-WI'); + INSERT INTO settings (param, value, section, `desc`) values('ssl_local_path', 'certs', 'main', 'Path to dir for local save SSL certs. This is a relative path, begins with $HOME_ROXY-WI/app/'); + INSERT INTO settings (param, value, section, `desc`) values('lists_path', 'lists', 'main', 'Path to black/white lists. This is a relative path, begins with $HOME_ROXY-WI'); INSERT INTO settings (param, value, section, `desc`) values('local_path_logs', '/var/log/haproxy.log', 'logs', 'Logs save locally, enabled by default'); INSERT INTO settings (param, value, section, `desc`) values('syslog_server_enable', '0', 'logs', 'If exist syslog server for HAProxy logs, enable this option'); INSERT INTO settings (param, value, section, `desc`) values('syslog_server', '0', 'logs', 'IP address of syslog server'); @@ -258,7 +258,7 @@ def create_table(**kwargs): con.close() else: try: - for line in open("haproxy-wi.db.sql"): + for line in open("roxy-wi.db.sql"): cur.execute(line) except sqltool.Error as e: print('
') @@ -1251,6 +1251,25 @@ def update_db_v_5_1_3(**kwargs): con.close() +def update_db_v_5_1_3_2(**kwargs): + con, cur = get_cur() + sql = """ + CREATE TABLE IF NOT EXISTS `metrics_http_status` (`serv` varchar(64), `2xx` INTEGER, `3xx` INTEGER, `4xx` INTEGER, `5xx` INTEGER,`date` DATETIME default '0000-00-00 00:00:00'); + """ + try: + cur.execute(sql) + con.commit() + except sqltool.Error as e: + if kwargs.get('silent') != 1: + if e.args[0] == 'duplicate column name: version' or e == "1060 (42S21): Duplicate column name 'version' ": + print('Updating... DB has been updated to version 5.1.1') + else: + print("Updating... DB has been updated to version 5.1.1") + + cur.close() + con.close() + + def update_db_v_5_2_0(**kwargs): con, cur = get_cur() sql = list() @@ -1313,6 +1332,7 @@ def update_all(): update_db_v_5_1_1() update_db_v_5_1_2() update_db_v_5_1_3() + update_db_v_5_1_3_2() update_db_v_5_2_0() update_ver() @@ -1350,6 +1370,7 @@ def update_all_silent(): update_db_v_5_1_1(silent=1) update_db_v_5_1_2(silent=1) update_db_v_5_1_3(silent=1) + update_db_v_5_1_3_2(silent=1) update_db_v_5_2_0(silent=1) update_ver() diff --git a/app/funct.py b/app/funct.py index 48ce471d..d77d90e7 100644 --- a/app/funct.py +++ b/app/funct.py @@ -16,12 +16,12 @@ def get_app_dir(): def get_config_var(sec, var): from configparser import ConfigParser, ExtendedInterpolation try: - path_config = "/var/www/haproxy-wi/app/haproxy-wi.cfg" + path_config = "/var/www/haproxy-wi/app/roxy-wi.cfg" config = ConfigParser(interpolation=ExtendedInterpolation()) config.read(path_config) except Exception: print('Content-type: text/html\n') - print('
Check the config file, whether it exists and the path. Must be: app/haproxy-wi.cfg
') + print('
Check the config file, whether it exists and the path. Must be: app/roxy-wi.cfg
') try: return config.get(sec, var) except Exception: @@ -679,13 +679,13 @@ def install_nginx(serv, **kwargs): def update_haproxy_wi(service): - if service != 'haproxy-wi': + if service != 'roxy-wi': try: if service != 'keep_alive': service = service.split('_')[0] except Exception: pass - service = 'haproxy-wi-'+service + service = 'roxy-wi-'+service cmd = 'sudo -S yum -y update ' + service +' && sudo systemctl restart ' + service output, stderr = subprocess_execute(cmd) print(output) diff --git a/app/haproxy-wi.cfg b/app/roxy-wi.cfg similarity index 100% rename from app/haproxy-wi.cfg rename to app/roxy-wi.cfg diff --git a/app/haproxy-wi.db.sql b/app/roxy-wi.db.sql similarity index 97% rename from app/haproxy-wi.db.sql rename to app/roxy-wi.db.sql index fd459ca1..d1c00669 100644 --- a/app/haproxy-wi.db.sql +++ b/app/roxy-wi.db.sql @@ -13,6 +13,7 @@ CREATE TABLE IF NOT EXISTS `uuid` (`user_id` INTEGER NOT NULL, `uuid` varchar ( CREATE TABLE IF NOT EXISTS `token` (`user_id` INTEGER, `token` varchar(64), `exp` timestamp default CURRENT_TIMESTAMP); CREATE TABLE IF NOT EXISTS `cred` (`id` integer primary key AUTO_INCREMENT, `name` VARCHAR ( 64 ), `enable` INTEGER NOT NULL DEFAULT 1, `username` VARCHAR ( 64 ) NOT NULL, `password` VARCHAR ( 64 ) NOT NULL, `groups` INTEGER NOT NULL DEFAULT 1, UNIQUE(name,`groups`)); CREATE TABLE IF NOT EXISTS `telegram` (`id` integer primary key auto_increment, `token` VARCHAR ( 64 ), `chanel_name` INTEGER NOT NULL DEFAULT 1, `groups` INTEGER NOT NULL DEFAULT 1); +CREATE TABLE IF NOT EXISTS `metrics_http_status` (`serv` varchar(64), `2xx` INTEGER, `3xx` INTEGER, `4xx` INTEGER, `5xx` INTEGER,`date` DATETIME default '0000-00-00 00:00:00'); CREATE TABLE IF NOT EXISTS `metrics` (`serv` varchar(64), curr_con INTEGER, cur_ssl_con INTEGER, sess_rate INTEGER, max_sess_rate INTEGER,`date` DATETIME default '0000-00-00 00:00:00'); CREATE TABLE IF NOT EXISTS `settings` (`param` varchar(64), value varchar(64), section varchar(64), `desc` varchar(100), `group` INTEGER NOT NULL DEFAULT 1, UNIQUE(param, `group`)); CREATE TABLE IF NOT EXISTS `version` (`version` varchar(64)); diff --git a/app/sql.py b/app/sql.py index 0c62fc39..1063711a 100644 --- a/app/sql.py +++ b/app/sql.py @@ -7,7 +7,7 @@ mysql_enable = funct.get_config_var('mysql', 'enable') if mysql_enable == '1': import mysql.connector as sqltool else: - db = "/var/www/haproxy-wi/app/haproxy-wi.db" + db = "/var/www/haproxy-wi/app/roxy-wi.db" import sqlite3 as sqltool @@ -522,8 +522,9 @@ def get_group_name_by_id(group_id): else: for name in cur.fetchone(): return name - cur.close() - con.close() + finally: + cur.close() + con.close() def get_group_id_by_name(group_name): @@ -537,8 +538,57 @@ def get_group_id_by_name(group_name): else: for group_id in cur.fetchone(): return group_id - cur.close() - con.close() + finally: + cur.close() + con.close() + + +def get_group_id_by_server_ip(server_ip): + con, cur = get_cur() + sql = """select `groups` from servers where ip = '%s' """ % server_ip + + try: + cur.execute(sql) + except sqltool.Error as e: + return funct.out_error(e) + else: + for group_id in cur.fetchone(): + return group_id + finally: + cur.close() + con.close() + + +def get_cred_id_by_server_ip(server_ip): + con, cur = get_cur() + sql = """select `cred` from servers where ip = '%s' """ % server_ip + + try: + cur.execute(sql) + except sqltool.Error as e: + return funct.out_error(e) + else: + for cred_id in cur.fetchone(): + return cred_id + finally: + cur.close() + con.close() + + +def get_hostname_by_server_ip(server_ip): + con, cur = get_cur() + sql = """select `hostname` from servers where ip = '%s' """ % server_ip + + try: + cur.execute(sql) + except sqltool.Error as e: + return funct.out_error(e) + else: + for hostname in cur.fetchone(): + return hostname + finally: + cur.close() + con.close() def select_server_by_name(name): @@ -2197,8 +2247,9 @@ def select_keealived(serv, **kwargs): else: for value in cur.fetchone(): return value - cur.close() - con.close() + finally: + cur.close() + con.close() def update_keepalived(serv): @@ -2212,8 +2263,9 @@ def update_keepalived(serv): funct.out_error(e) con.rollback() return False - cur.close() - con.close() + finally: + cur.close() + con.close() def select_nginx(serv, **kwargs): @@ -2241,8 +2293,9 @@ def update_nginx(serv): funct.out_error(e) con.rollback() return False - cur.close() - con.close() + finally: + cur.close() + con.close() def update_haproxy(serv): @@ -2256,8 +2309,25 @@ def update_haproxy(serv): funct.out_error(e) con.rollback() return False - cur.close() - con.close() + finally: + cur.close() + con.close() + + +def update_firewall(serv): + con, cur = get_cur() + sql = """update `servers` set `firewall_enable` = '1' where ip = '%s' """ % serv + try: + cur.execute(sql) + con.commit() + return True + except sqltool.Error as e: + funct.out_error(e) + con.rollback() + return False + finally: + cur.close() + con.close() def update_server_pos(pos, id): @@ -2845,6 +2915,22 @@ def delete_alert_history(keep_interval: int, service: str): con.close() +def delete_portscanner_history(keep_interval: int, service: str): + con, cur = get_cur() + if mysql_enable == '1': + sql = """ delete from port_scanner_history where date < now() - INTERVAL %s day and service = '%s'""" % (keep_interval, service) + else: + sql = """ delete from port_scanner_history where date < datetime('now', '-%s days') and service = '%s'""" % (keep_interval, service) + try: + cur.execute(sql) + con.commit() + except sqltool.Error as e: + funct.out_error(e) + con.rollback() + cur.close() + con.close() + + def select_port_scanner_history(serv): con, cur = get_cur() sql = """select * from port_scanner_history where serv = '%s' """ % serv diff --git a/config_other/httpd/haproxy-wi.conf b/config_other/httpd/haproxy-wi.conf index d0f163f3..94336cee 100644 --- a/config_other/httpd/haproxy-wi.conf +++ b/config_other/httpd/haproxy-wi.conf @@ -12,6 +12,9 @@ TimeOut 600 LimitRequestLine 16380 + WSGIDaemonProcess api display-name=%{GROUP} user=apache group=apache processes=1 threads=5 + WSGIScriptAlias /api /var/www/haproxy-wi/api/app.wsgi + DocumentRoot /var/www/haproxy-wi ScriptAlias /cgi-bin/ "/var/www/haproxy-wi/app/"