"""Модели запросов/ответов REST API веб-интерфейса. Автор: Сергей Антропов Сайт: https://devops.org.ru """ from __future__ import annotations from typing import Any, Literal from pydantic import BaseModel, Field class ClusterCreateRequest(BaseModel): """Тело POST /api/v1/clusters — создание кластера.""" name: str = Field(..., min_length=1, max_length=63, description="DNS-имя кластера (a-z0-9-)") kubernetes_version: str = Field( ..., min_length=1, description="Версия Kubernetes / тег kindest/node, например 1.29.4 или v1.29.4", ) workers: int = Field(2, ge=0, le=20, description="Число worker-нод (0–20)") class ClusterCreateAccepted(BaseModel): """Ответ 202 — задание поставлено в очередь.""" job_id: str status: Literal["queued"] = "queued" message: str = "Создание кластера выполняется в фоне; опросите GET /api/v1/jobs/{job_id}" class JobView(BaseModel): """Статус фонового задания.""" job_id: str kind: str status: Literal["queued", "running", "success", "failed", "cancelled"] cluster_name: str | None created_at_utc: str message: str | None = None result: dict[str, Any] | None = None progress_stage: str | None = Field(default=None, description="Текущий этап создания (пока задание активно)") progress_percent: int | None = Field(default=None, description="Прогресс 0–100 для индикатора в UI") class ClusterSummary(BaseModel): """Элемент списка кластеров.""" name: str registered_in_kind: bool has_local_kubeconfig: bool meta: dict[str, Any] = Field(default_factory=dict) class StatsResponse(BaseModel): """Краткая статистика для дашборда.""" kind_clusters_count: int local_cluster_dirs_count: int total_workers_from_meta: int | None jobs_total: int jobs_recent_failed: int class ClusterWorkloadsResponse(BaseModel): """Вывод kubectl по кластеру (узлы и поды).""" cluster_name: str nodes_rc: int | None = None nodes_output: str | None = None pods_rc: int | None = None pods_output: str | None = None error: str | None = None