Files
pvemanager/docs/roadmap.md
markmorado f4f917c73e
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
feat(install): add one-command bootstrap for regular hosts and PVE hosts
Adds bootstrap.sh implementing Stage 3 of the roadmap: it detects whether
it runs on a plain Debian/Ubuntu host or directly on a Proxmox VE host.
On a PVE host it provisions a Debian 12 LXC, installs the panel inside it
via the existing deploy.sh, then creates a root@pam API token locally and
registers the host as the panel's first node — no Proxmox password is
ever transmitted.

Also removes the insecure pvemanager_secure_password fallback for
POSTGRES_PASSWORD in compose.yml, since every deploy path already
generates a real .env before the stack starts.
2026-07-25 00:44:08 +05:00

18 KiB
Raw Blame History

План развития PVEmanager

Документ описывает шесть направлений развития панели, согласованных 24.07.2026. Два из них уже реализованы, четыре — предстоят. Для каждого этапа указаны цель, затрагиваемые файлы, шаги и критерии готовности, чтобы задачу мог взять любой разработчик без дополнительного контекста.

Статус

# Направление Статус Приоритет
1 Автосоздание API-токена при подключении ноды ✅ Сделано —
2 Графики метрик нод ✅ Сделано (не проверено визуально) —
3 Одна команда установки (curl | bash) 🟡 Загрузчик готов (ветка B), не проверен на реальном PVE 1
4 Интеграция с Proxmox Backup Server ⬜ Запланировано 2
5 Redis: вынос воркера задач и общий кэш ⬜ Запланировано 3
6 Внешний стек метрик и логов (опционально) ⬜ Запланировано 4

Порядок выбран так: сначала дистрибуция (от неё зависит рост аудитории), затем крупная продуктовая фича, затем инфраструктурные улучшения. Этап 6 — самый дорогой и наименее обязательный, поэтому идёт последним.


✅ Этап 1. Автосоздание API-токена

Что сделано. При добавлении сервера пользователь вводит логин и пароль, панель подключается ими один раз, создаёт на ноде собственный API-токен и дальше работает по нему. Токен отзывается из UI Proxmox, не даёт SSH- и веб-логина и виден в аудите PVE под своим именем.

  • backend/app/proxmox/token_provisioning.py — создание токена (privsep=0), выбор свободного имени (pvemanager, при коллизии pvemanager-2), откат через revoke_api_token.
  • POST /api/servers (backend/app/api/proxmox/servers.py) — поле auto_create_token; при сбое коммита созданный токен отзывается, чтобы на ноде не оставался сирота с потерянным секретом.
  • POST /api/servers/{id}/provision-token — перевод уже подключённого сервера с пароля на токен по сохранённому паролю.
  • api_token_value переведён на EncryptedString (backend/app/models/proxmox.py) — раньше токены лежали в БД открытым текстом, в отличие от паролей.
  • Фронтенд: выбор из трёх режимов подключения в NodesPage.tsx, кнопка «Перевести на API-токен» на карточке сервера.

Принятые решения. Пароль после создания токена остаётся в БД (зашифрованным) — он нужен ProxmoxClient._password для SSH-фолбэков вроде pvecm delnode. Токен создаётся с privsep=0, то есть наследует права пользователя.

✅ Этап 2. Графики метрик нод

Что сделано. Вкладка «Графики» в NodeDetailPage: CPU, IO delay, память, load average, сеть in/out, swap, корневая ФС. Пресеты 1h/24h/7d/30d/1y.

  • frontend/src/components/shared/MetricChart.tsx — общий ChartCard, переиспользуется вкладкой инстансов.
  • useNodeMetrics в frontend/src/hooks/use-nodes.ts — нормализация сырого RRD (PVE отдаёт cpu/iowait долями 0..1).
  • frontend/src/features/nodes/NodeGraphs.tsx.

Бэкенд не менялся — эндпоинт /api/{server_id}/node/rrddata существовал ранее. Дисковых I/O и IOPS в наборе нет: PVE их в node RRD не отдаёт.

Открытый хвост. Рендер с реальными данными не проверялся визуально.


🟡 Этап 3. Установка одной командой

