Веб-UI: логи kind create, старт/стоп кластеров, документация README
- Потоковые логи в job_store и UI; kind create через Popen с построчным выводом
- POST /clusters/{name}/start|stop; create по сохранённому kind-config.yaml
- Страница /documentation: GET /api/v1/docs/readme, marked+DOMPurify из static/vendor
- Иконки действий, плавающие подсказки, модалка подтверждения вместо confirm
- Makefile: make docker|podman rebuild; compose: монтирование README.md
- Dockerfile: COPY README.md; readme_doc: несколько путей к README
Автор: Сергей Антропов — https://devops.org.ru
This commit is contained in:
+80
-4
@@ -10,19 +10,21 @@
|
||||
| Swagger UI (OpenAPI) | `http://127.0.0.1:<порт>/docs` (порт на хосте по умолчанию **8080**, см. `KIND_K8S_WEB_PORT`; 6000 на хосте блокируется Chrome) |
|
||||
| ReDoc | `http://127.0.0.1:<порт>/redoc` |
|
||||
| Health (JSON) | `http://127.0.0.1:<порт>/api/v1/health` |
|
||||
| Документация проекта | `http://127.0.0.1:<порт>/documentation` — **README.md**: текст с `GET /api/v1/docs/readme`, рендер **Markdown** в браузере (**marked** + **DOMPurify** из `app/static/js/vendor/`, без CDN) |
|
||||
| Этот файл | `app/docs/api_routes.md` в репозитории |
|
||||
|
||||
С **веб-панели** (`GET /`) пункты меню **Swagger**, **ReDoc** и **Health** вызывают `window.open` с именами окон `kind_swagger`, `kind_redoc`, `kind_health` (отдельное окно, повторный клик переиспользует то же окно).
|
||||
С **веб-панели** (`GET /`) пункты меню **Swagger**, **ReDoc** и **Health** вызывают `window.open` с именами окон `kind_swagger`, `kind_redoc`, `kind_health` (отдельное окно, повторный клик переиспользует то же окно). Пункт **Документация** открывает `GET /documentation` в той же вкладке.
|
||||
|
||||
## Веб-интерфейс и статика (не JSON)
|
||||
|
||||
| Маршрут | Описание |
|
||||
|---------|----------|
|
||||
| `GET /` | HTML-панель: единая карточка «панель + среда», статистика, создание кластера (прогресс, отмена), таблицы (автообновление ~3,5 с), модалка узлов/подов; в шапке — меню-пилюли и отдельные окна для Swagger / ReDoc / Health. |
|
||||
| `GET /` | HTML-панель: единая карточка «панель + среда», статистика, создание кластера (прогресс, **журнал** `kind create`, отмена), таблица кластеров с **иконками** действий и **всплывающими подсказками**, модалка узлов/подов; шапка — пилюли, Swagger / ReDoc / Health в отдельных окнах. |
|
||||
| `GET /documentation` | HTML-оболочка; контент — запрос к **`GET /api/v1/docs/readme`** и разбор Markdown скриптами из **`/static/js/vendor/`** (marked, DOMPurify). Путь к README: `KIND_K8S_README_PATH` или `README.md` рядом с `app/`; в образе — `/opt/kind-k8s/README.md`. |
|
||||
| `GET /ui` | Редирект **307** на `/` (удобный ярлык). |
|
||||
| `GET /static/…` | CSS (`style.css`), скрипт панели (`js/dashboard.js`); базовый URL API задаётся атрибутом `data-api-base` на `<body>` (по умолчанию `/api/v1`). |
|
||||
|
||||
Шаблоны: `app/templates/base.html` (шапка, навигация), `app/templates/dashboard.html` (контент панели).
|
||||
Шаблоны: `app/templates/base.html` (шапка, навигация), `app/templates/dashboard.html` (контент панели), `app/templates/documentation.html` (README).
|
||||
|
||||
---
|
||||
|
||||
@@ -31,10 +33,13 @@
|
||||
| Метод | Путь | Кратко |
|
||||
|-------|------|--------|
|
||||
| GET | `/api/v1/health` | Среда: kind, kubectl, движок контейнеров |
|
||||
| GET | `/api/v1/docs/readme` | Текст **README.md** (`text/markdown`; для страницы `/documentation`) |
|
||||
| GET | `/api/v1/versions` | Теги `kindest/node` (Docker Hub) или пусто при `KIND_K8S_SKIP_VERSION_LIST` |
|
||||
| GET | `/api/v1/stats` | Сводка для дашборда |
|
||||
| GET | `/api/v1/clusters` | Список кластеров |
|
||||
| POST | `/api/v1/clusters` | Создание в фоне (**202** + `job_id`) |
|
||||
| POST | `/api/v1/clusters/{name}/start` | Запуск: **200** — `docker start` узлов (кластер в kind); **202** + `job_id` — фоновый `kind create` по сохранённому `kind-config.yaml` |
|
||||
| POST | `/api/v1/clusters/{name}/stop` | Остановка узлов (`docker`/`podman` **stop**), запись в kind сохраняется |
|
||||
| GET | `/api/v1/clusters/{name}` | Детали + `kubectl get nodes` при наличии kubeconfig |
|
||||
| GET | `/api/v1/clusters/{name}/kubeconfig` | Скачать файл kubeconfig |
|
||||
| GET | `/api/v1/clusters/{name}/workloads` | Узлы и поды (`kubectl`) |
|
||||
@@ -49,6 +54,8 @@
|
||||
- В памяти держится не более **200** записей; при превышении старые задания вытесняются (`app/core/job_store.py`).
|
||||
- Создание кластера: `POST /api/v1/clusters` → опрос `GET /api/v1/jobs/{job_id}` (как в веб-UI).
|
||||
- В ответе задания поля **`progress_stage`** (текст этапа) и **`progress_percent`** (0–100) обновляются во время создания.
|
||||
- Поле **`progress_log`** — массив последних строк журнала (вывод `kind create`: pull образов, подъём нод и т.д.); размер ограничен (см. `KIND_K8S_JOB_LOG_MAX_LINES` в коде `job_store`, по умолчанию до **500** строк в буфере, в JSON отдаётся хвост).
|
||||
- Тип задания **`kind`**: `create_cluster` или `start_cluster` (повторный подъём по `clusters/<имя>/kind-config.yaml`).
|
||||
- Статус **`cancelled`** — пользователь запросил отмену (`POST .../cancel`); этап `kind create cluster` до завершения не прерывается.
|
||||
|
||||
---
|
||||
@@ -86,6 +93,16 @@
|
||||
|
||||
---
|
||||
|
||||
## GET /api/v1/docs/readme
|
||||
|
||||
Сырое содержимое **README.md** проекта в кодировке UTF-8, заголовок **`Content-Type: text/markdown; charset=utf-8`**.
|
||||
|
||||
Используется страницей **`GET /documentation`**: скрипт `documentation.js` загружает текст и превращает его в HTML через **marked** и **DOMPurify** (файлы лежат в репозитории: `app/static/js/vendor/`, без внешних CDN).
|
||||
|
||||
**Ошибка 404:** файл не найден. В Compose смонтируйте `./README.md:/opt/kind-k8s/README.md:ro`, задайте `KIND_K8S_README_PATH` или пересоберите образ (`COPY README.md`). См. `app/core/readme_doc.py`.
|
||||
|
||||
---
|
||||
|
||||
## GET /api/v1/versions
|
||||
|
||||
Список стабильных тегов `kindest/node` с Docker Hub (для выпадающего списка в UI).
|
||||
@@ -293,6 +310,56 @@
|
||||
|
||||
---
|
||||
|
||||
## POST /api/v1/clusters/{name}/start
|
||||
|
||||
Запуск кластера двумя сценариями:
|
||||
|
||||
1. Кластер **есть** в `kind get clusters` (узлы когда-либо создавались) — выполняется **`docker start`** / **`podman start`** для всех контейнеров с именами вида `<имя>-control-plane`, `<имя>-worker`, … Ответ **200**.
|
||||
2. В **kind** кластера **нет**, но в `clusters/<имя>/kind-config.yaml` файл **есть** — ставится фоновое задание **`start_cluster`** (как при создании: `kind create` по сохранённому конфигу, журнал в `GET /jobs/{job_id}`). Ответ **202** + `job_id`.
|
||||
|
||||
**Пример ответа 200 (контейнеры запущены):**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "dev",
|
||||
"mode": "containers",
|
||||
"containers_started_ok": true,
|
||||
"summary": "dev-control-plane: OK; dev-worker: OK; dev-worker2: OK"
|
||||
}
|
||||
```
|
||||
|
||||
**Пример ответа 202 (подъём по конфигу):**
|
||||
|
||||
```json
|
||||
{
|
||||
"job_id": "cafebabe...",
|
||||
"status": "queued",
|
||||
"message": "Подъём кластера по kind-config.yaml; опросите GET /api/v1/jobs/{job_id}"
|
||||
}
|
||||
```
|
||||
|
||||
**Ошибка 400:** некорректное имя или нет ни кластера в kind, ни `kind-config.yaml` в `clusters/<имя>/`.
|
||||
|
||||
---
|
||||
|
||||
## POST /api/v1/clusters/{name}/stop
|
||||
|
||||
Остановка **всех** контейнеров узлов кластера (`docker stop` / `podman stop` по префиксу имени). Запись кластера в kind **не удаляется**; позже можно снова вызвать **POST …/start** (режим `containers`).
|
||||
|
||||
**Пример ответа 200:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "dev",
|
||||
"containers_stopped_ok": true,
|
||||
"summary": "dev-control-plane: OK; dev-worker: OK"
|
||||
}
|
||||
```
|
||||
|
||||
**Ошибка 400:** некорректное имя кластера.
|
||||
|
||||
---
|
||||
|
||||
## GET /api/v1/jobs/{job_id}
|
||||
|
||||
Статус фонового задания создания.
|
||||
@@ -307,7 +374,15 @@
|
||||
"cluster_name": "dev",
|
||||
"created_at_utc": "2026-04-04T12:00:00+00:00",
|
||||
"message": null,
|
||||
"result": null
|
||||
"result": null,
|
||||
"progress_stage": "kind create cluster (скачивание образов и подъём нод — может занять несколько минут)",
|
||||
"progress_percent": 28,
|
||||
"progress_log": [
|
||||
"[12%] Подготовка каталога и kind-config",
|
||||
"--- kind create cluster ---",
|
||||
"Creating cluster \"dev\" ...",
|
||||
" • Ensuring node image (kindest/node:v1.29.4) 🖼 ..."
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -321,6 +396,7 @@
|
||||
"cluster_name": "dev",
|
||||
"created_at_utc": "2026-04-04T12:00:00+00:00",
|
||||
"message": "Кластер создан",
|
||||
"progress_log": ["[95%] Финализация", "kubectl wait nodes: ..."],
|
||||
"result": {
|
||||
"cluster_name": "dev",
|
||||
"kubernetes_version_tag": "v1.29.4",
|
||||
|
||||
Reference in New Issue
Block a user