Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion core/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,40 @@
from config import settings
from logger import logger
from version import __version__
from setting.core import ensure_openvpn_running
from service.background_tasks import start_background_tasks

api = FastAPI(title="OV Node",
version=__version__,
docs_url="/doc" if settings.doc else None)

api.include_router(core_router)

@api.on_event("startup")
async def startup_event():
"""Run initialization tasks on startup"""
logger.info("Running startup initialization...")

# Ensure OpenVPN service is running correctly
# This will automatically:
# - Fix any config issues (missing IPs, etc.)
# - Enable the service if needed
# - Start/restart the service
# - Verify it's running and listening on port
logger.info("Checking and ensuring OpenVPN service is running...")
openvpn_ok = ensure_openvpn_running()

if openvpn_ok:
logger.info("✓ OpenVPN service is healthy and running")
else:
logger.error("✗ Failed to ensure OpenVPN is running - check logs for details")

# Start background monitoring tasks
await start_background_tasks()

logger.info("Startup initialization completed")

if __name__ == "__main__":
logger.info("OV-Node is starting...")
uvicorn.run("app:api", host="0.0.0.0", port=settings.service_port, reload=True)
# Disable reload in production for stability
uvicorn.run("app:api", host="0.0.0.0", port=settings.service_port, reload=False)
205 changes: 205 additions & 0 deletions core/openvpn_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#!/usr/bin/env python3
"""
CLI tool for OpenVPN service management
Usage: python openvpn_cli.py [command]

Commands:
status - Show OpenVPN service status
health - Run health check
fix - Auto-detect and fix issues
restart - Restart OpenVPN service
logs - Show recent logs
"""

import sys
import os
import json
from pathlib import Path

# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))

from service.openvpn_monitor import openvpn_monitor
from logger import logger


def print_json(data):
"""Pretty print JSON data"""
print(json.dumps(data, indent=2))


def cmd_status():
"""Show OpenVPN service status"""
print("=" * 50)
print("OpenVPN Service Status")
print("=" * 50)

status = openvpn_monitor.check_service_status()
print(f"Running: {status['running']}")
print(f"Enabled: {status['enabled']}")
print(f"Active State: {status['active_state']}")

if status['error']:
print(f"Error: {status['error']}")

port, protocol = openvpn_monitor.get_config_port_protocol()
port_open = openvpn_monitor.check_port_listening(port, protocol)

print(f"\nPort: {port}")
print(f"Protocol: {protocol}")
print(f"Port Open: {port_open}")
print()


def cmd_health():
"""Run health check"""
print("=" * 50)
print("OpenVPN Health Check")
print("=" * 50)

health = openvpn_monitor.health_check()

print(f"Overall Health: {'✓ HEALTHY' if health['healthy'] else '✗ UNHEALTHY'}")
print()
print(f"Service Running: {'✓' if health['service_running'] else '✗'}")
print(f"Port Listening: {'✓' if health['port_listening'] else '✗'}")
print(f"Config Valid: {'✓' if health['config_valid'] else '✗'}")

if health['issues']:
print(f"\nIssues Found: {len(health['issues'])}")
for i, issue in enumerate(health['issues'], 1):
print(f" {i}. {issue}")
else:
print("\nNo issues found!")
print()


def cmd_fix():
"""Auto-detect and fix issues"""
print("=" * 50)
print("OpenVPN Auto-Fix")
print("=" * 50)

print("Detecting and fixing issues...\n")

result = openvpn_monitor.auto_fix_and_restart()

if result['errors_detected']:
print(f"Errors Detected: {len(result['errors_detected'])}")
for error in result['errors_detected']:
print(f" - {error['message']}")
print()

if result['fixes_applied']:
print(f"Fixes Applied: {len(result['fixes_applied'])}")
for fix in result['fixes_applied']:
print(f" - {fix}")
print()

print(f"Service Running: {'✓' if result['service_running'] else '✗'}")
print(f"Port Open: {'✓' if result['port_open'] else '✗'}")
print()

if result['success']:
print("✓ SUCCESS: OpenVPN is now running correctly!")
else:
print("✗ FAILED: OpenVPN still has issues")
print("Check logs for more details: journalctl -u openvpn-server@server -n 50")
print()


def cmd_restart():
"""Restart OpenVPN service"""
print("=" * 50)
print("Restart OpenVPN Service")
print("=" * 50)

print("Restarting service...")
success = openvpn_monitor.restart_service()

if success:
print("✓ Service restarted successfully!")

# Check status after restart
status = openvpn_monitor.check_service_status()
if status['running']:
print("✓ Service is running")
else:
print("✗ Service failed to start")
else:
print("✗ Failed to restart service")
print()


def cmd_logs():
"""Show recent logs"""
print("=" * 50)
print("OpenVPN Recent Logs (Last 30 lines)")
print("=" * 50)

