Веб-UI FastAPI, REST API v1, интерактивный setup без env.example

- Дашборд (Jinja2 + static), управление кластерами kind, задания и kubeconfig.
- API: health, stats, clusters CRUD, versions, jobs; документация app/docs/api_routes.md.
- Docker Compose: том app, uvicorn reload, KIND_K8S_PATCH_KUBECONFIG по умолчанию 1.
- setup_env_interactive.py: список переменных в скрипте, удалён env.example.
- Makefile: явный префикс docker/podman; прочие правки CLI и ядра кластеров.
This commit is contained in:
Sergey Antropoff
2026-04-04 05:39:53 +03:00
parent ae961ef5fe
commit e46a62cfdb
31 changed files with 2507 additions and 393 deletions
+52
View File
@@ -303,6 +303,37 @@ def read_meta_json(cluster_name: str) -> dict[str, object] | None:
return None
def _container_cli_bin() -> str:
"""Имя CLI к сокету (docker / podman), как в kubeconfig_patch."""
return (os.environ.get("CONTAINER_CLI") or "docker").strip() or "docker"
def container_engine_ping(*, timeout_sec: float = 12.0) -> tuple[bool, str, str]:
"""
Проверить доступ к движку контейнеров (``docker info`` / ``podman info``).
Возвращает (успех, краткое сообщение или stderr, имя CLI).
"""
cli = _container_cli_bin()
if not shutil.which(cli):
return False, f"«{cli}» не найден в PATH", cli
try:
p = subprocess.run(
[cli, "info"],
capture_output=True,
text=True,
timeout=timeout_sec,
)
except subprocess.TimeoutExpired:
logger.warning("%s info: таймаут %s с", cli, timeout_sec)
return False, f"таймаут {timeout_sec} с", cli
if p.returncode == 0:
return True, "OK", cli
err = (p.stderr or p.stdout or "").strip() or f"код {p.returncode}"
logger.info("%s info неуспешно: %s", cli, err[:200])
return False, err[:800], cli
def kubectl_nodes_wide(*, kubeconfig: str | Path) -> tuple[int, str]:
"""``kubectl get nodes -o wide``; возвращает (код, объединённый вывод)."""
p = subprocess.run(
@@ -325,6 +356,27 @@ def kubectl_nodes_wide(*, kubeconfig: str | Path) -> tuple[int, str]:
return p.returncode, msg
def kubectl_pods_all_namespaces(*, kubeconfig: str | Path) -> tuple[int, str]:
"""``kubectl get pods -A``; сводка подов по кластеру."""
p = subprocess.run(
[
"kubectl",
"--kubeconfig",
str(kubeconfig),
"get",
"pods",
"-A",
"--request-timeout=20s",
],
capture_output=True,
text=True,
)
out = (p.stdout or "").strip()
err = (p.stderr or "").strip()
msg = out if out else err
return p.returncode, msg
def cluster_summary_for_api(name: str) -> dict[str, object]:
"""Сводка по кластеру для JSON API (без блокирующих долгих вызовов)."""
meta = read_meta_json(name) or {}