Commit Graph

377 Commits

Author SHA1 Message Date
markmorado
35220a1458 fix(bootstrap): tolerate apt update failures from the PVE enterprise repo
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
On an unsubscribed Proxmox host, apt's enterprise repo answers 401 and
apt-get update exits non-zero even though every other source succeeded,
aborting the whole bootstrap under set -e before git/curl were ever
installed. The subsequent apt-get install still fails loudly if a package
genuinely can't be found, so tolerating this specific failure is safe.

Found by running bootstrap.sh against a real Proxmox host.
2026-07-25 00:47:03 +05:00
markmorado
e81abf33df fix(nodes): stop showing wrong node uptime for multi-node clusters
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Server card used Math.max over all cluster nodes' uptime, so
rebooting one node still showed another node's higher uptime,
making it look like the reboot had no effect.
2026-07-25 00:44:56 +05:00
markmorado
f4f917c73e feat(install): add one-command bootstrap for regular hosts and PVE hosts
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
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
markmorado
b7c3a6ed35 feat(instances): ISO eject/mount with boot-order switch and hybrid reboot
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
- Images: show real ISO files already on the node storage (incl. those
  present before the node joined the panel) via existing node/isos endpoint
- ISO dialog: rename "detach" to "Eject", show current image inside the
  select (drop overflowing side text), add "boot from disk" checkbox
- Backend: on eject, put disk first in boot order; on mount, optional
  "boot from this ISO" puts CD-ROM first
- Reboot to apply the new boot order via hybrid restart: graceful ACPI
  shutdown with forceStop fallback, then start (fixes guest-ping timeout
  on freshly installed OS without QEMU Guest Agent)
- Update iso_next_steps hint to reflect the automated flow
2026-07-24 23:00:32 +05:00
markmorado
aa100b49c1 docs: release notes and version bump for v1.14.0
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
2026-07-24 07:00:46 +05:00
markmorado
29a5d4381d fix(instances): keep workspace-scoped filters in sync with active workspace
The per-column "Node" filter memoized its option list against TanStack's
Column object, which keeps the same identity across data updates, so the
checklist stayed frozen at whatever nodes were visible when the popover
first mounted instead of reflecting the current (workspace-scoped) rows.

Switching the active workspace also left the server/node/column filters
holding values from the previous workspace, which could filter the newly
scoped VM list down to nothing.
2026-07-24 07:00:41 +05:00
markmorado
dfe91964d9 docs: release notes and version bump for v1.13.0
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
2026-07-24 06:58:21 +05:00
markmorado
c526be3bb2 feat(appstore): add storage selection to golden template dialog
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Replace free-text storage inputs with dropdowns populated from the
server/node's actual storages (filtered by vztmpl/rootdir content),
matching the pattern used elsewhere in the app.
2026-07-24 06:52:30 +05:00
markmorado
3d63f4fb51 feat(scripts): add name search to scripts catalog
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
2026-07-24 06:42:43 +05:00
markmorado
d0b4c70c72 docs: release notes and version bump for v1.12.0
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
2026-07-24 06:39:24 +05:00
markmorado
9b493da7ad feat(cluster): import existing Proxmox cluster into the panel
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Add detect/import flow for nodes already clustered on the Proxmox side
(outside the panel). Matches nodelist entries from cluster/config/join
against known panel servers by IP/hostname and links their panel
records to the cluster_name group, without running any pvecm operation.
2026-07-24 06:35:34 +05:00
markmorado
b804a9bec5 docs: release notes and version bump for v1.11.0
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
2026-07-24 06:30:51 +05:00
markmorado
99d8ce750d feat(images): support uploading local ISO/vztmpl files to node storage
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Adds a local file upload path alongside the existing URL download flow:
a new /images/upload endpoint streams the file to a temp path and hands
it to a background worker that proxies it into Proxmox storage via the
upload API (requests-toolbelt handles the large multipart stream). Also
adds /images/resolve-filename to recover the real filename (Content-
Disposition) for URL-based downloads with opaque paths.

Raise nginx client_max_body_size and timeouts on both the frontend proxy
and the standalone nginx configs so multi-GB ISOs don't get cut off.
2026-07-24 06:17:46 +05:00
markmorado
8b4c8c3a30 fix(realtime): sync instance/workspace list state without manual refresh
- Invalidate workspace list cache after assigning servers/users so
  server/user counts on workspace cards update immediately.
- Invalidate node/VM caches after workspace server/user assignment so
  the Nodes page reflects visibility changes right away.
