1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
Commit graph

1830 commits

Author SHA1 Message Date
catborise
69ddbbdc94 feat(console): the console daemons' systemd units run sandboxed
webvirt-novncd and webvirt-socketiod get read-only system directories, no
access to /home and /root, no new privileges, no kernel tunables, modules
or cgroups, and only Unix, IPv4 and IPv6 sockets; socketiod also a private
/tmp. novncd keeps the shared /tmp, where a VM's VNC Unix socket may be.
They keep what they need: a pty and its console worker, TCP and Unix
sockets, ssh with its configuration, writes under /srv/webvirtcloud and
the service user's ~/.ssh. The units installed by the update steps bring
this.
2026-10-26 23:52:29 +03:00
catborise
554e3a7995 fix(console): a VM with a QEMU websocket port opens through novncd
A VM defined with QEMU's own VNC websocket (graphics websocket='...',
which the panel never sets) made the console page connect to that port on
the panel's host name: the port is on the compute, so the console did not
open unless the panel ran on that compute, and then it bypassed novncd and
the panel's console token. Such a VM has its ordinary VNC port too, and
novncd now reaches it there like any other VM.
2026-10-26 21:27:52 +03:00
catborise
3bd9fe63e5 fix(console): the console daemons log where the operator looks
- novncd and socketiod log to stderr: the journal on hosts, docker logs in
  the container (runit no longer sends them to unrotated files under
  /var/log). Django's settings gave them the panel's own log file, which
  every process rotated on its own, and made novncd's -v and -d have no
  effect; both work again.
- A refused console says why in the log: novncd's denials are warnings
  (they were shown only with -v), socketiod logs each refusal and who
  opened which VM's serial console.
- The README's serial console notes say what #228 changed (access
  re-checked, superuser takeover, reasons) and where the logs are.
2026-10-26 20:54:11 +03:00
catborise
c169ccf5fe fix(console): small console settings and page fixes
- The VM's console settings have no "Clear keymap" box: it wrote an empty
  keymap attribute into the VM, and choosing Auto already removes the
  keymap; that change is logged as "remove console keymap".
- The "Clip viewport" switch was labelled "View Clipboard".
- The full console page no longer fills the password field with "None"
  for a VM without a console password.
2026-10-26 20:41:46 +03:00
catborise
a0b203749a refactor(console): one keys menu module for both VNC console pages
The lite and the full console page each carried the same 150 lines that
send key combinations (Ctrl+Alt+Del, Ctrl+Alt+F1..F12, Alt+Tab, ...). They
now import static/js/console_keys.js, which binds the menu to the page's
RFB connection.
2026-10-26 20:41:46 +03:00
catborise
f6d4886d1b refactor(console): a console's URL names its compute and VM
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.
2026-10-26 20:41:46 +03:00
catborise
1a6dcc3e54 refactor(console): novncd keeps only the websockify handler it runs
- The fallbacks for websockify releases without ProxyRequestHandler and
  for noVNC's old wsproxy are gone (websockify 0.13 is pinned), with the
  Nova names, the per-connection mode switch and the traffic legend.
- The certificate option is gone: nginx ends TLS and novncd speaks plain
  websockets on the loopback.
- The mixin is ConsoleClient and the handler ConsoleProxyHandler; the
  CLI test that tested a copy of the parser instead of novncd's is
  removed (novncd's own parser is tested).
2026-10-26 20:41:46 +03:00
catborise
9c4c525800 fix(console): novncd reaches a VNC console where it listens
- A console listening on a given address is reached on that address;
  the compute's host name is used only for a wildcard listener (0.0.0.0,
  ::, none). It was always the host name, which may resolve to another
  interface.
- ::1 and localhost count as loopback like 127.0.0.0/8: such a console
  on a TCP or TLS host is refused instead of being tried on the host's
  name.
- The console page says why such a console cannot open and what to change
  (listen on all interfaces, or add the host over SSH) instead of a
  generic connection error.
