Commit Graph

23 Commits

Author SHA1 Message Date
abc819294c fix(images): unblock guest-exec in RHEL-family cloud images
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 1m45s
Deploy to Production / Trigger production update (push) Failing after 12s
SonarCloud / SonarCloud Analysis (push) Failing after 3m3s
The RHEL-family qemu-guest-agent package starts the agent with an allow-list
that omits guest-exec, guest-exec-status and guest-file-* (FILTER_RPC_ARGS in
/etc/sysconfig/qemu-ga; older packages spelled the same restriction as
BLOCK_RPCS or BLACKLIST_RPC). The agent answered "The command guest-exec has
been disabled for this instance", so running scripts in a VM, assigning extra
IP addresses and growing the filesystem after a disk resize did not work on
Rocky Linux, AlmaLinux, CentOS Stream and Fedora guests.

- patch-cloud-images.sh: clear all three variants while building the mirror
  (UNBLOCK_RPC=0 opts out) and add an ONLY filter to rebuild only part of the
  catalog. Three `[ ... ] && ...` statements that aborted the script under
  set -e are now plain ifs -- the one before mirrors.json generation killed
  every run that passed BASE_URL
- builtin.py: point the five RHEL-family amd64 entries at the rebuilt mirror
  release 2026-08-22 with their new checksums. Ubuntu and Debian images are
  unaffected and stay in the previous releases, so older panel versions keep
  working
- client.py: annotate the Proxmox error with what to clear inside the guest,
  the raw message names neither the file nor the variable
- WIKI, CHANGELOG: document the restriction and the unblock command
2026-08-22 14:03:49 +05:00
6ac505e481 fix(proxmox): send guest-agent scripts as bytes
Proxmox base64-encodes the input-data of an agent exec in Perl, which dies
with "Wide character in subroutine entry" as soon as the payload contains
non-ASCII — a Cyrillic comment in a script is enough, so running any such
script on a VM failed with a 500.

Hand the same UTF-8 bytes over as latin-1: the JSON carries plain bytes,
Perl is happy and the guest still receives valid UTF-8.
2026-08-22 01:35:56 +05:00
c9d8e8207f fix(proxmox): read LXC addresses from netN and live interfaces
get_container_interfaces() looked for ipconfigN keys, which exist only on
QEMU cloud-init guests. LXC keeps the address inside the netN string, so
the method never returned anything and containers showed no IP at all.

Parse netN with the existing net_parser, fall back to
/nodes/{node}/lxc/{vmid}/interfaces for DHCP guests (skipped when the
config already carries a static address or the container is stopped), and
validate addresses so loopback, link-local and the literal "dhcp" are
dropped. IPv6 from ip6/inet6 is reported as well.
2026-08-21 23:47:45 +05:00
markmorado
943207b6b7 fix: support moving LXC container disks to other storage
Disk move was hardcoded to the QEMU move_disk Proxmox API and was
never reachable in the UI for LXC (no Hardware tab for containers,
and the disk list regex only matched VM device names).

- add move_container_disk() using lxc/{vmid}/move_volume
- add POST /api/{server_id}/container/{vmid}/disk/move endpoint
- route useMoveDisk by instance type (vm vs container prefix)
- recognize rootfs/mp\d+ as LXC disk devices
- add a Move disk card on the Settings tab for LXC instances
- filter target storage list by supported content type
  (rootdir for LXC, images for VM) instead of showing all storages
2026-08-20 05:29:28 +05:00
markmorado
73493d7ef2 Add active tasks indicator, propagate LXC create errors, fix Fedora logo
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 1m24s
Deploy to Production / Trigger production update (push) Failing after 10s
- Surface a topbar indicator with a live count of active tasks
- Propagate exceptions from Proxmox LXC container creation instead of
  swallowing them, and validate minimum password length
- Replace the Fedora catalog icon with the official logo artwork
2026-08-18 23:34:32 +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
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
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
00e36e1cc6 feat: Proxmox management suite — hardware, firewall, pools, disks, storage, access, node admin
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 54s
Deploy to Production / Trigger production update (push) Successful in 7s
- VM/LXC hardware editor with PCI/USB passthrough (BIOS/OVMF + efidisk,
  machine type, VGA, SCSI controller, CPU sockets); passthrough locked while running
- Firewall at datacenter/node/VM levels: rules, security groups, IP sets,
  aliases, options, log — with rule dialog referencing security groups
- Resource pools (CRUD + membership) and per-instance tags editor
- Node disks: physical disk list, SMART viewer, ZFS pool create/destroy, wipe
- Storage: add LVM/LVM-thin/ZFS/RBD/CephFS types + enable/disable toggle
- PVE Access: API tokens (create with one-time secret, delete) and realms (LDAP/AD/OpenID)
- Node admin: systemd services (start/stop/restart), APT updates & repositories
- Shared: SelectTrigger defaults to full width (fixes narrow dropdowns)

Also bundles related in-progress work: auth screen refresh, node shell console
page, server-updates badge, and node:*/access:* RBAC permissions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 05:40:52 +05:00
markmorado
5c8baefb3f feat: add firewall, pools, access, disks, node admin and VM hardware management
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m0s
Deploy to Production / Trigger production update (push) Successful in 7s
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>
2026-07-04 00:02:15 +05:00
markmorado
c12fbf13e5 feat(instances): add VM/LXC migration, autostart/boot order, protection
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 52s
Deploy to Production / Trigger production update (push) Successful in 7s
- 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
2026-07-03 02:40:58 +05:00
161182b392 feat(api): support netN add/remove in VM and LXC config updates
- update_vm_config: whitelist netN/scsiN/virtioN/ideN/sataN/ipconfigN by
  regex instead of hardcoded 0-3; accept validated delete='netN' key;
  raise with real Proxmox error text instead of returning False