- Soft-delete the cached VM/LXC row and broadcast vm_deleted the moment
  a VM/container is destroyed, instead of waiting for the 10s
  background sync_vm_cache tick.
- Invalidate the VM list on the frontend when a deploy task completes,
  since the backend already persists the new instance to cache
  synchronously before marking the task done.
2026-07-24 05:39:23 +05:00
markmorado
e10f9a2a03 refactor(servers): unify connection status badges
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled
Extract ServerStatusBadge so every server list renders the auth-error
state identically instead of repeating the online/offline ternary, and
expose last_error_kind from the cluster topology and user-assignment
endpoints, which build their payloads by hand and so did not inherit it
from the server schema.
2026-07-24 05:04:45 +05:00
markmorado
ebc692a324 feat(instances): create blank VMs for ISO installs and download ISOs
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled
Add a third instance kind to the create wizard: a blank KVM VM with an
empty disk, the installation ISO mounted on ide2 and put first in the
boot order, so the guest boots straight into the installer over noVNC.
Picking a Windows guest presets OVMF, a SATA disk and an e1000 NIC,
which the installer sees without virtio drivers loaded.

Also teach the image downloader content=iso, so ISOs can be fetched
onto a node from the panel: by URL from the images page or from a saved
mirror (mirrors now accept kind=iso), and straight from the ISO step of
the wizard.

The bundled catalog stays qcow2-only on purpose — install ISOs have no
stable "latest" URLs, so hardcoded links would rot on every point release.
2026-07-24 05:00:51 +05:00
markmorado
6a4da4f80b docs: revise the one-command install stage
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled
deploy.sh already covers most of the installer (OS detection, Docker setup,
random secret generation, nginx, TLS, image build, pve CLI), so the stage is
about publishing a thin bootstrap rather than writing one from scratch.

Records the decisions taken: the bootstrap detects its environment and
creates an LXC when run on a PVE host, the repository is public, and images
keep being built locally. On a PVE host the node can register itself without
a password via pvesh, reusing the token provisioning from stage 1.
2026-07-24 04:43:07 +05:00
markmorado
075b8cdaaa feat(servers): distinguish rejected credentials from unreachable nodes
An offline server used to report a single "Failed to connect" state, but
"the node does not answer" and "the node answered 401" are fixed in
completely different ways — the first is power or network, the second is a
stale token, which is what happens when a node joins a cluster and its
user.cfg and priv/token.cfg are replaced by the cluster ones.

- add ProxmoxClient.check_connection() returning (ok, error_kind, error);
  token auth surfaces 401 as ResourceException rather than
  AuthenticationError, since proxmoxer validates the token on first use
- store the reason in proxmox_servers.last_error_kind (migration 40) and
  expose it through the server response
- surface an auth_error state in the UI with a hint explaining the usual
  cause

Storage listings now also report per-node availability: the cluster config
declares a storage for the whole cluster but says nothing about whether it
actually came up on a given node, so a missing volume group or pool stayed
invisible. Availability comes from a single /cluster/resources call.
2026-07-24 04:42:59 +05:00
markmorado
db7411b1bf docs: add development roadmap
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled
Records the six agreed directions with their status, the files each one
touches, the steps involved and the decisions already made, so the work can
be picked up without prior context.
2026-07-24 04:03:37 +05:00
markmorado
65c61e7886 feat(servers): auto-provision API tokens and add node metric graphs
Servers can now be connected with a login and password: the panel
authenticates once, creates its own API token on the node (privsep=0) and
uses it from then on. The token can be revoked from the Proxmox UI, cannot
be used for SSH or web login, and appears in the PVE audit log under its
own name. The password stays stored (encrypted) because ProxmoxClient needs
it for SSH fallbacks such as pvecm delnode.

- add proxmox/token_provisioning.py: token creation with free-name
  selection and revoke-on-failure so a failed registration does not leave
  an orphaned token whose secret was never persisted
- POST /api/servers accepts auto_create_token
- add POST /api/servers/{id}/provision-token to migrate servers that are
  still on password auth
- store api_token_value as EncryptedString; it was kept in plaintext while
  the password next to it was already encrypted
- drop the unused ProxmoxServerBase schema, a stale copy of the create
  schema whose validator rejected the new auth mode

