from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from typing import List from app.database import get_db, ProxmoxHost from app.models.schemas import ProxmoxHost as ProxmoxHostSchema, ProxmoxHostCreate, ProxmoxVM from app.services.proxmox_host_service import ProxmoxHostService from app.services.logging_service import LoggingService router = APIRouter() @router.get("/", response_model=List[ProxmoxHostSchema]) async def get_hosts(db: Session = Depends(get_db)): """Get all Proxmox hosts""" hosts = db.query(ProxmoxHost).all() return hosts @router.post("/", response_model=ProxmoxHostSchema) async def create_host(host: ProxmoxHostCreate, db: Session = Depends(get_db)): """Create a new Proxmox host""" try: # Test Proxmox connection before creating temp_host = ProxmoxHost(**host.dict()) host_service = ProxmoxHostService(temp_host) if not await host_service.test_proxmox_connection(): raise HTTPException(status_code=400, detail="Cannot connect to Proxmox host") # Create the host in database db_host = ProxmoxHost(**host.dict()) db.add(db_host) db.commit() db.refresh(db_host) # Log host creation LoggingService.log_host_action( db=db, action="create", host_id=db_host.id, host_name=db_host.name, success=True, message=f"Proxmox host '{db_host.name}' created successfully" ) return db_host except HTTPException: raise except Exception as e: raise HTTPException(status_code=500, detail=f"Error creating host: {str(e)}") @router.get("/{host_id}", response_model=ProxmoxHostSchema) async def get_host(host_id: int, db: Session = Depends(get_db)): """Get a specific Proxmox host""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") return host @router.put("/{host_id}", response_model=ProxmoxHostSchema) async def update_host(host_id: int, host_update: ProxmoxHostCreate, db: Session = Depends(get_db)): """Update a Proxmox host""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") # Test new connection if Proxmox settings changed temp_host = ProxmoxHost(**host_update.dict(), id=host_id) host_service = ProxmoxHostService(temp_host) if not await host_service.test_proxmox_connection(): raise HTTPException(status_code=400, detail="Cannot connect to Proxmox with new settings") old_name = host.name for key, value in host_update.dict().items(): setattr(host, key, value) db.commit() db.refresh(host) # Log host update LoggingService.log_host_action( db=db, action="update", host_id=host.id, host_name=host.name, success=True, message=f"Proxmox host '{old_name}' updated successfully" ) return host @router.delete("/{host_id}") async def delete_host(host_id: int, db: Session = Depends(get_db)): """Delete a Proxmox host""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") # Log host deletion before deleting LoggingService.log_host_action( db=db, action="delete", host_id=host.id, host_name=host.name, success=True, message=f"Proxmox host '{host.name}' deleted successfully" ) db.delete(host) db.commit() return {"message": "Host deleted successfully"} @router.post("/{host_id}/wake") async def wake_host(host_id: int, db: Session = Depends(get_db)): """Wake up a Proxmox host using Wake-on-LAN""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") host_service = ProxmoxHostService(host) success = await host_service.wake_host(db) if not success: raise HTTPException(status_code=500, detail="Failed to wake host") return {"message": f"WOL packet sent to {host.name}", "success": True} @router.post("/{host_id}/shutdown") async def shutdown_host(host_id: int, db: Session = Depends(get_db)): """Shutdown a Proxmox host (and all its VMs)""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") host_service = ProxmoxHostService(host) success = await host_service.shutdown_host(db) if not success: raise HTTPException(status_code=500, detail="Failed to shutdown host") return {"message": f"Shutdown initiated for {host.name}", "success": True} @router.get("/{host_id}/vms", response_model=List[ProxmoxVM]) async def get_host_vms(host_id: int, db: Session = Depends(get_db)): """Get all VMs/containers from a Proxmox host""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") try: host_service = ProxmoxHostService(host) vms = await host_service.get_vms() return vms except Exception as e: raise HTTPException(status_code=500, detail=f"Error getting VMs: {str(e)}") @router.post("/{host_id}/vms/{vmid}/start") async def start_vm(host_id: int, vmid: str, node: str, vm_type: str = "qemu", db: Session = Depends(get_db)): """Start a VM/container on a Proxmox host""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") host_service = ProxmoxHostService(host) success = await host_service.start_vm(node, vmid, vm_type) # Get VM name for logging try: vms = await host_service.get_vms() vm_name = next((vm.name for vm in vms if vm.vmid == vmid), f"VM-{vmid}") except: vm_name = f"VM-{vmid}" # Log VM start action LoggingService.log_proxmox_vm_action( db=db, action="start", vmid=vmid, vm_name=vm_name, node=node, success=success, message=f"VM {vm_name} ({'started' if success else 'failed to start'}) on node {node}" ) if not success: raise HTTPException(status_code=500, detail="Failed to start VM") return {"message": f"VM {vmid} start command sent", "success": True} @router.post("/{host_id}/vms/{vmid}/stop") async def stop_vm(host_id: int, vmid: str, node: str, vm_type: str = "qemu", db: Session = Depends(get_db)): """Stop a VM/container on a Proxmox host""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") host_service = ProxmoxHostService(host) success = await host_service.stop_vm(node, vmid, vm_type) # Get VM name for logging try: vms = await host_service.get_vms() vm_name = next((vm.name for vm in vms if vm.vmid == vmid), f"VM-{vmid}") except: vm_name = f"VM-{vmid}" # Log VM stop action LoggingService.log_proxmox_vm_action( db=db, action="stop", vmid=vmid, vm_name=vm_name, node=node, success=success, message=f"VM {vm_name} ({'stopped' if success else 'failed to stop'}) on node {node}" ) if not success: raise HTTPException(status_code=500, detail="Failed to stop VM") return {"message": f"VM {vmid} stop command sent", "success": True} @router.post("/check-status") async def check_all_hosts_status(db: Session = Depends(get_db)): """Check online status of all Proxmox hosts""" await ProxmoxHostService.check_all_hosts_status(db) return {"message": "Host status checked for all hosts"} @router.get("/{host_id}/status") async def check_host_status(host_id: int, db: Session = Depends(get_db)): """Check online status of a specific Proxmox host""" host = db.query(ProxmoxHost).filter(ProxmoxHost.id == host_id).first() if not host: raise HTTPException(status_code=404, detail="Host not found") is_online = await ProxmoxHostService.ping_host(host.ip_address) from datetime import datetime host.is_online = is_online host.last_ping = datetime.utcnow() db.commit() return { "host_id": host_id, "host_name": host.name, "is_online": is_online, "last_ping": host.last_ping }