logs = openvpn_monitor.get_service_logs(30)

for log in logs:
print(log)
print()


def cmd_errors():
"""Detect configuration errors"""
print("=" * 50)
print("OpenVPN Configuration Errors")
print("=" * 50)

errors = openvpn_monitor.detect_config_errors()

if errors:
print(f"Found {len(errors)} errors:\n")
for i, error in enumerate(errors, 1):
print(f"{i}. [{error['severity'].upper()}] {error['message']}")
print(f" Type: {error['type']}")
if 'log' in error:
print(f" Log: {error['log'][:100]}...")
print()
else:
print("No configuration errors detected!")
print()


def cmd_help():
"""Show help message"""
print(__doc__)


def main():
"""Main entry point"""
if len(sys.argv) < 2:
cmd_help()
return

command = sys.argv[1].lower()

commands = {
'status': cmd_status,
'health': cmd_health,
'fix': cmd_fix,
'restart': cmd_restart,
'logs': cmd_logs,
'errors': cmd_errors,
'help': cmd_help,
}

if command in commands:
try:
commands[command]()
except Exception as e:
print(f"Error: {e}")
logger.error(f"CLI error: {e}")
sys.exit(1)
else:
print(f"Unknown command: {command}")
print("Use 'help' to see available commands")
sys.exit(1)


if __name__ == "__main__":
main()
60 changes: 60 additions & 0 deletions core/routers/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
download_ovpn_file,
)
from setting.core import change_config
from service.openvpn_monitor import (
get_openvpn_health,
check_and_fix_openvpn_service,
openvpn_monitor
)


router = APIRouter(prefix="/sync", tags=["node_sync"])
Expand Down Expand Up @@ -71,3 +76,58 @@ async def download_ovpn(client_name: str, api_key: str = Depends(check_api_key))
)
else:
return ResponseModel(success=False, msg="OVPN file not found", data=None)


@router.get("/openvpn/health", response_model=ResponseModel)
async def openvpn_health(api_key: str = Depends(check_api_key)):
"""Get OpenVPN service health status"""
health = get_openvpn_health()
return ResponseModel(
success=health["healthy"],
msg="OpenVPN health check completed",
data=health
)


@router.post("/openvpn/fix", response_model=ResponseModel)
async def openvpn_fix(api_key: str = Depends(check_api_key)):
"""Automatically detect and fix OpenVPN service issues"""
result = check_and_fix_openvpn_service()
return ResponseModel(
success=result["success"],
msg="OpenVPN auto-fix completed",
data=result
)


@router.get("/openvpn/status", response_model=ResponseModel)
async def openvpn_status(api_key: str = Depends(check_api_key)):
"""Get detailed OpenVPN service status"""
status = openvpn_monitor.check_service_status()
port, protocol = openvpn_monitor.get_config_port_protocol()
port_open = openvpn_monitor.check_port_listening(port, protocol)

data = {
"service_status": status,
"port": port,
"protocol": protocol,
"port_open": port_open
}

return ResponseModel(
success=True,
msg="OpenVPN status retrieved",
data=data
)


@router.post("/openvpn/restart", response_model=ResponseModel)
async def openvpn_restart(api_key: str = Depends(check_api_key)):
"""Restart OpenVPN service"""
success = openvpn_monitor.restart_service()
return ResponseModel(
success=success,
msg="OpenVPN restart completed" if success else "Failed to restart OpenVPN",
data={"restarted": success}
)

51 changes: 51 additions & 0 deletions core/service/background_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Background tasks for monitoring and maintaining OpenVPN service
"""

import asyncio
from datetime import datetime
from logger import logger
from service.openvpn_monitor import openvpn_monitor


async def periodic_health_check():
"""
Periodically check OpenVPN service health and auto-fix if needed
Runs every 5 minutes
"""
while True:
try:
logger.info("Running periodic OpenVPN health check...")

# Check health
health = openvpn_monitor.health_check()

if not health["healthy"]:
logger.warning(f"OpenVPN is unhealthy: {health['issues']}")

# Attempt auto-fix
logger.info("Attempting auto-fix...")
fix_result = openvpn_monitor.auto_fix_and_restart()

if fix_result["success"]:
logger.info("Auto-fix successful, OpenVPN is now healthy")
else:
logger.error(f"Auto-fix failed: {fix_result}")
else:
logger.info("OpenVPN is healthy")

except Exception as e:
logger.error(f"Error in periodic health check: {e}")

# Wait 5 minutes before next check
await asyncio.sleep(300)


async def start_background_tasks():
"""Start all background monitoring tasks"""
logger.info("Starting background monitoring tasks...")

# Create task for periodic health check
asyncio.create_task(periodic_health_check())

logger.info("Background tasks started")
Loading