Node detail pages gain a Graphs tab (CPU, IO delay, memory, load average,
network, swap, root filesystem) built on the existing node rrddata
endpoint. The chart card is extracted from the instance graphs tab so both
views share it, and X axis ticks now switch to dates on multi-day ranges.
2026-07-24 04:03:30 +05:00
markmorado
b66424de12 chore: ignore .claude directory 2026-07-24 04:02:54 +05:00
markmorado
07af758f9a fix(nodes): show a loading state for the instances list
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled
The overview tab rendered "no data" while the VM list was still loading, so a
server with instances looked empty until the request came back. Gate the empty
state on isLoading and show skeleton rows instead.

Also add the missing nodes.instances_on_server key to both locales — the raw
key was rendered in place of the heading.
2026-07-24 03:18:22 +05:00
markmorado
ff1396142b fix(api): scope server listings to workspace, stop serialising Proxmox calls
/api/cluster/topology and /api/resources/all read every ProxmoxServer row
regardless of the caller access or the X-Active-Workspace header, so the
Cluster page listed all servers and dashboard aggregates counted the whole
panel instead of the active workspace. Extract the access + workspace filter
out of /api/servers into get_visible_server_ids() and apply it in all three.

Live metrics were also gathered server by server with the cache lock held
across the network calls, so a single unreachable cluster stalled the request
(21-31s in the logs) and concurrent requests queued behind it. Fetch in
parallel, skip servers already known offline, drop the redundant
is_connected() probe, and hold the lock only around the cache dict.

/api/resources/all now orders by server id: without it Postgres returned heap
order, which shifts whenever update_status rewrites a row, so the server list
reshuffled between requests.
2026-07-24 03:18:14 +05:00
markmorado
35a8a11bb5 docs: add commit message language and no-co-author rules 2026-07-23 23:23:45 +05:00
markmorado
4cdbed54e4 style(theme): add blue tint to dark theme surfaces
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Shift dark-theme background, card, popover, sidebar and border/input
tokens from neutral hue 286 (near-zero chroma) to a blue-graphite
hue 258 with higher chroma, so the panel reads as midnight-blue
instead of flat black.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 23:21:05 +05:00
markmorado
fca14828dc docs(wiki): expand RBAC guide and add full Russian WIKI.ru.md
Rewrite the RBAC/Security section with a detailed model: permission
format, engine evaluation order (admin bypass, wildcard, manage-implies),
requires dependencies, full permission catalogue, per-page permission
map, built-in role breakdown, and the ownership-based user isolation
(vm:manage, not vm:view, grants the global view). Fix stale references
(version 1.10.2, Networks needs server:manage, SSH keys user:manage).

Add WIKI.ru.md as a complete Russian translation mirroring WIKI.md,
including the expanded RBAC section.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 22:58:18 +05:00
markmorado
e67f6b7249 fix(update): recover from stalled panel self-update instead of hanging at 80%
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
The panel update status lived only in-memory and was cleared solely by the
host watchdog restarting the container. If the rebuild failed mid-way (e.g. the
build OOMs the host when no swap is configured), the container never restarted
and the UI stayed at "restarting - 80%" forever.

- update_service: get_update_status() now self-heals — after UPDATE_TIMEOUT_SECONDS
  (default 900s) of "is_updating" it transitions to a terminal "failed" state with
  a clear error pointing at the host update service / logs.
- use-settings: poll update status while the server reports is_updating (not only
  right after the click in the same tab), so reloading a stuck page keeps refreshing.
- SettingsPage: banner now renders the "failed" state with the error message.
- update_host.sh: build images sequentially (app, then frontend) to lower peak
  memory and avoid the OOM that killed the build mid-run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 22:57:41 +05:00
markmorado
ceec83d2fb docs: release notes and version bump for v1.10.2
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 22:22:10 +05:00
markmorado
06b61dae65 fix(templates): show clear message after auto-import instead of "undefined"
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Frontend read res.count but the auto-import endpoint returns imported_count,
so the toast showed "Импортировано: undefined". Read imported_count and show
a distinct message when no new templates were imported.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 22:15:02 +05:00
markmorado
3502a72a13 docs(claude): require English commit messages
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
2026-07-23 21:59:31 +05:00
markmorado
d0824df0f5 docs: release notes and version bump for v1.10.0
Document the command palette, reorganized instance menu/tabs, global
minimized-operations tray, owner-scoped live Proxmox resources, and the
React Query cache clear on login/logout; bump VERSION and README badges.
2026-07-23 21:59:24 +05:00
markmorado
0b0b11c689 feat(scripts): run script executions in background and poll for completion
Community scripts (build.func) install packages like Java/OpenSearch and
can take minutes, well past the nginx/proxy HTTP timeout. execute_script
now returns immediately with status "running" and finishes the job on a
background thread with its own DB session; the frontend polls
/api/scripts/executions/{id} every 3s while running.

