d1a01cca9e
- Цель make docker|podman kubectl CLUSTER=… (KUBECTL_ARGS) — exec kubectl в kind-k8s-web - README: без kubectl на хосте; раздел про проверку API из контейнера - create_cluster/cluster_status: подсказки для UI, make kubectl и exec в контейнере - app/docs: api_routes.md и README.md про kubectl и API workloads - Прочее: переименование проекта, документация, UI документации (ранее в рабочем дереве)
91 lines
3.1 KiB
Python
91 lines
3.1 KiB
Python
"""Отдача README.md и файлов ``app/docs/*.md`` для клиентского рендера Markdown (marked в static).
|
|
|
|
Автор: Сергей Антропов
|
|
Сайт: https://devops.org.ru
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import logging
|
|
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
from fastapi.responses import PlainTextResponse
|
|
|
|
from core.readme_doc import read_app_docs_file_text, read_readme_text
|
|
|
|
logger = logging.getLogger("kind_k8s.api.docs_readme")
|
|
|
|
router = APIRouter(tags=["documentation"])
|
|
|
|
|
|
@router.get(
|
|
"/docs/readme",
|
|
response_class=PlainTextResponse,
|
|
summary="README.md как текст (Markdown)",
|
|
responses={404: {"description": "Файл не найден"}},
|
|
)
|
|
async def get_readme_markdown() -> PlainTextResponse:
|
|
"""
|
|
Тело ответа — содержимое README в кодировке UTF-8.
|
|
|
|
Разбор Markdown выполняется в браузере скриптами из ``/static/js/vendor/`` (marked + DOMPurify).
|
|
"""
|
|
try:
|
|
|
|
def _read() -> str:
|
|
return read_readme_text()
|
|
|
|
text = await asyncio.to_thread(_read)
|
|
except FileNotFoundError:
|
|
logger.info("GET /docs/readme: файл README не найден")
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=(
|
|
"README.md не найден. Укажите KIND_K8S_README_PATH, смонтируйте в compose "
|
|
"./README.md:/opt/kind-k8s/README.md:ro или пересоберите образ (COPY README.md)."
|
|
),
|
|
) from None
|
|
logger.debug("GET /docs/readme: отдано %s символов", len(text))
|
|
return PlainTextResponse(
|
|
content=text,
|
|
media_type="text/markdown; charset=utf-8",
|
|
)
|
|
|
|
|
|
@router.get(
|
|
"/docs/file",
|
|
response_class=PlainTextResponse,
|
|
summary="Файл Markdown под app/docs/",
|
|
responses={400: {"description": "Некорректный путь"}, 403: {"description": "Вне app/docs"}, 404: {"description": "Нет файла"}},
|
|
)
|
|
async def get_app_docs_file(
|
|
path: str = Query(
|
|
...,
|
|
description="Относительный путь, например app/docs/api_routes.md",
|
|
examples=["app/docs/api_routes.md"],
|
|
),
|
|
) -> PlainTextResponse:
|
|
"""
|
|
Только файлы ``*.md`` с префиксом ``app/docs/`` (без ``..``).
|
|
|
|
Ссылки из README ведут на ``/documentation?path=...``; клиент запрашивает этот эндпоинт.
|
|
"""
|
|
try:
|
|
|
|
def _read() -> str:
|
|
return read_app_docs_file_text(path)
|
|
|
|
text = await asyncio.to_thread(_read)
|
|
except FileNotFoundError:
|
|
logger.info("GET /docs/file: не найден или запрещён путь %s", path)
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail="Файл не найден или путь не разрешён (ожидается app/docs/<имя>.md).",
|
|
) from None
|
|
logger.debug("GET /docs/file: отдан %s", path)
|
|
return PlainTextResponse(
|
|
content=text,
|
|
media_type="text/markdown; charset=utf-8",
|
|
)
|