2026-10-26 20:14:04 +03:00
catborise
68b104dfe4 feat(console): the VNC console uses the panel's own address
The console pages connect to /novncd/ on the address, scheme and port the
page itself was loaded from; nginx proxies it to novncd, which listens on
the loopback only. There is nothing to configure: the console works on
HTTPS (wss), behind another proxy and on any published port.

Before, the page connected to WS_PUBLIC_HOST/PORT/PATH, port 6080 by
default: straight to novncd, past nginx and without TLS, so an HTTPS panel
and a Docker container published on another port had no console until the
public port was set by hand, and novncd listened on every interface.

Gone: WS_PUBLIC_PORT, WS_PUBLIC_HOST, WS_PUBLIC_PATH and WS_CERT, the
installer's two public console questions and its 6080 firewall rule, the
Docker image's WS_PUBLIC_PORT and its init script lines, the manual
install's firewall rule for 6080 and nginx's unused /websockify location.
WS_HOST defaults to 127.0.0.1. A VM with a QEMU websocket port is still
reached on that port of the panel's host name (left for a separate
decision).
2026-10-26 20:14:04 +03:00
catborise
82af555d45 fix(console): a serial session follows its user's access; a superuser takes over
- The console worker learns whose session it is and checks every ten
  seconds that the user may still open the console: an owner removed or a
  user deactivated meanwhile loses it, with a line in the terminal. Access
  was checked only when the session started, which could last for days.
- One console per VM: a console left open in a forgotten tab locked
  everyone out, superusers included. A superuser's connection now takes
  the console over, and the other window is told so.
2026-10-26 19:46:41 +03:00
catborise
1d48cc6881 fix(console): the serial console worker keeps pastes whole and says what failed
- A paste reaches the VM whole: the non-blocking console stream takes it
  in parts, or none while the VM is busy, and the rest was dropped. The
  worker sends the rest until the VM has it, for at most five seconds.
- A libvirt error while the console is open (the host gone, the VM
  undefined or migrated) ends the session with one line in the terminal
  instead of a Python traceback; libvirt no longer prints its errors on
  the terminal. Errors are shown as users see them elsewhere: a host that
  cannot be reached is not named.
- The terminal says when the VM is not running and its console will open
  when it starts. The terminal is raw before the console opens, and the
  stream is dropped once when both threads see the VM stop.
2026-10-26 19:46:41 +03:00
catborise
1fac3de23c fix(console): serial sessions start under a lock and say why they are refused
- socketiod's handlers run on their own threads. A connection is now
  admitted under a lock, so two at once can no longer both open a VM's
  console or pass the session cap. A session's terminal is used and closed
  only under its own lock while it is open: a closed descriptor's number,
  taken again by a new session, never receives another session's input
  or gives it the other's output.
- A refused connection says why: serial console off, the link expired,
  the VM's console open in another window, too many consoles. The page
  shows it instead of "refused".
- The page no longer retries on its own with a token that has expired
  after two minutes; Reconnect loads a new page. Input the browser cannot
  encode no longer raises in the daemon.
2026-10-26 19:46:41 +03:00
catborise
294b008811 fix(console): an SSH compute's VNC console goes through ssh -W
- The tunnel is `ssh -W` to the console's address or Unix socket: the
  compute needs no nc and runs no shell. The old tunnel, copied from
  virt-manager, built a shell script with the console's address and socket
  path in it and eval'd it on the compute, and always passed "-p 22",
  overriding a Port in the SSH configuration.
- On an SSH compute the console always goes through the tunnel, also when
  it listens on a network address: it was sent there unencrypted.
- ssh never prompts (BatchMode) and gives up connecting after 10 seconds;
  when it fails, what it said is logged. The tunnel ends with the session.