Что сделано. bootstrap.sh в корне репозитория — единый загрузчик для обеих веток, определяет среду по наличию /etc/pve:

  • Ветка A (install_branch_a): ставит Docker (через get.docker.com, если его ещё нет) и git/curl/openssl/jq, клонирует репозиторий в PVEMANAGER_DIR (/opt/pvemanager по умолчанию) на выбранный git-реф (PVEMANAGER_VERSION, по умолчанию — последний тег репозитория, иначе main), передаёт управление deploy.sh --standalone. Docker ставится заранее нарочно: интерактивный запрос внутри check_requirements() в deploy.sh иначе заблокировал бы неинтерактивный запуск из LXC.
  • Ветка B (install_branch_b): создаёт LXC (Debian 12, DHCP на vmbr0, nesting=1,keyctl=1 для Docker внутри), параметры (vmid, storage, bridge, ресурсы) настраиваются переменными PVEMANAGER_LXC_*; шаблон скачивается через pveam, если его ещё нет. Затем клонирует репозиторий во временную директорию на хосте только чтобы забрать актуальную версию самого bootstrap.sh, кладёт его в контейнер через pct push и выполняет там — внутри LXC /etc/pve не существует, поэтому скрипт сам уходит в ветку A. После того как панель поднялась (GET /health), хост создаёт токен root@pam!pvemanager локально через pvesh create ... --privsep 0, логинится в панель под admin/сгенерированным паролем и регистрирует сам себя (POST /api/servers) — пароль от Proxmox никуда не передаётся.

Принятые решения при реализации.

  • Убран небезопасный дефолт ${POSTGRES_PASSWORD:-pvemanager_secure_password} в compose.yml (заменён на ${POSTGRES_PASSWORD:?...}) — раньше стек мог молча подняться с предсказуемым паролем БД при отсутствии .env.
  • Реф для клонирования (resolve_ref()) уже поддерживает пиннинг по последнему git-тегу через git ls-remote --tags, но в репозитории пока нет ни одного тега — до первого релиза загрузчик fallback'ится на main.

Не сделано / не проверено.

  • Скрипт не тестировался на живом Proxmox-хосте — нет доступного стенда в этой сессии. Нужна проверка: создание LXC, установка Docker внутри unprivileged-контейнера, полный проход deploy.sh --standalone, логин и регистрация ноды.
  • Инфраструктура раздачи (домен get.<домен>, статика с нужными Content-Type/Cache-Control, публикация sha256, второй путь установки в README) — не делалась, требует внешних ресурсов (домен, хостинг). bash bootstrap.sh уже работает как локальный путь установки.
  • pve --help не проверялся в связке с этим потоком (устанавливается тем же deploy.sh через install_pve_cli --auto, логика не менялась).

Осталось до полного закрытия этапа (инфраструктурная часть, не код):

  • Домен get.<домен> под контролем проекта + TLS, раздача статики (Cloudflare Pages/Worker или R2) с Content-Type: text/plain и коротким Cache-Control.
  • Публикация sha256 bootstrap.sh и второй путь установки в README («скачать → прочитать → запустить»).
  • Первый git-тег в репозитории, чтобы пиннинг версии в resolve_ref() начал реально на что-то указывать (сейчас fallback на main).
  • Живой прогон на Debian/Ubuntu-машине и на PVE-хосте — см. «Не сделано / не проверено» выше.

Готово, когда:

  • на чистой Debian/Ubuntu-машине одна команда поднимает работающую панель;
  • на PVE-хосте та же команда создаёт LXC, ставит панель внутрь и регистрирует ноду без ввода пароля;
  • pve --help отвечает;
  • повторный запуск обновляет установку, не ломая её.

⬜ Этап 4. Интеграция с Proxmox Backup Server

Цель. Управлять PBS напрямую, а не только через PVE.

Что уже есть. PBS подключается к PVE как storage типа pbs, поэтому бэкап и восстановление уже работают через backend/app/api/proxmox/backup.py (storages, native jobs, restore, bulk restore).

Чего не хватает (не видно через PVE API): использование datastore и дедупликация, задания verify/prune/GC, namespaces, sync- и tape-задания, браузер снапшотов с восстановлением отдельных файлов.

Шаги.

  1. Модель PBSServer: host, порт (по умолчанию 8007), api_user, токен (user@pbs!tokenid), fingerprint сертификата, verify_ssl. Секреты — через EncryptedString.
  2. Клиент backend/app/pbs/client.py по образцу ProxmoxClient с миксинами: datastores, snapshots, verify/prune/GC, namespaces.
  3. API-роутер backend/app/api/pbs/ + права в backend/app/rbac/permissions.py.
  4. Фронтенд: раздел PBS со списком серверов, datastore-обзором и браузером снапшотов.
  5. Связать с существующим разделом бэкапов: если storage типа pbs соответствует зарегистрированному PBS-серверу — показывать расширенные данные.

