from __future__ import annotations from fastapi import APIRouter, Depends from sqlmodel import Session from ..connectors.unraid import UnraidConnector from ..db.session import get_session from ..services.unraid_vm_service import request_vm_action, vm_capabilities from .connector_runtime import load_connector_runtime router = APIRouter(prefix='/api/unraid', dependencies=[Depends(load_connector_runtime)]) def _default_summary(): return { 'arrayStatus': 'stopped', 'parityStatus': 'invalid', 'cacheUsage': 0, 'diskWarnings': 0, 'uptime': 'unknown', 'dockerService': False, 'cpuUsage': 0, 'ramUsage': 0, } @router.get('/summary') def summary(): connector = UnraidConnector() data = _default_summary() if not connector.is_configured(): return data server_info = connector.get_server_info() if server_info.get('status') == 'ok': info = server_info.get('info', {}) data['uptime'] = str(info.get('uptime', 'unknown')) metrics = connector.get_system_metrics() if metrics.get('status') in {'ok', 'partial'}: if isinstance(metrics.get('cpuUsage'), int | float): data['cpuUsage'] = int(metrics.get('cpuUsage', 0)) if isinstance(metrics.get('ramUsage'), int | float): data['ramUsage'] = int(metrics.get('ramUsage', 0)) array_status = connector.get_array_status() if array_status.get('status') == 'ok': data['arrayStatus'] = str(array_status.get('arrayStatus', 'stopped')) disk_summary = connector.get_disk_warnings() if disk_summary.get('status') == 'ok': data['diskWarnings'] = int(disk_summary.get('diskWarnings', 0)) cache_summary = connector.get_cache_status() if cache_summary.get('status') == 'ok': data['cacheUsage'] = int(cache_summary.get('cacheUsage', 0)) parity_summary = connector.get_parity_status() if parity_summary.get('status') == 'ok': data['parityStatus'] = str(parity_summary.get('parityStatus', 'invalid')) docker_summary = connector.get_docker_service_status() if docker_summary.get('status') == 'ok': data['dockerService'] = bool(docker_summary.get('running', False)) return data @router.get('/array') def array(): result = UnraidConnector().get_array_status() if result.get('status') == 'ok': return {'status': result.get('arrayStatus', 'stopped')} if result.get('status') == 'missing_config': return {'status': 'missing_config', 'reason': result.get('reason', 'missing_config')} return {'status': 'disconnected', 'reason': result.get('reason', 'connection_failed')} @router.get('/disks') def disks(): result = UnraidConnector().get_disk_warnings() if result.get('status') == 'ok': return {'disks': result.get('disks', []), 'diskWarnings': result.get('diskWarnings', 0)} if result.get('status') == 'missing_config': return {'disks': [], 'diskWarnings': 0, 'status': 'missing_config', 'reason': result.get('reason', 'missing_config')} return {'disks': [], 'diskWarnings': 0, 'status': 'disconnected', 'reason': result.get('reason', 'connection_failed')} @router.get('/cache') def cache(): result = UnraidConnector().get_cache_status() if result.get('status') == 'ok': return {'cacheUsage': result.get('cacheUsage', 0), 'pools': result.get('pools', [])} if result.get('status') == 'missing_config': return {'cacheUsage': 0, 'pools': [], 'status': 'missing_config', 'reason': result.get('reason', 'missing_config')} return {'cacheUsage': 0, 'pools': [], 'status': 'disconnected', 'reason': result.get('reason', 'connection_failed')} @router.get('/parity') def parity(): result = UnraidConnector().get_parity_status() if result.get('status') == 'ok': return { 'status': result.get('parityStatus', 'invalid'), 'checkStatus': result.get('checkStatus', 'idle'), 'running': bool(result.get('running', False)), 'paused': bool(result.get('paused', False)), 'correcting': bool(result.get('correcting', False)), 'progress': result.get('progress'), 'speed': result.get('speed'), 'errors': int(result.get('errors', 0)), } if result.get('status') == 'missing_config': return {'status': 'missing_config', 'reason': result.get('reason', 'missing_config')} return {'status': 'disconnected', 'reason': result.get('reason', 'connection_failed')} @router.get('/docker') def docker(): result = UnraidConnector().get_docker_service_status() if result.get('status') == 'ok': return { 'status': result.get('serviceStatus', 'stopped'), 'running': result.get('running', False), } if result.get('status') == 'missing_config': return {'status': 'missing_config', 'running': False, 'reason': result.get('reason', 'missing_config')} return {'status': 'disconnected', 'running': False, 'reason': result.get('reason', 'connection_failed')} @router.get('/vms') def vms(): result = UnraidConnector().get_vm_summary() if result.get('status') == 'ok': return {'vms': result.get('vms', [])} if result.get('status') == 'missing_config': return {'vms': [], 'status': 'missing_config', 'reason': result.get('reason', 'missing_config')} if result.get('status') in {'unavailable', 'api_unavailable'}: return {'vms': [], 'status': result.get('status'), 'reason': result.get('reason', 'VM API unavailable')} return {'vms': [], 'status': 'disconnected', 'reason': result.get('reason', 'connection_failed')} @router.get('/vms/capabilities') def vms_capabilities(session: Session = Depends(get_session)): return vm_capabilities(session) @router.post('/vms/{vm_id}/actions/{action}') def run_vm_action(vm_id: str, action: str, payload: dict, session: Session = Depends(get_session)): return request_vm_action( session, vm_id=vm_id, action=action, source=str(payload.get('source') or 'manual'), confirmed=payload.get('confirm') is True, ) @router.get('/shares') def shares(): result = UnraidConnector().get_share_summary() if result.get('status') == 'ok': return {'shares': result.get('shares', [])} if result.get('status') == 'missing_config': return {'shares': [], 'status': 'missing_config', 'reason': result.get('reason', 'missing_config')} return {'shares': [], 'status': 'disconnected', 'reason': result.get('reason', 'connection_failed')}