from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Query from sqlmodel import Session from ..connectors.portainer import PortainerConnector from ..core.redaction import redact_message from ..db.session import get_session from ..services.setup_service import apply_stored_connector_settings router = APIRouter(prefix='/api/containers') def _raise_connector_error(response: dict): status = str(response.get('status', 'error')) reason = redact_message(str(response.get('reason', 'connection_failed'))) status_code = 503 if status == 'missing_config' else 502 raise HTTPException( status_code=status_code, detail={ 'status': status, 'reason': reason, 'connector': 'portainer', }, ) @router.get('') def list_containers( include_stats: bool = Query(False), stats_limit: int = Query(200, ge=1, le=500), session: Session = Depends(get_session), ): apply_stored_connector_settings(session) response = PortainerConnector().list_containers(include_stats=include_stats, stats_limit=stats_limit) if response.get('status') == 'ok': return response.get('containers', []) _raise_connector_error(response) @router.get('/{container_name}') def get_container(container_name: str, session: Session = Depends(get_session)): apply_stored_connector_settings(session) response = PortainerConnector().get_container_status(container_name) status = response.get('status') if status == 'ok': return response.get('container') if status == 'not_found': return None _raise_connector_error(response) @router.get('/{container_name}/logs') def get_container_logs(container_name: str, session: Session = Depends(get_session)): apply_stored_connector_settings(session) response = PortainerConnector().get_container_logs(container_name) return { 'container': response.get('container', container_name), 'status': response.get('status', 'unknown'), 'reason': redact_message(str(response.get('reason', ''))) if response.get('reason') else None, 'logs': [ redact_message(str(line)) for line in response.get('logs', []) ], }