import os import sys import ssl import configparser from flask import Flask, render_template, render_template_string, request, jsonify from routes.main_routes import main_bp from routes.edit_routes import edit_bp from utils.stats_utils import fetch_haproxy_stats, parse_haproxy_stats from auth.auth_middleware import setup_auth from log_parser import parse_log_file from utils.haproxy_config import update_haproxy_config, count_frontends_and_backends BASE_DIR = os.path.abspath(os.path.dirname(__file__)) app = Flask( __name__, static_folder=os.path.join(BASE_DIR, 'static'), static_url_path='/static', template_folder=os.path.join(BASE_DIR, 'templates') ) CONFIG_DIR_DOCKER = '/etc/haproxy-configurator' CONFIG_DIR_LOCAL = './config' CONFIG_DIR_ENV = os.environ.get('CONFIG_DIR', None) if CONFIG_DIR_ENV and os.path.exists(CONFIG_DIR_ENV): CONFIG_DIR = CONFIG_DIR_ENV elif os.path.exists(CONFIG_DIR_DOCKER): CONFIG_DIR = CONFIG_DIR_DOCKER elif os.path.exists(CONFIG_DIR_LOCAL): CONFIG_DIR = CONFIG_DIR_LOCAL else: CONFIG_DIR = CONFIG_DIR_DOCKER AUTH_CFG = os.path.join(CONFIG_DIR, 'auth', 'auth.cfg') SSL_INI = os.path.join(CONFIG_DIR, 'ssl.ini') os.makedirs(os.path.dirname(AUTH_CFG), exist_ok=True) os.makedirs(os.path.dirname(SSL_INI), exist_ok=True) BASIC_AUTH_USERNAME = "admin" BASIC_AUTH_PASSWORD = "admin" try: auth_config = configparser.ConfigParser() auth_config.read(AUTH_CFG) if auth_config.has_section('auth'): BASIC_AUTH_USERNAME = auth_config.get('auth', 'username', fallback='admin') BASIC_AUTH_PASSWORD = auth_config.get('auth', 'password', fallback='admin') else: BASIC_AUTH_USERNAME = "admin" BASIC_AUTH_PASSWORD = "admin" except Exception as e: print(f"[APP] Auth config error: {e}, using defaults", flush=True) BASIC_AUTH_USERNAME = "admin" BASIC_AUTH_PASSWORD = "admin" app.register_blueprint(main_bp) app.register_blueprint(edit_bp) setup_auth(app) certificate_path = None private_key_path = None ssl_context = None try: config2 = configparser.ConfigParser() config2.read(SSL_INI) if config2.has_section('ssl'): certificate_path = config2.get('ssl', 'certificate_path') private_key_path = config2.get('ssl', 'private_key_path') else: print(f"[APP] No [ssl] section in {SSL_INI}", flush=True) sys.exit(1) if not os.path.exists(certificate_path): print(f"[APP] Certificate not found: {certificate_path}", flush=True) sys.exit(1) if not os.path.exists(private_key_path): print(f"[APP] Private key not found: {private_key_path}", flush=True) sys.exit(1) ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) ssl_context.load_cert_chain(certfile=certificate_path, keyfile=private_key_path) print(f"[APP] SSL context loaded", flush=True) except Exception as e: print(f"[APP] SSL error: {e}", flush=True) sys.exit(1) @app.route('/statistics') def display_haproxy_stats(): haproxy_stats = fetch_haproxy_stats() parsed_stats = parse_haproxy_stats(haproxy_stats) return render_template('statistics.html', stats=parsed_stats) @app.route('/logs', endpoint='display_logs') def display_haproxy_logs(): log_file_path = '/var/log/haproxy.log' if not os.path.exists(log_file_path): return render_template('logs.html', logs=[], total_logs=0, error_message=f"Log file not found: {log_file_path}") try: logs = parse_log_file(log_file_path) total_logs = len(logs) # Załaduj ostatnie 200 logów initial_logs = logs[-200:] if len(logs) > 200 else logs return render_template('logs.html', logs=initial_logs, total_logs=total_logs, loaded_count=len(initial_logs)) except Exception as e: return render_template('logs.html', logs=[], total_logs=0, error_message=f"Error parsing logs: {str(e)}") @app.route('/api/logs', methods=['POST']) def api_get_logs(): """API endpoint for paginated and filtered logs""" try: log_file_path = '/var/log/haproxy.log' if not os.path.exists(log_file_path): return jsonify({'error': 'Log file not found', 'success': False}), 404 page = request.json.get('page', 1) per_page = request.json.get('per_page', 50) search_query = request.json.get('search', '').lower() exclude_phrases = request.json.get('exclude', []) if page < 1: page = 1 if per_page < 1 or per_page > 500: per_page = 50 print(f"[API] page={page}, per_page={per_page}, search={search_query}, exclude={len(exclude_phrases)}", flush=True) # Parse all logs all_logs = parse_log_file(log_file_path) total_logs = len(all_logs) # Reverse to show newest first all_logs = all_logs[::-1] # Apply filters filtered_logs = all_logs if search_query: filtered_logs = [log for log in filtered_logs if search_query in f"{log.get('timestamp', '')} {log.get('ip_address', '')} {log.get('http_method', '')} {log.get('requested_url', '')}".lower()] if exclude_phrases: filtered_logs = [log for log in filtered_logs if not any( phrase in f"{log.get('message', '')}" for phrase in exclude_phrases )] total_filtered = len(filtered_logs) # Paginate offset = (page - 1) * per_page paginated_logs = filtered_logs[offset:offset + per_page] print(f"[API] total={total_logs}, filtered={total_filtered}, returned={len(paginated_logs)}", flush=True) return jsonify({ 'success': True, 'logs': paginated_logs, 'page': page, 'per_page': per_page, 'total': total_logs, 'total_filtered': total_filtered, 'loaded_count': len(paginated_logs), 'has_more': offset + per_page < total_filtered }) except Exception as e: print(f"[API] Error: {e}", flush=True) return jsonify({'error': str(e), 'success': False}), 500 @app.route('/home') def home(): frontend_count, backend_count, acl_count, layer7_count, layer4_count = count_frontends_and_backends() return render_template('home.html', frontend_count=frontend_count, backend_count=backend_count, acl_count=acl_count, layer7_count=layer7_count, layer4_count=layer4_count) if __name__ == '__main__': app.run(host='::', port=5000, ssl_context=ssl_context, debug=True)