330 lines
11 KiB
Python
330 lines
11 KiB
Python
"""
|
|
Linux BenchTools - Devices API
|
|
"""
|
|
|
|
import json
|
|
from fastapi import APIRouter, Depends, HTTPException, status, Query, Response
|
|
from sqlalchemy.orm import Session
|
|
from typing import List
|
|
|
|
from app.db.session import get_db
|
|
from app.schemas.device import DeviceListResponse, DeviceDetail, DeviceSummary, DeviceUpdate
|
|
from app.schemas.benchmark import BenchmarkSummary
|
|
from app.schemas.hardware import HardwareSnapshotResponse
|
|
from app.schemas.document import DocumentResponse
|
|
from app.models.device import Device
|
|
from app.models.benchmark import Benchmark
|
|
from app.models.hardware_snapshot import HardwareSnapshot
|
|
from app.models.document import Document
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/devices", response_model=DeviceListResponse)
|
|
async def get_devices(
|
|
page: int = Query(1, ge=1),
|
|
page_size: int = Query(20, ge=1, le=100),
|
|
search: str = Query(None),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get paginated list of devices with their last benchmark
|
|
"""
|
|
query = db.query(Device)
|
|
|
|
# Apply search filter
|
|
if search:
|
|
search_filter = f"%{search}%"
|
|
query = query.filter(
|
|
(Device.hostname.like(search_filter)) |
|
|
(Device.description.like(search_filter)) |
|
|
(Device.tags.like(search_filter)) |
|
|
(Device.location.like(search_filter))
|
|
)
|
|
|
|
# Get total count
|
|
total = query.count()
|
|
|
|
# Apply pagination
|
|
offset = (page - 1) * page_size
|
|
devices = query.offset(offset).limit(page_size).all()
|
|
|
|
# Build response with last benchmark for each device
|
|
items = []
|
|
for device in devices:
|
|
# Get last benchmark
|
|
last_bench = db.query(Benchmark).filter(
|
|
Benchmark.device_id == device.id
|
|
).order_by(Benchmark.run_at.desc()).first()
|
|
|
|
last_bench_summary = None
|
|
if last_bench:
|
|
last_bench_summary = BenchmarkSummary(
|
|
id=last_bench.id,
|
|
run_at=last_bench.run_at.isoformat(),
|
|
global_score=last_bench.global_score,
|
|
cpu_score=last_bench.cpu_score,
|
|
memory_score=last_bench.memory_score,
|
|
disk_score=last_bench.disk_score,
|
|
network_score=last_bench.network_score,
|
|
gpu_score=last_bench.gpu_score,
|
|
bench_script_version=last_bench.bench_script_version,
|
|
notes=last_bench.notes
|
|
)
|
|
|
|
items.append(DeviceSummary(
|
|
id=device.id,
|
|
hostname=device.hostname,
|
|
fqdn=device.fqdn,
|
|
description=device.description,
|
|
asset_tag=device.asset_tag,
|
|
location=device.location,
|
|
owner=device.owner,
|
|
tags=device.tags,
|
|
purchase_store=device.purchase_store,
|
|
purchase_date=device.purchase_date,
|
|
purchase_price=device.purchase_price,
|
|
created_at=device.created_at.isoformat(),
|
|
updated_at=device.updated_at.isoformat(),
|
|
last_benchmark=last_bench_summary
|
|
))
|
|
|
|
return DeviceListResponse(
|
|
items=items,
|
|
total=total,
|
|
page=page,
|
|
page_size=page_size
|
|
)
|
|
|
|
|
|
@router.get("/devices/{device_id}", response_model=DeviceDetail)
|
|
async def get_device(
|
|
device_id: int,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get detailed information about a specific device
|
|
"""
|
|
device = db.query(Device).filter(Device.id == device_id).first()
|
|
|
|
if not device:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Device {device_id} not found"
|
|
)
|
|
|
|
# Get last benchmark
|
|
last_bench = db.query(Benchmark).filter(
|
|
Benchmark.device_id == device.id
|
|
).order_by(Benchmark.run_at.desc()).first()
|
|
|
|
last_bench_summary = None
|
|
if last_bench:
|
|
last_bench_summary = BenchmarkSummary(
|
|
id=last_bench.id,
|
|
run_at=last_bench.run_at.isoformat(),
|
|
global_score=last_bench.global_score,
|
|
cpu_score=last_bench.cpu_score,
|
|
memory_score=last_bench.memory_score,
|
|
disk_score=last_bench.disk_score,
|
|
network_score=last_bench.network_score,
|
|
gpu_score=last_bench.gpu_score,
|
|
bench_script_version=last_bench.bench_script_version,
|
|
notes=last_bench.notes
|
|
)
|
|
|
|
# Get last hardware snapshot
|
|
last_snapshot = db.query(HardwareSnapshot).filter(
|
|
HardwareSnapshot.device_id == device.id
|
|
).order_by(HardwareSnapshot.captured_at.desc()).first()
|
|
|
|
last_snapshot_data = None
|
|
if last_snapshot:
|
|
last_snapshot_data = HardwareSnapshotResponse(
|
|
id=last_snapshot.id,
|
|
device_id=last_snapshot.device_id,
|
|
captured_at=last_snapshot.captured_at.isoformat(),
|
|
cpu_vendor=last_snapshot.cpu_vendor,
|
|
cpu_model=last_snapshot.cpu_model,
|
|
cpu_cores=last_snapshot.cpu_cores,
|
|
cpu_threads=last_snapshot.cpu_threads,
|
|
cpu_base_freq_ghz=last_snapshot.cpu_base_freq_ghz,
|
|
cpu_max_freq_ghz=last_snapshot.cpu_max_freq_ghz,
|
|
ram_total_mb=last_snapshot.ram_total_mb,
|
|
ram_used_mb=last_snapshot.ram_used_mb,
|
|
ram_free_mb=last_snapshot.ram_free_mb,
|
|
ram_shared_mb=last_snapshot.ram_shared_mb,
|
|
ram_slots_total=last_snapshot.ram_slots_total,
|
|
ram_slots_used=last_snapshot.ram_slots_used,
|
|
gpu_summary=last_snapshot.gpu_summary,
|
|
gpu_model=last_snapshot.gpu_model,
|
|
storage_summary=last_snapshot.storage_summary,
|
|
storage_devices_json=last_snapshot.storage_devices_json,
|
|
partitions_json=last_snapshot.partitions_json,
|
|
network_interfaces_json=last_snapshot.network_interfaces_json,
|
|
network_shares_json=last_snapshot.network_shares_json,
|
|
os_name=last_snapshot.os_name,
|
|
os_version=last_snapshot.os_version,
|
|
kernel_version=last_snapshot.kernel_version,
|
|
architecture=last_snapshot.architecture,
|
|
virtualization_type=last_snapshot.virtualization_type,
|
|
screen_resolution=last_snapshot.screen_resolution,
|
|
display_server=last_snapshot.display_server,
|
|
session_type=last_snapshot.session_type,
|
|
last_boot_time=last_snapshot.last_boot_time,
|
|
uptime_seconds=last_snapshot.uptime_seconds,
|
|
battery_percentage=last_snapshot.battery_percentage,
|
|
battery_status=last_snapshot.battery_status,
|
|
battery_health=last_snapshot.battery_health,
|
|
hostname=last_snapshot.hostname,
|
|
desktop_environment=last_snapshot.desktop_environment,
|
|
motherboard_vendor=last_snapshot.motherboard_vendor,
|
|
motherboard_model=last_snapshot.motherboard_model,
|
|
bios_vendor=last_snapshot.bios_vendor,
|
|
bios_version=last_snapshot.bios_version,
|
|
bios_date=last_snapshot.bios_date,
|
|
pci_devices_json=last_snapshot.pci_devices_json,
|
|
usb_devices_json=last_snapshot.usb_devices_json
|
|
)
|
|
|
|
# Get documents for this device
|
|
documents = db.query(Document).filter(
|
|
Document.device_id == device.id
|
|
).all()
|
|
|
|
documents_list = [
|
|
DocumentResponse(
|
|
id=doc.id,
|
|
device_id=doc.device_id,
|
|
doc_type=doc.doc_type,
|
|
filename=doc.filename,
|
|
mime_type=doc.mime_type,
|
|
size_bytes=doc.size_bytes,
|
|
uploaded_at=doc.uploaded_at.isoformat()
|
|
)
|
|
for doc in documents
|
|
]
|
|
|
|
return DeviceDetail(
|
|
id=device.id,
|
|
hostname=device.hostname,
|
|
fqdn=device.fqdn,
|
|
description=device.description,
|
|
asset_tag=device.asset_tag,
|
|
location=device.location,
|
|
owner=device.owner,
|
|
tags=device.tags,
|
|
purchase_store=device.purchase_store,
|
|
purchase_date=device.purchase_date,
|
|
purchase_price=device.purchase_price,
|
|
created_at=device.created_at.isoformat(),
|
|
updated_at=device.updated_at.isoformat(),
|
|
last_benchmark=last_bench_summary,
|
|
last_hardware_snapshot=last_snapshot_data,
|
|
documents=documents_list
|
|
)
|
|
|
|
|
|
@router.get("/devices/{device_id}/benchmarks")
|
|
async def get_device_benchmarks(
|
|
device_id: int,
|
|
limit: int = Query(20, ge=1, le=100),
|
|
offset: int = Query(0, ge=0),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get benchmark history for a device
|
|
"""
|
|
device = db.query(Device).filter(Device.id == device_id).first()
|
|
|
|
if not device:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Device {device_id} not found"
|
|
)
|
|
|
|
# Get benchmarks
|
|
benchmarks = db.query(Benchmark).filter(
|
|
Benchmark.device_id == device_id
|
|
).order_by(Benchmark.run_at.desc()).offset(offset).limit(limit).all()
|
|
|
|
total = db.query(Benchmark).filter(Benchmark.device_id == device_id).count()
|
|
|
|
items = [
|
|
BenchmarkSummary(
|
|
id=b.id,
|
|
run_at=b.run_at.isoformat(),
|
|
global_score=b.global_score,
|
|
cpu_score=b.cpu_score,
|
|
memory_score=b.memory_score,
|
|
disk_score=b.disk_score,
|
|
network_score=b.network_score,
|
|
gpu_score=b.gpu_score,
|
|
bench_script_version=b.bench_script_version,
|
|
notes=b.notes
|
|
)
|
|
for b in benchmarks
|
|
]
|
|
|
|
return {
|
|
"items": items,
|
|
"total": total,
|
|
"limit": limit,
|
|
"offset": offset
|
|
}
|
|
|
|
|
|
@router.put("/devices/{device_id}", response_model=DeviceDetail)
|
|
async def update_device(
|
|
device_id: int,
|
|
update_data: DeviceUpdate,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Update device information
|
|
"""
|
|
device = db.query(Device).filter(Device.id == device_id).first()
|
|
|
|
if not device:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Device {device_id} not found"
|
|
)
|
|
|
|
# Update only provided fields
|
|
update_dict = update_data.dict(exclude_unset=True)
|
|
for key, value in update_dict.items():
|
|
setattr(device, key, value)
|
|
|
|
# Update timestamp
|
|
from datetime import datetime
|
|
device.updated_at = datetime.utcnow()
|
|
|
|
db.commit()
|
|
db.refresh(device)
|
|
|
|
# Return updated device (reuse get_device logic)
|
|
return await get_device(device_id, db)
|
|
|
|
|
|
@router.delete("/devices/{device_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
async def delete_device(
|
|
device_id: int,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Delete a device and all related data
|
|
"""
|
|
device = db.query(Device).filter(Device.id == device_id).first()
|
|
|
|
if not device:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Device {device_id} not found"
|
|
)
|
|
|
|
db.delete(device)
|
|
db.commit()
|
|
|
|
return Response(status_code=status.HTTP_204_NO_CONTENT)
|