2026-10-26 19:21:22 +03:00
catborise
504d86faa3 fix(console): a serial console worker holds only its own terminal
pty.fork returns an inheritable master descriptor, so each new console
worker, and the ssh it may start, held the terminals of every other open
session until it ended. A worker now closes every descriptor above its own
terminal before it starts.
2026-10-26 19:01:02 +03:00
catborise
cbd6317e55 fix(console): a VNC console connects to the VM its page was opened for
- novncd takes the console token only from its websocket URL. The page
  also put the token in a cookie, one for the whole browser, and novncd
  preferred the cookie: with two consoles open, a tab that (re)connected
  after another console was opened got that other VM.
- novncd opens the VM by its UUID, the VM the access check was made for,
  not by its name, which another VM on the host may carry now.
2026-10-26 19:01:02 +03:00
catborise
8d7f28482f fix(api): VM API answers as the VM pages do
- A VM delete reads delete_disk and delete_nvram as booleans from a JSON
  or form body. The view read them as HTML checkboxes from the form body
  only: JSON {"delete_disk": true} kept the disks while reporting success,
  and a form "delete_disk=false" deleted them. Refused options stop
  nothing; the API schema names both options.
- Power on and power cycle of a template answer 409 instead of reporting a
  start that did not happen.
- The VM details leave out the host's ISO images for non-superusers, as
  the VM page does; reading them also refreshed every pool of the host.
- Flavors take values of at least 1, as the web form does, and show their
  id for later changes; a migration needs neither live nor offline; a VM
  create on an unknown compute answers 404 instead of 500.
2026-10-26 17:47:18 +03:00
catborise
726f330dd0 fix(api): host API checks what the web forms check
- An API volume takes the name and size the web form takes. Its name went
  into the volume XML unchecked, so a name could add elements such as a
  backing store pointing at another VM's disk; the name is also escaped
  there now. A size of 0 and metadata preallocation on a non-qcow2 volume
  are refused or dropped, as on the web form.
- An API compute update with an empty or null password keeps the stored
  one, as the web form does; it emptied it and cut the host off.
- The architectures endpoint answers 404 for an unknown compute instead of
  500; an unrouted copy of it is removed.
2026-10-26 17:47:18 +03:00
catborise
c69c65728b fix(tests): a killed test run no longer breaks the next one
Django replaces a SQLite test database and its parallel clones by the main
file only. A run that is killed, or whose worker pool crashes on a failure
it cannot send back, leaves the clones' WAL files behind; the next run's
fresh copies then replay that run's writes, and hundreds of tests fail with
"Cannot operate on a closed database" or foreign key errors until a clean
run checkpoints the stale WAL away. The test runner now removes the test
database's and its clones' WAL files before it creates and clones them
(not with --keepdb, whose databases they belong to).
2026-10-26 16:43:22 +03:00
catborise
b89f280076 fix(instances): VM list columns, hosts for viewers, flavor units
- On a narrow screen the grouped list hid the User, VCPU and Memory
  headings but not the VMs' cells, so values sat under the wrong headings;
  the cells now hide with their headings. Memory says MiB.
- A user with the view_instances permission sees each VM's host in the
  list, as the host alerts already name them; the host page link stays a
  superuser's.
- A flavor's memory and disk are labelled MiB and GiB, and each value is at
  least 1, so "4" is no longer saved as a 4 MiB preset by mistake.
2026-10-26 16:14:37 +03:00
catborise
52d00e818b fix(datasource): no SSH keys for an address without a reverse DNS entry
- A booting VM is named by its address's reverse DNS entry. Without one,
  the address itself was taken as the name, so its first number ("10",
  "192") named the VM: a user who made a VM with that name had their keys
  given to every such VM. Such an address now gets no keys; its metadata
  hostname is still the address.
- Keys are written as quoted YAML strings, so a comment with an apostrophe
  or ": " no longer breaks the key or the file.
