The VM lists lose their inline scripts and handlers: host_groups.js
collapses a host's VMs in the grouped list, new_vm_dialog.js reads the
new-VM dialog's CPU bars and capacity lines, and console_window.js
(loaded by every page) opens a console button's window, on the lists and
on the VM page alike. A list row's Start no longer calls the please-wait
dialog, which the list pages do not have (the call only raised an
error). The VM page's URL placeholders take the __name__ form the other
pages use.
Deleting or detaching a disk, deleting a network card, forcing a VM off,
reverting or deleting a snapshot, stopping or deleting a pool, a
network, an interface, a filter or a secret, and the other actions that
ask first opened the browser's yes/no box (confirm()), and the ISO
upload told its mistakes in the browser's alert().
One dialog in the base page now asks for all of them: its title and
confirming button carry the button's own words, its body the button's
question, the confirming button red for a destructive action. Confirmed,
the button is clicked again, so its form sends what it did before. A
button inside another dialog (the flavors) hides that one while asking
and shows it again after; Cancel gives the focus back, and the
confirming button acts once. The ISO upload's mistakes show in its
dialog's error box, announced.
- The state filter is a row of pills, All and each state, counting the
VMs the search finds (the chosen state aside); a state without any is
hidden unless chosen (All never), and a status line tells screen
readers how many VMs match. Every state keeps its pill.
- A labelled "New VM" button replaces the bare green plus; "Find IP"
says "Find IP / MAC", which it finds.
- States are badges; a shut-off VM is grey, not red: it is not a fault.
- A VM's cell holds its name, its title, and for those who see owners
its first owner as a badge, "+N" for the others (named for screen
readers and on hover); the separate user column goes.
- Each row has the same button group for a superuser or the VM's
owners, from the actions the user may use (states.allowed_actions),
all of it disabled on a VM an administrator paused; view-only users
get none. It holds Console, the power action
the state calls for (Start, Resume, Shut down, or Clone for a
template) and a menu of the others (Suspend, Force off, Power cycle),
what does not apply now disabled. The power button is an icon,
named on hover and for screen readers, so every group is as wide and
they line up from row to row; the power cut confirmations stay. On a
phone Console shows its icon only too.
- A grouped host's row has its name, a Connected or Not connected
badge, its VM count and a labelled host memory bar; an unreachable
host's row is table-warning. Its collapse control and the one for
all hosts are buttons, with aria-expanded kept.
- vCPUs and memory hide on a phone in both layouts, and table cells
keep Bootstrap's own padding there: Zephyr doubles it and a list's
last column no longer fit the screen.
- The VM list's power forms (style="display:inline") are d-inline.
- The fields scripts show and hide are d-none, and the scripts add and
remove that class instead of calling jQuery's show() and hide(),
which could not undo it: the custom memory boxes of the Resize tab,
the ISO upload's error message and the clone dialog's metadata row.
- The please-wait dialog's full bar is w-100.
- The create-VM pages' own 56rem width (.create-vm) goes: pages stop
at 960px now, about the same.
- static/css/font-awesome.min.css goes: no page loaded it, no element
used its classes and its fonts were never in the repository.
The VM page offered a lite and a full VNC console. Lite lacked a clipboard,
display settings and a way to reconnect; full put noVNC's own side bar under
the panel's bar, with a Fullscreen item that called a function noVNC does
not have, status messages hidden behind the bar, saved noVNC settings that
overrode the Access tab's, connection settings that cannot apply, and a
Connect button that reused the page's two-minute token and failed.
console-vnc.html and static/js/console_vnc.js replace both, on noVNC's RFB
with Bootstrap controls, and keep what the full view did:
- Status in the bar (Connecting, Connected, Disconnected, Connection lost,
Could not connect, Authentication failed with the server's reason on
hover); Disconnect, then Reconnect, which loads the page again for a new
token.
- The VNC password in a dialog (with a username when the server asks for
one), not a browser prompt; without passwordless console it is not in
the page.
- Send key(s) gains Hold Ctrl / Alt / Windows (noVNC's extra keys).
- Clipboard: what the VM copies, sending text to the VM's clipboard, and
typing it key by key (new: works in firmware, installers and login
prompts; Shift for the characters a US keyboard shifts, 25 ms a key as
firmware drops faster keys, verified in a UEFI shell).
- View: scaling (none, fit, resize the VM's screen), clip, drag a clipped
screen, view only, dot cursor, quality, compression; it starts as
Settings > Console says (a touch screen starts fitted).
- A Keyboard item on touch devices (noVNC's on-screen keyboard input,
key events and Android's text-only input), Fullscreen with keyboard
lock, the bell.
Dropped with the full view: noVNC's websocket host/port/path, repeater ID
and log level (the panel fixes them), automatic reconnect (the token is
single use in time), XVP power buttons (QEMU has no XVP) and shared-mode off.
The bar is compact (about 45 px in the 850x600 window). The Access tab has
one Console button instead of the Lite/Full split and four switches, and
it and the VM list open one window per VM (opening it again reloads it).
The console page is /console/<compute>/<uuid>/ with the view and display
options in the query. It was /console/?token=<compute>-<uuid>, a "token"
that was only the VM's address, parsed alongside a signed token that no
link ever sent. The list's console button takes the VM's UUID from the
database instead of asking libvirt for each row, and no longer defines a
global function per row.
In the VM lists, Force Off and Power Cycle ran on a single click,
though both cut the VM off as a power failure does. Each button now
asks first, naming the VM and saying that what the guest has not
written to disk is lost.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The instance lists, the VM page header and the power tab knew three
libvirt states: running, paused and shut off. A VM that was blocked,
shutting down, crashed, suspended by its guest or without a state got
an empty status cell and no actions, so a crashed VM could not even be
forced off from the list. The lists also offered actions users could
not use: Suspend and Resume (views for superusers) to everyone, and
power actions to users who see every VM through the read-only
view_instances permission.
instances/states.py holds the rules in one place: the label and color
of each state, the actions each state allows, and which of them a user
may use (superusers all; a VM's owners all but suspend and resume, and
nothing on a VM an administrator suspended, as the VM page already
showed; nobody else any). Blocked is a running VM; shutting down,
crashed and suspended by the guest get Force Off, after which the VM
can be started. A shut-off template offers Clone to whoever has the
clone permission, as the clone view allows.
The templates read them through two tags (vm_states): the lists and the
VM page header show the state, instance_actions.html has one slot per
button, each enabled or disabled from the allowed actions. The power
tab offers Force Off in the states that need it.
The new tests check the rules directly and render every state in the
lists and on the VM page for a superuser, an owner and a
view_instances user; they fail on the previous code.
The instance lists read each VM from libvirt while rendering. When that
failed, the libvirt error replaced the whole page with the error page:
one VM removed out of band, or a host that is down, took the index or
a compute's instances page with it. To avoid that, both index views
left out every VM of a host that was not connected, so users saw their
VMs disappear.
- Instance.info is None when the VM cannot be read. The row then shows
the name and owners from the database, the state "Unknown", and no
title, vCPU, memory or actions.
- Both index views list the VMs of a host that is down. The grouped
view marks the host "Not Connected" and leaves out its CPU and memory.
- A compute's instances page shows the connection error, and no longer
says the hypervisor has no instances when it cannot be reached.
Checked against the test hosts with an unreachable compute added: both
index views list its VM as unknown next to the real VMs. The first
load takes 5.5 s (one bounded connection attempt), the next ones
0.1 s. The new tests fail on the previous code (VMs left out, error
pages).
The VM rows of the instance lists used instance.proxy.instance.info in
every state check, the vCPU column and the action buttons. A template
calls the method on each lookup, so every row made 7 virDomainGetInfo
RPCs (8 on a compute's instances page), and the memory column read the
domain XML once more.
- Instance.info reads virDomainGetInfo once per request; the lists and
instance_actions.html use it.
- The memory column of both index views comes from the same info
(current memory) instead of the domain XML. The value is the same:
checked against currentMemory for every running and shut-off VM of
the test hosts.
A row now makes one info call and one XML read (the title). The new
test counts the calls in the grouped and non-grouped index and on the
compute instances page; it fails on the previous code with 7 and 8
calls.