Also set TERM=xterm for script execution over SSH — community scripts
call `clear` and print colored output, which fails with "TERM
environment variable not set" when run without a PTY.
2026-07-23 21:59:18 +05:00
markmorado
761bd7bca8 fix(workspaces): grant server access via workspace membership alone
Non-privileged users previously needed a server to be both directly
assigned AND inside one of their workspaces (intersection) to see or use
it. Adding a user to a workspace should be sufficient on its own to let
them create instances on that workspace's servers, so the two access
paths are now unioned instead of intersected.
2026-07-23 21:59:09 +05:00
markmorado
203ae8bdd6 fix(workspaces): stop filtering server list by active workspace in assignment dialog
The workspace edit dialog reused useServers(), which always sends the
X-Active-Workspace header, so admins assigning servers to a workspace
only ever saw servers already in the currently active workspace instead
of the full list. apiClient now lets a caller override the header, and
useServers(allWorkspaces) requests '0' (admin "show all") for that dialog.
2026-07-23 21:59:02 +05:00
markmorado
ef5b40b2f7 fix(nodes): не давать пустым полям учётных данных затирать токен/пароль сервера
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled
При редактировании ноды (например, при смене имени) форма отправляла
пустые api_token_name/api_token_value, т.к. секреты не возвращаются
с бэкенда. Бэкенд принимал их как явно заданные и затирал реальные
credentials, из-за чего немедленная проверка подключения падала и
сервер помечался offline. Теперь пустые значения при редактировании
трактуются как «не менять» — и на фронтенде, и на бэкенде.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 21:57:27 +05:00
markmorado
d3b834cbe1 feat(auth): сбрасывать активную workspace при имперсонации и возврате
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
При смене токена (вход под пользователем / возврат к админу) сбрасываем
выбранную рабочую область через setActiveWorkspace(null): выбор
предыдущей личности передавался в хедере X-Active-Workspace и мог не
принадлежать новой. Дополняет уже существующий сброс кэша React Query.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 05:37:23 +05:00
markmorado
43336c02c7 feat(auth): имперсонация — вход админа под пользователем и возврат обратно
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Backend:
- POST /api/auth/impersonate/{user_id} — только для админа, выдаёт JWT
  с клеймом impersonator; запрещает вход под собой, отключённым,
  другим админом и вложенную имперсонацию
- POST /api/auth/stop-impersonate — по клейму impersonator завершает
  сессию имперсонации и перевыпускает токен исходного админа
- /api/auth/me отдаёт поле impersonator для баннера в SPA
- аудит-лог: impersonate_start / impersonate_stop

Frontend:
- auth-store: действия impersonate/stopImpersonate со сбросом кэша
  React Query при смене токена
- UsersPage: кнопка "войти под пользователем" (только админу,
  скрыта для себя/админов/неактивных и во время имперсонации)
- AppLayout: баннер имперсонации с кнопкой "вернуться к администратору"
- локали ru/en

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 05:33:04 +05:00
markmorado
982522b8b5 fix(auth): очищать кэш React Query при login/logout
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
При входе под другим пользователем в той же вкладке React Query отдавал
закэшированные данные предыдущего пользователя (список инстансов и др.) до
жёсткой перезагрузки, из-за staleTime и отсутствия сброса кэша при смене сессии.

- queryClient вынесен из App.tsx в lib/query-client.ts (доступен вне React)
- auth-store вызывает queryClient.clear() при успешном login и при logout

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 05:22:14 +05:00
markmorado
42c6acd52e fix(instances): изоляция по владельцу для живых ресурсов Proxmox
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Список инстансов (/api/virtual-machines) уже фильтровался по owner_id, но
эндпоинты живых ресурсов Proxmox — /api/resources/all (дашборд) и
/api/{server_id}/resources (страница ноды/сервера) — отдавали все VM/LXC без
фильтра. Обычный пользователь (proxmox.view) через страницу ноды видел чужие
инстансы.

- _helpers: get_owned_vmids() — VMID, которыми владеет пользователь
- servers: get_server_resources / get_all_resources фильтруют VM/LXC по
  владельцу для не-привилегированных (сверка vmid с кэшем vm_instances);
  админы и роли с vm:manage видят всё
- assign_instances_owner.py: скрипт массового назначения владельца
  существующим инстансам (owner_id синхронизированных из Proxmox = NULL)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 04:56:17 +05:00