2026-10-26 16:14:37 +03:00
catborise
5b24f9a6f8 fix(console): the console page connects only to the panel's own proxy
- The lite VNC page took the proxy's host, port and path from its link. A
  link naming another host made the page send that host a fresh signed
  console token, which opened the VM's console for two minutes. The page
  now uses only what the server gives it, like the full page.
- On a local-socket host, a VM whose console listens on 127.0.0.1 is
  reached directly instead of being refused for want of an SSH tunnel.
- A shut-off VM's console says that the VM is not running instead of
  failing with no reason.
2026-10-26 16:14:37 +03:00
catborise
93d3cc7238 fix(accounts): SSH keys with spaced comments, one token per create, OTP errors
- An SSH public key whose comment holds spaces (ssh-keygen -C "John Doe
  laptop") is accepted; only the type and the key are checked.
- The created API token is shown by a GET after a redirect, so reloading
  the page no longer creates a second token the user never sees.
- The OTP login page shows field errors instead of an empty error box.
- A user without a local password (an LDAP user) is not offered a password
  change that could never succeed.
2026-10-26 16:14:37 +03:00
catborise
484c544762 fix(interfaces): a new interface never replaces one the host defines
- The create form refuses a name the host already defines. Defining it
  again replaced that interface's configuration, for example the host's
  own uplink when a bridge was named after it.
- An interface that does not start is undefined again, so the name is
  free for another try; the name check above makes this safe.
2026-10-26 16:14:32 +03:00
catborise
09d7b0c08a fix(networks): fixed addresses, failed creates and stopped networks behave
- A network created with fixed addresses gets one per address of its DHCP
  range for any subnet; the old prefix cut assumed a gateway ending in .1
  and built addresses such as 10.0.0.1.130. Fixed addresses need a /24 or
  smaller subnet.
- A new network that does not start (its subnet is in use) is undefined
  again, so the name is free for another try.
- Fixed addresses are changed and deleted on a stopped network too: the
  running network is changed only while it runs. A host with only a name
  is deleted as defined, not with an empty MAC, shows no "None", and has no
  edit button it could not use.
- The create dialog disables the fields it hides, so an IPv6 subnet typed
  and then unchecked is not created, and switching from MACVTAP back to
  BRIDGE restores the bridge label and the Open vSwitch option.
- Isolated networks show QoS; QoS save buttons no longer raise a script
  error; saving an unchanged fixed address says so; two messages lose a
  stray backslash and spaces.
2026-10-26 15:36:57 +03:00
catborise
1262559793 fix(nwfilters): a rule is deleted and added exactly as clicked and entered
- Deleting a rule removes the row clicked, by its position, instead of the
  first rule with the same action, direction and priority; a filter changed
  since the page was read is refused instead of losing another rule.
- An added rule is added as entered, with all its attributes. It was merged
  into a rule with the same action, direction and priority, where libvirt
  keeps only the first protocol, so the new rule was silently dropped.
- A new filter shows in the list after it is created.
2026-10-26 15:36:57 +03:00
catborise
63aba5d9c9 fix(storages): pool pages work while a volume is cloned, failed pools are undefined
- libvirt refuses to refresh a pool while a volume is cloned in it. The pool
  page, the volume list of the VM and create pages, upload planning and the
  API no longer fail on that refusal; they use the list libvirt has.
- A new pool that does not start (unreachable NFS server, a device LVM
  cannot use) is undefined again, so the name is free for another try.
- A pool reporting no size, such as an iSCSI pool without LUNs, shows its
  page instead of a division error.
- Each clone dialog shows its own format and metadata rows, so a format
  is never shown without Convert ticked and silently ignored.
- The new-volume size is labelled in GiB and is at least 1; an inactive
  pool shows no "None" volume count.
2026-10-26 15:36:57 +03:00
catborise
9e02286926 fix(computes): host pages survive a down host and a vTPM secret
- The host graphs and the machine/bus lists connect inside their libvirt
  error handling, so a down host gives empty answers instead of a 500 page
  the polling script drops.
- The Secrets page lists vTPM secrets instead of failing on them, and a
  secret without usage data shows an empty cell instead of "None".
- A TCP/TLS host takes a SASL password longer than 14 characters and a
  login up to the Linux limit of 32.
- The compute edit page says "Edit Compute"; a host without VMs no longer
  closes an extra page element; the memory graph is labelled MiB.
2026-10-26 15:36:57 +03:00
catborise
c26e9a49c4 fix(instances): boot order, root password and NIC changes say what they did
A boot device moved up or down was rebuilt without its click handler, so
unticking it afterwards left it in the boot order that was applied; the
moved label now keeps its checkbox. An empty root password did nothing
and said nothing; it is refused with a message. Changing a NIC of a
shut-off VM gave no confirmation; it now says the device changed.
2026-10-26 13:49:37 +03:00
catborise
d696820120 fix(instances): a VM's DRBD status counts only its own resources
The resource pattern was not anchored and took any letters after the VM's
name, so VM "web" also counted "webserver" and "myweb"; a VM with no
resource of its own got "Secondary/OK", stored on every page view. A
VM's resources are now its name or name_SUFFIX at the start of a line,
and a VM without one is "None DRBD".
2026-10-26 13:49:37 +03:00
catborise
11348b2c37 fix(instances): Guest Info says when the agent fails and keeps what it answered
When the guest agent failed, the Guest Info section stayed empty with no
word: the request's error answer was not handled. An agent without the
time zone or host name command lost the OS details it had answered too.
The section now shows the agent's error, and a missing command leaves out
only its own details.
2026-10-26 13:49:37 +03:00
catborise
e29a79c76d fix(instances): internal snapshot names are checked, snapshot dates carry the year
Only external snapshots had their name checked. An internal one could be
taken with an empty name: libvirt named it, the job and its log row named
nothing, and a recovery looked for "" and marked the job failed though the
snapshot existed. Both kinds now pass the same check when queued, and the
internal form asks for a name as the external one does.

Snapshot dates showed no year, so last year's snapshot looked like this
year's in the list one reverts from; they now read 2026-10-13 23:04:00
under "Date (time zone)", as on the Jobs page.
2026-10-26 13:49:37 +03:00
catborise
fa84ce8113 fix(instances): a console save changes and logs only the fields edited
The saved console form had no initial values, so every posted field
counted as changed: saving only a password also logged the keymap and the
listen address again, each time. A listen address the form does not list
(set in the XML editor) was not a choice, so the select showed localhost
and a save moved the console there. The form now takes its initial values
from the VM, on the page and on the save, and offers the VM's own address.
2026-10-26 13:49:37 +03:00
catborise
182746c73e fix(instances): an owner cannot power a VM an administrator paused
Only administrators suspend and resume, and the page tells an owner of a
paused VM "Administrator blocked your instance", but the power views let
the owner force it off or cycle it, on the page and the API, and start it
again: the block ended. The power permission now refuses a paused VM to
everyone but administrators.
2026-10-26 13:49:37 +03:00
catborise
42a1783178 fix(instances): the Resize tab changes only what was asked
Disk sizes were pre-filled rounded to whole GiB, so a 3.5 GiB disk showed
4 and was grown, for good, whenever another disk was resized; an empty
field or a disk outside a pool was a 500. A disk's field is now empty with
its size as the placeholder: an empty field leaves the disk alone, a
larger whole number grows it, anything else is refused with a message.

vCPUs change only on a shut-off VM, also on a direct request: a running
VM got them at its next start, past the quota counted against its live
count. Current vCPUs or memory above the maximum are refused instead of
failing (and dropping vCPU hot-plug) or being capped by libvirt. A running
VM's maximum memory select is disabled, since its maximum is kept, and a
custom memory value is sent only while its box is ticked.
2026-10-26 13:49:37 +03:00
catborise
b619cf3cd4 fix(accounts): a user's page shows permissions as marks, says when there are no VMs, deletes keys
On a superuser's page of a user the VM permissions read True/False; they
are now check marks as on the Users list. A user without VMs gets "No VMs."
instead of an empty table. A superuser can delete one of the user's SSH
keys, as with API tokens: the same view takes the user, the row names
whose key it was.

Closes #218
2026-10-26 11:48:40 +03:00
catborise
6c2704f97d fix(admin): Removed VMs shows the host a VM left and confirms a delete
A tombstone kept the VM's name and UUID but not its compute, so the page
could not say where the VM had been. It now stores the compute's name (as
text: the compute may be the one deleted) and the list shows it; records
made before this have no host. Deleting a record says so, and the admin
tables use scope="col" instead of the invalid span="col".

