100 lines
8.1 KiB
Markdown
100 lines
8.1 KiB
Markdown
# Admin Dashboard
|
||
|
||
`admin-dashboard` — 4-й компонент системы: браузерная веб-панель,
|
||
дающая полное покрытие административного API `control-api`
|
||
([docs/API.md](API.md#управление-очередью-и-конфигурацией)) без единого
|
||
`curl`. Отдельный, полностью самостоятельный процесс — не хранит
|
||
состояния, не подключается к базе данных напрямую, общается с
|
||
`control-api` только через его же HTTP admin API.
|
||
|
||
## Устройство
|
||
|
||
- Рендеринг полностью на сервере: `html/template` + [htmx](https://htmx.org)
|
||
(частичные обновления без перезагрузки страницы) +
|
||
[Alpine.js](https://alpinejs.dev) (точечная клиентская интерактивность) +
|
||
[Pico CSS](https://picocss.com) в classless-сборке (минималистичный вид
|
||
на голой семантической разметке). Никакой сборки фронтенда нет — все три
|
||
библиотеки вендорены как статические файлы
|
||
(`internal/dashboard/static/vendor/`, см. `VENDOR.md` там же) и встроены
|
||
в бинарник через `//go:embed`. Дашборд работает полностью офлайн — при
|
||
открытии страницы браузер не делает ни одного запроса за пределы самого
|
||
дашборда (можно проверить через DevTools → Network).
|
||
- Браузер никогда не видит JSON `control-api` напрямую: каждая страница и
|
||
каждый htmx-фрагмент — это HTML, отрендеренный Go-хендлером дашборда
|
||
после вызова `control-api`. CORS и reverse-proxy не нужны.
|
||
- Как и `control-api`, дашборд **не аутентифицирован** — ограничивайте
|
||
доступ на уровне сети/файрвола (см.
|
||
[SETUP.md](SETUP.md#сетевые-доступы)).
|
||
|
||
## Запуск
|
||
|
||
```bash
|
||
cp configs/admin-dashboard.example.yaml /etc/cloud-ip-validator/admin-dashboard.yaml
|
||
# отредактируйте control_api.base_url под ваш стенд
|
||
admin-dashboard -config /etc/cloud-ip-validator/admin-dashboard.yaml
|
||
```
|
||
|
||
Развёртывание как systemd-юнита — по образцу остальных компонентов, см.
|
||
[SETUP.md](SETUP.md#развёртывание-admin-dashboard). Порт по умолчанию —
|
||
`:8090` (у `control-api` — `:8080`).
|
||
|
||
## Страницы и что на них можно делать
|
||
|
||
| Страница | Назначение |
|
||
|---|---|
|
||
| `/overview` | Сводная статистика: счётчики по состояниям, «текущая проверка» (live-снимок всех IP не в терминальном состоянии) и «последние N завершённых» (по умолчанию 20, `overview.last_completed_count`) с разбивкой pass/partial/fail/cancelled. Обновляется каждые `overview.poll_interval_seconds` секунд без перезагрузки страницы. |
|
||
| `/ips` | Полная очередь. Форма сверху принимает список адресов (по одному на строке или через запятую) и отправляет их в `POST /api/v1/admin/ips` — **один и тот же вызов** добавляет новые адреса и принудительно перезапускает уже завершённые (см. ниже). У каждого адреса — кнопка «Перепроверить» (для `done`/`failed`) или «Отменить» (для активных состояний). |
|
||
| `/ips/{ip}` | Детали одного адреса: все проверки текущей попытки и вся история событий. |
|
||
| `/validators` | Список валидаторов + создание/изменение `os_port_id`/удаление. |
|
||
| `/sites` | Три фиксированных слота площадок (1/2/3) — назначить/сменить/освободить `site_id`. |
|
||
| `/targets` | Группы целей для egress-проверок — создание/редактирование/удаление. |
|
||
| `/check-types` | Типы проверок (`https`/`icmp`/`ssh`/...), включение/выключение, привязка к группам целей. |
|
||
|
||
### «Текущая» и «последняя завершённая» проверка
|
||
|
||
В `control-api` нет понятия «запуска»/«цикла проверки» как отдельной
|
||
сущности — есть только общая очередь IP-адресов
|
||
(`docs/PLAN_ADMIN_DASHBOARD.md`). Дашборд ничего не меняет в этом
|
||
устройстве и не заводит своего состояния:
|
||
|
||
- **Текущая проверка** — все адреса, которые прямо сейчас не в
|
||
состоянии `done`/`failed` (`queued`, `assigning_fip`,
|
||
`awaiting_self_check`, `checking`, `aggregating`), вычисляется заново на
|
||
каждый запрос из `GET /api/v1/admin/status` + `GET /api/v1/admin/ips`.
|
||
- **Последняя завершённая проверка** — последние N адресов, перешедших в
|
||
`done`/`failed`, отсортированные по `AggregatedAt` по убыванию (не
|
||
«последний запуск», а именно скользящее окно последних по времени
|
||
завершений).
|
||
|
||
### Добавление адресов и принудительный повтор — один и тот же вызов
|
||
|
||
Форма на `/ips` всегда бьёт в `POST /api/v1/admin/ips`. Поведение зависит
|
||
от текущего состояния каждого конкретного адреса (см.
|
||
[docs/API.md](API.md#post-apiv1adminips)): новый — встаёт в очередь;
|
||
уже `done`/`failed` — принудительно перезапускается; уже `queued` —
|
||
просто переупорядочивается; уже активно проверяется — не трогается
|
||
(дашборд честно показывает это в таблице, а не делает вид, что запрос
|
||
ничего не значил).
|
||
|
||
## Конфигурация
|
||
|
||
См. `configs/admin-dashboard.example.yaml`. Ключевые поля:
|
||
|
||
- `server.listen_addr` — где слушает сам дашборд (по умолчанию `:8090`).
|
||
- `control_api.base_url` — адрес `control-api`, обязателен.
|
||
- `control_api.timeout_seconds` — таймаут HTTP-запросов к `control-api`.
|
||
- `overview.last_completed_count` — размер окна «последних завершённых»
|
||
на странице обзора.
|
||
- `overview.poll_interval_seconds` — как часто браузер опрашивает
|
||
`/overview/fragment` для live-обновления.
|
||
|
||
## Отображение ошибок
|
||
|
||
Любая ошибка `control-api` (4xx/5xx с телом `{"error":"..."}`) или сбой
|
||
связи с ним (недоступен, таймаут) показывается баннером наверху страницы,
|
||
а не приводит к падению дашборда — таблица/страница при этом всегда
|
||
отражает актуальное состояние `control-api` (дашборд перезапрашивает
|
||
данные после любой попытки мутации, независимо от её исхода). Жёлтый
|
||
баннер — бизнес-ошибка (4xx, например «валидатор занят»), красный —
|
||
инфраструктурная проблема (5xx или `control-api` недоступен).
|