118 lines
3.7 KiB
Python

"""
Schémas Pydantic pour les tâches - modèles API.
"""
from datetime import datetime, timezone
from typing import Optional, List, Literal, Dict, Any
from pydantic import BaseModel, Field, ConfigDict, field_validator
class Task(BaseModel):
"""Modèle complet d'une tâche pour l'API."""
id: str
name: str
host: str
status: Literal["pending", "running", "completed", "failed", "cancelled"] = "pending"
progress: int = Field(ge=0, le=100, default=0)
start_time: Optional[datetime] = None
end_time: Optional[datetime] = None
duration: Optional[str] = None
output: Optional[str] = None
error: Optional[str] = None
model_config = ConfigDict(
json_encoders={datetime: lambda v: v.isoformat() if v else None}
)
class TaskRequest(BaseModel):
"""Requête de création d'une tâche."""
host: Optional[str] = Field(default=None, description="Hôte cible")
group: Optional[str] = Field(default=None, description="Groupe cible")
action: str = Field(..., description="Action à exécuter")
cmd: Optional[str] = Field(default=None, description="Commande personnalisée")
extra_vars: Optional[Dict[str, Any]] = Field(default=None, description="Variables Ansible")
tags: Optional[List[str]] = Field(default=None, description="Tags Ansible")
dry_run: bool = Field(default=False, description="Mode simulation")
ssh_user: Optional[str] = Field(default=None, description="Utilisateur SSH")
ssh_password: Optional[str] = Field(default=None, description="Mot de passe SSH")
@field_validator('action')
@classmethod
def validate_action(cls, v: str) -> str:
valid_actions = ['upgrade', 'reboot', 'health-check', 'backup', 'deploy', 'rollback', 'maintenance', 'bootstrap']
if v not in valid_actions:
raise ValueError(f'Action doit être l\'une de: {", ".join(valid_actions)}')
return v
class TaskLogFile(BaseModel):
"""Représentation d'un fichier de log de tâche."""
id: str
filename: str
path: str
task_name: str
target: str
status: str
date: str # Format YYYY-MM-DD
year: str
month: str
day: str
created_at: datetime
size_bytes: int
start_time: Optional[str] = None
end_time: Optional[str] = None
duration: Optional[str] = None
duration_seconds: Optional[int] = None
hosts: List[str] = Field(default_factory=list)
category: Optional[str] = None
subcategory: Optional[str] = None
target_type: Optional[str] = None
source_type: Optional[str] = None
class TasksFilterParams(BaseModel):
"""Paramètres de filtrage des tâches."""
status: Optional[str] = None
year: Optional[str] = None
month: Optional[str] = None
day: Optional[str] = None
hour_start: Optional[str] = None
hour_end: Optional[str] = None
target: Optional[str] = None
source_type: Optional[str] = None
search: Optional[str] = None
limit: int = 50
offset: int = 0
class TaskLogsResponse(BaseModel):
"""Réponse API pour les logs de tâches."""
logs: List[dict] = Field(default_factory=list)
count: int = 0
total_count: int = 0
has_more: bool = False
filters: Dict[str, Optional[str]] = Field(default_factory=dict)
pagination: Dict[str, int] = Field(default_factory=dict)
class TaskLogDatesResponse(BaseModel):
"""Structure des dates disponibles pour le filtrage."""
years: Dict[str, Any] = Field(default_factory=dict)
class TaskStatsResponse(BaseModel):
"""Statistiques des tâches."""
total: int = 0
completed: int = 0
failed: int = 0
running: int = 0
pending: int = 0
class RunningTasksResponse(BaseModel):
"""Réponse API pour les tâches en cours."""
tasks: List[dict] = Field(default_factory=list)
count: int = 0