Closes #217
2026-10-26 11:48:40 +03:00
catborise
f7279610a8 fix(operations): Jobs dates carry the year and time zone, filters match part of a name
Job dates showed no year and no time zone, unlike the Logs page; they now
read 2026-10-13 23:04:00 under "Created (time zone)". The host filter
matched only a whole host name and the user filter only an exact username;
both now ignore case and take the start of a host or any part of a name.
2026-10-26 11:19:42 +03:00
catborise
d80ec72fe0 fix(accounts): a user's page reads only that user's VMs
The administrator's view of a user loaded every VM in the panel and never
used them; the user's own VMs are now read in one query.
2026-10-26 11:19:42 +03:00
catborise
addff12652 fix(admin): a default VM that is not exactly one VM is refused on the form
NEW_USER_DEFAULT_INSTANCES names VMs, and a name may repeat across hosts.
A name with no VM, or with one on two hosts, made creating any user a 500.
The create form now looks the names up and says which one is not exactly
one VM; the user and its default VMs are saved together.
2026-10-26 11:19:42 +03:00
catborise
2e5ef34473 fix(accounts): an email address belongs to one user, so "Lost OTP?" reaches it
"Lost OTP?" mails the QR code only when exactly one active user has the
address. Any user could enter another user's address in their profile and
silently switch the recovery off for both. The profile and the admin user
forms now refuse an address another user has, ignoring case; an empty
address stays allowed for everyone.
2026-10-26 11:19:42 +03:00
catborise
5d8b7e3f61 fix(appsettings): a group saves what was edited, all of it or none, in one row
- A group sent all its fields, and the ones left as they were undid
  what another administrator had saved meanwhile. Each field now sends
  the value the page showed, and only a field edited since is saved.
