301 lines
8.5 KiB
Python

"""Pydantic schemas for Docker management."""
from datetime import datetime
from typing import Optional, List, Dict, Any, Literal
from pydantic import BaseModel, Field, ConfigDict
# === Container Schemas ===
class DockerContainerBase(BaseModel):
"""Base schema for Docker container."""
container_id: str = Field(..., description="Docker container ID")
name: str = Field(..., description="Container name")
image: Optional[str] = Field(None, description="Image name")
state: Literal["running", "exited", "paused", "created", "dead", "restarting", "removing", "unknown"] = Field(
"unknown", description="Container state"
)
status: Optional[str] = Field(None, description="Container status string")
health: Optional[Literal["healthy", "unhealthy", "starting", "none"]] = Field(
None, description="Health check status"
)
ports: Optional[Dict[str, Any]] = Field(None, description="Port mappings")
labels: Optional[Dict[str, str]] = Field(None, description="Container labels")
compose_project: Optional[str] = Field(None, description="Docker Compose project name")
class DockerContainerResponse(DockerContainerBase):
"""Response schema for Docker container."""
id: int
host_id: str
created_at: Optional[datetime] = None
last_update_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class DockerContainerListResponse(BaseModel):
"""Response for listing containers."""
containers: List[DockerContainerResponse]
total: int
running: int
stopped: int
# === Image Schemas ===
class DockerImageBase(BaseModel):
"""Base schema for Docker image."""
image_id: str = Field(..., description="Docker image ID")
repo_tags: Optional[List[str]] = Field(None, description="Repository tags")
size: Optional[int] = Field(None, description="Image size in bytes")
class DockerImageResponse(DockerImageBase):
"""Response schema for Docker image."""
id: int
host_id: str
created: Optional[datetime] = None
last_update_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class DockerImageListResponse(BaseModel):
"""Response for listing images."""
images: List[DockerImageResponse]
total: int
total_size: int
# === Volume Schemas ===
class DockerVolumeBase(BaseModel):
"""Base schema for Docker volume."""
name: str = Field(..., description="Volume name")
driver: Optional[str] = Field(None, description="Volume driver")
mountpoint: Optional[str] = Field(None, description="Mount point path")
scope: Optional[str] = Field(None, description="Volume scope")
class DockerVolumeResponse(DockerVolumeBase):
"""Response schema for Docker volume."""
id: int
host_id: str
last_update_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class DockerVolumeListResponse(BaseModel):
"""Response for listing volumes."""
volumes: List[DockerVolumeResponse]
total: int
# === Alert Schemas ===
class DockerAlertBase(BaseModel):
"""Base schema for Docker alert."""
container_name: str = Field(..., description="Container name")
severity: Literal["warning", "error", "critical"] = Field("warning", description="Alert severity")
message: Optional[str] = Field(None, description="Alert message")
class DockerAlertResponse(DockerAlertBase):
"""Response schema for Docker alert."""
id: int
host_id: str
state: Literal["open", "closed", "acknowledged"] = "open"
opened_at: datetime
closed_at: Optional[datetime] = None
acknowledged_at: Optional[datetime] = None
acknowledged_by: Optional[str] = None
last_notified_at: Optional[datetime] = None
host_name: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class DockerAlertListResponse(BaseModel):
"""Response for listing alerts."""
alerts: List[DockerAlertResponse]
total: int
open_count: int
acknowledged_count: int
class DockerAlertAcknowledgeRequest(BaseModel):
"""Request to acknowledge an alert."""
note: Optional[str] = Field(None, description="Optional note for acknowledgement")
# === Docker Host Schemas ===
class DockerHostInfo(BaseModel):
"""Docker information for a host."""
host_id: str
host_name: str
host_ip: str
docker_enabled: bool = False
docker_version: Optional[str] = None
docker_status: Optional[Literal["online", "offline", "error"]] = None
docker_last_collect_at: Optional[datetime] = None
containers_total: int = 0
containers_running: int = 0
images_total: int = 0
volumes_total: int = 0
open_alerts: int = 0
model_config = ConfigDict(from_attributes=True)
class DockerHostListResponse(BaseModel):
"""Response for listing Docker hosts."""
hosts: List[DockerHostInfo]
total: int
enabled: int
class EnableDockerRequest(BaseModel):
"""Request to enable Docker monitoring on a host."""
enabled: bool = Field(True, description="Enable or disable Docker monitoring")
# === Container Action Schemas ===
class ContainerActionResponse(BaseModel):
"""Response for container actions."""
success: bool
message: str
container_id: str
action: str
output: Optional[str] = None
error: Optional[str] = None
class ContainerLogsRequest(BaseModel):
"""Request for container logs."""
tail: int = Field(200, ge=1, le=5000, description="Number of lines to retrieve")
timestamps: bool = Field(False, description="Include timestamps")
since: Optional[str] = Field(None, description="Show logs since timestamp or relative time")
class ContainerLogsResponse(BaseModel):
"""Response for container logs."""
container_id: str
container_name: str
logs: str
lines: int
class ContainerInspectResponse(BaseModel):
"""Response for container inspect."""
container_id: str
container_name: str
inspect_data: Dict[str, Any]
# === Collection Schemas ===
class DockerCollectRequest(BaseModel):
"""Request to trigger Docker collection."""
force: bool = Field(False, description="Force collection even if recently collected")
class DockerCollectResponse(BaseModel):
"""Response for Docker collection."""
success: bool
host_id: str
host_name: str
message: str
docker_version: Optional[str] = None
containers_count: int = 0
images_count: int = 0
volumes_count: int = 0
duration_ms: int = 0
error: Optional[str] = None
class DockerCollectAllResponse(BaseModel):
"""Response for collecting all Docker hosts."""
success: bool
message: str
total_hosts: int
successful: int
failed: int
results: List[DockerCollectResponse]
# === Stats Schemas ===
class DockerStatsResponse(BaseModel):
"""Global Docker statistics."""
total_hosts: int
enabled_hosts: int
online_hosts: int
total_containers: int
running_containers: int
total_images: int
total_volumes: int
open_alerts: int
last_collection: Optional[datetime] = None
# === Image Action Schemas ===
class ImageActionResponse(BaseModel):
"""Response for image actions."""
success: bool
message: str
image_id: str
action: str
output: Optional[str] = None
error: Optional[str] = None
# === Extended Image Response with usage info ===
class DockerImageExtendedResponse(DockerImageBase):
"""Response schema for Docker image with usage info."""
id: int
host_id: str
created: Optional[datetime] = None
last_update_at: Optional[datetime] = None
in_use: bool = Field(True, description="Whether the image is used by at least one container")
model_config = ConfigDict(from_attributes=True)
class DockerImageExtendedListResponse(BaseModel):
"""Response for listing images with usage info."""
images: List[DockerImageExtendedResponse]
total: int
total_size: int
unused_count: int = 0
# === Aggregated Containers Response ===
class DockerContainerAggregatedResponse(DockerContainerBase):
"""Response schema for Docker container with host info (for aggregated view)."""
id: int
host_id: str
host_name: str
host_ip: str
created_at: Optional[datetime] = None
last_update_at: Optional[datetime] = None
model_config = ConfigDict(from_attributes=True)
class DockerContainerAggregatedListResponse(BaseModel):
"""Response for listing all containers across all hosts."""
containers: List[DockerContainerAggregatedResponse]
total: int
running: int
stopped: int
paused: int
hosts_count: int
last_update: Optional[datetime] = None