Files
zebra-power/backend/app/api/hosts.py

247 lines
8.7 KiB
Python

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
}