- A database error partway left the group half saved. The group is now
  saved in one transaction, written as one audit row: "Settings: change
  Console Scale to True, Console Clip Viewport to True".
2026-10-26 10:12:53 +03:00
catborise
5ef3437291 fix(admin): the Logs download survives any row and stops at a size it can build
- A failed login writes the name it was tried with, as typed: a control
  character in it made every download holding that row fail, as the
  workbook cannot hold one. Workbooks now write it as \x01; the VM
  report shares the code.
- A download held every matching row in memory: it now takes the newest
  100000, and its About sheet says when the search should be narrowed.
2026-10-26 10:12:53 +03:00
catborise
0b5eb990ed fix(admin): a forced password change cannot trap a user or be skipped with a token
- The administrator's password form took "password-based
  authentication: Disabled" with "must change it at the next login":
  the change form asks for the old password, which the user then never
  had, so they could not get past it. That combination is refused, and
  an administrator cannot disable their own password.
- A user who must change the password could still use the API with
  their tokens. A token is now refused until they change it, as the
  pages are.
2026-10-26 10:12:53 +03:00
catborise
e5c7dc338d fix(templates): the list pages search their rows as text, with one script
The list pages' search (filter-table.js) read what was typed as a
regular expression: a "(" or "[" stopped it with an error. It also
needed jQuery, while the instance list had its own script for the same
search. Both are now static/js/table_filter.js: plain text in any case,
the instance list's state list and host groups where a page has them,
remembered for a day as before. A group's header row is marked as one
(data-group-header) instead of being any row without a state.
2026-10-25 23:08:42 +03:00
catborise
b4c999a22f feat(admin): the Logs page searches every row, shows failures and downloads them
The search box filtered only the 100 rows on screen, in the browser: an
older row seemed not to exist. The page now searches on the server, in
every row's user, host, VM, VM UUID, message and IP, as plain text, and
can show the failed rows only; its pages keep the search.