- update_container_config: refactor to dict signature with whitelist +
  netN + delete (fixes LXC config PUT endpoint that passed the whole
  dict as hostname)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 02:32:21 +05:00
7d52297f76 fix(deploy): apply VM config reliably after clone
- wait for clone lock release before config.put (cross-node clones kept
  lock past wait_for_task, dropping ALL requested settings silently)
- configure_vm applies params in independent groups (compute/network/
  cloudinit/disk) with per-group errors and lock retry
- set sockets=1 with cores so total vCPU matches request
- keep template net0 model/MAC/options, replace only bridge
- disk resize: pick boot disk via regex over all buses, report failures
- surface config errors as deploy warnings in UI toast instead of
  silent success

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 02:31:21 +05:00
c7edf72d19 feat(images): Phase 2 — auto-convert qcow2 to VM template
- client.create_vm_with_import: API-only disk import via scsi0 import-from (PVE 8.2+)
- _do_image_template_sync worker: download(import) -> create+import -> cloud-init
  -> convert_to_template -> register OSTemplate (Cloud Images group)
- images download endpoint: to_template branch + cloud-init/disk_storage params
- clear fallback error when storage lacks import support (file kept)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 23:11:20 +05:00
f67ee24155 Merge branch 'feature/metrics-history'
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 50s
Deploy to Production / Trigger production update (push) Successful in 7s
2026-06-22 02:47:45 +05:00
38d485be4b fix(disk-resize): honest task status, auto-grow FS, CRLF-safe guest exec
Backend fixes for VM/LXC disk resize:
- resize_vm_disk/resize_container_disk now honor wait_for_task and raise
  the real Proxmox exitstatus (e.g. "disk 'scsi0' does not exist") instead
  of always returning success.
- add grow_vm_filesystem: after a VM resize, rescan the disk (retry loop,
  needed for SATA/SCSI), growpart the partition and resize the FS
  (ext*/xfs/btrfs) via the guest agent; surface its output to the API.
- execute_script normalizes CRLF/CR to LF so pasted scripts and growpart
  don't break on trailing \r ("partition-number must be a number").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 02:43:03 +05:00
8f9f78ef91 feat(metrics): add blockstats + netstat client wrappers 2026-06-21 21:35:02 +05:00
d66928ee78 refactor(proxmox): unify ProxmoxClient construction via from_server
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 48s
Deploy to Production / Trigger production update (push) Successful in 8s
Collapse four duplicated host+auth client-building blocks into a single
ProxmoxClient.from_server() classmethod (the canonical source of truth):

- _helpers._get_proxmox_client now delegates to from_server (107 callers
  untouched)
- ipam._build_proxmox_client removed; its one call site uses from_server
- task_queue_service keeps its per-server cache pool, builds via from_server
- monitoring_worker keeps its ValueError-on-missing-auth contract, builds
  via from_server

Behaviour preserved (token-first, then password; non-default port appended).
Verified: containers rebuild healthy, smoke test of both auth paths passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 22:30:57 +05:00
508be2423a refactor(proxmox): extract _wait_exec_status helper from execute_command
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Move the guest-agent exec-status polling loop into a shared _wait_exec_status
method reused by execute_command and execute_script. No behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:14:35 +05:00
681aa2f303 feat(backups): restore target node/storage selection + task progress tracking
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m6s
Deploy to Production / Trigger production update (push) Successful in 8s
Add target node and storage overrides to single and bulk restore flows, and
track Proxmox task progress (parse_task_progress in the monitoring worker,
new ProxmoxTask progress column + migration, enriched task API responses).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 21:26:01 +05:00
2e8558fa51 fix(backend): restore operations — add force param, fix QEMU restore API
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 47s
- restore_vm/restore_lxc: add force=True param (needed for in-place overwrite)
- QEMU restore: remove `restore: 1` from params (breaks Proxmox API — restore
  is triggered by archive presence alone, unlike LXC where restore: 1 required).
  This fixes both single and bulk QEMU restores.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 16:32:23 +05:00
50f2ee1966 fix(security): authenticate VNC/terminal WebSockets and harden SSH/config
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 46s
Critical security and robustness fixes from a code audit:

- WS terminal/VNC now require a JWT (?token=), validate the session,
  vms.console permission and VM ownership before bridging to Proxmox
  (previously the LXC terminal gave unauthenticated root shell access).
  Frontend ConsolePage passes the token in both WS URLs.
- Fix SSH fallback for `pvecm delnode`: SSHClient now supports password
  auth (it previously crashed with TypeError); ProxmoxClient stores the
  password for SSH fallbacks and the host port suffix is stripped.
- Add production startup warnings for default ADMIN_PASSWORD and wildcard
  CORS_ORIGINS.
- dashboard: use tz-aware utcnow() instead of naive datetime.utcnow().
- crypto: narrow decrypt_value except to InvalidToken and log failures.
- ssh_client: guard the shared connection cache with a lock; make
  unknown-host-key rejection opt-in via SSH_REJECT_UNKNOWN_HOSTS.
- logging: send loguru console output to stderr instead of stdout.
- Sync version fallback to 1.5.1; remove one-off refactor scripts.
- Add CODE_REVIEW.md audit report.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 06:31:26 +05:00
bfd92102cf Refactor backend: Split models and proxmox_client into modules, add alembic
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Failing after 2m27s
2026-06-13 03:53:27 +05:00