from fastapi import FastAPI, HTTPException import subprocess import os import logging import threading # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = FastAPI() def run_setup_script(): """ Executes the run.sh script with root privileges. The script is expected to be at /opt/src/run.sh inside the container. """ script_path = "/opt/src/run.sh" logger.info(f"Attempting to execute setup script: {script_path}") # The container is running as root by default, so we don't need 'sudo'. # We execute the script directly. try: # Use subprocess.run to execute the script and wait for it to finish # We capture output for logging/debugging. result = subprocess.run( ["/bin/bash", script_path], check=True, # Raise an exception for non-zero exit codes stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True ) logger.info("Setup script executed successfully.") logger.info(f"Script output:\n{result.stdout}") except subprocess.CalledProcessError as e: logger.error(f"Setup script failed with exit code {e.returncode}.") logger.error(f"Script output:\n{e.stdout}") # Depending on the application's requirement, we might want to exit here # or just log the error and continue with the web server. # For a critical setup script like this VPN one, failure is critical. # We will log and let the main thread decide if it should exit. # For now, we just log the error. except FileNotFoundError: logger.error(f"Setup script not found at {script_path}") except Exception as e: logger.error(f"An unexpected error occurred during script execution: {e}") # Run the setup script in a separate thread or before the uvicorn server starts. # Since the setup script is likely long-running and critical, we'll run it # synchronously before starting the web server. If the web server is meant to # serve status while the script runs, we'd use a thread. Given the context # of a VPN setup, the setup must complete first. # We will use a simple function call before uvicorn.run. # For a production-ready FastAPI app, this logic should be in a startup event handler, # but for a simple script, running it before uvicorn.run is sufficient. if __name__ == "__main__": # 1. Run the setup script run_setup_script() # 2. Start the web server import uvicorn logger.info("Starting Uvicorn server...") uvicorn.run(app, host="0.0.0.0", port=8000)