From 961de020fb3f25299677fd474d5f7d1c68037a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD?= Date: Sat, 7 Feb 2026 14:51:15 +0300 Subject: [PATCH] container detection implemented --- APP_PROFILER/entrypoint.sh | 6 +-- APP_PROFILER/routers/server.py | 16 ++++--- APP_PROFILER/services/process.py | 82 ++++++++++++++++++++++++++++---- 3 files changed, 85 insertions(+), 19 deletions(-) diff --git a/APP_PROFILER/entrypoint.sh b/APP_PROFILER/entrypoint.sh index 8f7f357..80b2ec7 100644 --- a/APP_PROFILER/entrypoint.sh +++ b/APP_PROFILER/entrypoint.sh @@ -16,9 +16,9 @@ iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # MSS Clamping (Path MTU Tuning) iptables -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -# Minimal OpenRC initialization to allow rc-service to work in Alpine -mkdir -p /run/openrc -touch /run/openrc/softlevel +# Ensure /run exists for PID files +mkdir -p /run + # Initialize Easy-RSA if not already present in /app/easy-rsa if [ ! -f /app/easy-rsa/easyrsa ]; then diff --git a/APP_PROFILER/routers/server.py b/APP_PROFILER/routers/server.py index 4c8b26f..256daf8 100644 --- a/APP_PROFILER/routers/server.py +++ b/APP_PROFILER/routers/server.py @@ -12,12 +12,16 @@ def configure_server(db: Session = Depends(get_db)): # Generate to a temporary location or standard location # As per plan, we behave like srvconf output_path = "/etc/openvpn/server.conf" - # Since running locally for dev, maybe output to staging - import os - if not os.path.exists("/etc/openvpn"): - # For local dev safety, don't try to write to /etc/openvpn if not root or not existing - output_path = "staging/server.conf" - os.makedirs("staging", exist_ok=True) + + # Ensure we can write to /etc/openvpn + if not os.path.exists(os.path.dirname(output_path)) or not os.access(os.path.dirname(output_path), os.W_OK): + # For local dev or non-root host, use staging + output_path = "staging/server.conf" + os.makedirs("staging", exist_ok=True) + logger.info(f"[SERVER] /etc/openvpn not writable, using staging path: {output_path}") + else: + os.makedirs(os.path.dirname(output_path), exist_ok=True) + content = generator.generate_server_config(db, output_path=output_path) return {"message": "Server configuration generated", "path": output_path} diff --git a/APP_PROFILER/services/process.py b/APP_PROFILER/services/process.py index 9b85af4..620984b 100644 --- a/APP_PROFILER/services/process.py +++ b/APP_PROFILER/services/process.py @@ -6,13 +6,19 @@ import psutil logger = logging.getLogger(__name__) -def get_os_type(): +def is_container(): """ - Simple check to distinguish Alpine from others. + Checks if the application is running inside a Docker container. """ - if os.path.exists("/etc/alpine-release"): - return "alpine" - return "debian" # default fallback to systemctl + if os.path.exists('/.dockerenv'): + return True + try: + with open('/proc/self/cgroup', 'rt') as f: + if 'docker' in f.read(): + return True + except: + pass + return False def control_service(action: str): """ @@ -21,7 +27,63 @@ def control_service(action: str): if action not in ["start", "stop", "restart"]: raise ValueError("Invalid action") + CONFIG_PATH = "/etc/openvpn/server.conf" + PID_FILE = "/run/openvpn.pid" + + # In Container: Use direct execution to avoid OpenRC/cgroups issues + if is_container(): + logger.info(f"[PROCESS] Container detected, using direct execution for {action}") + + def start_vpn_direct(): + if not os.path.exists(CONFIG_PATH): + # Check for alternative location in dev/non-root environments + if os.path.exists("staging/server.conf"): + alt_path = os.path.abspath("staging/server.conf") + logger.info(f"[PROCESS] Using alternative config: {alt_path}") + config = alt_path + else: + return {"status": "error", "message": f"Configuration not found at {CONFIG_PATH}. Please generate it first."} + else: + config = CONFIG_PATH + + # Check if already running + for proc in psutil.process_iter(['name']): + if proc.info['name'] == 'openvpn': + return {"status": "success", "message": "OpenVPN is already running"} + + cmd = ["openvpn", "--config", config, "--daemon", "--writepid", PID_FILE] + try: + subprocess.run(cmd, check=True) + return {"status": "success", "message": "OpenVPN started successfully (direct)"} + except subprocess.CalledProcessError as e: + return {"status": "error", "message": f"Failed to start OpenVPN: {str(e)}"} + + def stop_vpn_direct(): + stopped = False + for proc in psutil.process_iter(['name']): + if proc.info['name'] == 'openvpn': + proc.terminate() + stopped = True + + if os.path.exists(PID_FILE): + try: os.remove(PID_FILE) + except: pass + + if stopped: + return {"status": "success", "message": "OpenVPN stopped successfully"} + else: + return {"status": "success", "message": "OpenVPN was not running"} + + if action == "start": return start_vpn_direct() + elif action == "stop": return stop_vpn_direct() + elif action == "restart": + stop_vpn_direct() + time.sleep(1) + return start_vpn_direct() + + # On Host OS: Use system service manager os_type = get_os_type() + logger.info(f"[PROCESS] Host OS detected ({os_type}), using service manager for {action}") cmd = [] if os_type == "alpine": @@ -30,27 +92,27 @@ def control_service(action: str): cmd = ["systemctl", action, "openvpn"] try: - # Capture output to return it or log it result = subprocess.run(cmd, capture_output=True, text=True, check=True) return { "status": "success", - "message": f"Service {action} executed successfully", + "message": f"Service {action} executed successfully via {cmd[0]}", "stdout": result.stdout } except subprocess.CalledProcessError as e: logger.error(f"Service control failed: {e.stderr}") return { "status": "error", - "message": f"Failed to {action} service", + "message": f"Failed to {action} service via {cmd[0]}", "stderr": e.stderr } except FileNotFoundError: - # Happens if rc-service or systemctl is missing (e.g. dev env) return { "status": "error", - "message": f"Command not found found for OS type {os_type}" + "message": f"Command {cmd[0]} not found found for OS type {os_type}" } + + def get_process_stats(): """ Returns dict with pid, cpu_percent, memory_mb, uptime.