DuckbootandClaude Opus 5.5 792667897a
CI / pytest and ruff (push) Successful in 5m19s
Add a node script that shrinks a container's root disk
scripts/pct-shrink-rootfs runs as root on the Proxmox node and keeps
the VMID. Without --yes it only measures and prints the plan.

It adds a temporary mp9 of the new size (Proxmox allocates and formats
it), rsyncs the root disk into it, and swaps it into rootfs under
Proxmox's config flock. The config is written like
file_set_contents does on pmxcfs (tmp file, then rename), after
checking that rootfs and mp9 did not change during the copy. The old
volume is kept as the first free unusedK and the exact delete command
is printed; pct rescan is not used, so other orphans of the VMID are
not pulled in.

It refuses snapshots and pending sections, a lock, template,
protection, HA, replication, any mount point, and sizes the data does
not fit (10 % headroom on top of the ext4 reserve and metadata, and an
inode check). On an rsync failure the new volume is freed by its volid.

Tests run the real script against stub pct, df, rsync, flock,
ha-manager, pvesr and id. README documents both shrink routes.

Design: docs/plans/lxc-shrink.md (section B).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 19:58:02 +01:00

cv4pve-cli-tui

CI

Textual TUI for cv4pve-cli: list Proxmox VE guests (VMs and LXC), start/shutdown/stop/reboot them, and change cores, memory and disk size. The table shows CPU % and Mem % of running guests and the info screen shows in-use values (refresh with g).

It shells out to cv4pve-cli and uses its current context (cv4pve-cli config use <name>); it stores no credentials itself. Tested with cv4pve-cli 2.4.0; with another version the app warns at startup, because it parses output formats that are not a stable API.

Install

Needs uv and a working cv4pve-cli on PATH.

uv tool install git+https://git.duckboot.net/Duckboot/cv4pve-cli-tui
cv4pve-tui                      # from any directory
uv tool upgrade cv4pve-tui      # later: get the newest main
uv tool uninstall cv4pve-tui

From a local checkout instead: uv tool install . (add --force to reinstall after changes).

Run

Installed: cv4pve-tui. From a checkout without installing:

uv run cv4pve-tui
Key Action
s start
S shutdown (confirm)
x stop - hard power-off (confirm)
r reboot (confirm)
Enter info: resources (CPU, memory, swap, disks), backups, backup job, network (config and runtime IPs)
Enter then e in info: edit cores / memory / grow a disk (disk growth asks again; it cannot be undone)
Enter then b in info: backup now (snapshot, zstd, storage choice); a there = also show backups of earlier guests that had the same VMID
Enter then n in info: edit network (bridge, VLAN, firewall, IPv4/IPv6; VM IP via cloud-init at next boot); u there = undo the last network change of this guest (this session only)
Enter then o in info: edit autostart, startup order (order, up and down delay) and tags (one confirmed set config call; empty fields remove the setting)
Enter then p / R / D in info: take a snapshot (name, description, VM: include RAM) / roll back to the snapshot under the cursor (confirms; starts the guest again if it is running) / delete the snapshot under the cursor (confirms)
Enter then f in info: fstrim in a running VM with the guest agent enabled (confirms; containers: use pct fstrim on the node)
Enter then r in info: restore the backup under the cursor, as a new VMID (default, the original stays untouched; a copy keeps the original's network settings, so leave Start off until they are changed) or overwriting the guest itself (stopped guests only; type the VMID, then confirm); container backups: optional smaller root disk, see Shrinking a container's root disk
t shell in a running LXC container (ssh -t root@<node> pct enter <vmid>)
l tasks: recent cluster tasks (start, duration, node, type, VMID, user, status; ! marks failures); Enter shows the log of the task under the cursor, g reloads. In info: l = only this guest's tasks
U package updates: pending updates per online node (node, package, current, new, origin, priority), read-only; g reloads. The list is as of the node's last apt update. The frame's bottom border shows the count
g refresh
/ filter the guest table as you type: space-separated terms, all must match (case-insensitive); plain term = part of name, VMID or a tag; is:running / is:stopped; type:lxc (or ct) / type:vm (or qemu). Enter keeps the filter and returns to the table, Escape clears it. The frame's bottom border shows filter: <text> · N of M
c switch cv4pve-cli context (cluster)
q quit

Warning: link changes (bridge, VLAN, firewall) apply immediately on a running guest and can cut its network (and DNS for others if the guest is your DNS server). IP changes on a running container may need a reboot of the container (seen: static -> DHCP gave no IPv4 until a reboot).

The shell key needs key-based root SSH to the PVE node (LXC only).

Switching context runs cv4pve-cli config use, which changes cv4pve-cli's global current context: other shells and scripts follow, and it stays after the app exits.

A ! in the first column marks a guest that no backup job covers (Proxmox's not-backed-up list); the frame's bottom border shows how many.

Empty fields in the edit dialog are left unchanged. If a CPU/memory change cannot be hot-plugged, the app tells you it applies at the next reboot.

Shrinking a container's root disk

Proxmox only grows disks. Two ways to get a smaller container root disk, both dangerous; take a backup first and test on a throwaway container.

In the TUI (Enter, then r on a container backup): fill in Root disk GiB. This restores the backup as a new guest with a new, smaller root disk (Proxmox's "advanced restore mode"); overwriting the original with a smaller disk is refused, because Proxmox deletes the old disks before it unpacks the backup. In this mode every mount point (mpN) of the backup is dropped: files of mount points with backup=1 land inside the root disk, backup=0 ones are not in the backup at all. Raw lxc.* lines (bind mounts too) can come back if cv4pve-cli runs as root@pam, so do not run both guests at once. A disk that is too small makes the restore fail; the original is untouched.

On the node (root shell, container stopped, keeps the VMID):

scripts/pct-shrink-rootfs <vmid> <new-size-GiB>         # measure and print the plan
scripts/pct-shrink-rootfs --yes <vmid> <new-size-GiB>   # do it

It adds a temporary mp9 of the new size (Proxmox allocates and formats it), copies the root disk into it with rsync, then swaps it into rootfs under Proxmox's config lock. The old root disk stays as an unusedK volume until you delete it with the exact pct set <vmid> --delete unusedK the script prints; the old config is copied to /root/pct-shrink-<vmid>-<timestamp>.conf. It refuses containers with snapshots, pending changes, a lock, template or protection flag, HA, replication, or any mount point (mpN, lxc.mount.entry), and sizes the data does not fit with headroom (5 % ext4 reserve, metadata, inodes). chattr flags (+i, +a) are not copied. Even the dry run mounts the container briefly (pct mount). Design: docs/plans/lxc-shrink.md.

Development

uv sync
uv run pytest
uv run ruff check src tests && uv run ruff format --check src tests

Tests mock cv4pve-cli; they never touch a cluster. CI (.gitea/workflows/ci.yaml) runs the same commands on every PR into main; ruff is pinned in the dev group so local runs and CI check the same rules. Design: docs/plans/guest-tui-mvp.md.

S
Description
No description provided
Readme
1.3 MiB
0 Stars 1 Watchers 0 Forks
Languages
Python 98.1%
Shell 1.9%