Готово, когда можно добавить PBS-сервер, увидеть занятость datastore и коэффициент дедупликации, запустить verify/prune и просмотреть содержимое снапшота.

Оценка. Сопоставимо по объёму со всем текущим модулем бэкапов.

⬜ Этап 5. Redis: вынос воркера и общий кэш

Цель. Вынести исполнение фоновых задач из процесса app в отдельный контейнер и убрать состояние, которое сейчас живёт только в памяти процесса.

Текущее состояние. TaskQueueService хранит задачи в Postgres, а исполняются они внутри app через APScheduler при UVICORN_WORKERS=1. Последствия: воркеры не масштабируются, задача в статусе running зависает при рестарте контейнера, нет ретраев.

Важно: очередь в Postgres сама по себе не проблема — для домашней нагрузки её достаточно. Выигрыш даёт именно вынос воркера; Redis нужен как брокер и попутно закрывает три места, которые сейчас ломаются при масштабировании:

  • connection_cache в backend/app/proxmox/client.py — словарь в памяти;
  • _rrd_cache в backend/app/services/metrics_broadcaster.py — то же;
  • websocket_manager.py — при более чем одном uvicorn-воркере рассылка не работает без pub/sub.

Шаги.

  1. Добавить сервис redis в compose.yml (alpine-образ, ограничение памяти).
  2. Подключить ARQ как брокер (asyncio-native; Celery для этой задачи избыточен). Postgres остаётся источником правды по истории задач.
  3. Вынести обработку TaskQueue в отдельный контейнер worker.
  4. Перевести connection_cache и _rrd_cache на Redis.
  5. Перевести WebSocket-рассылку на Redis pub/sub, после чего можно поднять UVICORN_WORKERS.
  6. Добавить ретраи и переустановку статуса зависших задач при старте воркера.

Готово, когда задачи исполняются в отдельном контейнере, переживают рестарт app, а панель корректно работает при UVICORN_WORKERS > 1.

⬜ Этап 6. Внешний стек метрик и логов

Цель. Снять с панели хранение метрик и дать историю глубже, чем позволяет RRD, — но не навязывая всем пользователям тяжёлый стек мониторинга.

Ключевой факт. Собирать метрики самим не нужно: у Proxmox есть встроенный external metric server (протоколы InfluxDB и Graphite) — нода push-ит метрики наружу без всякого кода в панели. Для pull-модели существует prometheus-pve-exporter.

Решения по составу.

  • VictoriaMetrics вместо Prometheus и VictoriaLogs вместо Loki — заметно меньше RAM и диска при совместимом PromQL/LogsQL.
  • Grafana необязательна. Если панель сама ходит в PromQL, Grafana нужна только продвинутым пользователям — подключается опционально.
  • Весь стек включается через docker compose --profile monitoring, а не входит в поставку по умолчанию: для типовой домашней установки это дороже самой панели.

Шаги.

  1. Профиль monitoring в compose.yml.
  2. В панели — переключаемый источник метрик: native (RRD через PVE API, как сейчас) либо victoriametrics (PromQL). Настройка в разделе Settings.
  3. Абстрагировать слой доступа к данным на фронтенде, чтобы GraphsTab и NodeGraphs не переписывать при смене источника.
  4. Инструкция по настройке external metric server на ноде.
  5. Опциональная Grafana с преднастроенными дашбордами.

Готово, когда при выключенном профиле всё работает как сейчас, а при включённом графики строятся из VictoriaMetrics с историей глубже RRD.

Зависимость. Этап 2 намеренно сделан на RRD. При выполнении этого этапа слой доступа к данным нужно спрятать за один хук, а не переписывать компоненты.


Технический долг, замеченный попутно

  • Хардкод русских строк в frontend/src/features/instances/tabs/GraphsTab.tsx: «IOPS чтение», «IOPS запись», «Заполненность диска», «Все», «Сбросить», «Нет данных» — не проходят через i18n.
  • graphify update . отказывается перезаписывать граф: AST-версия даёт 5938 узлов против 5959 в текущем graph.json. Нужно решить, форсить ли перестроение.