Files
KindClustersDashboard/app/models/schemas.py
T
inecs 9363d4e076 UI: навигация, документация, favicon; журнал развёртывания; валидация формы
- Меню API: ссылка «Теги образов», обёртка прокрутки пилюль, z-index и padding против обрезки hover
- Документация: ширина колонки как у дашборда (72rem)
- Favicon SVG + GET /favicon.ico, link в base.html
- provision_log.json, GET .../provision-log, кнопка в таблице кластеров
- Валидация create: имя, workers, тег kindest; модалка alert
- Прочие правки из сессии (clusters, job_store, стили, шаблоны)
2026-04-04 08:15:15 +03:00

143 lines
6.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Модели запросов/ответов 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="Тег kindest/node: latest, 1.29.4, v1.29.4 и т.д.",
)
workers: int = Field(2, ge=0, le=20, description="Число worker-нод (020)")
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")
progress_log: list[str] = Field(
default_factory=list,
description="Хвост журнала (скачивание образа, длительные команды, этапы); при опросе GET /jobs/{id}",
)
class ClusterSummary(BaseModel):
"""Элемент списка кластеров."""
name: str
registered_in_kind: bool
kind_nodes_running: bool = Field(
default=False,
description="Запущены контейнеры узлов kind (имя-control-plane, имя-worker…; docker/podman ps)",
)
has_local_kubeconfig: bool
has_provision_log: bool = Field(
default=False,
description="Есть сохранённый полный журнал развёртывания (provision_log.json)",
)
meta: dict[str, Any] = Field(default_factory=dict)
class KindNodeResourceStat(BaseModel):
"""Одна нода kind (контейнер): снимок ``docker stats`` / ``podman stats``."""
container_name: str
cpu_percent: str | None = Field(default=None, description="Доля CPU, напр. 1.23%")
memory_usage: str | None = Field(default=None, description="Использование / лимит, напр. 120MiB / 7.7GiB")
memory_percent: str | None = Field(default=None, description="Процент памяти от лимита контейнера")
net_io: str | None = Field(default=None, description="Сетевой I/O (накопительно за жизнь контейнера)")
block_io: str | None = Field(default=None, description="Блочный I/O")
pids: int | None = Field(default=None, description="Число процессов в контейнере")
class KindClusterResources(BaseModel):
"""Ресурсы узлов одного кластера kind (только запущенные контейнеры)."""
cluster_name: str
nodes: list[KindNodeResourceStat] = Field(default_factory=list)
note: str | None = Field(default=None, description="Пояснение, если узлов нет или ошибка списка")
class AggregateResourcesSummary(BaseModel):
"""Сводка по всем запущенным узлам kind для донат-диаграмм на главной."""
nodes_count: int = Field(0, description="Число учтённых контейнеров-нод")
cpu_ring: float = Field(0, ge=0, le=100, description="Заполнение кольца «средний CPU», 0–100")
cpu_label: str = Field("", description="Подпись в центре доната")
memory_percent_ring: float = Field(0, ge=0, le=100)
memory_percent_label: str = Field("")
memory_used_ratio_ring: float = Field(0, ge=0, le=100, description="Доля занятой RAM от лимита по строке MemUsage")
memory_used_ratio_label: str = Field("")
network_ring: float = Field(0, ge=0, le=100, description="Индикатор суммарного сетевого I/O (условная шкала)")
network_label: str = Field("")
disk_ring: float = Field(0, ge=0, le=100, description="Индикатор суммарного блочного I/O")
disk_label: str = Field("")
class StatsResponse(BaseModel):
"""Краткая статистика для дашборда."""
container_cli: str = Field(
description="CLI движка контейнеров (docker или podman): узлы kind и метрики собираются через него",
)
kind_clusters_count: int
local_cluster_dirs_count: int
total_workers_from_meta: int = Field(
0,
ge=0,
description="Сумма worker_nodes по meta.json каталогов; 0 если ни в одном meta нет поля или данных",
)
jobs_total: int
jobs_recent_failed: int
cluster_resources: list[KindClusterResources] = Field(
default_factory=list,
description="CPU/RAM/I/O узлов kind по данным container CLI",
)
cluster_resources_error: str | None = Field(
default=None,
description="Глобальная ошибка сбора метрик (например CLI не найден)",
)
aggregate_cluster_resources: AggregateResourcesSummary = Field(
default_factory=AggregateResourcesSummary,
description="Агрегаты по узлам для донатов на главной странице",
)
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