Failed rows are marked red, dates carry the year and the time zone, and
a VM's rows link to the VM while it is in the panel. Excel downloads the
rows the search chooses, all pages of them, with the VM report's
workbook (text stays text).
2026-10-25 23:08:42 +03:00
catborise
24896aaecd feat(admin): a password an administrator sets can be one the user must change
The administrator's password form has "The user must change it at their
next login". With it, the user is sent to the change form until they
choose their own, as the generated admin password already does.
2026-10-25 22:38:40 +03:00
catborise
0e8130f1b0 fix(admin): the Users pages keep an administrator in and say what their fields mean
- An administrator could block, delete or demote (unset Active or
  Superuser on) their own account, and with it the last one, leaving the
  panel without anyone to undo it. These are now refused.
- The user form showed "No password set." for users who have one: its
  password field never read the user's password. Its "Set password"
  link went to ../password/, a page this panel does not have. The form
  now says whether a password is set and links the page that sets it.
- "Staff status" said "can log into this admin site"; here it lets a
  user change and delete the template VMs given to them, and is now
  called Template editor.
- A quota of 0 counted as no limit, like -1, so a user's quota could not
  be taken away. Now -1 has no limit and 0 allows none; the help says
  so, and the labels give the units: memory in MiB, disk in GiB.
- A user's page for a user that does not exist answered with a server
  error instead of not found.
- The user list said "None" for a user who never logged in; it says
  "never", and dates fit their column.
- The password form's labels no longer break mid-word.
2026-10-25 22:38:40 +03:00
catborise
07a2e09c2f docs(appsettings): each setting's description says what it does
The descriptions were tooltips, many only repeating the setting's name
("Cpu modes", "Debug for user quotas"). Now shown under each field, they
say what the setting changes: what a new VM or disk gets, how the
console starts, what a page shows. A migration writes them.
2026-10-25 22:02:53 +03:00
catborise
632f5e15bd feat(appsettings): the Settings page groups its settings and saves a group at once
The page listed 37 settings by name, each its own form saved as soon as
its list or field changed, with the description only in a tooltip. It
now shows them in groups (New VM defaults, Disks, Clones, Console, VM
access and owners, Snapshots and jobs, Login, Lists and pages) with each
description under its field and the label tied to it. A group's Save
button saves its changed settings, or none when one is refused, and
says which were saved; number settings are number fields with their
range. Language and theme are under Appearance with their own buttons.
A setting in no group shows under Other.
2026-10-25 22:02:53 +03:00
catborise
7392a5b4d2 fix(appsettings): settings take only the values the panel can use
The Settings page saved whatever was posted, and some lists offered
values the panel cannot use:

- Quota Debug could not be turned off: "False" is a non-empty text and
  counted as on.
- VM Clone Name Prefix showed as a True/False list, so no prefix could
  be typed, and touching it set the prefix to True.
- Disk SCSI Controller listed " lsilogic" with a space, never shown as
  chosen, and virtio-blk, which is no SCSI controller.
- VM Machine Type listed x86_64, an architecture; VM CD-ROM Device
  listed virtio, a bus a CD-ROM cannot use.
- Logs per Page and Disk Owner UID/GID are read with int(): a letter
  broke the logs page and VM create.

A migration fixes the lists and moves a value they no longer offer to
the default (the clone prefix keeps its text). A listed setting now
takes one of its choices, and every number setting a whole number in
its range, checked before it is saved.
2026-10-25 22:02:53 +03:00