App Store install/update pipeline reliability fixes:
- explicit nameserver (APPSTORE_NAMESERVER) on App Store LXCs and the golden
template build CT, instead of inheriting a node resolver that may be
unreachable from the container network (e.g. Tailscale-only DNS)
- golden template storage/resolution moved from one global setting to
per-server_id (migration 37: app_operations.server_id) — building it on one
Proxmox server no longer overwrites the template configured for another
- golden template automated build fixed: vzdump export step no longer fails
on "unable to parse directory volume name 'vztmpl/probe'"
- bind-mount host directories are pre-created with permissive ownership
before `docker compose up`, fixing Permission denied for non-root
containers (e.g. MariaDB) writing to Docker-auto-created root-owned dirs
- delete/teardown now waits for Proxmox to actually confirm the destroy task
finished (was silently proceeding after a short timeout, letting a new
install reuse the VMID while the node was still wiping the old disk)
- pct create retries a few times on transient "got lock" config errors
- failed pipeline steps now report the tail of command output (4000 chars)
instead of the head, so the real error isn't buried under pull/progress noise
- install error box in the UI wraps long text and scrolls instead of
stretching the dialog
Also carries forward in-progress script catalog / instances / RBAC changes
that were already uncommitted in the working tree before this session.
Bump to v1.9.1, update WIKI.md/docs/CHANGELOG accordingly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Командная палитра (Ctrl+K) с общим реестром nav-items и его store
- Новые общие UI-примитивы: alert, breadcrumb, checkbox, progress, switch, textarea
- Меню инстанса: добавлены «Параметры», «Мигрировать», «Изменить ресурсы»,
«Создать резервную копию» (новый BackupDialog) и «Удалить»; исправлено
закрытие меню при живом обновлении списка (стабильные columns + getRowId)
- Вкладки инстанса: «Вычислительные ресурсы», «Опции CPU», «Управление
дисками» и «Изменение размера диска» перенесены с «Настройки» на
«Оборудование» для VM (для LXC, у которых нет вкладки «Оборудование»,
ресурсы и ресайз диска остаются в «Настройках»); общие карточки вынесены
в ResourceCards.tsx
- Локализация: новые ключи ru/en для добавленных пунктов меню и бэкапа
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Добавлена библиотека скриптов по образцу VMmanager: свои скрипты (CRUD в UI)
и синхронизация из git-репозитория, параметризация через env-переменные
(без конкатенации в shell), выполнение на нодах Proxmox (SSH), в LXC (pct
exec) и в VM (QEMU guest agent, переиспользует существующий execute_script).
Журнал запусков встроен в общий список задач /api/all-tasks.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5. UPID-синк: транзитная ошибка опроса статуса больше не помечает живую
задачу failed — get_task_status(raise_on_error=True) + счётчик из 3
последовательных неудач; в exit_status пишется реальная причина.
6. Дашборд и бэкапы для серверов на порту != 8006: metrics_broadcaster и
backup_scheduler строят клиент через ProxmoxClient.from_server (учёт
порта и token/password) вместо ручной сборки по ip_address.
7. Бэкап "все VM": create_backup при vmid in (None, 0, "all") передаёт
vzdump параметр all=1 — раньше уходил vmid=0 и PVE отвергал задание.
8. IPAM: get_next_available_ip собирает занятые IP глобально (как проверяет
allocate_ip), а не только по pool_id — авто-выдача больше не предлагает
занятый адрес и не срывает создание инстанса.
9. IPAM: fallback в release_ip_by_vmid ищет только записи без
proxmox_server_id — удаление VM не освобождает IP одноимённого vmid
на другом сервере.
10. _get_proxmox_client: сервер без валидных кредов теперь возвращает
понятную 503-ошибку вместо молчаливо пустых списков; перечисление
серверов в метриках защищено per-server try/except.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1. vms.py: catch-all маршруты /vm/{vmid}/{action} и /container/{vmid}/{action}
перенесены в конец файла — раньше они перехватывали POST /unlock,
/cloud-init и /exec, и эти операции всегда падали с 400 "Invalid action".
2. task_queue_service: зависшие после рестарта running-задачи помечаются
failed при старте — иначе очередь bulk-операций блокировалась навсегда.
3. api-client.ts: 401 от /api/auth/login больше не вызывает перезагрузку
страницы — пользователь видит сообщение "неверный логин/пароль".
4. task_queue_service: bulk shutdown теперь вызывает shutdown_vm/
shutdown_container (graceful) вместо жёсткого stop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Список серверов терял порядок при фоновом рефетче (каждые 30с),
т.к. запрос с WHERE id IN (...) не гарантирует стабильный порядок строк.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
При провале join нода остаётся стейл-записью с cluster_name в панели, хотя
в Proxmox она standalone. Обычный eject пытается pvecm delnode через SSH и
падает ("SSH connection failed"), т.к. нода не член кластера и/или узел
недоступен по SSH.
- eject-эндпоинт: новый параметр panel_only — отвязывает панельную запись
(cluster_name=None) без обращения к Proxmox/SSH.
- UI: чекбокс "Только отвязать запись в панели" в диалоге исключения,
блокирует поле пароля при выборе.
- Локали ru/en.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Проблема: присоединяемая нода подключалась к кластерной по её адресу из
панели (часто публичный FQDN), из-за чего join падал с
"Can't connect to <fqdn>:8006 (Connection timed out)" при выделенной
corosync-сети. Плюс панель помечала ноду как присоединённую сразу после
старта задачи, показывая ложное членство даже при провале join.
- join: новый опциональный параметр cluster_host — приватный IP кластерной
ноды в corosync-сети; используется как hostname для API-подключения и
для выбора fingerprint из nodelist. Фолбэк — ip_address из панели.
- join: cluster_name пишется в БД только после подтверждения, что нода
реально появилась среди нод кластерной ноды (опрос до ~40с, укладываемся
в nginx proxy_read_timeout 60с). Иначе — confirmed=false и предупреждение.
- UI: поле "Адрес кластерной ноды для подключения" в шаге 3 мастера,
обработка неподтверждённого join (toast.warning, окно не закрывается).
- Локали ru/en.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /cluster/config/join не возвращает fingerprint на верхнем уровне —
он лежит в nodelist[].pve_fp. Добавлен хелпер _extract_fingerprint,
который выбирает pve_fp целевой ноды (по IP), с фолбэком на
preferred_node и первую ноду. Устраняет ошибку 502
"Не удалось получить fingerprint кластера" при присоединении нод.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Сертификаты: методы клиента + endpoints GET/POST/DELETE
/nodes/{node}/certificates, хуки и вкладка «Сертификаты» в
NodeAdminManager (просмотр, загрузка PEM cert+key, удаление кастомного,
бейдж срока действия)
- Bulk migrate: тип bulk_migrate в очереди задач с WS-прогрессом,
target_node/online в BulkOperationItem, диалог выбора целевой ноды и
кнопка в тулбаре инстансов (в пределах одного сервера/кластера)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ядро:
- Reboot/Shutdown ноды (POST /nodes/{node}/status) под новым правом node:power
с подтверждением в UI; меню действий на карточке ноды + пункт «Консоль (Shell)».
Доп. вкладки в «Администрировании ноды»:
- Журнал (syslog ноды), История задач (tasks + лог задачи),
Система (DNS / /etc/hosts / часовой пояс).
Бэкенд: методы node_power_action/get_node_syslog/get_node_tasks/get_node_task_log/
get_node_task_status/DNS/hosts/time в NodeAdminMixin + эндпоинты в node_admin.py.
RBAC: право node:power (admin + backfill server:manage).
Проверено: py_compile, tsc --noEmit, vite build; live — маршруты в openapi,
403 без токена, node:power засеян роли admin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A1: иконки Umbrel тянутся пофайлово с GitHub Pages CDN в пуле из 16 потоков
(<app-id>/icon.svg) вместо тяжёлого tarball галереи со скриншотами. Синк
Umbrel: ~7.5 мин → ~13-17с, 379/379 иконок. Настройка UMBREL_APPSTORE_GALLERY_CDN
заменяет UMBREL_APPSTORE_GALLERY_REPO. 404/сетевой сбой отдельного запроса
просто пропускает иконку, не роняя синк.
A2: на свежем деплое каталог пуст, а IntervalTrigger впервые сработает лишь
через сутки. Теперь при пустом каталоге планировщик ставит разовый синк
немедленно (trigger=date) — каталог наполняется на старте без ручной кнопки.
Проверено на стенде: стартовый синк наполнил каталог 644 (runtipi 265 +
umbrel 379) за 16.5с; эндпоинт логотипа отдаёт 200 image/svg+xml.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- VERSION → 1.9.0
- CHANGELOG: запись v1.8.1 (Umbrel как второй источник каталога, адаптер
compose, иконки из галереи, мультиисточниковый синк, фильтр/бейдж источника,
кастомный порт установки, мгновенная чистка инстанса) и v1.9.0 (привязка
IPAM-сетей к серверу/ноде и области с автовыбором в визардах, приём FQDN в
поле хоста ноды)
- README (en/ru): App Store — мультиисточниковый каталог (Runtipi + Umbrel)
- WIKI: источники, env-настройки Umbrel, иконки из галереи, фильтр/бейдж,
параметр source в REST
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Планы разработки не хранятся в репозитории — только пользовательская
документация. Файл сохранён у автора отдельно.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Самодостаточный план для выполнения в отдельной сессии: контекст проекта и
конвенции, текущее состояние (Umbrel-мультиисточник), три workstream'а
(оптимизация каталога/иконок, автосоздание золотого LXC-шаблона, каркас
управляемых плагинов) с пошаговыми инструкциями и критериями приёмки.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
App Store:
- поле кастомного порта в мастере установки (переопределяет порт каталога)
- валидация диапазона порта 1..65535 (Pydantic Field + EngineError)
- APP_PORT в окружении синхронизируется с выбранным портом
- при удалении приложения инстанс сразу помечается deleted в кэше
vm_instances (soft_delete_vm_instance), не дожидаясь фонового воркера
Также включены правки IPAM (привязка сетей к рабочей области, UI
WorkspaceSelect) и синхронизации каталога App Store.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Поле ip_address валидировалось строго как IP, из-за чего подключение ноды по домену (node1.tzim.cloud) падало с 'Invalid IP address format'. Добавлен хелпер validate_host: принимает IP (v4/v6) или корректный hostname/FQDN. IPAM-валидаторы по-прежнему требуют строгий IP.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- network-scope: scopedNetworks/autoPickNetworkId — фильтрация IPAM-сетей по
выбранным серверу/ноде и детерминированный автовыбор сети для выдачи IP
- ServerNodeSelect: пара селектов «Сервер + Нода» для привязки сети
- Мастер установки App Store и CreateInstanceWizard: список сетей ограничен
релевантными, при смене сервера/ноды сеть подбирается автоматически
- IPAM: страницы сетей учитывают привязку к ноде
- Исправлены типы обработчиков Select (onValueChange отдаёт string|null)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Установка: поле «Хранилище» стало выпадающим списком доступных rootdir-хранилищ
ноды (useLXCStorages) с автовыбором валидного вместо ручного ввода
- Диагностика сбоя: увеличен захват вывода упавшей команды (400 → 2000 символов)
и добавлен 2>&1 к docker compose pull/up — реальная причина (напр. отсутствие
тега образа) больше не обрезается за строками warning
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- pipeline: _normalize_compose() объявляет упомянутые в сервисах сети
(tipi_main_network) как external в top-level — иначе docker compose up
падал с "refers to undefined network: invalid compose project"
- pipeline: LOCAL_DOMAIN=tipi.local в .env (стандартная переменная Runtipi)
- pipeline: per-command таймауты (_CMD_TIMEOUT/_DOCKER_TIMEOUT), при таймауте
установка падает с ошибкой, а не зависает на 75%
- ssh_client: execute() ждёт готовности exit-status с жёстким дедлайном
вместо бесконечного recv_exit_status() (ловушка paramiko)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Порт (CatalogApp.port) уже был в API и типах, но не выводился в UI. Добавлен вывод в шапку страницы приложения и бейджем в карточке каталога (ключ appstore.port уже в локалях).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Мастер установки получал прогресс только по WebSocket; при потерянном
событии (или долгом docker compose up с тяжёлыми образами) UI замирал на
последнем шаге. Добавлен поллинг /operations раз в 3с как фолбэк.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Удаление/обновление/откат приложения использовали window.confirm() — не в стиле панели.
Переведено на общий useConfirm (Promise API), удаление — destructive-вариант.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Компонент AuthPattern — бесшовный геометрический паттерн (SVG <pattern>,
currentColor) для левой панели логина. Пока не подключён к LoginPage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Скриншоты из сторонних README на CDN с hotlink-защитой (cloudinary)
обрывали запрос по Referer (NS_BINDING_ABORTED) и резались браузером
(OpaqueResponseBlocking). Снимаем реферер, мягко скрываем не
загрузившиеся изображения.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- AppOperation.to_task_dict(): операции install/update/delete/… приведены к
общему формату и включены в /api/all-tasks, active-count и clear-completed
- Установка приложения: опциональный выбор сети/пула IPAM — статический IP
вместо DHCP (net0 ip=<addr>/<mask>,gw=…), освобождение адреса при удалении
- Мастер установки: селекторы «Сеть IPAM»/«Пул IPAM» (ru/en), по умолчанию DHCP
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
При удалении LXC/VM через delete_vm/delete_container чистим таблицу installed_apps
(по server_id+vmid), иначе приложение из каталога оставалось «хвостом» в «Мои приложения».
Шлём WS-эвент appstore_app_deleted для live-обновления списка у владельца.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- docs/golden-template.md: шаг 1 разбит на 1a–1d, имя vztmpl берётся из
`pveam available` в переменную и переиспользуется (фикс no such template /
volume does not exist)
- backend/.env.example: добавлены APPSTORE_GOLDEN_TEMPLATE и APPSTORE_HOST_ARCH
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Категории приложений (gaming, media, network, …) отображаются переведёнными
подписями через i18n (appstore.categories.*, ru+en) при сохранении сырого ключа
как значения фильтра. Неизвестные категории показываются как есть (fallback).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Описания приложений: безопасный рендер markdown + HTML (react-markdown +
remark-gfm + rehype-raw + rehype-sanitize), скриншоты отображаются как картинки
- Фильтр по категории: переведён на надёжную фильтрацию в Python (JSONB-оператор
на generic JSON-колонке отрабатывал ненадёжно)
- Ошибка отсутствия золотого шаблона локализована (i18n appstore.golden_missing)
- Каталог: карточки шире (макс 3 колонки вместо 4), описание в 3 строки
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- VERSION → 1.8.0
- CHANGELOG (ru/en): запись v1.8.0 с разделом App Store
- README (ru/en): бейдж версии + категория App Store в возможностях
- WIKI: раздел «App Store» (предпосылки, env, install, My Apps, права, REST API) + оглавление
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Добавлена возможность пробросить физический диск ноды в VM по стабильному
пути /dev/disk/by-id/ (scsiN/virtioN/sataN) в карточке «Проброс устройств».
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Карточки на странице «Узлы» дополнены важной информацией:
- версия Proxmox VE (чип «PVE x.y.z»);
- число нод в кластере (для кластерных серверов);
- аптайм узла;
- чипы рабочих областей, в которых состоит сервер.
Бэкенд: эндпоинт /api/{id}/nodes отдаёт version; ответ серверов
дополнен полями cluster_name и workspaces (ServerWorkspaceBrief).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Реальные интервалы циклов: dashboard 2с, server 2с, instance 1с.
В комментариях было устаревшее 10с/5с. Логику не меняем — дашборд
уже обновляется раз в 2 секунды.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Данные по узлам (nodes) приходят только из WebSocket dashboard_metrics,
а REST /api/resources/all их не содержит. Каждый 15-секундный рефетч REST
затирал ноды -> таблица узлов и счётчик обнулялись, WS возвращал через 2с.
- frontend: при REST-рефетче переносим последние известные nodes из кэша,
чтобы node-таблица не мигала
- backend: кэш последнего удачного опроса по каждому серверу
(_server_last_good) — транзиентный таймаут Proxmox больше не отдаёт
пустые vms/containers/nodes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- поднять лимит /proxmox/api/all-tasks до 500 (дашборд запрашивал limit=500
при потолке le=200, что давало 422 каждые 5с)
- обработчик WS dashboard_metrics больше не затирает кэш пустыми/частичными
тиками: игнорирует пустые сводки и сохраняет последние валидные
nodes/vms/containers при транзиентном сбое Proxmox
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend: new proxmox mixins and API routes for firewall, pools, access
control, node admin and disks; extend storage and VM endpoints.
Frontend: node managers (firewall, pool, access, disk, node admin), VM
firewall and hardware tabs, PCI/USB device dialogs, related hooks and
locale strings.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Migrate VMs/LXCs between cluster nodes with live progress tracking
- Configure autostart, boot order, startup/shutdown delays, and delete protection from the instance settings tab
- Group OS templates by detected OS (Ubuntu, AlmaLinux, etc.) instead of a single "Cloud Images" bucket
- Expand native Proxmox backup job management (schedule, compression, retention, guest selection, notifications)
- Add ru/en translations for the above