check_user_quota added up the vCPUs, memory and disks of the user's
VMs, but skipped a VM whose host failed a TCP probe. A host that was
down therefore let users exceed their quota, and the probe always failed
for ssh computes named by an ssh_config alias or reached through
ProxyJump, so their VMs were never counted. A VM that could not be read
turned the page into the error page instead.
- Hosts are checked with Compute.status, the connection WebVirtCloud
uses, once per host. A VM that cannot be read (host down, VM gone)
makes the usage unknown: clone and resize up are refused with their
own message (fail closed).
- A request that adds nothing is not checked, so a user over quota can
still shrink a VM. Users without limits, and an exceeded instance
count (from the database), need no host either.
- Memory resize of a running VM changes only the current memory, but
the quota was charged with the submitted maximum. It is now charged
with no change, and resize_mem gets the current maximum, so a VM that
shuts down meanwhile cannot take an unchecked one.
- The VM page no longer computes the quota on every load (it read every
VM of the user on every host for a "quota reached" banner). The limit
is reported when a change is refused.
The test that expected a down host to pass the quota now expects it to
be refused. Checked against the test hosts: with a VM behind an
ssh_config alias the previous code counted 29 vCPUs, the new one 31;
with a VM on an unreachable host the previous code allowed +1 vCPU,
the new one refuses it after 5.1 s and allows -1 at once. The new
tests fail on the previous code, except the ones guarding unchanged
behaviour.
The instance list showed every user an alert for each compute that was
not connected, with the compute's name and libvirt's error text. That
text names the host and how it is reached (for example "ssh: connect
to host 10.20.30.132 port 22: No route to host"), while the list hides
host names from users who are not administrators.
- Superusers and users with the global view_instances permission see
each unreachable host and its error, as before.
- Other users see one alert without host details, and only when a host
of their own VMs is down. It explains why those VMs show as unknown.
- The alerts' close button works (data-bs-dismiss was "modal").
Checked against the test setup with an unreachable compute that holds a
user's VM: the user sees the VM as unknown and the alert, but no host
name, address or error text; a superuser still sees them. The tests for
the user 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.
libvirt has no timeout for opening a connection. Measured in the test
setup: an unreachable host blocked qemu+tcp for 135 s and qemu+ssh for
133 s; a daemon that accepts and never answers blocks forever. Gunicorn
runs sync workers and the instance list connects to every compute, so
one unreachable compute held a worker for minutes per page load.
- A connection is opened in a helper thread, at most one per
connection at a time. The request waits LIBVIRT_CONNECT_TIMEOUT
(default 5 s). An open nobody waits for any more keeps running; until
it ends, requests get its error at once, and if it succeeds later the
connection is used. A failed open is not repeated for
LIBVIRT_RETRY_AFTER (default 30 s). A stuck host holds one thread and
does not keep other hosts from connecting.
- qemu+ssh runs ssh through vrtManager/libvirt-ssh (the URI's command
parameter), which adds ConnectTimeout=10 and BatchMode=yes, so an
abandoned ssh process ends and no prompt can hang. The user's ssh
configuration (aliases, ProxyJump, keys) still applies.
- The close callback acts only for the connection it was registered
for: a late callback of a replaced connection dropped its successor.
The reason is reported as text. A connection that closed before it
was published is an error.
- Compute.status is a bool (it returned the exception object, so the
"host is down" check in refresh_instance_database never fired); the
message is Compute.connection_error.
Unit tests cover the timeout, retry delay, late success, single open,
a stuck host next to a healthy one and the close callback. Live tests
(vrtManager/test_live_connection.py), for TCP and SSH computes of the
test setup: an unreachable address (no ssh left after 10 s), an endpoint
that never answers, a slow open completing later, a host that goes
silent on an established connection (keepalive ends calls within 45 s,
the next request reconnects), an ssh_config alias and a ProxyJump host.
Creating each option on a RHEL qemu-kvm host showed:
- CD-ROM: the create page offered every disk bus, but the empty CD-ROM
of a new VM works only on ide, sata and scsi. fdc and virtio failed
("Invalid bus type", "does not support ejectable media"), usb failed
with a device named 'Nonea' because vol_dev_type() had no prefix for
usb, and after that libvirt refuses an empty usb disk. Only ide, sata
and scsi are offered now, and another value is refused before any
storage is allocated. vol_dev_type() names usb disks sdX, which also
fixes data volumes on the usb bus.
- USB controller: any input device added a bare <controller
type='usb'/>, which libvirt turns into piix3-uhci (USB 1.1) on q35
instead of its default qemu-xhci. The bare controller is gone; libvirt
adds the machine's default for USB inputs.
- MACs: with more networks than MAC addresses, create_instance indexed
past the list and the request failed with a 500. NICs without a given
MAC now get one from libvirt. MAC addresses are validated (format, not
more than networks) by the page and the API before anything is
created; they went into the XML unchecked.
Unit tests cover the refused values, the MAC rule and the usb prefix.
Live tests create a VM with every offered CD-ROM bus and start it,
check the USB controller with a USB input device and create a VM with
two networks and one MAC.
- change_network detached the NIC and attached one built from scratch,
dropping its QoS, link state and other settings. It now edits the NIC
of the persistent definition in place and defines once; a running VM
gets the change at its next start, as the UI already says.
- add_network, delete_network and set_link_state did nothing on a
paused VM, and set_link_state rewrote the persistent NIC from the live
XML. They now update the running definition when the VM is active and
the persistent one always, each from its own XML.
- Boot and console edits used xml.etree, which renamed the namespace
prefixes of other tools' metadata (<app:info> became <ns0:info>); they
use lxml now.
- The NIC table and the clone form are filled from the persistent
definition (Instance.config_networks, config_disks), so a pending NIC
change is shown and can be edited again.
A live test runs 18 domain edits on stopped, running and paused VMs
whose definition has elements WebVirtCloud does not manage, and checks
for each the effect, that nothing else in the persistent definition
changed, and that persistent-only edits leave the running VM alone.
SPICE was removed earlier; its leftovers and the console type choice go
too:
- the console settings form, update_console and the backend no longer
offer or change the type; an invalid console form now shows its
errors instead of being ignored;
- the create form, the API serializer and create_instance no longer take
a graphics type, new VMs get VNC; get_graphics_types and the graphics
entries of the domain capabilities are gone;
- migration appsettings.0013 deletes QEMU_CONSOLE_DEFAULT_TYPE;
- a VM defined elsewhere with another graphics type gets "Console type
... is not supported".
The locale catalogs still reference the deleted SPICE templates in
source comments; regenerating them is left to the translation work.
The edit form posts net-*-<n> fields for NIC n and carries only the
new MAC. The backend read index 0 and looked the NIC up by the new MAC,
so editing a MAC detached nothing and attached a second NIC, and edits
of any NIC but the first were applied with empty values.
The form now also posts the current MAC (net-old-mac-<n>). The view
reads the submitted NIC's fields, validates the new MAC and reports
errors. The backend replaces the NIC with the old MAC, refuses an
unknown one, and on a failed attach restores the old NIC and raises
instead of reporting success.
The view crashed with a TypeError without a Referer header; it now
returns to the instance page, and a Referer from another site is
ignored.
compute_graph (text/javascript) and the machine type, disk bus, video
model and domain capability views (text/html) return JSON; send it as
application/json. create_instance_w1.html builds the chipset <option>
elements with .val().text() instead of string concatenation.
The console settings form on the VM detail page renders the VNC password
(PasswordInput(render_value=True)) and was shown to every is_staff user.
A staff user with the global view_instances permission, or a staff owner
without is_vnc, could read the VNC password of every VM they could see.
Add instances.utils.can_manage_console (active superuser, or an active
owner with is_change and is_vnc), which matches what update_console
already enforced. The detail view only builds the form, and so only puts
the password into the page, when it returns True; the template and
update_console use the same rule.
Several views returned json.dumps() output through HttpResponse, i.e. as
text/html, and guess_mac_address reflects the URL's vname into it
(reflected XSS). Templates filled the log table and volume dropdowns by
concatenating server data into HTML strings, and log messages contain
user-entered snapshot/disk/clone names (stored XSS that runs when a
superuser opens the Logs tab).
- Use JsonResponse in guess_mac_address, random_mac_address,
guess_clone_name, sshkeys, storages.get_volumes,
datasource.os_metadata_json and logs.vm_logs; sshkeys?plain=true is
served as text/plain.
- stats_tab.html builds log rows with .text(); instance.html and
create_instance_w2.html build <option> elements with .val().text().
- Remove obsolete spice-html5 static assets and SPICE console templates
- Restrict default console types to VNC with migration 0012
- Filter out SPICE in VM creation form and backend capabilities
- Return friendly deprecation notice if legacy VM is opened with SPICE
- Clean up docs, architecture references, and libvirt-bootstrap scripts
* Add rest framework for API: First Commit
* modify some shell scripts to make variable references safer; modify some python scripts to reduce the code complexity and cyclomatic complexity of functions.
* Add REST API for some webvirtcloud functions. Instance list/delete/create, compute list/delete/create, storages-network list/retrieve. Add swagger and redoc for API interface
* update requirements
Co-authored-by: herengui <herengui@uniontech.com>