diff --git a/app/main.py b/app/main.py index b11e5f3..91a220a 100644 --- a/app/main.py +++ b/app/main.py @@ -121,11 +121,15 @@ app.include_router( prefix='/v3/crud', tags=['CRUD v3'], ) -# app.include_router( -# agent_bridge.router, -# prefix='/agent', -# tags=['Agent Bridge'], -# ) + +# Deferred import to avoid circular dependencies and ensure environment is ready +from app.routers import agent_bridge +app.include_router( + agent_bridge.router, + prefix='/agent', + tags=['Agent Bridge'], +) + app.include_router( api.router, prefix='/api', diff --git a/app/routers/agent_bridge.py b/app/routers/agent_bridge.py index 5dd37a8..2f9ed89 100644 --- a/app/routers/agent_bridge.py +++ b/app/routers/agent_bridge.py @@ -2,7 +2,6 @@ from fastapi import APIRouter, Depends, HTTPException, Query import os import platform import json -import psutil import shutil from typing import Dict, Any, List, Optional from datetime import datetime @@ -31,6 +30,13 @@ async def get_container_status( if not is_admin(account): raise HTTPException(status_code=403, detail="Administrative access required.") + boot_time = None + try: + import psutil + boot_time = datetime.fromtimestamp(psutil.boot_time()).isoformat() + except Exception as e: + boot_time = f"Error: {str(e)}" + status_data = { "os": platform.system(), "release": platform.release(), @@ -40,7 +46,7 @@ async def get_container_status( "environment_vars": {k: v for k, v in os.environ.items() if not any(s in k.upper() for s in ["PASSWORD", "KEY", "SECRET", "AUTH", "TOKEN"])}, "cwd": os.getcwd(), "container": os.path.exists('/.dockerenv'), - "boot_time": datetime.fromtimestamp(psutil.boot_time()).isoformat() + "boot_time": boot_time } return mk_resp(data=status_data) @@ -56,34 +62,49 @@ async def get_system_usage( if not is_admin(account): raise HTTPException(status_code=403, detail="Administrative access required.") - # CPU usage per core - cpu_percent = psutil.cpu_percent(interval=0.1, percpu=True) - - # Memory usage - mem = psutil.virtual_memory() - - # Disk usage (root) - disk = shutil.disk_usage("/") - - usage_data = { - "cpu": { + cpu_data = {"error": "psutil not available"} + mem_data = {"error": "psutil not available"} + + try: + import psutil + # CPU usage per core + cpu_percent = psutil.cpu_percent(interval=0.1, percpu=True) + cpu_data = { "percent_avg": sum(cpu_percent) / len(cpu_percent) if cpu_percent else 0, "percent_per_core": cpu_percent, "count": psutil.cpu_count(), "load_avg": os.getloadavg() if hasattr(os, 'getloadavg') else None - }, - "memory": { + } + + # Memory usage + mem = psutil.virtual_memory() + mem_data = { "total": mem.total, "available": mem.available, "percent": mem.percent, "used": mem.used - }, - "disk": { + } + except Exception as e: + cpu_data = {"error": str(e)} + mem_data = {"error": str(e)} + + # Disk usage (root) - uses shutil which is standard lib + disk_data = {} + try: + disk = shutil.disk_usage("/") + disk_data = { "total": disk.total, "used": disk.used, "free": disk.free, "percent": (disk.used / disk.total) * 100 if disk.total else 0 } + except Exception as e: + disk_data = {"error": str(e)} + + usage_data = { + "cpu": cpu_data, + "memory": mem_data, + "disk": disk_data } return mk_resp(data=usage_data) @@ -172,13 +193,17 @@ async def list_processes( raise HTTPException(status_code=403, detail="Administrative access required.") procs = [] - for proc in psutil.process_iter(['pid', 'name', 'username', 'cpu_percent', 'memory_info']): - try: - pinfo = proc.info - pinfo['memory_rss'] = pinfo['memory_info'].rss if pinfo.get('memory_info') else 0 - procs.append(pinfo) - except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): - pass + try: + import psutil + for proc in psutil.process_iter(['pid', 'name', 'username', 'cpu_percent', 'memory_info']): + try: + pinfo = proc.info + pinfo['memory_rss'] = pinfo['memory_info'].rss if pinfo.get('memory_info') else 0 + procs.append(pinfo) + except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): + pass + except Exception as e: + return mk_resp(data=[], status_message=f"Error listing processes: {str(e)}", status_code=500) if sort_by == "cpu": procs.sort(key=lambda x: x['cpu_percent'], reverse=True)