markmorado
25899866bc feat(appstore): глобальный трей свёрнутых операций, переживающий навигацию и перезагрузку
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 9s
Свёрнутые долгие операции (установка приложения, сборка золотого шаблона)
теперь живут в глобальном zustand-сторе (persist в localStorage) и
рендерятся треем MinimizedOpsTray в AppLayout, а не самим диалогом:

- плашка переживает навигацию между страницами и перезагрузку вкладки;
  прогресс опрашивает сам трей (REST, 3с) независимо от диалога
- клик по плашке возвращает на страницу операции и разворачивает диалог:
  установка — resume-режим InstallWizard (resumeInstall в navigation
  state), шаблон — openGolden с предвыбранным сервером
- «Свернуть» добавляет операцию в трей и закрывает диалог; крестик на
  плашке только убирает её (операция продолжается на сервере)
- плашки несуществующих операций (404 после перезагрузки) трей убирает сам

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 14:13:42 +05:00
markmorado
4621ffe88a fix(appstore): data files, надёжность установки/удаления и сворачиваемые диалоги
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 57s
Deploy to Production / Trigger production update (push) Successful in 8s
Доставка файлов приложения из каталога (data_files) до compose up,
APP_PASSWORD/default_credentials для Umbrel, сворачивание диалогов
долгих операций (MinimizableDialog), фильтрация pull-шума в ошибках.

Исправления багов:
- teardown: отсутствующий в Proxmox CT считается удалённым — orphaned-приложение
  теперь можно удалить из БД
- install: сдвиг VMID мимо занятых записей (nextid не резервирует номер,
  retry мог подхватить чужой контейнер)
- retry: параметры установки сохраняются в installed_apps.install_params
  (cores/memory/disk/storage/bridge/ip_config/port_explicit, миграция JSONB)
  вместо жёстких дефолтов
- reconcile: недоступный сервер больше не помечает все приложения orphaned
- update: реально опубликованный порт фиксируется в БД (url/health)
- .env: значения с '#' кавычатся (dotenv-парсер обрезал их как inline-комментарий)
- порт 80, выбранный явно в мастере, публикуется как есть
- useCatalog: available_only включён в queryKey (коллизия кэша)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 12:52:14 +05:00
markmorado
f22b24d86a fix(appstore): touch file bind-mounts instead of mkdir, breaking .env mounts
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
docker compose up failed for apps that bind-mount a single file (e.g.
AnythingLLM's .env) because _prepare_bind_mounts blindly mkdir -p'd every
bind-mount source, turning the file's path into a directory. Docker then
refused to mount a file onto that directory ("not a directory: ... mount
a directory onto a file"). File-looking sources (by name) now get touch'd
instead, with self-healing rm -rf for directories left over from prior
failed installs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-17 05:19:19 +05:00
markmorado
6a79dd2048 fix(appstore): DNS, per-server golden template, bind-mount perms, delete race
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m1s
Deploy to Production / Trigger production update (push) Successful in 8s
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>
2026-07-17 04:49:40 +05:00
markmorado
b8536ac2e8 feat(instances): command palette, unified nav, расширенное меню инстанса и правки табов
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
- Командная палитра (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>
2026-07-17 00:58:45 +05:00
markmorado
8ca33681ca feat(scripts): каталог bash-скриптов для нод и гостей (VM/LXC)
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 59s
Deploy to Production / Trigger production update (push) Successful in 8s
Добавлена библиотека скриптов по образцу 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>
2026-07-11 04:35:43 +05:00
markmorado
f2ee09ab5a polish(ui): пульсация статус-точки для online, моно-цифры в бейджах, fade-up анимация
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-11 04:35:29 +05:00
markmorado
db2f408d57 fix(core): пункты 5-10 аудита — UPID-синк, порт, бэкап all, IPAM, креды
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 8s
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>
2026-07-10 01:06:28 +05:00
markmorado
0efa5968ad fix(core): четыре критических бага — маршруты, очередь задач, логин, shutdown
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
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>
2026-07-10 00:58:40 +05:00
markmorado
e62626c79b fix(nodes): детерминированная сортировка списка серверов
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m0s
Deploy to Production / Trigger production update (push) Successful in 7s
Список серверов терял порядок при фоновом рефетче (каждые 30с),
т.к. запрос с WHERE id IN (...) не гарантирует стабильный порядок строк.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 00:40:17 +05:00
markmorado
3424823793 feat(cluster): режим eject "только панель" для нод, не входящих в кластер
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
При провале 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>
2026-07-09 03:36:55 +05:00