ipwatch
This commit is contained in:
227
backend/app/routers/tracking.py
Normal file
227
backend/app/routers/tracking.py
Normal file
@@ -0,0 +1,227 @@
|
||||
"""
|
||||
Endpoints API pour le suivi d'équipements (Wake-on-LAN, shutdown, etc.)
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
from backend.app.core.database import get_db
|
||||
from backend.app.models.ip import IP
|
||||
|
||||
router = APIRouter(prefix="/api/tracking", tags=["Tracking"])
|
||||
|
||||
|
||||
# Schémas Pydantic
|
||||
class IPTrackingResponse(BaseModel):
|
||||
"""Schéma de réponse pour les IPs suivies"""
|
||||
ip: str
|
||||
name: Optional[str]
|
||||
known: bool
|
||||
tracked: bool
|
||||
location: Optional[str]
|
||||
host: Optional[str]
|
||||
last_status: Optional[str]
|
||||
mac: Optional[str]
|
||||
vendor: Optional[str]
|
||||
hostname: Optional[str]
|
||||
link: Optional[str]
|
||||
last_seen: Optional[datetime]
|
||||
open_ports: List[int]
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class WOLResponse(BaseModel):
|
||||
"""Réponse après envoi Wake-on-LAN"""
|
||||
message: str
|
||||
ip: str
|
||||
mac: str
|
||||
success: bool
|
||||
|
||||
|
||||
class ShutdownResponse(BaseModel):
|
||||
"""Réponse après commande d'arrêt"""
|
||||
message: str
|
||||
ip: str
|
||||
success: bool
|
||||
|
||||
|
||||
@router.get("/", response_model=List[IPTrackingResponse])
|
||||
async def get_tracked_ips(db: Session = Depends(get_db)):
|
||||
"""
|
||||
Récupère toutes les IPs marquées comme suivies
|
||||
Retourne la liste des équipements avec leur état actuel
|
||||
"""
|
||||
tracked_ips = db.query(IP).filter(IP.tracked == True).order_by(IP.name, IP.ip).all()
|
||||
return tracked_ips
|
||||
|
||||
|
||||
@router.post("/wol/{ip_address}", response_model=WOLResponse)
|
||||
async def wake_on_lan(ip_address: str, db: Session = Depends(get_db)):
|
||||
"""
|
||||
Envoie un paquet Magic Packet Wake-on-LAN à l'équipement
|
||||
Nécessite que l'IP ait une adresse MAC enregistrée
|
||||
"""
|
||||
# Récupérer l'IP depuis la base
|
||||
ip_obj = db.query(IP).filter(IP.ip == ip_address).first()
|
||||
|
||||
if not ip_obj:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"IP {ip_address} non trouvée dans la base de données"
|
||||
)
|
||||
|
||||
if not ip_obj.mac:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Adresse MAC manquante pour {ip_address}. Impossible d'envoyer le paquet WOL."
|
||||
)
|
||||
|
||||
try:
|
||||
# Importer la bibliothèque wakeonlan
|
||||
from wakeonlan import send_magic_packet
|
||||
|
||||
# Envoyer le paquet Magic Packet
|
||||
send_magic_packet(ip_obj.mac)
|
||||
|
||||
return WOLResponse(
|
||||
message=f"Paquet Wake-on-LAN envoyé avec succès",
|
||||
ip=ip_address,
|
||||
mac=ip_obj.mac,
|
||||
success=True
|
||||
)
|
||||
|
||||
except ImportError:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="La bibliothèque 'wakeonlan' n'est pas installée. Exécutez: pip install wakeonlan"
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Erreur lors de l'envoi du paquet WOL: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.post("/shutdown/{ip_address}", response_model=ShutdownResponse)
|
||||
async def shutdown_device(ip_address: str, db: Session = Depends(get_db)):
|
||||
"""
|
||||
Envoie une commande shutdown via MQTT à l'équipement
|
||||
"""
|
||||
# Récupérer l'IP depuis la base
|
||||
ip_obj = db.query(IP).filter(IP.ip == ip_address).first()
|
||||
|
||||
if not ip_obj:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"IP {ip_address} non trouvée dans la base de données"
|
||||
)
|
||||
|
||||
if ip_obj.last_status != "online":
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"L'équipement {ip_address} est déjà hors ligne"
|
||||
)
|
||||
|
||||
try:
|
||||
from backend.app.services.mqtt_client import send_mqtt_command
|
||||
|
||||
# Envoyer commande shutdown via MQTT
|
||||
success = send_mqtt_command(ip_address, "shutdown")
|
||||
|
||||
if success:
|
||||
return ShutdownResponse(
|
||||
message=f"Commande shutdown envoyée à {ip_address} via MQTT",
|
||||
ip=ip_address,
|
||||
success=True
|
||||
)
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Échec de l'envoi de la commande MQTT"
|
||||
)
|
||||
|
||||
except ImportError:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Le service MQTT n'est pas configuré. Consultez mqtt/docs/README.md"
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Erreur lors de l'envoi de la commande: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.post("/reboot/{ip_address}", response_model=ShutdownResponse)
|
||||
async def reboot_device(ip_address: str, db: Session = Depends(get_db)):
|
||||
"""
|
||||
Envoie une commande reboot via MQTT à l'équipement
|
||||
"""
|
||||
# Récupérer l'IP depuis la base
|
||||
ip_obj = db.query(IP).filter(IP.ip == ip_address).first()
|
||||
|
||||
if not ip_obj:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"IP {ip_address} non trouvée"
|
||||
)
|
||||
|
||||
if ip_obj.last_status != "online":
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"L'équipement {ip_address} est hors ligne"
|
||||
)
|
||||
|
||||
try:
|
||||
from backend.app.services.mqtt_client import send_mqtt_command
|
||||
|
||||
# Envoyer commande reboot via MQTT
|
||||
success = send_mqtt_command(ip_address, "reboot")
|
||||
|
||||
if success:
|
||||
return ShutdownResponse(
|
||||
message=f"Commande reboot envoyée à {ip_address} via MQTT",
|
||||
ip=ip_address,
|
||||
success=True
|
||||
)
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Échec de l'envoi de la commande MQTT"
|
||||
)
|
||||
|
||||
except ImportError:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail="Le service MQTT n'est pas configuré"
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Erreur: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
@router.patch("/{ip_address}/toggle", response_model=IPTrackingResponse)
|
||||
async def toggle_tracking(ip_address: str, db: Session = Depends(get_db)):
|
||||
"""
|
||||
Bascule l'état de suivi d'une IP (tracked true/false)
|
||||
"""
|
||||
ip_obj = db.query(IP).filter(IP.ip == ip_address).first()
|
||||
|
||||
if not ip_obj:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"IP {ip_address} non trouvée"
|
||||
)
|
||||
|
||||
# Inverser l'état tracked
|
||||
ip_obj.tracked = not ip_obj.tracked
|
||||
db.commit()
|
||||
db.refresh(ip_obj)
|
||||
|
||||
return ip_obj
|
||||
Reference in New Issue
Block a user