A "Snapshots" section on the info screen lists the snapshots, newest
first, without Proxmox's "current" pseudo entry. Keys:
- p takes a snapshot. The name defaults to tui_YYYYMMDD_HHMM, the
description is optional, and VMs can include RAM.
- R rolls back to the snapshot under the cursor. The confirm names the
snapshot and its date. A running guest is started again; its status
is read right before the rollback, and if it cannot be read the
rollback does not run.
- D deletes the snapshot under the cursor, after a confirm.
`delete ct|vm <node> <vmid> -y` without the snapshot subcommand
destroys the whole guest. delete_snapshot therefore validates the name
first (letter first, then [A-Za-z0-9_-], not "current"), writes
"snapshot" into the argv as a literal, and checks the argv shape
before running it. A property test covers rejected names.
The info screen now scrolls, because four sections do not fit short
terminals. A description starting with "-" is refused, since it is a
positional argument and could be read as an option.
Live test on CT 104: take, roll back (started again) and delete. The
snapshot list, status, config and IPv4/IPv6 match the baseline.
Closes#8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guest table marks with "!" each guest that Proxmox's not-backed-up
list returns. The frame's bottom border shows the count, e.g.
"mainframe · 2 without backup job". This uses Proxmox's own answer, so
it also counts jobs that select guests by pool.
If the coverage call fails, the guests are still listed and a warning
says the coverage is unknown.
Closes#9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new "Resources" section at the top of the info screen shows CPU
cores (with sockets for VMs), memory, swap for containers, and each
disk with its size. The disks are the same ones the edit dialog
offers, so cloud-init and CD drives are left out. A container without
a cores limit shows "unlimited".
The open info screen reloads after any guest job, so values edited
with e show up straight away.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enter on a guest now opens its info screen, replacing i. The guest
table shows Enter as "Info" in the footer. A priority binding at app
level would have taken Enter away from buttons and lists in the
dialogs, so the hint comes from the table's own binding instead.
Editing cores, memory and disk moved from the main screen into the
info screen (key e). When the edit dialog closes, you are back on the
info screen. Test helpers that pressed i or e on the main screen now
go through Enter, because the requirement changed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The info screen's style now applies everywhere. The guest table sits
in a "Guests" frame with the active context in its bottom border.
Every dialog is a centred box with a title, labelled fields and the
buttons bottom right: confirm (titled by the action), edit resources,
switch context, back up and edit network.
Fixed:
- The network dialog hid most of its fields. In Horizontal rows
Textual gave Select a width of 1 and Input 100 %, which pushed
bridge, firewall, the IP mode selects and the gateways off-screen.
Every field in a row now has an explicit width.
- A guest name or note containing markup, such as "a[/b]", crashed the
guest table and the dialogs, because DataTable cells and border
titles were parsed as markup. They are now plain text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Put backups and network in their own bordered sections titled
"Backups" and "Network". Inside Network, the configured settings and
the addresses in use are labelled "Configured" and "In use". The
"unavailable" note is hidden when it is empty, so it no longer leaves
a blank line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Press n in the info screen to edit one interface: bridge, VLAN tag,
firewall, IPv4 (DHCP, static or none) and IPv6 (SLAAC, DHCP, static or
none). The netN string is parsed, the chosen fields are changed and
the string is written back, so hwaddr, model=MAC, mtu, rate, trunks
and type are kept. For VMs, IP settings go to cloud-init ipconfigN and
only when the VM has a cloud-init drive.
A confirm shows the old and new raw values before anything is sent.
Press u to restore the values from before the last change to that
guest in this session.
Review fixes:
- Undo entries are cleared on a context switch, because VMIDs repeat
across clusters.
- has_cloudinit only looks at disks.
- CIDR needs a decimal prefix: no netmask form and no /0.
- Fields you did not touch are not rewritten.
Live test on CT 104: firewall, VLAN 99, IPv6 DHCP and static IPv4 were
each applied and undone, and net0 ended identical to the baseline.
Going from static back to DHCP left the CT without IPv4 until a
reboot, so the confirm now warns that IP changes on a running
container may need one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Proxmox ties backups to the VMID only, so a deleted guest's backups
were listed under the new guest with that VMID. CT 104 showed planka
backups next to debian's, and VM 108 showed vaultwarden backups.
Backups whose notes name another guest are now hidden by default. The
notes come from the job's {{guestname}}, so "debian (manual)" still
counts as debian. A line says how many are hidden, and the a key shows
them, marked "(earlier guest)". Backups without notes are always
shown.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Press i on a guest to see its backups and network. Backups from every
backup-capable storage are listed newest first, with the backup jobs
that cover the guest. The network part shows the netN settings
(bridge, VLAN, MAC, IPv4/IPv6 setting, firewall) and the addresses in
use.
Press b in the info screen to back the guest up now: snapshot mode and
zstd, like the scheduled job, to a storage you pick (the job's storage
is preselected). It asks for confirmation, marks the guest busy and
uses --wait.
Fixed after review and a read-only live check:
- prune-backups arrives as a JSON string; parsing it as a dict
crashed the app.
- CT addresses come from ip-addresses. inet6 holds only the
link-local address, so the global SLAAC address was missing.
- The info screen uses the guest's live status, and odd API data
(null size, unknown address types) no longer kills the app.
- The test fake now copies guest dicts; a shared constant was being
mutated across tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write ESC c, the sequence `reset` sends, inside suspend() right before
ssh. The container shell then starts on a clean screen with no
leftover TUI terminal modes. It runs locally, so the container does
not need `reset` installed and `pct enter` is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Press t on a running container to suspend the TUI and run
`ssh -t root@<node> pct enter <vmid>`. cv4pve-cli has no shell or exec
for LXC, so this goes around it and needs key-based root SSH to the
PVE node.
- VMs, stopped containers and busy guests get a warning instead.
- Only exit code 255 (ssh failed) is reported as an error. Other codes
are the last status of the container's shell.
- OSError is caught inside suspend(). Textual's suspend() has no
try/finally, so an exception escaping it would leave the app
suspended.
- The guest table reloads when the shell returns.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Press c to list cv4pve-cli contexts and switch between them. The
active context is always shown in the header.
- Switching runs `cv4pve-cli config use`, which changes the global
current context. cv4pve-cli 2.4.0 has no per-call context option.
- `config list` has no JSON output, so its text lines are parsed.
- The guest table is cleared as soon as another context is chosen, so
the old cluster's guests cannot be acted on.
- A generation counter drops guest listings that started before a
switch, and g and c are refused while a switch runs. Without this,
a reload already in flight could refill the table with the old
cluster's guests, and VMIDs collide across clusters.
103 tests pass. The switch was tested live from mainframe to
mainframe-edge and back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
List VMs and LXC containers from the current cv4pve-cli context and
start, shutdown, stop and reboot them, change cores and memory, and
grow disks. The app shells out to `cv4pve-cli -o json` and stores no
credentials.
- Every mutating call uses --wait: without it cv4pve-cli exits 0 even
when the task fails.
- shutdown, stop and reboot need confirmation; disk growth is
increment-only and asks again because it cannot be undone.
- After an action the acted-on guest's status is read from
status/current, because /cluster/resources lags a few seconds.
- Notifies when a cores/memory change is pending until reboot.
Tests mock cv4pve-cli (85 tests). Live-tested edit, shutdown, start
and reboot on CT 104 (mainframe), restored afterwards; disk resize
was not run live.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>