Веб-UI: темы, навигация API, статистика и доработки API
- Шапка: логотип Kubernetes, ссылка на главную, выпадающее меню API (Swagger/ReDoc/Health), переключатель светлой/тёмной темы (localStorage). - Светлая тема в синей гамме; выравнивание кнопки темы в ряду с пилюлями. - Дашборд: единая карточка ошибки health/stats, подсказка Docker/Podman, поле container_cli в GET /stats, total_workers_from_meta всегда число (0 без meta). - Правки кластеров, job_store, compose, документация и частичные шаблоны.
This commit is contained in:
@@ -295,14 +295,49 @@ def _run_checked_stream(
|
||||
|
||||
def _docker_pull_plain_progress_enabled() -> bool:
|
||||
"""
|
||||
``docker pull --progress plain`` — построчный текст без TTY-ANSI; удобно с pipe (без PTY).
|
||||
Разрешить попытку ``docker pull --progress=plain`` (если CLI это поддерживает).
|
||||
|
||||
Отключить: ``KIND_K8S_DOCKER_PULL_PLAIN=0`` (если старая версия docker не знает флаг).
|
||||
Полностью отключить: ``KIND_K8S_DOCKER_PULL_PLAIN=0``.
|
||||
"""
|
||||
v = (os.environ.get("KIND_K8S_DOCKER_PULL_PLAIN") or "1").strip().lower()
|
||||
return v not in ("0", "false", "no", "off", "нет")
|
||||
|
||||
|
||||
# Кэш: есть ли в выводе ``docker pull --help`` опция ``--progress`` (в старых CLI её нет).
|
||||
_docker_pull_help_has_progress: bool | None = None
|
||||
|
||||
|
||||
def _docker_pull_cli_supports_progress_flag() -> bool:
|
||||
"""
|
||||
Узнать по справке, объявляет ли данный ``docker`` флаг ``--progress`` для ``pull``.
|
||||
|
||||
Без этого на старых клиентах в журнал попадало «unknown flag: --progress», а код выхода часто **1**,
|
||||
а не 125 — повтор без флага не срабатывал.
|
||||
"""
|
||||
global _docker_pull_help_has_progress
|
||||
if _docker_pull_help_has_progress is not None:
|
||||
return _docker_pull_help_has_progress
|
||||
exe = shutil.which("docker")
|
||||
if not exe:
|
||||
_docker_pull_help_has_progress = False
|
||||
return False
|
||||
try:
|
||||
p = subprocess.run(
|
||||
[exe, "pull", "--help"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=12,
|
||||
)
|
||||
blob = (p.stdout or "") + (p.stderr or "")
|
||||
_docker_pull_help_has_progress = "--progress" in blob
|
||||
if not _docker_pull_help_has_progress:
|
||||
logger.info("docker pull: в справке нет --progress — используем обычный pull (PTY по KIND_K8S_STREAM_PTY)")
|
||||
except (OSError, subprocess.TimeoutExpired) as e:
|
||||
logger.warning("Не удалось выполнить docker pull --help (%s), без флага --progress", e)
|
||||
_docker_pull_help_has_progress = False
|
||||
return _docker_pull_help_has_progress
|
||||
|
||||
|
||||
def _pull_node_image_streaming(*, image: str, on_line: Callable[[str], None], job_id: str | None) -> None:
|
||||
"""
|
||||
Скачать образ узлов через ``docker pull`` / ``podman pull`` с выводом в журнал задания.
|
||||
@@ -316,7 +351,12 @@ def _pull_node_image_streaming(*, image: str, on_line: Callable[[str], None], jo
|
||||
"Скачивание образа недоступно: не найдена программа для работы с контейнерами (docker/podman).",
|
||||
exit_code=127,
|
||||
)
|
||||
if cli == "docker" and _docker_pull_plain_progress_enabled():
|
||||
use_docker_plain = (
|
||||
cli == "docker"
|
||||
and _docker_pull_plain_progress_enabled()
|
||||
and _docker_pull_cli_supports_progress_flag()
|
||||
)
|
||||
if use_docker_plain:
|
||||
try:
|
||||
_run_checked_stream(
|
||||
[cli, "pull", "--progress=plain", image],
|
||||
@@ -326,16 +366,12 @@ def _pull_node_image_streaming(*, image: str, on_line: Callable[[str], None], jo
|
||||
)
|
||||
return
|
||||
except KindClusterError as e:
|
||||
# У docker CLI код 125 — «неверная команда/флаг»; тогда пробуем pull без plain.
|
||||
err_low = str(e).lower()
|
||||
if e.exit_code == 125 or any(
|
||||
x in err_low
|
||||
for x in ("progress", "unknown flag", "bad flag", "invalid option", "unknown shorthand")
|
||||
):
|
||||
logger.warning("Повтор docker pull без --progress=plain: %s", e)
|
||||
_run_checked_stream([cli, "pull", image], on_line=on_line, job_id=job_id, use_pty=None)
|
||||
return
|
||||
raise
|
||||
if e.exit_code == 130:
|
||||
raise
|
||||
# На всякий случай, если справка устарела или другой код ошибки.
|
||||
logger.warning("Повтор docker pull без --progress=plain (код %s): %s", e.exit_code, e)
|
||||
_run_checked_stream([cli, "pull", image], on_line=on_line, job_id=job_id, use_pty=None)
|
||||
return
|
||||
_run_checked_stream([cli, "pull", image], on_line=on_line, job_id=job_id, use_pty=None)
|
||||
|
||||
|
||||
@@ -800,6 +836,14 @@ def _container_cli_bin() -> str:
|
||||
return (os.environ.get("CONTAINER_CLI") or "docker").strip() or "docker"
|
||||
|
||||
|
||||
def configured_container_cli() -> str:
|
||||
"""Активное имя CLI из ``CONTAINER_CLI`` (docker/podman).
|
||||
|
||||
Единый источник для проверки движка, сбора ``docker stats``/``podman stats`` и поля ``container_cli`` в GET /stats.
|
||||
"""
|
||||
return _container_cli_bin()
|
||||
|
||||
|
||||
def container_engine_ping(*, timeout_sec: float = 12.0) -> tuple[bool, str, str]:
|
||||
"""
|
||||
Проверить доступ к движку контейнеров (``docker info`` / ``podman info``).
|
||||
|
||||
Reference in New Issue
Block a user